Simon Krajewski 10 місяців тому
батько
коміт
b25e93a54d

+ 17 - 4
src/typing/calls.ml

@@ -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 =
@@ -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)

+ 3 - 11
src/typing/typer.ml

@@ -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;
@@ -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

+ 11 - 1
src/typing/typerBase.ml

@@ -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 - 0
tests/unit/src/unit/issues/Issue11571.hx

@@ -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());
+	}
+}