// methodInfo represents an interface method.
// At least one of src or fun must be non-nil.
-// (Methods declared in the current package have a non-nil src,
-// and eventually a non-nil fun field; imported and predeclared
-// methods have a nil src, and only a non-nil fun field.)
+// (Methods declared in the current package have a non-nil scope
+// and src, and eventually a non-nil fun field; imported and pre-
+// declared methods have a nil scope and src, and only a non-nil
+// fun field.)
type methodInfo struct {
- src *ast.Field // syntax tree representation of interface method; or nil
- fun *Func // corresponding fully type-checked method type; or nil
+ scope *Scope // scope of interface method; or nil
+ src *ast.Field // syntax tree representation of interface method; or nil
+ fun *Func // corresponding fully type-checked method type; or nil
}
func (info *methodInfo) String() string {
}
}
-// infoFromTypeLit computes the method set for the given interface iface.
+// infoFromTypeLit computes the method set for the given interface iface
+// declared in scope.
// If a corresponding type name exists (tname != nil), it is used for
// cycle detection and to cache the method set.
// The result is the method set, or nil if there is a cycle via embedded
// but they were either reported (e.g., blank methods), or will be found
// (again) when computing the interface's type.
// If tname is not nil it must be the last element in path.
-func (check *Checker) infoFromTypeLit(iface *ast.InterfaceType, tname *TypeName, path []*TypeName) (info *ifaceInfo) {
+func (check *Checker) infoFromTypeLit(scope *Scope, iface *ast.InterfaceType, tname *TypeName, path []*TypeName) (info *ifaceInfo) {
assert(iface != nil)
// lazy-allocate interfaces map
continue // ignore
}
- m := &methodInfo{src: f}
+ m := &methodInfo{scope: scope, src: f}
if check.declareInMethodSet(&mset, f.Pos(), m) {
info.methods = append(info.methods, m)
}
return check.infoFromQualifiedTypeName(typ)
case *ast.InterfaceType:
// type tname interface{...}
- return check.infoFromTypeLit(typ, tname, path)
+ return check.infoFromTypeLit(decl.file, typ, tname, path)
}
// type tname X // and X is not an interface type
return nil
// collect embedded interfaces
// Only needed for printing and API. Delay collection
// to end of type-checking when all types are complete.
- interfaceScope := check.scope // capture for use in closure below
+ interfaceContext := check.context // capture for use in closure below
check.later(func() {
- check.scope = interfaceScope
+ check.context = interfaceContext
if trace {
check.trace(iface.Pos(), "-- delayed checking embedded interfaces of %s", iface)
check.indent++
if len(f.Names) == 0 {
typ := check.typ(f.Type)
// typ should be a named type denoting an interface
- // (the parser will make sure it's a name type but
+ // (the parser will make sure it's a named type but
// constructed ASTs may be wrong).
if typ == Typ[Invalid] {
continue // error reported before
if def != nil {
tname = def.obj
}
- info := check.infoFromTypeLit(iface, tname, path)
+ info := check.infoFromTypeLit(check.scope, iface, tname, path)
if info == nil || info == &emptyIfaceInfo {
// error or empty interface - exit early
ityp.allMethods = markComplete
}
// fix signatures now that we have collected all methods
+ savedContext := check.context
for _, minfo := range sigfix {
+ // (possibly embedded) methods must be type-checked within their scope and
+ // type-checking them must not affect the current context (was issue #23914)
+ check.context = context{scope: minfo.scope}
typ := check.typ(minfo.src.Type)
sig, _ := typ.(*Signature)
if sig == nil {
sig.recv = old.recv
*old = *sig // update signature (don't replace pointer!)
}
+ check.context = savedContext
// sort to match NewInterface
// TODO(gri) we may be able to switch to source order