Add type annotations to `clientConnect.ml`
[hiphop-php.git] / hphp / hack / src / server / serverEnv.ml
blob0284e28ee14d0524eceffcc6d1bb45321b07fcee
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 open Hh_core
12 (*****************************************************************************)
13 (* Recheck loop types. *)
14 (*****************************************************************************)
16 type recheck_loop_stats = {
17 (** Watchman subscription has gone down, so state of the world after the
18 * recheck loop may not reflect what is actually on disk. *)
19 updates_stale : bool;
20 rechecked_batches : int;
21 rechecked_count : int;
22 (* includes dependencies *)
23 total_rechecked_count : int;
26 let empty_recheck_loop_stats = {
27 updates_stale = false;
28 rechecked_batches = 0;
29 rechecked_count = 0;
30 total_rechecked_count = 0;
33 (*****************************************************************************)
34 (* The "static" environment, initialized first and then doesn't change *)
35 (*****************************************************************************)
37 type genv = {
38 options : ServerArgs.options;
39 config : ServerConfig.t;
40 local_config : ServerLocalConfig.t;
41 workers : MultiWorker.worker list option;
42 (* Returns the list of files under .hhconfig, subject to a filter *)
43 indexer : (string -> bool) -> (unit -> string list);
44 (* Each time this is called, it should return the files that have changed
45 * since the last invocation *)
46 notifier_async : unit -> ServerNotifierTypes.notifier_changes;
47 (* If this FD is readable, next call to notifier_async () should read
48 * something from it. *)
49 notifier_async_reader : unit -> Buffered_line_reader.t option;
50 notifier : unit -> SSet.t;
51 (* If daemons are spawned as part of the init process, wait for them here
52 * e.g. wait until dfindlib is ready (in the case that watchman is absent) *)
53 wait_until_ready : unit -> unit;
54 mutable debug_channels : (Timeout.in_channel * out_channel) option;
57 (*****************************************************************************)
58 (* The environment constantly maintained by the server *)
59 (*****************************************************************************)
61 type full_check_status =
62 (* Some updates have not been fully processed. We get into this state every
63 * time file contents change (on disk, or through IDE notifications).
64 * Operations that depend on global state (like taking full error list, or
65 * looking up things in dependency table) will have stale results. *)
66 | Full_check_needed
67 (* Same as above, except server will actively try to process outstanding
68 * changes (by going into ServerTypeCheck from main loop - this might need to
69 * be repeated several times before progressing to Full_check_done, due to
70 * ability to interrupt typecheck jobs).
71 * Server starts in this state, and we also enter it from Full_check_needed
72 * whenever there is a command requiring full check pending, or when user
73 * saves a file. *)
74 | Full_check_started
75 (* All the changes have been fully processed. *)
76 | Full_check_done
78 (* In addition to this environment, many functions are storing and
79 * updating ASTs, NASTs, and types in a shared space
80 * (see respectively Parser_heap, Naming_heap, Typing_env).
81 * The Ast.id are keys to index this shared space.
83 type env = {
84 files_info : FileInfo.t Relative_path.Map.t;
85 tcopt : TypecheckerOptions.t;
86 popt : ParserOptions.t;
87 (* Errors are indexed by files that were known to GENERATE errors in
88 * corresponding phases. Note that this is different from HAVING errors -
89 * it's possible for checking of A to generate error in B - in this case
90 * Errors.get_failed_files Typing should contain A, not B.
91 * Conversly, if declaring A will require declaring B, we should put
92 * B in failed decl. Same if checking A will cause declaring B (via lazy
93 * decl).
95 * During recheck, we add those files to the set of files to reanalyze
96 * at each stage in order to regenerate their error lists. So those
97 * failed_ sets are the main piece of mutable state that incremental mode
98 * needs to maintain - the errors themselves are more of a cache, and should
99 * always be possible to be regenerated based on those sets. *)
100 errorl : Errors.t;
101 (* failed_naming is used as kind of a dependency tracking mechanism:
102 * if files A.php and B.php both define class C, then those files are
103 * mutually depending on each other (edit to one might resolve naming
104 * ambiguity and change the interpretation of the other). Both of those
105 * files being inside failed_naming is how we track the need to
106 * check for this condition.
108 * See test_naming_errors.ml and test_failed_naming.ml
110 failed_naming : Relative_path.Set.t;
111 persistent_client : ClientProvider.client option;
112 (* Whether last received IDE command was IDE_IDLE *)
113 ide_idle : bool;
114 (* Timestamp of last IDE file synchronization command *)
115 last_command_time : float;
116 (* Timestamp of last query for disk changes *)
117 last_notifier_check_time : float;
118 (* Timestamp of last ServerIdle.go run *)
119 last_idle_job_time : float;
120 (* The map from full path to synchronized file contents *)
121 editor_open_files : Relative_path.Set.t;
122 (* Files which parse trees were invalidated (because they changed on disk
123 * or in editor) and need to be re-parsed *)
124 ide_needs_parsing : Relative_path.Set.t;
125 disk_needs_parsing : Relative_path.Set.t;
126 (* Declarations that became invalidated and moved to "old" part of the heap.
127 * We keep them there to be used in "determining changes" step of recheck.
128 * (when they are compared to "new" versions). Depending on lazy decl to
129 * compute "new" versions in all the other scenarios (like IDE queries) *)
130 needs_phase2_redecl : Relative_path.Set.t;
131 (* Files that need to be typechecked before commands that depend on global
132 * state (like full list of errors, build, or find all references) can be
133 * executed . After full check this should be empty, unless that check was
134 * cancelled mid-flight, in which case full_check will be set to
135 * Full_check_started and entire thing will be retried on next iteration. *)
136 needs_recheck : Relative_path.Set.t;
137 init_env : init_env;
138 full_check : full_check_status;
139 prechecked_files : prechecked_files_status;
140 (* Not every caller of rechecks expects that they can be interrupted,
141 * so making it opt-in by setting this flag at call site *)
142 can_interrupt : bool;
143 interrupt_handlers: genv -> env ->
144 (Unix.file_descr * env MultiThreadedCall.interrupt_handler) list;
145 (* When persistent client sends a command that cannot be handled (due to
146 * thread safety) we put the continuation that finishes handling it here. *)
147 pending_command_needs_writes : (env -> env) option;
148 (* When persistent client sends a command that cannot be immediately handled
149 * (due to needing full check) we put the continuation that finishes handling
150 * it here. The string specifies a reason why this command needs full
151 * recheck (for logging/debugging purposes) *)
152 persistent_client_pending_command_needs_full_check:
153 ((env -> env) * string) option;
154 (* Same as above, but for non-persistent clients *)
155 default_client_pending_command_needs_full_check:
156 ((env -> env) * string * ClientProvider.client) option;
157 (* The diagnostic subscription information of the current client *)
158 diag_subscribe : Diagnostic_subscription.t option;
159 recent_recheck_loop_stats : recheck_loop_stats;
162 and dirty_deps = {
163 (* We are rechecking dirty files to bootstrap the dependency graph.
164 * After this is done we need to also recheck full fan-out (in this updated
165 * graph) of provided set. *)
166 dirty_local_deps : Typing_deps.DepSet.t;
167 (* The fan-outs of those nodes were not expanded yet. *)
168 dirty_master_deps : Typing_deps.DepSet.t;
169 (* Files that have been rechecked since server startup *)
170 rechecked_files : Relative_path.Set.t;
171 (* Those deps have already been checked against their interaction with
172 * dirty_master_deps. Storing them here to avoid checking it over and over *)
173 clean_local_deps : Typing_deps.DepSet.t;
176 (* When using prechecked files we split initial typechecking in two phases
177 * (dirty files and a subset of their fan-out). Other init types compute the
178 * full fan-out up-front. *)
179 and prechecked_files_status =
180 | Prechecked_files_disabled
181 | Initial_typechecking of dirty_deps
182 | Prechecked_files_ready of dirty_deps
184 and init_env = {
185 init_start_t : float;
186 (* Whether a full check was ever completed since init. *)
187 needs_full_init : bool;
188 (* Additional data associated with init that we want to log when a first full
189 * check completes. *)
190 state_distance : int option;
191 approach_name : string;
192 init_error : string option;
193 init_type : string;
196 let list_files env oc =
197 let acc = List.fold_right
198 ~f:begin fun error acc ->
199 let pos = Errors.get_pos error in
200 Relative_path.Set.add acc (Pos.filename pos)
202 ~init:Relative_path.Set.empty
203 (Errors.get_error_list env.errorl) in
204 Relative_path.Set.iter acc (fun s ->
205 Printf.fprintf oc "%s\n" (Relative_path.to_absolute s));
206 flush oc