Skip to content

Commit

Permalink
fix: selector type precedence
Browse files Browse the repository at this point in the history
  • Loading branch information
nrwiersma committed Sep 10, 2021
1 parent f7b0641 commit 47889b0
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 21 deletions.
10 changes: 10 additions & 0 deletions _test/selector-scope0.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,20 @@ func test(time string, t time.Time) string {
return time
}

var zero = time.Time{}

func test2(time string) time.Time {
return zero
}

func main() {
str := test("test", time.Now())
fmt.Println(str)

str2 := test2("test2")
fmt.Println(str2)
}

// Output:
// test
// 0001-01-01 00:00:00 +0000 UTC
49 changes: 28 additions & 21 deletions interp/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -776,30 +776,19 @@ 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
// prioritise the package type.
if n.anc.kind == fieldExpr {
lt = findPackageType(interp, sc, n.child[0])
}
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, err = nodeType2(interp, localScope, n.child[0], seen); err != nil {
return nil, err
}

if lt.incomplete {
break
}
Expand Down Expand Up @@ -926,6 +915,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
Expand Down

0 comments on commit 47889b0

Please sign in to comment.