Browse Source

handle mixed constraints of types and anon fields (fixes #10162)

Aleksandr Kuzmenko 4 years ago
parent
commit
6fe3266047

+ 5 - 2
src/context/display/displayFields.ml

@@ -139,7 +139,7 @@ let collect ctx e_ast e dk with_type p =
 		in
 		match follow t with
 		| TMono m ->
-			begin match Monomorph.classify_down_constraints m with
+			let rec fold_constraints items = function
 			| CStructural(fields,is_open) ->
 				if not is_open then begin
 					Monomorph.close m;
@@ -153,7 +153,10 @@ let collect ctx e_ast e dk with_type p =
 				items
 			| CUnknown ->
 				items
-			end
+			| CMixed l ->
+				List.fold_left fold_constraints items l
+			in
+			fold_constraints items (Monomorph.classify_down_constraints m)
 		| TInst ({cl_kind = KTypeParameter tl},_) ->
 			(* Type parameters can access the fields of their constraints *)
 			List.fold_left (fun acc t -> loop acc t) items tl

+ 8 - 3
src/core/tPrinting.ml

@@ -39,10 +39,15 @@ let rec s_type ctx t =
 			with Not_found ->
 				let id = List.length !ctx in
 				ctx := (t,id) :: !ctx;
-			let s_const = match !monomorph_classify_constraints_ref r with
+			let s_const =
+				let rec loop = function
 				| CUnknown -> ""
-				| CTypes tl -> " : " ^ String.concat " & " (List.map (fun (t,_) -> s_type ctx t) tl)
-				| CStructural(fields,_) -> " : " ^ s_type ctx (mk_anon ~fields (ref Closed))
+				| CTypes tl -> String.concat " & " (List.map (fun (t,_) -> s_type ctx t) tl)
+				| CStructural(fields,_) -> s_type ctx (mk_anon ~fields (ref Closed))
+				| CMixed l -> String.concat " & " (List.map loop l)
+				in
+				let s = loop (!monomorph_classify_constraints_ref r) in
+				if s = "" then s else " : " ^ s
 			in
 				Printf.sprintf "Unknown<%d>%s" id s_const
 			end

+ 1 - 0
src/core/tType.ml

@@ -65,6 +65,7 @@ and tmono_constraint =
 and tmono_constraint_kind =
 	| CUnknown
 	| CStructural of (string,tclass_field) PMap.t * bool
+	| CMixed of tmono_constraint_kind list
 	| CTypes of (t * string option) list
 
 and tlazy =

+ 17 - 8
src/core/tUnification.ml

@@ -131,18 +131,25 @@ module Monomorph = struct
 		in
 		List.iter check m.tm_down_constraints;
 		let kind =
-			if DynArray.length types > 0 then
-				CTypes (DynArray.to_list types)
-			else if not (PMap.is_empty !fields) || !is_open then
-				CStructural(!fields,!is_open)
+			let k1 =
+				if DynArray.length types > 0 then
+					CTypes (DynArray.to_list types)
+				else
+					CUnknown
+			in
+			if not (PMap.is_empty !fields) || !is_open then
+				let k2 = CStructural(!fields,!is_open) in
+				match k1 with
+				| CTypes _ -> CMixed [k1; k2]
+				| _ -> k2
 			else
-				CUnknown
+				k1
 		in
 		!monos,kind
 
 	let classify_down_constraints m = snd (classify_down_constraints' m)
 
-	let check_down_constraints constr t =
+	let rec check_down_constraints constr t =
 		match constr with
 		| CUnknown ->
 			()
@@ -156,6 +163,8 @@ module Monomorph = struct
 		| CStructural(fields,is_open) ->
 			let t2 = mk_anon ~fields (ref Closed) in
 			(!unify_ref) default_unification_context t t2
+		| CMixed l ->
+			List.iter (fun constr -> check_down_constraints constr t) l
 
 	let rec collect_up_constraints m =
 		let rec collect m acc =
@@ -213,7 +222,7 @@ module Monomorph = struct
 			(* Due to recursive constraints like in #9603, we tentatively bind the monomorph to the type we're checking
 			   against before checking the constraints. *)
 			m.tm_type <- Some t;
-			let monos,kind = classify_down_constraints' m in
+			let kind = classify_down_constraints m in
 			Std.finally (fun () -> m.tm_type <- None) (fun () -> check_down_constraints kind t) ();
 			do_bind m t
 		end
@@ -227,7 +236,7 @@ module Monomorph = struct
 			| CTypes [(t,_)] ->
 				do_bind m t;
 				()
-			| CTypes _ ->
+			| CTypes _ | CMixed _ ->
 				()
 			| CStructural(fields,_) ->
 				let check_recursion cf =

+ 13 - 2
src/typing/fields.ml

@@ -354,7 +354,7 @@ let type_field cfg ctx e i p mode (with_type : WithType.t) =
 				(mk_field i (mk_mono()) p null_pos) with
 				cf_kind = Var { v_read = AccNormal; v_write = if is_set then AccNormal else AccNo }
 			} in
-			(match Monomorph.classify_down_constraints r with
+			let rec check_constr = function
 			| CStructural (fields,is_open) ->
 				(try
 					let f = PMap.find i fields in
@@ -377,7 +377,18 @@ let type_field cfg ctx e i p mode (with_type : WithType.t) =
 				Monomorph.add_down_constraint r (MField f);
 				Monomorph.add_down_constraint r MOpenStructure;
 				field_access f FHAnon
-			)
+			| CMixed l ->
+				let rec loop_constraints l =
+					match l with
+					| [] ->
+						raise Not_found
+					| constr :: l ->
+						try check_constr constr
+						with Not_found -> loop_constraints l
+				in
+				loop_constraints l
+			in
+			check_constr (Monomorph.classify_down_constraints r)
 		| TAbstract (a,tl) ->
 			(try
 				let c = find_some a.a_impl in

+ 10 - 0
tests/unit/src/unit/TestDCE.hx

@@ -190,6 +190,16 @@ class TestDCE extends Test {
 		var c = Type.getClass(me);
 		hf(c, "get_bar");
 	}
+
+	public function testIssue10162() {
+		eq('bar', foo(ClassWithBar));
+	}
+	static function foo<T:Class<Dynamic> & { function bar():String; }>(cls:T)
+		return cls.bar();
+}
+
+class ClassWithBar {
+	static public function bar() return 'bar';
 }
 
 class UsedConstructed {