]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.typeparams] go/types: set type parameter indices when they are bound
authorRob Findley <rfindley@google.com>
Wed, 21 Jul 2021 14:21:23 +0000 (10:21 -0400)
committerRobert Findley <rfindley@google.com>
Thu, 22 Jul 2021 17:05:56 +0000 (17:05 +0000)
It is invalid to use a type parameter for more than one type, so we can
avoid passing the type parameter index to NewTypeParam and just set it
when type parameters are bound to a type via SetTParams or during type
checking.

In order to enforce the correctness of this change, introduce a
TypeParams type to represent a list of type parameters that have been
associated with a type. For now, expose this new type as the API for
type parameters, but this is of course not necessarily a final API.

Allowing *TypeParams to be nil also decreases the size of Named and
Signature, which is good as most instances of these types will not be
parameterized.

Change-Id: Ia1e39ba51edb05bb535eb5f41c34e9dd02d39c38
Reviewed-on: https://go-review.googlesource.com/c/go/+/336249
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
17 files changed:
src/go/types/api_test.go
src/go/types/assignments.go
src/go/types/builtins.go
src/go/types/call.go
src/go/types/decl.go
src/go/types/index.go
src/go/types/instance.go
src/go/types/instantiate.go
src/go/types/lookup.go
src/go/types/named.go
src/go/types/object.go
src/go/types/predicates.go
src/go/types/signature.go
src/go/types/sizeof_test.go
src/go/types/subst.go
src/go/types/typeparam.go
src/go/types/typestring.go

index 444cb440872b45e4f9fadb88719be212c37a5e66..b2d532c4c8bb68bff4dc1841714ccd6725e0afef 100644 (file)
@@ -1828,7 +1828,7 @@ func TestInstantiate(t *testing.T) {
 
        // type T should have one type parameter
        T := pkg.Scope().Lookup("T").Type().(*Named)
-       if n := len(T.TParams()); n != 1 {
+       if n := T.TParams().Len(); n != 1 {
                t.Fatalf("expected 1 type parameter; found %d", n)
        }
 
index 18eae62184028ade83978e76483ebc20ba8c1102..595f426e1090a209c589edb80f305bd0ab146a68 100644 (file)
@@ -71,7 +71,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
        }
 
        // A generic (non-instantiated) function value cannot be assigned to a variable.
-       if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 {
+       if sig := asSignature(x.typ); sig != nil && sig.TParams().Len() > 0 {
                check.errorf(x, _Todo, "cannot use generic function %s without instantiation in %s", x, context)
        }
 
index 2edf90116540407503f89219354ed86ad56121be..b6fb36b185a3c1280045b423081b7b1317ddd865 100644 (file)
@@ -806,7 +806,8 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
                // type param is placed in the current package so export/import
                // works as expected.
                tpar := NewTypeName(token.NoPos, check.pkg, "<type parameter>", nil)
-               ptyp := check.NewTypeParam(tpar, tp.index, &emptyInterface) // assigns type to tpar as a side-effect
+               ptyp := check.NewTypeParam(tpar, &emptyInterface) // assigns type to tpar as a side-effect
+               ptyp.index = tp.index
                tsum := newUnion(rtypes, tildes)
                ptyp.bound = &Interface{complete: true, tset: &TypeSet{types: tsum}}
 
index 9453b53c3a2f541507122236184d0b4a3278f8c9..96d0429af95237d0f2e6efa48c44523e033ddd86 100644 (file)
@@ -27,7 +27,7 @@ func (check *Checker) funcInst(x *operand, ix *typeparams.IndexExpr) {
 
        // check number of type arguments (got) vs number of type parameters (want)
        sig := x.typ.(*Signature)
-       got, want := len(targs), len(sig.tparams)
+       got, want := len(targs), sig.TParams().Len()
        if got > want {
                check.errorf(ix.Indices[got-1], _Todo, "got %d type arguments but want %d", got, want)
                x.mode = invalid
@@ -39,7 +39,7 @@ func (check *Checker) funcInst(x *operand, ix *typeparams.IndexExpr) {
        inferred := false
 
        if got < want {
-               targs = check.infer(ix.Orig, sig.tparams, targs, nil, nil, true)
+               targs = check.infer(ix.Orig, sig.TParams().list(), targs, nil, nil, true)
                if targs == nil {
                        // error was already reported
                        x.mode = invalid
@@ -160,7 +160,7 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind {
                assert(len(targs) == len(ix.Indices))
 
                // check number of type arguments (got) vs number of type parameters (want)
-               got, want := len(targs), len(sig.tparams)
+               got, want := len(targs), sig.TParams().Len()
                if got > want {
                        check.errorf(ix.Indices[want], _Todo, "got %d type arguments but want %d", got, want)
                        check.use(call.Args...)
@@ -194,7 +194,7 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind {
 
        // if type inference failed, a parametrized result must be invalidated
        // (operands cannot have a parametrized type)
-       if x.mode == value && len(sig.tparams) > 0 && isParameterized(sig.tparams, x.typ) {
+       if x.mode == value && sig.TParams().Len() > 0 && isParameterized(sig.TParams().list(), x.typ) {
                x.mode = invalid
        }
 
@@ -324,10 +324,10 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type
        }
 
        // infer type arguments and instantiate signature if necessary
-       if len(sig.tparams) > 0 {
+       if sig.TParams().Len() > 0 {
                // TODO(gri) provide position information for targs so we can feed
                //           it to the instantiate call for better error reporting
-               targs := check.infer(call, sig.tparams, targs, sigParams, args, true)
+               targs := check.infer(call, sig.TParams().list(), targs, sigParams, args, true)
                if targs == nil {
                        return // error already reported
                }
@@ -341,7 +341,7 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type
                // need to compute it from the adjusted list; otherwise we can
                // simply use the result signature's parameter list.
                if adjusted {
-                       sigParams = check.subst(call.Pos(), sigParams, makeSubstMap(sig.tparams, targs)).(*Tuple)
+                       sigParams = check.subst(call.Pos(), sigParams, makeSubstMap(sig.TParams().list(), targs)).(*Tuple)
                } else {
                        sigParams = rsig.params
                }
@@ -517,7 +517,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
                // the signature accordingly.
                // TODO(gri) factor this code out
                sig := m.typ.(*Signature)
-               if len(sig.rparams) > 0 {
+               if sig.RParams().Len() > 0 {
                        // For inference to work, we must use the receiver type
                        // matching the receiver in the actual method declaration.
                        // If the method is embedded, the matching receiver is the
@@ -545,7 +545,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
                        // the receiver type arguments here, the receiver must be be otherwise invalid
                        // and an error has been reported elsewhere.
                        arg := operand{mode: variable, expr: x.expr, typ: recv}
-                       targs := check.infer(m, sig.rparams, nil, NewTuple(sig.recv), []*operand{&arg}, false /* no error reporting */)
+                       targs := check.infer(m, sig.RParams().list(), nil, NewTuple(sig.recv), []*operand{&arg}, false /* no error reporting */)
                        if targs == nil {
                                // We may reach here if there were other errors (see issue #40056).
                                goto Error
@@ -554,7 +554,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
                        // (If we modify m, some tests will fail; possibly because the m is in use.)
                        // TODO(gri) investigate and provide a correct explanation here
                        copy := *m
-                       copy.typ = check.subst(e.Pos(), m.typ, makeSubstMap(sig.rparams, targs))
+                       copy.typ = check.subst(e.Pos(), m.typ, makeSubstMap(sig.RParams().list(), targs))
                        obj = &copy
                }
                // TODO(gri) we also need to do substitution for parameterized interface methods
index 1195104b59dcacf3d14ed92e85b08e431d9398f0..be7753d9d18744276c52536a13ee69f195584172 100644 (file)
@@ -625,13 +625,13 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) {
        named.underlying = under(named)
 
        // If the RHS is a type parameter, it must be from this type declaration.
-       if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.tparams, tpar) < 0 {
+       if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.tparams.list(), tpar) < 0 {
                check.errorf(tdecl.Type, _Todo, "cannot use function type parameter %s as RHS in type declaration", tpar)
                named.underlying = Typ[Invalid]
        }
 }
 
-func (check *Checker) collectTypeParams(list *ast.FieldList) []*TypeName {
+func (check *Checker) collectTypeParams(list *ast.FieldList) *TypeParams {
        var tparams []*TypeName
        // Declare type parameters up-front, with empty interface as type bound.
        // The scope of type parameters starts at the beginning of the type parameter
@@ -655,13 +655,13 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) []*TypeName {
                index += len(f.Names)
        }
 
-       return tparams
+       return bindTParams(tparams)
 }
 
 func (check *Checker) declareTypeParams(tparams []*TypeName, names []*ast.Ident) []*TypeName {
        for _, name := range names {
                tpar := NewTypeName(name.Pos(), check.pkg, name.Name, nil)
-               check.NewTypeParam(tpar, len(tparams), &emptyInterface) // assigns type to tpar as a side-effect
+               check.NewTypeParam(tpar, &emptyInterface)               // assigns type to tpar as a side-effect
                check.declare(check.scope, name, tpar, check.scope.pos) // TODO(gri) check scope position
                tparams = append(tparams, tpar)
        }
index b2a5a2e94888017b261a179757b160eb42c787f1..a49bc5519cf3e9a5f29fdaf45d2595af2d1342ae 100644 (file)
@@ -33,7 +33,7 @@ func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst
                return false
 
        case value:
-               if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 {
+               if sig := asSignature(x.typ); sig != nil && sig.TParams().Len() > 0 {
                        // function instantiation
                        return true
                }
index 9d31b42690a1e22368f1938adb2bed33134d1815..7e158ea35217d93af14a2251acab433a32556273 100644 (file)
@@ -24,7 +24,7 @@ type instance struct {
 func (n *Named) complete() {
        if n.instance != nil && len(n.targs) > 0 && n.underlying == nil {
                check := n.instance.check
-               inst := check.instantiate(n.instance.pos, n.orig.underlying, n.tparams, n.targs, n.instance.posList)
+               inst := check.instantiate(n.instance.pos, n.orig.underlying, n.TParams().list(), n.targs, n.instance.posList)
                n.underlying = inst
                n.fromRHS = inst
                n.methods = n.orig.methods
index 14bbf2b12b1e8e8c54138a99af99e3a2c5193559..7e2f3173c3f143540f32bfcd54c864cb7114134f 100644 (file)
@@ -28,9 +28,9 @@ func (check *Checker) Instantiate(pos token.Pos, typ Type, targs []Type, posList
        var tparams []*TypeName
        switch t := typ.(type) {
        case *Named:
-               tparams = t.TParams()
+               tparams = t.TParams().list()
        case *Signature:
-               tparams = t.tparams
+               tparams = t.TParams().list()
                defer func() {
                        // If we had an unexpected failure somewhere don't panic below when
                        // asserting res.(*Signature). Check for *Signature in case Typ[Invalid]
@@ -109,9 +109,9 @@ func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, pos
        if base == nil {
                panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
        }
-       if verify && len(base.tparams) == len(targs) {
+       if verify && base.TParams().Len() == len(targs) {
                check.later(func() {
-                       check.verify(pos, base.tparams, targs, posList)
+                       check.verify(pos, base.tparams.list(), targs, posList)
                })
        }
        h := instantiatedHash(base, targs)
@@ -122,7 +122,7 @@ func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, pos
        }
 
        tname := NewTypeName(pos, base.obj.pkg, base.obj.name, nil)
-       named := check.newNamed(tname, base, nil, base.tparams, base.methods) // methods are instantiated lazily
+       named := check.newNamed(tname, base, nil, base.TParams(), base.methods) // methods are instantiated lazily
        named.targs = targs
        named.instance = &instance{
                check:   check,
index 304ae6e3c90f53aff4116783f0940a81a7afc5ba..8b1d70a9784fa37288f97c572b5f3e5ac0877eb6 100644 (file)
@@ -317,10 +317,10 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
                        // both methods must have the same number of type parameters
                        ftyp := f.typ.(*Signature)
                        mtyp := m.typ.(*Signature)
-                       if len(ftyp.tparams) != len(mtyp.tparams) {
+                       if ftyp.TParams().Len() != mtyp.TParams().Len() {
                                return m, f
                        }
-                       if len(ftyp.tparams) > 0 {
+                       if ftyp.TParams().Len() > 0 {
                                panic("internal error: method with type parameters")
                        }
 
@@ -330,7 +330,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
                        // TODO(gri) is this always correct? what about type bounds?
                        // (Alternative is to rename/subst type parameters and compare.)
                        u := newUnifier(true)
-                       u.x.init(ftyp.tparams)
+                       u.x.init(ftyp.TParams().list())
                        if !u.unify(ftyp, mtyp) {
                                return m, f
                        }
@@ -373,10 +373,10 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
                // both methods must have the same number of type parameters
                ftyp := f.typ.(*Signature)
                mtyp := m.typ.(*Signature)
-               if len(ftyp.tparams) != len(mtyp.tparams) {
+               if ftyp.TParams().Len() != mtyp.TParams().Len() {
                        return m, f
                }
-               if len(ftyp.tparams) > 0 {
+               if ftyp.TParams().Len() > 0 {
                        panic("internal error: method with type parameters")
                }
 
@@ -387,17 +387,17 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
                // In order to compare the signatures, substitute the receiver
                // type parameters of ftyp with V's instantiation type arguments.
                // This lazily instantiates the signature of method f.
-               if Vn != nil && len(Vn.TParams()) > 0 {
+               if Vn != nil && Vn.TParams().Len() > 0 {
                        // Be careful: The number of type arguments may not match
                        // the number of receiver parameters. If so, an error was
                        // reported earlier but the length discrepancy is still
                        // here. Exit early in this case to prevent an assertion
                        // failure in makeSubstMap.
                        // TODO(gri) Can we avoid this check by fixing the lengths?
-                       if len(ftyp.rparams) != len(Vn.targs) {
+                       if len(ftyp.RParams().list()) != len(Vn.targs) {
                                return
                        }
-                       ftyp = check.subst(token.NoPos, ftyp, makeSubstMap(ftyp.rparams, Vn.targs)).(*Signature)
+                       ftyp = check.subst(token.NoPos, ftyp, makeSubstMap(ftyp.RParams().list(), Vn.targs)).(*Signature)
                }
 
                // If the methods have type parameters we don't care whether they
@@ -406,7 +406,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
                // TODO(gri) is this always correct? what about type bounds?
                // (Alternative is to rename/subst type parameters and compare.)
                u := newUnifier(true)
-               u.x.init(ftyp.rparams)
+               u.x.init(ftyp.RParams().list())
                if !u.unify(ftyp, mtyp) {
                        return m, f
                }
index a500f5663ba5557bf8ea793dac317b5c46e77b83..03af3fbc5aa40b0d6fcaed6419e15bf1cf540b88 100644 (file)
@@ -16,7 +16,7 @@ type Named struct {
        orig       *Named      // original, uninstantiated type
        fromRHS    Type        // type (on RHS of declaration) this *Named type is derived of (for cycle reporting)
        underlying Type        // possibly a *Named during setup; never a *Named once set up completely
-       tparams    []*TypeName // type parameters, or nil
+       tparams    *TypeParams // type parameters, or nil
        targs      []Type      // type arguments (after instantiation), or nil
        methods    []*Func     // methods declared for this type (not the method set of this type); signatures are type-checked lazily
 
@@ -56,7 +56,7 @@ func (t *Named) expand() *Named {
                        panic("invalid underlying type")
                }
 
-               t.tparams = tparams
+               t.tparams = bindTParams(tparams)
                t.underlying = underlying
                t.methods = methods
        })
@@ -64,7 +64,7 @@ func (t *Named) expand() *Named {
 }
 
 // newNamed is like NewNamed but with a *Checker receiver and additional orig argument.
-func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams []*TypeName, methods []*Func) *Named {
+func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams *TypeParams, methods []*Func) *Named {
        var inst *instance
        if check != nil {
                inst = &instance{
@@ -108,14 +108,14 @@ func (t *Named) _Orig() *Named { return t.orig }
 // TODO(gri) Come up with a better representation and API to distinguish
 //           between parameterized instantiated and non-instantiated types.
 
-// _TParams returns the type parameters of the named type t, or nil.
+// TParams returns the type parameters of the named type t, or nil.
 // The result is non-nil for an (originally) parameterized type even if it is instantiated.
-func (t *Named) TParams() []*TypeName { return t.expand().tparams }
+func (t *Named) TParams() *TypeParams { return t.expand().tparams }
 
-// _SetTParams sets the type parameters of the named type t.
-func (t *Named) SetTParams(tparams []*TypeName) { t.expand().tparams = tparams }
+// SetTParams sets the type parameters of the named type t.
+func (t *Named) SetTParams(tparams []*TypeName) { t.expand().tparams = bindTParams(tparams) }
 
-// _TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated.
+// TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated.
 func (t *Named) TArgs() []Type { return t.targs }
 
 // SetTArgs sets the type arguments of the named type t.
index 4ea2837ea7c2312aa7e8acef35a4188ab470a392..7266623fbe99693ffc108e91e339ead3d896b256 100644 (file)
@@ -429,8 +429,8 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
                if _, ok := typ.(*Basic); ok {
                        return
                }
-               if named, _ := typ.(*Named); named != nil && len(named.tparams) > 0 {
-                       writeTParamList(buf, named.tparams, qf, nil)
+               if named, _ := typ.(*Named); named != nil && named.TParams().Len() > 0 {
+                       writeTParamList(buf, named.TParams().list(), qf, nil)
                }
                if tname.IsAlias() {
                        buf.WriteString(" =")
index ce350f4470daea8ae22dc45e2fa78ffda7b6b1b8..181e2fcfc549d3df827266d05ce118a00370a901 100644 (file)
@@ -242,7 +242,7 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
                // parameter names.
                if y, ok := y.(*Signature); ok {
                        return x.variadic == y.variadic &&
-                               identicalTParams(x.tparams, y.tparams, cmpTags, p) &&
+                               identicalTParams(x.TParams().list(), y.TParams().list(), cmpTags, p) &&
                                identical(x.params, y.params, cmpTags, p) &&
                                identical(x.results, y.results, cmpTags, p)
                }
index da01ec801a5a6afa893c12469a3b2f76da2ba1cb..5a69bb17b5724ffca0f4a889e033adeaa377a95c 100644 (file)
@@ -21,8 +21,8 @@ type Signature struct {
        // and store it in the Func Object) because when type-checking a function
        // literal we call the general type checker which returns a general Type.
        // We then unpack the *Signature and use the scope for the literal body.
-       rparams  []*TypeName // receiver type parameters from left to right, or nil
-       tparams  []*TypeName // type parameters from left to right, or nil
+       rparams  *TypeParams // receiver type parameters from left to right, or nil
+       tparams  *TypeParams // type parameters from left to right, or nil
        scope    *Scope      // function scope, present for package-local signatures
        recv     *Var        // nil if not a method
        params   *Tuple      // (incoming) parameters from left to right; or nil
@@ -56,13 +56,16 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
 func (s *Signature) Recv() *Var { return s.recv }
 
 // TParams returns the type parameters of signature s, or nil.
-func (s *Signature) TParams() []*TypeName { return s.tparams }
+func (s *Signature) TParams() *TypeParams { return s.tparams }
 
 // SetTParams sets the type parameters of signature s.
-func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = tparams }
+func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = bindTParams(tparams) }
+
+// RParams returns the receiver type parameters of signature s, or nil.
+func (s *Signature) RParams() *TypeParams { return s.rparams }
 
 // SetRParams sets the receiver type params of signature s.
-func (s *Signature) SetRParams(rparams []*TypeName) { s.rparams = rparams }
+func (s *Signature) SetRParams(rparams []*TypeName) { s.rparams = bindTParams(rparams) }
 
 // Params returns the parameters of signature s, or nil.
 func (s *Signature) Params() *Tuple { return s.params }
@@ -115,7 +118,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
                                // blank identifiers were found => use rewritten receiver type
                                recvTyp = isubst(recvPar.List[0].Type, smap)
                        }
-                       sig.rparams = check.declareTypeParams(nil, rparams)
+                       sig.rparams = bindTParams(check.declareTypeParams(nil, rparams))
                        // determine receiver type to get its type parameters
                        // and the respective type parameter bounds
                        var recvTParams []*TypeName
@@ -125,19 +128,19 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
                                //       again when we type-check the signature.
                                // TODO(gri) maybe the receiver should be marked as invalid instead?
                                if recv := asNamed(check.genericType(rname, false)); recv != nil {
-                                       recvTParams = recv.TParams()
+                                       recvTParams = recv.TParams().list()
                                }
                        }
                        // provide type parameter bounds
                        // - only do this if we have the right number (otherwise an error is reported elsewhere)
-                       if len(sig.rparams) == len(recvTParams) {
+                       if sig.RParams().Len() == len(recvTParams) {
                                // We have a list of *TypeNames but we need a list of Types.
-                               list := make([]Type, len(sig.rparams))
-                               for i, t := range sig.rparams {
+                               list := make([]Type, sig.RParams().Len())
+                               for i, t := range sig.RParams().list() {
                                        list[i] = t.typ
                                }
                                smap := makeSubstMap(recvTParams, list)
-                               for i, tname := range sig.rparams {
+                               for i, tname := range sig.RParams().list() {
                                        bound := recvTParams[i].typ.(*TypeParam).bound
                                        // bound is (possibly) parameterized in the context of the
                                        // receiver type declaration. Substitute parameters for the
index fc548f7c5891d85ffdd5b92bcb985481b97af8d4..29e298103bf8f0fd5e59735d841e2276e40b25ef 100644 (file)
@@ -25,12 +25,12 @@ func TestSizeof(t *testing.T) {
                {Struct{}, 24, 48},
                {Pointer{}, 8, 16},
                {Tuple{}, 12, 24},
-               {Signature{}, 44, 88},
+               {Signature{}, 28, 56},
                {Union{}, 24, 48},
                {Interface{}, 40, 80},
                {Map{}, 16, 32},
                {Chan{}, 12, 24},
-               {Named{}, 84, 160},
+               {Named{}, 76, 144},
                {TypeParam{}, 28, 48},
                {top{}, 0, 0},
 
index 42be508cd91c73f8b44b41d25f1b1679925735c9..197d79b6a8da7820045fb2199e4f9d22cfdf402a 100644 (file)
@@ -203,7 +203,7 @@ func (subst *subster) typ(typ Type) Type {
                if len(t.targs) > 0 {
                        // already instantiated
                        dump(">>> %s already instantiated", t)
-                       assert(len(t.targs) == len(t.TParams()))
+                       assert(len(t.targs) == t.TParams().Len())
                        // For each (existing) type argument targ, determine if it needs
                        // to be substituted; i.e., if it is or contains a type parameter
                        // that has a type argument for it.
@@ -213,7 +213,7 @@ func (subst *subster) typ(typ Type) Type {
                                if newTarg != targ {
                                        dump(">>> substituted %d targ %s => %s", i, targ, newTarg)
                                        if newTargs == nil {
-                                               newTargs = make([]Type, len(t.TParams()))
+                                               newTargs = make([]Type, t.TParams().Len())
                                                copy(newTargs, t.targs)
                                        }
                                        newTargs[i] = newTarg
index bb5b28cdf8731a9e81d8bb38ab98f0529f25afa8..8c18b52a9a926781a3955b97c72120026607c19a 100644 (file)
@@ -28,15 +28,19 @@ type TypeParam struct {
        bound Type // *Named or *Interface; underlying type is always *Interface
 }
 
-// NewTypeParam returns a new TypeParam.  bound can be nil (and set later).
-func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam {
+// NewTypeParam returns a new TypeParam. Type parameters may be set on a Named
+// or Signature type by calling SetTParams. Setting a type parameter on more
+// than one type will result in a panic.
+//
+// The bound argument can be nil, and set later via SetBound.
+func (check *Checker) NewTypeParam(obj *TypeName, bound Type) *TypeParam {
        // Always increment lastID, even if it is not used.
        id := nextID()
        if check != nil {
                check.nextID++
                id = check.nextID
        }
-       typ := &TypeParam{check: check, id: id, obj: obj, index: index, bound: bound}
+       typ := &TypeParam{check: check, id: id, obj: obj, index: -1, bound: bound}
        if obj.typ == nil {
                obj.typ = typ
        }
@@ -56,6 +60,8 @@ func (t *TypeParam) _SetId(id uint64) {
        t.id = id
 }
 
+// TODO(rfindley): document the Bound and SetBound methods.
+
 func (t *TypeParam) Bound() *Interface {
        // we may not have an interface (error reported elsewhere)
        iface, _ := under(t.bound).(*Interface)
@@ -72,7 +78,7 @@ func (t *TypeParam) Bound() *Interface {
        return iface
 }
 
-func (t *TypeParam) _SetBound(bound Type) {
+func (t *TypeParam) SetBound(bound Type) {
        if bound == nil {
                panic("internal error: bound must not be nil")
        }
@@ -82,6 +88,42 @@ func (t *TypeParam) _SetBound(bound Type) {
 func (t *TypeParam) Underlying() Type { return t }
 func (t *TypeParam) String() string   { return TypeString(t, nil) }
 
+// TypeParams holds a list of type parameters bound to a type.
+type TypeParams struct{ tparams []*TypeName }
+
+// Len returns the number of type parameters in the list.
+// It is safe to call on a nil receiver.
+func (tps *TypeParams) Len() int {
+       return len(tps.list())
+}
+
+// At returns the i'th type parameter in the list.
+// It is safe to call on a nil receiver.
+func (tps *TypeParams) At(i int) *TypeName {
+       return tps.list()[i]
+}
+
+func (tps *TypeParams) list() []*TypeName {
+       if tps == nil {
+               return nil
+       }
+       return tps.tparams
+}
+
+func bindTParams(list []*TypeName) *TypeParams {
+       if len(list) == 0 {
+               return nil
+       }
+       for i, tp := range list {
+               typ := tp.Type().(*TypeParam)
+               if typ.index >= 0 {
+                       panic("internal error: type parameter bound more than once")
+               }
+               typ.index = i
+       }
+       return &TypeParams{tparams: list}
+}
+
 // ----------------------------------------------------------------------------
 // Implementation
 
index ef3808230ad8823c76bbb725ef0705a069da75a0..18c436e3efb0f9f53a8b12103d07ceef1228447d 100644 (file)
@@ -278,7 +278,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
                        buf.WriteByte(']')
                } else if t.TParams() != nil {
                        // parameterized type
-                       writeTParamList(buf, t.TParams(), qf, visited)
+                       writeTParamList(buf, t.TParams().list(), qf, visited)
                }
 
        case *TypeParam:
@@ -425,7 +425,7 @@ func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
 
 func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
        if sig.tparams != nil {
-               writeTParamList(buf, sig.tparams, qf, visited)
+               writeTParamList(buf, sig.TParams().list(), qf, visited)
        }
 
        writeTuple(buf, sig.params, sig.variadic, qf, visited)