compiler: allow conversion to types from external packages
This commit is contained in:
parent
1f98289f5d
commit
e5d8c1c985
3 changed files with 68 additions and 5 deletions
|
@ -821,13 +821,20 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
}
|
||||
|
||||
f, ok = c.funcs[name]
|
||||
// @FIXME this could cause runtime errors.
|
||||
f.selector = fun.X.(*ast.Ident)
|
||||
if !ok {
|
||||
c.prog.Err = fmt.Errorf("could not resolve function %s", fun.Sel.Name)
|
||||
if ok {
|
||||
f.selector = fun.X.(*ast.Ident)
|
||||
isBuiltin = isCustomBuiltin(f)
|
||||
} else {
|
||||
typ := c.typeOf(fun)
|
||||
if _, ok := typ.(*types.Signature); ok {
|
||||
c.prog.Err = fmt.Errorf("could not resolve function %s", fun.Sel.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
ast.Walk(c, n.Args[0])
|
||||
c.emitExplicitConvert(c.typeOf(n.Args[0]), typ)
|
||||
return nil
|
||||
}
|
||||
isBuiltin = isCustomBuiltin(f)
|
||||
case *ast.ArrayType:
|
||||
// For now we will assume that there are only byte slice conversions.
|
||||
// E.g. []byte("foobar") or []byte(scriptHash).
|
||||
|
@ -1242,6 +1249,24 @@ func (c *codegen) processDefers() {
|
|||
}
|
||||
}
|
||||
|
||||
// emitExplicitConvert handles `someType(someValue)` conversions between string/[]byte.
|
||||
// Rules for conversion:
|
||||
// 1. interop.* types are converted to ByteArray if not already.
|
||||
// 2. Otherwise convert between ByteArray/Buffer.
|
||||
// 3. Rules for types which are not string/[]byte should already
|
||||
// be enforced by go parser.
|
||||
func (c *codegen) emitExplicitConvert(from, to types.Type) {
|
||||
if isInteropPath(to.String()) {
|
||||
if isByteSlice(from) && !isString(from) {
|
||||
c.emitConvert(stackitem.ByteArrayT)
|
||||
}
|
||||
} else if isByteSlice(to) && !isByteSlice(from) {
|
||||
c.emitConvert(stackitem.BufferT)
|
||||
} else if isString(to) && !isString(from) {
|
||||
c.emitConvert(stackitem.ByteArrayT)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *codegen) rangeLoadKey() {
|
||||
emit.Int(c.prog.BinWriter, 2)
|
||||
emit.Opcodes(c.prog.BinWriter,
|
||||
|
|
|
@ -87,6 +87,37 @@ func TestTypeConversion(t *testing.T) {
|
|||
eval(t, src, big.NewInt(42))
|
||||
}
|
||||
|
||||
func TestSelectorTypeConversion(t *testing.T) {
|
||||
src := `package foo
|
||||
import "github.com/nspcc-dev/neo-go/pkg/compiler/testdata/types"
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop/util"
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop"
|
||||
func Main() int {
|
||||
var a int
|
||||
if util.Equals(types.Buffer(nil), nil) {
|
||||
a += 1
|
||||
}
|
||||
|
||||
// Buffer != ByteArray
|
||||
if util.Equals(types.Buffer("\x12"), "\x12") {
|
||||
a += 10
|
||||
}
|
||||
|
||||
tmp := []byte{0x23}
|
||||
if util.Equals(types.ByteString(tmp), "\x23") {
|
||||
a += 100
|
||||
}
|
||||
|
||||
addr := "aaaaaaaaaaaaaaaaaaaa"
|
||||
buf := []byte(addr)
|
||||
if util.Equals(interop.Hash160(addr), interop.Hash160(buf)) {
|
||||
a += 1000
|
||||
}
|
||||
return a
|
||||
}`
|
||||
eval(t, src, big.NewInt(1101))
|
||||
}
|
||||
|
||||
func TestTypeConversionString(t *testing.T) {
|
||||
src := `package foo
|
||||
type mystr string
|
||||
|
|
7
pkg/compiler/testdata/types/types.go
vendored
Normal file
7
pkg/compiler/testdata/types/types.go
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
package types
|
||||
|
||||
// Buffer represents Buffer VM type.
|
||||
type Buffer []byte
|
||||
|
||||
// ByteString represents ByteString VM type.
|
||||
type ByteString string
|
Loading…
Reference in a new issue