Dead code: decl_tany
[hiphop-php.git] / hphp / hack / src / typing / typing_env.ml
blob7d527be1cad85148a165342a15ebfe5f6211203b
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_prelude
11 open Common
12 open Decl_env
13 open Typing_env_types
14 open Typing_defs
15 open Aast
16 open Typing_env_return_info
17 module Dep = Typing_deps.Dep
18 module Inf = Typing_inference_env
19 module LID = Local_id
20 module SG = SN.Superglobals
21 module LEnvC = Typing_per_cont_env
22 module C = Typing_continuations
23 module Cls = Decl_provider.Class
24 module Fake = Typing_fake_members
25 module ITySet = Internal_type_set
26 module TPEnv = Type_parameter_env
27 module KDefs = Typing_kinding_defs
28 module TySet = Typing_set
30 type class_or_typedef_result =
31 | ClassResult of Typing_classes_heap.Api.t
32 | TypedefResult of Typing_defs.typedef_type
34 let show_env _ = "<env>"
36 let pp_env _ _ = Printf.printf "%s\n" "<env>"
38 let get_tcopt env = env.genv.tcopt
40 let map_tcopt env ~f =
41 let tcopt = f env.genv.tcopt in
42 let genv = { env.genv with tcopt } in
43 { env with genv }
45 let get_deps_mode env = Provider_context.get_deps_mode env.decl_env.Decl_env.ctx
47 let get_ctx env = env.decl_env.Decl_env.ctx
49 let get_file env = env.genv.file
51 let get_tracing_info env = env.tracing_info
53 let set_log_level env key log_level =
54 { env with log_levels = SMap.add key log_level env.log_levels }
56 let get_log_level env key =
57 Option.value (SMap.find_opt key env.log_levels) ~default:0
59 let env_log_function = ref (fun _pos _name _old_env _new_env -> ())
61 let set_env_log_function f = env_log_function := f
63 let log_env_change_ :
64 type res. string -> ?level:int -> env -> env * res -> env * res =
65 fun name ?(level = 1) old_env (new_env, res) ->
66 ( if get_log_level new_env name >= 1 || get_log_level new_env "env" >= level
67 then
68 let pos =
69 Option.value
70 (Inf.get_current_pos_from_tyvar_stack old_env.inference_env)
71 ~default:old_env.function_pos
73 !env_log_function pos name old_env new_env );
74 (new_env, res)
76 let log_env_change name ?(level = 1) old_env new_env =
77 let (env, ()) = log_env_change_ name ~level old_env (new_env, ()) in
78 env
80 let wrap_inference_env_call :
81 type res. env -> (Inf.t -> Inf.t * res) -> env * res =
82 fun env f ->
83 let (inference_env, res) = f env.inference_env in
84 ({ env with inference_env }, res)
86 let wrap_inference_env_call_res : type res. env -> (Inf.t -> res) -> res =
87 fun env f ->
88 let (_env, res) =
89 wrap_inference_env_call env (fun env ->
90 let res = f env in
91 (env, res))
93 res
95 let wrap_inference_env_call_env : env -> (Inf.t -> Inf.t) -> env =
96 fun env f ->
97 let (env, ()) =
98 wrap_inference_env_call env (fun env ->
99 let env = f env in
100 (env, ()))
104 let expand_var env r v =
105 wrap_inference_env_call env (fun env -> Inf.expand_var env r v)
107 let fresh_type_reason ?variance env r =
108 log_env_change_ "fresh_type_reason" env
109 @@ wrap_inference_env_call env (fun env ->
110 Inf.fresh_type_reason ?variance env r)
112 let fresh_type env p =
113 log_env_change_ "fresh_type" env
114 @@ wrap_inference_env_call env (fun env -> Inf.fresh_type env p)
116 let fresh_invariant_type_var env p =
117 log_env_change_ "fresh_invariant_type_var" env
118 @@ wrap_inference_env_call env (fun env -> Inf.fresh_invariant_type_var env p)
120 let new_global_tyvar env ?i r =
121 log_env_change_ "new_global_tyvar" env
122 @@ wrap_inference_env_call env (fun env -> Inf.new_global_tyvar env ?i r)
124 let add_subtype_prop env prop =
125 log_env_change "add_subtype_prop" env
126 @@ wrap_inference_env_call_env env (fun env -> Inf.add_subtype_prop env prop)
128 let is_global_tyvar env var =
129 wrap_inference_env_call_res env (fun env -> Inf.is_global_tyvar env var)
131 let get_global_tyvar_reason env var =
132 wrap_inference_env_call_res env (fun env ->
133 Inf.get_global_tyvar_reason env var)
135 let empty_bounds = TySet.empty
137 let tyvar_is_solved_or_skip_global env var =
138 Inf.tyvar_is_solved_or_skip_global env.inference_env var
140 let make_tyvar_no_more_occur_in_tyvar env v ~no_more_in:v' =
141 wrap_inference_env_call_env env (fun env ->
142 Inf.make_tyvar_no_more_occur_in_tyvar env v ~no_more_in:v')
144 let not_implemented s _ =
145 failwith (Printf.sprintf "Function %s not implemented" s)
147 type simplify_unions = env -> locl_ty -> env * locl_ty
149 let (simplify_unions_ref : simplify_unions ref) =
150 ref (not_implemented "simplify_unions")
152 let simplify_unions x = !simplify_unions_ref x
154 let bind env v ty =
155 wrap_inference_env_call_env env (fun env -> Inf.bind env v ty)
157 (** Unions and intersections containing unsolved type variables may remain
158 in an unsimplified form once those type variables get solved.
160 For example, consider the union (#1 | int) where #1 is an unsolved type variable.
161 If #1 gets solved to int, then this union will remain in the unsimplified form
162 (int | int) which compromise the robustness of some of our logic and might
163 cause performance issues (by creating big unsimplified unions).
165 To solve this problem, we wrap each union and intersection in a type var,
166 so we'd get `#2 -> (#1 | int)` (This is done in Typing_union and
167 Typing_intersection), and register that #1 occurs in #2 in
168 [env.tyvar_occurrences]. Then when #1 gets solved, we simplify #2.
170 This function deals with this simplification.
172 The simplification is recursive: simplifying a type variable will
173 trigger simplification of its own occurrences. *)
174 let simplify_occurrences env v =
175 let rec simplify_occurrences env v ~seen_tyvars =
176 let vars = Inf.get_tyvar_occurrences env.inference_env v in
177 let (env, seen_tyvars) =
178 ISet.fold
179 (fun v' (env, seen_tyvars) ->
180 (* This type variable is now solved and does not contain any unsolved
181 type variable, so we can remove it from its occurrences. *)
182 let env = make_tyvar_no_more_occur_in_tyvar env v ~no_more_in:v' in
183 (* Only simplify when the type of v' does not contain any more
184 unsolved type variables. *)
185 if not @@ Inf.contains_unsolved_tyvars env.inference_env v' then
186 simplify_type_of_var env v' ~seen_tyvars
187 else
188 (env, seen_tyvars))
189 vars
190 (env, seen_tyvars)
192 (env, seen_tyvars)
193 and simplify_type_of_var env v ~seen_tyvars =
194 if ISet.mem v seen_tyvars then
195 (* TODO raise exception. *)
196 (env, seen_tyvars)
197 else
198 let seen_tyvars = ISet.add v seen_tyvars in
199 match Inf.get_direct_binding env.inference_env v with
200 | None -> failwith "Can only simplify type of bounded variables"
201 | Some ty ->
202 (* Only simplify the type of variables which are bound directly to a
203 concrete type to preserve the variable aliasings and save some memory. *)
204 let env =
205 match get_node ty with
206 | Tvar _ -> env
207 | _ ->
208 let (env, ty) = simplify_unions env ty in
209 (* we only call this function when v does not recursively contain unsolved
210 type variables, so ty here should not contain unsolved type variables and
211 it is safe to simply bind it without reupdating the type var occurrences. *)
212 let env = bind env v ty in
215 simplify_occurrences env v ~seen_tyvars
217 if not @@ Inf.contains_unsolved_tyvars env.inference_env v then
218 fst @@ simplify_occurrences env v ~seen_tyvars:ISet.empty
219 else
222 let add env ?(tyvar_pos = Pos.none) v ty =
223 let env =
224 wrap_inference_env_call_env env (fun env -> Inf.add env ~tyvar_pos v ty)
226 let env = simplify_occurrences env v in
229 let get_type env r var =
230 wrap_inference_env_call env (fun env -> Inf.get_type env r var)
232 let expand_type env ty =
233 wrap_inference_env_call env (fun env -> Inf.expand_type env ty)
235 let expand_internal_type env ty =
236 wrap_inference_env_call env (fun env -> Inf.expand_internal_type env ty)
238 let get_tyvar_pos env var =
239 wrap_inference_env_call_res env (fun env -> Inf.get_tyvar_pos env var)
241 let get_tyvar_lower_bounds env var =
242 wrap_inference_env_call_res env (fun env ->
243 Inf.get_tyvar_lower_bounds env var)
245 let set_tyvar_lower_bounds env var tys =
246 wrap_inference_env_call_env env (fun env ->
247 Inf.set_tyvar_lower_bounds env var tys)
249 let get_tyvar_upper_bounds env var =
250 wrap_inference_env_call_res env (fun env ->
251 Inf.get_tyvar_upper_bounds env var)
253 let set_tyvar_upper_bounds env var tys =
254 wrap_inference_env_call_env env (fun env ->
255 Inf.set_tyvar_upper_bounds env var tys)
257 let get_tyvar_appears_covariantly env var =
258 wrap_inference_env_call_res env (fun env ->
259 Inf.get_tyvar_appears_covariantly env var)
261 let set_tyvar_appears_covariantly env var =
262 wrap_inference_env_call_env env (fun env ->
263 Inf.set_tyvar_appears_covariantly env var)
265 let get_tyvar_appears_contravariantly env var =
266 wrap_inference_env_call_res env (fun env ->
267 Inf.get_tyvar_appears_contravariantly env var)
269 let set_tyvar_appears_contravariantly env var =
270 wrap_inference_env_call_env env (fun env ->
271 Inf.set_tyvar_appears_contravariantly env var)
273 let get_tyvar_appears_invariantly env var =
274 wrap_inference_env_call_res env (fun env ->
275 Inf.get_tyvar_appears_invariantly env var)
277 let get_tyvar_eager_solve_fail env var =
278 wrap_inference_env_call_res env (fun env ->
279 Inf.get_tyvar_eager_solve_fail env var)
281 let set_tyvar_eager_solve_fail env var =
282 wrap_inference_env_call_env env (fun env ->
283 Inf.set_tyvar_eager_solve_fail env var)
285 let get_tyvar_type_consts env var =
286 wrap_inference_env_call_res env (fun env -> Inf.get_tyvar_type_consts env var)
288 let get_tyvar_type_const env var tid =
289 wrap_inference_env_call_res env (fun env ->
290 Inf.get_tyvar_type_const env var tid)
292 let set_tyvar_type_const env var tconstid ty =
293 wrap_inference_env_call_env env (fun env ->
294 Inf.set_tyvar_type_const env var tconstid ty)
296 let get_current_tyvars env =
297 wrap_inference_env_call_res env Inf.get_current_tyvars
299 let open_tyvars env p =
300 wrap_inference_env_call_env env (fun env -> Inf.open_tyvars env p)
302 let close_tyvars env = wrap_inference_env_call_env env Inf.close_tyvars
304 let extract_global_inference_env env =
305 wrap_inference_env_call env (fun env -> Inf.extract_global_inference_env env)
307 let wrap_ty_in_var env r ty =
308 wrap_inference_env_call env (fun env -> Inf.wrap_ty_in_var env r ty)
310 let get_shape_field_name = function
311 | Ast_defs.SFlit_int (_, s)
312 | Ast_defs.SFlit_str (_, s) ->
314 | Ast_defs.SFclass_const ((_, s1), (_, s2)) -> s1 ^ "::" ^ s2
316 let get_shape_field_name_pos = function
317 | Ast_defs.SFlit_int (p, _)
318 | Ast_defs.SFlit_str (p, _)
319 | Ast_defs.SFclass_const ((p, _), _) ->
322 let next_cont_opt env = LEnvC.get_cont_option C.Next env.lenv.per_cont_env
324 let all_continuations env = LEnvC.all_continuations env.lenv.per_cont_env
326 let get_tpenv env =
327 match next_cont_opt env with
328 | None -> TPEnv.empty
329 | Some entry -> entry.Typing_per_cont_env.tpenv
331 let get_global_tpenv env = env.global_tpenv
333 let get_pos_and_kind_of_generic env name =
334 match TPEnv.get_with_pos name (get_tpenv env) with
335 | Some r -> Some r
336 | None -> TPEnv.get_with_pos name env.global_tpenv
338 let get_lower_bounds env name tyargs =
339 let tpenv = get_tpenv env in
340 let local = TPEnv.get_lower_bounds tpenv name tyargs in
341 let global = TPEnv.get_lower_bounds env.global_tpenv name tyargs in
342 TySet.union local global
344 let get_upper_bounds env name tyargs =
345 let tpenv = get_tpenv env in
346 let local = TPEnv.get_upper_bounds tpenv name tyargs in
347 let global = TPEnv.get_upper_bounds env.global_tpenv name tyargs in
348 TySet.union local global
350 let get_reified env name =
351 let tpenv = get_tpenv env in
352 let local = TPEnv.get_reified tpenv name in
353 let global = TPEnv.get_reified env.global_tpenv name in
354 match (local, global) with
355 | (Reified, _)
356 | (_, Reified) ->
357 Reified
358 | (SoftReified, _)
359 | (_, SoftReified) ->
360 SoftReified
361 | _ -> Erased
363 let get_enforceable env name =
364 let tpenv = get_tpenv env in
365 let local = TPEnv.get_enforceable tpenv name in
366 let global = TPEnv.get_enforceable env.global_tpenv name in
367 local || global
369 let get_newable env name =
370 let tpenv = get_tpenv env in
371 let local = TPEnv.get_newable tpenv name in
372 let global = TPEnv.get_newable env.global_tpenv name in
373 local || global
375 (* Get bounds that are both an upper and lower of a given generic *)
376 let get_equal_bounds env name tyargs =
377 let lower = get_lower_bounds env name tyargs in
378 let upper = get_upper_bounds env name tyargs in
379 TySet.inter lower upper
381 let env_with_tpenv env tpenv =
383 env with
384 lenv =
386 env.lenv with
387 per_cont_env =
388 Typing_per_cont_env.(
389 update_cont_entry C.Next env.lenv.per_cont_env (fun entry ->
390 { entry with tpenv }));
394 let env_with_global_tpenv env global_tpenv = { env with global_tpenv }
396 let add_upper_bound_global env name ty =
397 let tpenv =
398 let (env, ty) = expand_type env ty in
399 match deref ty with
400 | (r, Tgeneric (formal_super, [])) ->
401 TPEnv.add_lower_bound
402 env.global_tpenv
403 formal_super
404 (mk (r, Tgeneric (name, [])))
405 | (_r, Tgeneric (_formal_super, _targs)) ->
406 (* TODO(T70068435) Revisit this when implementing bounds on HK generic vars *)
407 env.global_tpenv
408 | _ -> env.global_tpenv
410 { env with global_tpenv = TPEnv.add_upper_bound tpenv name ty }
412 (* Add a single new upper bound [ty] to generic parameter [name] in the local
413 * type parameter environment of [env].
414 * If the optional [intersect] operation is supplied, then use this to avoid
415 * adding redundant bounds by merging the type with existing bounds. This makes
416 * sense because a conjunction of upper bounds
417 * (T <: t1) /\ ... /\ (T <: tn)
418 * is equivalent to a single upper bound
419 * T <: (t1 & ... & tn)
421 let add_upper_bound ?intersect env name ty =
422 env_with_tpenv env (TPEnv.add_upper_bound ?intersect (get_tpenv env) name ty)
424 (* Add a single new upper lower [ty] to generic parameter [name] in the
425 * local type parameter environment [env].
426 * If the optional [union] operation is supplied, then use this to avoid
427 * adding redundant bounds by merging the type with existing bounds. This makes
428 * sense because a conjunction of lower bounds
429 * (t1 <: T) /\ ... /\ (tn <: T)
430 * is equivalent to a single lower bound
431 * (t1 | ... | tn) <: T
433 let add_lower_bound ?union env name ty =
434 env_with_tpenv env (TPEnv.add_lower_bound ?union (get_tpenv env) name ty)
436 (* Add type parameters to environment, initially with no bounds.
437 * Existing type parameters with the same name will be overridden. *)
438 let add_generic_parameters env tparaml =
439 env_with_tpenv env (TPEnv.add_generic_parameters (get_tpenv env) tparaml)
441 let is_generic_parameter env name =
442 TPEnv.mem name (get_tpenv env) || SSet.mem name env.fresh_typarams
444 let get_generic_parameters env =
445 TPEnv.get_names (TPEnv.union (get_tpenv env) env.global_tpenv)
447 let get_tpenv_size env =
448 TPEnv.size (get_tpenv env) + TPEnv.size env.global_tpenv
450 let is_consistent env = TPEnv.is_consistent (get_tpenv env)
452 let mark_inconsistent env =
453 env_with_tpenv env (TPEnv.mark_inconsistent (get_tpenv env))
455 (* Generate a fresh generic parameter with a specified prefix but distinct
456 * from all generic parameters in the environment *)
457 let add_fresh_generic_parameter_by_kind env prefix kind =
458 let rec iterate i =
459 let name = Printf.sprintf "%s#%d" prefix i in
460 if is_generic_parameter env name then
461 iterate (i + 1)
462 else
463 name
465 let name = iterate 1 in
466 let env = { env with fresh_typarams = SSet.add name env.fresh_typarams } in
467 let env =
468 env_with_tpenv env (TPEnv.add ~def_pos:Pos.none name kind (get_tpenv env))
470 (env, name)
472 let add_fresh_generic_parameter env prefix ~reified ~enforceable ~newable =
473 let kind =
474 KDefs.
476 lower_bounds = empty_bounds;
477 upper_bounds = empty_bounds;
478 reified;
479 enforceable;
480 newable;
481 parameters = [];
484 add_fresh_generic_parameter_by_kind env prefix kind
486 let is_fresh_generic_parameter name =
487 String.contains name '#' && not (DependentKind.is_generic_dep_ty name)
489 let tparams_visitor env =
490 object (this)
491 inherit [SSet.t] Type_visitor.locl_type_visitor
493 method! on_tgeneric acc _ s _ =
494 (* as for tnewtype: not traversing args, although they may contain Tgenerics *)
495 SSet.add s acc
497 (* Perserving behavior but this seems incorrect to me since a newtype may
498 * contain type arguments with generics
500 method! on_tdependent acc _ _ _ = acc
502 method! on_tnewtype acc _ _ _ _ = acc
504 method! on_tvar acc r ix =
505 let (_env, ty) = expand_var env r ix in
506 match get_node ty with
507 | Tvar _ -> acc
508 | _ -> this#on_type acc ty
511 let get_tparams_aux env acc ty = (tparams_visitor env)#on_type acc ty
513 let get_tparams env ty = get_tparams_aux env SSet.empty ty
515 let get_tpenv_tparams env =
516 TPEnv.fold
517 begin
518 fun _x
519 KDefs.
521 lower_bounds;
522 upper_bounds;
523 reified = _;
524 enforceable = _;
525 newable = _;
526 (* FIXME what to do here? it seems dangerous to just traverse *)
527 parameters = _;
529 acc ->
530 let folder ty acc =
531 let (_env, ty) = expand_type env ty in
532 match get_node ty with
533 | Tgeneric _ -> acc
534 | _ -> get_tparams_aux env acc ty
536 TySet.fold folder lower_bounds @@ TySet.fold folder upper_bounds acc
538 (get_tpenv env)
539 SSet.empty
541 (* Replace types for locals with empty environment *)
542 let env_with_locals env locals =
543 { env with lenv = { env.lenv with per_cont_env = locals } }
545 (* This is used whenever we start checking a method. Retain tpenv from the class type parameters *)
546 let reinitialize_locals env =
547 env_with_locals
549 LEnvC.(initial_locals { empty_entry with tpenv = get_tpenv env })
551 let initial_local tpenv local_reactive =
553 per_cont_env = LEnvC.(initial_locals { empty_entry with tpenv });
554 local_using_vars = LID.Set.empty;
555 local_mutability = LID.Map.empty;
556 local_reactive;
559 let empty ?origin ?(mode = FileInfo.Mstrict) ctx file ~droot =
561 function_pos = Pos.none;
562 fresh_typarams = SSet.empty;
563 lenv = initial_local TPEnv.empty Nonreactive;
564 in_loop = false;
565 in_try = false;
566 in_case = false;
567 in_expr_tree = false;
568 inside_constructor = false;
569 decl_env = { mode; droot; ctx };
570 tracing_info =
571 Option.map origin ~f:(fun origin -> { Decl_counters.origin; file });
572 genv =
574 tcopt = Provider_context.get_tcopt ctx;
575 return =
577 (* Actually should get set straight away anyway *)
578 return_type =
579 { et_type = mk (Reason.Rnone, Tunion []); et_enforced = false };
580 return_disposable = false;
581 return_mutable = false;
582 return_explicit = false;
583 return_void_to_rx = false;
584 return_dynamically_callable = false;
586 params = LID.Map.empty;
587 condition_types = SMap.empty;
588 self = None;
589 static = false;
590 val_kind = Other;
591 parent = None;
592 fun_kind = Ast_defs.FSync;
593 fun_mutable = None;
594 file;
596 global_tpenv = TPEnv.empty;
597 log_levels = TypecheckerOptions.log_levels (Provider_context.get_tcopt ctx);
598 inference_env = Inf.empty_inference_env;
599 allow_wildcards = false;
600 big_envs = ref [];
601 pessimize = false;
604 let set_env_reactive env reactive =
605 { env with lenv = { env.lenv with local_reactive = reactive } }
607 let set_env_pessimize env =
608 let pessimize_coefficient =
609 TypecheckerOptions.simple_pessimize (get_tcopt env)
611 let pessimize =
612 Pos.pessimize_enabled env.function_pos pessimize_coefficient
614 { env with pessimize }
616 let set_env_function_pos env function_pos = { env with function_pos }
618 let set_condition_type env n ty =
620 env with
621 genv =
622 { env.genv with condition_types = SMap.add n ty env.genv.condition_types };
625 let get_condition_type env n = SMap.find_opt n env.genv.condition_types
627 (* Some form (strict/shallow/local) of reactivity *)
628 let env_local_reactive env =
629 not (equal_reactivity (env_reactivity env) Nonreactive)
631 let function_is_mutable env = env.genv.fun_mutable
633 let set_fun_mutable env mut =
634 { env with genv = { env.genv with fun_mutable = mut } }
636 let error_if_reactive_context env f =
637 if env_local_reactive env && not (TypecheckerOptions.unsafe_rx env.genv.tcopt)
638 then
639 f ()
641 let make_depend_on_class env class_name =
642 let dep = Dep.Class class_name in
643 Option.iter env.decl_env.droot (fun root ->
644 Typing_deps.add_idep (get_deps_mode env) root dep);
647 let make_depend_on_constructor env class_name =
648 make_depend_on_class env class_name;
649 let dep = Dep.Cstr class_name in
650 Option.iter env.decl_env.droot (fun root ->
651 Typing_deps.add_idep (get_deps_mode env) root dep);
654 let make_depend_on_class_def env x cd =
655 match cd with
656 | Some cd when Pos.is_hhi (Cls.pos cd) -> ()
657 | _ -> make_depend_on_class env x
659 let print_size _kind _name obj =
660 match obj with
661 | None -> obj
662 | Some _r ->
663 (* Printf.printf
664 "%s %s: %d\n"
665 kind
666 name
667 (Obj.reachable_words (Obj.repr r) * (Sys.word_size / 8));*)
670 let get_typedef env x =
671 let res =
672 print_size
673 "type"
675 (Decl_provider.get_typedef
676 ?tracing_info:(get_tracing_info env)
677 (get_ctx env)
680 match res with
681 | Some td when Pos.is_hhi td.td_pos -> res
682 | _ ->
683 make_depend_on_class env x;
686 let is_typedef env x =
687 match Naming_provider.get_type_kind (get_ctx env) x with
688 | Some Naming_types.TTypedef -> true
689 | _ -> false
691 let get_class (env : env) (name : string) : Cls.t option =
692 let res =
693 print_size
694 "class"
695 name
696 (Decl_provider.get_class
697 ?tracing_info:(get_tracing_info env)
698 (get_ctx env)
699 name)
701 make_depend_on_class_def env name res;
704 let get_class_or_typedef env x =
705 if is_typedef env x then
706 match get_typedef env x with
707 | None -> None
708 | Some td -> Some (TypedefResult td)
709 else
710 match get_class env x with
711 | None -> None
712 | Some cd -> Some (ClassResult cd)
714 let get_class_dep env x =
715 let res = get_class env x in
716 match res with
717 | Some cd when Pos.is_hhi (Cls.pos cd) -> res
718 | _ ->
719 Decl_env.add_extends_dependency env.decl_env x;
722 let get_fun env x =
723 let res =
724 print_size
725 "fun"
727 (Decl_provider.get_fun
728 ?tracing_info:(get_tracing_info env)
729 (get_ctx env)
732 match res with
733 | Some fd when Pos.is_hhi fd.fe_pos -> res
734 | _ ->
735 let dep = Typing_deps.Dep.Fun x in
736 Option.iter env.decl_env.Decl_env.droot (fun root ->
737 Typing_deps.add_idep (get_deps_mode env) root dep);
740 let get_enum_constraint env x =
741 match get_class env x with
742 | None -> None
743 | Some tc ->
744 (match Cls.enum_type tc with
745 | None -> None
746 | Some e -> e.te_constraint)
748 let env_with_mut env local_mutability =
749 { env with lenv = { env.lenv with local_mutability } }
751 let get_env_mutability env = env.lenv.local_mutability
753 let get_enum env x =
754 match get_class_or_typedef env x with
755 | Some (ClassResult tc) when Option.is_some (Cls.enum_type tc) -> Some tc
756 | _ -> None
758 let is_enum env x =
759 match get_enum env x with
760 | Some cls ->
761 (match Cls.enum_type cls with
762 | Some enum_type -> not enum_type.te_enum_class
763 | None -> false (* we know this is impossible due to get_enum *))
764 | None -> false
766 let is_enum_class env x =
767 match get_enum env x with
768 | Some cls ->
769 (match Cls.enum_type cls with
770 | Some enum_type -> enum_type.te_enum_class
771 | None -> false (* we know this is impossible due to get_enum *))
772 | None -> false
774 let get_typeconst env class_ mid =
775 if not (Pos.is_hhi (Cls.pos class_)) then begin
776 let dep = Dep.Const (Cls.name class_, mid) in
777 make_depend_on_class env (Cls.name class_);
778 Option.iter env.decl_env.droot (fun root ->
779 Typing_deps.add_idep (get_deps_mode env) root dep)
780 end;
781 Cls.get_typeconst class_ mid
783 (* Used to access class constants. *)
784 let get_const env class_ mid =
785 if not (Pos.is_hhi (Cls.pos class_)) then begin
786 let dep = Dep.Const (Cls.name class_, mid) in
787 make_depend_on_class env (Cls.name class_);
788 Option.iter env.decl_env.droot (fun root ->
789 Typing_deps.add_idep (get_deps_mode env) root dep)
790 end;
791 Cls.get_const class_ mid
793 (* Used to access "global constants". That is constants that were
794 * introduced with "const X = ...;" at topelevel, or "define('X', ...);"
796 let get_gconst env cst_name =
797 let res =
798 Decl_provider.get_gconst
799 ?tracing_info:(get_tracing_info env)
800 (get_ctx env)
801 cst_name
803 match res with
804 | Some cst when Pos.is_hhi cst.cd_pos -> res
805 | _ ->
806 let dep = Dep.GConst cst_name in
807 Option.iter env.decl_env.droot (fun root ->
808 Typing_deps.add_idep (get_deps_mode env) root dep);
811 let get_static_member is_method env class_ mid =
812 (* The type of a member is stored separately in the heap. This means that
813 * any user of the member also has a dependency on the class where the member
814 * originated.
816 let ce_opt =
817 if is_method then
818 Cls.get_smethod class_ mid
819 else
820 Cls.get_sprop class_ mid
822 if not (Pos.is_hhi (Cls.pos class_)) then begin
823 make_depend_on_class env (Cls.name class_);
824 let add_dep x =
825 let dep =
826 if is_method then
827 Dep.SMethod (x, mid)
828 else
829 Dep.SProp (x, mid)
831 Option.iter env.decl_env.droot (fun root ->
832 Typing_deps.add_idep (get_deps_mode env) root dep)
834 add_dep (Cls.name class_);
835 Option.iter ce_opt (fun ce -> add_dep ce.ce_origin)
836 end;
838 ce_opt
840 (* Given a list of things whose name we can extract with `f`, return
841 the item whose name is closest to `name`. *)
842 let most_similar (name : string) (possibilities : 'a list) (f : 'a -> string) :
843 'a option =
844 let distance = String_utils.levenshtein_distance in
845 let choose_closest x y =
846 if distance (f x) name < distance (f y) name then
848 else
851 List.fold possibilities ~init:None ~f:(fun acc possibility ->
852 match acc with
853 | None -> Some possibility
854 | Some current_best -> Some (choose_closest current_best possibility))
856 let suggest_member members mid =
857 let pairs =
858 List.map members ~f:(fun (x, { ce_type = (lazy ty); _ }) -> (get_pos ty, x))
860 most_similar mid pairs snd
862 let suggest_static_member is_method class_ mid =
863 let mid = String.lowercase mid in
864 let members =
865 if is_method then
866 Cls.smethods class_
867 else
868 Cls.sprops class_
870 suggest_member members mid
872 let get_member is_method env class_ mid =
873 let add_dep x =
874 let dep =
875 if is_method then
876 Dep.Method (x, mid)
877 else
878 Dep.Prop (x, mid)
880 Option.iter env.decl_env.droot (fun root ->
881 Typing_deps.add_idep (get_deps_mode env) root dep)
883 (* The type of a member is stored separately in the heap. This means that
884 * any user of the member also has a dependency on the class where the member
885 * originated.
887 let ce_opt =
888 if is_method then
889 Cls.get_method class_ mid
890 else
891 Cls.get_prop class_ mid
893 if not (Pos.is_hhi (Cls.pos class_)) then
894 make_depend_on_class env (Cls.name class_);
895 Option.iter ce_opt (fun ce ->
896 add_dep (Cls.name class_);
897 add_dep ce.ce_origin);
898 ce_opt
900 let suggest_member is_method class_ mid =
901 let mid = String.lowercase mid in
902 let members =
903 if is_method then
904 Cls.methods class_
905 else
906 Cls.props class_
908 suggest_member members mid
910 let get_construct env class_ =
911 if not (Pos.is_hhi (Cls.pos class_)) then begin
912 make_depend_on_constructor env (Cls.name class_);
913 Option.iter
914 (fst (Cls.construct class_))
915 (fun ce -> make_depend_on_constructor env ce.ce_origin)
916 end;
917 Cls.construct class_
919 let get_return env = env.genv.return
921 let set_return env x =
922 let genv = env.genv in
923 let genv = { genv with return = x } in
924 { env with genv }
926 let get_params env = env.genv.params
928 let set_params env params = { env with genv = { env.genv with params } }
930 let set_param env x param =
931 let params = get_params env in
932 let params = LID.Map.add x param params in
933 set_params env params
935 let clear_params env = set_params env LID.Map.empty
937 let with_env env f =
938 let ret = get_return env in
939 let params = get_params env in
940 let (env, result) = f env in
941 let env = set_params env params in
942 let env = set_return env ret in
943 (env, result)
945 let with_origin env origin f =
946 let ti1 = env.tracing_info in
947 let ti2 = Option.map ti1 ~f:(fun ti -> { ti with Decl_counters.origin }) in
948 let env = { env with tracing_info = ti2 } in
949 let (env, result) = f env in
950 let env = { env with tracing_info = ti1 } in
951 (env, result)
953 let with_origin2 env origin f =
954 let ti1 = env.tracing_info in
955 let ti2 = Option.map ti1 ~f:(fun ti -> { ti with Decl_counters.origin }) in
956 let env = { env with tracing_info = ti2 } in
957 let (env, r1, r2) = f env in
958 let env = { env with tracing_info = ti1 } in
959 (env, r1, r2)
961 let is_static env = env.genv.static
963 let get_val_kind env = env.genv.val_kind
965 let get_self_ty env = Option.map env.genv.self ~f:snd
967 let get_self_class_type env =
968 match get_self_ty env with
969 | Some self ->
970 begin
971 match get_node self with
972 | Tclass (id, exact, tys) -> Some (id, exact, tys)
973 | _ -> None
975 | None -> None
977 let get_self_id env = Option.map env.genv.self ~f:fst
979 let get_self_class env =
980 let open Option in
981 get_self_id env >>= get_class env
983 let get_parent_ty env = Option.map env.genv.parent ~f:snd
985 let get_parent_id env = Option.map env.genv.parent ~f:fst
987 let get_parent_class env =
988 let open Option in
989 get_parent_id env >>= get_class_dep env
991 let get_fn_kind env = env.genv.fun_kind
993 let set_fn_kind env fn_type =
994 let genv = env.genv in
995 let genv = { genv with fun_kind = fn_type } in
996 { env with genv }
998 let set_self env self_id self_ty =
999 let genv = env.genv in
1000 let genv = { genv with self = Some (self_id, self_ty) } in
1001 { env with genv }
1003 let set_parent env parent_id parent_ty =
1004 let genv = env.genv in
1005 let genv = { genv with parent = Some (parent_id, parent_ty) } in
1006 { env with genv }
1008 let set_static env =
1009 let genv = env.genv in
1010 let genv = { genv with static = true } in
1011 { env with genv }
1013 let set_val_kind env x =
1014 let genv = env.genv in
1015 let genv = { genv with val_kind = x } in
1016 { env with genv }
1018 let set_mode env mode =
1019 let decl_env = env.decl_env in
1020 let decl_env = { decl_env with mode } in
1021 { env with decl_env }
1023 let get_mode env = env.decl_env.mode
1025 let is_strict env = FileInfo.is_strict (get_mode env)
1027 let is_hhi env = FileInfo.(equal_mode (get_mode env) Mhhi)
1029 let get_allow_solve_globals env =
1030 wrap_inference_env_call_res env Inf.get_allow_solve_globals
1032 let set_allow_solve_globals env flag =
1033 wrap_inference_env_call_env env (fun env ->
1034 Inf.set_allow_solve_globals env flag)
1036 (*****************************************************************************)
1037 (* Locals *)
1038 (*****************************************************************************)
1040 let set_local_ env x ty =
1041 let per_cont_env = LEnvC.add_to_cont C.Next x ty env.lenv.per_cont_env in
1042 { env with lenv = { env.lenv with per_cont_env } }
1044 (* We maintain 2 states for a local: the type
1045 * that the local currently has, and an expression_id generated from
1046 * the last assignment to this local.
1048 let set_local ?(immutable = false) env x new_type pos =
1049 let new_type =
1050 match get_node new_type with
1051 | Tunion [ty] -> ty
1052 | _ -> new_type
1054 match next_cont_opt env with
1055 | None -> env
1056 | Some next_cont ->
1057 let expr_id =
1058 match LID.Map.find_opt x next_cont.LEnvC.local_types with
1059 | None -> Ident.tmp ()
1060 | Some (_, _, y) -> y
1062 let expr_id =
1063 if immutable then
1064 LID.make_immutable expr_id
1065 else
1066 expr_id
1068 let local = (new_type, pos, expr_id) in
1069 set_local_ env x local
1071 let is_using_var env x = LID.Set.mem x env.lenv.local_using_vars
1073 let set_using_var env x =
1075 env with
1076 lenv =
1078 env.lenv with
1079 local_using_vars = LID.Set.add x env.lenv.local_using_vars;
1083 let unset_local env local =
1084 let { per_cont_env; local_using_vars; local_mutability; local_reactive } =
1085 env.lenv
1087 let per_cont_env =
1088 LEnvC.remove_from_cont C.Next local
1089 @@ LEnvC.remove_from_cont C.Catch local
1090 @@ per_cont_env
1092 let local_using_vars = LID.Set.remove local local_using_vars in
1093 let local_mutability = LID.Map.remove local local_mutability in
1094 let env =
1096 env with
1097 lenv =
1098 { per_cont_env; local_using_vars; local_mutability; local_reactive };
1103 let add_mutable_var env local mutability_type =
1104 env_with_mut env (LID.Map.add local mutability_type env.lenv.local_mutability)
1106 let local_is_mutable ~include_borrowed env id =
1107 let module TME = Typing_mutability_env in
1108 match LID.Map.find_opt id (get_env_mutability env) with
1109 | Some (_, TME.Mutable) -> true
1110 | Some (_, TME.Borrowed) -> include_borrowed
1111 | _ -> false
1113 let tany env =
1114 let dynamic_view_enabled = TypecheckerOptions.dynamic_view (get_tcopt env) in
1115 if dynamic_view_enabled then
1116 Tdynamic
1117 else
1118 Typing_defs.make_tany ()
1120 let get_local_in_ctx env ?error_if_undef_at_pos:p x ctx_opt =
1121 let not_found_is_ok x ctx =
1122 let xstr = LID.to_string x in
1123 (String.equal xstr SG.globals || SG.is_superglobal xstr)
1124 && not (is_strict env)
1125 || Fake.is_valid ctx.LEnvC.fake_members x
1127 let error_if_pos_provided posopt ctx =
1128 match posopt with
1129 | Some p ->
1130 let in_rx_scope = env_local_reactive env in
1131 let lid = LID.to_string x in
1132 let suggest_most_similar lid =
1133 (* Ignore fake locals *)
1134 let all_locals =
1135 LID.Map.fold
1136 (fun k v acc ->
1137 if String.is_prefix ~prefix:"$#" (LID.to_string k) then
1139 else
1140 (k, v) :: acc)
1141 ctx.LEnvC.local_types
1144 let var_name (k, _) = LID.to_string k in
1145 match most_similar lid all_locals var_name with
1146 | Some (k, (_, pos, _)) -> Some (LID.to_string k, pos)
1147 | None -> None
1149 Errors.undefined ~in_rx_scope p lid (suggest_most_similar lid)
1150 | None -> ()
1152 match ctx_opt with
1153 | None ->
1154 (* If the continuation is absent, we are in dead code so the variable should
1155 have type nothing. *)
1156 Some (Typing_make_type.nothing Reason.Rnone, Pos.none, 0)
1157 | Some ctx ->
1158 let lcl = LID.Map.find_opt x ctx.LEnvC.local_types in
1159 begin
1160 match lcl with
1161 | None ->
1162 if not_found_is_ok x ctx then
1164 else
1165 error_if_pos_provided p ctx
1166 | Some _ -> ()
1167 end;
1170 let get_local_ty_in_ctx env ?error_if_undef_at_pos x ctx_opt =
1171 match get_local_in_ctx env ?error_if_undef_at_pos x ctx_opt with
1172 | None -> (false, mk (Reason.Rnone, tany env), Pos.none)
1173 | Some (x, pos, _) -> (true, x, pos)
1175 let get_local_in_next_continuation ?error_if_undef_at_pos:p env x =
1176 let next_cont = next_cont_opt env in
1177 get_local_ty_in_ctx env ?error_if_undef_at_pos:p x next_cont
1179 let get_local_ ?error_if_undef_at_pos:p env x =
1180 let (mut, ty, _) =
1181 get_local_in_next_continuation ?error_if_undef_at_pos:p env x
1183 (mut, ty)
1185 let get_local env x = snd (get_local_ env x)
1187 let get_local_pos env x =
1188 let (_, ty, pos) = get_local_in_next_continuation env x in
1189 (ty, pos)
1191 let get_locals env plids =
1192 let next_cont = next_cont_opt env in
1193 List.fold plids ~init:LID.Map.empty ~f:(fun locals (p, lid) ->
1194 match get_local_in_ctx env ~error_if_undef_at_pos:p lid next_cont with
1195 | None -> locals
1196 | Some ty_eid -> LID.Map.add lid ty_eid locals)
1198 let set_locals env locals =
1199 LID.Map.fold (fun lid ty env -> set_local_ env lid ty) locals env
1201 let is_local_defined env x =
1202 let next_cont = next_cont_opt env in
1203 Option.is_some next_cont && fst (get_local_ env x)
1205 let get_local_check_defined env (p, x) =
1206 snd (get_local_ ~error_if_undef_at_pos:p env x)
1208 let set_local_expr_id env x new_eid =
1209 let per_cont_env = env.lenv.per_cont_env in
1210 match LEnvC.get_cont_option C.Next per_cont_env with
1211 | None -> env
1212 | Some next_cont ->
1213 begin
1214 match LID.Map.find_opt x next_cont.LEnvC.local_types with
1215 | Some (type_, pos, eid)
1216 when not (Typing_local_types.equal_expression_id eid new_eid) ->
1217 if LID.is_immutable eid then Errors.immutable_local pos;
1218 let local = (type_, pos, new_eid) in
1219 let per_cont_env = LEnvC.add_to_cont C.Next x local per_cont_env in
1220 let env = { env with lenv = { env.lenv with per_cont_env } } in
1222 | _ -> env
1225 let get_local_expr_id env x =
1226 match next_cont_opt env with
1227 | None -> (* dead code *) None
1228 | Some next_cont ->
1229 let lcl = LID.Map.find_opt x next_cont.LEnvC.local_types in
1230 Option.map lcl ~f:(fun (_, _, x) -> x)
1232 let set_fake_members env fake_members =
1233 let per_cont_env =
1234 LEnvC.update_cont_entry C.Next env.lenv.per_cont_env (fun entry ->
1235 { entry with LEnvC.fake_members })
1237 { env with lenv = { env.lenv with per_cont_env } }
1239 let get_fake_members env =
1240 match LEnvC.get_cont_option C.Next env.lenv.per_cont_env with
1241 | None -> Fake.empty
1242 | Some next_cont -> next_cont.LEnvC.fake_members
1244 let update_lost_info name blame env ty =
1245 let info r = Reason.Rlost_info (name, r, blame) in
1246 let rec update_ty (env, seen_tyvars) ty =
1247 let (env, ty) = expand_type env ty in
1248 match deref ty with
1249 | (_, Tvar v) ->
1250 if ISet.mem v seen_tyvars then
1251 ((env, seen_tyvars), ty)
1252 else
1253 let seen_tyvars = ISet.add v seen_tyvars in
1254 let bs = get_tyvar_lower_bounds env v in
1255 let ((env, seen_tyvars), bs) =
1256 ITySet.fold_map bs ~init:(env, seen_tyvars) ~f:update_ty_i
1258 let env = set_tyvar_lower_bounds env v bs in
1259 let bs = get_tyvar_upper_bounds env v in
1260 let ((env, seen_tyvars), bs) =
1261 ITySet.fold_map bs ~init:(env, seen_tyvars) ~f:update_ty_i
1263 let env = set_tyvar_upper_bounds env v bs in
1264 ((env, seen_tyvars), ty)
1265 | (r, Toption ty) ->
1266 let ((env, seen_tyvars), ty) = update_ty (env, seen_tyvars) ty in
1267 ((env, seen_tyvars), mk (info r, Toption ty))
1268 | (r, Tunion tyl) ->
1269 let ((env, seen_tyvars), tyl) =
1270 List.fold_map tyl ~init:(env, seen_tyvars) ~f:update_ty
1272 ((env, seen_tyvars), mk (info r, Tunion tyl))
1273 | _ -> ((env, seen_tyvars), map_reason ty ~f:info)
1274 and update_ty_i (env, seen_tyvars) ty =
1275 match ty with
1276 | LoclType ty ->
1277 let ((env, seen_tyvars), ty) = update_ty (env, seen_tyvars) ty in
1278 ((env, seen_tyvars), LoclType ty)
1279 | ConstraintType ty ->
1280 let (r, ty) = deref_constraint_type ty in
1281 ((env, seen_tyvars), ConstraintType (mk_constraint_type (info r, ty)))
1283 let ((env, _seen_tyvars), ty) = update_ty (env, ISet.empty) ty in
1284 (env, ty)
1286 let forget_generic forget env blame =
1287 let fake_members = get_fake_members env in
1288 let fake_members = forget fake_members blame in
1289 set_fake_members env fake_members
1291 let forget_members = forget_generic Fake.forget
1293 let forget_prefixed_members env lid =
1294 forget_generic (fun fake_members -> Fake.forget_prefixed fake_members lid) env
1296 let forget_suffixed_members env suffix =
1297 forget_generic
1298 (fun fake_members -> Fake.forget_suffixed fake_members suffix)
1301 module FakeMembers = struct
1302 let update_fake_members env fake_members =
1303 let per_cont_env =
1304 LEnvC.update_cont_entry C.Next env.lenv.per_cont_env (fun entry ->
1305 LEnvC.{ entry with fake_members })
1307 { env with lenv = { env.lenv with per_cont_env } }
1309 let is_valid env obj member_name =
1310 match obj with
1311 | (_, This)
1312 | (_, Lvar _) ->
1313 let fake_members = get_fake_members env in
1314 let id = Fake.make_id obj member_name in
1315 Fake.is_valid fake_members id
1316 | _ -> false
1318 let is_valid_static env cid member_name =
1319 let name = Fake.make_static_id cid member_name in
1320 let fake_members = get_fake_members env in
1321 Fake.is_valid fake_members name
1323 let check_static_invalid env cid member_name ty =
1324 let fake_members = get_fake_members env in
1325 let fake_id = Fake.make_static_id cid member_name in
1326 match Fake.is_invalid fake_members fake_id with
1327 | None -> (env, ty)
1328 | Some blame -> update_lost_info (Local_id.to_string fake_id) blame env ty
1330 let check_instance_invalid env obj member_name ty =
1331 match obj with
1332 | (_, This)
1333 | (_, Lvar _) ->
1334 let fake_members = get_fake_members env in
1335 let fake_id = Fake.make_id obj member_name in
1336 begin
1337 match Fake.is_invalid fake_members fake_id with
1338 | None -> (env, ty)
1339 | Some blame ->
1340 update_lost_info (Local_id.to_string fake_id) blame env ty
1342 | _ -> (env, ty)
1344 let add_member env fake_id pos =
1345 let fake_members = get_fake_members env in
1346 let fake_members = Fake.add fake_members fake_id pos in
1347 set_fake_members env fake_members
1349 let make env obj_name member_name pos =
1350 let my_fake_local_id = Fake.make_id obj_name member_name in
1351 let env = add_member env my_fake_local_id pos in
1352 (env, my_fake_local_id)
1354 let make_static env class_name member_name pos =
1355 let my_fake_local_id = Fake.make_static_id class_name member_name in
1356 let env = add_member env my_fake_local_id pos in
1357 (env, my_fake_local_id)
1360 (*****************************************************************************)
1361 (* Sets up/cleans up the environment when typing anonymous function / lambda *)
1362 (*****************************************************************************)
1364 let closure lenv env f =
1365 (* Setting up the environment. *)
1366 let old_lenv = env.lenv in
1367 let old_return = get_return env in
1368 let old_params = get_params env in
1369 let outer_fun_kind = get_fn_kind env in
1370 let env = { env with lenv } in
1371 (* Typing *)
1372 let (env, ret) = f env in
1373 (* Cleaning up the environment. *)
1374 let env = { env with lenv = old_lenv } in
1375 let env = set_params env old_params in
1376 let env = set_return env old_return in
1377 let env = set_fn_kind env outer_fun_kind in
1378 (env, ret)
1380 let in_try env f =
1381 let old_in_try = env.in_try in
1382 let env = { env with in_try = true } in
1383 let (env, result) = f env in
1384 ({ env with in_try = old_in_try }, result)
1386 let in_case env f =
1387 let old_in_case = env.in_case in
1388 let env = { env with in_case = true } in
1389 let (env, result) = f env in
1390 ({ env with in_case = old_in_case }, result)
1392 (* Return the subset of env which is saved in the Typed AST's EnvAnnotation. *)
1393 let save local_tpenv env =
1395 Tast.tcopt = get_tcopt env;
1396 Tast.inference_env = env.inference_env;
1397 Tast.tpenv = TPEnv.union local_tpenv env.global_tpenv;
1398 Tast.reactivity = env_reactivity env;
1399 Tast.local_mutability = get_env_mutability env;
1400 Tast.fun_mutable = function_is_mutable env;
1401 Tast.condition_types = env.genv.condition_types;
1402 Tast.pessimize = env.pessimize;
1405 (* Compute the type variables appearing covariantly (positively)
1406 * resp. contravariantly (negatively) in a given type ty.
1407 * Return a pair of sets of positive and negative type variables
1408 * (as well as an updated environment).
1410 let rec get_tyvars env (ty : locl_ty) = get_tyvars_i env (LoclType ty)
1412 and get_tyvars_i env (ty : internal_type) =
1413 let get_tyvars_union (env, acc_positive, acc_negative) ty =
1414 let (env, positive, negative) = get_tyvars env ty in
1415 (env, ISet.union acc_positive positive, ISet.union acc_negative negative)
1417 let get_tyvars_param (env, acc_positive, acc_negative) fp =
1418 let (env, positive, negative) = get_tyvars env fp.fp_type.et_type in
1419 match get_fp_mode fp with
1420 (* Parameters are treated contravariantly *)
1421 | FPnormal ->
1422 (env, ISet.union negative acc_positive, ISet.union positive acc_negative)
1423 (* Inout parameters are both co- and contra-variant *)
1424 | FPinout ->
1425 let tyvars = ISet.union negative positive in
1426 (env, ISet.union tyvars acc_positive, ISet.union tyvars acc_negative)
1428 let (env, ety) = expand_internal_type env ty in
1429 match ety with
1430 | LoclType ety ->
1431 (match get_node ety with
1432 | Tvar v -> (env, ISet.singleton v, ISet.empty)
1433 | Tany _
1434 | Tnonnull
1435 | Terr
1436 | Tdynamic
1437 | Tobject
1438 | Tprim _ ->
1439 (env, ISet.empty, ISet.empty)
1440 | Toption ty -> get_tyvars env ty
1441 | Ttuple tyl
1442 | Tunion tyl
1443 | Tintersection tyl ->
1444 List.fold_left tyl ~init:(env, ISet.empty, ISet.empty) ~f:get_tyvars_union
1445 | Tshape (_, m) ->
1446 Nast.ShapeMap.fold
1447 (fun _ { sft_ty; _ } res -> get_tyvars_union res sft_ty)
1449 (env, ISet.empty, ISet.empty)
1450 | Tfun ft ->
1451 let (env, params_positive, params_negative) =
1452 match ft.ft_arity with
1453 | Fstandard -> (env, ISet.empty, ISet.empty)
1454 | Fvariadic fp -> get_tyvars_param (env, ISet.empty, ISet.empty) fp
1456 let (env, params_positive, params_negative) =
1457 List.fold_left
1458 ft.ft_params
1459 ~init:(env, params_positive, params_negative)
1460 ~f:get_tyvars_param
1462 let (env, ret_positive, ret_negative) =
1463 get_tyvars env ft.ft_ret.et_type
1465 ( env,
1466 ISet.union ret_positive params_positive,
1467 ISet.union ret_negative params_negative )
1468 | Tnewtype (name, tyl, _) ->
1469 if List.is_empty tyl then
1470 (env, ISet.empty, ISet.empty)
1471 else begin
1472 match get_typedef env name with
1473 | Some { td_tparams; _ } ->
1474 let variancel = List.map td_tparams (fun t -> t.tp_variance) in
1475 get_tyvars_variance_list (env, ISet.empty, ISet.empty) variancel tyl
1476 | None -> (env, ISet.empty, ISet.empty)
1478 | Tdependent (_, ty) -> get_tyvars env ty
1479 | Tgeneric (_, tyl) ->
1480 (* TODO(T69931993) Once implementing variance support for HK types, query
1481 tyvar env here for list of variances *)
1482 let variancel = List.replicate (List.length tyl) Ast_defs.Invariant in
1483 get_tyvars_variance_list (env, ISet.empty, ISet.empty) variancel tyl
1484 | Tclass ((_, cid), _, tyl) ->
1485 if List.is_empty tyl then
1486 (env, ISet.empty, ISet.empty)
1487 else begin
1488 match get_class env cid with
1489 | Some cls ->
1490 let variancel = List.map (Cls.tparams cls) (fun t -> t.tp_variance) in
1491 get_tyvars_variance_list (env, ISet.empty, ISet.empty) variancel tyl
1492 | None -> (env, ISet.empty, ISet.empty)
1494 | Tvarray ty -> get_tyvars env ty
1495 | Tdarray (ty1, ty2) ->
1496 let (env, positive1, negative1) = get_tyvars env ty1 in
1497 let (env, positive2, negative2) = get_tyvars env ty2 in
1498 (env, ISet.union positive1 positive2, ISet.union negative1 negative2)
1499 | Tvec_or_dict (ty1, ty2)
1500 | Tvarray_or_darray (ty1, ty2) ->
1501 let (env, positive1, negative1) = get_tyvars env ty1 in
1502 let (env, positive2, negative2) = get_tyvars env ty2 in
1503 (env, ISet.union positive1 positive2, ISet.union negative1 negative2)
1504 | Tunapplied_alias _ -> (env, ISet.empty, ISet.empty)
1505 | Taccess (ty, _ids) -> get_tyvars env ty)
1506 | ConstraintType ty ->
1507 (match deref_constraint_type ty with
1508 | (_, Tdestructure { d_required; d_optional; d_variadic; d_kind = _ }) ->
1509 let (env, positive1, negative1) =
1510 List.fold_left
1511 d_required
1512 ~init:(env, ISet.empty, ISet.empty)
1513 ~f:get_tyvars_union
1515 let (env, positive2, negative2) =
1516 List.fold_left
1517 d_optional
1518 ~init:(env, ISet.empty, ISet.empty)
1519 ~f:get_tyvars_union
1521 let (env, positive3, negative3) =
1522 match d_variadic with
1523 | Some ty -> get_tyvars env ty
1524 | None -> (env, ISet.empty, ISet.empty)
1526 ( env,
1527 ISet.union (ISet.union positive1 positive2) positive3,
1528 ISet.union (ISet.union negative1 negative2) negative3 )
1529 | (_, Thas_member hm) ->
1530 let { hm_type; hm_name = _; hm_class_id = _; hm_explicit_targs = _ } =
1533 get_tyvars env hm_type
1534 | (_, TCunion (lty, cty))
1535 | (_, TCintersection (lty, cty)) ->
1536 let (env, positive1, negative1) = get_tyvars env lty in
1537 let (env, positive2, negative2) = get_tyvars_i env (ConstraintType cty) in
1538 (env, ISet.union positive1 positive2, ISet.union negative1 negative2))
1540 and get_tyvars_variance_list (env, acc_positive, acc_negative) variancel tyl =
1541 match (variancel, tyl) with
1542 | (variance :: variancel, ty :: tyl) ->
1543 let (env, positive, negative) = get_tyvars env ty in
1544 let (acc_positive, acc_negative) =
1545 match variance with
1546 | Ast_defs.Covariant ->
1547 (ISet.union acc_positive positive, ISet.union acc_negative negative)
1548 | Ast_defs.Contravariant ->
1549 (ISet.union acc_positive negative, ISet.union acc_negative positive)
1550 | Ast_defs.Invariant ->
1551 let positive_or_negative = ISet.union positive negative in
1552 ( ISet.union acc_positive positive_or_negative,
1553 ISet.union acc_negative positive_or_negative )
1555 get_tyvars_variance_list (env, acc_positive, acc_negative) variancel tyl
1556 | _ -> (env, acc_positive, acc_negative)
1558 let rec set_tyvar_appears_covariantly_and_propagate env var =
1559 if get_tyvar_appears_covariantly env var then
1561 else
1562 let env = set_tyvar_appears_covariantly env var in
1563 let lower_bounds = get_tyvar_lower_bounds env var in
1564 update_variance_of_tyvars_occurring_in_lower_bounds env lower_bounds
1566 and set_tyvar_appears_contravariantly_and_propagate env var =
1567 if get_tyvar_appears_contravariantly env var then
1569 else
1570 let env = set_tyvar_appears_contravariantly env var in
1571 let upper_bounds = get_tyvar_upper_bounds env var in
1572 update_variance_of_tyvars_occurring_in_upper_bounds env upper_bounds
1574 and update_variance_of_tyvars_occurring_in_lower_bounds env tys =
1575 ITySet.fold
1576 (fun ty env -> update_variance_of_tyvars_occurring_in_lower_bound env ty)
1580 and update_variance_of_tyvars_occurring_in_upper_bounds env tys =
1581 ITySet.fold
1582 (fun ty env -> update_variance_of_tyvars_occurring_in_upper_bound env ty)
1586 and update_variance_of_tyvars_occurring_in_lower_bound env ty =
1587 let (env, ety) = expand_internal_type env ty in
1588 match ety with
1589 | LoclType ty when is_tyvar ty -> env
1590 | _ ->
1591 let (env, positive, negative) = get_tyvars_i env ty in
1592 let env =
1593 ISet.fold
1594 (fun var env -> set_tyvar_appears_covariantly env var)
1595 positive
1598 let env =
1599 ISet.fold
1600 (fun var env -> set_tyvar_appears_contravariantly env var)
1601 negative
1606 and update_variance_of_tyvars_occurring_in_upper_bound env ty =
1607 let (env, ety) = expand_internal_type env ty in
1608 match ety with
1609 | LoclType ty when is_tyvar ty -> env
1610 | _ ->
1611 let (env, positive, negative) = get_tyvars_i env ty in
1612 let env =
1613 ISet.fold
1614 (fun var env -> set_tyvar_appears_contravariantly env var)
1615 positive
1618 let env =
1619 ISet.fold
1620 (fun var env -> set_tyvar_appears_covariantly env var)
1621 negative
1626 let set_tyvar_appears_covariantly = set_tyvar_appears_covariantly_and_propagate
1628 let set_tyvar_appears_contravariantly =
1629 set_tyvar_appears_contravariantly_and_propagate
1631 (* After a type variable var has been "solved", or bound to a type ty, we need
1632 * to update the variance of type variables occurring in ty. Suppose that
1633 * variable var is marked "appears covariantly", i.e. it appears (at least) in
1634 * positive positions in the type of an expression. Then when we substitute ty
1635 * for var, variables that appear positively in ty must now be marked as
1636 * appearing covariantly; variables that appear negatively in ty must now be
1637 * marked as appearing contravariantly. And the dual, if the variable var is marked
1638 * "appears contravariantly".
1640 let update_variance_after_bind env var ty =
1641 let appears_contravariantly = get_tyvar_appears_contravariantly env var in
1642 let appears_covariantly = get_tyvar_appears_covariantly env var in
1643 let (env, positive, negative) = get_tyvars env ty in
1644 let env =
1645 ISet.fold
1646 (fun var env ->
1647 let env =
1648 if appears_contravariantly then
1649 set_tyvar_appears_contravariantly env var
1650 else
1653 if appears_covariantly then
1654 set_tyvar_appears_covariantly env var
1655 else
1656 env)
1657 positive
1660 let env =
1661 ISet.fold
1662 (fun var env ->
1663 let env =
1664 if appears_contravariantly then
1665 set_tyvar_appears_covariantly env var
1666 else
1669 if appears_covariantly then
1670 set_tyvar_appears_contravariantly env var
1671 else
1672 env)
1673 negative
1678 let set_tyvar_variance_i env ?(flip = false) ?(for_all_vars = false) ty =
1679 log_env_change "set_tyvar_variance" env
1681 let (env, positive, negative) = get_tyvars_i env ty in
1682 let (positive, negative) =
1683 if flip then
1684 (negative, positive)
1685 else
1686 (positive, negative)
1688 let tyvars =
1689 if for_all_vars then
1690 ISet.union positive negative |> ISet.elements
1691 else
1692 get_current_tyvars env
1694 List.fold_left tyvars ~init:env ~f:(fun env var ->
1695 let env =
1696 if ISet.mem var positive then
1697 set_tyvar_appears_covariantly env var
1698 else
1701 let env =
1702 if ISet.mem var negative then
1703 set_tyvar_appears_contravariantly env var
1704 else
1707 env)
1709 let set_tyvar_variance env ?(flip = false) ?(for_all_vars = false) ty =
1710 set_tyvar_variance_i env ~flip ~for_all_vars (LoclType ty)
1712 let add_tyvar_upper_bound ?intersect env var (ty : internal_type) =
1713 log_env_change "add_tyvar_upper_bound" env
1714 @@ wrap_inference_env_call_env env (fun env ->
1715 Inf.add_tyvar_upper_bound ?intersect env var ty)
1717 (* Add a single new upper bound [ty] to type variable [var] in [env.inference_env].
1718 * If the optional [intersect] operation is supplied, then use this to avoid
1719 * adding redundant bounds by merging the type with existing bounds. This makes
1720 * sense because a conjunction of upper bounds
1721 * (v <: t1) /\ ... /\ (v <: tn)
1722 * is equivalent to a single upper bound
1723 * v <: (t1 & ... & tn)
1725 let add_tyvar_upper_bound_and_update_variances
1726 ?intersect env var (ty : internal_type) =
1727 log_env_change "add_tyvar_upper_bound" env
1729 let env = add_tyvar_upper_bound ?intersect env var ty in
1730 if get_tyvar_appears_contravariantly env var then
1731 update_variance_of_tyvars_occurring_in_upper_bound env ty
1732 else
1735 (* Remove type variable `upper_var` from the upper bounds on `var`, if it exists
1737 let remove_tyvar_upper_bound env var upper_var =
1738 log_env_change "remove_tyvar_upper_bound" env
1739 @@ wrap_inference_env_call_env env (fun env ->
1740 Inf.remove_tyvar_upper_bound env var upper_var)
1742 (* Remove type variable `lower_var` from the lower bounds on `var`, if it exists
1744 let remove_tyvar_lower_bound env var lower_var =
1745 log_env_change "remove_tyvar_lower_bound var" env
1746 @@ wrap_inference_env_call_env env (fun env ->
1747 Inf.remove_tyvar_lower_bound env var lower_var)
1749 let add_tyvar_lower_bound ?union env var ty =
1750 log_env_change "add_tyvar_lower_bound" env
1751 @@ wrap_inference_env_call_env env (fun env ->
1752 Inf.add_tyvar_lower_bound ?union env var ty)
1754 (* Add a single new lower bound [ty] to type variable [var] in [env.tvenv].
1755 * If the optional [union] operation is supplied, then use this to avoid
1756 * adding redundant bounds by merging the type with existing bounds. This makes
1757 * sense because a conjunction of lower bounds
1758 * (t1 <: v) /\ ... /\ (tn <: v)
1759 * is equivalent to a single lower bound
1760 * (t1 | ... | tn) <: v
1762 let add_tyvar_lower_bound_and_update_variances ?union env var ty =
1763 log_env_change "add_tyvar_lower_bound" env
1765 let env = add_tyvar_lower_bound ?union env var ty in
1766 if get_tyvar_appears_covariantly env var then
1767 update_variance_of_tyvars_occurring_in_lower_bound env ty
1768 else
1771 let initialize_tyvar_as_in ~as_in:genv env v =
1772 log_env_change "initialize_tyvar_as_in" env
1773 @@ wrap_inference_env_call_env env (fun env ->
1774 Inf.initialize_tyvar_as_in ~as_in:genv env v)
1776 let copy_tyvar_from_genv_to_env var ~to_:env ~from:genv =
1777 log_env_change_ "copy_tyvar_from_genv_to_env" env
1778 @@ wrap_inference_env_call env (fun env ->
1779 Inf.copy_tyvar_from_genv_to_env var ~to_:env ~from:genv)
1781 let get_all_tyvars env =
1782 wrap_inference_env_call_res env (fun env -> Inf.get_vars env)
1784 let remove_var env var ~search_in_upper_bounds_of ~search_in_lower_bounds_of =
1785 log_env_change "remove_var" env
1786 @@ wrap_inference_env_call_env env (fun env ->
1787 Inf.remove_var
1790 ~search_in_upper_bounds_of
1791 ~search_in_lower_bounds_of)
1793 let unsolve env v =
1794 wrap_inference_env_call_env env (fun env -> Inf.unsolve env v)
1796 module Log = struct
1797 (** Convert a type variable from an environment into json *)
1798 let tyvar_to_json
1799 (p_locl_ty : locl_ty -> string)
1800 (p_internal_type : internal_type -> string)
1801 (env : env)
1802 (v : Ident.t) =
1803 wrap_inference_env_call_res env (fun env ->
1804 Inf.Log.tyvar_to_json p_locl_ty p_internal_type env v)