Skip to content

Commit

Permalink
[lua] Improve codegen for handling instance Var functions (#10817)
Browse files Browse the repository at this point in the history
* [lua] make function-type class fields use dot access by default

* [lua] do not modify function assignments to dot methods

* [lua] wrap functions on assignments from dot-access to non-dot-access instance fields

* [tests] add test for #10799

* [lua] skip wrapping function instance fields when generating arguments or returns
  • Loading branch information
Frixuu authored Jan 3, 2023
1 parent 9485876 commit 8d4f2d7
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 8 deletions.
41 changes: 33 additions & 8 deletions src/generators/genlua.ml
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,15 @@ let this ctx = match ctx.in_value with None -> "self" | Some _ -> "self"

let is_dot_access e cf =
match follow(e.etype), cf with
| TInst (c,_), FInstance(_,_,icf) when (Meta.has Meta.LuaDotMethod c.cl_meta || Meta.has Meta.LuaDotMethod icf.cf_meta)->
true;
| TInst (c, _), FInstance(_, _, icf) -> (match icf.cf_kind with
| Var _ ->
true
| Method _ when Meta.has Meta.LuaDotMethod c.cl_meta ->
true
| Method _ when Meta.has Meta.LuaDotMethod icf.cf_meta ->
true
| Method _ ->
false)
| _ ->
false

Expand Down Expand Up @@ -345,7 +352,7 @@ let rec is_function_type t =

and gen_argument ?(reflect=false) ctx e = begin
match e.eexpr with
| TField (x,((FInstance (_,_,f)| FAnon(f) | FClosure(_,f)))) when (is_function_type e.etype) ->
| TField (x, ((FInstance (_, _, f) | FAnon(f) | FClosure(_,f)) as i)) when ((is_function_type e.etype) && (not(is_dot_access x i))) ->
(
if reflect then (
add_feature ctx "use._hx_funcToField";
Expand Down Expand Up @@ -1265,10 +1272,14 @@ and gen_value ctx e =

and gen_tbinop ctx op e1 e2 =
(match op, e1.eexpr, e2.eexpr with
| Ast.OpAssign, TField(e3, FInstance _), TFunction f ->
| Ast.OpAssign, TField(e3, (FInstance _ as ci)), TFunction f ->
gen_expr ctx e1;
spr ctx " = " ;
print ctx "function(%s) " (String.concat "," ("self" :: List.map ident (List.map arg_name f.tf_args)));
let fn_args = List.map ident (List.map arg_name f.tf_args) in
print ctx "function(%s) " (String.concat ","
(if is_dot_access e3 ci
then fn_args
else "self" :: fn_args));
let fblock = fun_block ctx f e1.epos in
(match fblock.eexpr with
| TBlock el ->
Expand Down Expand Up @@ -1300,14 +1311,28 @@ and gen_tbinop ctx op e1 e2 =
gen_value ctx e1;
spr ctx " = ";
gen_value ctx e3;
| TField(e3, (FInstance _| FClosure _ | FAnon _ ) ), TField(e4, (FClosure _| FStatic _ | FAnon _) ) ->
| TField(e3, (FClosure _ | FAnon _)), TField(e4, (FClosure _ | FStatic _ | FAnon _)) ->
gen_value ctx e1;
print ctx " %s " (Ast.s_binop op);
add_feature ctx "use._hx_funcToField";
spr ctx "_hx_funcToField(";
gen_value ctx e2;
spr ctx ")";
| TField(e3, (FInstance _ as lhs)), TField(e4, (FInstance _ as rhs)) when not (is_dot_access e3 lhs) && (is_dot_access e4 rhs) ->
gen_value ctx e1;
print ctx " %s " (Ast.s_binop op);
add_feature ctx "use._hx_funcToField";
spr ctx "_hx_funcToField(";
gen_value ctx e2;
spr ctx ")";
| TField(e3, (FInstance _ as ci)), TField(e4, (FClosure _ | FStatic _ | FAnon _)) when not (is_dot_access e3 ci) ->
gen_value ctx e1;
print ctx " %s " (Ast.s_binop op);
add_feature ctx "use._hx_funcToField";
spr ctx "_hx_funcToField(";
gen_value ctx e2;
spr ctx ")";
| TField(_, FInstance _ ), TLocal t when (is_function_type t.v_type) ->
| TField(e3, (FInstance _ as ci)), TLocal t when ((is_function_type t.v_type) && (not (is_dot_access e3 ci))) ->
gen_value ctx e1;
print ctx " %s " (Ast.s_binop op);
add_feature ctx "use._hx_funcToField";
Expand Down Expand Up @@ -1444,7 +1469,7 @@ and gen_return ctx e eo =
spr ctx "do return end"
| Some e ->
(match e.eexpr with
| TField (e2, ((FClosure (_, tcf) | FAnon tcf |FInstance (_,_,tcf)))) when (is_function_type tcf.cf_type) ->
| TField (e2, ((FAnon tcf | FInstance (_,_,tcf)) as t)) when ((is_function_type tcf.cf_type) && (not(is_dot_access e2 t)))->
(* See issue #6259 *)
add_feature ctx "use._hx_bind";
spr ctx "do return ";
Expand Down
79 changes: 79 additions & 0 deletions tests/unit/src/unit/issues/Issue10799.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package unit.issues;

class Issue10799 extends Test {
#if lua
var myField:(Int) -> Int;

private static function foo(x:Int):Int
return x * 3;

private dynamic function bar(x:Int):Int {
eq("table", untyped __lua__("_G.type(self)"));
eq("number", untyped __lua__("_G.type(x)"));
return x * 4;
}

private dynamic function baz(x:Int):Int {
throw "not implemented";
}

private function returnsField():(Int) -> Int {
return this.myField;
}

private function returnsMethod():(Int) -> Int {
return this.bar;
}

private function returnsClosure():(Int) -> Int {
final obj = lua.Lua.assert({num: 7});
final fn:(Int) -> Int = x -> x * obj.num;
lua.Lua.assert(fn);
return fn;
}

public function test() {
this.myField = x -> x * 2;
eq(6, untyped __lua__("self.myField(3)"));
this.myField = Issue10799.foo;
eq(9, untyped __lua__("self.myField(3)"));
eq(9, untyped __lua__("__unit_issues_Issue10799.foo(3)"));
this.myField = this.bar;
eq(12, untyped __lua__("self.myField(3)"));
exc(() -> untyped __lua__("self.bar(3)"));
this.myField = x -> x * 2;
this.bar = this.myField;
eq(6, untyped __lua__("self:bar(3)"));
this.baz = this.bar;
eq(6, untyped __lua__("self:baz(3)"));

var localVar = this.myField;
lua.Lua.assert(localVar);
eq(6, untyped __lua__("localVar(3)"));

localVar = this.bar;
lua.Lua.assert(localVar);
eq(6, untyped __lua__("localVar(3)"));

final field = this.returnsField();
eq(6, untyped __lua__("field(3)"));
final method = this.returnsMethod();
eq(6, untyped __lua__("method(3)"));
final closure = this.returnsClosure();
eq(21, untyped __lua__("closure(3)"));

final anon = lua.Lua.assert({
fromField: this.myField,
fromStatic: Issue10799.foo,
fromMethod: this.bar,
});

exc(() -> untyped __lua__("anon.fromField(3)"));
eq(6, untyped __lua__("anon:fromField(3)"));
exc(() -> untyped __lua__("anon.fromStatic(3)"));
eq(9, untyped __lua__("anon:fromStatic(3)"));
exc(() -> untyped __lua__("anon.fromMethod(3)"));
eq(6, untyped __lua__("anon:fromMethod(3)"));
}
#end
}

0 comments on commit 8d4f2d7

Please sign in to comment.