Sfoglia il codice sorgente

when checking for casts between two abstract, check for direct to/from first and then for @:to/@:from field casts (closes #6751) (#6753)

Dan Korostelev 8 anni fa
parent
commit
b5a0c44433
3 ha cambiato i file con 45 aggiunte e 8 eliminazioni
  1. 1 4
      src/context/typecore.ml
  2. 23 4
      src/core/abstract.ml
  3. 21 0
      tests/unit/src/unit/issues/Issue6751.hx

+ 1 - 4
src/context/typecore.ml

@@ -369,10 +369,7 @@ module AbstractCast = struct
 		else begin
 			let rec loop tleft tright = match follow tleft,follow tright with
 			| TAbstract(a1,tl1),TAbstract(a2,tl2) ->
-				begin try find a2 tl2 (fun () -> Abstract.find_to a2 tl2 tleft)
-				with Not_found -> try find a1 tl1 (fun () -> Abstract.find_from a1 tl1 eright.etype tleft)
-				with Not_found -> raise Not_found
-				end
+				Abstract.find_to_from find a1 tl1 a2 tl2 tleft eright.etype
 			| TAbstract(a,tl),_ ->
 				begin try find a tl (fun () -> Abstract.find_from a tl eright.etype tleft)
 				with Not_found ->

+ 23 - 4
src/core/abstract.ml

@@ -2,21 +2,40 @@ open Meta
 open Type
 open Error
 
+let has_direct_to ab pl b =
+	List.exists (unify_to ab pl ~allow_transitive_cast:false b) ab.a_to
+
+let has_direct_from ab pl a b =
+	List.exists (unify_from ab pl a ~allow_transitive_cast:false b) ab.a_from
+
+let find_field_to ab pl b =
+	List.find (unify_to_field ab pl b) ab.a_to_field
+
+let find_field_from ab pl a b =
+	List.find (unify_from_field ab pl a b) ab.a_from_field
+
+let find_to_from f ab_left tl_left ab_right tl_right tleft tright =
+	if has_direct_to ab_right tl_right tleft || has_direct_from ab_left tl_left tright tleft then
+		raise Not_found
+	else
+		try f ab_right tl_right (fun () -> find_field_to ab_right tl_right tleft)
+		with Not_found -> f ab_left tl_left (fun () -> find_field_from ab_left tl_left tright tleft)
+
 let find_to ab pl b =
 	if follow b == t_dynamic then
 		List.find (fun (t,_) -> follow t == t_dynamic) ab.a_to_field
-	else if List.exists (unify_to ab pl ~allow_transitive_cast:false b) ab.a_to then
+	else if has_direct_to ab pl b then
 		raise Not_found (* legacy compatibility *)
 	else
-		List.find (unify_to_field ab pl b) ab.a_to_field
+		find_field_to ab pl b
 
 let find_from ab pl a b =
 	if follow a == t_dynamic then
 		List.find (fun (t,_) -> follow t == t_dynamic) ab.a_from_field
-	else if List.exists (unify_from ab pl a ~allow_transitive_cast:false b) ab.a_from then
+	else if has_direct_from ab pl a b then
 		raise Not_found (* legacy compatibility *)
 	else
-		List.find (unify_from_field ab pl a b) ab.a_from_field
+		find_field_from ab pl a b
 
 let underlying_type_stack = ref []
 

+ 21 - 0
tests/unit/src/unit/issues/Issue6751.hx

@@ -0,0 +1,21 @@
+package unit.issues;
+
+import unit.HelperMacros.typedAs;
+
+private abstract O(String) {
+	public function new(s) this = s;
+	@:to function toInt() return 42;
+}
+
+private abstract A<T>(T) from T {}
+
+class Issue6751 extends Test {
+	function test() {
+		function make<T>(o:A<T>) return o;
+
+		var o = new O("hello");
+		var a = make(o);
+		typedAs(a, (null : A<O>));
+		eq(Std.string(a), "hello");
+	}
+}