interp: fix type selector precedence

The current `nodeType` selector precedence is heavy handed in favour of package type. It seems to often create `typeSym` symbols as variable types in the scope will never be found. To fix this if the ancestor node is a field expression, the package type is searched for. After this, if the type is still `nil` the normal scope is searched using `nodeType2`.

Fixes #1158
This commit is contained in:
Nicholas Wiersma
2021-09-15 10:42:08 +02:00
committed by GitHub
parent e7c0f68bab
commit 5af51aefe6
4 changed files with 41 additions and 24 deletions

View File

@@ -777,28 +777,17 @@ func nodeType2(interp *Interpreter, sc *scope, n *node, seen map[*node]bool) (t
// Resolve the left part of selector, then lookup the right part on it
var lt *itype
// If we are in a list of func parameters, and we are a selector on a binPkgT, but
// one of the other parameters has the same name as the pkg name, in the list of
// symbols we would find the other parameter instead of the pkg because it comes
// first when looking up in the stack of scopes. So in that case we force the
// lookup directly in the root scope to shortcircuit that issue.
var localScope *scope
localScope = sc
if n.anc != nil && len(n.anc.child) > 1 && n.anc.child[1] == n &&
// This check is weaker than what we actually want to know, i.e. whether
// n.anc.child[0] is a variable, but it seems at this point in the run we have no
// way of knowing that yet (typ is nil, so there's no typ.cat yet).
n.anc.child[0].kind == identExpr {
for {
if localScope.level == 0 {
break
}
localScope = localScope.anc
}
// Lookup the package symbol first if we are in a field expression as
// a previous parameter has the same name as the package, we need to
// prioritize the package type.
if n.anc.kind == fieldExpr {
lt = findPackageType(interp, sc, n.child[0])
}
if lt, err = nodeType2(interp, localScope, n.child[0], seen); err != nil {
return nil, err
if lt == nil {
// No package was found or we are not in a field expression, we are looking for a variable.
if lt, err = nodeType2(interp, sc, n.child[0], seen); err != nil {
return nil, err
}
}
if lt.incomplete {
@@ -927,6 +916,24 @@ func nodeType2(interp *Interpreter, sc *scope, n *node, seen map[*node]bool) (t
return t, err
}
// findPackageType searches the top level scope for a package type.
func findPackageType(interp *Interpreter, sc *scope, n *node) *itype {
// Find the root scope, the package symbols will exist there.
for {
if sc.level == 0 {
break
}
sc = sc.anc
}
baseName := filepath.Base(interp.fset.Position(n.pos).Filename)
sym, _, found := sc.lookup(filepath.Join(n.ident, baseName))
if !found || sym.typ == nil && sym.typ.cat != srcPkgT && sym.typ.cat != binPkgT {
return nil
}
return sym.typ
}
func isBuiltinCall(n *node, sc *scope) bool {
if n.kind != callExpr {
return false