compiler: allow to declare slices of compound types

Previously this declarations were ignored which resulted
in runtime errors, because VM's nil is an element of primitive type
and can't be converted to an array.
This commit is contained in:
Evgenii Stratonikov 2020-03-26 15:29:49 +03:00
parent c738975b7b
commit 6baed7a010
3 changed files with 58 additions and 11 deletions

View file

@ -187,6 +187,22 @@ func isBuiltin(expr ast.Expr) bool {
return false
}
func (c *codegen) isCompoundArrayType(t ast.Expr) bool {
switch s := t.(type) {
case *ast.ArrayType:
return true
case *ast.Ident:
arr, ok := c.typeInfo.Types[s].Type.Underlying().(*types.Slice)
return ok && !isByte(arr.Elem())
}
return false
}
func isByte(t types.Type) bool {
e, ok := t.(*types.Basic)
return ok && e.Kind() == types.Byte
}
func isByteArray(lit *ast.CompositeLit, tInfo *types.Info) bool {
if len(lit.Elts) == 0 {
if typ, ok := lit.Type.(*ast.ArrayType); ok {
@ -199,14 +215,7 @@ func isByteArray(lit *ast.CompositeLit, tInfo *types.Info) bool {
}
typ := tInfo.Types[lit.Elts[0]].Type.Underlying()
switch t := typ.(type) {
case *types.Basic:
switch t.Kind() {
case types.Byte:
return true
}
}
return false
return isByte(typ)
}
func isSyscall(fun *funcScope) bool {

View file

@ -276,9 +276,16 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
for _, spec := range n.Specs {
switch t := spec.(type) {
case *ast.ValueSpec:
for i, val := range t.Values {
ast.Walk(c, val)
l := c.scope.newLocal(t.Names[i].Name)
if len(t.Values) != 0 {
for i, val := range t.Values {
ast.Walk(c, val)
l := c.scope.newLocal(t.Names[i].Name)
c.emitStoreLocal(l)
}
} else if c.isCompoundArrayType(t.Type) {
emit.Opcode(c.prog.BinWriter, opcode.PUSH0)
emit.Opcode(c.prog.BinWriter, opcode.NEWARRAY)
l := c.scope.newLocal(t.Names[0].Name)
c.emitStoreLocal(l)
}
}

View file

@ -3,6 +3,8 @@ package compiler_test
import (
"math/big"
"testing"
"github.com/nspcc-dev/neo-go/pkg/vm"
)
var sliceTestCases = []testCase{
@ -128,6 +130,35 @@ var sliceTestCases = []testCase{
}`,
[]byte{2, 3},
},
{
"declare compound slice",
`package foo
func Main() []string {
var a []string
a = append(a, "a")
a = append(a, "b")
return a
}`,
[]vm.StackItem{
vm.NewByteArrayItem([]byte("a")),
vm.NewByteArrayItem([]byte("b")),
},
},
{
"declare compound slice alias",
`package foo
type strs []string
func Main() []string {
var a strs
a = append(a, "a")
a = append(a, "b")
return a
}`,
[]vm.StackItem{
vm.NewByteArrayItem([]byte("a")),
vm.NewByteArrayItem([]byte("b")),
},
},
}
func TestSliceOperations(t *testing.T) {