From 3c00a2839a8b577912f78d5fe1ba2d765d0f6c7c Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 16 Nov 2021 12:20:11 -0800 Subject: [PATCH] cmd/compile/internal/types2: return an error from Instantiate on incorrect len(targs) This CL is a clean port of CL 363635 from go/types to types2. Updates #47916 Change-Id: Ib46758435c31ad9a6a4a63f552503d5afa66b5c0 Reviewed-on: https://go-review.googlesource.com/c/go/+/364534 Trust: Robert Griesemer Reviewed-by: Robert Findley --- .../compile/internal/types2/instantiate.go | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index 35fcc7c040753..3f5fc56f5d20f 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -13,40 +13,50 @@ import ( "fmt" ) -// Instantiate instantiates the type typ with the given type arguments targs. -// typ must be a *Named or a *Signature type, and its number of type parameters -// must match the number of provided type arguments. The result is a new, -// instantiated (not parameterized) type of the same kind (either a *Named or a -// *Signature). Any methods attached to a *Named are simply copied; they are -// not instantiated. +// Instantiate instantiates the type orig with the given type arguments targs. +// orig must be a *Named or a *Signature type. If there is no error, the +// resulting Type is a new, instantiated (not parameterized) type of the same +// kind (either a *Named or a *Signature). Methods attached to a *Named type +// are also instantiated, and associated with a new *Func that has the same +// position as the original method, but nil function scope. // -// If ctxt is non-nil, it may be used to de-dupe the instance against previous -// instances with the same identity. +// If ctxt is non-nil, it may be used to de-duplicate the instance against +// previous instances with the same identity. As a special case, generic +// *Signature origin types are only considered identical if they are pointer +// equivalent, so that instantiating distinct (but possibly identical) +// signatures will yield different instances. // -// If verify is set and constraint satisfaction fails, the returned error may -// wrap an *ArgumentError indicating which type argument did not satisfy its -// corresponding type parameter constraint, and why. +// If validate is set, Instantiate verifies that the number of type arguments +// and parameters match, and that the type arguments satisfy their +// corresponding type constraints. If verification fails, the resulting error +// may wrap an *ArgumentError indicating which type argument did not satisfy +// its corresponding type parameter constraint, and why. // -// TODO(rfindley): change this function to also return an error if lengths of -// tparams and targs do not match. -func Instantiate(ctxt *Context, typ Type, targs []Type, validate bool) (Type, error) { - inst := (*Checker)(nil).instance(nopos, typ, targs, ctxt) - - var err error +// If validate is not set, Instantiate does not verify the type argument count +// or whether the type arguments satisfy their constraints. Instantiate is +// guaranteed to not return an error, but may panic. Specifically, for +// *Signature types, Instantiate will panic immediately if the type argument +// count is incorrect; for *Named types, a panic may occur later inside the +// *Named API. +func Instantiate(ctxt *Context, orig Type, targs []Type, validate bool) (Type, error) { if validate { var tparams []*TypeParam - switch t := typ.(type) { + switch t := orig.(type) { case *Named: tparams = t.TypeParams().list() case *Signature: tparams = t.TypeParams().list() } + if len(targs) != len(tparams) { + return nil, fmt.Errorf("got %d type arguments but %s has %d type parameters", len(targs), orig, len(tparams)) + } if i, err := (*Checker)(nil).verify(nopos, tparams, targs); err != nil { - return inst, &ArgumentError{i, err} + return nil, &ArgumentError{i, err} } } - return inst, err + inst := (*Checker)(nil).instance(nopos, orig, targs, ctxt) + return inst, nil } // instance creates a type or function instance using the given original type