From 76925fe3e0f2a7d425e3b33b2546b681a6417c54 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Thu, 9 Jul 2020 13:06:49 +0300 Subject: [PATCH] compiler: slices must default to nil --- pkg/compiler/codegen.go | 22 ++++++++++++++-------- pkg/compiler/slice_test.go | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index c1014cfd7..c7d888a42 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -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, diff --git a/pkg/compiler/slice_test.go b/pkg/compiler/slice_test.go index 2dfe9adbc..f386beddf 100644 --- a/pkg/compiler/slice_test.go +++ b/pkg/compiler/slice_test.go @@ -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) {