2 * Copyright (c) 2015, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
10 (** On the fly defs-declaration are called when the user modified a file
11 and we are not at initilalization time anymore. Therefore, we have a bit more
12 work to do. We need to calculate what must be re-checked. *)
15 open Reordered_argument_collections
18 type get_classes_in_file
= Relative_path.t
-> SSet.t
26 type redo_type_decl_result
= {
29 old_decl_missing_count
: int;
32 let lvl = Hh_logger.Level.Debug
34 let shallow_decl_enabled (ctx
: Provider_context.t
) =
35 TypecheckerOptions.shallow_class_decl
(Provider_context.get_tcopt ctx
)
37 let force_shallow_decl_fanout_enabled (ctx
: Provider_context.t
) =
38 TypecheckerOptions.force_shallow_decl_fanout
(Provider_context.get_tcopt ctx
)
41 let empty = DepSet.make
() in
42 { changed
= empty; to_redecl
= empty; to_recheck
= empty }
44 let compute_deps_neutral = (empty_fanout, 0)
46 (** This is the place where we are going to put everything necessary for
47 the redeclaration. We could "pass" the values directly to the workers,
48 but it gives too much work to the master and slows things down,
49 so what we do instead is pass the data through shared memory via
51 I tried replicating the data to speed things up but it had no effect. *)
52 module OnTheFlyStore
= GlobalStorage.Make
(struct
53 type t
= Naming_table.defs_per_file
56 (** Compute the decls in a file *)
57 let decl_file ctx errors fn
=
58 let (decl_errors
, ()) =
59 Errors.do_with_context fn
Errors.Decl
(fun () ->
60 Decl.make_env ~sh
:SharedMem.Uses ctx fn
)
62 Errors.merge decl_errors errors
64 (** Given a set of classes, compare the old and the new decl and deduce
65 what must be rechecked accordingly. *)
66 let compare_classes_and_get_fanout ctx old_classes new_classes acc classes
=
67 let { changed
; to_redecl
; to_recheck
} = acc
in
68 let ((rc
, rdd
, rdc
), old_classes_missing
) =
69 Decl_compare.get_classes_deps ~ctx old_classes new_classes classes
71 let changed = DepSet.union rc
changed in
72 let to_redecl = DepSet.union rdd
to_redecl in
73 let to_recheck = DepSet.union rdc
to_recheck in
74 ({ changed; to_redecl; to_recheck }, old_classes_missing
)
76 (** Given a set of functions, compare the old and the new decl and deduce
77 what must be rechecked accordingly. *)
78 let compare_funs_and_get_fanout
79 ctx old_funs
{ changed; to_redecl; to_recheck } funs
=
80 let ((rc
, rdd
, rdc
), old_funs_missing
) =
81 Decl_compare.get_funs_deps ~ctx old_funs funs
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_funs_missing
)
88 (** Given a set of typedefs, compare the old and the new decl and deduce
89 what must be rechecked accordingly. *)
90 let compare_types_and_get_fanout
91 ctx old_types
{ changed; to_redecl; to_recheck } types
=
92 let ((rc
, rdc
), old_types_missing
) =
93 Decl_compare.get_types_deps ~ctx old_types types
95 let changed = DepSet.union rc
changed in
96 let to_recheck = DepSet.union rdc
to_recheck in
97 ({ changed; to_redecl; to_recheck }, old_types_missing
)
99 (* Given a set of global constants, compare the old and the new decl and
100 deduce what must be rechecked accordingly. *)
101 let compare_gconsts_and_get_fanout
102 ctx old_gconsts
{ changed; to_redecl; to_recheck } gconsts
=
103 let ((rc
, rdd
, rdc
), old_gconsts_missing
) =
104 Decl_compare.get_gconsts_deps ~ctx old_gconsts gconsts
106 let changed = DepSet.union rc
changed in
107 let to_redecl = DepSet.union rdd
to_redecl in
108 let to_recheck = DepSet.union rdc
to_recheck in
109 ({ changed; to_redecl; to_recheck }, old_gconsts_missing
)
111 (* Given a set of modules, compare the old and the new decl and
112 deduce what must be rechecked accordingly. *)
113 let compare_module_and_get_fanout
114 ctx old_modules new_modules
{ changed; to_redecl; to_recheck } modules
=
115 let ((rc
, rdd
, rdc
), old_modules_missing
) =
116 Decl_compare.get_module_deps ~ctx ~old_modules ~new_modules ~modules
118 let changed = DepSet.union rc
changed in
119 let to_redecl = DepSet.union rdd
to_redecl in
120 let to_recheck = DepSet.union rdc
to_recheck in
121 ({ changed; to_redecl; to_recheck }, old_modules_missing
)
123 (*****************************************************************************)
124 (* Redeclares a list of files
125 * And then computes the files that must be redeclared/rechecked by looking
126 * at what changed in the signatures of the classes/functions.
128 (*****************************************************************************)
130 (** Compute decls in files. Return errors raised during decling. *)
131 let redeclare_files ctx filel
=
132 List.fold_left filel ~f
:(decl_file ctx
) ~init
:Errors.empty
134 (** Invalidate local caches and compute decls in files. Return errors raised during decling. *)
135 let decl_files ctx filel
=
136 SharedMem.invalidate_local_caches
();
137 redeclare_files ctx filel
139 let compare_decls_and_get_fanout
140 ctx defs_per_file
(filel
: Relative_path.t list
) : fanout
* int =
142 List.map filel ~f
:(fun fn
-> Relative_path.Map.find defs_per_file fn
)
147 ~f
:FileInfo.merge_names
148 ~init
:FileInfo.empty_names
150 let { FileInfo.n_classes
; n_funs
; n_types
; n_consts
; n_modules
} = all_defs in
151 let acc = empty_fanout in
152 (* Fetching everything at once is faster *)
153 let old_funs = Decl_heap.Funs.get_old_batch n_funs
in
154 let (acc, old_funs_missing
) =
155 compare_funs_and_get_fanout ctx
old_funs acc n_funs
157 let old_types = Decl_heap.Typedefs.get_old_batch n_types
in
158 let (acc, old_types_missing
) =
159 compare_types_and_get_fanout ctx
old_types acc n_types
161 let old_consts = Decl_heap.GConsts.get_old_batch n_consts
in
162 let (acc, old_gconsts_missing
) =
163 compare_gconsts_and_get_fanout ctx
old_consts acc n_consts
166 let (acc, old_classes_missing
) =
167 if shallow_decl_enabled ctx
|| force_shallow_decl_fanout_enabled ctx
then
170 let old_classes = Decl_heap.Classes.get_old_batch n_classes
in
171 let new_classes = Decl_heap.Classes.get_batch n_classes
in
172 compare_classes_and_get_fanout ctx
old_classes new_classes acc n_classes
175 let (acc, old_modules_missing
) =
176 let old_modules = Decl_heap.Modules.get_old_batch n_modules
in
177 let new_modules = Decl_heap.Modules.get_batch n_modules
in
178 compare_module_and_get_fanout ctx
old_modules new_modules acc n_modules
181 let old_decl_missing_count =
184 + old_gconsts_missing
185 + old_classes_missing
186 + old_modules_missing
188 let { changed; to_redecl; to_recheck } = acc in
189 ({ changed; to_redecl; to_recheck }, old_decl_missing_count)
191 (*****************************************************************************)
192 (* Load the environment and then redeclare *)
193 (*****************************************************************************)
195 (** Invalidate local caches and compute decls in files. Return the file count and errors raised during decling. *)
196 let decl_files_job ctx _ filel
=
197 try (List.length filel
, decl_files ctx filel
) with
199 let e = Exception.wrap exn
in
200 Printf.printf
"Error: %s\n" (Exception.get_ctor_string
e);
201 Out_channel.flush stdout
;
204 let load_defs_compare_and_get_fanout ctx _acc
(filel
: Relative_path.t list
) :
205 (fanout
* int) * int =
207 let defs_per_file = OnTheFlyStore.load
() in
208 let (fanout
, old_decl_missing_count) =
209 compare_decls_and_get_fanout ctx
defs_per_file filel
211 ((fanout
, List.length filel
), old_decl_missing_count)
214 let e = Exception.wrap exn
in
215 Printf.printf
"Error: %s\n" (Exception.get_ctor_string
e);
216 Out_channel.flush stdout
;
219 (*****************************************************************************)
220 (* Merges the results coming back from the different workers *)
221 (*****************************************************************************)
224 files_initial_count files_declared_count
(count
, errorl1
) errorl2
=
225 files_declared_count
:= !files_declared_count
+ count
;
226 ServerProgress.send_percentage_progress
227 ~operation
:"declaring"
228 ~done_count
:!files_declared_count
229 ~total_count
:files_initial_count
233 Errors.merge errorl1 errorl2
235 let merge_compute_deps
238 ((fanout1
, computed_count
), old_decl_missing_count1
)
239 (fanout2
, old_decl_missing_count2
) =
240 files_computed_count
:= !files_computed_count
+ computed_count
;
242 let { changed = changed1
; to_redecl = to_redecl1
; to_recheck = to_recheck1
} =
245 let { changed = changed2
; to_redecl = to_redecl2
; to_recheck = to_recheck2
} =
250 changed = DepSet.union changed1 changed2
;
251 to_redecl = DepSet.union to_redecl1 to_redecl2
;
252 to_recheck = DepSet.union to_recheck1 to_recheck2
;
256 ServerProgress.send_percentage_progress
257 ~operation
:"computing dependencies of"
258 ~done_count
:!files_computed_count
259 ~total_count
:files_initial_count
263 (fanout, old_decl_missing_count1
+ old_decl_missing_count2
)
265 (*****************************************************************************)
266 (* The parallel worker *)
267 (*****************************************************************************)
269 (** Invalidate local decl caches and recompute decls in files in parallel.
270 Compare new and old decls and deduce the fanout.
271 Return errors raised during decling, fanout and missing old decl count. *)
272 let parallel_redecl_compare_and_get_fanout
273 (ctx
: Provider_context.t
)
274 (workers
: MultiWorker.worker list
option)
276 (defs_per_file : FileInfo.names
Relative_path.Map.t
)
277 (fnl
: Relative_path.t list
) : (Errors.t
* fanout) * int =
279 OnTheFlyStore.store
defs_per_file;
280 let files_initial_count = List.length fnl
in
281 let files_declared_count = ref 0 in
282 let t = Unix.gettimeofday
() in
283 Hh_logger.log ~
lvl "Declaring on-the-fly %d files" files_initial_count;
284 ServerProgress.send_percentage_progress
285 ~operation
:"declaring"
286 ~done_count
:!files_declared_count
287 ~total_count
:files_initial_count
293 ~job
:(decl_files_job ctx
)
294 ~neutral
:Errors.empty
295 ~merge
:(merge_on_the_fly files_initial_count files_declared_count)
296 ~next
:(MultiWorker.next ~max_size
:bucket_size workers fnl
)
298 let t = Hh_logger.log_duration ~
lvl "Finished declaring on-the-fly" t in
299 Hh_logger.log ~
lvl "Computing dependencies of %d files" files_initial_count;
300 let files_computed_count = ref 0 in
301 ServerProgress.send_percentage_progress
302 ~operation
:"computing dependencies of"
303 ~done_count
:!files_computed_count
304 ~total_count
:files_initial_count
307 let (fanout, old_decl_missing_count) =
310 ~job
:(load_defs_compare_and_get_fanout ctx
)
311 ~neutral
:compute_deps_neutral
312 ~merge
:(merge_compute_deps files_initial_count files_computed_count)
313 ~next
:(MultiWorker.next ~max_size
:bucket_size workers fnl
)
316 Hh_logger.log_duration ~
lvl "Finished computing dependencies" t
318 OnTheFlyStore.clear
();
319 ((errors, fanout), old_decl_missing_count)
322 let e = Exception.wrap exn
in
323 if SharedMem.SMTelemetry.is_heap_overflow
() then
324 Exit.exit
Exit_status.Redecl_heap_overflow
328 (*****************************************************************************)
329 (* Code invalidating the heap *)
330 (*****************************************************************************)
332 (ctx
: Provider_context.t)
333 { FileInfo.n_funs
; n_classes
; n_types
; n_consts
; n_modules
}
334 (elems
: Decl_class_elements.t SMap.t)
335 ~
(collect_garbage
: bool) : unit =
336 Decl_heap.Funs.oldify_batch n_funs
;
337 Decl_class_elements.oldify_all elems
;
338 Decl_heap.Classes.oldify_batch n_classes
;
339 Shallow_classes_provider.oldify_batch ctx n_classes
;
340 Decl_heap.Typedefs.oldify_batch n_types
;
341 Decl_heap.GConsts.oldify_batch n_consts
;
342 Decl_heap.Modules.oldify_batch n_modules
;
343 if collect_garbage
then SharedMem.GC.collect `gentle
;
347 (ctx
: Provider_context.t)
348 { FileInfo.n_funs
; n_classes
; n_types
; n_consts
; n_modules
}
349 (elems
: Decl_class_elements.t SMap.t) : unit =
350 Decl_heap.Funs.remove_old_batch n_funs
;
351 Decl_class_elements.remove_old_all elems
;
352 Decl_heap.Classes.remove_old_batch n_classes
;
353 Shallow_classes_provider.remove_old_batch ctx n_classes
;
354 Decl_heap.Typedefs.remove_old_batch n_types
;
355 Decl_heap.GConsts.remove_old_batch n_consts
;
356 Decl_heap.Modules.remove_old_batch n_modules
;
357 SharedMem.GC.collect `gentle
;
361 (ctx
: Provider_context.t)
362 { FileInfo.n_funs
; n_classes
; n_types
; n_consts
; n_modules
}
363 (elems
: Decl_class_elements.t SMap.t)
364 ~
(collect_garbage
: bool) : unit =
365 Decl_heap.Funs.remove_batch n_funs
;
366 Decl_class_elements.remove_all elems
;
367 Decl_heap.Classes.remove_batch n_classes
;
368 Shallow_classes_provider.remove_batch ctx n_classes
;
369 Linearization_provider.remove_batch ctx n_classes
;
370 Decl_heap.Typedefs.remove_batch n_types
;
371 Decl_heap.GConsts.remove_batch n_consts
;
372 Decl_heap.Modules.remove_batch n_modules
;
373 if collect_garbage
then SharedMem.GC.collect `gentle
;
376 let is_dependent_class_of_any ctx classes
(c
: string) : bool =
377 if SSet.mem classes c
then
379 else if shallow_decl_enabled ctx
then
382 match Decl_heap.Classes.get c
with
384 (* it might be a dependent class, but we are only doing this
385 * check for the purpose of invalidating things from the heap
386 * - if it's already not there, then we don't care. *)
388 let intersection_nonempty s1 s2
= SSet.exists s1 ~f
:(SSet.mem s2
) in
389 SMap.exists c
.Decl_defs.dc_ancestors ~f
:(fun c _
-> SSet.mem classes c
)
390 || intersection_nonempty c
.Decl_defs.dc_extends classes
391 || intersection_nonempty c
.Decl_defs.dc_xhp_attr_deps classes
392 || intersection_nonempty c
.Decl_defs.dc_req_ancestors_extends classes
394 let get_maybe_dependent_classes
395 (get_classes
: Relative_path.t -> SSet.t)
397 (files
: Relative_path.Set.t) : string list
=
398 Relative_path.Set.fold files ~init
:classes ~f
:(fun x
acc ->
399 SSet.union
acc @@ get_classes x
)
402 let get_dependent_classes_files (ctx
: Provider_context.t) (classes
: SSet.t) :
403 Relative_path.Set.t =
404 let mode = Provider_context.get_deps_mode ctx
in
405 let visited = VisitedSet.make
() in
408 ~init
:Typing_deps.(DepSet.make
())
410 let source_class = Dep.make
(Dep.Type c
) in
411 Typing_deps.get_extend_deps ~
mode ~
visited ~
source_class ~
acc)
412 |> Naming_provider.get_files ctx
414 let filter_dependent_classes
415 (ctx
: Provider_context.t)
417 (maybe_dependent_classes
: string list
) : string list
=
418 List.filter maybe_dependent_classes ~f
:(is_dependent_class_of_any ctx classes
)
420 module ClassSetStore
= GlobalStorage.Make
(struct
424 let load_and_filter_dependent_classes
425 (ctx
: Provider_context.t) (maybe_dependent_classes
: string list
) :
427 let classes = ClassSetStore.load
() in
428 ( filter_dependent_classes ctx
classes maybe_dependent_classes
,
429 List.length maybe_dependent_classes
)
431 let merge_dependent_classes
432 classes_initial_count
433 classes_filtered_count
434 (dependent_classes
, filtered
)
436 classes_filtered_count
:= !classes_filtered_count
+ filtered
;
437 ServerProgress.send_percentage_progress
438 ~operation
:"filtering"
439 ~done_count
:!classes_filtered_count
440 ~total_count
:classes_initial_count
443 dependent_classes
@ acc
445 let filter_dependent_classes_parallel
446 (ctx
: Provider_context.t)
447 (workers
: MultiWorker.worker list
option)
450 (maybe_dependent_classes
: string list
) : string list
=
451 if List.length maybe_dependent_classes
< 10 then
452 filter_dependent_classes ctx
classes maybe_dependent_classes
454 ClassSetStore.store
classes;
455 let classes_initial_count = List.length maybe_dependent_classes
in
456 let classes_filtered_count = ref 0 in
457 let t = Unix.gettimeofday
() in
458 Hh_logger.log ~
lvl "Filtering %d dependent classes" classes_initial_count;
459 ServerProgress.send_percentage_progress
460 ~operation
:"filtering"
461 ~done_count
:!classes_filtered_count
462 ~total_count
:classes_initial_count
468 ~job
:(fun _ c
-> load_and_filter_dependent_classes ctx c
)
470 (merge_dependent_classes classes_initial_count classes_filtered_count)
474 ~max_size
:bucket_size
476 maybe_dependent_classes
)
479 Hh_logger.log_duration ~
lvl "Finished filtering dependent classes" t
481 ClassSetStore.clear
();
485 let get_dependent_classes
486 (ctx
: Provider_context.t)
487 (workers
: MultiWorker.worker list
option)
489 (get_classes
: Relative_path.t -> SSet.t)
490 (classes : SSet.t) : SSet.t =
491 get_dependent_classes_files ctx
classes
492 |> get_maybe_dependent_classes get_classes
classes
493 |> filter_dependent_classes_parallel ctx workers ~bucket_size
classes
497 classes_initial_count classes_processed_count
(elements
, count
) acc =
498 classes_processed_count
:= !classes_processed_count
+ count
;
500 let acc = SMap.union elements
acc in
501 ServerProgress.send_percentage_progress
502 ~operation
:"getting members of"
503 ~done_count
:!classes_processed_count
504 ~total_count
:classes_initial_count
506 ~extra
:(Some
(Printf.sprintf
"%d elements" (SMap.cardinal
acc)));
510 * Get the [Decl_class_elements.t]s corresponding to the classes contained in
513 (ctx
: Provider_context.t)
514 (workers
: MultiWorker.worker list
option)
517 (defs
: FileInfo.names
) : Decl_class_elements.t SMap.t =
518 if shallow_decl_enabled ctx
then
521 let classes = SSet.elements defs
.FileInfo.n_classes
in
522 (* Getting the members of a class requires fetching the class from the heap.
523 * Doing this for too many classes will cause a large amount of allocations
524 * to be performed on the master process triggering the GC and slowing down
525 * redeclaration. Using the workers prevents this from occurring
527 let classes_initial_count = List.length
classes in
528 let t = Unix.gettimeofday
() in
529 Hh_logger.log ~
lvl "Getting elements of %d classes" classes_initial_count;
531 if classes_initial_count < 10 then
532 Decl_class_elements.get_for_classes ~old
classes
534 let classes_processed_count = ref 0 in
535 ServerProgress.send_percentage_progress
536 ~operation
:"getting members of"
537 ~done_count
:!classes_processed_count
538 ~total_count
:classes_initial_count
544 (Decl_class_elements.get_for_classes ~old c
, List.length c
))
545 ~merge
:(merge_elements classes_initial_count classes_processed_count)
547 ~next
:(MultiWorker.next ~max_size
:bucket_size workers
classes)
551 Hh_logger.log_duration ~
lvl "Finished getting elements" t
555 let invalidate_folded_classes_for_shallow_fanout
556 ctx workers ~bucket_size ~get_classes_in_file changed_classes
=
559 |> Typing_deps.add_extend_deps
(Provider_context.get_deps_mode ctx
)
560 |> Shallow_class_fanout.class_names_from_deps ~ctx ~get_classes_in_file
562 let get_elems n_classes
=
563 get_elems ctx workers ~bucket_size
FileInfo.{ empty_names
with n_classes
}
565 Decl_class_elements.remove_old_all
(get_elems invalidated ~old
:true);
566 Decl_class_elements.remove_all
(get_elems invalidated ~old
:false);
567 Decl_heap.Classes.remove_old_batch
invalidated;
568 Decl_heap.Classes.remove_batch
invalidated;
569 SharedMem.GC.collect `gentle
;
572 (*****************************************************************************)
573 (* The main entry point *)
574 (*****************************************************************************)
576 (** Oldify any defs in [defs] which aren't already in
577 [previously_oldified_defs], then determines which symbols need to be
578 re-typechecked as a result of comparing the current versions of the symbols
579 to their old versions. *)
581 (ctx
: Provider_context.t)
582 (workers
: MultiWorker.worker list
option)
584 (get_classes
: Relative_path.t -> SSet.t)
585 ~
(previously_oldified_defs
: FileInfo.names
)
586 ~
(defs
: FileInfo.names
Relative_path.Map.t)
587 ~
(telemetry_label
: string) : redo_type_decl_result
=
589 Relative_path.Map.fold defs ~init
:FileInfo.empty_names ~f
:(fun _
->
590 FileInfo.merge_names
)
592 (* Some of the definitions are already in the old heap, left there by a
593 * previous lazy check *)
594 let (oldified_defs
, current_defs
) =
595 Decl_utils.split_defs
all_defs previously_oldified_defs
597 (* Oldify the remaining defs along with their elements *)
598 let get_elems = get_elems ctx workers ~bucket_size
in
599 let current_elems = get_elems current_defs ~old
:false in
600 oldify_defs ctx current_defs
current_elems ~collect_garbage
:true;
602 (* Fetch the already oldified elements too so we can remove them later *)
603 let oldified_elems = get_elems oldified_defs ~old
:true in
604 let all_elems = SMap.union
current_elems oldified_elems in
605 let fnl = Relative_path.Map.keys defs
in
607 let ((errors, { changed; to_redecl; to_recheck }), old_decl_missing_count) =
608 (* If there aren't enough files, let's do this ourselves ... it's faster! *)
609 if List.length
fnl < 10 then
610 let errors = decl_files ctx
fnl in
611 let (fanout, old_decl_missing_count) =
612 compare_decls_and_get_fanout ctx defs
fnl
614 ((errors, fanout), old_decl_missing_count)
616 parallel_redecl_compare_and_get_fanout ctx workers bucket_size defs
fnl
618 let (changed, to_recheck) =
619 if shallow_decl_enabled ctx
then (
620 let AffectedDeps.{ changed = changed'
; mro_invalidated
; needs_recheck
} =
621 Shallow_decl_compare.compute_class_fanout
625 (Remote_old_decl_client.fetch_old_decls ~ctx ~telemetry_label
)
628 let changed = DepSet.union
changed changed'
in
629 let to_recheck = DepSet.union
to_recheck needs_recheck
in
630 let mro_invalidated =
632 |> Naming_provider.get_files ctx
633 |> Relative_path.Set.fold ~init
:SSet.empty ~f
:(fun path
acc ->
634 SSet.union
acc (get_classes path
))
636 Linearization_provider.remove_batch ctx
mro_invalidated;
637 (changed, to_recheck)
638 ) else if force_shallow_decl_fanout_enabled ctx
then (
640 { changed = changed'
; mro_invalidated = _
; needs_recheck
} =
641 Shallow_decl_compare.compute_class_fanout
645 (Remote_old_decl_client.fetch_old_decls ~ctx ~telemetry_label
)
649 invalidate_folded_classes_for_shallow_fanout
653 ~get_classes_in_file
:get_classes
656 let changed = DepSet.union
changed changed'
in
657 let to_recheck = DepSet.union
to_recheck needs_recheck
in
659 (changed, to_recheck)
661 (changed, to_recheck)
663 remove_old_defs ctx
all_defs all_elems;
665 Hh_logger.log
"Finished recomputing type declarations:";
666 Hh_logger.log
" changed: %d" (DepSet.cardinal
changed);
667 Hh_logger.log
" to_redecl: %d" (DepSet.cardinal
to_redecl);
668 Hh_logger.log
" to_recheck: %d" (DepSet.cardinal
to_recheck);
672 fanout = { changed; to_redecl; to_recheck };
673 old_decl_missing_count;
676 (** Mark all provided [defs] as old, as long as they were not previously
677 oldified. All definitions in [previously_oldified_defs] are then removed from
680 Typically, there are only any [previously_oldified_defs] during two-phase
683 (ctx
: Provider_context.t)
684 ?
(collect_garbage
= true)
685 (workers
: MultiWorker.worker list
option)
686 (get_classes
: Relative_path.t -> SSet.t)
688 ~
(previously_oldified_defs
: FileInfo.names
)
689 ~
(defs
: FileInfo.names
) : unit =
690 (* Some defs are already oldified, waiting for their recheck *)
691 let (oldified_defs
, current_defs
) =
692 Decl_utils.split_defs defs previously_oldified_defs
694 let get_elems = get_elems ctx workers ~bucket_size
in
695 (* Oldify things that are not oldified yet *)
696 let current_elems = get_elems current_defs ~old
:false in
697 oldify_defs ctx current_defs
current_elems ~collect_garbage
;
699 (* For the rest, just invalidate their current versions *)
700 let oldified_elems = get_elems oldified_defs ~old
:false in
701 remove_defs ctx oldified_defs
oldified_elems ~collect_garbage
;
703 (* Oldifying/removing classes also affects their elements
704 * (see Decl_class_elements), which might be shared with other classes. We
705 * need to remove all of them too to avoid dangling references *)
706 let all_classes = defs
.FileInfo.n_classes
in
707 let dependent_classes =
708 get_dependent_classes ctx workers get_classes ~bucket_size
all_classes
710 let dependent_classes =
712 { empty_names
with n_classes
= SSet.diff
dependent_classes all_classes }
714 remove_defs ctx
dependent_classes SMap.empty ~collect_garbage
717 (ctx
: Provider_context.t)
719 (workers
: MultiWorker.worker list
option)
720 (names
: FileInfo.names
) : unit =
721 let elems = get_elems ctx workers ~bucket_size names ~old
:true in
722 remove_old_defs ctx names
elems