firstErr error // first error encountered
methods map[*TypeName][]*Func // maps package scope type names to associated non-blank (non-interface) methods
untyped map[ast.Expr]exprInfo // map of expressions without final type
- delayed []func() // stack of delayed actions
+ delayed []func() // stack of delayed action segments; segments are processed in FIFO order
+ finals []func() // list of final actions; processed at the end of type-checking the current set of files
objPath []Object // path of object dependencies during type inference (for cycle reporting)
// context within which the current object is type-checked
check.delayed = append(check.delayed, f)
}
+// atEnd adds f to the list of actions processed at the end
+// of type-checking, before initialization order computation.
+// Actions added by atEnd are processed after any actions
+// added by later.
+func (check *Checker) atEnd(f func()) {
+ check.finals = append(check.finals, f)
+}
+
// push pushes obj onto the object path and returns its index in the path.
func (check *Checker) push(obj Object) int {
check.objPath = append(check.objPath, obj)
check.methods = nil
check.untyped = nil
check.delayed = nil
+ check.finals = nil
// determine package name and collect valid files
pkg := check.pkg
check.packageObjects()
check.processDelayed(0) // incl. all functions
+ check.processFinals()
check.initOrder()
return
}
+func (check *Checker) processFinals() {
+ n := len(check.finals)
+ for _, f := range check.finals {
+ f() // must not append to check.finals
+ }
+ if len(check.finals) != n {
+ panic("internal error: final action list grew")
+ }
+}
+
func (check *Checker) recordUntyped() {
if !debug && check.Types == nil {
return // nothing to do
type AB interface {
a() interface {
A
- // TODO(gri) there shouldn't be an error here. See issue #33656.
- B // ERROR duplicate method a
+ B
}
b() interface {
A
- // TODO(gri) there shouldn't be an error here. See issue #33656.
- B // ERROR duplicate method a
+ B
}
}
t.allMethods = markComplete // avoid infinite recursion
+ var todo []*Func
var methods []*Func
var seen objset
addMethod := func(m *Func, explicit bool) {
- switch alt := seen.insert(m); {
- case alt == nil:
+ switch other := seen.insert(m); {
+ case other == nil:
methods = append(methods, m)
- case explicit || !Identical(m.Type(), alt.Type()):
+ case explicit:
panic("duplicate method " + m.name)
default:
- // silently drop method m
+ // check method signatures after all locally embedded interfaces are computed
+ todo = append(todo, m, other.(*Func))
}
}
}
}
+ 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)
+ }
+ }
+
if methods != nil {
sort.Sort(byUniqueMethodName(methods))
t.allMethods = methods
//
// Delay this check because it requires fully setup types;
// it is safe to continue in any case (was issue 6667).
- check.later(func() {
+ check.atEnd(func() {
if !Comparable(typ.key) {
check.errorf(e.Key.Pos(), "invalid map key type %s", typ.key)
}
var methods []*Func
var seen objset
addMethod := func(m *Func, explicit bool) {
- switch alt := seen.insert(m); {
- case alt == nil:
+ switch other := seen.insert(m); {
+ case other == nil:
methods = append(methods, m)
- case explicit || !Identical(m.Type(), alt.Type()):
+ case explicit:
check.errorf(m.pos, "duplicate method %s", m.name)
- // We use "other" rather than "previous" here because
- // the first declaration seen may not be textually
- // earlier in the source.
- check.errorf(alt.Pos(), "\tother declaration of %s", m) // secondary error, \t indented
+ check.reportAltDecl(other)
default:
- // silently drop method m
+ // check method signatures after all types are computed (issue #33656)
+ check.atEnd(func() {
+ if !Identical(m.typ, other.Type()) {
+ check.errorf(m.pos, "duplicate method %s", m.name)
+ check.reportAltDecl(other)
+ }
+ })
}
}
posList := check.posMap[ityp]
for i, typ := range ityp.embeddeds {
pos := posList[i] // embedding position
- typ := typ.Underlying().(*Interface)
+ typ := underlying(typ).(*Interface)
check.completeInterface(typ)
for _, m := range typ.allMethods {
copy := *m