aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/compile/internal/types2/check.go2
-rw-r--r--src/cmd/compile/internal/types2/decl.go7
-rw-r--r--src/cmd/compile/internal/types2/instantiate.go18
-rw-r--r--src/cmd/compile/internal/types2/labels.go3
-rw-r--r--src/cmd/compile/internal/types2/lookup.go5
-rw-r--r--src/cmd/compile/internal/types2/object.go8
-rw-r--r--src/cmd/compile/internal/types2/predicates.go2
-rw-r--r--src/cmd/compile/internal/types2/resolver.go19
-rw-r--r--src/cmd/compile/internal/types2/sanitize.go1
-rw-r--r--src/cmd/compile/internal/types2/scope.go93
-rw-r--r--src/cmd/compile/internal/types2/signature.go2
-rw-r--r--src/cmd/compile/internal/types2/sizeof_test.go2
-rw-r--r--src/cmd/compile/internal/types2/stmt.go3
-rw-r--r--src/cmd/compile/internal/types2/subst.go12
-rw-r--r--src/cmd/compile/internal/types2/type.go46
-rw-r--r--src/cmd/compile/internal/types2/typestring.go4
-rw-r--r--src/cmd/compile/internal/types2/typexpr.go2
17 files changed, 186 insertions, 43 deletions
diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go
index f80a918467..5d3c2c8ad2 100644
--- a/src/cmd/compile/internal/types2/check.go
+++ b/src/cmd/compile/internal/types2/check.go
@@ -71,7 +71,7 @@ type importKey struct {
// A dotImportKey describes a dot-imported object in the given scope.
type dotImportKey struct {
scope *Scope
- obj Object
+ name string
}
// A Checker maintains the state of the type checker.
diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go
index aa70f3880b..00b4ef7010 100644
--- a/src/cmd/compile/internal/types2/decl.go
+++ b/src/cmd/compile/internal/types2/decl.go
@@ -522,7 +522,7 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init syntax.Expr) {
// 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 {
- u := n0.underlying
+ u := n0.Underlying()
if u == Typ[Invalid] {
return u
@@ -560,7 +560,7 @@ func (n0 *Named) under() Type {
seen := map[*Named]int{n0: 0}
path := []Object{n0.obj}
for {
- u = n.underlying
+ u = n.Underlying()
if u == nil {
u = Typ[Invalid]
break
@@ -764,7 +764,7 @@ func (check *Checker) collectMethods(obj *TypeName) {
// and field names must be distinct."
base := asNamed(obj.typ) // shouldn't fail but be conservative
if base != nil {
- if t, _ := base.underlying.(*Struct); t != nil {
+ if t, _ := base.Underlying().(*Struct); t != nil {
for _, fld := range t.fields {
if fld.name != "_" {
assert(mset.insert(fld) == nil)
@@ -806,6 +806,7 @@ func (check *Checker) collectMethods(obj *TypeName) {
}
if base != nil {
+ base.expand() // TODO(mdempsky): Probably unnecessary.
base.methods = append(base.methods, m)
}
}
diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go
index 0df52e851c..85c897a909 100644
--- a/src/cmd/compile/internal/types2/instantiate.go
+++ b/src/cmd/compile/internal/types2/instantiate.go
@@ -23,7 +23,7 @@ func Instantiate(pos syntax.Pos, typ Type, targs []Type) (res Type) {
var tparams []*TypeName
switch t := typ.(type) {
case *Named:
- tparams = t.tparams
+ tparams = t.TParams()
case *Signature:
tparams = t.tparams
defer func() {
@@ -61,3 +61,19 @@ func Instantiate(pos syntax.Pos, typ Type, targs []Type) (res Type) {
smap := makeSubstMap(tparams, targs)
return (*Checker)(nil).subst(pos, typ, smap)
}
+
+// InstantiateLazy is like Instantiate, but avoids actually
+// instantiating the type until needed.
+func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type) (res Type) {
+ base := asNamed(typ)
+ if base == nil {
+ panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
+ }
+
+ return &instance{
+ check: check,
+ pos: pos,
+ base: base,
+ targs: targs,
+ }
+}
diff --git a/src/cmd/compile/internal/types2/labels.go b/src/cmd/compile/internal/types2/labels.go
index d3206988b5..6f02e2fc96 100644
--- a/src/cmd/compile/internal/types2/labels.go
+++ b/src/cmd/compile/internal/types2/labels.go
@@ -32,7 +32,8 @@ func (check *Checker) labels(body *syntax.BlockStmt) {
}
// spec: "It is illegal to define a label that is never used."
- for _, obj := range all.elems {
+ for name, obj := range all.elems {
+ obj = resolve(name, obj)
if lbl := obj.(*Label); !lbl.used {
check.softErrorf(lbl.pos, "label %s declared but not used", lbl.name)
}
diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go
index eb2b17dd4d..93ed620449 100644
--- a/src/cmd/compile/internal/types2/lookup.go
+++ b/src/cmd/compile/internal/types2/lookup.go
@@ -54,7 +54,7 @@ func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package
// pointer type but discard the result if it is a method since we would
// not have found it for T (see also issue 8590).
if t := asNamed(T); t != nil {
- if p, _ := t.underlying.(*Pointer); p != nil {
+ if p, _ := t.Underlying().(*Pointer); p != nil {
obj, index, indirect = check.rawLookupFieldOrMethod(p, false, pkg, name)
if _, ok := obj.(*Func); ok {
return nil, nil, false
@@ -126,6 +126,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
seen[named] = true
// look for a matching attached method
+ named.expand()
if i, m := lookupMethod(named.methods, pkg, name); m != nil {
// potential match
// caution: method may not have a proper signature yet
@@ -400,7 +401,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
// In order to compare the signatures, substitute the receiver
// type parameters of ftyp with V's instantiation type arguments.
// This lazily instantiates the signature of method f.
- if Vn != nil && len(Vn.tparams) > 0 {
+ if Vn != nil && len(Vn.TParams()) > 0 {
// Be careful: The number of type arguments may not match
// the number of receiver parameters. If so, an error was
// reported earlier but the length discrepancy is still
diff --git a/src/cmd/compile/internal/types2/object.go b/src/cmd/compile/internal/types2/object.go
index 8ed55f1dbf..82297ff17f 100644
--- a/src/cmd/compile/internal/types2/object.go
+++ b/src/cmd/compile/internal/types2/object.go
@@ -276,6 +276,14 @@ func NewTypeName(pos syntax.Pos, pkg *Package, name string, typ Type) *TypeName
return &TypeName{object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}}
}
+// NewTypeNameLazy returns a new defined type like NewTypeName, but it
+// lazily calls resolve to finish constructing the Named object.
+func NewTypeNameLazy(pos syntax.Pos, pkg *Package, name string, resolve func(named *Named) (tparams []*TypeName, underlying Type, methods []*Func)) *TypeName {
+ obj := NewTypeName(pos, pkg, name, nil)
+ NewNamed(obj, nil, nil).resolve = resolve
+ return obj
+}
+
// IsAlias reports whether obj is an alias name for a type.
func (obj *TypeName) IsAlias() bool {
switch t := obj.typ.(type) {
diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go
index 74436836cd..66de249044 100644
--- a/src/cmd/compile/internal/types2/predicates.go
+++ b/src/cmd/compile/internal/types2/predicates.go
@@ -21,7 +21,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.tparams != nil && named.targs == nil
+ return named != nil && named.obj != nil && named.TParams() != nil && named.targs == nil
}
func is(typ Type, what BasicInfo) bool {
diff --git a/src/cmd/compile/internal/types2/resolver.go b/src/cmd/compile/internal/types2/resolver.go
index 9b1482b14e..018a20cfb2 100644
--- a/src/cmd/compile/internal/types2/resolver.go
+++ b/src/cmd/compile/internal/types2/resolver.go
@@ -308,22 +308,26 @@ func (check *Checker) collectObjects() {
check.dotImportMap = make(map[dotImportKey]*PkgName)
}
// merge imported scope with file scope
- for _, obj := range imp.scope.elems {
+ for name, obj := range imp.scope.elems {
+ // Note: Avoid eager resolve(name, obj) here, so we only
+ // resolve dot-imported objects as needed.
+
// A package scope may contain non-exported objects,
// do not import them!
- if obj.Exported() {
+ if isExported(name) {
// declare dot-imported object
// (Do not use check.declare because it modifies the object
// via Object.setScopePos, which leads to a race condition;
// the object may be imported into more than one file scope
// concurrently. See issue #32154.)
- if alt := fileScope.Insert(obj); alt != nil {
+ if alt := fileScope.Lookup(name); alt != nil {
var err error_
- err.errorf(s.LocalPkgName, "%s redeclared in this block", obj.Name())
+ err.errorf(s.LocalPkgName, "%s redeclared in this block", alt.Name())
err.recordAltDecl(alt)
check.report(&err)
} else {
- check.dotImportMap[dotImportKey{fileScope, obj}] = pkgName
+ fileScope.insert(name, obj)
+ check.dotImportMap[dotImportKey{fileScope, name}] = pkgName
}
}
}
@@ -469,8 +473,9 @@ func (check *Checker) collectObjects() {
// verify that objects in package and file scopes have different names
for _, scope := range fileScopes {
- for _, obj := range scope.elems {
- if alt := pkg.scope.Lookup(obj.Name()); alt != nil {
+ for name, obj := range scope.elems {
+ if alt := pkg.scope.Lookup(name); alt != nil {
+ obj = resolve(name, obj)
var err error_
if pkg, ok := obj.(*PkgName); ok {
err.errorf(alt, "%s already declared through import of %s", alt.Name(), pkg.Imported())
diff --git a/src/cmd/compile/internal/types2/sanitize.go b/src/cmd/compile/internal/types2/sanitize.go
index 03aef90fe1..4e654e074f 100644
--- a/src/cmd/compile/internal/types2/sanitize.go
+++ b/src/cmd/compile/internal/types2/sanitize.go
@@ -134,6 +134,7 @@ func (s sanitizer) typ(typ Type) Type {
if debug && t.check != nil {
panic("internal error: Named.check != nil")
}
+ t.expand()
if orig := s.typ(t.fromRHS); orig != t.fromRHS {
t.fromRHS = orig
}
diff --git a/src/cmd/compile/internal/types2/scope.go b/src/cmd/compile/internal/types2/scope.go
index ade0a79b31..2f1814a631 100644
--- a/src/cmd/compile/internal/types2/scope.go
+++ b/src/cmd/compile/internal/types2/scope.go
@@ -13,6 +13,7 @@ import (
"io"
"sort"
"strings"
+ "sync"
)
// A Scope maintains a set of objects and links to its containing
@@ -66,7 +67,7 @@ func (s *Scope) Child(i int) *Scope { return s.children[i] }
// Lookup returns the object in scope s with the given name if such an
// object exists; otherwise the result is nil.
func (s *Scope) Lookup(name string) Object {
- return s.elems[name]
+ return resolve(name, s.elems[name])
}
// LookupParent follows the parent chain of scopes starting with s until
@@ -81,7 +82,7 @@ func (s *Scope) Lookup(name string) Object {
// whose scope is the scope of the package that exported them.
func (s *Scope) LookupParent(name string, pos syntax.Pos) (*Scope, Object) {
for ; s != nil; s = s.parent {
- if obj := s.elems[name]; obj != nil && (!pos.IsKnown() || obj.scopePos().Cmp(pos) <= 0) {
+ if obj := s.Lookup(name); obj != nil && (!pos.IsKnown() || obj.scopePos().Cmp(pos) <= 0) {
return s, obj
}
}
@@ -95,19 +96,38 @@ func (s *Scope) LookupParent(name string, pos syntax.Pos) (*Scope, Object) {
// if not already set, and returns nil.
func (s *Scope) Insert(obj Object) Object {
name := obj.Name()
- if alt := s.elems[name]; alt != nil {
+ if alt := s.Lookup(name); alt != nil {
return alt
}
- if s.elems == nil {
- s.elems = make(map[string]Object)
- }
- s.elems[name] = obj
+ s.insert(name, obj)
if obj.Parent() == nil {
obj.setParent(s)
}
return nil
}
+// InsertLazy is like Insert, but allows deferring construction of the
+// inserted object until it's accessed with Lookup. The Object
+// returned by resolve must have the same name as given to InsertLazy.
+// If s already contains an alternative object with the same name,
+// InsertLazy leaves s unchanged and returns false. Otherwise it
+// records the binding and returns true. The object's parent scope
+// will be set to s after resolve is called.
+func (s *Scope) InsertLazy(name string, resolve func() Object) bool {
+ if s.elems[name] != nil {
+ return false
+ }
+ s.insert(name, &lazyObject{parent: s, resolve: resolve})
+ return true
+}
+
+func (s *Scope) insert(name string, obj Object) {
+ if s.elems == nil {
+ s.elems = make(map[string]Object)
+ }
+ s.elems[name] = obj
+}
+
// Squash merges s with its parent scope p by adding all
// objects of s to p, adding all children of s to the
// children of p, and removing s from p's children.
@@ -117,7 +137,8 @@ func (s *Scope) Insert(obj Object) Object {
func (s *Scope) Squash(err func(obj, alt Object)) {
p := s.parent
assert(p != nil)
- for _, obj := range s.elems {
+ for name, obj := range s.elems {
+ obj = resolve(name, obj)
obj.setParent(nil)
if alt := p.Insert(obj); alt != nil {
err(obj, alt)
@@ -196,7 +217,7 @@ func (s *Scope) WriteTo(w io.Writer, n int, recurse bool) {
indn1 := indn + ind
for _, name := range s.Names() {
- fmt.Fprintf(w, "%s%s\n", indn1, s.elems[name])
+ fmt.Fprintf(w, "%s%s\n", indn1, s.Lookup(name))
}
if recurse {
@@ -214,3 +235,57 @@ func (s *Scope) String() string {
s.WriteTo(&buf, 0, false)
return buf.String()
}
+
+// A lazyObject represents an imported Object that has not been fully
+// resolved yet by its importer.
+type lazyObject struct {
+ parent *Scope
+ resolve func() Object
+ obj Object
+ once sync.Once
+}
+
+// resolve returns the Object represented by obj, resolving lazy
+// objects as appropriate.
+func resolve(name string, obj Object) Object {
+ if lazy, ok := obj.(*lazyObject); ok {
+ lazy.once.Do(func() {
+ obj := lazy.resolve()
+
+ if _, ok := obj.(*lazyObject); ok {
+ panic("recursive lazy object")
+ }
+ if obj.Name() != name {
+ panic("lazy object has unexpected name")
+ }
+
+ if obj.Parent() == nil {
+ obj.setParent(lazy.parent)
+ }
+ lazy.obj = obj
+ })
+
+ obj = lazy.obj
+ }
+ return obj
+}
+
+// stub implementations so *lazyObject implements Object and we can
+// store them directly into Scope.elems.
+func (*lazyObject) Parent() *Scope { panic("unreachable") }
+func (*lazyObject) Pos() syntax.Pos { panic("unreachable") }
+func (*lazyObject) Pkg() *Package { panic("unreachable") }
+func (*lazyObject) Name() string { panic("unreachable") }
+func (*lazyObject) Type() Type { panic("unreachable") }
+func (*lazyObject) Exported() bool { panic("unreachable") }
+func (*lazyObject) Id() string { panic("unreachable") }
+func (*lazyObject) String() string { panic("unreachable") }
+func (*lazyObject) order() uint32 { panic("unreachable") }
+func (*lazyObject) color() color { panic("unreachable") }
+func (*lazyObject) setType(Type) { panic("unreachable") }
+func (*lazyObject) setOrder(uint32) { panic("unreachable") }
+func (*lazyObject) setColor(color color) { panic("unreachable") }
+func (*lazyObject) setParent(*Scope) { panic("unreachable") }
+func (*lazyObject) sameId(pkg *Package, name string) bool { panic("unreachable") }
+func (*lazyObject) scopePos() syntax.Pos { panic("unreachable") }
+func (*lazyObject) setScopePos(pos syntax.Pos) { panic("unreachable") }
diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go
index c8c4cca0a7..a7edc5ac03 100644
--- a/src/cmd/compile/internal/types2/signature.go
+++ b/src/cmd/compile/internal/types2/signature.go
@@ -62,7 +62,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
// again when we type-check the signature.
// TODO(gri) maybe the receiver should be marked as invalid instead?
if recv := asNamed(check.genericType(rname, false)); recv != nil {
- recvTParams = recv.tparams
+ recvTParams = recv.TParams()
}
}
// provide type parameter bounds
diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go
index daa039bf92..3cb162764c 100644
--- a/src/cmd/compile/internal/types2/sizeof_test.go
+++ b/src/cmd/compile/internal/types2/sizeof_test.go
@@ -31,7 +31,7 @@ func TestSizeof(t *testing.T) {
{Interface{}, 52, 104},
{Map{}, 16, 32},
{Chan{}, 12, 24},
- {Named{}, 68, 136},
+ {Named{}, 84, 160},
{TypeParam{}, 28, 48},
{instance{}, 52, 96},
{top{}, 0, 0},
diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go
index e9ffd4f5ca..ab66432126 100644
--- a/src/cmd/compile/internal/types2/stmt.go
+++ b/src/cmd/compile/internal/types2/stmt.go
@@ -64,7 +64,8 @@ func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body
func (check *Checker) usage(scope *Scope) {
var unused []*Var
- for _, elem := range scope.elems {
+ for name, elem := range scope.elems {
+ elem = resolve(name, elem)
if v, _ := elem.(*Var); v != nil && !v.used {
unused = append(unused, v)
}
diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go
index 35ca197d64..dd8dd74161 100644
--- a/src/cmd/compile/internal/types2/subst.go
+++ b/src/cmd/compile/internal/types2/subst.go
@@ -76,7 +76,7 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis
var tparams []*TypeName
switch t := typ.(type) {
case *Named:
- tparams = t.tparams
+ tparams = t.TParams()
case *Signature:
tparams = t.tparams
defer func() {
@@ -347,7 +347,7 @@ func (subst *subster) typ(typ Type) Type {
}
}
- if t.tparams == nil {
+ if t.TParams() == nil {
dump(">>> %s is not parameterized", t)
return t // type is not parameterized
}
@@ -357,7 +357,7 @@ func (subst *subster) typ(typ Type) Type {
if len(t.targs) > 0 {
// already instantiated
dump(">>> %s already instantiated", t)
- assert(len(t.targs) == len(t.tparams))
+ assert(len(t.targs) == len(t.TParams()))
// For each (existing) type argument targ, determine if it needs
// to be substituted; i.e., if it is or contains a type parameter
// that has a type argument for it.
@@ -367,7 +367,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.tparams))
+ new_targs = make([]Type, len(t.TParams()))
copy(new_targs, t.targs)
}
new_targs[i] = new_targ
@@ -397,7 +397,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, t.underlying, t.tparams, 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.targs = new_targs
if subst.check != nil {
subst.check.typMap[h] = named
@@ -406,7 +406,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.underlying = subst.typOrNil(t.Underlying())
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 92f35f1279..604520d27f 100644
--- a/src/cmd/compile/internal/types2/type.go
+++ b/src/cmd/compile/internal/types2/type.go
@@ -6,6 +6,7 @@ package types2
import (
"cmd/compile/internal/syntax"
+ "sync"
"sync/atomic"
)
@@ -497,6 +498,9 @@ type Named struct {
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
+
+ resolve func(*Named) ([]*TypeName, Type, []*Func)
+ once sync.Once
}
// NewNamed returns a new named type for the given type name, underlying type, and associated methods.
@@ -509,6 +513,35 @@ func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods)
}
+func (t *Named) expand() *Named {
+ if t.resolve == nil {
+ return t
+ }
+
+ t.once.Do(func() {
+ // TODO(mdempsky): Since we're passing t to resolve anyway
+ // (necessary because types2 expects the receiver type for methods
+ // on defined interface types to be the Named rather than the
+ // underlying Interface), maybe it should just handle calling
+ // SetTParams, SetUnderlying, and AddMethod instead? Those
+ // methods would need to support reentrant calls though. It would
+ // also make the API more future-proof towards further extensions
+ // (like SetTParams).
+
+ tparams, underlying, methods := t.resolve(t)
+
+ switch underlying.(type) {
+ case nil, *Named:
+ panic("invalid underlying type")
+ }
+
+ t.tparams = tparams
+ t.underlying = underlying
+ t.methods = methods
+ })
+ return t
+}
+
// 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}
@@ -550,10 +583,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() []*TypeName { return t.tparams }
+func (t *Named) TParams() []*TypeName { return t.expand().tparams }
// SetTParams sets the type parameters of the named type t.
-func (t *Named) SetTParams(tparams []*TypeName) { t.tparams = tparams }
+func (t *Named) SetTParams(tparams []*TypeName) { t.expand().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 }
@@ -562,10 +595,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.methods) }
+func (t *Named) NumMethods() int { return len(t.expand().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.methods[i] }
+func (t *Named) Method(i int) *Func { return t.expand().methods[i] }
// SetUnderlying sets the underlying type and marks t as complete.
func (t *Named) SetUnderlying(underlying Type) {
@@ -575,11 +608,12 @@ func (t *Named) SetUnderlying(underlying Type) {
if _, ok := underlying.(*Named); ok {
panic("types2.Named.SetUnderlying: underlying type must not be *Named")
}
- t.underlying = underlying
+ t.expand().underlying = underlying
}
// AddMethod adds method m unless it is already in the method list.
func (t *Named) AddMethod(m *Func) {
+ t.expand()
if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 {
t.methods = append(t.methods, m)
}
@@ -743,7 +777,7 @@ func (t *Signature) Underlying() Type { return t }
func (t *Interface) Underlying() Type { return t }
func (t *Map) Underlying() Type { return t }
func (t *Chan) Underlying() Type { return t }
-func (t *Named) Underlying() Type { return t.underlying }
+func (t *Named) Underlying() Type { return t.expand().underlying }
func (t *TypeParam) Underlying() Type { return t }
func (t *instance) Underlying() Type { return t }
func (t *top) Underlying() Type { return t }
diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go
index 28583b62d9..07ed510d11 100644
--- a/src/cmd/compile/internal/types2/typestring.go
+++ b/src/cmd/compile/internal/types2/typestring.go
@@ -272,9 +272,9 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
buf.WriteByte('[')
writeTypeList(buf, t.targs, qf, visited)
buf.WriteByte(']')
- } else if t.tparams != nil {
+ } else if t.TParams() != nil {
// parameterized type
- writeTParamList(buf, t.tparams, qf, visited)
+ writeTParamList(buf, t.TParams(), qf, visited)
}
case *TypeParam:
diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go
index b27b2a00df..583bb464b2 100644
--- a/src/cmd/compile/internal/types2/typexpr.go
+++ b/src/cmd/compile/internal/types2/typexpr.go
@@ -58,7 +58,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *Named, wantType boo
// If so, mark the respective package as used.
// (This code is only needed for dot-imports. Without them,
// we only have to mark variables, see *Var case below).
- if pkgName := check.dotImportMap[dotImportKey{scope, obj}]; pkgName != nil {
+ if pkgName := check.dotImportMap[dotImportKey{scope, obj.Name()}]; pkgName != nil {
pkgName.used = true
}