From 681f2f9c4034b4c63be1cf416d0d73f90680e3e8 Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Wed, 12 Feb 2020 12:32:03 +0100 Subject: [PATCH] fix: correctly handle constant init for further type declarations --- _test/const6.go | 22 ++++++++++++++++++++++ _test/const7.go | 19 +++++++++++++++++++ interp/ast.go | 4 ---- interp/cfg.go | 22 +++++++++------------- interp/gta.go | 7 ++++++- interp/interp_eval_test.go | 8 ++++---- interp/value.go | 3 --- 7 files changed, 60 insertions(+), 25 deletions(-) create mode 100644 _test/const6.go create mode 100644 _test/const7.go diff --git a/_test/const6.go b/_test/const6.go new file mode 100644 index 000000000..a9115db19 --- /dev/null +++ b/_test/const6.go @@ -0,0 +1,22 @@ +package main + +const ( + maxNonStarters = 30 + maxBufferSize = maxNonStarters + 2 +) + +type reorderBuffer struct { + rune [maxBufferSize]Properties +} + +type Properties struct { + pos uint8 + size uint8 +} + +func main() { + println(len(reorderBuffer{}.rune)) +} + +// Output: +// 32 diff --git a/_test/const7.go b/_test/const7.go new file mode 100644 index 000000000..27d4af6da --- /dev/null +++ b/_test/const7.go @@ -0,0 +1,19 @@ +package main + +import "fmt" + +const ( + a = iota + b + c + d +) + +type T [c]int + +func main() { + fmt.Println(T{}) +} + +// Output: +// [0 0] diff --git a/interp/ast.go b/interp/ast.go index 872379f4b..5395d0e28 100644 --- a/interp/ast.go +++ b/interp/ast.go @@ -75,8 +75,6 @@ const ( parenExpr rangeStmt returnStmt - rvalueExpr - rtypeExpr selectStmt selectorExpr selectorImport @@ -154,8 +152,6 @@ var kinds = [...]string{ parenExpr: "parenExpr", rangeStmt: "rangeStmt", returnStmt: "returnStmt", - rvalueExpr: "rvalueExpr", - rtypeExpr: "rtypeExpr", selectStmt: "selectStmt", selectorExpr: "selectorExpr", selectorImport: "selectorImport", diff --git a/interp/cfg.go b/interp/cfg.go index 2bb25ede3..e0398ef76 100644 --- a/interp/cfg.go +++ b/interp/cfg.go @@ -429,7 +429,8 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) { if sc.global { // Do not overload existing symbols (defined in GTA) in global scope sym, _, _ = sc.lookup(dest.ident) - } else { + } + if sym == nil { sym = &symbol{index: sc.add(dest.typ), kind: varSym, typ: dest.typ} sc.sym[dest.ident] = sym } @@ -509,9 +510,10 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) { if isMapEntry(dest) { dest.gen = nop // skip getIndexMap } - } - if n.anc.kind == constDecl { - iotaValue++ + if n.anc.kind == constDecl { + sc.sym[dest.ident].kind = constSym + iotaValue++ + } } case incDecStmt: @@ -924,7 +926,8 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) { case identExpr: if isKey(n) || isNewDefine(n, sc) { break - } else if sym, level, ok := sc.lookup(n.ident); ok { + } + if sym, level, ok := sc.lookup(n.ident); ok { // Found symbol, populate node info n.typ, n.findex, n.level = sym.typ, sym.index, level if n.findex < 0 { @@ -941,11 +944,6 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) { case n.ident == "nil": n.kind = basicLit case sym.kind == binSym: - if sym.rval.IsValid() { - n.kind = rvalueExpr - } else { - n.kind = rtypeExpr - } n.typ = sym.typ n.rval = sym.rval case sym.kind == bltnSym: @@ -1161,10 +1159,8 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) { pkg := n.child[0].sym.typ.path if s, ok := interp.binPkg[pkg][name]; ok { if isBinType(s) { - n.kind = rtypeExpr n.typ = &itype{cat: valueT, rtype: s.Type().Elem()} } else { - n.kind = rvalueExpr n.typ = &itype{cat: valueT, rtype: s.Type(), untyped: isValueUntyped(s)} n.rval = s } @@ -1587,7 +1583,7 @@ func isBinType(v reflect.Value) bool { return v.IsValid() && v.Kind() == reflect // isType returns true if node refers to a type definition, false otherwise func (n *node) isType(sc *scope) bool { switch n.kind { - case arrayType, chanType, funcType, interfaceType, mapType, structType, rtypeExpr: + case arrayType, chanType, funcType, interfaceType, mapType, structType: return true case parenExpr, starExpr: if len(n.child) == 1 { diff --git a/interp/gta.go b/interp/gta.go index bfabb9091..cbc1fb0b1 100644 --- a/interp/gta.go +++ b/interp/gta.go @@ -21,6 +21,9 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error) switch n.kind { case constDecl: iotaValue = 0 + // Early parse of constDecl subtree, to compute all constant + // values which may be necessary in further declarations. + _, err = interp.cfg(n, pkgID) case blockStmt: if n != root { @@ -63,7 +66,9 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error) if typ.isBinMethod { typ = &itype{cat: valueT, rtype: typ.methodCallType(), isBinMethod: true} } - sc.sym[dest.ident] = &symbol{kind: varSym, global: true, index: sc.add(typ), typ: typ, rval: val} + if sc.sym[dest.ident] == nil { + sc.sym[dest.ident] = &symbol{kind: varSym, global: true, index: sc.add(typ), typ: typ, rval: val} + } if n.anc.kind == constDecl { sc.sym[dest.ident].kind = constSym iotaValue++ diff --git a/interp/interp_eval_test.go b/interp/interp_eval_test.go index a595ae2f9..e8d5fed67 100644 --- a/interp/interp_eval_test.go +++ b/interp/interp_eval_test.go @@ -78,11 +78,11 @@ func TestEvalBuiltin(t *testing.T) { i := interp.New(interp.Options{}) runTests(t, i, []testCase{ {src: `a := []int{}; a = append(a, 1); a`, res: "[1]"}, - {src: `a := []int{1}; a = append(a, 2, 3); a`, res: "[1 2 3]"}, - {src: `a := []int{1}; b := []int{2, 3}; a = append(a, b...); a`, res: "[1 2 3]"}, + {src: `b := []int{1}; b = append(a, 2, 3); b`, res: "[1 2 3]"}, + {src: `c := []int{1}; d := []int{2, 3}; c = append(c, d...); c`, res: "[1 2 3]"}, {src: `string(append([]byte("hello "), "world"...))`, res: "hello world"}, - {src: `a := "world"; string(append([]byte("hello "), a...))`, res: "hello world"}, - {src: `a := []byte("Hello"); copy(a, "world"); string(a)`, res: "world"}, + {src: `e := "world"; string(append([]byte("hello "), e...))`, res: "hello world"}, + {src: `f := []byte("Hello"); copy(f, "world"); string(f)`, res: "world"}, }) } diff --git a/interp/value.go b/interp/value.go index f7284daa1..a5df4628a 100644 --- a/interp/value.go +++ b/interp/value.go @@ -90,9 +90,6 @@ func genValue(n *node) func(*frame) reflect.Value { v = reflect.ValueOf(n.val) } return func(f *frame) reflect.Value { return v } - case rvalueExpr: - v := n.rval - return func(f *frame) reflect.Value { return v } default: if n.rval.IsValid() { v := n.rval