Merge pull request #1383 from nspcc-dev/compiler/switchtag

compiler: fix a bug with type conversion in switch
This commit is contained in:
Roman Khimov 2020-09-03 14:40:17 +03:00 committed by GitHub
commit 18204ec21a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 62 additions and 3 deletions

View file

@ -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":

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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))
})
}

View file

@ -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