Browse Source

type return/break/continue expressions with monomorphs instead of Dynamic (see #10744) (#10745)

* type return/break/continue expressions with monomorphs instead of Dynamic (see #10744)

this is what we already do for `throw` since 2008 (https://github.com/HaxeFoundation/haxe/commit/9cee2fcc78e7715d69fcdc8dcee36413c052c9e1)

* add test (closes #10744)

* test throw too (works already, just in case we break it in future)

* spawn monos only if we need a value

Co-authored-by: Simon Krajewski <[email protected]>
Dan Korostelev 3 years ago
parent
commit
02b4357bb3
2 changed files with 32 additions and 10 deletions
  1. 17 10
      src/typing/typer.ml
  2. 15 0
      tests/unit/src/unit/issues/Issue10744.hx

+ 17 - 10
src/typing/typer.ml

@@ -36,6 +36,12 @@ open Operators
 (* ---------------------------------------------------------------------- *)
 (* ---------------------------------------------------------------------- *)
 (* TOOLS *)
 (* TOOLS *)
 
 
+let mono_or_dynamic ctx with_type p = match with_type with
+	| WithType.NoValue ->
+		t_dynamic
+	| Value _ | WithType _ ->
+		spawn_monomorph ctx p
+
 let get_iterator_param t =
 let get_iterator_param t =
 	match follow t with
 	match follow t with
 	| TAnon a ->
 	| TAnon a ->
@@ -1476,7 +1482,7 @@ and type_return ?(implicit=false) ctx e with_type p =
 	match e with
 	match e with
 	| None when is_abstract_ctor ->
 	| None when is_abstract_ctor ->
 		let e_cast = mk (TCast(get_this ctx p,None)) ctx.ret p in
 		let e_cast = mk (TCast(get_this ctx p,None)) ctx.ret p in
-		mk (TReturn (Some e_cast)) t_dynamic p
+		mk (TReturn (Some e_cast)) (mono_or_dynamic ctx with_type p) p
 	| None ->
 	| None ->
 		let v = ctx.t.tvoid in
 		let v = ctx.t.tvoid in
 		unify ctx v ctx.ret p;
 		unify ctx v ctx.ret p;
@@ -1485,7 +1491,7 @@ and type_return ?(implicit=false) ctx e with_type p =
 			| WithType.Value (Some ImplicitReturn) -> true
 			| WithType.Value (Some ImplicitReturn) -> true
 			| _ -> false
 			| _ -> false
 		in
 		in
-		mk (TReturn None) (if expect_void then v else t_dynamic) p
+		mk (TReturn None) (if expect_void then v else (mono_or_dynamic ctx with_type p)) p
 	| Some e ->
 	| Some e ->
 		if is_abstract_ctor then begin
 		if is_abstract_ctor then begin
 			match fst e with
 			match fst e with
@@ -1511,18 +1517,19 @@ and type_return ?(implicit=false) ctx e with_type p =
 					| _ -> ()
 					| _ -> ()
 					end;
 					end;
 					(* if we get a Void expression (e.g. from inlining) we don't want to return it (issue #4323) *)
 					(* if we get a Void expression (e.g. from inlining) we don't want to return it (issue #4323) *)
+					let t = mono_or_dynamic ctx with_type p in
 					mk (TBlock [
 					mk (TBlock [
 						e;
 						e;
-						mk (TReturn None) t_dynamic p
-					]) t_dynamic e.epos;
+						mk (TReturn None) t p
+					]) t e.epos;
 				| _ ->
 				| _ ->
-					mk (TReturn (Some e)) t_dynamic p
+					mk (TReturn (Some e)) (mono_or_dynamic ctx with_type p) p
 		with Error(err,p) ->
 		with Error(err,p) ->
 			check_error ctx err p;
 			check_error ctx err p;
 			(* If we have a bad return, let's generate a return null expression at least. This surpresses various
 			(* If we have a bad return, let's generate a return null expression at least. This surpresses various
 				follow-up errors that come from the fact that the function no longer has a return expression (issue #6445). *)
 				follow-up errors that come from the fact that the function no longer has a return expression (issue #6445). *)
 			let e_null = mk (TConst TNull) (mk_mono()) p in
 			let e_null = mk (TConst TNull) (mk_mono()) p in
-			mk (TReturn (Some e_null)) t_dynamic p
+			mk (TReturn (Some e_null)) (mono_or_dynamic ctx with_type p) p
 
 
 and type_cast ctx e t p =
 and type_cast ctx e t p =
 	let tpos = pos t in
 	let tpos = pos t in
@@ -1915,7 +1922,7 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) =
 			display_error ctx.com "Return outside function" p;
 			display_error ctx.com "Return outside function" p;
 			match e with
 			match e with
 			| None ->
 			| None ->
-				Texpr.Builder.make_null t_dynamic p
+				Texpr.Builder.make_null (mono_or_dynamic ctx with_type p) p
 			| Some e ->
 			| Some e ->
 				(* type the return expression to see if there are more errors
 				(* type the return expression to see if there are more errors
 				   as well as use its type as if there was no `return`, since
 				   as well as use its type as if there was no `return`, since
@@ -1925,17 +1932,17 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) =
 			type_return ctx e with_type p
 			type_return ctx e with_type p
 	| EBreak ->
 	| EBreak ->
 		if not ctx.in_loop then display_error ctx.com "Break outside loop" p;
 		if not ctx.in_loop then display_error ctx.com "Break outside loop" p;
-		mk TBreak t_dynamic p
+		mk TBreak (mono_or_dynamic ctx with_type p) p
 	| EContinue ->
 	| EContinue ->
 		if not ctx.in_loop then display_error ctx.com "Continue outside loop" p;
 		if not ctx.in_loop then display_error ctx.com "Continue outside loop" p;
-		mk TContinue t_dynamic p
+		mk TContinue (mono_or_dynamic ctx with_type p) p
 	| ETry (e1,[]) ->
 	| ETry (e1,[]) ->
 		type_expr ctx e1 with_type
 		type_expr ctx e1 with_type
 	| ETry (e1,catches) ->
 	| ETry (e1,catches) ->
 		type_try ctx e1 catches with_type p
 		type_try ctx e1 catches with_type p
 	| EThrow e ->
 	| EThrow e ->
 		let e = type_expr ctx e WithType.value in
 		let e = type_expr ctx e WithType.value in
-		mk (TThrow e) (spawn_monomorph ctx p) p
+		mk (TThrow e) (mono_or_dynamic ctx with_type p) p
 	| ENew (t,el) ->
 	| ENew (t,el) ->
 		type_new ctx t el with_type false p
 		type_new ctx t el with_type false p
 	| EUnop (op,flag,e) ->
 	| EUnop (op,flag,e) ->

+ 15 - 0
tests/unit/src/unit/issues/Issue10744.hx

@@ -0,0 +1,15 @@
+package unit.issues;
+
+import unit.HelperMacros.typeString;
+
+class Issue10744 extends Test {
+	function test() {
+		var v:Null<Int> = 10;
+		eq("Null<Int>", typeString(v ?? return));
+		eq("Null<Int>", typeString(v ?? throw true));
+		for (i in 0...1) {
+			eq("Null<Int>", typeString(v ?? break));
+			eq("Null<Int>", typeString(v ?? continue));
+		}
+	}
+}