]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile/internal/types2: use a TypeList type to hold type arguments
authorRobert Griesemer <gri@golang.org>
Tue, 24 Aug 2021 03:43:57 +0000 (20:43 -0700)
committerRobert Griesemer <gri@golang.org>
Tue, 24 Aug 2021 16:36:55 +0000 (16:36 +0000)
This is a port of CL 343933 from go/types with the necessary
adjustments in the compiler.

With this CL type parameters and type lists are now held in
TParamList and TypeList data types which don't expose the
internal representation.

Change-Id: I6d60881b5db995dbc04ed3f4a96e8b5d41f83969
Reviewed-on: https://go-review.googlesource.com/c/go/+/344615
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Dan Scales <danscales@google.com>
15 files changed:
src/cmd/compile/internal/importer/iimport.go
src/cmd/compile/internal/noder/expr.go
src/cmd/compile/internal/noder/types.go
src/cmd/compile/internal/noder/writer.go
src/cmd/compile/internal/types2/infer.go
src/cmd/compile/internal/types2/instantiate.go
src/cmd/compile/internal/types2/lookup.go
src/cmd/compile/internal/types2/named.go
src/cmd/compile/internal/types2/predicates.go
src/cmd/compile/internal/types2/sizeof_test.go
src/cmd/compile/internal/types2/subst.go
src/cmd/compile/internal/types2/typelists.go [new file with mode: 0644]
src/cmd/compile/internal/types2/typeparam.go
src/cmd/compile/internal/types2/typestring.go
src/cmd/compile/internal/types2/unify.go

index a46971d0a7f1f40cf8af513a5ffab037eee28d7b..c303126ea635c9e16a369ac0ebffbb1aae81df07 100644 (file)
@@ -346,10 +346,10 @@ func (r *importReader) obj(name string) {
                                // rparams of the method (since those are the
                                // typeparams being used in the method sig/body).
                                targs := baseType(msig.Recv().Type()).TArgs()
-                               if len(targs) > 0 {
-                                       rparams := make([]*types2.TypeParam, len(targs))
-                                       for i, targ := range targs {
-                                               rparams[i] = types2.AsTypeParam(targ)
+                               if targs.Len() > 0 {
+                                       rparams := make([]*types2.TypeParam, targs.Len())
+                                       for i := range rparams {
+                                               rparams[i] = types2.AsTypeParam(targs.At(i))
                                        }
                                        msig.SetRParams(rparams)
                                }
index 3e3c352a32f69533ced634c035148391985498be..cb20d645aa7019a052221fc1b38130052991bdb5 100644 (file)
@@ -360,9 +360,9 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto
                                // selinfo.Targs() are the types used to
                                // instantiate the type of receiver
                                targs2 := getTargs(selinfo)
-                               targs := make([]ir.Node, len(targs2))
-                               for i, targ2 := range targs2 {
-                                       targs[i] = ir.TypeNode(g.typ(targ2))
+                               targs := make([]ir.Node, targs2.Len())
+                               for i := range targs {
+                                       targs[i] = ir.TypeNode(g.typ(targs2.At(i)))
                                }
 
                                // Create function instantiation with the type
@@ -386,7 +386,7 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto
 }
 
 // getTargs gets the targs associated with the receiver of a selected method
-func getTargs(selinfo *types2.Selection) []types2.Type {
+func getTargs(selinfo *types2.Selection) *types2.TypeList {
        r := deref2(selinfo.Recv())
        n := types2.AsNamed(r)
        if n == nil {
index dd1fdcf96b56c5cb0d727764d53b9a966838d620..541ed68ef30e580d157098dc14a3afec9c8fb9da 100644 (file)
@@ -66,10 +66,12 @@ func (g *irgen) typ1(typ types2.Type) *types.Type {
 
 // instTypeName2 creates a name for an instantiated type, base on the type args
 // (given as types2 types).
-func instTypeName2(name string, targs []types2.Type) string {
+func instTypeName2(name string, targs *types2.TypeList) string {
        b := bytes.NewBufferString(name)
        b.WriteByte('[')
-       for i, targ := range targs {
+       n := targs.Len()
+       for i := 0; i < n; i++ {
+               targ := targs.At(i)
                if i > 0 {
                        b.WriteByte(',')
                }
@@ -140,9 +142,10 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
                        // non-generic types used to instantiate this type. We'll
                        // use these when instantiating the methods of the
                        // instantiated type.
-                       rparams := make([]*types.Type, len(typ.TArgs()))
-                       for i, targ := range typ.TArgs() {
-                               rparams[i] = g.typ1(targ)
+                       targs := typ.TArgs()
+                       rparams := make([]*types.Type, targs.Len())
+                       for i := range rparams {
+                               rparams[i] = g.typ1(targs.At(i))
                        }
                        ntyp.SetRParams(rparams)
                        //fmt.Printf("Saw new type %v %v\n", instName, ntyp.HasTParam())
@@ -267,9 +270,10 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
 // and for actually generating the methods for instantiated types.
 func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) {
        if typ.NumMethods() != 0 {
-               targs := make([]*types.Type, len(typ.TArgs()))
-               for i, targ := range typ.TArgs() {
-                       targs[i] = g.typ1(targ)
+               targs2 := typ.TArgs()
+               targs := make([]*types.Type, targs2.Len())
+               for i := range targs {
+                       targs[i] = g.typ1(targs2.At(i))
                }
 
                methods := make([]*types.Field, typ.NumMethods())
index 02df9a43de169211643a72173647794c7ded82c0..a6bd8b2426d41275f1fb73795dfab4ff69ef0e05 100644 (file)
@@ -299,7 +299,7 @@ func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) typeInfo {
                // Type aliases can refer to uninstantiated generic types, so we
                // might see len(TParams) != 0 && len(TArgs) == 0 here.
                // TODO(mdempsky): Revisit after #46477 is resolved.
-               assert(typ.TParams().Len() == len(typ.TArgs()) || len(typ.TArgs()) == 0)
+               assert(typ.TParams().Len() == typ.TArgs().Len() || typ.TArgs().Len() == 0)
 
                // TODO(mdempsky): Why do we need to loop here?
                orig := typ
@@ -441,10 +441,10 @@ func (w *writer) param(param *types2.Var) {
 
 // @@@ Objects
 
-func (w *writer) obj(obj types2.Object, explicits []types2.Type) {
-       explicitInfos := make([]typeInfo, len(explicits))
-       for i, explicit := range explicits {
-               explicitInfos[i] = w.p.typIdx(explicit, w.dict)
+func (w *writer) obj(obj types2.Object, explicits *types2.TypeList) {
+       explicitInfos := make([]typeInfo, explicits.Len())
+       for i := range explicitInfos {
+               explicitInfos[i] = w.p.typIdx(explicits.At(i), w.dict)
        }
        info := objInfo{idx: w.p.objIdx(obj), explicits: explicitInfos}
 
@@ -1212,7 +1212,7 @@ func (w *writer) expr(expr syntax.Expr) {
        if obj != nil {
                if isGlobal(obj) {
                        w.code(exprName)
-                       w.obj(obj, targs)
+                       w.obj(obj, types2.NewTypeList(targs))
                        return
                }
 
@@ -1321,7 +1321,7 @@ func (w *writer) expr(expr syntax.Expr) {
 
                                // As if w.expr(expr.Fun), but using inf.TArgs instead.
                                w.code(exprName)
-                               w.obj(obj, inf.TArgs)
+                               w.obj(obj, types2.NewTypeList(inf.TArgs))
                        } else {
                                w.expr(expr.Fun)
                        }
@@ -1711,7 +1711,7 @@ func (w *writer) pkgDecl(decl syntax.Decl) {
                // TODO(mdempsky): Revisit after #46477 is resolved.
                if name.IsAlias() {
                        named, ok := name.Type().(*types2.Named)
-                       if ok && named.TParams().Len() != 0 && len(named.TArgs()) == 0 {
+                       if ok && named.TParams().Len() != 0 && named.TArgs().Len() == 0 {
                                break
                        }
                }
index 6e4fe502b6c6c65c3a1a7a629108030c4735c9d3..5badecc0700e2f2f6154eb82d1e40868fce658f2 100644 (file)
@@ -335,7 +335,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) {
                return w.isParameterized(t.elem)
 
        case *Named:
-               return w.isParameterizedTypeList(t.targs)
+               return w.isParameterizedTypeList(t.targs.list())
 
        case *TypeParam:
                // t must be one of w.tparams
index 06cbcda58ea0fb8d0bc006193b0c75d66843e0f7..8bea63ec862a7f950ad1211594cf7b6effda2ec7 100644 (file)
@@ -137,7 +137,7 @@ func (check *Checker) instance(pos syntax.Pos, typ Type, targs []Type) (res Type
 
                tname := NewTypeName(pos, t.obj.pkg, t.obj.name, nil)
                named := check.newNamed(tname, t, nil, nil, nil) // methods and tparams are set when named is loaded
-               named.targs = targs
+               named.targs = NewTypeList(targs)
                named.instance = &instance{pos}
                if check != nil {
                        check.typMap[h] = named
@@ -145,7 +145,7 @@ func (check *Checker) instance(pos syntax.Pos, typ Type, targs []Type) (res Type
                res = named
        case *Signature:
                tparams := t.TParams()
-               if !check.validateTArgLen(pos, tparams, targs) {
+               if !check.validateTArgLen(pos, tparams.Len(), len(targs)) {
                        return Typ[Invalid]
                }
                if tparams.Len() == 0 {
@@ -180,14 +180,14 @@ func (check *Checker) instance(pos syntax.Pos, typ Type, targs []Type) (res Type
 // validateTArgLen verifies that the length of targs and tparams matches,
 // reporting an error if not. If validation fails and check is nil,
 // validateTArgLen panics.
-func (check *Checker) validateTArgLen(pos syntax.Pos, tparams *TParamList, targs []Type) bool {
-       if len(targs) != tparams.Len() {
+func (check *Checker) validateTArgLen(pos syntax.Pos, ntparams, ntargs int) bool {
+       if ntargs != ntparams {
                // TODO(gri) provide better error message
                if check != nil {
-                       check.errorf(pos, "got %d arguments but %d type parameters", len(targs), tparams.Len())
+                       check.errorf(pos, "got %d arguments but %d type parameters", ntargs, ntparams)
                        return false
                }
-               panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), tparams.Len()))
+               panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, ntargs, ntparams))
        }
        return true
 }
index 668c5ff3ec643fe81f01d36a69c3e275fd92a7d1..d0718e51e2d5848a583410a1bf781d495e35ed28 100644 (file)
@@ -394,10 +394,10 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
                        // 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().list()) != len(Vn.targs) {
+                       if len(ftyp.RParams().list()) != Vn.targs.Len() {
                                return
                        }
-                       ftyp = check.subst(nopos, ftyp, makeSubstMap(ftyp.RParams().list(), Vn.targs), nil).(*Signature)
+                       ftyp = check.subst(nopos, ftyp, makeSubstMap(ftyp.RParams().list(), Vn.targs.list()), nil).(*Signature)
                }
 
                // If the methods have type parameters we don't care whether they
index db12b08e6751436df2cb9586ec7953c23bccb4b5..a3a2595a22218b1ccd47e1be0594012c7c1d334e 100644 (file)
@@ -21,7 +21,7 @@ type Named struct {
        underlying Type        // possibly a *Named during setup; never a *Named once set up completely
        instance   *instance   // position information for lazy instantiation, or nil
        tparams    *TParamList // type parameters, or nil
-       targs      []Type      // type arguments (after instantiation), or nil
+       targs      *TypeList   // 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
 
        resolve func(*Named) ([]*TypeParam, Type, []*Func)
@@ -46,7 +46,7 @@ func (t *Named) load() *Named {
        // underlying is set when t is expanded.
        //
        // By convention, a type instance is loaded iff its tparams are set.
-       if len(t.targs) > 0 && t.tparams == nil {
+       if t.targs.Len() > 0 && t.tparams == nil {
                t.orig.load()
                t.tparams = t.orig.tparams
                t.methods = t.orig.methods
@@ -128,8 +128,8 @@ func (t *Named) TParams() *TParamList { return t.load().tparams }
 // SetTParams sets the type parameters of the named type t.
 func (t *Named) SetTParams(tparams []*TypeParam) { t.load().tparams = bindTParams(tparams) }
 
-// 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 }
+// TArgs returns the type arguments used to instantiate the named type t.
+func (t *Named) TArgs() *TypeList { return t.targs }
 
 // NumMethods returns the number of explicit methods whose receiver is named type t.
 func (t *Named) NumMethods() int { return len(t.load().methods) }
@@ -259,7 +259,7 @@ func (n *Named) expand(typMap map[string]*Named) *Named {
                // explicit is harmless: load is idempotent.
                n.load()
                var u Type
-               if n.check.validateTArgLen(n.instance.pos, n.tparams, n.targs) {
+               if n.check.validateTArgLen(n.instance.pos, n.tparams.Len(), n.targs.Len()) {
                        if typMap == nil {
                                if n.check != nil {
                                        typMap = n.check.typMap
@@ -268,11 +268,11 @@ func (n *Named) expand(typMap map[string]*Named) *Named {
                                        // type-checking pass. In that case we won't have a pre-existing
                                        // typMap, but don't want to create a duplicate of the current instance
                                        // in the process of expansion.
-                                       h := instantiatedHash(n.orig, n.targs)
+                                       h := instantiatedHash(n.orig, n.targs.list())
                                        typMap = map[string]*Named{h: n}
                                }
                        }
-                       u = n.check.subst(n.instance.pos, n.orig.underlying, makeSubstMap(n.TParams().list(), n.targs), typMap)
+                       u = n.check.subst(n.instance.pos, n.orig.underlying, makeSubstMap(n.TParams().list(), n.targs.list()), typMap)
                } else {
                        u = Typ[Invalid]
                }
index ed62743f6d6efe4d3ac31d8471608fe41dfc0d0b..3ccafef990c0073a931c0d51f59522f9db743af0 100644 (file)
@@ -305,8 +305,8 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
                        x.expand(nil)
                        y.expand(nil)
 
-                       xargs := x.TArgs()
-                       yargs := y.TArgs()
+                       xargs := x.TArgs().list()
+                       yargs := y.TArgs().list()
 
                        if len(xargs) != len(yargs) {
                                return false
index 718d2d266a39fd10878372bc5f6d607c49d6e157..5be369d84389c873b7395212a6779ccdb5611cd3 100644 (file)
@@ -31,7 +31,7 @@ func TestSizeof(t *testing.T) {
                {Interface{}, 40, 80},
                {Map{}, 16, 32},
                {Chan{}, 12, 24},
-               {Named{}, 80, 152},
+               {Named{}, 72, 136},
                {TypeParam{}, 28, 48},
                {term{}, 12, 24},
                {top{}, 0, 0},
index 467066cc698b924f343534b89d0cb98f7566de49..918e5f3043b59ed7844499a936caceeb18f74f59 100644 (file)
@@ -188,21 +188,21 @@ func (subst *subster) typ(typ Type) Type {
                }
 
                var newTArgs []Type
-               assert(len(t.targs) == t.TParams().Len())
+               assert(t.targs.Len() == t.TParams().Len())
 
                // already instantiated
                dump(">>> %s already instantiated", t)
                // 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.
-               for i, targ := range t.targs {
+               for i, targ := range t.targs.list() {
                        dump(">>> %d targ = %s", i, targ)
                        new_targ := subst.typ(targ)
                        if new_targ != targ {
                                dump(">>> substituted %d targ %s => %s", i, targ, new_targ)
                                if newTArgs == nil {
                                        newTArgs = make([]Type, t.TParams().Len())
-                                       copy(newTArgs, t.targs)
+                                       copy(newTArgs, t.targs.list())
                                }
                                newTArgs[i] = new_targ
                        }
@@ -230,7 +230,7 @@ func (subst *subster) typ(typ Type) Type {
                // It's ok to provide a nil *Checker because the newly created type
                // doesn't need to be (lazily) expanded; it's expanded below.
                named := (*Checker)(nil).newNamed(tname, t.orig, nil, t.tparams, t.methods) // t is loaded, so tparams and methods are available
-               named.targs = newTArgs
+               named.targs = NewTypeList(newTArgs)
                subst.typMap[h] = named
                t.expand(subst.typMap) // must happen after typMap update to avoid infinite recursion
 
diff --git a/src/cmd/compile/internal/types2/typelists.go b/src/cmd/compile/internal/types2/typelists.go
new file mode 100644 (file)
index 0000000..3258a5e
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types2
+
+// TParamList holds a list of type parameters.
+type TParamList struct{ tparams []*TypeParam }
+
+// Len returns the number of type parameters in the list.
+// It is safe to call on a nil receiver.
+func (l *TParamList) Len() int { return len(l.list()) }
+
+// At returns the i'th type parameter in the list.
+func (l *TParamList) At(i int) *TypeParam { return l.tparams[i] }
+
+// list is for internal use where we expect a []*TypeParam.
+// TODO(rfindley): list should probably be eliminated: we can pass around a
+// TParamList instead.
+func (l *TParamList) list() []*TypeParam {
+       if l == nil {
+               return nil
+       }
+       return l.tparams
+}
+
+// TypeList holds a list of types.
+type TypeList struct{ types []Type }
+
+// NewTypeList returns a new TypeList with the types in list.
+func NewTypeList(list []Type) *TypeList {
+       if len(list) == 0 {
+               return nil
+       }
+       return &TypeList{list}
+}
+
+// Len returns the number of types in the list.
+// It is safe to call on a nil receiver.
+func (l *TypeList) Len() int { return len(l.list()) }
+
+// At returns the i'th type in the list.
+func (l *TypeList) At(i int) Type { return l.types[i] }
+
+// list is for internal use where we expect a []Type.
+// TODO(rfindley): list should probably be eliminated: we can pass around a
+// TypeList instead.
+func (l *TypeList) list() []Type {
+       if l == nil {
+               return nil
+       }
+       return l.types
+}
+
+// ----------------------------------------------------------------------------
+// Implementation
+
+func bindTParams(list []*TypeParam) *TParamList {
+       if len(list) == 0 {
+               return nil
+       }
+       for i, typ := range list {
+               if typ.index >= 0 {
+                       panic("type parameter bound more than once")
+               }
+               typ.index = i
+       }
+       return &TParamList{tparams: list}
+}
index 0d76dd1a6ed507e43d2a34231e42af9549405744..445337fee88ed85b5a8bd6f3e661ff2cd4815682 100644 (file)
@@ -83,40 +83,6 @@ func (t *TypeParam) SetConstraint(bound Type) {
 func (t *TypeParam) Underlying() Type { return t }
 func (t *TypeParam) String() string   { return TypeString(t, nil) }
 
-// TParamList holds a list of type parameters bound to a type.
-type TParamList struct{ tparams []*TypeParam }
-
-// Len returns the number of type parameters in the list.
-// It is safe to call on a nil receiver.
-func (tps *TParamList) Len() int {
-       return len(tps.list())
-}
-
-// At returns the i'th type parameter in the list.
-func (tps *TParamList) At(i int) *TypeParam {
-       return tps.list()[i]
-}
-
-func (tps *TParamList) list() []*TypeParam {
-       if tps == nil {
-               return nil
-       }
-       return tps.tparams
-}
-
-func bindTParams(list []*TypeParam) *TParamList {
-       if len(list) == 0 {
-               return nil
-       }
-       for i, typ := range list {
-               if typ.index >= 0 {
-                       panic("type parameter bound more than once")
-               }
-               typ.index = i
-       }
-       return &TParamList{tparams: list}
-}
-
 // ----------------------------------------------------------------------------
 // Implementation
 
index 5759118c94c04fec4983677aed83ed847d54068e..2c34d036db8cbff8e9783fe85ae5530c52868fd1 100644 (file)
@@ -202,7 +202,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
                if t.targs != nil {
                        // instantiated type
                        buf.WriteByte('[')
-                       writeTypeList(buf, t.targs, qf, visited)
+                       writeTypeList(buf, t.targs.list(), qf, visited)
                        buf.WriteByte(']')
                } else if t.TParams().Len() != 0 {
                        // parameterized type
index 58f5c17e5f4dddb3e955c93fb9b41ae313977855..d4fbebc11b382e51dd995a3db79f4b8694bf8718 100644 (file)
@@ -429,13 +429,17 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool {
                if y, ok := y.(*Named); ok {
                        x.expand(nil)
                        y.expand(nil)
+
+                       xargs := x.targs.list()
+                       yargs := y.targs.list()
+
                        // TODO(gri) This is not always correct: two types may have the same names
                        //           in the same package if one of them is nested in a function.
                        //           Extremely unlikely but we need an always correct solution.
                        if x.obj.pkg == y.obj.pkg && x.obj.name == y.obj.name {
-                               assert(len(x.targs) == len(y.targs))
-                               for i, x := range x.targs {
-                                       if !u.nify(x, y.targs[i], p) {
+                               assert(len(xargs) == len(yargs))
+                               for i, x := range xargs {
+                                       if !u.nify(x, yargs[i], p) {
                                                return false
                                        }
                                }