2 * Copyright (c) 2018, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE fn in the "hack" directory of this source tree.
13 let should_use options local_config
=
14 Option.value (ServerArgs.prechecked options
)
15 ~default
:local_config
.ServerLocalConfig.prechecked_files
17 let set env prechecked_files
= { env
with prechecked_files
}
19 let intersect_with_master_deps ~deps ~dirty_master_deps ~rechecked_files genv env
=
20 (* Compute maximum fan-out of input dep set *)
21 let deps = Typing_deps.add_all_deps
deps in
22 (* See if it intersects in any way with dirty_master_deps *)
23 let common_deps = Typing_deps.DepSet.inter
deps dirty_master_deps
in
24 (* Expand the common part *)
25 let more_deps = Typing_deps.add_all_deps
common_deps in
26 (* Remove the common part from dirty_master_deps (because after expanding it's
28 let dirty_master_deps = Typing_deps.DepSet.diff
dirty_master_deps common_deps in
30 (* Translate the dependencies to files that need to be rechecked. *)
31 let needs_recheck = Typing_deps.get_files
more_deps in
32 let needs_recheck = Relative_path.Set.diff
needs_recheck rechecked_files
in
34 let size = Relative_path.Set.cardinal
needs_recheck in
35 let env = if size = 0 then env else begin
36 ServerRevisionTracker.typing_changed genv
.local_config
size;
37 Hh_logger.log
"Adding %d files to recheck" size;
39 Relative_path.Set.union
env.needs_recheck needs_recheck in
40 { env with needs_recheck }
42 env, dirty_master_deps, size
44 let update_rechecked_files env rechecked
=
45 let t = Unix.gettimeofday
() in
46 let add_rechecked dirty_deps
=
47 let rechecked_files = Relative_path.Map.fold rechecked
48 ~init
:dirty_deps
.rechecked_files
49 ~f
:begin fun path _ acc
->
50 Relative_path.Set.add acc path
53 { dirty_deps
with rechecked_files }
55 let env = set env @@ match env.prechecked_files
with
56 | Prechecked_files_disabled
-> Prechecked_files_disabled
57 | Initial_typechecking dirty_deps
->
58 Initial_typechecking
(add_rechecked dirty_deps
)
59 | Prechecked_files_ready dirty_deps
->
60 Prechecked_files_ready
(add_rechecked dirty_deps
)
62 HackEventLogger.prechecked_update_rechecked
t;
65 let update_after_recheck genv
env rechecked
=
66 let env = update_rechecked_files env rechecked
in
67 match env.full_check
, env.prechecked_files
with
68 | Full_check_done
, Initial_typechecking
{
74 let t = Unix.gettimeofday
() in
75 assert (Typing_deps.DepSet.is_empty clean_local_deps
);
76 Hh_logger.log
"Finished rechecking dirty files, evaluating their fanout";
77 (* Take any prechecked files that could have been affected by local changes
78 * and expand them too *)
79 let env, dirty_master_deps, size = intersect_with_master_deps
80 ~
deps:dirty_local_deps
85 let env = if (size = 0) then env else begin
86 let full_check = Full_check_started
in
87 let init_env = { env.init_env with needs_full_init
= true } in
88 { env with init_env; full_check; }
90 let clean_local_deps = dirty_local_deps
in
91 let dirty_local_deps = Typing_deps.DepSet.empty
in
92 HackEventLogger.prechecked_evaluate_init
t size;
94 set env (Prechecked_files_ready
{
102 let update_after_local_changes genv
env changes
=
103 match env.prechecked_files
with
104 | Prechecked_files_disabled
-> env
105 | Initial_typechecking dirty_deps
->
106 let dirty_local_deps =
107 Typing_deps.DepSet.union changes dirty_deps
.dirty_local_deps in
108 set env (Initial_typechecking
{ dirty_deps
with dirty_local_deps })
109 | Prechecked_files_ready dirty_deps
->
110 (* This is cleared during transition from Initial_typechecking to
111 * Prechecked_files_ready and should not be populated again *)
112 assert (Typing_deps.DepSet.is_empty dirty_deps
.dirty_local_deps);
113 let changes = Typing_deps.DepSet.diff
changes dirty_deps
.clean_local_deps in
114 if Typing_deps.DepSet.is_empty
changes then env else
115 let t = Unix.gettimeofday
() in
116 let clean_local_deps =
117 Typing_deps.DepSet.union dirty_deps
.clean_local_deps changes in
118 let env, dirty_master_deps, size = intersect_with_master_deps
120 ~
dirty_master_deps:dirty_deps
.dirty_master_deps
121 ~
rechecked_files:dirty_deps
.rechecked_files
124 let env = if (size = 0) then env else begin
125 let full_check = match env.full_check with
126 | Full_check_done
-> Full_check_needed
129 { env with full_check; }
131 HackEventLogger.prechecked_evaluate_incremental
t size;
132 set env (Prechecked_files_ready
{ dirty_deps
with
138 match env.prechecked_files
with
139 | Prechecked_files_disabled
-> env
140 | Initial_typechecking dirty_deps
141 | Prechecked_files_ready dirty_deps
->
142 let deps = Typing_deps.add_all_deps dirty_deps
.dirty_master_deps in
143 let needs_recheck = Typing_deps.get_files
deps in
145 Relative_path.Set.diff
needs_recheck dirty_deps
.rechecked_files in
146 let env = if Relative_path.Set.is_empty
needs_recheck then env else begin
147 Hh_logger.log
"Adding %d files to recheck after expanding all master deps"
148 (Relative_path.Set.cardinal
needs_recheck);
150 Relative_path.Set.union
env.needs_recheck needs_recheck in
153 full_check = Full_check_started
;
156 set env (Prechecked_files_ready
{ dirty_deps
with
157 dirty_master_deps = Typing_deps.DepSet.empty
;