go/types, types2: unifier constructor to accept type parameters and arguments

Change-Id: I2f20cb8f1dd95ba97de7630d0bbe6dee4e019f94
Reviewed-on: https://go-review.googlesource.com/c/go/+/463990
Reviewed-by: Robert Griesemer <gri@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go
index b5565b7..b9defb3 100644
--- a/src/cmd/compile/internal/types2/infer.go
+++ b/src/cmd/compile/internal/types2/infer.go
@@ -135,14 +135,7 @@
 	// Unify parameter and argument types for generic parameters with typed arguments
 	// and collect the indices of generic parameters with untyped arguments.
 	// Terminology: generic parameter = function parameter with a type-parameterized type
-	u := newUnifier(tparams)
-
-	// Set the type arguments which we know already.
-	for i, targ := range targs {
-		if targ != nil {
-			u.set(tparams[i], targ)
-		}
-	}
+	u := newUnifier(tparams, targs)
 
 	errorf := func(kind string, tpar, targ Type, arg *operand) {
 		// provide a better error message if we can
@@ -462,14 +455,7 @@
 	}
 
 	// Unify type parameters with their constraints.
-	u := newUnifier(tparams)
-
-	// Set the type arguments which we know already.
-	for i, targ := range targs {
-		if targ != nil {
-			u.set(tparams[i], targ)
-		}
-	}
+	u := newUnifier(tparams, targs)
 
 	// Repeatedly apply constraint type inference as long as
 	// there are still unknown type arguments and progress is
diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go
index 221700b..bdafdf9 100644
--- a/src/cmd/compile/internal/types2/unify.go
+++ b/src/cmd/compile/internal/types2/unify.go
@@ -61,15 +61,23 @@
 	depth   int // recursion depth during unification
 }
 
-// newUnifier returns a new unifier initialized with the given type parameter list.
-func newUnifier(tparams []*TypeParam) *unifier {
+// newUnifier returns a new unifier initialized with the given type parameter
+// and corresponding type argument lists. The type argument list may be shorter
+// than the type parameter list, and it may contain nil types. Matching type
+// parameters and arguments must have the same index.
+func newUnifier(tparams []*TypeParam, targs []Type) *unifier {
+	assert(len(tparams) >= len(targs))
 	handles := make(map[*TypeParam]*Type, len(tparams))
 	// Allocate all handles up-front: in a correct program, all type parameters
 	// must be resolved and thus eventually will get a handle.
 	// Also, sharing of handles caused by unified type parameters is rare and
 	// so it's ok to not optimize for that case (and delay handle allocation).
-	for _, x := range tparams {
-		handles[x] = new(Type)
+	for i, x := range tparams {
+		var t Type
+		if i < len(targs) {
+			t = targs[i]
+		}
+		handles[x] = &t
 	}
 	return &unifier{tparams, handles, 0}
 }
diff --git a/src/go/types/infer.go b/src/go/types/infer.go
index f86cc3b..70d256b 100644
--- a/src/go/types/infer.go
+++ b/src/go/types/infer.go
@@ -137,14 +137,7 @@
 	// Unify parameter and argument types for generic parameters with typed arguments
 	// and collect the indices of generic parameters with untyped arguments.
 	// Terminology: generic parameter = function parameter with a type-parameterized type
-	u := newUnifier(tparams)
-
-	// Set the type arguments which we know already.
-	for i, targ := range targs {
-		if targ != nil {
-			u.set(tparams[i], targ)
-		}
-	}
+	u := newUnifier(tparams, targs)
 
 	errorf := func(kind string, tpar, targ Type, arg *operand) {
 		// provide a better error message if we can
@@ -464,14 +457,7 @@
 	}
 
 	// Unify type parameters with their constraints.
-	u := newUnifier(tparams)
-
-	// Set the type arguments which we know already.
-	for i, targ := range targs {
-		if targ != nil {
-			u.set(tparams[i], targ)
-		}
-	}
+	u := newUnifier(tparams, targs)
 
 	// Repeatedly apply constraint type inference as long as
 	// there are still unknown type arguments and progress is
diff --git a/src/go/types/unify.go b/src/go/types/unify.go
index 094aa22..03c4739 100644
--- a/src/go/types/unify.go
+++ b/src/go/types/unify.go
@@ -63,15 +63,23 @@
 	depth   int // recursion depth during unification
 }
 
-// newUnifier returns a new unifier initialized with the given type parameter list.
-func newUnifier(tparams []*TypeParam) *unifier {
+// newUnifier returns a new unifier initialized with the given type parameter
+// and corresponding type argument lists. The type argument list may be shorter
+// than the type parameter list, and it may contain nil types. Matching type
+// parameters and arguments must have the same index.
+func newUnifier(tparams []*TypeParam, targs []Type) *unifier {
+	assert(len(tparams) >= len(targs))
 	handles := make(map[*TypeParam]*Type, len(tparams))
 	// Allocate all handles up-front: in a correct program, all type parameters
 	// must be resolved and thus eventually will get a handle.
 	// Also, sharing of handles caused by unified type parameters is rare and
 	// so it's ok to not optimize for that case (and delay handle allocation).
-	for _, x := range tparams {
-		handles[x] = new(Type)
+	for i, x := range tparams {
+		var t Type
+		if i < len(targs) {
+			t = targs[i]
+		}
+		handles[x] = &t
 	}
 	return &unifier{tparams, handles, 0}
 }