瀏覽代碼

[typer] try to get commutative binops right

closes #9771
Simon Krajewski 5 年之前
父節點
當前提交
71f357206a
共有 2 個文件被更改,包括 51 次插入12 次删除
  1. 12 12
      src/typing/operators.ml
  2. 39 0
      tests/unit/src/unit/issues/Issue9771.hx

+ 12 - 12
src/typing/operators.ml

@@ -109,8 +109,8 @@ module BinopResult = struct
 				| false ->
 				| false ->
 					e1,e2
 					e1,e2
 				| true ->
 				| true ->
-					let eloc1 = vr#as_var "lhs" e1 in
-					let eloc2 = vr#as_var "rhs" e2 in
+					let eloc1 = vr#as_var "lhs" e2 in
+					let eloc2 = vr#as_var "rhs" e1 in
 					eloc2,eloc1
 					eloc2,eloc1
 			in
 			in
 			let e = mk (TBinop(bn.binop_op,e1,e2)) bn.binop_type bn.binop_pos in
 			let e = mk (TBinop(bn.binop_op,e1,e2)) bn.binop_type bn.binop_pos in
@@ -459,10 +459,15 @@ let find_abstract_binop_overload ctx op e1 e2 a c tl left is_assign_op with_type
 				end;
 				end;
 			end;
 			end;
 			BinopResult.create_normal op e1 e2 tret needs_assign swapped p
 			BinopResult.create_normal op e1 e2 tret needs_assign swapped p
-		end else begin
-			let el = if swapped then [e2;e1] else [e1;e2] in
-			BinopResult.create_special (make_static_call ctx c cf map el tret p) needs_assign
-		end
+		end else if swapped then begin
+			let vr = new value_reference ctx in
+			let e2' = vr#as_var "lhs" e2 in
+			let e1' = vr#as_var "rhs" e1 in
+			let e = make_static_call ctx c cf map [e1';e2'] tret p in
+			let e = vr#to_texpr e in
+			BinopResult.create_special e needs_assign
+		end else
+			BinopResult.create_special (make_static_call ctx c cf map [e1;e2] tret p) needs_assign
 	in
 	in
 	(* special case for == and !=: if the second type is a monomorph, assume that we want to unify
 	(* special case for == and !=: if the second type is a monomorph, assume that we want to unify
 		it with the first type to preserve comparison semantics. *)
 		it with the first type to preserve comparison semantics. *)
@@ -510,12 +515,7 @@ let find_abstract_binop_overload ctx op e1 e2 a c tl left is_assign_op with_type
 							check_null e1 t1;
 							check_null e1 t1;
 						end;
 						end;
 						let needs_assign = is_assign_op && op_cf = op in
 						let needs_assign = is_assign_op && op_cf = op in
-						let e = if not swapped then
-							make e1 e2 needs_assign false
-						else begin
-							make e2 e1 needs_assign true
-						end in
-						e
+						make e1 e2 needs_assign swapped
 					in
 					in
 					begin try
 					begin try
 						check e1 e2 false
 						check e1 e2 false

+ 39 - 0
tests/unit/src/unit/issues/Issue9771.hx

@@ -0,0 +1,39 @@
+package unit.issues;
+
+private abstract Continue(Dynamic) {
+	@:commutative @:op(a+b)
+	@:extern static inline function then<A>(e:Continue, a:A):A
+	  return a;
+  }
+
+class Issue9771 extends unit.Test {
+	var buf:StringBuf;
+
+	function append(v:Dynamic):Continue {
+		buf.add(v);
+		return v;
+	}
+
+	function test() {
+		function bar() {
+			append('bar');
+			return 'bar';
+		}
+		buf = new StringBuf();
+		eq('bar', append('foo') + bar());
+		eq('foobar', buf.toString());
+		buf = new StringBuf();
+		eq('bar', bar() + append('foo'));
+	}
+
+	function testMutableLocal() {
+		var bar = "bar";
+		function append(v:Dynamic):Continue {
+			bar = "notbar";
+			return v;
+		}
+		eq('notbar', append('foo') + bar);
+		bar = "bar";
+		eq('bar', bar + append('foo'));
+	}
+}