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:
parent
c738975b7b
commit
6baed7a010
3 changed files with 58 additions and 11 deletions
|
@ -187,6 +187,22 @@ func isBuiltin(expr ast.Expr) bool {
|
||||||
return false
|
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 {
|
func isByteArray(lit *ast.CompositeLit, tInfo *types.Info) bool {
|
||||||
if len(lit.Elts) == 0 {
|
if len(lit.Elts) == 0 {
|
||||||
if typ, ok := lit.Type.(*ast.ArrayType); ok {
|
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()
|
typ := tInfo.Types[lit.Elts[0]].Type.Underlying()
|
||||||
switch t := typ.(type) {
|
return isByte(typ)
|
||||||
case *types.Basic:
|
|
||||||
switch t.Kind() {
|
|
||||||
case types.Byte:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func isSyscall(fun *funcScope) bool {
|
func isSyscall(fun *funcScope) bool {
|
||||||
|
|
|
@ -276,9 +276,16 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
for _, spec := range n.Specs {
|
for _, spec := range n.Specs {
|
||||||
switch t := spec.(type) {
|
switch t := spec.(type) {
|
||||||
case *ast.ValueSpec:
|
case *ast.ValueSpec:
|
||||||
for i, val := range t.Values {
|
if len(t.Values) != 0 {
|
||||||
ast.Walk(c, val)
|
for i, val := range t.Values {
|
||||||
l := c.scope.newLocal(t.Names[i].Name)
|
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)
|
c.emitStoreLocal(l)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ package compiler_test
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
)
|
)
|
||||||
|
|
||||||
var sliceTestCases = []testCase{
|
var sliceTestCases = []testCase{
|
||||||
|
@ -128,6 +130,35 @@ var sliceTestCases = []testCase{
|
||||||
}`,
|
}`,
|
||||||
[]byte{2, 3},
|
[]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) {
|
func TestSliceOperations(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue