cmd/gc: rewrite argtype to substitute in a single pass

Substituting in multiple passes meant walking the type
multiple times, and worse, if a complex type was substituted
in an early pass, later passes would follow it, possibly recursively,
until hitting the depth 10 limit.

Change-Id: Ie61d6ec08438e297baabe932afe33d08f358e55f
Reviewed-on: https://go-review.googlesource.com/7625
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/src/cmd/internal/gc/subr.go b/src/cmd/internal/gc/subr.go
index f77d151..ec4958a 100644
--- a/src/cmd/internal/gc/subr.go
+++ b/src/cmd/internal/gc/subr.go
@@ -1369,66 +1369,57 @@
 	return r
 }
 
-func subtype(stp **Type, t *Type, d int) bool {
-loop:
-	st := *stp
-	if st == nil {
-		return false
+// substArgTypes substitutes the given list of types for
+// successive occurrences of the "any" placeholder in the
+// type syntax expression n.Type.
+func substArgTypes(n *Node, types ...*Type) {
+	for _, t := range types {
+		dowidth(t)
 	}
-
-	d++
-	if d >= 10 {
-		return false
+	substAny(&n.Type, &types)
+	if len(types) > 0 {
+		Fatal("substArgTypes: too many argument types")
 	}
+}
 
-	switch st.Etype {
-	default:
-		return false
-
-	case TPTR32,
-		TPTR64,
-		TCHAN,
-		TARRAY:
-		stp = &st.Type
-		goto loop
-
-	case TANY:
-		if st.Copyany == 0 {
-			return false
+// substAny walks *tp, replacing instances of "any" with successive
+// elements removed from types.
+func substAny(tp **Type, types *[]*Type) {
+	for {
+		t := *tp
+		if t == nil {
+			return
 		}
-		*stp = t
-
-	case TMAP:
-		if subtype(&st.Down, t, d) {
-			break
-		}
-		stp = &st.Type
-		goto loop
-
-	case TFUNC:
-		for {
-			if subtype(&st.Type, t, d) {
-				break
+		if t.Etype == TANY && t.Copyany != 0 {
+			if len(*types) == 0 {
+				Fatal("substArgTypes: not enough argument types")
 			}
-			if subtype(&st.Type.Down.Down, t, d) {
-				break
-			}
-			if subtype(&st.Type.Down, t, d) {
-				break
-			}
-			return false
+			*tp = (*types)[0]
+			*types = (*types)[1:]
 		}
 
-	case TSTRUCT:
-		for st = st.Type; st != nil; st = st.Down {
-			if subtype(&st.Type, t, d) {
-				return true
+		switch t.Etype {
+		case TPTR32, TPTR64, TCHAN, TARRAY:
+			tp = &t.Type
+			continue
+
+		case TMAP:
+			substAny(&t.Down, types)
+			tp = &t.Type
+			continue
+
+		case TFUNC:
+			substAny(&t.Type, types)
+			substAny(&t.Type.Down.Down, types)
+			substAny(&t.Type.Down, types)
+
+		case TSTRUCT:
+			for t = t.Type; t != nil; t = t.Down {
+				substAny(&t.Type, types)
 			}
 		}
-		return false
+		return
 	}
-
-	return true
 }
 
 /*
@@ -1484,13 +1475,6 @@
 	return false
 }
 
-func argtype(on *Node, t *Type) {
-	dowidth(t)
-	if !subtype(&on.Type, t, 0) {
-		Fatal("argtype: failed %v %v\n", Nconv(on, 0), Tconv(t, 0))
-	}
-}
-
 func shallow(t *Type) *Type {
 	if t == nil {
 		return nil
@@ -2793,18 +2777,13 @@
 		fn = syslook("memequal", 1)
 		*needsize = 1
 
-	case 1,
-		2,
-		4,
-		8,
-		16:
+	case 1, 2, 4, 8, 16:
 		buf := fmt.Sprintf("memequal%d", int(size)*8)
 		fn = syslook(buf, 1)
 		*needsize = 0
 	}
 
-	argtype(fn, type_)
-	argtype(fn, type_)
+	substArgTypes(fn, type_, type_)
 	return fn
 }