diff --git a/_test/add1.go b/_test/add1.go index 01876511..238ae331 100644 --- a/_test/add1.go +++ b/_test/add1.go @@ -22,6 +22,12 @@ func main() { var g int = 2 a = 10 + g println(a.(int)) + + // multiple assignment + var foo interface{} + foo, a = "hello", 11 + g + println(a.(int)) + println(foo.(string)) } // Output: @@ -31,3 +37,5 @@ func main() { // 10 // 11 // 12 +// 13 +// hello diff --git a/_test/issue-1094.go b/_test/issue-1094.go new file mode 100644 index 00000000..02e5bd28 --- /dev/null +++ b/_test/issue-1094.go @@ -0,0 +1,12 @@ +package main + +import "fmt" + +func main() { + var x interface{} + x = "a" + fmt.Sprintf("b") + fmt.Printf("%v %T\n", x, x) +} + +// Ouput: +// ab string diff --git a/interp/type.go b/interp/type.go index 9d2024c3..c2e96eb2 100644 --- a/interp/type.go +++ b/interp/type.go @@ -277,40 +277,26 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) { } } - // Because an empty interface concrete type "mutates" as different values are - // assigned to it, we need to make a new itype from scratch everytime a new - // assignment is made, and not let different nodes (of the same variable) share the - // same itype. Otherwise they would overwrite each other. - if n.anc.kind == assignStmt && isInterface(n.anc.child[0].typ) && len(n.anc.child[0].typ.field) == 0 { - // TODO(mpl): do the indexes properly for multiple assignments on the same line. - // Also, maybe we should use nodeType to figure out dt.cat? but isn't it always - // gonna be an interfaceT anyway? - dt := new(itype) - dt.cat = interfaceT - val := new(itype) - val.cat = t.cat - dt.val = val - // TODO(mpl): do the indexes properly for multiple assignments on the same line. - // Also, maybe we should use nodeType to figure out dt.cat? but isn't it always - // gonna be an interfaceT anyway? - n.anc.child[0].typ = dt - // TODO(mpl): not sure yet whether we should do that last step. It doesn't seem - // to change anything either way though. - // t = dt - break - } - // If the node is to be assigned or returned, the node type is the destination type. dt := t switch a := n.anc; { + case a.kind == assignStmt && isEmptyInterface(a.child[0].typ): + // Because an empty interface concrete type "mutates" as different values are + // assigned to it, we need to make a new itype from scratch everytime a new + // assignment is made, and not let different nodes (of the same variable) share the + // same itype. Otherwise they would overwrite each other. + a.child[0].typ = &itype{cat: interfaceT, val: dt} + case a.kind == defineStmt && len(a.child) > a.nleft+a.nright: if dt, err = nodeType(interp, sc, a.child[a.nleft]); err != nil { return nil, err } + case a.kind == returnStmt: dt = sc.def.typ.ret[childPos(n)] } + if isInterface(dt) { dt.val = t }