aboutsummaryrefslogtreecommitdiff
path: root/src/go/types/named.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/go/types/named.go')
-rw-r--r--src/go/types/named.go49
1 files changed, 28 insertions, 21 deletions
diff --git a/src/go/types/named.go b/src/go/types/named.go
index 03af3fbc5a..87eaa3179e 100644
--- a/src/go/types/named.go
+++ b/src/go/types/named.go
@@ -10,12 +10,13 @@ import "sync"
// A Named represents a named (defined) type.
type Named struct {
- instance *instance // syntactic information for lazy instantiation
+ check *Checker
info typeInfo // for cycle detection
obj *TypeName // corresponding declared object
orig *Named // original, uninstantiated type
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
+ instance *instance // syntactic information for lazy instantiation
tparams *TypeParams // 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
@@ -34,7 +35,19 @@ func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods)
}
-func (t *Named) expand() *Named {
+func (t *Named) load() *Named {
+ // If t is an instantiated type, it derives its methods and tparams from its
+ // base type. Since we expect type parameters and methods to be set after a
+ // call to load, we must load the base and copy here.
+ //
+ // 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 {
+ t.orig.load()
+ t.tparams = t.orig.tparams
+ t.methods = t.orig.methods
+ }
if t.resolve == nil {
return t
}
@@ -65,13 +78,7 @@ func (t *Named) expand() *Named {
// newNamed is like NewNamed but with a *Checker receiver and additional orig argument.
func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams *TypeParams, methods []*Func) *Named {
- var inst *instance
- if check != nil {
- inst = &instance{
- check: check,
- }
- }
- typ := &Named{instance: inst, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods}
+ typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods}
if typ.orig == nil {
typ.orig = typ
}
@@ -92,7 +99,7 @@ func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tpar
case *Named:
panic("internal error: unexpanded underlying type")
}
- typ.instance = nil
+ typ.check = nil
})
}
return typ
@@ -110,10 +117,10 @@ func (t *Named) _Orig() *Named { return t.orig }
// 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.
-func (t *Named) TParams() *TypeParams { return t.expand().tparams }
+func (t *Named) TParams() *TypeParams { return t.load().tparams }
// SetTParams sets the type parameters of the named type t.
-func (t *Named) SetTParams(tparams []*TypeName) { t.expand().tparams = bindTParams(tparams) }
+func (t *Named) SetTParams(tparams []*TypeName) { 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 }
@@ -122,10 +129,10 @@ func (t *Named) TArgs() []Type { return t.targs }
func (t *Named) SetTArgs(args []Type) { t.targs = args }
// NumMethods returns the number of explicit methods whose receiver is named type t.
-func (t *Named) NumMethods() int { return len(t.expand().methods) }
+func (t *Named) NumMethods() int { return len(t.load().methods) }
// Method returns the i'th method of named type t for 0 <= i < t.NumMethods().
-func (t *Named) Method(i int) *Func { return t.expand().methods[i] }
+func (t *Named) Method(i int) *Func { return t.load().methods[i] }
// SetUnderlying sets the underlying type and marks t as complete.
func (t *Named) SetUnderlying(underlying Type) {
@@ -135,18 +142,18 @@ func (t *Named) SetUnderlying(underlying Type) {
if _, ok := underlying.(*Named); ok {
panic("types.Named.SetUnderlying: underlying type must not be *Named")
}
- t.expand().underlying = underlying
+ t.load().underlying = underlying
}
// AddMethod adds method m unless it is already in the method list.
func (t *Named) AddMethod(m *Func) {
- t.expand()
+ t.load()
if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 {
t.methods = append(t.methods, m)
}
}
-func (t *Named) Underlying() Type { return t.expand().underlying }
+func (t *Named) Underlying() Type { return t.load().underlying }
func (t *Named) String() string { return TypeString(t, nil) }
// ----------------------------------------------------------------------------
@@ -159,7 +166,7 @@ func (t *Named) String() string { return TypeString(t, nil) }
// is detected, the result is Typ[Invalid]. If a cycle is detected and
// n0.check != nil, the cycle is reported.
func (n0 *Named) under() Type {
- n0.complete()
+ n0.expand()
u := n0.Underlying()
@@ -180,13 +187,13 @@ func (n0 *Named) under() Type {
// handled below
}
- if n0.instance == nil || n0.instance.check == nil {
+ if n0.check == nil {
panic("internal error: Named.check == nil but type is incomplete")
}
// Invariant: after this point n0 as well as any named types in its
// underlying chain should be set up when this function exits.
- check := n0.instance.check
+ check := n0.check
// If we can't expand u at this point, it is invalid.
n := asNamed(u)
@@ -207,7 +214,7 @@ func (n0 *Named) under() Type {
var n1 *Named
switch u1 := u.(type) {
case *Named:
- u1.complete()
+ u1.expand()
n1 = u1
}
if n1 == nil {