From 892cad7a9b6632533f87bf89d98c43f21c749a80 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 13 Apr 2021 17:48:45 -0700 Subject: [PATCH] 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 Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/decl.go | 9 ++-- .../compile/internal/types2/issues_test.go | 2 +- src/cmd/compile/internal/types2/sanitize.go | 4 +- .../compile/internal/types2/stdlib_test.go | 2 +- src/cmd/compile/internal/types2/subst.go | 5 +-- src/cmd/compile/internal/types2/type.go | 42 ++++++++++++------- src/cmd/compile/internal/types2/typexpr.go | 4 +- 7 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index f8559a43bba..178bebe2eca 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -333,7 +333,7 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo { switch t.info { case unknown: 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: // cycle detected for i, tn := range path { @@ -611,9 +611,8 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named } else { // defined type declaration - named := &Named{check: check, obj: obj} + named := check.newNamed(obj, nil, nil, nil, nil) def.setUnderlying(named) - obj.typ = named // make sure recursive type declarations terminate if tdecl.TParamList != nil { 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 - 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 // 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. // Determine the (final, unnamed) underlying type by resolving // 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. named.underlying = under(named) } diff --git a/src/cmd/compile/internal/types2/issues_test.go b/src/cmd/compile/internal/types2/issues_test.go index e1f5c92fc47..643d6789b51 100644 --- a/src/cmd/compile/internal/types2/issues_test.go +++ b/src/cmd/compile/internal/types2/issues_test.go @@ -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 // listed in the sources src1, src2 below. // The actual issue is in go/internal/gcimporter which has a corresponding diff --git a/src/cmd/compile/internal/types2/sanitize.go b/src/cmd/compile/internal/types2/sanitize.go index cd1719c8c0f..8b8bc72d85d 100644 --- a/src/cmd/compile/internal/types2/sanitize.go +++ b/src/cmd/compile/internal/types2/sanitize.go @@ -126,8 +126,8 @@ func (s sanitizer) typ(typ Type) Type { } case *Named: - if orig := s.typ(t.orig); orig != t.orig { - t.orig = orig + if orig := s.typ(t.fromRHS); orig != t.fromRHS { + t.fromRHS = orig } if under := s.typ(t.underlying); under != t.underlying { t.underlying = under diff --git a/src/cmd/compile/internal/types2/stdlib_test.go b/src/cmd/compile/internal/types2/stdlib_test.go index 6853bd23b00..c04f5e1c46d 100644 --- a/src/cmd/compile/internal/types2/stdlib_test.go +++ b/src/cmd/compile/internal/types2/stdlib_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // 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. package types2_test diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index d730642831c..d089317f7d5 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -385,8 +385,7 @@ func (subst *subster) typ(typ Type) Type { // create a new named type and populate caches to avoid endless recursion 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.tparams = t.tparams // new type is still parameterized + named := subst.check.newNamed(tname, t, t.underlying, t.tparams, t.methods) // method signatures are updated lazily named.targs = new_targs subst.check.typMap[h] = named subst.cache[t] = named @@ -394,7 +393,7 @@ func (subst *subster) typ(typ Type) Type { // do the substitution dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, new_targs) 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 diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index daa00ddd3ae..e6c260ff679 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -224,10 +224,10 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature { if variadic { n := params.Len() 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 { - 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} @@ -645,12 +645,15 @@ func (c *Chan) Dir() ChanDir { return c.dir } // Elem returns the element type of channel c. 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. type Named struct { check *Checker // for Named.under implementation 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) + 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 tparams []*TypeName // type parameters, 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. func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { 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} - if obj.typ == nil { - obj.typ = typ - } - return typ + return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods) } -func (check *Checker) NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { - typ := &Named{check: check, obj: obj, orig: underlying, underlying: underlying, methods: methods} +// 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 { + 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 { 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. 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 // 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. 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. 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 } // 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. func (t *Named) SetUnderlying(underlying Type) { 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 { - panic("types.Named.SetUnderlying: underlying type must not be *Named") + panic("types2.Named.SetUnderlying: underlying type must not be *Named") } t.underlying = underlying } @@ -731,9 +741,9 @@ func nextId() uint64 { return uint64(atomic.AddUint32(&lastId, 1)) } // A TypeParam represents a type parameter type. type TypeParam struct { check *Checker // for lazy type bound completion - id uint64 // unique id + id uint64 // unique id, for debugging only 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 } diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index e7d24949a47..61b290c0751 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -431,9 +431,9 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] } // 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 { - 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.