Array unification switch
[hiphop-php.git] / hphp / hack / src / server / serverConfig.ml
blob130af8948d170987029b66f0007231396c5a6ad0
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 * Parses and gathers information from the .hhconfig in the repo.
14 open Hh_prelude
15 open Config_file.Getters
16 open Reordered_argument_collections
17 open ServerLocalConfig
19 type t = {
20 version: Config_file.version; [@printer (fun fmt _ -> fprintf fmt "version")]
21 load_script_timeout: int;
22 (* in seconds *)
24 (* Configures only the workers. Workers can have more relaxed GC configs as
25 * they are short-lived processes *)
26 gc_control: Gc.control; [@printer (fun fmt _ -> fprintf fmt "control")]
27 sharedmem_config: SharedMem.config;
28 tc_options: TypecheckerOptions.t;
29 parser_options: ParserOptions.t;
30 glean_options: GleanOptions.t;
31 symbol_write_options: SymbolWriteOptions.t;
32 formatter_override: Path.t option;
33 config_hash: string option;
34 (* A list of regexps for paths to ignore *)
35 ignored_paths: string list;
36 (* A list of extra paths to search for declarations *)
37 extra_paths: Path.t list;
38 warn_on_non_opt_build: bool;
40 [@@deriving show]
42 let filename =
43 Relative_path.from_root ~suffix:Config_file.file_path_relative_to_repo_root
45 let is_compatible c1 c2 =
46 (* This comparison can eventually be made more complex; we may not always
47 * need to restart hh_server, e.g. changing the path to the load script
48 * is immaterial*)
49 Poly.equal c1 c2
51 let make_gc_control config =
52 let { Gc.Control.minor_heap_size; space_overhead; _ } =
53 GlobalConfig.gc_control
55 let minor_heap_size =
56 int_ "gc_minor_heap_size" ~default:minor_heap_size config
58 let space_overhead =
59 int_ "gc_space_overhead" ~default:space_overhead config
61 { GlobalConfig.gc_control with Gc.Control.minor_heap_size; space_overhead }
63 let make_sharedmem_config config options local_config =
64 let { SharedMem.global_size; heap_size; shm_min_avail; _ } =
65 SharedMem.default_config
67 let shm_dirs = local_config.ServerLocalConfig.shm_dirs in
68 let global_size = int_ "sharedmem_global_size" ~default:global_size config in
69 let heap_size = int_ "sharedmem_heap_size" ~default:heap_size config in
70 let dep_table_pow = int_ "sharedmem_dep_table_pow" ~default:17 config in
71 let hash_table_pow = int_ "sharedmem_hash_table_pow" ~default:18 config in
72 let log_level = int_ "sharedmem_log_level" ~default:0 config in
73 let sample_rate = float_ "sharedmem_sample_rate" ~default:0.0 config in
74 let shm_dirs =
75 string_list
76 ~delim:(Str.regexp ",")
77 "sharedmem_dirs"
78 ~default:shm_dirs
79 config
81 let shm_min_avail =
82 int_ "sharedmem_minimum_available" ~default:shm_min_avail config
84 let (global_size, heap_size, dep_table_pow, hash_table_pow) =
85 match ServerArgs.ai_mode options with
86 | None -> (global_size, heap_size, dep_table_pow, hash_table_pow)
87 | Some ai_options ->
88 Ai_options.modify_shared_mem_sizes
89 global_size
90 heap_size
91 dep_table_pow
92 hash_table_pow
93 ai_options
96 SharedMem.global_size;
97 heap_size;
98 dep_table_pow;
99 hash_table_pow;
100 log_level;
101 sample_rate;
102 shm_dirs;
103 shm_min_avail;
106 let config_list_regexp = Str.regexp "[, \t]+"
108 let process_experimental sl =
109 match List.map sl String.lowercase with
110 | ["false"] -> SSet.empty
111 | ["true"] -> TypecheckerOptions.experimental_all
112 | features -> List.fold_left features ~f:SSet.add ~init:SSet.empty
114 let config_experimental_tc_features config =
115 match SMap.find_opt config "enable_experimental_tc_features" with
116 | None -> SSet.empty
117 | Some s ->
118 let sl = Str.split config_list_regexp s in
119 process_experimental sl
121 let process_migration_flags sl =
122 match sl with
123 | ["false"] -> SSet.empty
124 | ["true"] -> TypecheckerOptions.migration_flags_all
125 | flags ->
126 List.iter flags ~f:(fun s ->
127 if not (SSet.mem TypecheckerOptions.migration_flags_all s) then
128 failwith ("invalid migration flag: " ^ s));
129 List.fold_left flags ~f:SSet.add ~init:SSet.empty
131 let config_tc_migration_flags config =
132 SMap.find_opt config "enable_tc_migration_flags"
133 |> Option.value_map ~f:(Str.split config_list_regexp) ~default:[]
134 |> List.map ~f:String.lowercase
135 |> process_migration_flags
137 let convert_paths str =
138 let json = Hh_json.json_of_string ~strict:true str in
139 let l = Hh_json.get_array_exn json in
140 List.filter_map
141 ~f:(fun s ->
142 match s with
143 | Hh_json.JSON_String path -> Some path
144 | _ -> None)
147 let process_ignored_paths config =
148 SMap.find_opt config "ignored_paths"
149 |> Option.value_map ~f:convert_paths ~default:[]
151 let maybe_relative_path fn =
152 (* Note: this is not the same as calling realpath; the cwd is not
153 * necessarily the same as hh_server's root!!! *)
154 Path.make
155 begin
156 if Filename.is_relative fn then
157 Relative_path.(to_absolute (from_root fn))
158 else
162 let process_extra_paths config =
163 match SMap.find_opt config "extra_paths" with
164 | Some s -> Str.split config_list_regexp s |> List.map ~f:maybe_relative_path
165 | _ -> []
167 let process_untrusted_mode config =
168 match SMap.find_opt config "untrusted_mode" with
169 | Some s ->
170 if bool_of_string s then
171 let blacklist =
173 (* out of tree file access*)
174 "extra_paths";
175 (* potential resource abuse *)
176 "language_feature_logging";
179 let prefix_blacklist =
180 [(* potential resource abuse *) "gc_"; "sharedmem_"]
182 let invalid_keys =
183 SMap.filter
184 ~f:(fun ck _ ->
185 let ck = String.lowercase ck in
186 let exact_match =
187 List.find ~f:(fun bli -> String.equal bli ck) blacklist
189 let prefix_match =
190 List.find
191 ~f:(fun blp -> String_utils.string_starts_with ck blp)
192 prefix_blacklist
194 match (exact_match, prefix_match) with
195 | (None, None) -> false
196 | _ -> true)
197 config
198 |> SMap.keys
200 if not (List.is_empty invalid_keys) then
201 failwith
202 ( "option not permitted in untrusted_mode: "
203 ^ String.concat ~sep:", " invalid_keys )
204 else
205 failwith "untrusted_mode can only be enabled, not disabled"
206 | _ -> ()
208 let extract_auto_namespace_element ns_map element =
209 match element with
210 | (source, Hh_json.JSON_String target) -> (source, target) :: ns_map
211 | _ ->
212 (* This means the JSON we received is incorrect *)
213 ns_map
215 let convert_auto_namespace_to_map map =
216 let json = Hh_json.json_of_string ~strict:true map in
217 let pairs = Hh_json.get_object_exn json in
218 (* We do a fold instead of a map to filter
219 * out the incorrect entrie as we look at each item *)
220 List.fold_left ~init:[] ~f:extract_auto_namespace_element pairs
222 let prepare_auto_namespace_map config =
223 Option.value_map
224 (SMap.find_opt config "auto_namespace_map")
225 ~default:[]
226 ~f:convert_auto_namespace_to_map
228 let prepare_iset config config_name initial_values =
229 SMap.find_opt config config_name
230 |> Option.value_map ~f:(Str.split config_list_regexp) ~default:[]
231 |> List.map ~f:int_of_string
232 |> List.fold_right ~init:initial_values ~f:ISet.add
234 let prepare_error_codes_treated_strictly config =
235 prepare_iset config "error_codes_treated_strictly" (ISet.of_list [])
237 let prepare_allowed_decl_fixme_codes config =
238 prepare_iset config "allowed_decl_fixme_codes" (ISet.of_list [])
240 let load ~silent config_filename options : t * ServerLocalConfig.t =
241 let config_overrides = SMap.of_list @@ ServerArgs.config options in
242 let (config_hash, config) =
243 Config_file.parse_hhconfig
244 ~silent:true
245 (Relative_path.to_absolute config_filename)
247 let config =
248 Config_file.apply_overrides ~silent:true ~config ~overrides:config_overrides
250 process_untrusted_mode config;
251 let version = Config_file.parse_version (SMap.find_opt config "version") in
252 let local_config =
253 ServerLocalConfig.load ~silent ~current_version:version config_overrides
255 let local_config =
256 if Option.is_some (ServerArgs.ai_mode options) then
257 let open ServerLocalConfig in
258 let open Watchman in
260 local_config with
261 watchman =
262 { local_config.watchman with enabled = false; subscribe = false };
263 interrupt_on_watchman = false;
264 interrupt_on_client = false;
265 trace_parsing = false;
267 else
268 local_config
270 let ignored_paths = process_ignored_paths config in
271 let extra_paths = process_extra_paths config in
272 (* Since we use the unix alarm() for our timeouts, a timeout value of 0 means
273 * to wait indefinitely *)
274 let load_script_timeout = int_ "load_script_timeout" ~default:0 config in
275 let warn_on_non_opt_build =
276 bool_ "warn_on_non_opt_build" ~default:false config
278 let formatter_override =
279 Option.map (SMap.find_opt config "formatter_override") maybe_relative_path
281 let global_opts =
282 GlobalOptions.make
283 ?po_deregister_php_stdlib:(bool_opt "deregister_php_stdlib" config)
284 ?po_disable_static_closures:(bool_opt "disable_static_closures" config)
285 ?po_disable_array_typehint:
286 (bool_opt "disable_parse_array_typehint" config)
287 ?tco_disallow_array_typehint:(bool_opt "disallow_array_typehint" config)
288 ?tco_disallow_array_literal:(bool_opt "disallow_array_literal" config)
289 ?tco_num_local_workers:local_config.num_local_workers
290 ~tco_parallel_type_checking_threshold:
291 local_config.parallel_type_checking_threshold
292 ?tco_max_typechecker_worker_memory_mb:
293 local_config.max_typechecker_worker_memory_mb
294 ?tco_defer_class_declaration_threshold:
295 local_config.defer_class_declaration_threshold
296 ?tco_defer_class_memory_mb_threshold:
297 local_config.defer_class_memory_mb_threshold
298 ?tco_max_times_to_defer_type_checking:
299 local_config.max_times_to_defer_type_checking
300 ?tco_prefetch_deferred_files:(Some local_config.prefetch_deferred_files)
301 ?tco_remote_type_check_threshold:
302 ServerLocalConfig.RemoteTypeCheck.(
303 local_config.remote_type_check.recheck_threshold)
304 ?tco_remote_type_check:
305 ServerLocalConfig.RemoteTypeCheck.(
306 Some local_config.remote_type_check.enabled)
307 ?tco_remote_worker_key:local_config.remote_worker_key
308 ?tco_remote_check_id:local_config.remote_check_id
309 ?tco_remote_max_batch_size:
310 ServerLocalConfig.RemoteTypeCheck.(
311 Some local_config.remote_type_check.max_batch_size)
312 ?tco_remote_min_batch_size:
313 ServerLocalConfig.RemoteTypeCheck.(
314 Some local_config.remote_type_check.min_batch_size)
315 ?tco_num_remote_workers:
316 ServerLocalConfig.RemoteTypeCheck.(
317 Some local_config.remote_type_check.num_workers)
318 ?so_remote_version_specifier:local_config.remote_version_specifier
319 ?so_remote_worker_vfs_checkout_threshold:
320 ServerLocalConfig.RemoteTypeCheck.(
321 Some local_config.remote_type_check.worker_vfs_checkout_threshold)
322 ?so_naming_sqlite_path:local_config.naming_sqlite_path
323 ?tco_language_feature_logging:(bool_opt "language_feature_logging" config)
324 ?tco_unsafe_rx:(bool_opt "unsafe_rx" config)
325 ?tco_disallow_scrutinee_case_value_type_mismatch:
326 (bool_opt "disallow_scrutinee_case_value_type_mismatch" config)
327 ?tco_timeout:(int_opt "timeout" config)
328 ?tco_disallow_invalid_arraykey:
329 (bool_opt "disallow_invalid_arraykey" config)
330 ?tco_disallow_byref_dynamic_calls:
331 (bool_opt "disallow_byref_dynamic_calls" config)
332 ?tco_disallow_byref_calls:(bool_opt "disallow_byref_calls" config)
333 ?po_disable_lval_as_an_expression:
334 (bool_opt "disable_lval_as_an_expression" config)
335 ~allowed_fixme_codes_strict:
336 (prepare_iset config "allowed_fixme_codes_strict" ISet.empty)
337 ~allowed_fixme_codes_partial:
338 (prepare_iset config "allowed_fixme_codes_partial" ISet.empty)
339 ~codes_not_raised_partial:
340 (prepare_iset config "codes_not_raised_partial" ISet.empty)
341 ~po_auto_namespace_map:(prepare_auto_namespace_map config)
342 ~tco_experimental_features:(config_experimental_tc_features config)
343 ~tco_log_inference_constraints:
344 (ServerArgs.log_inference_constraints options)
345 ~tco_migration_flags:(config_tc_migration_flags config)
346 ~tco_shallow_class_decl:local_config.ServerLocalConfig.shallow_class_decl
347 ~po_allow_unstable_features:
348 local_config.ServerLocalConfig.allow_unstable_features
349 ~profile_type_check_duration_threshold:
350 local_config.ServerLocalConfig.profile_type_check_duration_threshold
351 ~profile_type_check_twice:
352 local_config.ServerLocalConfig.profile_type_check_twice
353 ?profile_owner:local_config.ServerLocalConfig.profile_owner
354 ~profile_desc:local_config.ServerLocalConfig.profile_desc
355 ?tco_like_type_hints:(bool_opt "like_type_hints" config)
356 ?tco_union_intersection_type_hints:
357 (bool_opt "union_intersection_type_hints" config)
358 ?tco_coeffects:(bool_opt "call_coeffects" config)
359 ?tco_coeffects_local:(bool_opt "local_coeffects" config)
360 ?tco_like_casts:(bool_opt "like_casts" config)
361 ?tco_simple_pessimize:(float_opt "simple_pessimize" config)
362 ?tco_complex_coercion:(bool_opt "complex_coercion" config)
363 ?tco_disable_partially_abstract_typeconsts:
364 (bool_opt "disable_partially_abstract_typeconsts" config)
365 ~error_codes_treated_strictly:
366 (prepare_error_codes_treated_strictly config)
367 ?tco_check_xhp_attribute:(bool_opt "check_xhp_attribute" config)
368 ?tco_check_redundant_generics:(bool_opt "check_redundant_generics" config)
369 ?tco_disallow_unresolved_type_variables:
370 (bool_opt "disallow_unresolved_type_variables" config)
371 ?tco_disallow_trait_reuse:(bool_opt "disallow_trait_reuse" config)
372 ?tco_disallow_invalid_arraykey_constraint:
373 (bool_opt "disallow_invalid_arraykey_constraint" config)
374 ?po_enable_class_level_where_clauses:
375 (bool_opt "class_level_where_clauses" config)
376 ?po_disable_legacy_soft_typehints:
377 (bool_opt "disable_legacy_soft_typehints" config)
378 ?po_disallow_toplevel_requires:
379 (bool_opt "disallow_toplevel_requires" config)
380 ~po_allowed_decl_fixme_codes:(prepare_allowed_decl_fixme_codes config)
381 ?po_allow_new_attribute_syntax:
382 (bool_opt "allow_new_attribute_syntax" config)
383 ?po_disable_legacy_attribute_syntax:
384 (bool_opt "disable_legacy_attribute_syntax" config)
385 ?tco_const_attribute:(bool_opt "const_attribute" config)
386 ?po_const_default_func_args:(bool_opt "const_default_func_args" config)
387 ?po_const_default_lambda_args:
388 (bool_opt "const_default_lambda_args" config)
389 ?po_disallow_silence:(bool_opt "disallow_silence" config)
390 ?tco_global_inference:(bool_opt "global_inference" config)
391 ?tco_gi_reinfer_types:(string_list_opt "reinfer_types" config)
392 ?tco_const_static_props:(bool_opt "const_static_props" config)
393 ?po_abstract_static_props:(bool_opt "abstract_static_props" config)
394 ?po_disable_unset_class_const:
395 (bool_opt "disable_unset_class_const" config)
396 ~po_parser_errors_only:(Option.is_some (ServerArgs.ai_mode options))
397 ?tco_check_attribute_locations:
398 (bool_opt "check_attribute_locations" config)
399 ?glean_service:(string_opt "glean_service" config)
400 ?glean_hostname:(string_opt "glean_hostname" config)
401 ?glean_port:(int_opt "glean_port" config)
402 ?glean_reponame:(string_opt "glean_reponame" config)
403 ?symbol_write_root_path:(string_opt "symbol_write_root_path" config)
404 ?symbol_write_hhi_path:(string_opt "symbol_write_hhi_path" config)
405 ?symbol_write_ignore_paths:
406 (string_list_opt "symbol_write_ignore_paths" config)
407 ?symbol_write_index_paths:
408 (string_list_opt "symbol_write_index_paths" config)
409 ?symbol_write_include_hhi:(bool_opt "symbol_write_include_hhi" config)
410 ?po_disallow_func_ptrs_in_constants:
411 (bool_opt "disallow_func_ptrs_in_constants" config)
412 ?tco_error_php_lambdas:(bool_opt "error_php_lambdas" config)
413 ?tco_disallow_discarded_nullable_awaitables:
414 (bool_opt "disallow_discarded_nullable_awaitables" config)
415 ?po_disable_xhp_element_mangling:
416 (bool_opt "disable_xhp_element_mangling" config)
417 ?po_disable_xhp_children_declarations:
418 (bool_opt "disable_xhp_children_declarations" config)
419 ?po_enable_xhp_class_modifier:
420 (bool_opt "enable_xhp_class_modifier" config)
421 ?po_disable_modes:(bool_opt "disable_modes" config)
422 ?po_disable_hh_ignore_error:(bool_opt "disable_hh_ignore_error" config)
423 ?tco_method_call_inference:(bool_opt "method_call_inference" config)
424 ?tco_report_pos_from_reason:(bool_opt "report_pos_from_reason" config)
425 ?tco_typecheck_sample_rate:(float_opt "typecheck_sample_rate" config)
426 ?tco_enable_sound_dynamic:(bool_opt "enable_sound_dynamic_type" config)
427 ?po_disallow_hash_comments:(bool_opt "disallow_hash_comments" config)
428 ?po_disallow_fun_and_cls_meth_pseudo_funcs:
429 (bool_opt "disallow_fun_and_cls_meth_pseudo_funcs" config)
430 ~tco_use_direct_decl_parser:
431 local_config.ServerLocalConfig.use_direct_decl_parser
432 ~tco_ifc_enabled:(ServerArgs.enable_ifc options)
433 ?po_enable_enum_classes:(bool_opt "enable_enum_classes" config)
434 ?po_enable_enum_supertyping:(bool_opt "enable_enum_supertyping" config)
435 ?po_array_unification:(bool_opt "array_unification" config)
438 Errors.allowed_fixme_codes_strict :=
439 GlobalOptions.allowed_fixme_codes_strict global_opts;
440 Errors.allowed_fixme_codes_partial :=
441 GlobalOptions.allowed_fixme_codes_partial global_opts;
442 Errors.codes_not_raised_partial :=
443 GlobalOptions.codes_not_raised_partial global_opts;
444 Errors.error_codes_treated_strictly :=
445 GlobalOptions.error_codes_treated_strictly global_opts;
446 Errors.report_pos_from_reason :=
447 GlobalOptions.tco_report_pos_from_reason global_opts;
449 version;
450 load_script_timeout;
451 gc_control = make_gc_control config;
452 sharedmem_config = make_sharedmem_config config options local_config;
453 tc_options = global_opts;
454 parser_options = global_opts;
455 glean_options = global_opts;
456 symbol_write_options = global_opts;
457 formatter_override;
458 config_hash = Some config_hash;
459 ignored_paths;
460 extra_paths;
461 warn_on_non_opt_build;
463 local_config )
465 (* useful in testing code *)
466 let default_config =
468 version = Config_file.Opaque_version None;
469 load_script_timeout = 0;
470 gc_control = GlobalConfig.gc_control;
471 sharedmem_config = SharedMem.default_config;
472 tc_options = TypecheckerOptions.default;
473 glean_options = GleanOptions.default;
474 symbol_write_options = SymbolWriteOptions.default;
475 parser_options = ParserOptions.default;
476 formatter_override = None;
477 config_hash = None;
478 ignored_paths = [];
479 extra_paths = [];
480 warn_on_non_opt_build = false;
483 let set_parser_options config popt = { config with parser_options = popt }
485 let set_tc_options config tcopt = { config with tc_options = tcopt }
487 let set_glean_options config gleanopt = { config with glean_options = gleanopt }
489 let set_symbol_write_options config swriteopt =
490 { config with symbol_write_options = swriteopt }
492 let gc_control config = config.gc_control
494 let sharedmem_config config = config.sharedmem_config
496 let typechecker_options config = config.tc_options
498 let parser_options config = config.parser_options
500 let glean_options config = config.glean_options
502 let symbol_write_options config = config.symbol_write_options
504 let formatter_override config = config.formatter_override
506 let config_hash config = config.config_hash
508 let ignored_paths config = config.ignored_paths
510 let extra_paths config = config.extra_paths
512 let version config = config.version
514 let warn_on_non_opt_build config = config.warn_on_non_opt_build