Quellcode durchsuchen

Follow through abstract underlying types for null-checks when matching (#11716)

* [hl] Fix switch abstract<null<int>> null detection

* [tests] add test for switch abstract null int

* follow through abstract underlying types for null-checks when matching

see #11715

* Revert "[hl] Fix switch abstract<null<int>> null detection"

This reverts commit b9974d5a37d65d64846ad22a08aefc6a5877bc10.

---------

Co-authored-by: Simon Krajewski <[email protected]>
Yuxiao Mao vor 1 Jahr
Ursprung
Commit
16f0708c91

+ 2 - 2
src/typing/matcher/compile.ml

@@ -270,7 +270,7 @@ and compile_switch mctx subjects cases =
 	let (subject_null,subject_switch,subject_default),reset_subject =
 		let subjects = match null with
 			| [] ->
-				if is_explicit_null subject.etype then
+				if is_explicit_null_or_abstract_over_that subject.etype then
 					switch_subject,subject,subject
 				else begin match switch_cases with
 				| [] ->
@@ -291,7 +291,7 @@ and compile_switch mctx subjects cases =
 	in
 	let dt = match null with
 		| [] ->
-			if is_explicit_null subject.etype then null_guard switch_default else dt
+			if is_explicit_null_or_abstract_over_that subject.etype then null_guard switch_default else dt
 		| cases ->
 			let dt_null = compile mctx subjects (cases @ default) in
 			null_guard dt_null

+ 15 - 0
src/typing/matcher/matcherGlobals.ml

@@ -7,3 +7,18 @@ let s_expr_pretty e = s_expr_pretty false "" false s_type e
 
 let make_offset_list left right middle other =
 	(ExtList.List.make left other) @ [middle] @ (ExtList.List.make right other)
+
+(* Like is_explicit_null, but follows abstract underlying types. *)
+let rec is_explicit_null_or_abstract_over_that = function
+	| TMono r ->
+		(match r.tm_type with None -> false | Some t -> is_explicit_null_or_abstract_over_that t)
+	| TAbstract ({ a_path = ([],"Null") },[t]) ->
+		true
+	| TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) ->
+		is_explicit_null_or_abstract_over_that (Abstract.get_underlying_type a tl)
+	| TLazy f ->
+		is_explicit_null_or_abstract_over_that (lazy_type f)
+	| TType (t,tl) ->
+		is_explicit_null_or_abstract_over_that (apply_typedef t tl)
+	| _ ->
+		false

+ 1 - 1
src/typing/matcher/texprConverter.ml

@@ -274,7 +274,7 @@ let to_texpr ctx t_switch with_type dt =
 							| Some e -> Some {case_patterns = List.map (constructor_to_texpr ctx) (List.sort Constructor.compare cons);case_expr = e}
 						end
 					) cases in
-					let is_nullable_subject = is_explicit_null e_subject.etype in
+					let is_nullable_subject = is_explicit_null_or_abstract_over_that e_subject.etype in
 					let e_subject = match kind with
 						| SKValue -> e_subject
 						| SKEnum -> mk_index_call e_subject

+ 25 - 0
tests/unit/src/unit/issues/Issue11715.hx

@@ -0,0 +1,25 @@
+package unit.issues;
+
+private enum abstract Foo(Null<Int>) {
+	public var A = 0;
+	public var B = 1;
+}
+
+class Issue11715 extends Test {
+	var b1: Null<Int> = null;
+	var b2: Foo = null;
+	function test() {
+		var t1 = switch (b1) {
+			case 0: "A";
+			case 1: "B";
+			default: "C";
+		};
+		eq("C", t1);
+		var t2 = switch (b2) {
+			case A: "A";
+			case B: "B";
+			default: "C";
+		};
+		eq("C", t2);
+	}
+}