// NewInterfaceType takes ownership of the provided methods and may modify their types by setting
// missing receivers. To compute the method set of the interface, Complete must be called.
func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
- typ := new(Interface)
-
if len(methods) == 0 && len(embeddeds) == 0 {
- return typ
+ return &emptyInterface
}
- var mset objset
+ // set method receivers if necessary
+ typ := new(Interface)
for _, m := range methods {
- if mset.insert(m) != nil {
- panic("multiple methods with the same name")
- }
- // set receiver if we don't have one
if sig := m.typ.(*Signature); sig.recv == nil {
sig.recv = NewVar(m.pos, m.pkg, "", typ)
}
}
- sort.Sort(byUniqueMethodName(methods))
- if len(embeddeds) > 0 {
- // All embedded types should be interfaces; however, defined types
- // may not yet be fully resolved. Only verify that non-defined types
- // are interfaces. This matches the behavior of the code before the
- // fix for #25301 (issue #25596).
- for _, t := range embeddeds {
- if _, ok := t.(*Named); !ok && !IsInterface(t) {
- panic("embedded type is not an interface")
- }
+ // All embedded types should be interfaces; however, defined types
+ // may not yet be fully resolved. Only verify that non-defined types
+ // are interfaces. This matches the behavior of the code before the
+ // fix for #25301 (issue #25596).
+ for _, t := range embeddeds {
+ if _, ok := t.(*Named); !ok && !IsInterface(t) {
+ panic("embedded type is not an interface")
}
- sort.Stable(byUniqueTypeName(embeddeds))
}
+ // sort for API stability
+ sort.Sort(byUniqueMethodName(methods))
+ sort.Stable(byUniqueTypeName(embeddeds))
+
typ.methods = methods
typ.embeddeds = embeddeds
return typ
func (t *Interface) EmbeddedType(i int) Type { return t.embeddeds[i] }
// NumMethods returns the total number of methods of interface t.
-func (t *Interface) NumMethods() int { return len(t.allMethods) }
+// The interface must have been completed.
+func (t *Interface) NumMethods() int { t.assertCompleteness(); return len(t.allMethods) }
+
+func (t *Interface) assertCompleteness() {
+ if t.allMethods == nil {
+ panic("interface is incomplete")
+ }
+}
// Method returns the i'th method of interface t for 0 <= i < t.NumMethods().
// The methods are ordered by their unique Id.
-func (t *Interface) Method(i int) *Func { return t.allMethods[i] }
+// The interface must have been completed.
+func (t *Interface) Method(i int) *Func { t.assertCompleteness(); return t.allMethods[i] }
// Empty reports whether t is the empty interface.
-func (t *Interface) Empty() bool { return len(t.allMethods) == 0 }
+// The interface must have been completed.
+func (t *Interface) Empty() bool { t.assertCompleteness(); return len(t.allMethods) == 0 }
// Complete computes the interface's method set. It must be called by users of
// NewInterfaceType and NewInterface after the interface's embedded types are
// fully defined and before using the interface type in any way other than to
-// form other types. Complete returns the receiver.
+// form other types. The interface must not contain duplicate methods or a
+// panic occurs. Complete returns the receiver.
func (t *Interface) Complete() *Interface {
+ // TODO(gri) consolidate this method with Checker.completeInterface
if t.allMethods != nil {
return t
}
- // collect all methods
- var allMethods []*Func
- allMethods = append(allMethods, t.methods...)
- for _, et := range t.embeddeds {
- it := et.Underlying().(*Interface)
- it.Complete()
- // copy embedded methods unchanged (see issue #28282)
- allMethods = append(allMethods, it.allMethods...)
+ t.allMethods = markComplete // avoid infinite recursion
+
+ var todo []*Func
+ var methods []*Func
+ var seen objset
+ addMethod := func(m *Func, explicit bool) {
+ switch other := seen.insert(m); {
+ case other == nil:
+ methods = append(methods, m)
+ case explicit:
+ panic("duplicate method " + m.name)
+ default:
+ // check method signatures after all locally embedded interfaces are computed
+ todo = append(todo, m, other.(*Func))
+ }
+ }
+
+ for _, m := range t.methods {
+ addMethod(m, true)
+ }
+
+ for _, typ := range t.embeddeds {
+ typ := typ.Underlying().(*Interface)
+ typ.Complete()
+ for _, m := range typ.allMethods {
+ addMethod(m, false)
+ }
+ }
+
+ for i := 0; i < len(todo); i += 2 {
+ m := todo[i]
+ other := todo[i+1]
+ if !Identical(m.typ, other.typ) {
+ panic("duplicate method " + m.name)
+ }
}
- sort.Sort(byUniqueMethodName(allMethods))
- // t.methods and/or t.embeddeds may have been empty
- if allMethods == nil {
- allMethods = markComplete
+ if methods != nil {
+ sort.Sort(byUniqueMethodName(methods))
+ t.allMethods = methods
}
- t.allMethods = allMethods
return t
}
// A Named represents a named type.
type Named struct {
+ info typeInfo // for cycle detection
obj *TypeName // corresponding declared object
+ orig 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
methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily
}
if _, ok := underlying.(*Named); ok {
panic("types.NewNamed: underlying type must not be *Named")
}
- typ := &Named{obj: obj, underlying: underlying, methods: methods}
+ typ := &Named{obj: obj, orig: underlying, underlying: underlying, methods: methods}
if obj.typ == nil {
obj.typ = typ
}