compiler: slices must default to nil

This commit is contained in:
Roman Khimov 2020-07-09 13:06:49 +03:00
parent eee8ac1655
commit 76925fe3e0
2 changed files with 51 additions and 8 deletions

View file

@ -231,13 +231,6 @@ func (c *codegen) emitDefault(t types.Type) {
default: default:
emit.Opcode(c.prog.BinWriter, opcode.PUSHNULL) emit.Opcode(c.prog.BinWriter, opcode.PUSHNULL)
} }
case *types.Slice:
if isCompoundSlice(t) {
emit.Opcode(c.prog.BinWriter, opcode.NEWARRAY0)
} else {
emit.Int(c.prog.BinWriter, 0)
emit.Opcode(c.prog.BinWriter, opcode.NEWBUFFER)
}
case *types.Struct: case *types.Struct:
num := t.NumFields() num := t.NumFields()
emit.Int(c.prog.BinWriter, int64(num)) emit.Int(c.prog.BinWriter, int64(num))
@ -1183,9 +1176,22 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
case "append": case "append":
arg := expr.Args[0] arg := expr.Args[0]
typ := c.typeInfo.Types[arg].Type typ := c.typeInfo.Types[arg].Type
emit.Opcode(c.prog.BinWriter, opcode.OVER)
emit.Opcode(c.prog.BinWriter, opcode.ISNULL)
emit.Instruction(c.prog.BinWriter, opcode.JMPIFNOT, []byte{2 + 4})
if isByteSlice(typ) { if isByteSlice(typ) {
emit.Opcode(c.prog.BinWriter, opcode.NIP)
emit.Opcode(c.prog.BinWriter, opcode.PUSH0)
emit.Opcode(c.prog.BinWriter, opcode.NEWBUFFER)
emit.Opcode(c.prog.BinWriter, opcode.SWAP)
// Jump target.
emit.Opcode(c.prog.BinWriter, opcode.CAT) emit.Opcode(c.prog.BinWriter, opcode.CAT)
} else { } else {
emit.Opcode(c.prog.BinWriter, opcode.NIP)
emit.Opcode(c.prog.BinWriter, opcode.NEWARRAY0)
emit.Opcode(c.prog.BinWriter, opcode.SWAP)
emit.Opcode(c.prog.BinWriter, opcode.NOP)
// Jump target.
emit.Opcode(c.prog.BinWriter, opcode.OVER) emit.Opcode(c.prog.BinWriter, opcode.OVER)
emit.Opcode(c.prog.BinWriter, opcode.SWAP) emit.Opcode(c.prog.BinWriter, opcode.SWAP)
emit.Opcode(c.prog.BinWriter, opcode.APPEND) emit.Opcode(c.prog.BinWriter, opcode.APPEND)
@ -1513,7 +1519,7 @@ func (c *codegen) writeJumps(b []byte) error {
opcode.JMPEQ, opcode.JMPNE, opcode.JMPEQ, opcode.JMPNE,
opcode.JMPGT, opcode.JMPGE, opcode.JMPLE, opcode.JMPLT: opcode.JMPGT, opcode.JMPGE, opcode.JMPLE, opcode.JMPLT:
// Noop, assumed to be correct already. If you're fixing #905, // Noop, assumed to be correct already. If you're fixing #905,
// make sure not to break "len" handling above. // make sure not to break "len" and "append" handling above.
case opcode.JMPL, opcode.JMPIFL, opcode.JMPIFNOTL, case opcode.JMPL, opcode.JMPIFL, opcode.JMPIFNOTL,
opcode.JMPEQL, opcode.JMPNEL, opcode.JMPEQL, opcode.JMPNEL,
opcode.JMPGTL, opcode.JMPGEL, opcode.JMPLEL, opcode.JMPLTL, opcode.JMPGTL, opcode.JMPGEL, opcode.JMPLEL, opcode.JMPLTL,

View file

@ -243,6 +243,43 @@ var sliceTestCases = []testCase{
}`, }`,
big.NewInt(42), big.NewInt(42),
}, },
{
"defaults to nil for byte slice",
`
package foo
func Main() int {
var a []byte
if a != nil { return 1}
return 2
}
`,
big.NewInt(2),
},
{
"defaults to nil for int slice",
`
package foo
func Main() int {
var a []int
if a != nil { return 1}
return 2
}
`,
big.NewInt(2),
},
{
"defaults to nil for struct slice",
`
package foo
type pair struct { a, b int }
func Main() int {
var a []pair
if a != nil { return 1}
return 2
}
`,
big.NewInt(2),
},
} }
func TestSliceOperations(t *testing.T) { func TestSliceOperations(t *testing.T) {