Skip to content

Commit

Permalink
fixed infinite loop in unification (close HaxeFoundation#2315)
Browse files Browse the repository at this point in the history
  • Loading branch information
ncannasse committed Feb 19, 2015
1 parent c51a363 commit cd38ec7
Showing 1 changed file with 49 additions and 5 deletions.
54 changes: 49 additions & 5 deletions type.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1238,6 +1238,25 @@ let rec fast_eq a b =
| _ , _ ->
false

let rec fast_eq_mono ml a b =
if a == b then
true
else match a , b with
| TFun (l1,r1) , TFun (l2,r2) when List.length l1 = List.length l2 ->
List.for_all2 (fun (_,_,t1) (_,_,t2) -> fast_eq_mono ml t1 t2) l1 l2 && fast_eq_mono ml r1 r2
| TType (t1,l1), TType (t2,l2) ->
t1 == t2 && List.for_all2 (fast_eq_mono ml) l1 l2
| TEnum (e1,l1), TEnum (e2,l2) ->
e1 == e2 && List.for_all2 (fast_eq_mono ml) l1 l2
| TInst (c1,l1), TInst (c2,l2) ->
c1 == c2 && List.for_all2 (fast_eq_mono ml) l1 l2
| TAbstract (a1,l1), TAbstract (a2,l2) ->
a1 == a2 && List.for_all2 (fast_eq_mono ml) l1 l2
| TMono _, _ ->
List.memq a ml
| _ , _ ->
false

(* perform unification with subtyping.
the first type is always the most down in the class hierarchy
it's also the one that is pointed by the position.
Expand Down Expand Up @@ -1413,6 +1432,7 @@ let type_iseq a b =

let unify_stack = ref []
let abstract_cast_stack = ref []
let unify_new_monos = ref []

let rec unify a b =
if a == b then
Expand Down Expand Up @@ -1509,13 +1529,37 @@ let rec unify a b =
| _ -> ());
(try
PMap.iter (fun n f2 ->
let _, ft, f1 = (try class_field c tl n with Not_found -> error [has_no_field a n]) in
(*
introducing monomorphs while unifying might create infinite loops - see #2315
let's store these monomorphs and make sure we reach a fixed point
*)
let monos = ref [] in
let make_type f =
match f.cf_params with
| [] -> f.cf_type
| l ->
let ml = List.map (fun _ -> mk_mono()) l in
monos := ml;
apply_params f.cf_params ml f.cf_type
in
let _, ft, f1 = (try raw_class_field make_type c tl n with Not_found -> error [has_no_field a n]) in
let ft = apply_params c.cl_params tl ft in
if not (unify_kind f1.cf_kind f2.cf_kind) then error [invalid_kind n f1.cf_kind f2.cf_kind];
if f2.cf_public && not f1.cf_public then error [invalid_visibility n];
(try
unify_with_access (apply_params c.cl_params tl ft) f2
with
Unify_error l -> error (invalid_field n :: l));
let old_monos = !unify_new_monos in
unify_new_monos := !monos @ !unify_new_monos;
if not (List.exists (fun (a2,b2) -> fast_eq b2 f2.cf_type && fast_eq_mono !unify_new_monos ft a2) (!unify_stack)) then begin
unify_stack := (ft,f2.cf_type) :: !unify_stack;
(try
unify_with_access ft f2
with
Unify_error l ->
unify_new_monos := old_monos;
unify_stack := List.tl !unify_stack;
error (invalid_field n :: l));
unify_stack := List.tl !unify_stack;
end;
unify_new_monos := old_monos;
List.iter (fun f2o ->
if not (List.exists (fun f1o -> type_iseq f1o.cf_type f2o.cf_type) (f1 :: f1.cf_overloads))
then error [Missing_overload (f1, f2o.cf_type)]
Expand Down

0 comments on commit cd38ec7

Please sign in to comment.