1
0
mirror of https://github.com/golang/go synced 2024-11-26 08:27:56 -07:00

cmd/compile/internal/types2: add Named.SetTParams and Named.Orig methods

Named.SetTParams sets the type parameters for a named type.

Named.Orig returns the original generic type an instantiated
type is derived from. Added a new field orig for that purpose
and renamed the already existing orig field to fromRHS.

Finally, updated various comments.

Change-Id: Ic9d173e42740422d195713d8bdc62a54dc8c5f54
Reviewed-on: https://go-review.googlesource.com/c/go/+/309832
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2021-04-13 17:48:45 -07:00
parent 283f9fdbd3
commit 892cad7a9b
7 changed files with 38 additions and 30 deletions

View File

@ -333,7 +333,7 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
switch t.info { switch t.info {
case unknown: case unknown:
t.info = marked t.info = marked
t.info = check.validType(t.orig, append(path, t.obj)) // only types of current package added to path t.info = check.validType(t.fromRHS, append(path, t.obj)) // only types of current package added to path
case marked: case marked:
// cycle detected // cycle detected
for i, tn := range path { for i, tn := range path {
@ -611,9 +611,8 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
} else { } else {
// defined type declaration // defined type declaration
named := &Named{check: check, obj: obj} named := check.newNamed(obj, nil, nil, nil, nil)
def.setUnderlying(named) def.setUnderlying(named)
obj.typ = named // make sure recursive type declarations terminate
if tdecl.TParamList != nil { if tdecl.TParamList != nil {
check.openScope(tdecl, "type parameters") check.openScope(tdecl, "type parameters")
@ -622,7 +621,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
} }
// determine underlying type of named // determine underlying type of named
named.orig = check.definedType(tdecl.Type, named) named.fromRHS = check.definedType(tdecl.Type, named)
// The underlying type of named may be itself a named type that is // The underlying type of named may be itself a named type that is
// incomplete: // incomplete:
@ -637,7 +636,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
// and which has as its underlying type the named type B. // and which has as its underlying type the named type B.
// Determine the (final, unnamed) underlying type by resolving // Determine the (final, unnamed) underlying type by resolving
// any forward chain. // any forward chain.
// TODO(gri) Investigate if we can just use named.origin here // TODO(gri) Investigate if we can just use named.fromRHS here
// and rely on lazy computation of the underlying type. // and rely on lazy computation of the underlying type.
named.underlying = under(named) named.underlying = under(named)
} }

View File

@ -195,7 +195,7 @@ L7 uses var z int`
} }
} }
// This tests that the package associated with the types.Object.Pkg method // This tests that the package associated with the types2.Object.Pkg method
// is the type's package independent of the order in which the imports are // is the type's package independent of the order in which the imports are
// listed in the sources src1, src2 below. // listed in the sources src1, src2 below.
// The actual issue is in go/internal/gcimporter which has a corresponding // The actual issue is in go/internal/gcimporter which has a corresponding

View File

@ -126,8 +126,8 @@ func (s sanitizer) typ(typ Type) Type {
} }
case *Named: case *Named:
if orig := s.typ(t.orig); orig != t.orig { if orig := s.typ(t.fromRHS); orig != t.fromRHS {
t.orig = orig t.fromRHS = orig
} }
if under := s.typ(t.underlying); under != t.underlying { if under := s.typ(t.underlying); under != t.underlying {
t.underlying = under t.underlying = under

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// This file tests types.Check by using it to // This file tests types2.Check by using it to
// typecheck the standard library and tests. // typecheck the standard library and tests.
package types2_test package types2_test

View File

@ -385,8 +385,7 @@ func (subst *subster) typ(typ Type) Type {
// create a new named type and populate caches to avoid endless recursion // create a new named type and populate caches to avoid endless recursion
tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil) tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil)
named := subst.check.NewNamed(tname, t.underlying, t.methods) // method signatures are updated lazily named := subst.check.newNamed(tname, t, t.underlying, t.tparams, t.methods) // method signatures are updated lazily
named.tparams = t.tparams // new type is still parameterized
named.targs = new_targs named.targs = new_targs
subst.check.typMap[h] = named subst.check.typMap[h] = named
subst.cache[t] = named subst.cache[t] = named
@ -394,7 +393,7 @@ func (subst *subster) typ(typ Type) Type {
// do the substitution // do the substitution
dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, new_targs) dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, new_targs)
named.underlying = subst.typOrNil(t.underlying) named.underlying = subst.typOrNil(t.underlying)
named.orig = named.underlying // for cycle detection (Checker.validType) named.fromRHS = named.underlying // for cycle detection (Checker.validType)
return named return named

View File

@ -224,10 +224,10 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
if variadic { if variadic {
n := params.Len() n := params.Len()
if n == 0 { if n == 0 {
panic("types.NewSignature: variadic function must have at least one parameter") panic("types2.NewSignature: variadic function must have at least one parameter")
} }
if _, ok := params.At(n - 1).typ.(*Slice); !ok { if _, ok := params.At(n - 1).typ.(*Slice); !ok {
panic("types.NewSignature: variadic parameter must be of unnamed slice type") panic("types2.NewSignature: variadic parameter must be of unnamed slice type")
} }
} }
return &Signature{recv: recv, params: params, results: results, variadic: variadic} return &Signature{recv: recv, params: params, results: results, variadic: variadic}
@ -645,12 +645,15 @@ func (c *Chan) Dir() ChanDir { return c.dir }
// Elem returns the element type of channel c. // Elem returns the element type of channel c.
func (c *Chan) Elem() Type { return c.elem } func (c *Chan) Elem() Type { return c.elem }
// TODO(gri) Clean up Named struct below; specifically the fromRHS field (can we use underlying?).
// A Named represents a named (defined) type. // A Named represents a named (defined) type.
type Named struct { type Named struct {
check *Checker // for Named.under implementation check *Checker // for Named.under implementation
info typeInfo // for cycle detection info typeInfo // for cycle detection
obj *TypeName // corresponding declared object obj *TypeName // corresponding declared object
orig Type // type (on RHS of declaration) this *Named type is derived of (for cycle reporting) orig *Named // original, uninstantiated type
fromRHS Type // type (on RHS of declaration) this *Named type is derived from (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 []*TypeName // type parameters, or nil
targs []Type // type arguments (after instantiation), or nil targs []Type // type arguments (after instantiation), or nil
@ -662,17 +665,17 @@ type Named struct {
// The underlying type must not be a *Named. // The underlying type must not be a *Named.
func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
if _, ok := underlying.(*Named); ok { if _, ok := underlying.(*Named); ok {
panic("types.NewNamed: underlying type must not be *Named") panic("types2.NewNamed: underlying type must not be *Named")
} }
typ := &Named{obj: obj, orig: underlying, underlying: underlying, methods: methods} return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods)
if obj.typ == nil {
obj.typ = typ
}
return typ
} }
func (check *Checker) NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { // newNamed is like NewNamed but with a *Checker receiver and additional orig argument.
typ := &Named{check: check, obj: obj, orig: underlying, underlying: underlying, methods: methods} func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams []*TypeName, methods []*Func) *Named {
typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods}
if typ.orig == nil {
typ.orig = typ
}
if obj.typ == nil { if obj.typ == nil {
obj.typ = typ obj.typ = typ
} }
@ -682,6 +685,10 @@ func (check *Checker) NewNamed(obj *TypeName, underlying Type, methods []*Func)
// Obj returns the type name for the named type t. // Obj returns the type name for the named type t.
func (t *Named) Obj() *TypeName { return t.obj } func (t *Named) Obj() *TypeName { return t.obj }
// Orig returns the original generic type an instantiated type is derived from.
// If t is not an instantiated type, the result is t.
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.
@ -689,10 +696,13 @@ func (t *Named) Obj() *TypeName { return t.obj }
// 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.tparams } func (t *Named) TParams() []*TypeName { return t.tparams }
// SetTParams sets the type parameters of the named type t.
func (t *Named) SetTParams(tparams []*TypeName) { t.tparams = 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 Named. // SetTArgs sets the type arguments of the named type t.
func (t *Named) SetTArgs(args []Type) { t.targs = args } func (t *Named) SetTArgs(args []Type) { t.targs = args }
// NumMethods returns the number of explicit methods whose receiver is named type t. // NumMethods returns the number of explicit methods whose receiver is named type t.
@ -704,10 +714,10 @@ func (t *Named) Method(i int) *Func { return t.methods[i] }
// SetUnderlying sets the underlying type and marks t as complete. // SetUnderlying sets the underlying type and marks t as complete.
func (t *Named) SetUnderlying(underlying Type) { func (t *Named) SetUnderlying(underlying Type) {
if underlying == nil { if underlying == nil {
panic("types.Named.SetUnderlying: underlying type must not be nil") panic("types2.Named.SetUnderlying: underlying type must not be nil")
} }
if _, ok := underlying.(*Named); ok { if _, ok := underlying.(*Named); ok {
panic("types.Named.SetUnderlying: underlying type must not be *Named") panic("types2.Named.SetUnderlying: underlying type must not be *Named")
} }
t.underlying = underlying t.underlying = underlying
} }
@ -731,9 +741,9 @@ func nextId() uint64 { return uint64(atomic.AddUint32(&lastId, 1)) }
// A TypeParam represents a type parameter type. // A TypeParam represents a type parameter type.
type TypeParam struct { type TypeParam struct {
check *Checker // for lazy type bound completion check *Checker // for lazy type bound completion
id uint64 // unique id id uint64 // unique id, for debugging only
obj *TypeName // corresponding type name obj *TypeName // corresponding type name
index int // parameter index index int // type parameter index in source order, starting at 0
bound Type // *Named or *Interface; underlying type is always *Interface bound Type // *Named or *Interface; underlying type is always *Interface
} }

View File

@ -431,9 +431,9 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
} }
// goTypeName returns the Go type name for typ and // goTypeName returns the Go type name for typ and
// removes any occurrences of "types." from that name. // removes any occurrences of "types2." from that name.
func goTypeName(typ Type) string { func goTypeName(typ Type) string {
return strings.Replace(fmt.Sprintf("%T", typ), "types.", "", -1) // strings.ReplaceAll is not available in Go 1.4 return strings.Replace(fmt.Sprintf("%T", typ), "types2.", "", -1) // strings.ReplaceAll is not available in Go 1.4
} }
// typInternal drives type checking of types. // typInternal drives type checking of types.