Prechádzať zdrojové kódy

check exact cast before checking transitive ones (closes #2614)

Simon Krajewski 11 rokov pred
rodič
commit
631150fa5c
2 zmenil súbory, kde vykonal 40 pridanie a 5 odobranie
  1. 32 0
      tests/unit/issues/Issue2614.hx
  2. 8 5
      type.ml

+ 32 - 0
tests/unit/issues/Issue2614.hx

@@ -0,0 +1,32 @@
+package unit.issues;
+import unit.Test;
+
+abstract Lazy<T>(Void->T) {
+	public function new(f) {
+		this = f;
+	}
+	
+	public function evaluate() {
+		return this();
+	}
+	
+    @:from static function ofConst<T>(c:T):Lazy<T> {
+        return new Lazy(function() return c);
+	}
+}
+
+class Issue2614 extends Test {
+	
+	function test() {
+		var fInt = lazy(2);
+		var fFloat = lazy(2.);
+		eq(fInt.evaluate(), 2);
+		feq(fFloat.evaluate(), 2.);
+		unit.TestType.typedAs(fInt, (null : Lazy<Int>));
+		unit.TestType.typedAs(fFloat, (null : Lazy<Float>));
+	}
+	
+	static public function lazy<A>(l:Lazy<A>):Lazy<A> {
+        return l;
+	}
+}

+ 8 - 5
type.ml

@@ -1046,7 +1046,10 @@ let rec unify a b =
 	| _ , TAbstract ({a_path=[],"Void"},_) ->
 		error [cannot_unify a b]
 	| TAbstract (a1,tl1) , TAbstract (a2,tl2) ->
-		if not (List.exists (unify_to_field a1 tl1 b) a1.a_to) && not (List.exists (unify_from_field a2 tl2 a b) a2.a_from) then error [cannot_unify a b]
+		let f1 = unify_to_field a1 tl1 b in
+		let f2 = unify_from_field 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]
 	| TInst (c1,tl1) , TInst (c2,tl2) ->
 		let rec loop c tl =
 			if c == c2 then begin
@@ -1219,10 +1222,10 @@ let rec unify a b =
 	| _ , _ ->
 		error [cannot_unify a b]
 
-and unify_from_field ab tl a b (t,cfo) =
+and unify_from_field ab tl a b ?(allow_transitive_cast=true) (t,cfo) =
 	if (List.exists (fun (a2,b2) -> fast_eq a a2 && fast_eq b b2) (!abstract_cast_stack)) then false else begin
 	abstract_cast_stack := (a,b) :: !abstract_cast_stack;
-	let unify_func = match follow a with TAbstract({a_impl = Some _},_) when ab.a_impl <> None -> type_eq EqStrict | _ -> unify in
+	let unify_func = match follow a with TAbstract({a_impl = Some _},_) when ab.a_impl <> None || not allow_transitive_cast -> type_eq EqStrict | _ -> unify in
 	let b = try begin match cfo with
 		| Some cf -> (match follow cf.cf_type with
 			| TFun(_,r) ->
@@ -1241,11 +1244,11 @@ and unify_from_field ab tl a b (t,cfo) =
 	b
 	end
 
-and unify_to_field ab tl b (t,cfo) =
+and unify_to_field ab tl b ?(allow_transitive_cast=true) (t,cfo) =
 	let a = TAbstract(ab,tl) in
 	if (List.exists (fun (b2,a2) -> fast_eq a a2 && fast_eq b b2) (!abstract_cast_stack)) then false else begin
 	abstract_cast_stack := (b,a) :: !abstract_cast_stack;
-	let unify_func = match follow b with TAbstract({a_impl = Some _},_) when ab.a_impl <> None -> type_eq EqStrict | _ -> unify in
+	let unify_func = match follow b with TAbstract({a_impl = Some _},_) when ab.a_impl <> None || not allow_transitive_cast -> type_eq EqStrict | _ -> unify in
 	let b = try begin match cfo with
 		| Some cf -> (match follow cf.cf_type with
 			| TFun((_,_,ta) :: _,_) ->