Remove unnecessary condition types
[hiphop-php.git] / hphp / hack / src / decl / decl_redecl_service.ml
blob937cf238c34f54acf5138b261ee62e47cca4a25b
1 (*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
8 *)
10 (*****************************************************************************)
11 (* On the fly type-declaration are called when the user modified a file
12 * we are not at initilalization time anymore. Therefore, we have a bit more
13 * work to do. We need calculate what must be re-checked.
15 (*****************************************************************************)
16 open Hh_prelude
17 open Reordered_argument_collections
18 open Typing_deps
20 type get_classes_in_file = Relative_path.t -> SSet.t
22 type redo_type_decl_result = {
23 errors: Errors.t;
24 changed: DepSet.t;
25 to_redecl: DepSet.t;
26 to_recheck: DepSet.t;
27 old_decl_missing_count: int;
30 let lvl = Hh_logger.Level.Debug
32 let shallow_decl_enabled (ctx : Provider_context.t) =
33 TypecheckerOptions.shallow_class_decl (Provider_context.get_tcopt ctx)
35 let force_shallow_decl_fanout_enabled (ctx : Provider_context.t) =
36 TypecheckerOptions.force_shallow_decl_fanout (Provider_context.get_tcopt ctx)
38 (*****************************************************************************)
39 (* The neutral element of declaration (cf procs/multiWorker.mli) *)
40 (*****************************************************************************)
41 let on_the_fly_neutral = Errors.empty
43 let compute_deps_neutral () =
44 let empty = DepSet.make () in
45 ((empty, empty, empty), 0)
47 (*****************************************************************************)
48 (* This is the place where we are going to put everything necessary for
49 * the redeclaration. We could "pass" the values directly to the workers,
50 * but it gives too much work to the master and slows things down,
51 * so what we do instead is pass the data through shared memory via
52 * OnTheFlyStore.
53 * I tried replicating the data to speed things up but it had no effect.
55 (*****************************************************************************)
57 module OnTheFlyStore = GlobalStorage.Make (struct
58 type t = Naming_table.fast
59 end)
61 (*****************************************************************************)
62 (* Re-declaring the types in a file *)
63 (*****************************************************************************)
65 let on_the_fly_decl_file ctx errors fn =
66 let (decl_errors, ()) =
67 Errors.do_with_context fn Errors.Decl (fun () ->
68 Decl.make_env ~sh:SharedMem.Uses ctx fn)
70 Errors.merge decl_errors errors
72 (*****************************************************************************)
73 (* Given a set of classes, compare the old and the new type and deduce
74 * what must be rechecked accordingly.
76 (*****************************************************************************)
78 let compute_classes_deps ctx old_classes new_classes acc classes =
79 let (changed, to_redecl, to_recheck) = acc in
80 let ((rc, rdd, rdc), old_classes_missing) =
81 Decl_compare.get_classes_deps ~ctx old_classes new_classes classes
83 let changed = DepSet.union rc changed in
84 let to_redecl = DepSet.union rdd to_redecl in
85 let to_recheck = DepSet.union rdc to_recheck in
86 ((changed, to_redecl, to_recheck), old_classes_missing)
88 (*****************************************************************************)
89 (* Given a set of functions, compare the old and the new type and deduce
90 * what must be rechecked accordingly.
92 (*****************************************************************************)
94 let compute_funs_deps ctx old_funs (changed, to_redecl, to_recheck) funs =
95 let ((rc, rdd, rdc), old_funs_missing) =
96 Decl_compare.get_funs_deps ~ctx old_funs funs
98 let changed = DepSet.union rc changed in
99 let to_redecl = DepSet.union rdd to_redecl in
100 let to_recheck = DepSet.union rdc to_recheck in
101 ((changed, to_redecl, to_recheck), old_funs_missing)
103 (*****************************************************************************)
104 (* Given a set of typedefs, compare the old and the new type and deduce
105 * what must be rechecked accordingly.
107 (*****************************************************************************)
109 let compute_types_deps ctx old_types (changed, to_redecl, to_recheck) types =
110 let ((rc, rdc), old_types_missing) =
111 Decl_compare.get_types_deps ~ctx old_types types
113 let changed = DepSet.union rc changed in
114 let to_recheck = DepSet.union rdc to_recheck in
115 ((changed, to_redecl, to_recheck), old_types_missing)
117 (*****************************************************************************)
118 (* Given a set of global constants, compare the old and the new type and
119 * deduce what must be rechecked accordingly.
121 (*****************************************************************************)
123 let compute_gconsts_deps
124 ctx old_gconsts (changed, to_redecl, to_recheck) gconsts =
125 let ((rc, rdd, rdc), old_gconsts_missing) =
126 Decl_compare.get_gconsts_deps ~ctx old_gconsts gconsts
128 let changed = DepSet.union rc changed in
129 let to_redecl = DepSet.union rdd to_redecl in
130 let to_recheck = DepSet.union rdc to_recheck in
131 ((changed, to_redecl, to_recheck), old_gconsts_missing)
133 (*****************************************************************************)
134 (* Redeclares a list of files
135 * And then computes the files that must be redeclared/rechecked by looking
136 * at what changed in the signatures of the classes/functions.
138 (*****************************************************************************)
140 let redeclare_files ctx filel =
141 let errors =
142 List.fold_left filel ~f:(on_the_fly_decl_file ctx) ~init:Errors.empty
144 (List.length filel, errors)
146 let on_the_fly_decl_files filel =
147 SharedMem.invalidate_local_caches ();
149 (* Redeclaring the files *)
150 redeclare_files filel
152 let compute_deps ctx fast (filel : Relative_path.t list) =
153 let infol = List.map filel ~f:(fun fn -> Relative_path.Map.find fast fn) in
154 let names =
155 List.fold_left infol ~f:FileInfo.merge_names ~init:FileInfo.empty_names
157 let { FileInfo.n_classes; n_funs; n_types; n_consts } = names in
158 let empty = DepSet.make () in
159 let acc = (empty, empty, empty) in
160 (* Fetching everything at once is faster *)
161 let old_funs = Decl_heap.Funs.get_old_batch n_funs in
162 let (acc, old_funs_missing) = compute_funs_deps ctx old_funs acc n_funs in
163 let old_types = Decl_heap.Typedefs.get_old_batch n_types in
164 let (acc, old_types_missing) = compute_types_deps ctx old_types acc n_types in
165 let old_consts = Decl_heap.GConsts.get_old_batch n_consts in
166 let (acc, old_gconsts_missing) =
167 compute_gconsts_deps ctx old_consts acc n_consts
170 let (acc, old_classes_missing) =
171 if shallow_decl_enabled ctx || force_shallow_decl_fanout_enabled ctx then
172 (acc, 0)
173 else
174 let old_classes = Decl_heap.Classes.get_old_batch n_classes in
175 let new_classes = Decl_heap.Classes.get_batch n_classes in
176 compute_classes_deps ctx old_classes new_classes acc n_classes
179 let old_decl_missing_count =
180 old_funs_missing
181 + old_types_missing
182 + old_gconsts_missing
183 + old_classes_missing
185 let (changed, to_redecl, to_recheck) = acc in
186 ((changed, to_redecl, to_recheck), old_decl_missing_count)
188 (*****************************************************************************)
189 (* Load the environment and then redeclare *)
190 (*****************************************************************************)
192 let load_and_on_the_fly_decl_files ctx _ filel =
193 try on_the_fly_decl_files ctx filel with
194 | e ->
195 Printf.printf "Error: %s\n" (Exn.to_string e);
196 Out_channel.flush stdout;
197 raise e
199 let load_and_compute_deps ctx _acc (filel : Relative_path.t list) :
200 (DepSet.t * DepSet.t * DepSet.t * int) * int =
202 let fast = OnTheFlyStore.load () in
203 let ((changed, to_redecl, to_recheck), old_decl_missing_count) =
204 compute_deps ctx fast filel
206 ((changed, to_redecl, to_recheck, List.length filel), old_decl_missing_count)
207 with
208 | e ->
209 Printf.printf "Error: %s\n" (Exn.to_string e);
210 Out_channel.flush stdout;
211 raise e
213 (*****************************************************************************)
214 (* Merges the results coming back from the different workers *)
215 (*****************************************************************************)
217 let merge_on_the_fly
218 files_initial_count files_declared_count (count, errorl1) errorl2 =
219 files_declared_count := !files_declared_count + count;
220 ServerProgress.send_percentage_progress
221 ~operation:"declaring"
222 ~done_count:!files_declared_count
223 ~total_count:files_initial_count
224 ~unit:"files"
225 ~extra:None;
227 Errors.merge errorl1 errorl2
229 let merge_compute_deps
230 files_initial_count
231 files_computed_count
232 ( (changed1, to_redecl1, to_recheck1, computed_count),
233 old_decl_missing_count1 )
234 ((changed2, to_redecl2, to_recheck2), old_decl_missing_count2) =
235 files_computed_count := !files_computed_count + computed_count;
237 let (changed, to_redecl, to_recheck) =
238 ( DepSet.union changed1 changed2,
239 DepSet.union to_redecl1 to_redecl2,
240 DepSet.union to_recheck1 to_recheck2 )
243 ServerProgress.send_percentage_progress
244 ~operation:"computing dependencies of"
245 ~done_count:!files_computed_count
246 ~total_count:files_initial_count
247 ~unit:"files"
248 ~extra:None;
250 ( (changed, to_redecl, to_recheck),
251 old_decl_missing_count1 + old_decl_missing_count2 )
253 (*****************************************************************************)
254 (* The parallel worker *)
255 (*****************************************************************************)
256 let parallel_on_the_fly_decl
257 (ctx : Provider_context.t)
258 (workers : MultiWorker.worker list option)
259 (bucket_size : int)
260 (fast : FileInfo.names Relative_path.Map.t)
261 (fnl : Relative_path.t list) :
262 (Errors.t * DepSet.t * DepSet.t * DepSet.t) * int =
264 OnTheFlyStore.store fast;
265 let files_initial_count = List.length fnl in
266 let files_declared_count = ref 0 in
267 let t = Unix.gettimeofday () in
268 Hh_logger.log ~lvl "Declaring on-the-fly %d files" files_initial_count;
269 ServerProgress.send_percentage_progress
270 ~operation:"declaring"
271 ~done_count:!files_declared_count
272 ~total_count:files_initial_count
273 ~unit:"files"
274 ~extra:None;
275 let errors =
276 MultiWorker.call
277 workers
278 ~job:(load_and_on_the_fly_decl_files ctx)
279 ~neutral:on_the_fly_neutral
280 ~merge:(merge_on_the_fly files_initial_count files_declared_count)
281 ~next:(MultiWorker.next ~max_size:bucket_size workers fnl)
283 let t = Hh_logger.log_duration ~lvl "Finished declaring on-the-fly" t in
284 Hh_logger.log ~lvl "Computing dependencies of %d files" files_initial_count;
285 let files_computed_count = ref 0 in
286 ServerProgress.send_percentage_progress
287 ~operation:"computing dependencies of"
288 ~done_count:!files_computed_count
289 ~total_count:files_initial_count
290 ~unit:"files"
291 ~extra:None;
292 let ((changed, to_redecl, to_recheck), old_decl_missing_count) =
293 MultiWorker.call
294 workers
295 ~job:(load_and_compute_deps ctx)
296 ~neutral:(compute_deps_neutral ())
297 ~merge:(merge_compute_deps files_initial_count files_computed_count)
298 ~next:(MultiWorker.next ~max_size:bucket_size workers fnl)
300 let (_t : float) =
301 Hh_logger.log_duration ~lvl "Finished computing dependencies" t
303 OnTheFlyStore.clear ();
304 ((errors, changed, to_redecl, to_recheck), old_decl_missing_count)
305 with
306 | e ->
307 if SharedMem.SMTelemetry.is_heap_overflow () then
308 Exit.exit Exit_status.Redecl_heap_overflow
309 else
310 raise e
312 (*****************************************************************************)
313 (* Code invalidating the heap *)
314 (*****************************************************************************)
315 let oldify_defs
316 (ctx : Provider_context.t)
317 { FileInfo.n_funs; n_classes; n_types; n_consts }
318 (elems : Decl_class_elements.t SMap.t)
319 ~(collect_garbage : bool) : unit =
320 Decl_heap.Funs.oldify_batch n_funs;
321 Decl_class_elements.oldify_all elems;
322 Decl_heap.Classes.oldify_batch n_classes;
323 Shallow_classes_provider.oldify_batch ctx n_classes;
324 Decl_heap.Typedefs.oldify_batch n_types;
325 Decl_heap.GConsts.oldify_batch n_consts;
326 if collect_garbage then SharedMem.GC.collect `gentle;
329 let remove_old_defs
330 (ctx : Provider_context.t)
331 { FileInfo.n_funs; n_classes; n_types; n_consts }
332 (elems : Decl_class_elements.t SMap.t) : unit =
333 Decl_heap.Funs.remove_old_batch n_funs;
334 Decl_class_elements.remove_old_all elems;
335 Decl_heap.Classes.remove_old_batch n_classes;
336 Shallow_classes_provider.remove_old_batch ctx n_classes;
337 Decl_heap.Typedefs.remove_old_batch n_types;
338 Decl_heap.GConsts.remove_old_batch n_consts;
339 SharedMem.GC.collect `gentle;
342 let remove_defs
343 (ctx : Provider_context.t)
344 { FileInfo.n_funs; n_classes; n_types; n_consts }
345 (elems : Decl_class_elements.t SMap.t)
346 ~(collect_garbage : bool) : unit =
347 Decl_heap.Funs.remove_batch n_funs;
348 Decl_class_elements.remove_all elems;
349 Decl_heap.Classes.remove_batch n_classes;
350 Shallow_classes_provider.remove_batch ctx n_classes;
351 Linearization_provider.remove_batch ctx n_classes;
352 Decl_heap.Typedefs.remove_batch n_types;
353 Decl_heap.GConsts.remove_batch n_consts;
354 if collect_garbage then SharedMem.GC.collect `gentle;
357 let is_dependent_class_of_any ctx classes (c : string) : bool =
358 if SSet.mem classes c then
359 true
360 else if shallow_decl_enabled ctx then
361 true
362 else
363 match Decl_heap.Classes.get c with
364 | None -> false
365 (* it might be a dependent class, but we are only doing this
366 * check for the purpose of invalidating things from the heap
367 * - if it's already not there, then we don't care. *)
368 | Some c ->
369 let intersection_nonempty s1 s2 = SSet.exists s1 ~f:(SSet.mem s2) in
370 SMap.exists c.Decl_defs.dc_ancestors ~f:(fun c _ -> SSet.mem classes c)
371 || intersection_nonempty c.Decl_defs.dc_extends classes
372 || intersection_nonempty c.Decl_defs.dc_xhp_attr_deps classes
373 || intersection_nonempty c.Decl_defs.dc_req_ancestors_extends classes
375 let get_maybe_dependent_classes
376 (get_classes : Relative_path.t -> SSet.t)
377 (classes : SSet.t)
378 (files : Relative_path.Set.t) : string list =
379 Relative_path.Set.fold files ~init:classes ~f:(fun x acc ->
380 SSet.union acc @@ get_classes x)
381 |> SSet.elements
383 let get_dependent_classes_files (ctx : Provider_context.t) (classes : SSet.t) :
384 Relative_path.Set.t =
385 let mode = Provider_context.get_deps_mode ctx in
386 let visited = VisitedSet.make () in
387 SSet.fold
388 classes
389 ~init:Typing_deps.(DepSet.make ())
390 ~f:(fun c acc ->
391 let source_class = Dep.make (Dep.Type c) in
392 Typing_deps.get_extend_deps ~mode ~visited ~source_class ~acc)
393 |> Naming_provider.get_files ctx
395 let filter_dependent_classes
396 (ctx : Provider_context.t)
397 (classes : SSet.t)
398 (maybe_dependent_classes : string list) : string list =
399 List.filter maybe_dependent_classes ~f:(is_dependent_class_of_any ctx classes)
401 module ClassSetStore = GlobalStorage.Make (struct
402 type t = SSet.t
403 end)
405 let load_and_filter_dependent_classes
406 (ctx : Provider_context.t) (maybe_dependent_classes : string list) :
407 string list * int =
408 let classes = ClassSetStore.load () in
409 ( filter_dependent_classes ctx classes maybe_dependent_classes,
410 List.length maybe_dependent_classes )
412 let merge_dependent_classes
413 classes_initial_count
414 classes_filtered_count
415 (dependent_classes, filtered)
416 acc =
417 classes_filtered_count := !classes_filtered_count + filtered;
418 ServerProgress.send_percentage_progress
419 ~operation:"filtering"
420 ~done_count:!classes_filtered_count
421 ~total_count:classes_initial_count
422 ~unit:"classes"
423 ~extra:None;
424 dependent_classes @ acc
426 let filter_dependent_classes_parallel
427 (ctx : Provider_context.t)
428 (workers : MultiWorker.worker list option)
429 ~(bucket_size : int)
430 (classes : SSet.t)
431 (maybe_dependent_classes : string list) : string list =
432 if List.length maybe_dependent_classes < 10 then
433 filter_dependent_classes ctx classes maybe_dependent_classes
434 else (
435 ClassSetStore.store classes;
436 let classes_initial_count = List.length maybe_dependent_classes in
437 let classes_filtered_count = ref 0 in
438 let t = Unix.gettimeofday () in
439 Hh_logger.log ~lvl "Filtering %d dependent classes" classes_initial_count;
440 ServerProgress.send_percentage_progress
441 ~operation:"filtering"
442 ~done_count:!classes_filtered_count
443 ~total_count:classes_initial_count
444 ~unit:"classes"
445 ~extra:None;
446 let res =
447 MultiWorker.call
448 workers
449 ~job:(fun _ c -> load_and_filter_dependent_classes ctx c)
450 ~merge:
451 (merge_dependent_classes classes_initial_count classes_filtered_count)
452 ~neutral:[]
453 ~next:
454 (MultiWorker.next
455 ~max_size:bucket_size
456 workers
457 maybe_dependent_classes)
459 let (_t : float) =
460 Hh_logger.log_duration ~lvl "Finished filtering dependent classes" t
462 ClassSetStore.clear ();
466 let get_dependent_classes
467 (ctx : Provider_context.t)
468 (workers : MultiWorker.worker list option)
469 ~(bucket_size : int)
470 (get_classes : Relative_path.t -> SSet.t)
471 (classes : SSet.t) : SSet.t =
472 get_dependent_classes_files ctx classes
473 |> get_maybe_dependent_classes get_classes classes
474 |> filter_dependent_classes_parallel ctx workers ~bucket_size classes
475 |> SSet.of_list
477 let merge_elements
478 classes_initial_count classes_processed_count (elements, count) acc =
479 classes_processed_count := !classes_processed_count + count;
481 let acc = SMap.union elements acc in
482 ServerProgress.send_percentage_progress
483 ~operation:"getting members of"
484 ~done_count:!classes_processed_count
485 ~total_count:classes_initial_count
486 ~unit:"classes"
487 ~extra:(Some (Printf.sprintf "%d elements" (SMap.cardinal acc)));
491 * Get the [Decl_class_elements.t]s corresponding to the classes contained in
492 * [defs]. *)
493 let get_elems
494 (ctx : Provider_context.t)
495 (workers : MultiWorker.worker list option)
496 ~(bucket_size : int)
497 ~(old : bool)
498 (defs : FileInfo.names) : Decl_class_elements.t SMap.t =
499 if shallow_decl_enabled ctx then
500 SMap.empty
501 else
502 let classes = SSet.elements defs.FileInfo.n_classes in
503 (* Getting the members of a class requires fetching the class from the heap.
504 * Doing this for too many classes will cause a large amount of allocations
505 * to be performed on the master process triggering the GC and slowing down
506 * redeclaration. Using the workers prevents this from occurring
508 let classes_initial_count = List.length classes in
509 let t = Unix.gettimeofday () in
510 Hh_logger.log ~lvl "Getting elements of %d classes" classes_initial_count;
511 let elements =
512 if classes_initial_count < 10 then
513 Decl_class_elements.get_for_classes ~old classes
514 else
515 let classes_processed_count = ref 0 in
516 ServerProgress.send_percentage_progress
517 ~operation:"getting members of"
518 ~done_count:!classes_processed_count
519 ~total_count:classes_initial_count
520 ~unit:"classes"
521 ~extra:None;
522 MultiWorker.call
523 workers
524 ~job:(fun _ c ->
525 (Decl_class_elements.get_for_classes ~old c, List.length c))
526 ~merge:(merge_elements classes_initial_count classes_processed_count)
527 ~neutral:SMap.empty
528 ~next:(MultiWorker.next ~max_size:bucket_size workers classes)
531 let (_t : float) =
532 Hh_logger.log_duration ~lvl "Finished getting elements" t
534 elements
536 let invalidate_folded_classes_for_shallow_fanout
537 ctx workers ~bucket_size ~get_classes_in_file changed_classes =
538 let invalidated =
539 changed_classes
540 |> Typing_deps.add_extend_deps (Provider_context.get_deps_mode ctx)
541 |> Shallow_class_fanout.class_names_from_deps ~ctx ~get_classes_in_file
543 let get_elems n_classes =
544 get_elems ctx workers ~bucket_size FileInfo.{ empty_names with n_classes }
546 Decl_class_elements.remove_old_all (get_elems invalidated ~old:true);
547 Decl_class_elements.remove_all (get_elems invalidated ~old:false);
548 Decl_heap.Classes.remove_old_batch invalidated;
549 Decl_heap.Classes.remove_batch invalidated;
550 SharedMem.GC.collect `gentle;
553 (*****************************************************************************)
554 (* The main entry point *)
555 (*****************************************************************************)
557 let redo_type_decl
558 (ctx : Provider_context.t)
559 (workers : MultiWorker.worker list option)
560 ~(bucket_size : int)
561 (get_classes : Relative_path.t -> SSet.t)
562 ~(previously_oldified_defs : FileInfo.names)
563 ~(defs : FileInfo.names Relative_path.Map.t) : redo_type_decl_result =
564 let all_defs =
565 Relative_path.Map.fold defs ~init:FileInfo.empty_names ~f:(fun _ ->
566 FileInfo.merge_names)
568 (* Some of the defintions are already in the old heap, left there by a
569 * previous lazy check *)
570 let (oldified_defs, current_defs) =
571 Decl_utils.split_defs all_defs previously_oldified_defs
573 (* Oldify the remaining defs along with their elements *)
574 let get_elems = get_elems ctx workers ~bucket_size in
575 let current_elems = get_elems current_defs ~old:false in
576 oldify_defs ctx current_defs current_elems ~collect_garbage:true;
578 (* Fetch the already oldified elements too so we can remove them later *)
579 let oldified_elems = get_elems oldified_defs ~old:true in
580 let all_elems = SMap.union current_elems oldified_elems in
581 let fnl = Relative_path.Map.keys defs in
583 (* If there aren't enough files, let's do this ourselves ... it's faster! *)
584 let ((errors, changed, to_redecl, to_recheck), old_decl_missing_count) =
585 if List.length fnl < 10 then
586 let ((_declared : int), errors) = on_the_fly_decl_files ctx fnl in
587 let ((changed, to_redecl, to_recheck), old_decl_missing_count) =
588 compute_deps ctx defs fnl
590 ((errors, changed, to_redecl, to_recheck), old_decl_missing_count)
591 else
592 parallel_on_the_fly_decl ctx workers bucket_size defs fnl
594 let (changed, to_recheck) =
595 if shallow_decl_enabled ctx then (
596 let AffectedDeps.{ changed = changed'; mro_invalidated; needs_recheck } =
597 Shallow_decl_compare.compute_class_fanout
599 ~defs
600 ~fetch_old_decls:(Remote_old_decl_client.fetch_old_decls ~ctx)
603 let changed = DepSet.union changed changed' in
604 let to_recheck = DepSet.union to_recheck needs_recheck in
605 let mro_invalidated =
606 mro_invalidated
607 |> Naming_provider.get_files ctx
608 |> Relative_path.Set.fold ~init:SSet.empty ~f:(fun path acc ->
609 SSet.union acc (get_classes path))
611 Linearization_provider.remove_batch ctx mro_invalidated;
612 (changed, to_recheck)
613 ) else if force_shallow_decl_fanout_enabled ctx then (
614 let AffectedDeps.
615 { changed = changed'; mro_invalidated = _; needs_recheck } =
616 Shallow_decl_compare.compute_class_fanout
618 ~defs
619 ~fetch_old_decls:(Remote_old_decl_client.fetch_old_decls ~ctx)
623 invalidate_folded_classes_for_shallow_fanout
625 workers
626 ~bucket_size
627 ~get_classes_in_file:get_classes
628 changed';
630 let changed = DepSet.union changed changed' in
631 let to_recheck = DepSet.union to_recheck needs_recheck in
633 (changed, to_recheck)
634 ) else
635 (changed, to_recheck)
637 remove_old_defs ctx all_defs all_elems;
639 Hh_logger.log "Finished recomputing type declarations:";
640 Hh_logger.log " changed: %d" (DepSet.cardinal changed);
641 Hh_logger.log " to_redecl: %d" (DepSet.cardinal to_redecl);
642 Hh_logger.log " to_recheck: %d" (DepSet.cardinal to_recheck);
644 { errors; changed; to_redecl; to_recheck; old_decl_missing_count }
646 let oldify_type_decl
647 (ctx : Provider_context.t)
648 ?(collect_garbage = true)
649 (workers : MultiWorker.worker list option)
650 (get_classes : Relative_path.t -> SSet.t)
651 ~(bucket_size : int)
652 ~(previously_oldified_defs : FileInfo.names)
653 ~(defs : FileInfo.names) : unit =
654 (* Some defs are already oldified, waiting for their recheck *)
655 let (oldified_defs, current_defs) =
656 Decl_utils.split_defs defs previously_oldified_defs
658 let get_elems = get_elems ctx workers ~bucket_size in
659 (* Oldify things that are not oldified yet *)
660 let current_elems = get_elems current_defs ~old:false in
661 oldify_defs ctx current_defs current_elems ~collect_garbage;
663 (* For the rest, just invalidate their current versions *)
664 let oldified_elems = get_elems oldified_defs ~old:false in
665 remove_defs ctx oldified_defs oldified_elems ~collect_garbage;
667 (* Oldifying/removing classes also affects their elements
668 * (see Decl_class_elements), which might be shared with other classes. We
669 * need to remove all of them too to avoid dangling references *)
670 let all_classes = defs.FileInfo.n_classes in
671 let dependent_classes =
672 get_dependent_classes ctx workers get_classes ~bucket_size all_classes
674 let dependent_classes =
675 FileInfo.
676 { empty_names with n_classes = SSet.diff dependent_classes all_classes }
678 remove_defs ctx dependent_classes SMap.empty ~collect_garbage
680 let remove_old_defs
681 (ctx : Provider_context.t)
682 ~(bucket_size : int)
683 (workers : MultiWorker.worker list option)
684 (names : FileInfo.names) : unit =
685 let elems = get_elems ctx workers ~bucket_size names ~old:true in
686 remove_old_defs ctx names elems