Bläddra i källkod

avoid ambiguous op casts (#12146)

Simon Krajewski 3 månader sedan
förälder
incheckning
0a18d75dfc
2 ändrade filer med 52 tillägg och 2 borttagningar
  1. 13 2
      src/typing/operators.ml
  2. 39 0
      tests/unit/src/unit/issues/Issue12145.hx

+ 13 - 2
src/typing/operators.ml

@@ -638,8 +638,19 @@ let type_non_assign_op ctx op e1 e2 is_assign_op abstract_overload_only with_typ
 	in
 	in
 	let e1 = type_expr ctx e1 wt in
 	let e1 = type_expr ctx e1 wt in
 	let e1 = match wt with
 	let e1 = match wt with
-		| WithType.WithType(t,_) -> AbstractCast.cast_or_unify ctx t e1 e1.epos
-		| _ -> e1
+		| WithType.WithType(t,_) ->
+			let has_matching_op a =
+				List.exists (fun (o,_) -> o = op) a.a_ops
+			in
+			begin match follow e1.etype with
+				| TAbstract(a,tl) when has_matching_op a ->
+					(* The operator could be ambiguous, let's not cast (issue #12145). *)
+					e1
+				| _ ->
+					AbstractCast.cast_or_unify ctx t e1 e1.epos
+			end
+		| _ ->
+			e1
 	in
 	in
 	let result = if abstract_overload_only then begin
 	let result = if abstract_overload_only then begin
 		let e2 = type_binop_rhs ctx op e1 e2 is_assign_op with_type p in
 		let e2 = type_binop_rhs ctx op e1 e2 is_assign_op with_type p in

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

@@ -0,0 +1,39 @@
+package unit.issues;
+
+import utest.Assert;
+
+@:structInit
+final private class PointImpl {
+	public var x:Float;
+}
+
+@:forward
+private abstract Point(PointImpl) from PointImpl to PointImpl {
+	@:op(a - b)
+	public function sub_p(p:Point):Vec
+		return {x: this.x - p.x};
+}
+
+@:structInit
+final private class VecImpl {
+	public var x:Float;
+}
+
+@:forward
+private abstract Vec(VecImpl) from VecImpl to VecImpl {
+	// comment out this function and compilation will succeed
+	@:op(a - b)
+	public function sub_v(v:Vec):Vec
+		return {x: this.x - v.x};
+}
+
+class Issue12145 extends Test {
+	function test() {
+		final a:Point = {x: 2};
+		final b:Point = {x: 1};
+		// success if remove the :Vec, and even determines the correct type
+		// however the same scenario can be repro'd by passing the result of the subtraction to a function which accepts Vec
+		final c:Vec = a - b;
+		feq(1.0, c.x);
+	}
+}