Parcourir la source

allow transitive casts only if one of the abstracts is a `@:coreType` like we previously did (closes #3360)

Simon Krajewski il y a 11 ans
Parent
commit
262ba9a354
2 fichiers modifiés avec 60 ajouts et 2 suppressions
  1. 53 0
      tests/unit/issues/Issue3360.hx
  2. 7 2
      type.ml

+ 53 - 0
tests/unit/issues/Issue3360.hx

@@ -0,0 +1,53 @@
+package unit.issues;
+
+private abstract Vec3(Array<Float>) from Array<Float> to Array<Float> {
+    inline public function new(_x:Float, _y:Float, _z:Float):Vec3
+    	this = _alloc(_x, _y, _z);
+
+	inline private static function _alloc(_x:Float, _y:Float, _z:Float):Array<Float>
+        return [_x, _y, _z];
+}
+
+private abstract Quat(Array<Float>) from Array<Float> to Array<Float> {
+    inline public function new(_x:Float, _y:Float, _z:Float, _w:Float):Quat
+    	this = _alloc(_x, _y, _z, _w);
+
+	inline private static function _alloc(_x:Float, _y:Float, _z:Float, _w:Float):Array<Float>
+        return [_x, _y, _z, _w];
+
+    @:op(A * B)
+    inline public static function transformVec3(lhs:Quat, rhs:Vec3):Vec3 {
+        return new Vec3(1,2,3);
+    }
+
+    @:op(A * B)
+	inline public static function mult(lhs:Quat, rhs:Quat):Quat {
+        return new Quat(1,2,3,1);
+    }
+}
+
+private abstract Kilometer(Float) from Float to Float { }
+private abstract Meter(Float) from Float { }
+
+class Issue3360 extends Test {
+	function test() {
+        var v = new Vec3(0,0,0);
+        var q0 = new Quat(0,0,0,1);
+        var q1 = new Quat(0,0,0,1);
+
+        var res = q0 * v;
+		unit.TestType.typedAs(res, (null : Vec3));
+		feq(1, res[0]);
+		feq(2, res[1]);
+		feq(3, res[2]);
+        var res = q0 * q1;
+		unit.TestType.typedAs(res, (null : Quat));
+		feq(1, res[0]);
+		feq(2, res[1]);
+		feq(3, res[2]);
+		feq(1, res[3]);
+
+		var k:Kilometer = 1;
+		t(unit.TestType.typeError(var m:Meter = k));
+	}
+}

+ 7 - 2
type.ml

@@ -1299,8 +1299,13 @@ let rec unify a b =
 	| TAbstract (a1,tl1) , TAbstract (a2,tl2) ->
 		let f1 = unify_to a1 tl1 b in
 		let f2 = unify_from a2 tl2 a b in
-		if not (List.exists (f1 ~allow_transitive_cast:false) a1.a_to) && not (List.exists (f2 ~allow_transitive_cast:false) a2.a_from)
-		    && not (List.exists f1 a1.a_to) && not (List.exists f2 a2.a_from) then error [cannot_unify a b]
+		if (List.exists (f1 ~allow_transitive_cast:false) a1.a_to)
+		|| (List.exists (f2 ~allow_transitive_cast:false) a2.a_from)
+		|| (((Meta.has Meta.CoreType a1.a_meta) || (Meta.has Meta.CoreType a2.a_meta))
+			&& ((List.exists f1 a1.a_to) || (List.exists f2 a2.a_from))) then
+			()
+		else
+			error [cannot_unify a b]
 	| TInst (c1,tl1) , TInst (c2,tl2) ->
 		let rec loop c tl =
 			if c == c2 then begin