mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-29 23:33:37 +00:00
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.
|
// not the assertion type.
|
||||||
case *ast.TypeAssertExpr:
|
case *ast.TypeAssertExpr:
|
||||||
ast.Walk(c, n.X)
|
ast.Walk(c, n.X)
|
||||||
|
typ := toNeoType(c.typeOf(n.Type))
|
||||||
|
emit.Instruction(c.prog.BinWriter, opcode.CONVERT, []byte{byte(typ)})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return c
|
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 (
|
import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/types"
|
"go/types"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *codegen) typeAndValueOf(e ast.Expr) types.TypeAndValue {
|
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)
|
t, ok := typ.Underlying().(*types.Slice)
|
||||||
return ok && isByte(t.Elem())
|
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