Bläddra i källkod

add unify_with_variance and with_variance, use it for type parameter and @:to unification

Simon Krajewski 11 år sedan
förälder
incheckning
b61dd2322b
1 ändrade filer med 35 tillägg och 21 borttagningar
  1. 35 21
      type.ml

+ 35 - 21
type.ml

@@ -1270,7 +1270,7 @@ and unify_to_field ab tl b ?(allow_transitive_cast=true) (t,cfo) =
 				let athis = map ab.a_this in
 				(* we cannot allow implicit casts when the this type is not completely known yet *)
 				if has_mono athis then raise (Unify_error []);
-				type_eq EqStrict athis (map ta);
+				with_variance (type_eq EqStrict) athis (map ta);
 				(* immediate constraints checking is ok here because we know there are no monomorphs *)
 				List.iter2 (fun m (name,t) -> match follow t with
 					| TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] ->
@@ -1289,33 +1289,47 @@ and unify_to_field ab tl b ?(allow_transitive_cast=true) (t,cfo) =
 	b
 	end
 
+and unify_with_variance t1 t2 =
+	let allows_variance_to t (tf,cfo) = match cfo with
+		| None -> type_iseq tf t
+		| Some _ -> false
+	in
+	match follow t1,follow t2 with
+	| TInst(c1,tl1),TInst(c2,tl2) when c1 == c2 ->
+		List.iter2 unify_with_variance tl1 tl2
+	| TEnum(en1,tl1),TEnum(en2,tl2) when en1 == en2 ->
+		List.iter2 unify_with_variance tl1 tl2
+	| TAbstract(a1,pl1),TAbstract(a2,pl2) ->
+		let ta1 = apply_params a1.a_types pl1 a1.a_this in
+		let ta2 = apply_params a2.a_types pl2 a2.a_this in
+		type_eq EqStrict ta1 ta2;
+		if not (List.exists (allows_variance_to ta2) a1.a_to) && not (List.exists (allows_variance_to ta1) a2.a_from) then error [cannot_unify t1 t2]
+	| TAbstract(a,pl),t ->
+		type_eq EqStrict (apply_params a.a_types pl a.a_this) t;
+		if not (List.exists (allows_variance_to t) a.a_to) then error [cannot_unify t1 t2]
+	| t,TAbstract(a,pl) ->
+		type_eq EqStrict t (apply_params a.a_types pl a.a_this);
+		if not (List.exists (allows_variance_to t) a.a_from) then error [cannot_unify t1 t2]
+	| _ ->
+		error [cannot_unify t1 t2]
+
 and unify_types a b tl1 tl2 =
 	List.iter2 (fun t1 t2 ->
 		try
-			type_eq EqRightDynamic t1 t2
+			with_variance (type_eq EqRightDynamic) t1 t2
 		with Unify_error l ->
 			let err = cannot_unify a b in
-			let allows_variance_to t (tf,cfo) = match cfo with
-				| None -> type_iseq tf t
-				| Some _ -> false
-			in
-			(try (match follow t1, follow t2 with
-				| TAbstract({a_impl = Some _} as a1,pl1),TAbstract({a_impl = Some _ } as a2,pl2) ->
-					let ta1 = apply_params a1.a_types pl1 a1.a_this in
-					let ta2 = apply_params a2.a_types pl2 a2.a_this in
-					type_eq EqStrict ta1 ta2;
-					if not (List.exists (allows_variance_to ta2) a1.a_to) && not (List.exists (allows_variance_to ta1) a2.a_from) then raise (Unify_error l)
-				| TAbstract({a_impl = Some _} as a,pl),t ->
-					type_eq EqStrict (apply_params a.a_types pl a.a_this) t;
-					if not (List.exists (allows_variance_to t) a.a_to) then raise (Unify_error l)
-				| t,TAbstract({a_impl = Some _ } as a,pl) ->
-					type_eq EqStrict t (apply_params a.a_types pl a.a_this);
-					if not (List.exists (allows_variance_to t) a.a_from) then raise (Unify_error l)
-				| _ -> raise (Unify_error l))
-			with Unify_error _ ->
-				error (err :: (Invariant_parameter (t1,t2)) :: l))
+			error (err :: (Invariant_parameter (t1,t2)) :: l)
 	) tl1 tl2
 
+and with_variance f t1 t2 =
+	try
+		f t1 t2
+	with Unify_error l -> try
+		unify_with_variance t1 t2
+	with Unify_error _ ->
+		raise (Unify_error l)
+
 and unify_with_access t1 f2 =
 	match f2.cf_kind with
 	(* write only *)