2 * Copyright (c) 2014, Facebook, Inc.
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the "hack" directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
12 (*****************************************************************************)
13 (* Module used when we want to figure out what has changed.
14 * 1) The user modifies a file
15 * 2) We compute the type of the file (cf typing_redecl_service.ml)
16 * 3) We compare the old type and the new type of the class (or function)
17 * to see if anything has changed. This is where the code of this module
18 * comes into play. This code compares the old and the new class type
19 * and computes the set of dependencies if something needs to be
20 * either redeclared or checked again.
22 (*****************************************************************************)
27 module Env
= Typing_env
29 (*****************************************************************************)
30 (* Module comparing types "modulo" positions.
31 * It returns a substitution (from positions to position) and a true when
32 * both types are equivalent.
33 * Let's imagine we have ty1 ty2:
34 * 1) They are equivalent, and all the positions are the same
35 * CompareTypes.ty ty1 ty2 = [], true
36 * 2) They are equivalent, but a position differs:
37 * CompareTypes.ty ty1 ty2 = subst, true
38 * where (apply_subst subst ty1) = ty2
39 * 3) They are different:
40 * CompareTypes.ty ty1 ty2 = _, false
42 (*****************************************************************************)
43 module CompareTypes
= struct
45 type result
= (Pos.t
* Pos.t
) list
* bool
47 let default = [], false
49 let string_id (subst
, same
) (p1
, s1
) (p2
, s2
) =
52 else (p1
, p2
) :: subst
, same
54 let pos (subst
, same
as acc
) p1 p2
=
57 else (p1
, p2
) :: subst
, same
59 let reason acc r1 r2
=
60 let p1 = Typing_reason.to_pos r1
in
61 let p2 = Typing_reason.to_pos r2
in
64 let smap f acc smap1 smap2
=
66 SMap.fold
begin fun x ce1
acc ->
68 let ce2 = SMap.find_unsafe x smap2
in
70 with Not_found
-> default
73 (* Checking if all the members in smap2 are defined in smap1 *)
75 SMap.iter
(fun x _
-> ignore
(SMap.find_unsafe x smap1
)) smap2
;
77 with Not_found
-> default
79 let rec ty acc (r1
, x
) (r2
, y
) =
80 let acc = reason acc r1 r2
in
81 let acc = ty_
acc x y
in
84 and ty_
(subst
, same
as acc) ty1 ty2
=
88 | Tmixed
, Tmixed
-> acc
89 | Tarray
(b1
, ty1
, ty2
), Tarray
(b2
, ty3
, ty4
) ->
90 let same = same && b1
= b2
in
91 let acc = ty_opt
(subst
, same) ty1 ty3
in
92 let acc = ty_opt
acc ty2 ty4
in
94 | Tgeneric
(s1
, x
), Tgeneric
(s2
, y
) ->
95 let same = same && s1
= s2
in
96 let acc = ty_opt
(subst
, same) x y
in
98 | Toption ty1
, Toption ty2
->
100 | Tprim x
, Tprim y
->
104 | Tfun f1
, Tfun f2
->
106 | Tabstract
(sid1
, tyl1
, cstr1
), Tabstract
(sid2
, tyl2
, cstr2
) ->
107 let acc = ty_opt
acc cstr1 cstr2
in
108 let acc = string_id acc sid1 sid2
in
109 let acc = tyl
acc tyl1 tyl2
in
111 | Tapply
(sid1
, tyl1
), Tapply
(sid2
, tyl2
) ->
112 let acc = string_id acc sid1 sid2
in
113 let acc = tyl
acc tyl1 tyl2
in
115 | Tunresolved tyl1
, Tunresolved tyl2
116 | Ttuple tyl1
, Ttuple tyl2
->
118 | Tanon
(x1
, y1
, z1
), Tanon
(x2
, y2
, z2
) ->
119 subst
, same && x1
= x2
&& y1
= y2
&& z1
= z2
120 | Tshape fdm1
, Tshape fdm2
->
121 SMap.fold
begin fun name v1
acc ->
122 match SMap.get name fdm2
with
127 | (Tanon _
|Tany
|Tmixed
|Tarray
(_
, _
, _
)| Tshape _
|
128 Tgeneric
(_
, _
)|Toption _
|Tprim _
|Tvar _
| Tabstract _
|
129 Tfun _
|Tapply
(_
, _
)|Ttuple _
|Tunresolved _
|Tobject
), _
-> default
131 and tyl
acc tyl1 tyl2
=
132 if List.length tyl1
<> List.length tyl2
134 else List.fold_left2
ty acc tyl1 tyl2
136 and ty_opt
acc ty1 ty2
=
139 | Some ty1
, Some ty2
-> ty acc ty1 ty2
142 and fun_type
acc ft1 ft2
=
143 let acc = pos acc ft1
.ft_pos ft2
.ft_pos
in
144 let acc = tparam_list
acc ft1
.ft_tparams ft2
.ft_tparams
in
145 let acc = fun_params
acc ft1
.ft_params ft2
.ft_params
in
146 let subst, same = ty acc ft1
.ft_ret ft2
.ft_ret
in
149 ft1
.ft_unsafe
= ft2
.ft_unsafe
&&
150 ft1
.ft_abstract
= ft2
.ft_abstract
&&
151 ft1
.ft_arity_min
= ft2
.ft_arity_min
&&
152 ft1
.ft_arity_max
= ft2
.ft_arity_max
154 and fun_params
acc params1 params2
=
155 if List.length params1
<> List.length params2
157 else List.fold_left2 fun_param
acc params1 params2
159 and fun_param
acc (name1
, ty1
) (name2
, ty2
) =
164 and tparam_list
acc tpl1 tpl2
=
165 if List.length tpl1
<> List.length tpl2
167 else List.fold_left2 tparam
acc tpl1 tpl2
169 and tparam
acc (sid1
, x1
) (sid2
, x2
) =
170 let acc = string_id acc sid1 sid2
in
171 let acc = ty_opt
acc x1 x2
in
174 and class_elt
(subst, same) celt1 celt2
=
175 let same = same && celt1
.ce_visibility
= celt2
.ce_visibility
in
176 let same = same && celt1
.ce_final
= celt2
.ce_final
in
177 let same = same && celt1
.ce_override
= celt2
.ce_override
in
178 ty (subst, same) celt1
.ce_type celt2
.ce_type
180 and members
acc m1 m2
= smap class_elt
acc m1 m2
182 and constructor
acc c1 c2
=
184 | Some x1
, Some x2
-> class_elt
acc x1 x2
187 and implements
acc imp1 imp2
= smap ty acc imp1 imp2
189 and class_
(subst, same) c1 c2
=
191 c1
.tc_final
= c2
.tc_final
&&
192 c1
.tc_need_init
= c2
.tc_need_init
&&
193 c1
.tc_members_fully_known
= c2
.tc_members_fully_known
&&
194 c1
.tc_abstract
= c2
.tc_abstract
&&
195 c1
.tc_kind
= c2
.tc_kind
&&
196 c1
.tc_name
= c2
.tc_name
&&
197 SSet.compare c1
.tc_members_init c2
.tc_members_init
= 0 &&
198 SSet.compare c1
.tc_extends c2
.tc_extends
= 0 &&
199 SSet.compare c1
.tc_req_ancestors_extends c2
.tc_req_ancestors_extends
= 0 &&
200 SSet.compare c1
.tc_req_ancestors c2
.tc_req_ancestors
= 0
202 let acc = subst, same in
203 let acc = tparam_list
acc c1
.tc_tparams c2
.tc_tparams
in
204 let acc = members
acc c1
.tc_consts c2
.tc_consts
in
205 let acc = members
acc c1
.tc_cvars c2
.tc_cvars
in
206 let acc = members
acc c1
.tc_scvars c2
.tc_scvars
in
207 let acc = members
acc c1
.tc_methods c2
.tc_methods
in
208 let acc = members
acc c1
.tc_smethods c2
.tc_smethods
in
209 let acc = constructor
acc c1
.tc_construct c2
.tc_construct
in
210 let acc = implements
acc c1
.tc_ancestors c2
.tc_ancestors
in
211 let acc = implements
acc c1
.tc_ancestors_checked_when_concrete c2
.tc_ancestors_checked_when_concrete
in
216 (*****************************************************************************)
217 (* Functor traversing a type, but applies a user defined function for
220 (*****************************************************************************)
221 module TraversePos
(ImplementPos
: sig val pos: Pos.t
-> Pos.t
end) = struct
224 let pos = ImplementPos.pos
226 let rec reason = function
228 | Rwitness p
-> Rwitness
(pos p
)
229 | Ridx p
-> Ridx
(pos p
)
230 | Ridx_vector p
-> Ridx_vector
(pos p
)
231 | Rappend p
-> Rappend
(pos p
)
232 | Rfield p
-> Rfield
(pos p
)
233 | Rforeach p
-> Rforeach
(pos p
)
234 | Raccess p
-> Raccess
(pos p
)
235 | Rcall p
-> Rcall
(pos p
)
236 | Rarith p
-> Rarith
(pos p
)
237 | Rarith_ret p
-> Rarith_ret
(pos p
)
238 | Rstring2 p
-> Rstring2
(pos p
)
239 | Rcomp p
-> Rcomp
(pos p
)
240 | Rconcat p
-> Rconcat
(pos p
)
241 | Rconcat_ret p
-> Rconcat_ret
(pos p
)
242 | Rlogic p
-> Rlogic
(pos p
)
243 | Rlogic_ret p
-> Rlogic_ret
(pos p
)
244 | Rbitwise p
-> Rbitwise
(pos p
)
245 | Rbitwise_ret p
-> Rbitwise_ret
(pos p
)
246 | Rstmt p
-> Rstmt
(pos p
)
247 | Rno_return p
-> Rno_return
(pos p
)
248 | Rno_return_async p
-> Rno_return_async
(pos p
)
249 | Rhint p
-> Rhint
(pos p
)
250 | Rnull_check p
-> Rnull_check
(pos p
)
251 | Rnot_in_cstr p
-> Rnot_in_cstr
(pos p
)
252 | Rthrow p
-> Rthrow
(pos p
)
253 | Rattr p
-> Rattr
(pos p
)
254 | Rxhp p
-> Rxhp
(pos p
)
255 | Rret_div p
-> Rret_div
(pos p
)
256 | Rlost_info
(s
, r1
, p2) -> Rlost_info
(s
, reason r1
, pos p2)
257 | Rcoerced
(p1, p2, x
) -> Rcoerced
(pos p1, pos p2, x
)
258 | Rformat
(p1, s
, r
) -> Rformat
(pos p1, s
, reason r
)
259 | Rclass_class
(p
, s
) -> Rclass_class
(pos p
, s
)
260 | Runknown_class p
-> Runknown_class
(pos p
)
261 | Rdynamic_yield
(p1, p2, s1
, s2
) -> Rdynamic_yield
(pos p1, pos p2, s1
, s2
)
262 | Rmap_append p
-> Rmap_append
(pos p
)
264 let string_id (p
, x
) = pos p
, x
271 | Tvar _
-> raise
(Error
[Pos.none
, "internal error"])
274 | Tarray
(b
, ty1
, ty2
) -> Tarray
(b
, ty_opt ty1
, ty_opt ty2
)
276 | Tgeneric
(s
, t
) -> Tgeneric
(s
, ty_opt t
)
277 | Ttuple tyl
-> Ttuple
(List.map
(ty) tyl
)
278 | Tunresolved tyl
-> Tunresolved
(List.map
(ty) tyl
)
279 | Toption x
-> Toption
(ty x
)
280 | Tfun ft
-> Tfun
(fun_type ft
)
281 | Tapply
(sid
, xl
) -> Tapply
(string_id sid
, List.map
(ty) xl
)
282 | Tabstract
(sid
, xl
, x
) ->
283 Tabstract
(string_id sid
, List.map
(ty) xl
, ty_opt x
)
285 | Tshape fdm
-> Tshape
(SMap.map
ty fdm
)
287 and ty_opt
= function
289 | Some x
-> Some
(ty x
)
293 ft_tparams
= List.map
(type_param
) ft
.ft_tparams
;
294 ft_params
= List.map fun_param ft
.ft_params
;
295 ft_ret
= ty ft
.ft_ret
;
296 ft_pos
= pos ft
.ft_pos
;
299 and fun_param
(x
, y
) = x
, ty y
302 { ce_final
= ce
.ce_final
;
303 ce_override
= ce
.ce_override
;
304 ce_visibility
= ce
.ce_visibility
;
305 ce_type
= ty ce
.ce_type
;
306 ce_origin
= ce
.ce_origin
;
309 and type_param
(sid
, y
) =
310 string_id sid
, ty_opt y
313 { tc_final
= tc
.tc_final
;
314 tc_need_init
= tc
.tc_need_init
;
315 tc_members_init
= tc
.tc_members_init
;
316 tc_abstract
= tc
.tc_abstract
;
317 tc_members_fully_known
= tc
.tc_members_fully_known
;
318 tc_kind
= tc
.tc_kind
;
319 tc_name
= tc
.tc_name
;
320 tc_extends
= tc
.tc_extends
;
321 tc_req_ancestors
= tc
.tc_req_ancestors
;
322 tc_req_ancestors_extends
= tc
.tc_req_ancestors_extends
;
323 tc_tparams
= List.map type_param tc
.tc_tparams
;
324 tc_consts
= SMap.map class_elt tc
.tc_consts
;
325 tc_cvars
= SMap.map class_elt tc
.tc_cvars
;
326 tc_scvars
= SMap.map class_elt tc
.tc_scvars
;
327 tc_methods
= SMap.map class_elt tc
.tc_methods
;
328 tc_smethods
= SMap.map class_elt tc
.tc_smethods
;
329 tc_construct
= constructor tc
.tc_construct
;
330 tc_ancestors
= SMap.map
ty tc
.tc_ancestors
;
331 tc_ancestors_checked_when_concrete
= SMap.map
ty tc
.tc_ancestors_checked_when_concrete
;
332 tc_user_attributes
= tc
.tc_user_attributes
;
333 tc_prefetch_classes
= tc
.tc_prefetch_classes
;
334 tc_prefetch_funs
= tc
.tc_prefetch_funs
;
338 and constructor
= function
340 | Some c
-> Some
(class_elt c
)
342 and typedef
= function
343 | Typing_env.Typedef.Error
as x
-> x
344 | Typing_env.Typedef.Ok
(is_abstract
, tparams
, tcstr
, h
) ->
345 let tparams = List.map type_param
tparams in
346 let tcstr = ty_opt
tcstr in
347 let tdef = (is_abstract
, tparams, tcstr, ty h
) in
348 Typing_env.Typedef.Ok
tdef
351 (*****************************************************************************)
352 (* Applies a position substitution to a class type *)
353 (*****************************************************************************)
354 module SubstPos
= struct
355 let class_type subst c
=
356 let module IPos
= struct
358 try Hashtbl.find
subst x
with Not_found
-> x
360 let module Apply
= TraversePos
(IPos
) in
364 (*****************************************************************************)
365 (* Returns a signature with all the positions replaced with Pos.none *)
366 (*****************************************************************************)
367 module NormalizeSig
= struct
368 include TraversePos
(struct let pos _
= Pos.none
end)
371 (*****************************************************************************)
372 (* Given two classes give back the set of functions or classes that need
375 (*****************************************************************************)
376 module ClassDiff
= struct
387 let smap_left s1 s2
=
388 SMap.fold
begin fun x ty1 diff
->
389 let ty2 = SMap.get x s2
in
392 if ty1
= ty2 then diff
else
399 SSet.union
(smap_left s1 s2
) (smap_left s2 s1
)
401 let add_inverted_dep build_obj x
acc =
402 ISet.union
(Typing_deps.get_ideps
(build_obj x
)) acc
404 let add_inverted_deps acc build_obj xset
=
405 SSet.fold
(add_inverted_dep build_obj
) xset
acc
407 let compare cid class1 class2
=
408 let acc = ISet.empty
in
409 let is_unchanged = true in
411 (* compare class constants *)
412 let consts_diff = smap class1
.tc_consts class2
.tc_consts
in
413 let is_unchanged = is_unchanged && SSet.is_empty
consts_diff in
414 let acc = add_inverted_deps acc (fun x
-> Dep.Const
(cid
, x
)) consts_diff in
416 (* compare class members *)
417 let cvars_diff = smap class1
.tc_cvars class2
.tc_cvars
in
418 let is_unchanged = is_unchanged && SSet.is_empty
cvars_diff in
419 let acc = add_inverted_deps acc (fun x
-> Dep.CVar
(cid
, x
)) cvars_diff in
421 (* compare class static members *)
422 let scvars_diff = smap class1
.tc_scvars class2
.tc_scvars
in
423 let is_unchanged = is_unchanged && SSet.is_empty
scvars_diff in
424 let acc = add_inverted_deps acc (fun x
-> Dep.SCVar
(cid
, x
)) scvars_diff in
426 (* compare class methods *)
427 let methods_diff = smap class1
.tc_methods class2
.tc_methods
in
428 let is_unchanged = is_unchanged && SSet.is_empty
methods_diff in
429 let acc = add_inverted_deps acc (fun x
-> Dep.Method
(cid
, x
)) methods_diff in
431 (* compare class static methods *)
432 let smethods_diff = smap class1
.tc_smethods class2
.tc_smethods
in
433 let is_unchanged = is_unchanged && SSet.is_empty
smethods_diff in
434 let acc = add_inverted_deps acc (fun x
-> Dep.SMethod
(cid
, x
)) smethods_diff in
436 (* compare class constructors *)
437 let cstr_diff = class1
.tc_construct
<> class2
.tc_construct
in
438 let is_unchanged = is_unchanged && not
cstr_diff in
439 let cstr_ideps = Typing_deps.get_ideps
(Dep.Cstr cid
) in
440 let acc = if cstr_diff then ISet.union
acc cstr_ideps else acc in
446 (*****************************************************************************)
447 (* Determines if there is a "big" difference between two classes
448 * What it really means: most of the time, a change in a class doesn't affect
449 * the users of the class, recomputing the sub-classes is enough.
450 * However, there are some cases, where we really need to re-check all the
451 * use cases of a class. For example: if a class doesn't implement an
452 * interface anymore, all the subtyping is changed, so we have to recheck
453 * all the places where the class was used.
455 (*****************************************************************************)
456 let class_big_diff class1 class2
=
457 let class1 = NormalizeSig.class_type class1 in
458 let class2 = NormalizeSig.class_type class2 in
459 class1.tc_need_init
<> class2.tc_need_init
||
460 SSet.compare class1.tc_members_init
class2.tc_members_init
<> 0 ||
461 class1.tc_members_fully_known
<> class2.tc_members_fully_known
||
462 class1.tc_kind
<> class2.tc_kind
||
463 class1.tc_tparams
<> class2.tc_tparams
||
464 SMap.compare class1.tc_ancestors
class2.tc_ancestors
<> 0 ||
465 SMap.compare class1.tc_ancestors_checked_when_concrete
class2.tc_ancestors_checked_when_concrete
<> 0 ||
466 SSet.compare class1.tc_req_ancestors
class2.tc_req_ancestors
<> 0 ||
467 SSet.compare class1.tc_req_ancestors_extends
class2.tc_req_ancestors_extends
<> 0 ||
468 SSet.compare class1.tc_extends
class2.tc_extends
<> 0
470 (*****************************************************************************)
471 (* Given a class name adds all the subclasses, we need a "trace" to follow
472 * what we have already added.
474 (*****************************************************************************)
475 let rec get_extend_deps trace cid_hash to_redecl
=
476 if ISet.mem cid_hash
!trace
479 trace
:= ISet.add cid_hash
!trace
;
480 let cid_hash = Typing_deps.Dep.extends_of_class
cid_hash in
481 let ideps = Typing_deps.get_ideps_from_hash
cid_hash in
482 ISet.fold
begin fun obj
acc ->
483 if Typing_deps.Dep.is_class obj
485 let to_redecl = ISet.add obj
acc in
486 get_extend_deps trace obj
to_redecl
491 (*****************************************************************************)
492 (* GET EVERYTHING, don't think, don't try to be subtle, don't try to be
493 * smart what so ever, just get EVERYTHING that ever used the class "cid"
494 * (cid = class identifier).
495 * Hence the name "get_bazooka".
497 (*****************************************************************************)
498 and get_all_dependencies trace cid
(to_redecl, to_recheck
) =
499 let bazooka = Typing_deps.get_bazooka
(Dep.Class cid
) in
500 let to_redecl = ISet.union
bazooka to_redecl in
501 let to_recheck = ISet.union
bazooka to_recheck in
502 let cid_hash = Typing_deps.Dep.make
(Dep.Class cid
) in
503 let to_redecl = get_extend_deps trace
cid_hash to_redecl in
504 to_redecl, to_recheck
506 (*****************************************************************************)
507 (* Determine which functions/classes have to be rechecked after comparing
508 * the old and the new type signature of "fid" (function identifier).
510 (*****************************************************************************)
511 let get_fun_deps old_funs fid
(to_redecl, to_recheck) =
512 match SMap.find_unsafe fid old_funs
, Env.Funs.get fid
with
514 to_redecl, to_recheck
515 | None
, _
| _
, None
->
516 let where_fun_is_used = Typing_deps.get_bazooka
(Dep.Fun fid
) in
517 let to_recheck = ISet.union
where_fun_is_used to_recheck in
518 let fun_name = Typing_deps.get_bazooka
(Dep.FunName fid
) in
519 ISet.union
fun_name to_redecl, ISet.union
fun_name to_recheck
520 | Some fty1
, Some fty2
->
521 let fty1 = NormalizeSig.fun_type
fty1 in
522 let fty2 = NormalizeSig.fun_type
fty2 in
523 let is_same_signature = fty1 = fty2 in
525 then to_redecl, to_recheck
527 (* No need to add Dep.FunName stuff here -- we found a function with the
528 * right name already otherwise we'd be in the None case above. *)
529 let where_fun_is_used = Typing_deps.get_bazooka
(Dep.Fun fid
) in
530 to_redecl, ISet.union
where_fun_is_used to_recheck
532 let get_funs_deps old_funs funs
=
533 SSet.fold
(get_fun_deps old_funs
) funs
(ISet.empty
, ISet.empty
)
535 (*****************************************************************************)
536 (* Determine which functions/classes have to be rechecked after comparing
537 * the old and the new typedef
539 (*****************************************************************************)
540 let get_type_deps old_types tid
to_recheck =
541 match SMap.find_unsafe tid old_types
, Env.Typedefs.get tid
with
544 | None
, _
| _
, None
->
545 let bazooka = Typing_deps.get_bazooka
(Dep.Class tid
) in
546 ISet.union
bazooka to_recheck
547 | Some tdef1
, Some tdef2
->
548 let tdef1 = NormalizeSig.typedef
tdef1 in
549 let tdef2 = NormalizeSig.typedef
tdef2 in
550 let is_same_signature = tdef1 = tdef2 in
554 let where_type_is_used = Typing_deps.get_ideps
(Dep.Class tid
) in
555 let to_recheck = ISet.union
where_type_is_used to_recheck in
558 let get_types_deps old_types types
=
559 SSet.fold
(get_type_deps old_types
) types
ISet.empty
561 (*****************************************************************************)
562 (* Determine which top level definitions have to be rechecked if the constant
565 (*****************************************************************************)
566 let get_gconst_deps old_gconsts cst_id
(to_redecl, to_recheck) =
567 match SMap.find_unsafe cst_id old_gconsts
, Env.GConsts.get cst_id
with
569 to_redecl, to_recheck
570 | None
, _
| _
, None
->
571 let where_const_is_used = Typing_deps.get_bazooka
(Dep.GConst cst_id
) in
572 let to_recheck = ISet.union
where_const_is_used to_recheck in
573 let const_name = Typing_deps.get_bazooka
(Dep.GConstName cst_id
) in
574 ISet.union
const_name to_redecl, ISet.union
const_name to_recheck
575 | Some cst1
, Some cst2
->
576 let is_same_signature = cst1
= cst2
in
578 then to_redecl, to_recheck
580 let where_type_is_used = Typing_deps.get_ideps
(Dep.GConst cst_id
) in
581 let to_recheck = ISet.union
where_type_is_used to_recheck in
582 to_redecl, to_recheck
584 let get_gconsts_deps old_gconsts gconsts
=
585 SSet.fold
(get_gconst_deps old_gconsts
) gconsts
(ISet.empty
, ISet.empty
)
587 (*****************************************************************************)
588 (* Determine which functions/classes have to be rechecked after comparing
589 * the old and the new type signature of "cid" (class identifier).
591 (*****************************************************************************)
592 let get_class_deps old_classes new_classes trace cid
(to_redecl, to_recheck) =
593 match SMap.find_unsafe cid old_classes
, SMap.find_unsafe cid new_classes
with
594 | None
, None
-> to_redecl, to_recheck
595 | None
, _
| _
, None
->
596 get_all_dependencies trace cid
(to_redecl, to_recheck)
597 | Some
class1, Some
class2 when class_big_diff class1 class2 ->
598 get_all_dependencies trace cid
(to_redecl, to_recheck)
599 | Some
class1, Some
class2 ->
600 let nclass1 = NormalizeSig.class_type class1 in
601 let nclass2 = NormalizeSig.class_type class2 in
602 let deps, is_unchanged = ClassDiff.compare cid
nclass1 nclass2 in
603 let cid_hash = Typing_deps.Dep.make
(Dep.Class cid
) in
606 let _, is_unchanged = ClassDiff.compare cid
class1 class2 in
608 then to_redecl, to_recheck
610 (* If we reach this case it means that class1 and class2
611 * have the same signatures, but that some of their
612 * positions differ. We therefore must redeclare the sub-classes
613 * but not recheck them.
615 let to_redecl = get_extend_deps trace
cid_hash to_redecl in
616 to_redecl, to_recheck
618 let to_redecl = get_extend_deps trace
cid_hash to_redecl in
619 let to_recheck = ISet.union
to_redecl to_recheck in
620 ISet.union
deps to_redecl, ISet.union
deps to_recheck
622 let get_classes_deps old_classes new_classes trace classes
=
624 (get_class_deps old_classes new_classes trace
)
626 (ISet.empty
, ISet.empty
)
628 (*****************************************************************************)
629 (* When the type of a class didn't change, returns a substitution from
630 * the positions in the old type to the positions in the new ones.
631 * The idea is applying this substitution is enough to compute the new type
632 * of all the subclasses. No need to fully redeclare all of them.
634 (*****************************************************************************)
635 let get_classes_psubst old_classes new_classes classes
=
636 let subst = Hashtbl.create
23 in
637 let is_empty = ref true in
638 SSet.iter
begin fun cid
->
639 match SMap.find_unsafe cid old_classes
, SMap.find_unsafe cid new_classes
with
640 | Some
class1, Some
class2 ->
641 let subst_list, same = CompareTypes.class_
([], true) class1 class2 in
643 List.iter
begin fun (pos1
, pos2
) ->
645 Hashtbl.add
subst pos1 pos2