Merge pull request #1383 from nspcc-dev/compiler/switchtag
compiler: fix a bug with type conversion in switch
This commit is contained in:
commit
18204ec21a
6 changed files with 62 additions and 3 deletions
|
@ -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":
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue