diff options
-rw-r--r-- | src/cmd/compile/internal/types2/check.go | 2 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/decl.go | 7 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/instantiate.go | 18 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/labels.go | 3 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/lookup.go | 5 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/object.go | 8 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/predicates.go | 2 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/resolver.go | 19 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/sanitize.go | 1 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/scope.go | 93 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/signature.go | 2 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/sizeof_test.go | 2 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/stmt.go | 3 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/subst.go | 12 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/type.go | 46 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/typestring.go | 4 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/typexpr.go | 2 |
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 } |