From 6baed7a010b89c9547b700000e859d32a6d51741 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 26 Mar 2020 15:29:49 +0300 Subject: [PATCH] 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. --- pkg/compiler/analysis.go | 25 +++++++++++++++++-------- pkg/compiler/codegen.go | 13 ++++++++++--- pkg/compiler/slice_test.go | 31 +++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 11 deletions(-) diff --git a/pkg/compiler/analysis.go b/pkg/compiler/analysis.go index bf3272baa..6ae160931 100644 --- a/pkg/compiler/analysis.go +++ b/pkg/compiler/analysis.go @@ -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 { diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index 5761f94f9..7980b9ac1 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -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) } } diff --git a/pkg/compiler/slice_test.go b/pkg/compiler/slice_test.go index a9b0ce8f8..40600ea28 100644 --- a/pkg/compiler/slice_test.go +++ b/pkg/compiler/slice_test.go @@ -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) {