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:
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:
num := t.NumFields()
emit.Int(c.prog.BinWriter, int64(num))
@ -1183,9 +1176,22 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
case "append":
arg := expr.Args[0]
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) {
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)
} 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.SWAP)
emit.Opcode(c.prog.BinWriter, opcode.APPEND)
@ -1513,7 +1519,7 @@ func (c *codegen) writeJumps(b []byte) error {
opcode.JMPEQ, opcode.JMPNE,
opcode.JMPGT, opcode.JMPGE, opcode.JMPLE, opcode.JMPLT:
// 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,
opcode.JMPEQL, opcode.JMPNEL,
opcode.JMPGTL, opcode.JMPGEL, opcode.JMPLEL, opcode.JMPLTL,

View file

@ -243,6 +243,43 @@ var sliceTestCases = []testCase{
}`,
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) {