Browse Source

[typer] add dummy unification context to unify

Simon Krajewski 5 years ago
parent
commit
b9a55b4319
3 changed files with 89 additions and 80 deletions
  1. 6 4
      src/context/abstractCast.ml
  2. 19 19
      src/core/abstract.ml
  3. 64 57
      src/core/tUnification.ml

+ 6 - 4
src/context/abstractCast.ml

@@ -26,6 +26,7 @@ let rec make_static_call ctx c cf a pl args t p =
 		Typecore.make_static_call ctx c cf (apply_params a.a_params pl) args t p
 
 and do_check_cast ctx tleft eright p =
+	let uctx = default_unification_context in
 	let recurse cf f =
 		(*
 			Without this special check for macro @:from methods we will always get "Recursive implicit cast" error
@@ -61,9 +62,9 @@ and do_check_cast ctx tleft eright p =
 				let stack = (tleft,tright) :: stack in
 				match follow tleft,follow tright with
 				| TAbstract(a1,tl1),TAbstract(a2,tl2) ->
-					Abstract.find_to_from find a1 tl1 a2 tl2 tleft eright.etype
+					Abstract.find_to_from uctx 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)
+					begin try find a tl (fun () -> Abstract.find_from uctx a tl eright.etype tleft)
 					with Not_found ->
 						let rec loop2 tcl = match tcl with
 							| tc :: tcl ->
@@ -74,7 +75,7 @@ and do_check_cast ctx tleft eright p =
 						loop2 a.a_from
 					end
 				| _,TAbstract(a,tl) ->
-					begin try find a tl (fun () -> Abstract.find_to a tl tleft)
+					begin try find a tl (fun () -> Abstract.find_to uctx a tl tleft)
 					with Not_found ->
 						let rec loop2 tcl = match tcl with
 							| tc :: tcl ->
@@ -162,6 +163,7 @@ let find_array_access ctx a tl e1 e2o p =
 			error (Printf.sprintf "No @:arrayAccess function for %s accepts arguments of %s and %s" (s_type (TAbstract(a,tl))) (s_type e1.etype) (s_type e2.etype)) p
 
 let find_multitype_specialization com a pl p =
+	let uctx = default_unification_context in
 	let m = mk_mono() in
 	let tl = match Meta.get Meta.MultiType a.a_meta with
 		| _,[],_ -> pl
@@ -210,7 +212,7 @@ let find_multitype_specialization com a pl p =
 	in
 	let _,cf =
 		try
-			Abstract.find_to a tl m
+			Abstract.find_to uctx a tl m
 		with Not_found ->
 			let at = apply_params a.a_params pl a.a_this in
 			let st = s_type (print_context()) at in

+ 19 - 19
src/core/abstract.ml

@@ -9,46 +9,46 @@ let build_abstract a = match a.a_impl with
 	| Some c -> ignore(c.cl_build())
 	| None -> ()
 
-let has_direct_to ab pl b =
-	List.exists (unify_to ab pl ~allow_transitive_cast:false b) ab.a_to
+let has_direct_to uctx ab pl b =
+	List.exists (unify_to uctx 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 has_direct_from uctx ab pl a b =
+	List.exists (unify_from uctx ab pl a ~allow_transitive_cast:false b) ab.a_from
 
-let find_field_to ab pl b =
+let find_field_to uctx ab pl b =
 	build_abstract ab;
-	List.find (unify_to_field ab pl b) ab.a_to_field
+	List.find (unify_to_field uctx ab pl b) ab.a_to_field
 
-let find_field_from ab pl a b =
+let find_field_from uctx ab pl a b =
 	build_abstract ab;
-	List.find (unify_from_field ab pl a b) ab.a_from_field
+	List.find (unify_from_field uctx ab pl a b) ab.a_from_field
 
-let find_to_from f ab_left tl_left ab_right tl_right tleft tright =
+let find_to_from uctx f ab_left tl_left ab_right tl_right tleft tright =
 	build_abstract ab_left;
 	build_abstract ab_right;
-	if has_direct_to ab_right tl_right tleft || has_direct_from ab_left tl_left tright tleft then
+	if has_direct_to uctx ab_right tl_right tleft || has_direct_from uctx 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)
+		try f ab_right tl_right (fun () -> find_field_to uctx ab_right tl_right tleft)
+		with Not_found -> f ab_left tl_left (fun () -> find_field_from uctx ab_left tl_left tright tleft)
 
-let find_to ab pl b =
+let find_to uctx ab pl b =
 	build_abstract ab;
 	if follow b == t_dynamic then
 		List.find (fun (t,_) -> follow t == t_dynamic) ab.a_to_field
-	else if has_direct_to ab pl b then
+	else if has_direct_to uctx ab pl b then
 		raise Not_found (* legacy compatibility *)
 	else
-		find_field_to ab pl b
+		find_field_to uctx ab pl b
 
-let find_from ab pl a b =
+let find_from uctx ab pl a b =
 	build_abstract ab;
 	if follow a == t_dynamic then
 		List.find (fun (t,_) -> follow t == t_dynamic) ab.a_from_field
-	else if has_direct_from ab pl a b then
+	else if has_direct_from uctx ab pl a b then
 		raise Not_found (* legacy compatibility *)
 	else
-		find_field_from ab pl a b
+		find_field_from uctx ab pl a b
 
 let underlying_type_stack = new_rec_stack()
 
@@ -90,7 +90,7 @@ let rec get_underlying_type ?(return_first=false) a pl =
 			`find_to` is probably needed for `@:multiType`
 		*)
 		let m = mk_mono() in
-		let _ = find_to a pl m in
+		let _ = find_to default_unification_context a pl m in
 		maybe_recurse (follow m)
 	with Not_found ->
 		if Meta.has Meta.CoreType a.a_meta then

+ 64 - 57
src/core/tUnification.ml

@@ -268,6 +268,8 @@ type eq_kind =
 	| EqBothDynamic
 	| EqDoNotFollowNull (* like EqStrict, but does not follow Null<T> *)
 
+type unification_context = unit
+
 let rec type_eq param a b =
 	let can_follow t = match param with
 		| EqCoreType -> false
@@ -405,46 +407,48 @@ let print_stacks() =
 	print_endline "abstract_cast_stack";
 	List.iter (fun (a,b) -> Printf.printf "\t%s , %s\n" (st a) (st b)) abstract_cast_stack.rec_stack
 
-let rec unify a b =
+let default_unification_context = ()
+
+let rec unify (uctx : unification_context) a b =
 	if a == b then
 		()
 	else match a, b with
-	| TLazy f , _ -> unify (lazy_type f) b
-	| _ , TLazy f -> unify a (lazy_type f)
+	| TLazy f , _ -> unify uctx (lazy_type f) b
+	| _ , TLazy f -> unify uctx a (lazy_type f)
 	| TMono t , _ ->
 		(match t.tm_type with
 		| None -> if not (link t a b) then error [cannot_unify a b]
-		| Some t -> unify t b)
+		| Some t -> unify uctx t b)
 	| _ , TMono t ->
 		(match t.tm_type with
 		| None -> if not (link t b a) then error [cannot_unify a b]
-		| Some t -> unify a t)
+		| Some t -> unify uctx a t)
 	| TType (t,tl) , _ ->
 		rec_stack unify_stack (a,b)
 			(fun(a2,b2) -> fast_eq a a2 && fast_eq b b2)
-			(fun() -> try_apply_params_rec t.t_params tl t.t_type (fun a -> unify a b))
+			(fun() -> try_apply_params_rec t.t_params tl t.t_type (fun a -> unify uctx a b))
 			(fun l -> error (cannot_unify a b :: l))
 	| _ , TType (t,tl) ->
 		rec_stack unify_stack (a,b)
 			(fun(a2,b2) -> fast_eq a a2 && fast_eq b b2)
-			(fun() -> try_apply_params_rec t.t_params tl t.t_type (unify a))
+			(fun() -> try_apply_params_rec t.t_params tl t.t_type (unify uctx a))
 			(fun l -> error (cannot_unify a b :: l))
 	| TEnum (ea,tl1) , TEnum (eb,tl2) ->
 		if ea != eb then error [cannot_unify a b];
-		unify_type_params a b tl1 tl2
+		unify_type_params uctx a b tl1 tl2
 	| TAbstract ({a_path=[],"Null"},[t]),_ ->
-		begin try unify t b
+		begin try unify uctx t b
 		with Unify_error l -> error (cannot_unify a b :: l) end
 	| _,TAbstract ({a_path=[],"Null"},[t]) ->
-		begin try unify a t
+		begin try unify uctx a t
 		with Unify_error l -> error (cannot_unify a b :: l) end
 	| TAbstract (a1,tl1) , TAbstract (a2,tl2) when a1 == a2 ->
 		begin try
-			unify_type_params a b tl1 tl2
+			unify_type_params uctx a b tl1 tl2
 		with Unify_error _ as err ->
 			(* the type could still have a from/to relation to itself (issue #3494) *)
 			begin try
-				unify_abstracts a b a1 tl1 a2 tl2
+				unify_abstracts uctx a b a1 tl1 a2 tl2
 			with Unify_error _ ->
 				raise err
 			end
@@ -456,11 +460,11 @@ let rec unify a b =
 	| _, TAbstract ({ a_path = ["haxe"],"NotVoid" },[]) ->
 		()
 	| TAbstract (a1,tl1) , TAbstract (a2,tl2) ->
-		unify_abstracts a b a1 tl1 a2 tl2
+		unify_abstracts uctx a b a1 tl1 a2 tl2
 	| TInst (c1,tl1) , TInst (c2,tl2) ->
 		let rec loop c tl =
 			if c == c2 then begin
-				unify_type_params a b tl tl2;
+				unify_type_params uctx a b tl tl2;
 				true
 			end else (match c.cl_super with
 				| None -> false
@@ -473,7 +477,7 @@ let rec unify a b =
 			| KTypeParameter pl -> List.exists (fun t ->
 				match follow t with
 				| TInst (cs,tls) -> loop cs (List.map (apply_params c.cl_params tl) tls)
-				| TAbstract(aa,tl) -> List.exists (unify_to aa tl b) aa.a_to
+				| TAbstract(aa,tl) -> List.exists (unify_to uctx aa tl b) aa.a_to
 				| _ -> false
 			) pl
 			| _ -> false)
@@ -484,10 +488,10 @@ let rec unify a b =
 		(try
 			(match follow r2 with
 			| TAbstract ({a_path=[],"Void"},_) -> incr i
-			| _ -> unify r1 r2; incr i);
+			| _ -> unify uctx r1 r2; incr i);
 			List.iter2 (fun (_,o1,t1) (_,o2,t2) ->
 				if o1 && not o2 then error [Cant_force_optional];
-				unify t1 t2;
+				unify uctx t1 t2;
 				incr i
 			) l2 l1 (* contravariance *)
 		with
@@ -527,7 +531,7 @@ let rec unify a b =
 					unify_new_monos.rec_stack <- !monos @ unify_new_monos.rec_stack;
 					rec_stack unify_stack (ft,f2.cf_type)
 						(fun (a2,b2) -> fast_eq b2 f2.cf_type && fast_eq_mono unify_new_monos.rec_stack ft a2)
-						(fun() -> try unify_with_access f1 ft f2 with e -> unify_new_monos.rec_stack <- old_monos; raise e)
+						(fun() -> try unify_with_access uctx f1 ft f2 with e -> unify_new_monos.rec_stack <- old_monos; raise e)
 						(fun l -> error (invalid_field n :: l));
 					unify_new_monos.rec_stack <- old_monos;
 				| Method MethNormal | Method MethInline | Var { v_write = AccNo } | Var { v_write = AccNever } ->
@@ -536,13 +540,13 @@ let rec unify a b =
 					unify_new_monos.rec_stack <- !monos @ unify_new_monos.rec_stack;
 					rec_stack unify_stack (f2.cf_type,ft)
 						(fun(a2,b2) -> fast_eq_mono unify_new_monos.rec_stack b2 ft && fast_eq f2.cf_type a2)
-						(fun() -> try unify_with_access f1 ft f2 with e -> unify_new_monos.rec_stack <- old_monos; raise e)
+						(fun() -> try unify_with_access uctx f1 ft f2 with e -> unify_new_monos.rec_stack <- old_monos; raise e)
 						(fun l -> error (invalid_field n :: l));
 					unify_new_monos.rec_stack <- old_monos;
 				| _ ->
 					(* will use fast_eq, which have its own stack *)
 					try
-						unify_with_access f1 ft f2
+						unify_with_access uctx f1 ft f2
 					with
 						Unify_error l ->
 							error (invalid_field n :: l));
@@ -580,14 +584,14 @@ let rec unify a b =
 		with
 			Unify_error l -> error (cannot_unify a b :: l))
 	| TAnon a1, TAnon a2 ->
-		unify_anons a b a1 a2
+		unify_anons uctx a b a1 a2
 	| TAnon an, TAbstract ({ a_path = [],"Class" },[pt]) ->
 		(match !(an.a_status) with
-		| Statics cl -> unify (TInst (cl,List.map (fun _ -> mk_mono()) cl.cl_params)) pt
+		| Statics cl -> unify uctx (TInst (cl,List.map (fun _ -> mk_mono()) cl.cl_params)) pt
 		| _ -> error [cannot_unify a b])
 	| TAnon an, TAbstract ({ a_path = [],"Enum" },[pt]) ->
 		(match !(an.a_status) with
-		| EnumStatics e -> unify (TEnum (e,List.map (fun _ -> mk_mono()) e.e_params)) pt
+		| EnumStatics e -> unify uctx (TEnum (e,List.map (fun _ -> mk_mono()) e.e_params)) pt
 		| _ -> error [cannot_unify a b])
 	| TEnum _, TAbstract ({ a_path = [],"EnumValue" },[]) ->
 		()
@@ -604,7 +608,7 @@ let rec unify a b =
 				| _ ->
 					let _,t,cf = class_field c tl "new" in
 					if not (has_class_field_flag cf CfPublic) then error [invalid_visibility "new"];
-					begin try unify t t1
+					begin try unify uctx t t1
 					with Unify_error l -> error (cannot_unify a b :: l) end
 			end
 		with Not_found ->
@@ -620,7 +624,7 @@ let rec unify a b =
 					type_eq EqRightDynamic t t2
 				with
 					Unify_error l -> error (cannot_unify a b :: l));
-		| TAbstract(bb,tl) when (List.exists (unify_from bb tl a b) bb.a_from) ->
+		| TAbstract(bb,tl) when (List.exists (unify_from uctx bb tl a b) bb.a_from) ->
 			()
 		| _ ->
 			error [cannot_unify a b])
@@ -648,26 +652,26 @@ let rec unify a b =
 				) an.a_fields
 			with Unify_error l ->
 				error (cannot_unify a b :: l))
-		| TAbstract(aa,tl) when (List.exists (unify_to aa tl b) aa.a_to) ->
+		| TAbstract(aa,tl) when (List.exists (unify_to uctx aa tl b) aa.a_to) ->
 			()
 		| _ ->
 			error [cannot_unify a b])
 	| TAbstract (aa,tl), _  ->
-		if not (List.exists (unify_to aa tl b) aa.a_to) then error [cannot_unify a b];
+		if not (List.exists (unify_to uctx aa tl b) aa.a_to) then error [cannot_unify a b];
 	| TInst ({ cl_kind = KTypeParameter ctl } as c,pl), TAbstract (bb,tl) ->
 		(* one of the constraints must satisfy the abstract *)
 		if not (List.exists (fun t ->
 			let t = apply_params c.cl_params pl t in
-			try unify t b; true with Unify_error _ -> false
-		) ctl) && not (List.exists (unify_from bb tl a b) bb.a_from) then error [cannot_unify a b];
+			try unify uctx t b; true with Unify_error _ -> false
+		) ctl) && not (List.exists (unify_from uctx bb tl a b) bb.a_from) then error [cannot_unify a b];
 	| _, TAbstract (bb,tl) ->
-		if not (List.exists (unify_from bb tl a b) bb.a_from) then error [cannot_unify a b]
+		if not (List.exists (unify_from uctx bb tl a b) bb.a_from) then error [cannot_unify a b]
 	| _ , _ ->
 		error [cannot_unify a b]
 
-and unify_abstracts a b a1 tl1 a2 tl2 =
-	let f1 = unify_to a1 tl1 b in
-		let f2 = unify_from a2 tl2 a b in
+and unify_abstracts uctx a b a1 tl1 a2 tl2 =
+	let f1 = unify_to uctx a1 tl1 b in
+		let f2 = unify_from uctx a2 tl2 a b in
 		if (List.exists (f1 ~allow_transitive_cast:false) a1.a_to)
 		|| (List.exists (f2 ~allow_transitive_cast:false) a2.a_from)
 		|| (((Meta.has Meta.CoreType a1.a_meta) || (Meta.has Meta.CoreType a2.a_meta))
@@ -676,7 +680,7 @@ and unify_abstracts a b a1 tl1 a2 tl2 =
 		else
 			error [cannot_unify a b]
 
-and unify_anons a b a1 a2 =
+and unify_anons uctx a b a1 a2 =
 	if would_produce_recursive_anon a1 a2 then error [cannot_unify a b];
 	(try
 		PMap.iter (fun n f2 ->
@@ -693,7 +697,7 @@ and unify_anons a b a1 a2 =
 					if fast_eq f1.cf_type f2.cf_type then f1.cf_type
 					else field_type f1
 				in
-				unify_with_access f1 f1_type f2;
+				unify_with_access uctx f1 f1_type f2;
 				(match !(a1.a_status) with
 				| Statics c when not (Meta.has Meta.MaybeUsed f1.cf_meta) -> f1.cf_meta <- (Meta.MaybeUsed,[],f1.cf_pos) :: f1.cf_meta
 				| _ -> ());
@@ -725,28 +729,28 @@ and unify_anons a b a1 a2 =
 	with
 		Unify_error l -> error (cannot_unify a b :: l))
 
-and unify_from ab tl a b ?(allow_transitive_cast=true) t =
+and unify_from uctx ab tl a b ?(allow_transitive_cast=true) t =
 	rec_stack_bool abstract_cast_stack (a,b)
 		(fun (a2,b2) -> fast_eq a a2 && fast_eq b b2)
 		(fun() ->
 			let t = apply_params ab.a_params tl t in
-			let unify_func = if allow_transitive_cast then unify else type_eq EqRightDynamic in
+			let unify_func = if allow_transitive_cast then unify uctx else type_eq EqRightDynamic in
 			unify_func a t)
 
-and unify_to ab tl b ?(allow_transitive_cast=true) t =
+and unify_to uctx ab tl b ?(allow_transitive_cast=true) t =
 	let t = apply_params ab.a_params tl t in
-	let unify_func = if allow_transitive_cast then unify else type_eq EqStrict in
+	let unify_func = if allow_transitive_cast then unify uctx else type_eq EqStrict in
 	try
 		unify_func t b;
 		true
 	with Unify_error _ ->
 		false
 
-and unify_from_field ab tl a b ?(allow_transitive_cast=true) (t,cf) =
+and unify_from_field uctx ab tl a b ?(allow_transitive_cast=true) (t,cf) =
 	rec_stack_bool abstract_cast_stack (a,b)
 		(fun (a2,b2) -> fast_eq a a2 && fast_eq b b2)
 		(fun() ->
-			let unify_func = if allow_transitive_cast then unify else type_eq EqStrict in
+			let unify_func = if allow_transitive_cast then unify uctx else type_eq EqStrict in
 			match follow cf.cf_type with
 			| TFun(_,r) ->
 				let monos = List.map (fun _ -> mk_mono()) cf.cf_params in
@@ -754,19 +758,19 @@ and unify_from_field ab tl a b ?(allow_transitive_cast=true) (t,cf) =
 				unify_func a (map t);
 				List.iter2 (fun m (name,t) -> match follow t with
 					| TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] ->
-						List.iter (fun tc -> match follow m with TMono _ -> raise (Unify_error []) | _ -> unify m (map tc) ) constr
+						List.iter (fun tc -> match follow m with TMono _ -> raise (Unify_error []) | _ -> unify uctx m (map tc) ) constr
 					| _ -> ()
 				) monos cf.cf_params;
 				unify_func (map r) b;
 				true
 			| _ -> die "" __LOC__)
 
-and unify_to_field ab tl b ?(allow_transitive_cast=true) (t,cf) =
+and unify_to_field uctx ab tl b ?(allow_transitive_cast=true) (t,cf) =
 	let a = TAbstract(ab,tl) in
 	rec_stack_bool abstract_cast_stack (b,a)
 		(fun (b2,a2) -> fast_eq a a2 && fast_eq b b2)
 		(fun() ->
-			let unify_func = if allow_transitive_cast then unify else type_eq EqStrict in
+			let unify_func = if allow_transitive_cast then unify uctx else type_eq EqStrict in
 			match follow cf.cf_type with
 			| TFun((_,_,ta) :: _,_) ->
 				let monos = List.map (fun _ -> mk_mono()) cf.cf_params in
@@ -774,17 +778,17 @@ and unify_to_field ab tl b ?(allow_transitive_cast=true) (t,cf) =
 				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 []); *)
-				with_variance (type_eq EqStrict) athis (map ta);
+				with_variance uctx (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 <> [] ->
-						List.iter (fun tc -> match follow m with TMono _ -> raise (Unify_error []) | _ -> unify m (map tc) ) constr
+						List.iter (fun tc -> match follow m with TMono _ -> raise (Unify_error []) | _ -> unify uctx m (map tc) ) constr
 					| _ -> ()
 				) monos cf.cf_params;
 				unify_func (map t) b;
 			| _ -> die "" __LOC__)
 
-and unify_with_variance f t1 t2 =
+and unify_with_variance uctx f t1 t2 =
 	let allows_variance_to t tf = type_iseq tf t in
 	match follow t1,follow t2 with
 	| TInst(c1,tl1),TInst(c2,tl2) when c1 == c2 ->
@@ -810,44 +814,47 @@ and unify_with_variance f t1 t2 =
 	| (TAnon a1 as t1), (TAnon a2 as t2) ->
 		rec_stack unify_stack (t1,t2)
 			(fun (a,b) -> fast_eq a t1 && fast_eq b t2)
-			(fun() -> unify_anons t1 t2 a1 a2)
+			(fun() -> unify_anons uctx t1 t2 a1 a2)
 			(fun l -> error l)
 	| _ ->
 		error [cannot_unify t1 t2]
 
-and unify_type_params a b tl1 tl2 =
+and unify_type_params uctx a b tl1 tl2 =
 	let i = ref 0 in
 	List.iter2 (fun t1 t2 ->
 		incr i;
 		try
-			with_variance (type_eq EqRightDynamic) t1 t2
+			with_variance uctx (type_eq EqRightDynamic) t1 t2
 		with Unify_error l ->
 			let err = cannot_unify a b in
 			error (err :: (Invariant_parameter !i) :: l)
 	) tl1 tl2
 
-and with_variance f t1 t2 =
+and with_variance uctx f t1 t2 =
 	try
 		f t1 t2
 	with Unify_error l -> try
-		unify_with_variance (with_variance f) t1 t2
+		unify_with_variance uctx (with_variance uctx f) t1 t2
 	with Unify_error _ ->
 		raise (Unify_error l)
 
-and unify_with_access f1 t1 f2 =
+and unify_with_access uctx f1 t1 f2 =
 	match f2.cf_kind with
 	(* write only *)
-	| Var { v_read = AccNo } | Var { v_read = AccNever } -> unify f2.cf_type t1
+	| Var { v_read = AccNo } | Var { v_read = AccNever } -> unify uctx f2.cf_type t1
 	(* read only *)
 	| Method MethNormal | Method MethInline | Var { v_write = AccNo } | Var { v_write = AccNever } ->
 		if (has_class_field_flag f1 CfFinal) <> (has_class_field_flag f2 CfFinal) then raise (Unify_error [FinalInvariance]);
-		unify t1 f2.cf_type
+		unify uctx t1 f2.cf_type
 	(* read/write *)
-	| _ -> with_variance (type_eq EqBothDynamic) t1 f2.cf_type
+	| _ -> with_variance uctx (type_eq EqBothDynamic) t1 f2.cf_type
 
 let does_unify a b =
 	try
-		unify a b;
+		unify default_unification_context a b;
 		true
 	with Unify_error _ ->
 		false
+
+let unify_custom = unify
+let unify = unify default_unification_context