diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index a5fe85d1c..710d58de6 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -1455,6 +1455,14 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) { emit.Int(c.prog.BinWriter, 3) emit.Opcode(c.prog.BinWriter, opcode.ROLL) emit.Opcode(c.prog.BinWriter, opcode.MIN) + if !c.scope.voidCalls[expr] { + // insert top item to the bottom of MEMCPY args, so that it is left on stack + emit.Opcode(c.prog.BinWriter, opcode.DUP) + emit.Int(c.prog.BinWriter, 6) + emit.Opcode(c.prog.BinWriter, opcode.REVERSEN) + emit.Int(c.prog.BinWriter, 5) + emit.Opcode(c.prog.BinWriter, opcode.REVERSEN) + } emit.Opcode(c.prog.BinWriter, opcode.MEMCPY) case "make": typ := c.typeOf(expr.Args[0]) @@ -1512,7 +1520,9 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) { case "panic": emit.Opcode(c.prog.BinWriter, opcode.THROW) case "recover": - c.emitLoadByIndex(varGlobal, c.exceptionIndex) + if !c.scope.voidCalls[expr] { + c.emitLoadByIndex(varGlobal, c.exceptionIndex) + } emit.Opcode(c.prog.BinWriter, opcode.PUSHNULL) c.emitStoreByIndex(varGlobal, c.exceptionIndex) case "ToInteger", "ToByteArray", "ToBool": diff --git a/pkg/compiler/defer_test.go b/pkg/compiler/defer_test.go index 4a2f8f3b0..d9b39ea07 100644 --- a/pkg/compiler/defer_test.go +++ b/pkg/compiler/defer_test.go @@ -128,8 +128,8 @@ func TestRecover(t *testing.T) { return h() + a } func h() int { - defer func() { a += 2; _ = recover() }() - defer func() { a *= 3; _ = recover(); panic("again") }() + defer func() { a += 2; recover() }() + defer func() { a *= 3; recover(); panic("again") }() a = 1 panic("msg") return a diff --git a/pkg/compiler/for_test.go b/pkg/compiler/for_test.go index df2fa06df..f2995cc3c 100644 --- a/pkg/compiler/for_test.go +++ b/pkg/compiler/for_test.go @@ -737,6 +737,20 @@ func TestForLoopRangeMap(t *testing.T) { eval(t, src, big.NewInt(42)) } +func TestForLoopRangeTypeConversion(t *testing.T) { + src := `package foo + type intArr []int + func Main() int { + a := []int{1, 2, 3} + s := 0 + for _, v := range intArr(a) { + s += v + } + return s + }` + eval(t, src, big.NewInt(6)) +} + func TestForLoopComplexConditions(t *testing.T) { src := ` package foo diff --git a/pkg/compiler/func_scope.go b/pkg/compiler/func_scope.go index 5fa4613d1..e0df8f6a0 100644 --- a/pkg/compiler/func_scope.go +++ b/pkg/compiler/func_scope.go @@ -107,12 +107,22 @@ func (c *funcScope) analyzeVoidCalls(node ast.Node) bool { } case *ast.BinaryExpr: return false + case *ast.RangeStmt: + ce, ok := n.X.(*ast.CallExpr) + if ok { + c.voidCalls[ce] = false + } case *ast.IfStmt: // we can't just return `false`, because we still need to process body ce, ok := n.Cond.(*ast.CallExpr) if ok { c.voidCalls[ce] = false } + case *ast.SwitchStmt: + ce, ok := n.Tag.(*ast.CallExpr) + if ok { + c.voidCalls[ce] = false + } case *ast.CaseClause: for _, e := range n.List { ce, ok := e.(*ast.CallExpr) diff --git a/pkg/compiler/slice_test.go b/pkg/compiler/slice_test.go index 6ceb967dc..ee776407f 100644 --- a/pkg/compiler/slice_test.go +++ b/pkg/compiler/slice_test.go @@ -427,4 +427,14 @@ func TestCopy(t *testing.T) { }` eval(t, src, []byte{0, 3}) }) + t.Run("AssignToVariable", func(t *testing.T) { + src := `package foo + func Main() int { + src := []byte{3, 2, 1} + dst := make([]byte, 2) + n := copy(dst, src) + return n + }` + eval(t, src, big.NewInt(2)) + }) } diff --git a/pkg/compiler/switch_test.go b/pkg/compiler/switch_test.go index ce90ee0c2..73c711b79 100644 --- a/pkg/compiler/switch_test.go +++ b/pkg/compiler/switch_test.go @@ -33,6 +33,21 @@ var switchTestCases = []testCase{ }`, big.NewInt(2), }, + { + "type conversion in tag", + `package main + type state int + func Main() int { + a := 1 + switch state(a) { + case 1: + return 42 + default: + return 11 + } + }`, + big.NewInt(42), + }, { "simple switch fail", `package main