فهرست منبع

respect boolean short-circuit when handling side-effects

Simon Krajewski 12 سال پیش
والد
کامیت
cdb0ef5f71
2فایلهای تغییر یافته به همراه111 افزوده شده و 7 حذف شده
  1. 27 6
      filters.ml
  2. 84 1
      tests/unit/unitstd/EvaluationOrder.unit.hx

+ 27 - 6
filters.ml

@@ -64,18 +64,39 @@ let handle_side_effects com gen_temp e =
 		| TObjectDecl fl ->
 			let el = ordered_list (List.map snd fl) in
 			{e with eexpr = TObjectDecl (List.map2 (fun (n,_) e -> n,e) fl el)}
+		| TBinop(OpBoolAnd | OpBoolOr as op,e1,e2) when Optimizer.has_side_effect e1 || Optimizer.has_side_effect e2 ->
+			let e1 = loop e1 in
+			let e_then = mk (TBlock (block loop [e2])) e2.etype e2.epos in
+			let e_if,e_else = if op = OpBoolOr then
+				mk (TUnop(Not,Prefix,e1)) com.basic.tbool e.epos,mk (TConst (TBool(true))) com.basic.tbool e.epos
+			else
+				e1,mk (TConst (TBool(false))) com.basic.tbool e.epos
+			in
+			mk (TIf(e_if,e_then,Some e_else)) com.basic.tbool e.epos
+ 		| TBinop(op,e1,e2) when (match op with OpAssign | OpAssignOp _ -> false | _ -> true) ->
+			begin match ordered_list [e1;e2] with
+				| [e1;e2] ->
+					{e with eexpr = TBinop(op,e1,e2)}
+				| _ ->
+					assert false
+			end
 		| _ ->
 			Type.map_expr loop e
 	and ordered_list el =
 		let had_side_effect = ref false in
+		let bind e =
+			if !had_side_effect then
+				declare_temp e.etype (Some (loop e)) e.epos
+			else begin
+				had_side_effect := true;
+				e
+			end
+		in
 		let rec no_side_effect e = match e.eexpr with
 			| TNew _ | TCall _ | TArrayDecl _ | TObjectDecl _ | TBinop ((OpAssignOp _ | OpAssign),_,_) | TUnop ((Increment|Decrement),_,_) ->
-				if !had_side_effect then
-					declare_temp e.etype (Some (loop e)) e.epos
-				else begin
-					had_side_effect := true;
-					e
-				end
+				bind e;
+			| TBinop(op,e1,e2) when Optimizer.has_side_effect e1 || Optimizer.has_side_effect e2 ->
+				bind e;
 			| TConst _ | TLocal _ | TTypeExpr _ | TFunction _
 			| TReturn _ | TBreak | TContinue | TThrow _ | TCast (_,Some _) ->
 				e

+ 84 - 1
tests/unit/unitstd/EvaluationOrder.unit.hx

@@ -18,4 +18,87 @@ obj.a = 6;
 obj.b = 7;
 obj.c = 8;
 
-func(i++, [i++, i++].join(";"), i++) == "9;10;11;12";
+func(i++, [i++, i++].join(";"), i++) == "9;10;11;12";
+
+var buf:Array<Int> = [];
+
+function a() {
+	buf.push(1);
+	return 1;
+}
+
+function b() {
+	buf.push(2);
+	return 2;
+}
+
+function c() {
+	buf.push(3);
+	return 3;
+}
+
+function d() {
+	buf.push(4);
+	return 4;
+}
+
+function e() {
+	buf.push(5);
+	return 5;
+}
+
+function f() {
+	buf.push(6);
+	return 6;
+}
+
+function begin() {
+	buf = [];
+	return function() {
+		return buf.join("_");
+	}
+}
+
+// &&
+
+var end = begin();
+(a() + b()) >= 0 && (c() + d()) >= 0;
+end() == "1_2_3_4";
+
+var end = begin();
+(a() + b()) >= 99 && (c() + d()) >= 0;
+end() == "1_2";
+
+var end = begin();
+(a() + b()) >= 0 && (c() + d()) >= 0 && (e() + f()) >= 0;
+end() == "1_2_3_4_5_6";
+
+var end = begin();
+(a() + b()) >= 99 && (c() + d()) >= 0 && (e() + f()) >= 0;
+end() == "1_2";
+
+var end = begin();
+(a() + b()) >= 0 && (c() + d()) >= 99 && (e() + f()) >= 0;
+end() == "1_2_3_4";
+
+// ||
+
+var end = begin();
+(a() + b()) >= 0 || (c() + d()) >= 0;
+end() == "1_2";
+
+var end = begin();
+(a() + b()) >= 99 || (c() + d()) >= 0;
+end() == "1_2_3_4";
+
+var end = begin();
+(a() + b()) >= 0 || (c() + d()) >= 0 || (e() + f()) >= 0;
+end() == "1_2";
+
+var end = begin();
+(a() + b()) >= 99 || (c() + d()) >= 0 || (e() + f()) >= 0;
+end() == "1_2_3_4";
+
+var end = begin();
+(a() + b()) >= 99 || (c() + d()) >= 99 || (e() + f()) >= 0;
+eq(end(), "1_2_3_4_5_6");