diff options
Diffstat (limited to 'src/go/types/named.go')
-rw-r--r-- | src/go/types/named.go | 49 |
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 { |