Bladeren bron

treat Any as Dynamic in variance unification, add @:forward.variance (#9741)

Dmitrii Maganov 5 jaren geleden
bovenliggende
commit
c9408747b4
4 gewijzigde bestanden met toevoegingen van 50 en 2 verwijderingen
  1. 6 0
      src-json/meta.json
  2. 7 2
      src/core/tUnification.ml
  3. 1 0
      std/Any.hx
  4. 36 0
      tests/unit/src/unit/issues/Issue9741.hx

+ 6 - 0
src-json/meta.json

@@ -402,6 +402,12 @@
 		"targets": ["TAbstract"],
 		"links": ["https://haxe.org/manual/types-abstract-forward.html"]
 	},
+	{
+		"name": "ForwardVariance",
+		"metadata": ":forward.variance",
+		"doc": "Forwards variance unification to underlying type.",
+		"targets": ["TAbstract"]
+	},
 	{
 		"name": "From",
 		"metadata": ":from",

+ 7 - 2
src/core/tUnification.ml

@@ -961,8 +961,9 @@ and unify_with_variance uctx f t1 t2 =
 	let t1 = follow t1 in
 	let t2 = follow t2 in
 	let unify_nested t1 t2 = with_variance (get_nested_context uctx) f t1 t2 in
-	let rec get_underlying_type t = match map get_underlying_type (follow t) with
-		| TAbstract(ab,tl) -> (match apply_params ab.a_params tl ab.a_this with
+	let get_this_type ab tl = follow (apply_params ab.a_params tl ab.a_this) in
+	let rec get_underlying_type t = match map get_underlying_type t with
+		| TAbstract(ab,tl) -> (match get_this_type ab tl with
 			| TAbstract(ab',_) as t when ab == ab' -> t
 			| t -> get_underlying_type t)
 		| t -> t
@@ -992,6 +993,10 @@ and unify_with_variance uctx f t1 t2 =
 		List.iter2 unify_nested tl1 tl2
 	| TAbstract(a1,tl1),TAbstract(a2,tl2) when a1 == a2 ->
 		List.iter2 unify_nested tl1 tl2
+	| TAbstract(ab,tl),_ when Meta.has Meta.ForwardVariance ab.a_meta ->
+		unify_with_variance uctx f (get_this_type ab tl) t2
+	| _,TAbstract(ab,tl) when Meta.has Meta.ForwardVariance ab.a_meta ->
+		unify_with_variance uctx f t1 (get_this_type ab tl)
 	| TAbstract(a1,tl1),TAbstract(a2,tl2) ->
 		if not (unifies_abstract uctx t1 t2 a1 tl1 a1.a_to)
 		&& not (unifies_abstract uctx t1 t2 a2 tl2 a2.a_from) then fail();

+ 1 - 0
std/Any.hx

@@ -31,6 +31,7 @@
 	to work with the actual value, it needs to be explicitly promoted
 	to another type.
 **/
+@:forward.variance
 abstract Any(Dynamic) {
 	@:noCompletion @:to extern inline function __promote<T>():T
 		return this;

+ 36 - 0
tests/unit/src/unit/issues/Issue9741.hx

@@ -0,0 +1,36 @@
+package unit.issues;
+
+class Issue9741 extends Test {
+  function test() {
+    var any: Any = null;
+    checkMainT(any);
+
+    var arrayInt: Array<Int> = [0, 1];
+    checkArrayAny(arrayInt);
+
+    var arrayAny: Array<Any> = arrayInt;
+    checkSameT(arrayInt, arrayInt);
+    checkSameT(arrayAny, arrayAny);
+    checkSameT(arrayAny, arrayInt);
+    t(unit.HelperMacros.typeError(checkSameT(arrayInt, arrayAny)));
+
+    t(unit.HelperMacros.typeError(((null: Bar): Int)));
+    t(unit.HelperMacros.typeError(((null: Int): Bar)));
+    ((null: {x: Bar}): {x: Int});
+    ((null: {x: Int}): {x: Bar});
+  }
+
+  static function checkMainT<T:Issue9741>(v:T) {}
+
+  static function checkArrayAny(a:Array<Any>) {}
+
+  static function checkSameT<T>(a1:T, a2:T) {}
+}
+
+private class Foo {
+  public function new() {}
+}
+
+@:forward.variance private abstract Bar(Int) {
+  public inline function new() this = 0;
+}