From 63732d432646def8b49d78d33c63ae41451d53e6 Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Mon, 28 Jan 2019 16:00:15 +0100 Subject: [PATCH] fix: set type correctly for variable declaration with assignment (#59) Do not ignore type node when used in a variable declaration with assign. The source node in a assign node can be the 2nd or the 3rd (the 2nd being the type). --- _test/method10.go | 16 +++++++--------- _test/var5.go | 12 ++++++++++++ interp/cfg.go | 40 ++++++++++++++++++++++++---------------- interp/interp_test.go | 39 ++++++++++++++++++++++++++++++--------- interp/run.go | 2 +- 5 files changed, 74 insertions(+), 35 deletions(-) create mode 100644 _test/var5.go diff --git a/_test/method10.go b/_test/method10.go index 9527488a..f8fee19f 100644 --- a/_test/method10.go +++ b/_test/method10.go @@ -1,15 +1,13 @@ package main +type T int + +func (t T) foo() { println("foo", t) } + func main() { - o := Coord{3, 4} - println(o.dist()) -} - -func (c Coord) dist() int { return c.x*c.x + c.y*c.y } - -type Coord struct { - x, y int + var t T = 2 + t.foo() } // Output: -// 25 +// foo 2 diff --git a/_test/var5.go b/_test/var5.go new file mode 100644 index 00000000..c8b51228 --- /dev/null +++ b/_test/var5.go @@ -0,0 +1,12 @@ +package main + +import "fmt" + +func main() { + var a int64 = 64 + fmt.Printf("a: %v %T", a, a) + fmt.Println() +} + +// Output: +// a: 64 int64 diff --git a/interp/cfg.go b/interp/cfg.go index e1a62d8b..5a332b1b 100644 --- a/interp/cfg.go +++ b/interp/cfg.go @@ -148,10 +148,6 @@ func (interp *Interpreter) Cfg(root *Node) ([]*Node, error) { if l := len(n.child); n.anc.kind == ConstDecl && l == 1 { // Implicit iota assignment. TODO: replicate previous explicit assignment n.child = append(n.child, &Node{anc: n, interp: interp, kind: Ident, ident: "iota"}) - } else if l%2 == 1 { - // Odd number of children: remove the type node, useless for assign - i := l / 2 - n.child = append(n.child[:i], n.child[i+1:]...) } case BlockStmt: @@ -221,9 +217,6 @@ func (interp *Interpreter) Cfg(root *Node) ([]*Node, error) { case If0, If1, If2, If3: scope = scope.push(0) - //case SelectStmt: - // err = CfgError(fmt.Errorf("cfg: SelectStmt not implemented; %s", n.fset.Position(n.pos))) - case Switch0: // Make sure default clause is in last position c := n.child[1].child @@ -253,12 +246,16 @@ func (interp *Interpreter) Cfg(root *Node) ([]*Node, error) { n.findex = scope.inc(interp) case Define, AssignStmt: - wireChild(n) - dest, src := n.child[0], n.child[1] + dest, src := n.child[0], n.child[len(n.child)-1] sym, level, _ := scope.lookup(dest.ident) if n.kind == Define { + if len(n.child) == 3 { + // Type is provided in var declaration + dest.typ, err = nodeType(interp, scope, n.child[1]) + } else { + dest.typ = src.typ + } dest.val = src.val - dest.typ = src.typ dest.recv = src.recv dest.findex = sym.index if src.action == GetFunc { @@ -273,6 +270,7 @@ func (interp *Interpreter) Cfg(root *Node) ([]*Node, error) { sym.typ = dest.typ } } + wireChild(n) // Detect invalid float truncate if isInt(dest.typ) && isFloat(src.typ) { err = src.cfgError("invalid float truncate") @@ -293,9 +291,13 @@ func (interp *Interpreter) Cfg(root *Node) ([]*Node, error) { src.level = level case src.kind == BasicLit: // TODO: perform constant folding and propagation here - // Convert literal value to destination type - src.val = reflect.ValueOf(src.val).Convert(dest.typ.TypeOf()) - src.typ = dest.typ + if dest.typ.cat == InterfaceT { + src.val = reflect.ValueOf(src.val) + } else { + // Convert literal value to destination type + src.val = reflect.ValueOf(src.val).Convert(dest.typ.TypeOf()) + src.typ = dest.typ + } } n.typ = dest.typ if sym != nil { @@ -895,9 +897,15 @@ func (interp *Interpreter) Cfg(root *Node) ([]*Node, error) { } case StarExpr: - wireChild(n) - n.typ = n.child[0].typ.val - n.findex = scope.inc(interp) + if n.anc.kind == Define && len(n.anc.child) == 3 && n.anc.child[1] == n { + // pointer type expression in a var definition + n.gen = nop + } else { + // dereference expression + wireChild(n) + n.typ = n.child[0].typ.val + n.findex = scope.inc(interp) + } case Switch0: n.start = n.child[1].start diff --git a/interp/interp_test.go b/interp/interp_test.go index 157e18f7..39f6c442 100644 --- a/interp/interp_test.go +++ b/interp/interp_test.go @@ -2926,15 +2926,13 @@ func Example_method10() { src := ` package main +type T int + +func (t T) foo() { println("foo", t) } + func main() { - o := Coord{3, 4} - println(o.dist()) -} - -func (c Coord) dist() int { return c.x*c.x + c.y*c.y } - -type Coord struct { - x, y int + var t T = 2 + t.foo() } ` i := interp.New(interp.Opt{Entry: "main"}) @@ -2945,7 +2943,7 @@ type Coord struct { } // Output: - // 25 + // foo 2 } func Example_method11() { @@ -5709,6 +5707,29 @@ func main() { // 2 3 } +func Example_var5() { + src := ` +package main + +import "fmt" + +func main() { + var a int64 = 64 + fmt.Printf("a: %v %T", a, a) + fmt.Println() +} +` + i := interp.New(interp.Opt{Entry: "main"}) + i.Use(stdlib.Value, stdlib.Type) + _, err := i.Eval(src) + if err != nil { + panic(err) + } + + // Output: + // a: 64 int64 +} + func Example_variadic() { src := ` package main diff --git a/interp/run.go b/interp/run.go index 0bd67563..f6b3b539 100644 --- a/interp/run.go +++ b/interp/run.go @@ -185,7 +185,7 @@ func assignX(n *Node) { // assign implements single value assignment func assign(n *Node) { value := genValue(n) - value1 := genValue(n.child[1]) + value1 := genValue(n.child[len(n.child)-1]) next := getExec(n.tnext) if n.child[0].typ.cat == InterfaceT {