Browse Source

[analyzer] don't do-reconstruct if there's a continue

because that changes semantics! closes #11040
Simon Krajewski 2 years ago
parent
commit
7d9faa20d0
2 changed files with 59 additions and 2 deletions
  1. 9 2
      src/optimization/analyzerTexpr.ml
  2. 50 0
      tests/unit/src/unit/issues/Issue11040.hx

+ 9 - 2
src/optimization/analyzerTexpr.ml

@@ -1032,6 +1032,13 @@ module Cleanup = struct
 			| TWhile(e1,e2,NormalWhile) ->
 				let e1 = loop e1 in
 				let e2 = loop e2 in
+				let rec has_continue e = match e.eexpr with
+					| TContinue ->
+						true
+					| _ ->
+						check_expr has_continue e
+				in
+				let has_continue = has_continue e2 in
 				begin match e2.eexpr with
 					| TBlock ({eexpr = TIf(e1,({eexpr = TBlock[{eexpr = TBreak}]} as eb),None)} :: el2) ->
 						let e1 = Texpr.skip e1 in
@@ -1053,10 +1060,10 @@ module Cleanup = struct
 						in
 						let can_do = match com.platform with Hl -> false | _ -> true in
 						let rec loop2 el = match el with
-							| [{eexpr = TBreak}] when is_true_expr e1 && can_do ->
+							| [{eexpr = TBreak}] when is_true_expr e1 && can_do && not has_continue ->
 								do_while := Some (Texpr.Builder.make_bool com.basic true e1.epos);
 								[]
-							| [{eexpr = TIf(econd,{eexpr = TBlock[{eexpr = TBreak}]},None)}] when is_true_expr e1 && not (references_local econd) && can_do ->
+							| [{eexpr = TIf(econd,{eexpr = TBlock[{eexpr = TBreak}]},None)}] when is_true_expr e1 && not (references_local econd) && can_do && not has_continue ->
 								do_while := Some econd;
 								[]
 							| {eexpr = TBreak | TContinue | TReturn _ | TThrow _} as e :: el ->

+ 50 - 0
tests/unit/src/unit/issues/Issue11040.hx

@@ -0,0 +1,50 @@
+package unit.issues;
+
+class Issue11040 extends Test {
+	function run() {
+		var tagName = "Array";
+		var text:String = "<Array<haxe.Json>>";
+		var startTag = '<$tagName';
+		var endTag = '</$tagName>';
+
+		var depth = 0;
+		var index = 0;
+		var buf = new StringBuf();
+		function append(s:String) {
+			buf.add(s);
+			buf.add("\n");
+		}
+		append("enter loop");
+		while (true) {
+			append("looping");
+			var indexStartTag = text.indexOf(startTag, index);
+			var indexEndTag = text.indexOf(endTag, index);
+			if ((indexStartTag == -1) && (indexEndTag == -1)) {
+				append(">>> should exit here >>>");
+				return buf.toString();
+			}
+			index++;
+			switch (text.charAt(index)) {
+				case " " | "/" | ">":
+				default:
+					append("default -> continue loop");
+					continue;
+			}
+			if (depth <= 0) {
+				break;
+			}
+		}
+		text = text.substr(0, index);
+		append("exit loop");
+		return buf.toString();
+	}
+
+	function test() {
+		eq("enter loop
+looping
+default -> continue loop
+looping
+>>> should exit here >>>
+", run());
+	}
+}