mirror of https://github.com/golang/go.git
go/types: move tparams field out of TypeName and into Named
Type parameters are a property of the type, not the type name. Change-Id: I479eafea80f9bfbd638e688ac0747cfa52df5da1
This commit is contained in:
parent
1a93d0a2ca
commit
d45f7ef80d
|
|
@ -6,9 +6,9 @@ TODO
|
|||
- interface embedding doesn't take care of literal type constraints yet
|
||||
(need an allTypes list, like we have an allMethods list?)
|
||||
- type assertions on/against parameterized types
|
||||
- consolidate Signature.tparams and Signature.mtparams?
|
||||
- can we always set Named.targs?
|
||||
- use []*TypeParam for tparams in subst
|
||||
- move Func.tparams to Signature (as we have done for TypeName.tparams to Named)
|
||||
- distinguish more clearly between Signature.tparams and mtparams (the latter are solely for recv type params)
|
||||
- use []*TypeParam for tparams in subst? (unclear)
|
||||
|
||||
OPEN ISSUES
|
||||
- using a contract and enumerating type arguments currently leads to an error (e.g. func f(type T C(T)) (x T) ... )
|
||||
|
|
@ -29,6 +29,13 @@ DESIGN/IMPLEMENTATION
|
|||
|
||||
is not valid, no matter how T1 and T2 are instantiated (but if T1 and T2 were type aliases with
|
||||
both of them having type int, the return x would be valid). In fact, the type parameters act more
|
||||
like named types. With their underlying type being the interface by which they are bound.
|
||||
like named types with the methods described by their type bound. But type parameters are never
|
||||
interfaces. To determine: Given a type parameter P, is P == underlying(P) (like for basic types),
|
||||
or is the the underlying type of P something else (like for defined types). Is there an observable
|
||||
difference?
|
||||
|
||||
- 12/19/2019: rewrote contract handling: they are now treated as Objects not Types throughout
|
||||
- 12/19/2019: Rewrote contract handling: they are now treated as Objects (rather than Types) throughout.
|
||||
|
||||
- 12/20/2019: Decided to start moving type parameters to types (from TypeName to Named), need to do the
|
||||
same for Func. This make more sense as in general any type (conceptually even literal types) could
|
||||
have type parameters. It's a property of the type, not the type name. It also simplified the code.
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ func (check *Checker) contractDecl(contr *Contract, e *ast.ContractSpec) {
|
|||
if named == nil {
|
||||
index := tpar.typ.(*TypeParam).index
|
||||
tname := NewTypeName(e.Pos(), check.pkg, contr.name+string(subscript(uint64(index))), nil)
|
||||
tname.tparams = tparams
|
||||
named = NewNamed(tname, new(Interface), nil)
|
||||
named.tparams = tparams
|
||||
bounds[tpar] = named
|
||||
}
|
||||
return named
|
||||
|
|
|
|||
|
|
@ -572,7 +572,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) {
|
|||
|
||||
if tdecl.TParams != nil {
|
||||
check.openScope(tdecl, "type parameters")
|
||||
obj.tparams = check.collectTypeParams(tdecl.TParams)
|
||||
named.tparams = check.collectTypeParams(tdecl.TParams)
|
||||
}
|
||||
|
||||
// determine underlying type of named
|
||||
|
|
@ -779,7 +779,7 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
|
|||
if rname != nil {
|
||||
// recv should be a Named type (otherwise an error is reported elsewhere)
|
||||
if recv, _ := check.genericType(rname).(*Named); recv != nil {
|
||||
recvTParams = recv.obj.tparams
|
||||
recvTParams = recv.tparams
|
||||
}
|
||||
}
|
||||
// provide type parameter bounds
|
||||
|
|
|
|||
|
|
@ -213,7 +213,6 @@ func (*Const) isDependency() {} // a constant may be a dependency of an initiali
|
|||
// A TypeName represents a name for a (defined or alias) type.
|
||||
type TypeName struct {
|
||||
object
|
||||
tparams []*TypeName // type parameters from left to right; or nil
|
||||
}
|
||||
|
||||
// NewTypeName returns a new type name denoting the given typ.
|
||||
|
|
@ -224,12 +223,7 @@ type TypeName struct {
|
|||
// argument for NewNamed, which will set the TypeName's type as a side-
|
||||
// effect.
|
||||
func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName {
|
||||
return &TypeName{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, nil}
|
||||
}
|
||||
|
||||
// IsParameterized reports whether obj is a parametrized type.
|
||||
func (obj *TypeName) IsParameterized() bool {
|
||||
return len(obj.tparams) > 0
|
||||
return &TypeName{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}}
|
||||
}
|
||||
|
||||
// IsAlias reports whether obj is an alias name for a type.
|
||||
|
|
@ -256,17 +250,6 @@ func (obj *TypeName) IsAlias() bool {
|
|||
}
|
||||
}
|
||||
|
||||
// TypeParams returns the list if *TypeParam types for the type parameters of obj; or nil.
|
||||
func (obj *TypeName) TypeParams() (tparams []*TypeParam) {
|
||||
if n := len(obj.tparams); n > 0 {
|
||||
tparams = make([]*TypeParam, n)
|
||||
for i, tpar := range obj.tparams {
|
||||
tparams[i] = tpar.typ.(*TypeParam)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// A Variable represents a declared variable (including function parameters and results, and struct fields).
|
||||
type Var struct {
|
||||
object
|
||||
|
|
@ -499,24 +482,6 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
|
|||
if _, ok := typ.(*Basic); ok {
|
||||
return
|
||||
}
|
||||
if tname.IsParameterized() {
|
||||
fmt.Fprint(buf, "(type ")
|
||||
for i, p := range tname.tparams {
|
||||
if i > 0 {
|
||||
fmt.Fprint(buf, ", ")
|
||||
}
|
||||
buf.WriteString(p.name)
|
||||
if p.typ != nil {
|
||||
if ptyp, _ := p.typ.(*TypeParam); ptyp != nil && ptyp.bound != nil {
|
||||
buf.WriteByte(' ')
|
||||
WriteType(buf, ptyp.bound, qf)
|
||||
// TODO(gri) if this is a generic type bound, we should print
|
||||
// the type parameters
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Fprint(buf, ")")
|
||||
}
|
||||
if tname.IsAlias() {
|
||||
buf.WriteString(" =")
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ func isNamed(typ Type) bool {
|
|||
func isGeneric(typ Type) bool {
|
||||
// A parameterized type is only instantiated if it doesn't have an instantiation already.
|
||||
named, _ := typ.(*Named)
|
||||
return named != nil && named.obj != nil && named.obj.IsParameterized() && named.targs == nil
|
||||
return named != nil && named.obj != nil && named.tparams != nil && named.targs == nil
|
||||
}
|
||||
|
||||
func is(typ Type, what BasicInfo) bool {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist
|
|||
var tparams []*TypeName
|
||||
switch typ := typ.(type) {
|
||||
case *Named:
|
||||
tparams = typ.obj.tparams
|
||||
tparams = typ.tparams
|
||||
case *Signature:
|
||||
tparams = typ.tparams
|
||||
default:
|
||||
|
|
@ -272,7 +272,7 @@ func (subst *subster) typ(typ Type) Type {
|
|||
}
|
||||
}
|
||||
|
||||
if len(t.obj.tparams) == 0 {
|
||||
if t.tparams == nil {
|
||||
dump(">>> %s is not parameterized", t)
|
||||
return t // type is not parameterized
|
||||
}
|
||||
|
|
@ -293,7 +293,7 @@ func (subst *subster) typ(typ Type) Type {
|
|||
if new_targ != targ {
|
||||
dump(">>> substituted %d targ %s => %s", i, targ, new_targ)
|
||||
if new_targs == nil {
|
||||
new_targs = make([]Type, len(t.obj.tparams))
|
||||
new_targs = make([]Type, len(t.tparams))
|
||||
copy(new_targs, t.targs)
|
||||
}
|
||||
new_targs[i] = new_targ
|
||||
|
|
@ -324,9 +324,9 @@ func (subst *subster) typ(typ Type) Type {
|
|||
|
||||
// create a new named type and populate caches to avoid endless recursion
|
||||
tname := NewTypeName(subst.pos, subst.check.pkg, name, nil)
|
||||
tname.tparams = t.obj.tparams // new type is still parameterized
|
||||
subst.check.typMap[name] = tname
|
||||
named := NewNamed(tname, nil, nil)
|
||||
named.tparams = t.tparams // new type is still parameterized
|
||||
named.targs = new_targs
|
||||
subst.cache[t] = named
|
||||
dump(">>> subst %s(%s) with %s (new: %s)", t.underlying, subst.tpars, subst.targs, new_targs)
|
||||
|
|
|
|||
|
|
@ -474,12 +474,13 @@ func (c *Chan) Elem() Type { return c.elem }
|
|||
|
||||
// A Named represents a named (defined) type.
|
||||
type Named struct {
|
||||
info typeInfo // for cycle detection
|
||||
obj *TypeName // corresponding declared object
|
||||
orig 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
|
||||
targs []Type // type arguments after instantiation
|
||||
methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily
|
||||
info typeInfo // for cycle detection
|
||||
obj *TypeName // corresponding declared object
|
||||
orig 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
|
||||
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
|
||||
}
|
||||
|
||||
// NewNamed returns a new named type for the given type name, underlying type, and associated methods.
|
||||
|
|
|
|||
|
|
@ -259,16 +259,22 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
|
|||
|
||||
case *Named:
|
||||
writeTypeName(buf, t.obj, qf)
|
||||
// if t.obj != nil && len(t.obj.tparams) > 0 {
|
||||
// buf.WriteByte('(')
|
||||
// for i, tpar := range t.obj.tparams {
|
||||
// if i > 0 {
|
||||
// buf.WriteString(", ")
|
||||
// }
|
||||
// writeType(buf, tpar.typ, qf, visited)
|
||||
// }
|
||||
// buf.WriteByte(')')
|
||||
// }
|
||||
if t.tparams != nil {
|
||||
buf.WriteString("(type ")
|
||||
for i, p := range t.tparams {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(p.name)
|
||||
if ptyp, _ := p.typ.(*TypeParam); ptyp != nil && ptyp.bound != nil {
|
||||
buf.WriteByte(' ')
|
||||
writeType(buf, ptyp.bound, qf, visited)
|
||||
// TODO(gri) if this is a generic type bound, we should print
|
||||
// the type parameters
|
||||
}
|
||||
}
|
||||
buf.WriteByte(')')
|
||||
}
|
||||
|
||||
case *TypeParam:
|
||||
var s string
|
||||
|
|
|
|||
Loading…
Reference in New Issue