aboutsummaryrefslogtreecommitdiff
path: root/src/go/types/methodset.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/go/types/methodset.go')
-rw-r--r--src/go/types/methodset.go52
1 files changed, 25 insertions, 27 deletions
diff --git a/src/go/types/methodset.go b/src/go/types/methodset.go
index b27f2dac34..4f791d9d51 100644
--- a/src/go/types/methodset.go
+++ b/src/go/types/methodset.go
@@ -72,24 +72,22 @@ func NewMethodSet(T Type) *MethodSet {
var base methodSet
typ, isPtr := deref(T)
- named, _ := typ.(*Named)
// *typ where typ is an interface has no methods.
- if isPtr {
- utyp := typ
- if named != nil {
- utyp = named.underlying
- }
- if _, ok := utyp.(*Interface); ok {
- return &emptyMethodSet
- }
+ if isPtr && IsInterface(typ) {
+ return &emptyMethodSet
}
// Start with typ as single entry at shallowest depth.
- // If typ is not a named type, insert a nil type instead.
- current := []embeddedType{{named, nil, isPtr, false}}
-
- // named types that we have seen already, allocated lazily
+ current := []embeddedType{{typ, nil, isPtr, false}}
+
+ // Named types that we have seen already, allocated lazily.
+ // Used to avoid endless searches in case of recursive types.
+ // Since only Named types can be used for recursive types, we
+ // only need to track those.
+ // (If we ever allow type aliases to construct recursive types,
+ // we must use type identity rather than pointer equality for
+ // the map key comparison, as we do in consolidateMultiples.)
var seen map[*Named]bool
// collect methods at current depth
@@ -101,11 +99,12 @@ func NewMethodSet(T Type) *MethodSet {
var mset methodSet
for _, e := range current {
- // The very first time only, e.typ may be nil.
- // In this case, we don't have a named type and
- // we simply continue with the underlying type.
- if e.typ != nil {
- if seen[e.typ] {
+ typ := e.typ
+
+ // If we have a named type, we may have associated methods.
+ // Look for those first.
+ if named, _ := typ.(*Named); named != nil {
+ if seen[named] {
// We have seen this type before, at a more shallow depth
// (note that multiples of this type at the current depth
// were consolidated before). The type at that depth shadows
@@ -116,12 +115,12 @@ func NewMethodSet(T Type) *MethodSet {
if seen == nil {
seen = make(map[*Named]bool)
}
- seen[e.typ] = true
+ seen[named] = true
- mset = mset.add(e.typ.methods, e.index, e.indirect, e.multiples)
+ mset = mset.add(named.methods, e.index, e.indirect, e.multiples)
// continue with underlying type
- typ = e.typ.underlying
+ typ = named.underlying
}
switch t := typ.(type) {
@@ -130,16 +129,15 @@ func NewMethodSet(T Type) *MethodSet {
fset = fset.add(f, e.multiples)
// Embedded fields are always of the form T or *T where
- // T is a named type. If typ appeared multiple times at
+ // T is a type name. If typ appeared multiple times at
// this depth, f.Type appears multiple times at the next
// depth.
if f.anonymous {
- // Ignore embedded basic types - only user-defined
- // named types can have methods or struct fields.
typ, isPtr := deref(f.typ)
- if t, _ := typ.(*Named); t != nil {
- next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples})
- }
+ // TODO(gri) optimization: ignore types that can't
+ // have fields or methods (only Named, Struct, and
+ // Interface types need to be considered).
+ next = append(next, embeddedType{typ, concat(e.index, i), e.indirect || isPtr, e.multiples})
}
}