Commit 73becbf9 authored by Robert Griesemer's avatar Robert Griesemer

go/types: use correct (file) scopes when computing interface method sets

This was already partially fixed by commit 99843e22
(https://go-review.googlesource.com/c/go/+/96376); but
we missed a couple of places where we also need to
propagate the scope.

Fixes #25008.

Change-Id: I041fa74d1f6d3b5a8edb922efa126ff1dacd7900
Reviewed-on: https://go-review.googlesource.com/109139Reviewed-by: default avatarAlan Donovan <adonovan@google.com>
parent f2df0ec7
...@@ -90,6 +90,7 @@ var tests = [][]string{ ...@@ -90,6 +90,7 @@ var tests = [][]string{
{"testdata/labels.src"}, {"testdata/labels.src"},
{"testdata/issues.src"}, {"testdata/issues.src"},
{"testdata/blank.src"}, {"testdata/blank.src"},
{"testdata/issue25008b.src", "testdata/issue25008a.src"}, // order (b before a) is crucial!
} }
var fset = token.NewFileSet() var fset = token.NewFileSet()
......
...@@ -221,9 +221,9 @@ func (check *Checker) infoFromTypeLit(scope *Scope, iface *ast.InterfaceType, tn ...@@ -221,9 +221,9 @@ func (check *Checker) infoFromTypeLit(scope *Scope, iface *ast.InterfaceType, tn
var e *ifaceInfo var e *ifaceInfo
switch ename := f.Type.(type) { switch ename := f.Type.(type) {
case *ast.Ident: case *ast.Ident:
e = check.infoFromTypeName(ename, path) e = check.infoFromTypeName(scope, ename, path)
case *ast.SelectorExpr: case *ast.SelectorExpr:
e = check.infoFromQualifiedTypeName(ename) e = check.infoFromQualifiedTypeName(scope, ename)
default: default:
// The parser makes sure we only see one of the above. // The parser makes sure we only see one of the above.
// Constructed ASTs may contain other (invalid) nodes; // Constructed ASTs may contain other (invalid) nodes;
...@@ -262,7 +262,7 @@ func (check *Checker) infoFromTypeLit(scope *Scope, iface *ast.InterfaceType, tn ...@@ -262,7 +262,7 @@ func (check *Checker) infoFromTypeLit(scope *Scope, iface *ast.InterfaceType, tn
// which must denote a type whose underlying type is an interface. // which must denote a type whose underlying type is an interface.
// The same result qualifications apply as for infoFromTypeLit. // The same result qualifications apply as for infoFromTypeLit.
// infoFromTypeName should only be called from infoFromTypeLit. // infoFromTypeName should only be called from infoFromTypeLit.
func (check *Checker) infoFromTypeName(name *ast.Ident, path []*TypeName) *ifaceInfo { func (check *Checker) infoFromTypeName(scope *Scope, name *ast.Ident, path []*TypeName) *ifaceInfo {
// A single call of infoFromTypeName handles a sequence of (possibly // A single call of infoFromTypeName handles a sequence of (possibly
// recursive) type declarations connected via unqualified type names. // recursive) type declarations connected via unqualified type names.
// Each type declaration leading to another typename causes a "tail call" // Each type declaration leading to another typename causes a "tail call"
...@@ -291,7 +291,7 @@ func (check *Checker) infoFromTypeName(name *ast.Ident, path []*TypeName) *iface ...@@ -291,7 +291,7 @@ func (check *Checker) infoFromTypeName(name *ast.Ident, path []*TypeName) *iface
typenameLoop: typenameLoop:
// name must be a type name denoting a type whose underlying type is an interface // name must be a type name denoting a type whose underlying type is an interface
obj := check.lookup(name.Name) _, obj := scope.LookupParent(name.Name, check.pos)
if obj == nil { if obj == nil {
return nil return nil
} }
...@@ -333,7 +333,7 @@ typenameLoop: ...@@ -333,7 +333,7 @@ typenameLoop:
goto typenameLoop goto typenameLoop
case *ast.SelectorExpr: case *ast.SelectorExpr:
// type tname p.T // type tname p.T
return check.infoFromQualifiedTypeName(typ) return check.infoFromQualifiedTypeName(decl.file, typ)
case *ast.InterfaceType: case *ast.InterfaceType:
// type tname interface{...} // type tname interface{...}
return check.infoFromTypeLit(decl.file, typ, tname, path) return check.infoFromTypeLit(decl.file, typ, tname, path)
...@@ -360,13 +360,13 @@ typenameLoop: ...@@ -360,13 +360,13 @@ typenameLoop:
} }
// infoFromQualifiedTypeName computes the method set for the given qualified type name, or nil. // infoFromQualifiedTypeName computes the method set for the given qualified type name, or nil.
func (check *Checker) infoFromQualifiedTypeName(qname *ast.SelectorExpr) *ifaceInfo { func (check *Checker) infoFromQualifiedTypeName(scope *Scope, qname *ast.SelectorExpr) *ifaceInfo {
// see also Checker.selector // see also Checker.selector
name, _ := qname.X.(*ast.Ident) name, _ := qname.X.(*ast.Ident)
if name == nil { if name == nil {
return nil return nil
} }
obj1 := check.lookup(name.Name) _, obj1 := scope.LookupParent(name.Name, check.pos)
if obj1 == nil { if obj1 == nil {
return nil return nil
} }
......
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
import "io"
type A interface {
io.Reader
}
func f(a A) {
a.Read(nil)
}
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
type B interface {
A
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment