Browse Source

only bind known type parameters to monomorphs in definition mode (#11658)

Simon Krajewski 1 year ago
parent
commit
9d2007b6ae

+ 13 - 5
src/core/tUnification.ml

@@ -32,6 +32,7 @@ type eq_kind =
 	| EqStricter
 
 type type_param_unification_context = {
+	known_type_params : typed_type_param list;
 	mutable type_param_pairs : (typed_type_param * typed_type_param) list;
 }
 
@@ -328,7 +329,7 @@ let rec follow_and_close t = match follow t with
 	| t ->
 		t
 
-let link e a b =
+let link uctx e a b =
 	(* tell if setting a == b will create a type-loop *)
 	let rec loop t =
 		if t == a then
@@ -336,6 +337,13 @@ let link e a b =
 		else match t with
 		| TMono t -> (match t.tm_type with None -> false | Some t -> loop t)
 		| TEnum (_,tl) -> List.exists loop tl
+		| TInst ({cl_kind = KTypeParameter ttp}, tl) ->
+			begin match uctx.type_param_mode with
+				| TpDefault ->
+					List.exists loop tl
+				| TpDefinition tctx ->
+					not (List.memq ttp tctx.known_type_params)
+			end
 		| TInst (_,tl) | TType (_,tl) | TAbstract (_,tl) -> List.exists loop tl
 		| TFun (tl,t) -> List.exists (fun (_,_,t) -> loop t) tl || loop t
 		| TDynamic None ->
@@ -554,11 +562,11 @@ let rec type_eq uctx a b =
 	| _ , TLazy f -> type_eq uctx a (lazy_type f)
 	| TMono t , _ ->
 		(match t.tm_type with
-		| None -> if param = EqCoreType || param = EqStricter || not (link t a b) then error [cannot_unify a b]
+		| None -> if param = EqCoreType || param = EqStricter || not (link uctx t a b) then error [cannot_unify a b]
 		| Some t -> type_eq uctx t b)
 	| _ , TMono t ->
 		(match t.tm_type with
-		| None -> if param = EqCoreType || param = EqStricter || not (link t b a) then error [cannot_unify a b]
+		| None -> if param = EqCoreType || param = EqStricter || not (link uctx t b a) then error [cannot_unify a b]
 		| Some t -> type_eq uctx a t)
 	| TDynamic None, TDynamic None ->
 		()
@@ -714,11 +722,11 @@ let rec unify (uctx : unification_context) a b =
 	| _ , TLazy f -> unify uctx a (lazy_type f)
 	| TMono t , _ ->
 		(match t.tm_type with
-		| None -> if uctx.equality_kind = EqStricter || not (link t a b) then error [cannot_unify a b]
+		| None -> if uctx.equality_kind = EqStricter || not (link uctx t a b) then error [cannot_unify a b]
 		| Some t -> unify uctx t b)
 	| _ , TMono t ->
 		(match t.tm_type with
-		| None -> if uctx.equality_kind = EqStricter || not (link t b a) then error [cannot_unify a b]
+		| None -> if uctx.equality_kind = EqStricter || not (link uctx t b a) then error [cannot_unify a b]
 		| Some t -> unify uctx a t)
 	| TType (t,tl) , _ ->
 		rec_stack unify_stack (a,b)

+ 1 - 0
src/typing/typeloadCheck.ml

@@ -50,6 +50,7 @@ let is_generic_parameter ctx c =
 let valid_redefinition map1 map2 f1 t1 f2 t2 = (* child, parent *)
 	let tctx = {
 		type_param_pairs = [];
+		known_type_params = f1.cf_params
 	} in
 	let uctx = {default_unification_context with type_param_mode = TpDefinition tctx} in
 	let valid t1 t2 =

+ 9 - 0
tests/misc/projects/Issue11624/MainBar.hx

@@ -0,0 +1,9 @@
+interface Foo {
+	function bar<T>():T;
+}
+
+class Bar implements Foo {
+	public function bar<T>() return null; // Error: write_full_path hxb writer failure
+}
+
+function main() {}

+ 9 - 0
tests/misc/projects/Issue11624/MainBaz.hx

@@ -0,0 +1,9 @@
+interface Foo {
+	function baz<T>():T;
+}
+
+class Bar implements Foo {
+	public function baz<T>():T return null; // this is fine
+}
+
+function main() {}

+ 9 - 0
tests/misc/projects/Issue11624/MainFoo.hx

@@ -0,0 +1,9 @@
+interface Foo {
+	function foo<T>():T;
+}
+
+class Bar implements Foo {
+	public function foo() return null; // Warning: Unbound type parameter foo.T
+}
+
+function main() {}

+ 2 - 0
tests/misc/projects/Issue11624/compile-bar-fail.hxml

@@ -0,0 +1,2 @@
+--main MainBar
+--interp

+ 5 - 0
tests/misc/projects/Issue11624/compile-bar-fail.hxml.stderr

@@ -0,0 +1,5 @@
+MainBar.hx:6: characters 18-21 : Field bar has different type than in Foo
+MainBar.hx:2: characters 11-14 : ... Interface field is defined here
+MainBar.hx:6: characters 18-21 : ... error: Null<Unknown<0>> should be bar.T
+MainBar.hx:6: characters 18-21 : ... have: (...) -> Null<...>
+MainBar.hx:6: characters 18-21 : ... want: (...) -> bar.T

+ 2 - 0
tests/misc/projects/Issue11624/compile-baz.hxml

@@ -0,0 +1,2 @@
+--main MainBaz
+--interp

+ 2 - 0
tests/misc/projects/Issue11624/compile-foo-fail.hxml

@@ -0,0 +1,2 @@
+--main MainFoo
+--interp

+ 5 - 0
tests/misc/projects/Issue11624/compile-foo-fail.hxml.stderr

@@ -0,0 +1,5 @@
+MainFoo.hx:6: characters 18-21 : Field foo has different type than in Foo
+MainFoo.hx:2: characters 11-14 : ... Interface field is defined here
+MainFoo.hx:6: characters 18-21 : ... error: Null<Unknown<0>> should be foo.T
+MainFoo.hx:6: characters 18-21 : ... have: (...) -> Null<...>
+MainFoo.hx:6: characters 18-21 : ... want: (...) -> foo.T