Skip to content

Commit

Permalink
support f?.bind()
Browse files Browse the repository at this point in the history
see #11571
  • Loading branch information
Simn committed Oct 22, 2024
1 parent 6f20d6b commit cf4d729
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 16 deletions.
21 changes: 17 additions & 4 deletions src/typing/calls.ml
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ let call_to_string ctx ?(resume=false) e =
mk (TIf (check_null, string_null, Some (gen_to_string e))) ctx.t.tstring e.epos
end

let type_bind ctx (e : texpr) (args,ret) params p =
let type_bind ctx (e : texpr) (args,ret) params safe p =
let vexpr v = mk (TLocal v) v.v_type p in
let acount = ref 0 in
let alloc_name n =
Expand Down Expand Up @@ -409,10 +409,23 @@ let type_bind ctx (e : texpr) (args,ret) params p =
let e_var = alloc_var VGenerated gen_local_prefix e.etype e.epos in
(mk (TLocal e_var) e.etype e.epos), (mk (TVar(e_var,Some e)) ctx.t.tvoid e.epos) :: var_decls
in
let call = make_call ctx e ordered_args ret p in
let e_body = if safe then begin
let eobj, tempvar = get_safe_nav_base ctx e in
let sn = {
sn_pos = p;
sn_base = eobj;
sn_temp_var = tempvar;
sn_access = AKExpr e; (* This is weird, but it's not used by safe_nav_branch. *)
} in
safe_nav_branch ctx sn (fun () ->
make_call ctx eobj ordered_args ret p
)
end else
make_call ctx e ordered_args ret p
in
let body =
if ExtType.is_void (follow ret) then call
else mk (TReturn(Some call)) ret p
if ExtType.is_void (follow ret) then e_body
else mk (TReturn(Some e_body)) ret p
in
let arg_default optional t =
if optional then Some (Texpr.Builder.make_null t null_pos)
Expand Down
14 changes: 3 additions & 11 deletions src/typing/typer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -605,15 +605,7 @@ and handle_efield ctx e p0 mode with_type =
create safe navigation chain from the object expression *)
let acc_obj = type_access ctx eobj pobj MGet WithType.value in
let eobj = acc_get ctx acc_obj in
let eobj, tempvar = match (Texpr.skip eobj).eexpr with
| TLocal _ | TTypeExpr _ | TConst _ ->
eobj, None
| _ ->
let v = alloc_var VGenerated "tmp" eobj.etype eobj.epos in
let temp_var = mk (TVar(v, Some eobj)) ctx.t.tvoid v.v_pos in
let eobj = mk (TLocal v) v.v_type v.v_pos in
eobj, Some temp_var
in
let eobj, tempvar = get_safe_nav_base ctx eobj in
let access = field_chain ctx ((mk_dot_path_part s p) :: dot_path_acc) (AKExpr eobj) mode with_type in
AKSafeNav {
sn_pos = p;
Expand Down Expand Up @@ -1738,10 +1730,10 @@ and type_call_builtin ctx e el mode with_type p =
| (EField ((EConst (Ident "super"),_),_,_),_), _ ->
(* no builtins can be applied to super as it can't be a value *)
raise Exit
| (EField (e,"bind",efk_todo),p), args ->
| (EField (e,"bind",efk),p), args ->
let e = type_expr ctx e WithType.value in
(match follow e.etype with
| TFun signature -> type_bind ctx e signature args p
| TFun signature -> type_bind ctx e signature args (efk = EFSafe) p
| _ -> raise Exit)
| (EConst (Ident "$type"),_) , e1 :: el ->
let expected = match el with
Expand Down
12 changes: 11 additions & 1 deletion src/typing/typerBase.ml
Original file line number Diff line number Diff line change
Expand Up @@ -369,4 +369,14 @@ let safe_nav_branch ctx sn f_then =
let eif = mk (TIf(eneq,ethen,Some eelse)) tnull sn.sn_pos in
(match sn.sn_temp_var with
| None -> eif
| Some evar -> { eif with eexpr = TBlock [evar; eif] })
| Some evar -> { eif with eexpr = TBlock [evar; eif] })

let get_safe_nav_base ctx eobj =
match (Texpr.skip eobj).eexpr with
| TLocal _ | TTypeExpr _ | TConst _ ->
eobj, None
| _ ->
let v = alloc_var VGenerated "tmp" eobj.etype eobj.epos in
let temp_var = mk (TVar(v, Some eobj)) ctx.t.tvoid v.v_pos in
let eobj = mk (TLocal v) v.v_type v.v_pos in
eobj, Some temp_var
15 changes: 15 additions & 0 deletions tests/unit/src/unit/issues/Issue11571.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package unit.issues;

class Issue11571 extends unit.Test {
public function test() {
var fOk = () -> "ok";
var f:Null<() -> String> = fOk;
var boundOk = f?.bind();
f = null;
eq("ok", boundOk());

var boundNull = f?.bind();
f = fOk;
eq(null, boundNull());
}
}

0 comments on commit cf4d729

Please sign in to comment.