interp: fix redeclarations containing a blank variable
In [short variable declarations](https://go.dev/ref/spec#Short_variable_declarations), The reuse of existing symbols is possible only if a new variable is defined, otherwise a new symbol must be created, which was not the case in the issue. Search for new symbols and correctly ignore blank variables. Fixes #1434.
This commit is contained in:
21
_test/assign17.go
Normal file
21
_test/assign17.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
s := make([]map[string]string, 0)
|
||||
m := make(map[string]string)
|
||||
m["m1"] = "m1"
|
||||
m["m2"] = "m2"
|
||||
s = append(s, m)
|
||||
tmpStr := "start"
|
||||
println(tmpStr)
|
||||
for _, v := range s {
|
||||
tmpStr, ok := v["m1"]
|
||||
println(tmpStr, ok)
|
||||
}
|
||||
println(tmpStr)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// start
|
||||
// m1 true
|
||||
// start
|
||||
21
_test/assign18.go
Normal file
21
_test/assign18.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
s := make([]map[string]string, 0)
|
||||
m := make(map[string]string)
|
||||
m["m1"] = "m1"
|
||||
m["m2"] = "m2"
|
||||
s = append(s, m)
|
||||
tmpStr := "start"
|
||||
println(tmpStr)
|
||||
for _, v := range s {
|
||||
tmpStr, _ := v["m1"]
|
||||
println(tmpStr)
|
||||
}
|
||||
println(tmpStr)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// start
|
||||
// m1
|
||||
// start
|
||||
@@ -221,6 +221,14 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
|
||||
sc.sym[label] = sym
|
||||
c.sym = sym
|
||||
}
|
||||
// If block is the body of a function, get declared variables in current scope.
|
||||
// This is done in order to add the func signature symbols into sc.sym,
|
||||
// as we will need them in post-processing.
|
||||
if n.anc != nil && n.anc.kind == funcDecl {
|
||||
for k, v := range sc.anc.sym {
|
||||
sc.sym[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
case breakStmt, continueStmt, gotoStmt:
|
||||
if len(n.child) == 0 {
|
||||
@@ -2288,11 +2296,36 @@ func compDefineX(sc *scope, n *node) error {
|
||||
return n.cfgErrorf("unsupported assign expression")
|
||||
}
|
||||
|
||||
// Handle redeclarations: find out new symbols vs existing ones.
|
||||
symIsNew := map[string]bool{}
|
||||
hasNewSymbol := false
|
||||
for i := range types {
|
||||
id := n.child[i].ident
|
||||
if id == "_" || id == "" {
|
||||
continue
|
||||
}
|
||||
if _, found := symIsNew[id]; found {
|
||||
return n.cfgErrorf("%s repeated on left side of :=", id)
|
||||
}
|
||||
// A new symbol doesn't exist in current scope. Upper scopes are not
|
||||
// taken into accout here, as a new symbol can shadow an existing one.
|
||||
if _, found := sc.sym[id]; found {
|
||||
symIsNew[id] = false
|
||||
} else {
|
||||
symIsNew[id] = true
|
||||
hasNewSymbol = true
|
||||
}
|
||||
}
|
||||
|
||||
for i, t := range types {
|
||||
var index int
|
||||
id := n.child[i].ident
|
||||
if sym, level, ok := sc.lookup(id); ok && level == n.child[i].level && sym.kind == varSym && sym.typ.id() == t.id() {
|
||||
// Reuse symbol in case of a variable redeclaration with the same type.
|
||||
// A variable can be redeclared if at least one other not blank variable is created.
|
||||
// The redeclared variable must be of same type (it is reassigned, not created).
|
||||
// Careful to not reuse a variable which has been shadowed (it must not be a newSym).
|
||||
sym, level, ok := sc.lookup(id)
|
||||
canRedeclare := hasNewSymbol && len(symIsNew) > 1 && !symIsNew[id] && ok
|
||||
if canRedeclare && level == n.child[i].level && sym.kind == varSym && sym.typ.id() == t.id() {
|
||||
index = sym.index
|
||||
} else {
|
||||
index = sc.add(t)
|
||||
|
||||
@@ -133,6 +133,8 @@ func TestEvalAssign(t *testing.T) {
|
||||
{src: "j := true || _", err: "1:33: cannot use _ as value"},
|
||||
{src: "j := true && _", err: "1:33: cannot use _ as value"},
|
||||
{src: "j := interface{}(int(1)); j.(_)", err: "1:54: cannot use _ as value"},
|
||||
{src: "ff := func() (a, b, c int) {return 1, 2, 3}; x, y, x := ff()", err: "1:73: x repeated on left side of :="},
|
||||
{src: "xx := 1; xx, _ := 2, 3", err: "1:37: no new variables on left side of :="},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user