From ec58bec8034b3754c2fed670208c9016b547a4fc Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Tue, 8 Dec 2020 15:24:01 +0300 Subject: [PATCH] compiler: fix global constant traversal There can be no global variables, but some global constants. Introduced in 0b44a430. --- pkg/compiler/analysis.go | 25 ++++++++++++++++-------- pkg/compiler/global_test.go | 22 +++++++++++++++------ pkg/compiler/testdata/constonly/const.go | 4 ++++ 3 files changed, 37 insertions(+), 14 deletions(-) create mode 100644 pkg/compiler/testdata/constonly/const.go diff --git a/pkg/compiler/analysis.go b/pkg/compiler/analysis.go index b1015d3cd..fa3fa5501 100644 --- a/pkg/compiler/analysis.go +++ b/pkg/compiler/analysis.go @@ -43,11 +43,13 @@ func (c *codegen) getIdentName(pkg string, name string) string { // Same for `_deploy()` functions (see docs/compiler.md). func (c *codegen) traverseGlobals() (int, int, int) { var hasDefer bool - var n int + var n, nConst int initLocals := -1 deployLocals := -1 c.ForEachFile(func(f *ast.File, _ *types.Package) { - n += countGlobals(f) + nv, nc := countGlobals(f) + n += nv + nConst += nc if initLocals == -1 || deployLocals == -1 || !hasDefer { ast.Inspect(f, func(node ast.Node) bool { switch n := node.(type) { @@ -75,7 +77,7 @@ func (c *codegen) traverseGlobals() (int, int, int) { if hasDefer { n++ } - if n != 0 || initLocals > -1 { + if n+nConst != 0 || initLocals > -1 { if n > 255 { c.prog.BinWriter.Err = errors.New("too many global variables") return 0, initLocals, deployLocals @@ -88,7 +90,7 @@ func (c *codegen) traverseGlobals() (int, int, int) { } seenBefore := false c.ForEachPackage(func(pkg *loader.PackageInfo) { - if n > 0 { + if n+nConst > 0 { for _, f := range pkg.Files { c.fillImportMap(f, pkg.Pkg) c.convertGlobals(f, pkg.Pkg) @@ -116,7 +118,9 @@ func (c *codegen) traverseGlobals() (int, int, int) { // countGlobals counts the global variables in the program to add // them with the stack size of the function. -func countGlobals(f ast.Node) (i int) { +// Second returned argument contains amount of global constants. +func countGlobals(f ast.Node) (int, int) { + var numVar, numConst int ast.Inspect(f, func(node ast.Node) bool { switch n := node.(type) { // Skip all function declarations if we have already encountered `defer`. @@ -125,11 +129,16 @@ func countGlobals(f ast.Node) (i int) { // After skipping all funcDecls we are sure that each value spec // is a global declared variable or constant. case *ast.GenDecl: - if n.Tok == token.VAR { + isVar := n.Tok == token.VAR + if isVar || n.Tok == token.CONST { for _, s := range n.Specs { for _, id := range s.(*ast.ValueSpec).Names { if id.Name != "_" { - i++ + if isVar { + numVar++ + } else { + numConst++ + } } } } @@ -138,7 +147,7 @@ func countGlobals(f ast.Node) (i int) { } return true }) - return + return numVar, numConst } // isExprNil looks if the given expression is a `nil`. diff --git a/pkg/compiler/global_test.go b/pkg/compiler/global_test.go index 434c22290..f58673d07 100644 --- a/pkg/compiler/global_test.go +++ b/pkg/compiler/global_test.go @@ -202,12 +202,22 @@ func TestExportedVariable(t *testing.T) { } func TestExportedConst(t *testing.T) { - src := `package foo - import "github.com/nspcc-dev/neo-go/pkg/compiler/testdata/multi" - func Main() int { - return multi.SomeConst - }` - eval(t, src, big.NewInt(42)) + t.Run("with vars", func(t *testing.T) { + src := `package foo + import "github.com/nspcc-dev/neo-go/pkg/compiler/testdata/multi" + func Main() int { + return multi.SomeConst + }` + eval(t, src, big.NewInt(42)) + }) + t.Run("const only", func(t *testing.T) { + src := `package foo + import "github.com/nspcc-dev/neo-go/pkg/compiler/testdata/constonly" + func Main() int { + return constonly.Answer + }` + eval(t, src, big.NewInt(42)) + }) } func TestMultipleFuncSameName(t *testing.T) { diff --git a/pkg/compiler/testdata/constonly/const.go b/pkg/compiler/testdata/constonly/const.go new file mode 100644 index 000000000..8066eab5f --- /dev/null +++ b/pkg/compiler/testdata/constonly/const.go @@ -0,0 +1,4 @@ +package constonly + +// Answer is the only thing you will ever need. +const Answer = 42