mirror of https://github.com/golang/go.git
[dev.typeparams] go/types: set type parameter indices when they are bound
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>
This commit is contained in:
parent
311baf65f4
commit
6f57139c7a
|
|
@ -1828,7 +1828,7 @@ func TestInstantiate(t *testing.T) {
|
||||||
|
|
||||||
// type T should have one type parameter
|
// type T should have one type parameter
|
||||||
T := pkg.Scope().Lookup("T").Type().(*Named)
|
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)
|
t.Fatalf("expected 1 type parameter; found %d", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
// 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)
|
check.errorf(x, _Todo, "cannot use generic function %s without instantiation in %s", x, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
// type param is placed in the current package so export/import
|
||||||
// works as expected.
|
// works as expected.
|
||||||
tpar := NewTypeName(token.NoPos, check.pkg, "<type parameter>", nil)
|
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)
|
tsum := newUnion(rtypes, tildes)
|
||||||
ptyp.bound = &Interface{complete: true, tset: &TypeSet{types: tsum}}
|
ptyp.bound = &Interface{complete: true, tset: &TypeSet{types: tsum}}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
// check number of type arguments (got) vs number of type parameters (want)
|
||||||
sig := x.typ.(*Signature)
|
sig := x.typ.(*Signature)
|
||||||
got, want := len(targs), len(sig.tparams)
|
got, want := len(targs), sig.TParams().Len()
|
||||||
if got > want {
|
if got > want {
|
||||||
check.errorf(ix.Indices[got-1], _Todo, "got %d type arguments but want %d", got, want)
|
check.errorf(ix.Indices[got-1], _Todo, "got %d type arguments but want %d", got, want)
|
||||||
x.mode = invalid
|
x.mode = invalid
|
||||||
|
|
@ -39,7 +39,7 @@ func (check *Checker) funcInst(x *operand, ix *typeparams.IndexExpr) {
|
||||||
inferred := false
|
inferred := false
|
||||||
|
|
||||||
if got < want {
|
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 {
|
if targs == nil {
|
||||||
// error was already reported
|
// error was already reported
|
||||||
x.mode = invalid
|
x.mode = invalid
|
||||||
|
|
@ -160,7 +160,7 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind {
|
||||||
assert(len(targs) == len(ix.Indices))
|
assert(len(targs) == len(ix.Indices))
|
||||||
|
|
||||||
// check number of type arguments (got) vs number of type parameters (want)
|
// 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 {
|
if got > want {
|
||||||
check.errorf(ix.Indices[want], _Todo, "got %d type arguments but want %d", got, want)
|
check.errorf(ix.Indices[want], _Todo, "got %d type arguments but want %d", got, want)
|
||||||
check.use(call.Args...)
|
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
|
// if type inference failed, a parametrized result must be invalidated
|
||||||
// (operands cannot have a parametrized type)
|
// (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
|
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
|
// 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
|
// TODO(gri) provide position information for targs so we can feed
|
||||||
// it to the instantiate call for better error reporting
|
// 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 {
|
if targs == nil {
|
||||||
return // error already reported
|
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
|
// need to compute it from the adjusted list; otherwise we can
|
||||||
// simply use the result signature's parameter list.
|
// simply use the result signature's parameter list.
|
||||||
if adjusted {
|
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 {
|
} else {
|
||||||
sigParams = rsig.params
|
sigParams = rsig.params
|
||||||
}
|
}
|
||||||
|
|
@ -517,7 +517,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
|
||||||
// the signature accordingly.
|
// the signature accordingly.
|
||||||
// TODO(gri) factor this code out
|
// TODO(gri) factor this code out
|
||||||
sig := m.typ.(*Signature)
|
sig := m.typ.(*Signature)
|
||||||
if len(sig.rparams) > 0 {
|
if sig.RParams().Len() > 0 {
|
||||||
// For inference to work, we must use the receiver type
|
// For inference to work, we must use the receiver type
|
||||||
// matching the receiver in the actual method declaration.
|
// matching the receiver in the actual method declaration.
|
||||||
// If the method is embedded, the matching receiver is the
|
// 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
|
// the receiver type arguments here, the receiver must be be otherwise invalid
|
||||||
// and an error has been reported elsewhere.
|
// and an error has been reported elsewhere.
|
||||||
arg := operand{mode: variable, expr: x.expr, typ: recv}
|
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 {
|
if targs == nil {
|
||||||
// We may reach here if there were other errors (see issue #40056).
|
// We may reach here if there were other errors (see issue #40056).
|
||||||
goto Error
|
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.)
|
// (If we modify m, some tests will fail; possibly because the m is in use.)
|
||||||
// TODO(gri) investigate and provide a correct explanation here
|
// TODO(gri) investigate and provide a correct explanation here
|
||||||
copy := *m
|
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 = ©
|
obj = ©
|
||||||
}
|
}
|
||||||
// TODO(gri) we also need to do substitution for parameterized interface methods
|
// TODO(gri) we also need to do substitution for parameterized interface methods
|
||||||
|
|
|
||||||
|
|
@ -625,13 +625,13 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) {
|
||||||
named.underlying = under(named)
|
named.underlying = under(named)
|
||||||
|
|
||||||
// If the RHS is a type parameter, it must be from this type declaration.
|
// 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)
|
check.errorf(tdecl.Type, _Todo, "cannot use function type parameter %s as RHS in type declaration", tpar)
|
||||||
named.underlying = Typ[Invalid]
|
named.underlying = Typ[Invalid]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *Checker) collectTypeParams(list *ast.FieldList) []*TypeName {
|
func (check *Checker) collectTypeParams(list *ast.FieldList) *TypeParams {
|
||||||
var tparams []*TypeName
|
var tparams []*TypeName
|
||||||
// Declare type parameters up-front, with empty interface as type bound.
|
// Declare type parameters up-front, with empty interface as type bound.
|
||||||
// The scope of type parameters starts at the beginning of the type parameter
|
// 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)
|
index += len(f.Names)
|
||||||
}
|
}
|
||||||
|
|
||||||
return tparams
|
return bindTParams(tparams)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *Checker) declareTypeParams(tparams []*TypeName, names []*ast.Ident) []*TypeName {
|
func (check *Checker) declareTypeParams(tparams []*TypeName, names []*ast.Ident) []*TypeName {
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
tpar := NewTypeName(name.Pos(), check.pkg, name.Name, nil)
|
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
|
check.declare(check.scope, name, tpar, check.scope.pos) // TODO(gri) check scope position
|
||||||
tparams = append(tparams, tpar)
|
tparams = append(tparams, tpar)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst
|
||||||
return false
|
return false
|
||||||
|
|
||||||
case value:
|
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
|
// function instantiation
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ type instance struct {
|
||||||
func (n *Named) complete() {
|
func (n *Named) complete() {
|
||||||
if n.instance != nil && len(n.targs) > 0 && n.underlying == nil {
|
if n.instance != nil && len(n.targs) > 0 && n.underlying == nil {
|
||||||
check := n.instance.check
|
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.underlying = inst
|
||||||
n.fromRHS = inst
|
n.fromRHS = inst
|
||||||
n.methods = n.orig.methods
|
n.methods = n.orig.methods
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,9 @@ func (check *Checker) Instantiate(pos token.Pos, typ Type, targs []Type, posList
|
||||||
var tparams []*TypeName
|
var tparams []*TypeName
|
||||||
switch t := typ.(type) {
|
switch t := typ.(type) {
|
||||||
case *Named:
|
case *Named:
|
||||||
tparams = t.TParams()
|
tparams = t.TParams().list()
|
||||||
case *Signature:
|
case *Signature:
|
||||||
tparams = t.tparams
|
tparams = t.TParams().list()
|
||||||
defer func() {
|
defer func() {
|
||||||
// If we had an unexpected failure somewhere don't panic below when
|
// If we had an unexpected failure somewhere don't panic below when
|
||||||
// asserting res.(*Signature). Check for *Signature in case Typ[Invalid]
|
// 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 {
|
if base == nil {
|
||||||
panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
|
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.later(func() {
|
||||||
check.verify(pos, base.tparams, targs, posList)
|
check.verify(pos, base.tparams.list(), targs, posList)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
h := instantiatedHash(base, targs)
|
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)
|
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.targs = targs
|
||||||
named.instance = &instance{
|
named.instance = &instance{
|
||||||
check: check,
|
check: check,
|
||||||
|
|
|
||||||
|
|
@ -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
|
// both methods must have the same number of type parameters
|
||||||
ftyp := f.typ.(*Signature)
|
ftyp := f.typ.(*Signature)
|
||||||
mtyp := m.typ.(*Signature)
|
mtyp := m.typ.(*Signature)
|
||||||
if len(ftyp.tparams) != len(mtyp.tparams) {
|
if ftyp.TParams().Len() != mtyp.TParams().Len() {
|
||||||
return m, f
|
return m, f
|
||||||
}
|
}
|
||||||
if len(ftyp.tparams) > 0 {
|
if ftyp.TParams().Len() > 0 {
|
||||||
panic("internal error: method with type parameters")
|
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?
|
// TODO(gri) is this always correct? what about type bounds?
|
||||||
// (Alternative is to rename/subst type parameters and compare.)
|
// (Alternative is to rename/subst type parameters and compare.)
|
||||||
u := newUnifier(true)
|
u := newUnifier(true)
|
||||||
u.x.init(ftyp.tparams)
|
u.x.init(ftyp.TParams().list())
|
||||||
if !u.unify(ftyp, mtyp) {
|
if !u.unify(ftyp, mtyp) {
|
||||||
return m, f
|
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
|
// both methods must have the same number of type parameters
|
||||||
ftyp := f.typ.(*Signature)
|
ftyp := f.typ.(*Signature)
|
||||||
mtyp := m.typ.(*Signature)
|
mtyp := m.typ.(*Signature)
|
||||||
if len(ftyp.tparams) != len(mtyp.tparams) {
|
if ftyp.TParams().Len() != mtyp.TParams().Len() {
|
||||||
return m, f
|
return m, f
|
||||||
}
|
}
|
||||||
if len(ftyp.tparams) > 0 {
|
if ftyp.TParams().Len() > 0 {
|
||||||
panic("internal error: method with type parameters")
|
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
|
// In order to compare the signatures, substitute the receiver
|
||||||
// type parameters of ftyp with V's instantiation type arguments.
|
// type parameters of ftyp with V's instantiation type arguments.
|
||||||
// This lazily instantiates the signature of method f.
|
// 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
|
// Be careful: The number of type arguments may not match
|
||||||
// the number of receiver parameters. If so, an error was
|
// the number of receiver parameters. If so, an error was
|
||||||
// reported earlier but the length discrepancy is still
|
// reported earlier but the length discrepancy is still
|
||||||
// here. Exit early in this case to prevent an assertion
|
// here. Exit early in this case to prevent an assertion
|
||||||
// failure in makeSubstMap.
|
// failure in makeSubstMap.
|
||||||
// TODO(gri) Can we avoid this check by fixing the lengths?
|
// 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
|
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
|
// 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?
|
// TODO(gri) is this always correct? what about type bounds?
|
||||||
// (Alternative is to rename/subst type parameters and compare.)
|
// (Alternative is to rename/subst type parameters and compare.)
|
||||||
u := newUnifier(true)
|
u := newUnifier(true)
|
||||||
u.x.init(ftyp.rparams)
|
u.x.init(ftyp.RParams().list())
|
||||||
if !u.unify(ftyp, mtyp) {
|
if !u.unify(ftyp, mtyp) {
|
||||||
return m, f
|
return m, f
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ type Named struct {
|
||||||
orig *Named // original, uninstantiated type
|
orig *Named // original, uninstantiated type
|
||||||
fromRHS Type // type (on RHS of declaration) this *Named type is derived of (for cycle reporting)
|
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
|
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
|
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
|
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")
|
panic("invalid underlying type")
|
||||||
}
|
}
|
||||||
|
|
||||||
t.tparams = tparams
|
t.tparams = bindTParams(tparams)
|
||||||
t.underlying = underlying
|
t.underlying = underlying
|
||||||
t.methods = methods
|
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.
|
// 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
|
var inst *instance
|
||||||
if check != nil {
|
if check != nil {
|
||||||
inst = &instance{
|
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
|
// TODO(gri) Come up with a better representation and API to distinguish
|
||||||
// between parameterized instantiated and non-instantiated types.
|
// 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.
|
// 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.
|
// SetTParams sets the type parameters of the named type t.
|
||||||
func (t *Named) SetTParams(tparams []*TypeName) { t.expand().tparams = tparams }
|
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 }
|
func (t *Named) TArgs() []Type { return t.targs }
|
||||||
|
|
||||||
// SetTArgs sets the type arguments of the named type t.
|
// SetTArgs sets the type arguments of the named type t.
|
||||||
|
|
|
||||||
|
|
@ -429,8 +429,8 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
|
||||||
if _, ok := typ.(*Basic); ok {
|
if _, ok := typ.(*Basic); ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if named, _ := typ.(*Named); named != nil && len(named.tparams) > 0 {
|
if named, _ := typ.(*Named); named != nil && named.TParams().Len() > 0 {
|
||||||
writeTParamList(buf, named.tparams, qf, nil)
|
writeTParamList(buf, named.TParams().list(), qf, nil)
|
||||||
}
|
}
|
||||||
if tname.IsAlias() {
|
if tname.IsAlias() {
|
||||||
buf.WriteString(" =")
|
buf.WriteString(" =")
|
||||||
|
|
|
||||||
|
|
@ -242,7 +242,7 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
|
||||||
// parameter names.
|
// parameter names.
|
||||||
if y, ok := y.(*Signature); ok {
|
if y, ok := y.(*Signature); ok {
|
||||||
return x.variadic == y.variadic &&
|
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.params, y.params, cmpTags, p) &&
|
||||||
identical(x.results, y.results, cmpTags, p)
|
identical(x.results, y.results, cmpTags, p)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ type Signature struct {
|
||||||
// and store it in the Func Object) because when type-checking a function
|
// 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.
|
// 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.
|
// We then unpack the *Signature and use the scope for the literal body.
|
||||||
rparams []*TypeName // receiver type parameters from left to right, or nil
|
rparams *TypeParams // receiver type parameters from left to right, or nil
|
||||||
tparams []*TypeName // 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
|
scope *Scope // function scope, present for package-local signatures
|
||||||
recv *Var // nil if not a method
|
recv *Var // nil if not a method
|
||||||
params *Tuple // (incoming) parameters from left to right; or nil
|
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 }
|
func (s *Signature) Recv() *Var { return s.recv }
|
||||||
|
|
||||||
// TParams returns the type parameters of signature s, or nil.
|
// 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.
|
// 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.
|
// 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.
|
// Params returns the parameters of signature s, or nil.
|
||||||
func (s *Signature) Params() *Tuple { return s.params }
|
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
|
// blank identifiers were found => use rewritten receiver type
|
||||||
recvTyp = isubst(recvPar.List[0].Type, smap)
|
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
|
// determine receiver type to get its type parameters
|
||||||
// and the respective type parameter bounds
|
// and the respective type parameter bounds
|
||||||
var recvTParams []*TypeName
|
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.
|
// again when we type-check the signature.
|
||||||
// TODO(gri) maybe the receiver should be marked as invalid instead?
|
// TODO(gri) maybe the receiver should be marked as invalid instead?
|
||||||
if recv := asNamed(check.genericType(rname, false)); recv != nil {
|
if recv := asNamed(check.genericType(rname, false)); recv != nil {
|
||||||
recvTParams = recv.TParams()
|
recvTParams = recv.TParams().list()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// provide type parameter bounds
|
// provide type parameter bounds
|
||||||
// - only do this if we have the right number (otherwise an error is reported elsewhere)
|
// - 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.
|
// We have a list of *TypeNames but we need a list of Types.
|
||||||
list := make([]Type, len(sig.rparams))
|
list := make([]Type, sig.RParams().Len())
|
||||||
for i, t := range sig.rparams {
|
for i, t := range sig.RParams().list() {
|
||||||
list[i] = t.typ
|
list[i] = t.typ
|
||||||
}
|
}
|
||||||
smap := makeSubstMap(recvTParams, list)
|
smap := makeSubstMap(recvTParams, list)
|
||||||
for i, tname := range sig.rparams {
|
for i, tname := range sig.RParams().list() {
|
||||||
bound := recvTParams[i].typ.(*TypeParam).bound
|
bound := recvTParams[i].typ.(*TypeParam).bound
|
||||||
// bound is (possibly) parameterized in the context of the
|
// bound is (possibly) parameterized in the context of the
|
||||||
// receiver type declaration. Substitute parameters for the
|
// receiver type declaration. Substitute parameters for the
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,12 @@ func TestSizeof(t *testing.T) {
|
||||||
{Struct{}, 24, 48},
|
{Struct{}, 24, 48},
|
||||||
{Pointer{}, 8, 16},
|
{Pointer{}, 8, 16},
|
||||||
{Tuple{}, 12, 24},
|
{Tuple{}, 12, 24},
|
||||||
{Signature{}, 44, 88},
|
{Signature{}, 28, 56},
|
||||||
{Union{}, 24, 48},
|
{Union{}, 24, 48},
|
||||||
{Interface{}, 40, 80},
|
{Interface{}, 40, 80},
|
||||||
{Map{}, 16, 32},
|
{Map{}, 16, 32},
|
||||||
{Chan{}, 12, 24},
|
{Chan{}, 12, 24},
|
||||||
{Named{}, 84, 160},
|
{Named{}, 76, 144},
|
||||||
{TypeParam{}, 28, 48},
|
{TypeParam{}, 28, 48},
|
||||||
{top{}, 0, 0},
|
{top{}, 0, 0},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -203,7 +203,7 @@ func (subst *subster) typ(typ Type) Type {
|
||||||
if len(t.targs) > 0 {
|
if len(t.targs) > 0 {
|
||||||
// already instantiated
|
// already instantiated
|
||||||
dump(">>> %s already instantiated", t)
|
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
|
// For each (existing) type argument targ, determine if it needs
|
||||||
// to be substituted; i.e., if it is or contains a type parameter
|
// to be substituted; i.e., if it is or contains a type parameter
|
||||||
// that has a type argument for it.
|
// that has a type argument for it.
|
||||||
|
|
@ -213,7 +213,7 @@ func (subst *subster) typ(typ Type) Type {
|
||||||
if newTarg != targ {
|
if newTarg != targ {
|
||||||
dump(">>> substituted %d targ %s => %s", i, targ, newTarg)
|
dump(">>> substituted %d targ %s => %s", i, targ, newTarg)
|
||||||
if newTargs == nil {
|
if newTargs == nil {
|
||||||
newTargs = make([]Type, len(t.TParams()))
|
newTargs = make([]Type, t.TParams().Len())
|
||||||
copy(newTargs, t.targs)
|
copy(newTargs, t.targs)
|
||||||
}
|
}
|
||||||
newTargs[i] = newTarg
|
newTargs[i] = newTarg
|
||||||
|
|
|
||||||
|
|
@ -28,15 +28,19 @@ type TypeParam struct {
|
||||||
bound Type // *Named or *Interface; underlying type is always *Interface
|
bound Type // *Named or *Interface; underlying type is always *Interface
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTypeParam returns a new TypeParam. bound can be nil (and set later).
|
// NewTypeParam returns a new TypeParam. Type parameters may be set on a Named
|
||||||
func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam {
|
// 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.
|
// Always increment lastID, even if it is not used.
|
||||||
id := nextID()
|
id := nextID()
|
||||||
if check != nil {
|
if check != nil {
|
||||||
check.nextID++
|
check.nextID++
|
||||||
id = 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 {
|
if obj.typ == nil {
|
||||||
obj.typ = typ
|
obj.typ = typ
|
||||||
}
|
}
|
||||||
|
|
@ -56,6 +60,8 @@ func (t *TypeParam) _SetId(id uint64) {
|
||||||
t.id = id
|
t.id = id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(rfindley): document the Bound and SetBound methods.
|
||||||
|
|
||||||
func (t *TypeParam) Bound() *Interface {
|
func (t *TypeParam) Bound() *Interface {
|
||||||
// we may not have an interface (error reported elsewhere)
|
// we may not have an interface (error reported elsewhere)
|
||||||
iface, _ := under(t.bound).(*Interface)
|
iface, _ := under(t.bound).(*Interface)
|
||||||
|
|
@ -72,7 +78,7 @@ func (t *TypeParam) Bound() *Interface {
|
||||||
return iface
|
return iface
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TypeParam) _SetBound(bound Type) {
|
func (t *TypeParam) SetBound(bound Type) {
|
||||||
if bound == nil {
|
if bound == nil {
|
||||||
panic("internal error: bound must not be 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) Underlying() Type { return t }
|
||||||
func (t *TypeParam) String() string { return TypeString(t, nil) }
|
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
|
// Implementation
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -278,7 +278,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
|
||||||
buf.WriteByte(']')
|
buf.WriteByte(']')
|
||||||
} else if t.TParams() != nil {
|
} else if t.TParams() != nil {
|
||||||
// parameterized type
|
// parameterized type
|
||||||
writeTParamList(buf, t.TParams(), qf, visited)
|
writeTParamList(buf, t.TParams().list(), qf, visited)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *TypeParam:
|
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) {
|
func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
|
||||||
if sig.tparams != nil {
|
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)
|
writeTuple(buf, sig.params, sig.variadic, qf, visited)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue