compiler: distinguish between type conversions and function calls

RN every identifier in call expression is considered to be lambda.
But it also can be type expression, so we need to distinguish between
these cases.
This commit is contained in:
Evgenii Stratonikov 2020-06-24 18:36:21 +03:00
parent 904b2136fc
commit 1d275ceb65
2 changed files with 24 additions and 3 deletions

View file

@ -712,6 +712,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
name string
numArgs = len(n.Args)
isBuiltin bool
isFunc bool
)
switch fun := n.Fun.(type) {
@ -721,6 +722,10 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
if !ok && !isBuiltin {
name = fun.Name
}
// distinguish lambda invocations from type conversions
if fun.Obj != nil && fun.Obj.Kind == ast.Var {
isFunc = true
}
case *ast.SelectorExpr:
// If this is a method call we need to walk the AST to load the struct locally.
// Otherwise this is a function call from a imported package and we can call it
@ -767,9 +772,11 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
// We can be sure builtins are of type *ast.Ident.
c.convertBuiltin(n)
case name != "":
// Function was not found thus is can be only an invocation of func-typed variable.
c.emitLoadVar(name)
emit.Opcode(c.prog.BinWriter, opcode.CALLA)
// Function was not found thus is can be only an invocation of func-typed variable or type conversion.
if isFunc {
c.emitLoadVar(name)
emit.Opcode(c.prog.BinWriter, opcode.CALLA)
}
case isSyscall(f):
c.convertSyscall(n, f.selector.Name, f.name)
default:

View file

@ -72,3 +72,17 @@ func TestTypeAssertion(t *testing.T) {
}`
eval(t, src, big.NewInt(1))
}
func TestTypeConversion(t *testing.T) {
src := `package foo
type myInt int
func Main() int32 {
var a int32 = 41
b := myInt(a)
incMy := func(x myInt) myInt { return x + 1 }
c := incMy(b)
return int32(c)
}`
eval(t, src, big.NewInt(42))
}