// 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)
}
// 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
}
// 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 {
// 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(',')
}
// 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())
// 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())
// 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
// @@@ 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}
if obj != nil {
if isGlobal(obj) {
w.code(exprName)
- w.obj(obj, targs)
+ w.obj(obj, types2.NewTypeList(targs))
return
}
// 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)
}
// 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
}
}
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
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
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 {
// 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
}
// 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
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)
// 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
// 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) }
// 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
// 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]
}
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
{Interface{}, 40, 80},
{Map{}, 16, 32},
{Chan{}, 12, 24},
- {Named{}, 80, 152},
+ {Named{}, 72, 136},
{TypeParam{}, 28, 48},
{term{}, 12, 24},
{top{}, 0, 0},
}
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
}
// 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
--- /dev/null
+// 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}
+}
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
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
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
}
}