forked from TrueCloudLab/neoneo-go
compiler: set default values for complex struct fields
Set default value also for complex (struct, map) types. Note: because VM does not distinguish empty array and nil array, comparison 'a == nil' can't be handled properly without substantial effort. This will be fixed in NEO3.
This commit is contained in:
parent
788304ec49
commit
bf6aa02dcf
4 changed files with 54 additions and 3 deletions
|
@ -44,8 +44,9 @@ func typeAndValueForField(fld *types.Var) (types.TypeAndValue, error) {
|
|||
default:
|
||||
return types.TypeAndValue{}, fmt.Errorf("could not initialize struct field %s to zero, type: %s", fld.Name(), t)
|
||||
}
|
||||
default:
|
||||
return types.TypeAndValue{Type: t}, nil
|
||||
}
|
||||
return types.TypeAndValue{}, nil
|
||||
}
|
||||
|
||||
// countGlobals counts the global variables in the program to add
|
||||
|
|
|
@ -533,6 +533,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
c.emitLoadConst(value)
|
||||
} else if tv := c.typeInfo.Types[n]; tv.Value != nil {
|
||||
c.emitLoadConst(tv)
|
||||
} else if n.Name == "nil" {
|
||||
c.emitDefault(new(types.Slice))
|
||||
} else {
|
||||
c.emitLoadLocal(n.Name)
|
||||
}
|
||||
|
@ -1230,11 +1232,32 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit) {
|
|||
|
||||
emit.Opcode(c.prog.BinWriter, opcode.DUP)
|
||||
emit.Int(c.prog.BinWriter, int64(i))
|
||||
c.emitLoadConst(typeAndVal)
|
||||
c.emitDefault(typeAndVal.Type)
|
||||
emit.Opcode(c.prog.BinWriter, opcode.SETITEM)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *codegen) emitDefault(typ types.Type) {
|
||||
switch t := c.scTypeFromGo(typ); t {
|
||||
case "Integer":
|
||||
emit.Int(c.prog.BinWriter, 0)
|
||||
case "Boolean":
|
||||
emit.Bool(c.prog.BinWriter, false)
|
||||
case "String":
|
||||
emit.String(c.prog.BinWriter, "")
|
||||
case "Map":
|
||||
emit.Opcode(c.prog.BinWriter, opcode.NEWMAP)
|
||||
case "Struct":
|
||||
emit.Int(c.prog.BinWriter, int64(typ.(*types.Struct).NumFields()))
|
||||
emit.Opcode(c.prog.BinWriter, opcode.NEWSTRUCT)
|
||||
case "Array":
|
||||
emit.Int(c.prog.BinWriter, 0)
|
||||
emit.Opcode(c.prog.BinWriter, opcode.NEWARRAY)
|
||||
case "ByteArray":
|
||||
emit.Bytes(c.prog.BinWriter, []byte{})
|
||||
}
|
||||
}
|
||||
|
||||
func (c *codegen) convertToken(tok token.Token) {
|
||||
switch tok {
|
||||
case token.ADD_ASSIGN:
|
||||
|
|
|
@ -183,7 +183,11 @@ func (c *codegen) scReturnTypeFromScope(scope *funcScope) string {
|
|||
}
|
||||
|
||||
func (c *codegen) scTypeFromExpr(typ ast.Expr) string {
|
||||
switch t := c.typeInfo.Types[typ].Type.(type) {
|
||||
return c.scTypeFromGo(c.typeInfo.Types[typ].Type)
|
||||
}
|
||||
|
||||
func (c *codegen) scTypeFromGo(typ types.Type) string {
|
||||
switch t := typ.(type) {
|
||||
case *types.Basic:
|
||||
info := t.Info()
|
||||
switch {
|
||||
|
|
|
@ -338,6 +338,29 @@ var structTestCases = []testCase{
|
|||
}`,
|
||||
big.NewInt(2),
|
||||
},
|
||||
{
|
||||
"uninitialized struct fields",
|
||||
`package foo
|
||||
type Foo struct {
|
||||
i int
|
||||
m map[string]int
|
||||
b []byte
|
||||
a []int
|
||||
s struct { ii int }
|
||||
}
|
||||
func NewFoo() Foo { return Foo{} }
|
||||
func Main() int {
|
||||
foo := NewFoo()
|
||||
if foo.i != 0 { return 1 }
|
||||
if len(foo.m) != 0 { return 1 }
|
||||
if len(foo.b) != 0 { return 1 }
|
||||
if len(foo.a) != 0 { return 1 }
|
||||
s := foo.s
|
||||
if s.ii != 0 { return 1 }
|
||||
return 2
|
||||
}`,
|
||||
big.NewInt(2),
|
||||
},
|
||||
}
|
||||
|
||||
func TestStructs(t *testing.T) {
|
||||
|
|
Loading…
Reference in a new issue