forked from TrueCloudLab/neoneo-go
compiler: emit CONVERT opcode for type assertions
Emit CONVERT for converting between different types. NeoVM behavior is different from that of Go (e.g. assertions of `int` and `uint32` are equivalent).
This commit is contained in:
parent
f75d888f5f
commit
904b2136fc
3 changed files with 46 additions and 0 deletions
|
@ -991,6 +991,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
// not the assertion type.
|
||||
case *ast.TypeAssertExpr:
|
||||
ast.Walk(c, n.X)
|
||||
typ := toNeoType(c.typeOf(n.Type))
|
||||
emit.Instruction(c.prog.BinWriter, opcode.CONVERT, []byte{byte(typ)})
|
||||
return nil
|
||||
}
|
||||
return c
|
||||
|
|
|
@ -61,3 +61,14 @@ func TestConvert(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeAssertion(t *testing.T) {
|
||||
src := `package foo
|
||||
func Main() int {
|
||||
a := []byte{1}
|
||||
var u interface{}
|
||||
u = a
|
||||
return u.(int)
|
||||
}`
|
||||
eval(t, src, big.NewInt(1))
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ package compiler
|
|||
import (
|
||||
"go/ast"
|
||||
"go/types"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
func (c *codegen) typeAndValueOf(e ast.Expr) types.TypeAndValue {
|
||||
|
@ -42,3 +44,34 @@ func isByteSlice(typ types.Type) bool {
|
|||
t, ok := typ.Underlying().(*types.Slice)
|
||||
return ok && isByte(t.Elem())
|
||||
}
|
||||
|
||||
func toNeoType(typ types.Type) stackitem.Type {
|
||||
if typ == nil {
|
||||
return stackitem.AnyT
|
||||
}
|
||||
switch t := typ.Underlying().(type) {
|
||||
case *types.Basic:
|
||||
info := t.Info()
|
||||
switch {
|
||||
case info&types.IsInteger != 0:
|
||||
return stackitem.IntegerT
|
||||
case info&types.IsBoolean != 0:
|
||||
return stackitem.BooleanT
|
||||
case info&types.IsString != 0:
|
||||
return stackitem.ByteArrayT
|
||||
default:
|
||||
return stackitem.AnyT
|
||||
}
|
||||
case *types.Map:
|
||||
return stackitem.MapT
|
||||
case *types.Struct:
|
||||
return stackitem.StructT
|
||||
case *types.Slice:
|
||||
if isByte(t.Elem()) {
|
||||
return stackitem.BufferT
|
||||
}
|
||||
return stackitem.ArrayT
|
||||
default:
|
||||
return stackitem.AnyT
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue