compiler: fix global constant traversal

There can be no global variables, but some global constants.
Introduced in 0b44a430.
This commit is contained in:
Evgenii Stratonikov 2020-12-08 15:24:01 +03:00
parent b807fd9e7f
commit ec58bec803
3 changed files with 37 additions and 14 deletions

View file

@ -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`.

View file

@ -202,12 +202,22 @@ func TestExportedVariable(t *testing.T) {
}
func TestExportedConst(t *testing.T) {
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) {

View file

@ -0,0 +1,4 @@
package constonly
// Answer is the only thing you will ever need.
const Answer = 42