Update as and foreach typing for sound dynamic
[hiphop-php.git] / hphp / hack / src / typing / typing.ml
blobdaf06d9493fa47c6a8c773febe572c4e81602369
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 (* This module implements the typing.
12 * Given an Nast.program, it infers the type of all the local
13 * variables, and checks that all the types are correct (aka
14 * consistent) *)
15 open Hh_prelude
16 open Common
17 open Aast
18 open Tast
19 open Typing_defs
20 open Typing_env_types
21 open Utils
22 open Typing_helpers
23 module TFTerm = Typing_func_terminality
24 module TUtils = Typing_utils
25 module Reason = Typing_reason
26 module Type = Typing_ops
27 module Env = Typing_env
28 module Inf = Typing_inference_env
29 module LEnv = Typing_lenv
30 module Async = Typing_async
31 module SubType = Typing_subtype
32 module Union = Typing_union
33 module Inter = Typing_intersection
34 module SN = Naming_special_names
35 module TVis = Typing_visibility
36 module Phase = Typing_phase
37 module TOG = Typing_object_get
38 module Subst = Decl_subst
39 module ExprDepTy = Typing_dependent_type.ExprDepTy
40 module TCO = TypecheckerOptions
41 module EnvFromDef = Typing_env_from_def
42 module C = Typing_continuations
43 module CMap = C.Map
44 module Try = Typing_try
45 module TR = Typing_reactivity
46 module FL = FeatureLogging
47 module MakeType = Typing_make_type
48 module Cls = Decl_provider.Class
49 module Partial = Partial_provider
50 module Fake = Typing_fake_members
51 module ExpectedTy = Typing_helpers.ExpectedTy
53 type newable_class_info =
54 env
55 * Tast.targ list
56 * Tast.class_id
57 * [ `Class of sid * Cls.t * locl_ty | `Dynamic ] list
59 (*****************************************************************************)
60 (* Debugging *)
61 (*****************************************************************************)
63 (* A guess as to the last position we were typechecking, for use in debugging,
64 * such as figuring out what a runaway hh_server thread is doing. Updated
65 * only best-effort -- it's an approximation to point debugging in the right
66 * direction, nothing more. *)
67 let debug_last_pos = ref Pos.none
69 let debug_print_last_pos _ =
70 Hh_logger.info
71 "Last typecheck pos: %s"
72 (Pos.string (Pos.to_absolute !debug_last_pos))
74 (*****************************************************************************)
75 (* Helpers *)
76 (*****************************************************************************)
78 let err_witness env p = TUtils.terr env (Reason.Rwitness p)
80 (* Set all the types in an expression to the given type. *)
81 let with_type ty env (e : Nast.expr) : Tast.expr =
82 let visitor =
83 object
84 inherit [_] Aast.map
86 method on_'ex _ p = (p, ty)
88 method on_'fb _ _ = ()
90 method on_'en _ _ = env
92 method on_'hi _ _ = ty
93 end
95 visitor#on_expr () e
97 let expr_error env (r : Reason.t) (e : Nast.expr) =
98 let ty = TUtils.terr env r in
99 (env, with_type ty Tast.dummy_saved_env e, ty)
101 let expr_any env p e =
102 let ty = Typing_utils.mk_tany env p in
103 (env, with_type ty Tast.dummy_saved_env e, ty)
105 let unbound_name env (pos, name) e =
106 let strictish = Partial.should_check_error (Env.get_mode env) 4107 in
107 match Env.get_mode env with
108 | FileInfo.Mstrict ->
109 Errors.unbound_name_typing pos name;
110 expr_error env (Reason.Rwitness pos) e
111 | FileInfo.Mpartial when strictish ->
112 Errors.unbound_name_typing pos name;
113 expr_error env (Reason.Rwitness pos) e
114 | FileInfo.Mdecl
115 | FileInfo.Mpartial ->
116 expr_any env pos e
118 (* Is this type Traversable<vty> or Container<vty> for some vty? *)
119 let get_value_collection_inst ty =
120 match get_node ty with
121 | Tclass ((_, c), _, [vty])
122 when String.equal c SN.Collections.cTraversable
123 || String.equal c SN.Collections.cContainer ->
124 Some vty
125 (* If we're expecting a mixed or a nonnull then we can just assume
126 * that the element type is mixed *)
127 | Tnonnull -> Some (MakeType.mixed Reason.Rnone)
128 | Tany _ -> Some ty
129 | _ -> None
131 (* Is this type KeyedTraversable<kty,vty>
132 * or KeyedContainer<kty,vty>
133 * for some kty, vty?
135 let get_key_value_collection_inst p ty =
136 match get_node ty with
137 | Tclass ((_, c), _, [kty; vty])
138 when String.equal c SN.Collections.cKeyedTraversable
139 || String.equal c SN.Collections.cKeyedContainer ->
140 Some (kty, vty)
141 (* If we're expecting a mixed or a nonnull then we can just assume
142 * that the key type is arraykey and the value type is mixed *)
143 | Tnonnull ->
144 let arraykey = MakeType.arraykey (Reason.Rkey_value_collection_key p) in
145 let mixed = MakeType.mixed Reason.Rnone in
146 Some (arraykey, mixed)
147 | Tany _ -> Some (ty, ty)
148 | _ -> None
150 (* Is this type varray<vty> or a supertype for some vty? *)
151 let get_varray_inst ty =
152 match get_node ty with
153 (* It's varray<vty> *)
154 | Tvarray vty -> Some vty
155 | _ -> get_value_collection_inst ty
157 (* Is this type one of the value collection types with element type vty? *)
158 let get_vc_inst vc_kind ty =
159 match get_node ty with
160 | Tclass ((_, c), _, [vty]) when String.equal c (Nast.vc_kind_to_name vc_kind)
162 Some vty
163 | _ -> get_value_collection_inst ty
165 (* Is this type one of the three key-value collection types
166 * e.g. dict<kty,vty> or a supertype for some kty and vty? *)
167 let get_kvc_inst p kvc_kind ty =
168 match get_node ty with
169 | Tclass ((_, c), _, [kty; vty])
170 when String.equal c (Nast.kvc_kind_to_name kvc_kind) ->
171 Some (kty, vty)
172 | _ -> get_key_value_collection_inst p ty
174 (* Is this type darray<kty, vty> or a supertype for some kty and vty? *)
175 let get_darray_inst p ty =
176 match get_node ty with
177 (* It's darray<kty, vty> *)
178 | Tdarray (kty, vty) -> Some (kty, vty)
179 | _ -> get_key_value_collection_inst p ty
181 (* Check whether this is a function type that (a) either returns a disposable
182 * or (b) has the <<__ReturnDisposable>> attribute
184 let is_return_disposable_fun_type env ty =
185 let (_env, ty) = Env.expand_type env ty in
186 match get_node ty with
187 | Tfun ft ->
188 get_ft_return_disposable ft
189 || Option.is_some
190 (Typing_disposable.is_disposable_type env ft.ft_ret.et_type)
191 | _ -> false
193 (* Turn an environment into a local_id_map suitable to be embedded
194 * into an AssertEnv statement
196 let annot_map env =
197 match Env.next_cont_opt env with
198 | Some { Typing_per_cont_env.local_types; _ } ->
199 Some (Local_id.Map.map (fun (ty, pos, _expr_id) -> (pos, ty)) local_types)
200 | None -> None
202 (* Similar to annot_map above, but filters the map to only contain
203 * information about locals in lset
205 let refinement_annot_map env lset =
206 match annot_map env with
207 | Some map ->
208 let map =
209 Local_id.Map.filter (fun lid _ -> Local_id.Set.mem lid lset) map
211 if Local_id.Map.is_empty map then
212 None
213 else
214 Some map
215 | None -> None
217 let assert_env_blk ~pos ~at annotation_kind env_map_opt blk =
218 let mk_assert map = (pos, Aast.AssertEnv (annotation_kind, map)) in
219 let annot_blk = Option.to_list (Option.map ~f:mk_assert env_map_opt) in
220 match at with
221 | `Start -> annot_blk @ blk
222 | `End -> blk @ annot_blk
224 let assert_env_stmt ~pos ~at annotation_kind env_map_opt stmt =
225 let mk_assert map = (pos, Aast.AssertEnv (annotation_kind, map)) in
226 match env_map_opt with
227 | Some env_map ->
228 let blk =
229 match at with
230 | `Start -> [mk_assert env_map; (pos, stmt)]
231 | `End -> [(pos, stmt); mk_assert env_map]
233 Aast.Block blk
234 | None -> stmt
236 let set_tcopt_unstable_features env { fa_user_attributes; _ } =
237 match
238 Naming_attributes.find
239 SN.UserAttributes.uaEnableUnstableFeatures
240 fa_user_attributes
241 with
242 | None -> env
243 | Some { ua_name = _; ua_params } ->
244 let ( = ) = String.equal in
245 List.fold ua_params ~init:env ~f:(fun env feature ->
246 match snd feature with
247 | Aast.String s when s = SN.UnstableFeatures.ifc ->
248 Env.map_tcopt ~f:TypecheckerOptions.enable_ifc env
249 | _ -> env)
251 (* Given a localized parameter type and parameter information, infer
252 * a type for the parameter default expression (if present) and check that
253 * it is a subtype of the parameter type (if present). If no parameter type
254 * is specified, then union with Tany. (So it's as though we did a conditional
255 * assignment of the default expression to the parameter).
256 * Set the type of the parameter in the locals environment *)
257 let rec bind_param env (ty1, param) =
258 let (env, param_te, ty1) =
259 match param.param_expr with
260 | None -> (env, None, ty1)
261 | Some e ->
262 let decl_hint =
263 Option.map
264 ~f:(Decl_hint.hint env.decl_env)
265 (hint_of_type_hint param.param_type_hint)
267 let enforced =
268 match decl_hint with
269 | None -> false
270 | Some ty -> Typing_enforceability.is_enforceable env ty
272 let ty1_enforced = { et_type = ty1; et_enforced = enforced } in
273 let expected =
274 ExpectedTy.make_and_allow_coercion
275 param.param_pos
276 Reason.URparam
277 ty1_enforced
279 let (env, te, ty2) = expr ~expected env e in
280 Typing_sequencing.sequence_check_expr e;
281 let (env, ty1) =
283 Option.is_none (hint_of_type_hint param.param_type_hint)
284 && (not @@ TCO.global_inference (Env.get_tcopt env))
285 (* ty1 will be Tany iff we have no type hint and we are not in
286 * 'infer missing mode'. When it ty1 is Tany we just union it with
287 * the type of the default expression *)
288 then
289 Union.union env ty1 ty2
290 (* Otherwise we have an explicit type, and the default expression type
291 * must be a subtype *)
292 else
293 let env =
294 Typing_coercion.coerce_type
295 param.param_pos
296 Reason.URhint
299 ty1_enforced
300 Errors.parameter_default_value_wrong_type
302 (env, ty1)
304 (env, Some te, ty1)
306 let (env, user_attributes) =
307 List.map_env env param.param_user_attributes user_attribute
309 let tparam =
311 Aast.param_annotation = Tast.make_expr_annotation param.param_pos ty1;
312 Aast.param_type_hint = (ty1, hint_of_type_hint param.param_type_hint);
313 Aast.param_is_variadic = param.param_is_variadic;
314 Aast.param_pos = param.param_pos;
315 Aast.param_name = param.param_name;
316 Aast.param_expr = param_te;
317 Aast.param_callconv = param.param_callconv;
318 Aast.param_user_attributes = user_attributes;
319 Aast.param_visibility = param.param_visibility;
322 let mode = get_param_mode param.param_callconv in
323 let id = Local_id.make_unscoped param.param_name in
324 let env = Env.set_local env id ty1 param.param_pos in
325 let env = Env.set_param env id (ty1, param.param_pos, mode) in
326 let env =
327 if has_accept_disposable_attribute param then
328 Env.set_using_var env id
329 else
332 let env =
333 match get_param_mutability param with
334 | Some Param_borrowed_mutable ->
335 Env.add_mutable_var
338 (param.param_pos, Typing_mutability_env.Borrowed)
339 | Some Param_owned_mutable ->
340 Env.add_mutable_var env id (param.param_pos, Typing_mutability_env.Mutable)
341 | Some Param_maybe_mutable ->
342 Env.add_mutable_var
345 (param.param_pos, Typing_mutability_env.MaybeMutable)
346 | None ->
347 Env.add_mutable_var
350 (param.param_pos, Typing_mutability_env.Immutable)
352 (env, tparam)
354 and check_inout_return ret_pos env =
355 let params = Local_id.Map.elements (Env.get_params env) in
356 List.fold params ~init:env ~f:(fun env (id, (ty, param_pos, mode)) ->
357 match mode with
358 | FPinout ->
359 (* Whenever the function exits normally, we require that each local
360 * corresponding to an inout parameter be compatible with the original
361 * type for the parameter (under subtyping rules). *)
362 let (local_ty, local_pos) = Env.get_local_pos env id in
363 let (env, ety) = Env.expand_type env local_ty in
364 let pos =
365 if not (Pos.equal Pos.none local_pos) then
366 local_pos
367 else if not (Pos.equal Pos.none ret_pos) then
368 ret_pos
369 else
370 param_pos
372 let param_ty = mk (Reason.Rinout_param (get_pos ty), get_node ty) in
373 Type.sub_type
375 Reason.URassign_inout
378 param_ty
379 Errors.inout_return_type_mismatch
380 | _ -> env)
382 (*****************************************************************************)
383 (* function used to type closures, functions and methods *)
384 (*****************************************************************************)
385 and fun_ ?(abstract = false) ?(disable = false) env return pos named_body f_kind
387 Env.with_env env (fun env ->
388 debug_last_pos := pos;
389 let env = Env.set_return env return in
390 let (env, tb) =
391 if disable then
392 let () =
393 Errors.internal_error
395 ( "Type inference for this function has been disabled by the "
396 ^ SN.UserAttributes.uaDisableTypecheckerInternal
397 ^ " attribute" )
399 block env []
400 else
401 block env named_body.fb_ast
403 Typing_sequencing.sequence_check_block named_body.fb_ast;
404 let { Typing_env_return_info.return_type = ret; _ } =
405 Env.get_return env
407 let env =
409 (not @@ LEnv.has_next env)
410 || abstract
411 || Nast.named_body_is_unsafe named_body
412 then
414 else
415 fun_implicit_return env pos ret.et_type f_kind
417 debug_last_pos := Pos.none;
418 (env, tb))
420 and fun_implicit_return env pos ret = function
421 | Ast_defs.FGenerator
422 | Ast_defs.FAsyncGenerator ->
424 | Ast_defs.FSync ->
425 (* A function without a terminal block has an implicit return; the
426 * "void" type *)
427 let env = check_inout_return Pos.none env in
428 let r = Reason.Rno_return pos in
429 let rty = MakeType.void r in
430 Typing_return.implicit_return env pos ~expected:ret ~actual:rty
431 | Ast_defs.FAsync ->
432 (* An async function without a terminal block has an implicit return;
433 * the Awaitable<void> type *)
434 let r = Reason.Rno_return_async pos in
435 let rty = MakeType.awaitable r (MakeType.void r) in
436 Typing_return.implicit_return env pos ~expected:ret ~actual:rty
438 and block env stl =
439 Typing_env.with_origin env Decl_counters.Body @@ fun env ->
440 List.map_env env stl ~f:stmt
442 (* Set a local; must not be already assigned if it is a using variable *)
443 and set_local ?(is_using_clause = false) env (pos, x) ty =
444 if Env.is_using_var env x then
445 if is_using_clause then
446 Errors.duplicate_using_var pos
447 else
448 Errors.illegal_disposable pos "assigned";
449 let env = Env.set_local env x ty pos in
450 if is_using_clause then
451 Env.set_using_var env x
452 else
455 (* Check an individual component in the expression `e` in the
456 * `using (e) { ... }` statement.
457 * This consists of either
458 * a simple assignment `$x = e`, in which `$x` is the using variable, or
459 * an arbitrary expression `e`, in which case a temporary is the using
460 * variable, inaccessible in the source.
461 * Return the typed expression and its type, and any variables that must
462 * be designated as "using variables" for avoiding escapes.
464 and check_using_expr has_await env ((pos, content) as using_clause) =
465 match content with
466 (* Simple assignment to local of form `$lvar = e` *)
467 | Binop (Ast_defs.Eq None, (lvar_pos, Lvar lvar), e) ->
468 let (env, te, ty) = expr ~is_using_clause:true env e in
469 let env =
470 Typing_disposable.enforce_is_disposable_type env has_await (fst e) ty
472 let env = set_local ~is_using_clause:true env lvar ty in
473 (* We are assigning a new value to the local variable, so we need to
474 * generate a new expression id
476 let env = Env.set_local_expr_id env (snd lvar) (Ident.tmp ()) in
477 ( env,
478 ( Tast.make_typed_expr
481 (Aast.Binop
482 ( Ast_defs.Eq None,
483 Tast.make_typed_expr lvar_pos ty (Aast.Lvar lvar),
484 te )),
485 [snd lvar] ) )
486 (* Arbitrary expression. This will be assigned to a temporary *)
487 | _ ->
488 let (env, typed_using_clause, ty) =
489 expr ~is_using_clause:true env using_clause
491 let env =
492 Typing_disposable.enforce_is_disposable_type env has_await pos ty
494 (env, (typed_using_clause, []))
496 (* Check the using clause e in
497 * `using (e) { ... }` statement (`has_await = false`) or
498 * `await using (e) { ... }` statement (`has_await = true`).
499 * `using_clauses` is a list of expressions.
500 * Return the typed expression, and any variables that must
501 * be designated as "using variables" for avoiding escapes.
503 and check_using_clause env has_await using_clauses =
504 let (env, pairs) =
505 List.map_env env using_clauses (check_using_expr has_await)
507 let (typed_using_clauses, vars) = List.unzip pairs in
508 (env, typed_using_clauses, List.concat vars)
510 (* Require a new construct with disposable *)
511 and enforce_return_disposable _env e =
512 match e with
513 | (_, New _) -> ()
514 | (_, Call _) -> ()
515 | (_, Await (_, Call _)) -> ()
516 | (p, _) -> Errors.invalid_return_disposable p
518 (* Wrappers around the function with the same name in Typing_lenv, which only
519 * performs the move/save and merge operation if we are in a try block or in a
520 * function with return type 'noreturn'.
521 * This enables significant perf improvement, because this is called at every
522 * function of method call, when most calls are outside of a try block. *)
523 and move_and_merge_next_in_catch env =
524 if env.in_try || TFTerm.is_noreturn env then
525 LEnv.move_and_merge_next_in_cont env C.Catch
526 else
527 LEnv.drop_cont env C.Next
529 and save_and_merge_next_in_catch env =
530 if env.in_try || TFTerm.is_noreturn env then
531 LEnv.save_and_merge_next_in_cont env C.Catch
532 else
535 and might_throw env = save_and_merge_next_in_catch env
537 and stmt env (pos, st) =
538 let (env, st) = stmt_ env pos st in
539 Typing_debug.log_env_if_too_big pos env;
540 (env, (pos, st))
542 and stmt_ env pos st =
543 (* Type check a loop. f env = (env, result) checks the body of the loop.
544 * We iterate over the loop until the "next" continuation environment is
545 * stable. alias_depth is supposed to be an upper bound on this; but in
546 * certain cases this fails (e.g. a generic type grows unboundedly). TODO:
547 * fix this.
549 let infer_loop env f =
550 let in_loop_outer = env.in_loop in
551 let alias_depth =
552 if in_loop_outer then
554 else
555 Typing_alias.get_depth (pos, st)
557 let env = { env with in_loop = true } in
558 let rec loop env n =
559 (* Remember the old environment *)
560 let old_next_entry = Env.next_cont_opt env in
561 let (env, result) = f env in
562 let new_next_entry = Env.next_cont_opt env in
563 (* Finish if we reach the bound, or if the environments match *)
565 Int.equal n alias_depth
566 || Typing_per_cont_ops.is_sub_opt_entry
567 Typing_subtype.is_sub_type
569 new_next_entry
570 old_next_entry
571 then
572 let env = { env with in_loop = in_loop_outer } in
573 (env, result)
574 else
575 loop env (n + 1)
577 loop env 1
579 let env = Env.open_tyvars env pos in
580 (fun (env, tb) ->
581 (Typing_solver.close_tyvars_and_solve env Errors.unify_error, tb))
583 match st with
584 | Fallthrough ->
585 let env =
586 if env.in_case then
587 LEnv.move_and_merge_next_in_cont env C.Fallthrough
588 else
591 (env, Aast.Fallthrough)
592 | Noop -> (env, Aast.Noop)
593 | AssertEnv _ -> (env, Aast.Noop)
594 | Expr e ->
595 let (env, te, _) = expr env e in
596 let env =
597 if TFTerm.typed_expression_exits te then
598 LEnv.move_and_merge_next_in_cont env C.Exit
599 else
602 (env, Aast.Expr te)
603 | If (e, b1, b2) ->
604 let assert_refinement_env =
605 assert_env_blk ~pos ~at:`Start Aast.Refinement
607 let (env, te, _) = expr env e in
608 let (env, tb1, tb2) =
609 branch
611 (fun env ->
612 let (env, lset) = condition env true te in
613 let refinement_map = refinement_annot_map env lset in
614 let (env, b1) = block env b1 in
615 let b1 = assert_refinement_env refinement_map b1 in
616 (env, b1))
617 (fun env ->
618 let (env, lset) = condition env false te in
619 let refinement_map = refinement_annot_map env lset in
620 let (env, b2) = block env b2 in
621 let b2 = assert_refinement_env refinement_map b2 in
622 (env, b2))
624 (* TODO TAST: annotate with joined types *)
625 (env, Aast.If (te, tb1, tb2))
626 | Return None ->
627 let env = check_inout_return pos env in
628 let rty = MakeType.void (Reason.Rwitness pos) in
629 let { Typing_env_return_info.return_type = expected_return; _ } =
630 Env.get_return env
632 let expected_return =
633 Typing_return.strip_awaitable (Env.get_fn_kind env) env expected_return
635 let env =
636 match Env.get_fn_kind env with
637 | Ast_defs.FGenerator
638 | Ast_defs.FAsyncGenerator ->
640 | _ ->
641 Typing_return.implicit_return
644 ~expected:expected_return.et_type
645 ~actual:rty
647 let env = LEnv.move_and_merge_next_in_cont env C.Exit in
648 (env, Aast.Return None)
649 | Return (Some e) ->
650 let env = check_inout_return pos env in
651 let expr_pos = fst e in
652 let Typing_env_return_info.
654 return_type;
655 return_disposable;
656 return_mutable;
657 return_explicit;
658 return_void_to_rx;
659 return_dynamically_callable = _;
661 Env.get_return env
663 let return_type =
664 Typing_return.strip_awaitable (Env.get_fn_kind env) env return_type
666 let expected =
667 if return_explicit then
668 Some
669 (ExpectedTy.make_and_allow_coercion
670 expr_pos
671 Reason.URreturn
672 return_type)
673 else
674 None
676 if return_disposable then enforce_return_disposable env e;
677 let (env, te, rty) =
678 expr ~is_using_clause:return_disposable ?expected env e
680 let env =
681 if not (equal_reactivity (env_reactivity env) Nonreactive) then
682 Typing_mutability.handle_value_in_return
683 ~function_returns_mutable:return_mutable
684 ~function_returns_void_for_rx:return_void_to_rx
686 env.function_pos
688 else
691 let return_type =
693 return_type with
694 et_type = TR.strip_condition_type_in_return env return_type.et_type;
697 (* This is a unify_error rather than a return_type_mismatch because the return
698 * statement is the problem, not the return type itself. *)
699 let env =
700 Typing_coercion.coerce_type
701 expr_pos
702 Reason.URreturn
705 return_type
706 Errors.unify_error
708 let env = LEnv.move_and_merge_next_in_cont env C.Exit in
709 (env, Aast.Return (Some te))
710 | Do (b, e) ->
711 (* NOTE: leaks scope as currently implemented; this matches
712 the behavior in naming (cf. `do_stmt` in naming/naming.ml).
714 let (env, (tb, te)) =
715 LEnv.stash_and_do env [C.Continue; C.Break; C.Do] (fun env ->
716 let env = LEnv.save_and_merge_next_in_cont env C.Do in
717 let (env, _) = block env b in
718 (* saving the locals in continue here even if there is no continue
719 * statement because they must be merged at the end of the loop, in
720 * case there is no iteration *)
721 let env = LEnv.save_and_merge_next_in_cont env C.Continue in
722 let (env, tb) =
723 infer_loop env (fun env ->
724 let env =
725 LEnv.update_next_from_conts env [C.Continue; C.Next]
727 (* The following is necessary in case there is an assignment in the
728 * expression *)
729 let (env, te, _) = expr env e in
730 let (env, _lset) = condition env true te in
731 let env = LEnv.update_next_from_conts env [C.Do; C.Next] in
732 let (env, tb) = block env b in
733 (env, tb))
735 let env = LEnv.update_next_from_conts env [C.Continue; C.Next] in
736 let (env, te, _) = expr env e in
737 let (env, _lset) = condition env false te in
738 let env = LEnv.update_next_from_conts env [C.Break; C.Next] in
739 (env, (tb, te)))
741 (env, Aast.Do (tb, te))
742 | While (e, b) ->
743 let (env, (te, tb, refinement_map)) =
744 LEnv.stash_and_do env [C.Continue; C.Break] (fun env ->
745 let env = LEnv.save_and_merge_next_in_cont env C.Continue in
746 let (env, tb) =
747 infer_loop env (fun env ->
748 let env =
749 LEnv.update_next_from_conts env [C.Continue; C.Next]
751 let join_map = annot_map env in
752 (* The following is necessary in case there is an assignment in the
753 * expression *)
754 let (env, te, _) = expr env e in
755 let (env, lset) = condition env true te in
756 let refinement_map = refinement_annot_map env lset in
757 (* TODO TAST: avoid repeated generation of block *)
758 let (env, tb) = block env b in
760 (* Annotate loop body with join and refined environments *)
761 let assert_env_blk = assert_env_blk ~pos ~at:`Start in
762 let tb = assert_env_blk Aast.Refinement refinement_map tb in
763 let tb = assert_env_blk Aast.Join join_map tb in
765 (env, tb))
767 let env = LEnv.update_next_from_conts env [C.Continue; C.Next] in
768 let (env, te, _) = expr env e in
769 let (env, lset) = condition env false te in
770 let refinement_map_at_exit = refinement_annot_map env lset in
771 let env = LEnv.update_next_from_conts env [C.Break; C.Next] in
772 (env, (te, tb, refinement_map_at_exit)))
774 let while_st = Aast.While (te, tb) in
775 (* Export the refined environment after the exit condition holds *)
776 let while_st =
777 assert_env_stmt ~pos ~at:`End Aast.Refinement refinement_map while_st
779 (env, while_st)
780 | Using
782 us_has_await = has_await;
783 us_exprs = (loc, using_clause);
784 us_block = using_block;
785 us_is_block_scoped;
786 } ->
787 let (env, typed_using_clause, using_vars) =
788 check_using_clause env has_await using_clause
790 let (env, typed_using_block) = block env using_block in
791 (* Remove any using variables from the environment, as they should not
792 * be in scope outside the block *)
793 let env = List.fold_left using_vars ~init:env ~f:Env.unset_local in
794 ( env,
795 Aast.Using
796 Aast.
798 us_has_await = has_await;
799 us_exprs = (loc, typed_using_clause);
800 us_block = typed_using_block;
801 us_is_block_scoped;
803 | For (e1, e2, e3, b) ->
804 let e2 =
805 match e2 with
806 | Some e2 -> e2
807 | None -> (Pos.none, True)
809 let (env, (te1, te2, te3, tb, refinement_map)) =
810 LEnv.stash_and_do env [C.Continue; C.Break] (fun env ->
811 (* For loops leak their initalizer, but nothing that's defined in the
812 body
814 let (env, te1, _) = exprs env e1 in
815 (* initializer *)
816 let env = LEnv.save_and_merge_next_in_cont env C.Continue in
817 let (env, (tb, te3)) =
818 infer_loop env (fun env ->
819 (* The following is necessary in case there is an assignment in the
820 * expression *)
821 let (env, te2, _) = expr env e2 in
822 let (env, lset) = condition env true te2 in
823 let refinement_map = refinement_annot_map env lset in
824 let (env, tb) = block env b in
825 let env =
826 LEnv.update_next_from_conts env [C.Continue; C.Next]
828 let join_map = annot_map env in
829 let (env, te3, _) = exprs env e3 in
831 (* Export the join and refinement environments *)
832 let assert_env_blk = assert_env_blk ~pos ~at:`Start in
833 let tb = assert_env_blk Aast.Refinement refinement_map tb in
834 let tb = assert_env_blk Aast.Join join_map tb in
836 (env, (tb, te3)))
838 let env = LEnv.update_next_from_conts env [C.Continue; C.Next] in
839 let (env, te2, _) = expr env e2 in
840 let (env, lset) = condition env false te2 in
841 let refinement_map_at_exit = refinement_annot_map env lset in
842 let env = LEnv.update_next_from_conts env [C.Break; C.Next] in
843 (env, (te1, te2, te3, tb, refinement_map_at_exit)))
845 let for_st = Aast.For (te1, Some te2, te3, tb) in
846 let for_st =
847 assert_env_stmt ~pos ~at:`End Aast.Refinement refinement_map for_st
849 (env, for_st)
850 | Switch (((pos, _) as e), cl) ->
851 let (env, te, ty) = expr env e in
852 (* NB: A 'continue' inside a 'switch' block is equivalent to a 'break'.
853 * See the note in
854 * http://php.net/manual/en/control-structures.continue.php *)
855 let (env, (te, tcl)) =
856 LEnv.stash_and_do env [C.Continue; C.Break] (fun env ->
857 let parent_locals = LEnv.get_all_locals env in
858 let case_list env = case_list parent_locals ty env pos cl in
859 let (env, tcl) = Env.in_case env case_list in
860 let env =
861 LEnv.update_next_from_conts env [C.Continue; C.Break; C.Next]
863 (env, (te, tcl)))
865 (env, Aast.Switch (te, tcl))
866 | Foreach (e1, e2, b) ->
867 (* It's safe to do foreach over a disposable, as no leaking is possible *)
868 let (env, te1, ty1) = expr ~accept_using_var:true env e1 in
869 let (env, (te1, te2, tb)) =
870 LEnv.stash_and_do env [C.Continue; C.Break] (fun env ->
871 let env = LEnv.save_and_merge_next_in_cont env C.Continue in
872 let (env, tk, tv) = as_expr env ty1 (fst e1) e2 in
873 let (env, (te2, tb)) =
874 infer_loop env (fun env ->
875 let env =
876 LEnv.update_next_from_conts env [C.Continue; C.Next]
878 let join_map = annot_map env in
879 let (env, te2) = bind_as_expr env (fst e1) tk tv e2 in
880 let (env, tb) = block env b in
881 (* Export the join environment *)
882 let tb = assert_env_blk ~pos ~at:`Start Aast.Join join_map tb in
883 (env, (te2, tb)))
885 let env =
886 LEnv.update_next_from_conts env [C.Continue; C.Break; C.Next]
888 (env, (te1, te2, tb)))
890 (env, Aast.Foreach (te1, te2, tb))
891 | Try (tb, cl, fb) ->
892 let (env, ttb, tcl, tfb) = try_catch env tb cl fb in
893 (env, Aast.Try (ttb, tcl, tfb))
894 | Awaitall (el, b) ->
895 let env = might_throw env in
896 let (env, el) =
897 List.fold_left el ~init:(env, []) ~f:(fun (env, tel) (e1, e2) ->
898 let (env, te2, ty2) = expr env e2 in
899 let (env, ty2) =
900 Async.overload_extract_from_awaitable env (fst e2) ty2
902 match e1 with
903 | Some e1 ->
904 let (env, _, _) = assign (fst e1) env (fst e1, Lvar e1) ty2 in
905 (env, (Some e1, te2) :: tel)
906 | None -> (env, (None, te2) :: tel))
908 let (env, b) = block env b in
909 (env, Aast.Awaitall (el, b))
910 | Throw e ->
911 let p = fst e in
912 let (env, te, ty) = expr env e in
913 let env = coerce_to_throwable p env ty in
914 let env = move_and_merge_next_in_catch env in
915 (env, Aast.Throw te)
916 | Continue ->
917 let env = LEnv.move_and_merge_next_in_cont env C.Continue in
918 (env, Aast.Continue)
919 | Break ->
920 let env = LEnv.move_and_merge_next_in_cont env C.Break in
921 (env, Aast.Break)
922 | Block _
923 | Markup _ ->
924 failwith
925 "Unexpected nodes in AST. These nodes should have been removed in naming."
927 and branch :
928 type res. env -> (env -> env * res) -> (env -> env * res) -> env * res * res
930 fun env branch1 branch2 ->
931 let parent_lenv = env.lenv in
932 let (env, tbr1) = branch1 env in
933 let lenv1 = env.lenv in
934 let env = { env with lenv = parent_lenv } in
935 let (env, tbr2) = branch2 env in
936 let lenv2 = env.lenv in
937 let env = LEnv.union_lenvs env parent_lenv lenv1 lenv2 in
938 (env, tbr1, tbr2)
940 and finally_cont fb env ctx =
941 (* The only locals in scope are the ones from the current continuation *)
942 let env = Env.env_with_locals env @@ CMap.singleton C.Next ctx in
943 let (env, _tfb) = block env fb in
944 (env, LEnv.get_all_locals env)
946 and finally env fb =
947 match fb with
948 | [] ->
949 let env = LEnv.update_next_from_conts env [C.Next; C.Finally] in
950 (env, [])
951 | _ ->
952 let parent_locals = LEnv.get_all_locals env in
953 (* First typecheck the finally block against all continuations merged
954 * together.
955 * During this phase, record errors found in the finally block, but discard
956 * the resulting environment. *)
957 let all_conts = Env.all_continuations env in
958 let env = LEnv.update_next_from_conts env all_conts in
959 let (env, tfb) = block env fb in
960 let env = LEnv.restore_conts_from env parent_locals all_conts in
961 (* Second, typecheck the finally block once against each continuation. This
962 * helps be more clever about what each continuation will be after the
963 * finally block.
964 * We don't want to record errors during this phase, because certain types
965 * of errors will fire wrongly. For example, if $x is nullable in some
966 * continuations but not in others, then we must use `?->` on $x, but an
967 * error will fire when typechecking the finally block againts continuations
968 * where $x is non-null. *)
969 let finally_cont env _key = finally_cont fb env in
970 let (env, locals_map) =
971 Errors.ignore_ (fun () -> CMap.map_env finally_cont env parent_locals)
973 let union env _key = LEnv.union_contextopts env in
974 let (env, locals) = Try.finally_merge union env locals_map all_conts in
975 (Env.env_with_locals env locals, tfb)
977 and try_catch env tb cl fb =
978 let parent_locals = LEnv.get_all_locals env in
979 let env =
980 LEnv.drop_conts env [C.Break; C.Continue; C.Exit; C.Catch; C.Finally]
982 let (env, (ttb, tcb)) =
983 Env.in_try env (fun env ->
984 let (env, ttb) = block env tb in
985 let env = LEnv.move_and_merge_next_in_cont env C.Finally in
986 let catchctx = LEnv.get_cont_option env C.Catch in
987 let (env, lenvtcblist) = List.map_env env ~f:(catch catchctx) cl in
988 let (lenvl, tcb) = List.unzip lenvtcblist in
989 let env = LEnv.union_lenv_list env env.lenv lenvl in
990 let env = LEnv.move_and_merge_next_in_cont env C.Finally in
991 (env, (ttb, tcb)))
993 let (env, tfb) = finally env fb in
994 let env = LEnv.update_next_from_conts env [C.Finally] in
995 let env = LEnv.drop_cont env C.Finally in
996 let env =
997 LEnv.restore_and_merge_conts_from
999 parent_locals
1000 [C.Break; C.Continue; C.Exit; C.Catch; C.Finally]
1002 (env, ttb, tcb, tfb)
1004 and case_list parent_locals ty env switch_pos cl =
1005 let initialize_next_cont env =
1006 let env = LEnv.restore_conts_from env parent_locals [C.Next] in
1007 let env = LEnv.update_next_from_conts env [C.Next; C.Fallthrough] in
1008 LEnv.drop_cont env C.Fallthrough
1010 let check_fallthrough env switch_pos case_pos block rest_of_list ~is_default =
1011 if not @@ List.is_empty block then
1012 match rest_of_list with
1013 | []
1014 | [Default (_, [])] ->
1016 | _ ->
1017 begin
1018 match LEnv.get_cont_option env C.Next with
1019 | Some _ ->
1020 if is_default then
1021 Errors.default_fallthrough switch_pos
1022 else
1023 Errors.case_fallthrough switch_pos case_pos
1024 | None -> ()
1026 (* match *)
1027 (* match *)
1028 else
1031 let make_exhaustive_equivalent_case_list env cl =
1032 let has_default =
1033 List.exists cl ~f:(function
1034 | Default _ -> true
1035 | _ -> false)
1037 let (env, ty) =
1038 (* If it hasn't got a default clause then we need to solve type variables
1039 * in order to check for an enum *)
1040 if has_default then
1041 Env.expand_type env ty
1042 else
1043 Typing_solver.expand_type_and_solve
1045 ~description_of_expected:"a value"
1046 switch_pos
1048 Errors.unify_error
1050 let is_enum =
1051 let top_type =
1052 MakeType.class_type
1053 Reason.Rnone
1054 SN.Classes.cHH_BuiltinEnum
1055 [MakeType.mixed Reason.Rnone]
1057 Typing_subtype.is_sub_type_for_coercion env ty top_type
1059 (* If there is no default case and this is not a switch on enum (since
1060 * exhaustiveness is garanteed elsewhere on enums),
1061 * then add a default case for control flow correctness
1063 if has_default || is_enum then
1064 (env, cl, false)
1065 else
1066 (env, cl @ [Default (Pos.none, [])], true)
1068 let rec case_list env = function
1069 | [] -> (env, [])
1070 | Default (pos, b) :: rl ->
1071 let env = initialize_next_cont env in
1072 let (env, tb) = block env b in
1073 check_fallthrough env switch_pos pos b rl ~is_default:true;
1074 let (env, tcl) = case_list env rl in
1075 (env, Aast.Default (pos, tb) :: tcl)
1076 | Case (((pos, _) as e), b) :: rl ->
1077 let env = initialize_next_cont env in
1078 let (env, te, _) = expr env e in
1079 let (env, tb) = block env b in
1080 check_fallthrough env switch_pos pos b rl ~is_default:false;
1081 let (env, tcl) = case_list env rl in
1082 (env, Aast.Case (te, tb) :: tcl)
1084 let (env, cl, added_empty_default) =
1085 make_exhaustive_equivalent_case_list env cl
1087 let (env, tcl) = case_list env cl in
1088 let tcl =
1089 if added_empty_default then
1090 List.take tcl (List.length tcl - 1)
1091 else
1094 (env, tcl)
1096 and catch catchctx env (sid, exn_lvar, b) =
1097 let env = LEnv.replace_cont env C.Next catchctx in
1098 let cid = CI sid in
1099 let ety_p = fst sid in
1100 let (env, _, _, _) = instantiable_cid ety_p env cid [] in
1101 let (env, _tal, _te, ety) =
1102 static_class_id ~check_constraints:false ety_p env [] cid
1104 let env = coerce_to_throwable ety_p env ety in
1105 let env = set_local env exn_lvar ety in
1106 let (env, tb) = block env b in
1107 (env, (env.lenv, (sid, exn_lvar, tb)))
1109 and as_expr env ty1 pe e =
1110 let env = Env.open_tyvars env pe in
1111 let (env, tv) = Env.fresh_type env pe in
1112 let (env, expected_ty, tk, tv) =
1113 match e with
1114 | As_v _ ->
1115 let tk = MakeType.mixed Reason.Rnone in
1116 (env, MakeType.traversable (Reason.Rforeach pe) tv, tk, tv)
1117 | As_kv _ ->
1118 let (env, tk) = Env.fresh_type env pe in
1119 (env, MakeType.keyed_traversable (Reason.Rforeach pe) tk tv, tk, tv)
1120 | Await_as_v _ ->
1121 let tk = MakeType.mixed Reason.Rnone in
1122 (env, MakeType.async_iterator (Reason.Rasyncforeach pe) tv, tk, tv)
1123 | Await_as_kv _ ->
1124 let (env, tk) = Env.fresh_type env pe in
1125 ( env,
1126 MakeType.async_keyed_iterator (Reason.Rasyncforeach pe) tk tv,
1128 tv )
1130 let rec distribute_union env ty =
1131 let (env, ty) = Env.expand_type env ty in
1132 match get_node ty with
1133 | Tunion tyl -> List.fold tyl ~init:env ~f:distribute_union
1134 | _ ->
1135 if SubType.is_sub_type_for_union env ty (MakeType.dynamic Reason.Rnone)
1136 then
1137 let env = SubType.sub_type env ty tk Errors.unify_error in
1138 let env = SubType.sub_type env ty tv Errors.unify_error in
1140 else
1141 let ur = Reason.URforeach in
1142 Type.sub_type pe ur env ty expected_ty Errors.unify_error
1144 let env = distribute_union env ty1 in
1145 let env = Env.set_tyvar_variance env expected_ty in
1146 (Typing_solver.close_tyvars_and_solve env Errors.unify_error, tk, tv)
1148 and bind_as_expr env p ty1 ty2 aexpr =
1149 let check_reassigned_mutable env te =
1150 if Env.env_local_reactive env then
1151 Typing_mutability.handle_assignment_mutability env te None
1152 else
1155 match aexpr with
1156 | As_v ev ->
1157 let (env, te, _) = assign p env ev ty2 in
1158 let env = check_reassigned_mutable env te in
1159 (env, Aast.As_v te)
1160 | Await_as_v (p, ev) ->
1161 let (env, te, _) = assign p env ev ty2 in
1162 let env = check_reassigned_mutable env te in
1163 (env, Aast.Await_as_v (p, te))
1164 | As_kv ((p, Lvar ((_, k) as id)), ev) ->
1165 let env = set_valid_rvalue p env k ty1 in
1166 let (env, te, _) = assign p env ev ty2 in
1167 let tk = Tast.make_typed_expr p ty1 (Aast.Lvar id) in
1168 let env = check_reassigned_mutable env tk in
1169 let env = check_reassigned_mutable env te in
1170 (env, Aast.As_kv (tk, te))
1171 | Await_as_kv (p, (p1, Lvar ((_, k) as id)), ev) ->
1172 let env = set_valid_rvalue p env k ty1 in
1173 let (env, te, _) = assign p env ev ty2 in
1174 let tk = Tast.make_typed_expr p1 ty1 (Aast.Lvar id) in
1175 let env = check_reassigned_mutable env tk in
1176 let env = check_reassigned_mutable env te in
1177 (env, Aast.Await_as_kv (p, tk, te))
1178 | _ ->
1179 (* TODO Probably impossible, should check that *)
1180 assert false
1182 and expr
1183 ?(expected : ExpectedTy.t option)
1184 ?(accept_using_var = false)
1185 ?(is_using_clause = false)
1186 ?(valkind = `other)
1187 ?(check_defined = true)
1188 ?in_await
1190 ((p, _) as e) =
1192 begin
1193 match expected with
1194 | None -> ()
1195 | Some ExpectedTy.{ reason = r; ty = { et_type = ty; _ }; _ } ->
1196 Typing_log.(
1197 log_with_level env "typing" 1 (fun () ->
1198 log_types
1202 Log_head
1203 ( "Typing.expr " ^ Typing_reason.string_of_ureason r,
1204 [Log_type ("expected_ty", ty)] );
1206 end;
1207 raw_expr
1208 ~accept_using_var
1209 ~is_using_clause
1210 ~valkind
1211 ~check_defined
1212 ?in_await
1213 ?expected
1216 with Inf.InconsistentTypeVarState _ as e ->
1217 (* we don't want to catch unwanted exceptions here, eg Timeouts *)
1218 Errors.exception_occurred p (Exception.wrap e);
1219 make_result env p Aast.Any @@ err_witness env p
1221 and raw_expr
1222 ?(accept_using_var = false)
1223 ?(is_using_clause = false)
1224 ?(expected : ExpectedTy.t option)
1225 ?lhs_of_null_coalesce
1226 ?(valkind = `other)
1227 ?(check_defined = true)
1228 ?in_await
1231 debug_last_pos := fst e;
1232 expr_
1233 ~accept_using_var
1234 ~is_using_clause
1235 ?expected
1236 ?lhs_of_null_coalesce
1237 ?in_await
1238 ~valkind
1239 ~check_defined
1243 and lvalue env e =
1244 let valkind = `lvalue in
1245 expr_ ~valkind ~check_defined:false env e
1247 and lvalues env el =
1248 match el with
1249 | [] -> (env, [], [])
1250 | e :: el ->
1251 let (env, te, ty) = lvalue env e in
1252 let (env, tel, tyl) = lvalues env el in
1253 (env, te :: tel, ty :: tyl)
1255 and is_pseudo_function s =
1256 String.equal s SN.PseudoFunctions.hh_show
1257 || String.equal s SN.PseudoFunctions.hh_show_env
1258 || String.equal s SN.PseudoFunctions.hh_log_level
1259 || String.equal s SN.PseudoFunctions.hh_force_solve
1260 || String.equal s SN.PseudoFunctions.hh_loop_forever
1262 and loop_forever env =
1263 (* forever = up to 10 minutes, to avoid accidentally stuck processes *)
1264 for i = 1 to 600 do
1265 (* Look up things in shared memory occasionally to have a chance to be
1266 * interrupted *)
1267 match Env.get_class env "FOR_TEST_ONLY" with
1268 | None -> Unix.sleep 1
1269 | _ -> assert false
1270 done;
1271 Utils.assert_false_log_backtrace
1272 (Some "hh_loop_forever was looping for more than 10 minutes")
1274 (* $x ?? 0 is handled similarly to $x ?: 0, except that the latter will also
1275 * look for sketchy null checks in the condition. *)
1276 (* TODO TAST: type refinement should be made explicit in the typed AST *)
1277 and eif env ~(expected : ExpectedTy.t option) ?in_await p c e1 e2 =
1278 let condition = condition ~lhs_of_null_coalesce:false in
1279 let (env, tc, tyc) = raw_expr ~lhs_of_null_coalesce:false env c in
1280 let parent_lenv = env.lenv in
1281 let (env, _lset) = condition env true tc in
1282 let (env, te1, ty1) =
1283 match e1 with
1284 | None ->
1285 let (env, ty) = Typing_solver.non_null env p tyc in
1286 (env, None, ty)
1287 | Some e1 ->
1288 let (env, te1, ty1) = expr ?expected ?in_await env e1 in
1289 (env, Some te1, ty1)
1291 let lenv1 = env.lenv in
1292 let env = { env with lenv = parent_lenv } in
1293 let (env, _lset) = condition env false tc in
1294 let (env, te2, ty2) = expr ?expected ?in_await env e2 in
1295 let lenv2 = env.lenv in
1296 let env = LEnv.union_lenvs env parent_lenv lenv1 lenv2 in
1297 let (env, ty) = Union.union env ty1 ty2 in
1298 make_result env p (Aast.Eif (tc, te1, te2)) ty
1300 and is_parameter env x = Local_id.Map.mem x (Env.get_params env)
1302 and check_escaping_var env (pos, x) =
1303 if Env.is_using_var env x then
1304 if Local_id.equal x this then
1305 Errors.escaping_this pos
1306 else if is_parameter env x then
1307 Errors.escaping_disposable_parameter pos
1308 else
1309 Errors.escaping_disposable pos
1310 else
1313 and exprs
1314 ?(accept_using_var = false)
1315 ?(expected : ExpectedTy.t option)
1316 ?(valkind = `other)
1317 ?(check_defined = true)
1319 el =
1320 match el with
1321 | [] -> (env, [], [])
1322 | e :: el ->
1323 let (env, te, ty) =
1324 expr ~accept_using_var ?expected ~valkind ~check_defined env e
1326 let (env, tel, tyl) =
1327 exprs ~accept_using_var ?expected ~valkind ~check_defined env el
1329 (env, te :: tel, ty :: tyl)
1331 and exprs_expected (pos, ur, expected_tyl) env el =
1332 match (el, expected_tyl) with
1333 | ([], _) -> (env, [], [])
1334 | (e :: el, expected_ty :: expected_tyl) ->
1335 let expected = ExpectedTy.make pos ur expected_ty in
1336 let (env, te, ty) = expr ~expected env e in
1337 let (env, tel, tyl) = exprs_expected (pos, ur, expected_tyl) env el in
1338 (env, te :: tel, ty :: tyl)
1339 | (el, []) -> exprs env el
1341 and make_result env p te ty =
1342 (* Set the variance of any type variables that were generated according
1343 * to how they appear in the expression type *)
1344 let env = Env.set_tyvar_variance env ty in
1345 (env, Tast.make_typed_expr p ty te, ty)
1347 and localize_targ env ta =
1348 let pos = fst ta in
1349 let (env, targ) = Phase.localize_targ ~check_well_kinded:true env ta in
1350 (env, targ, ExpectedTy.make pos Reason.URhint (fst targ))
1352 and set_function_pointer ty =
1353 match get_node ty with
1354 | Tfun ft ->
1355 let ft = set_ft_is_function_pointer ft true in
1356 mk (get_reason ty, Tfun ft)
1357 | _ -> ty
1359 and expr_
1360 ?(expected : ExpectedTy.t option)
1361 ?(accept_using_var = false)
1362 ?(is_using_clause = false)
1363 ?lhs_of_null_coalesce
1364 ?in_await
1365 ~(valkind : [> `lvalue | `lvalue_subexpr | `other ])
1366 ~check_defined
1368 ((p, e) as outer) =
1369 let env = Env.open_tyvars env p in
1370 (fun (env, te, ty) ->
1371 let env = Typing_solver.close_tyvars_and_solve env Errors.unify_error in
1372 (env, te, ty))
1374 let expr = expr ~check_defined in
1375 let exprs = exprs ~check_defined in
1376 let raw_expr = raw_expr ~check_defined in
1378 * Given a list of types, computes their supertype. If any of the types are
1379 * unknown (e.g., comes from PHP), the supertype will be Typing_utils.tany env.
1381 let compute_supertype
1382 ~(expected : ExpectedTy.t option) ~reason ~use_pos r env tys =
1383 let (env, supertype) =
1384 match expected with
1385 | None -> Env.fresh_type_reason env r
1386 | Some ExpectedTy.{ ty = { et_type = ty; _ }; _ } -> (env, ty)
1388 match get_node supertype with
1389 (* No need to check individual subtypes if expected type is mixed or any! *)
1390 | Tany _ -> (env, supertype)
1391 | _ ->
1392 let subtype_value env ty =
1393 Type.sub_type use_pos reason env ty supertype Errors.unify_error
1395 let env = List.fold_left tys ~init:env ~f:subtype_value in
1397 List.exists tys (fun ty ->
1398 equal_locl_ty_ (get_node ty) (Typing_utils.tany env))
1399 then
1400 (* If one of the values comes from PHP land, we have to be conservative
1401 * and consider that we don't know what the type of the values are. *)
1402 (env, Typing_utils.mk_tany env p)
1403 else
1404 (env, supertype)
1407 * Given a 'a list and a method to extract an expr and its ty from a 'a, this
1408 * function extracts a list of exprs from the list, and computes the supertype
1409 * of all of the expressions' tys.
1411 let compute_exprs_and_supertype
1412 ~(expected : ExpectedTy.t option)
1413 ?(reason = Reason.URarray_value)
1414 ~use_pos
1418 extract_expr_and_ty =
1419 let (env, exprs_and_tys) =
1420 List.map_env env l (extract_expr_and_ty ~expected)
1422 let (exprs, tys) = List.unzip exprs_and_tys in
1423 let (env, supertype) =
1424 compute_supertype ~expected ~reason ~use_pos r env tys
1426 (env, exprs, supertype)
1428 let forget_fake_members env p callexpr =
1429 (* Some functions are well known to not change the types of members, e.g.
1430 * `is_null`.
1431 * There are a lot of usages like
1432 * if (!is_null($x->a) && !is_null($x->a->b))
1433 * where the second is_null call invalidates the first condition.
1434 * This function is a bit best effort. Add stuff here when you want
1435 * To avoid adding too many undue HH_FIXMEs. *)
1436 match callexpr with
1437 | (_, Id (_, func))
1438 when String.equal func SN.StdlibFunctions.is_null
1439 || String.equal func SN.PseudoFunctions.isset ->
1441 | _ -> Env.forget_members env Reason.(Blame (p, BScall))
1443 let check_call
1444 ~is_using_clause
1445 ~(expected : ExpectedTy.t option)
1446 ?in_await
1450 explicit_targs
1452 unpacked_element =
1453 let (env, te, result) =
1454 dispatch_call
1455 ~is_using_clause
1456 ~expected
1457 ?in_await
1461 explicit_targs
1463 unpacked_element
1465 let env = forget_fake_members env p e in
1466 (env, te, result)
1468 match e with
1469 | Import _
1470 | Collection _ ->
1471 failwith "AST should not contain these nodes"
1472 | Omitted ->
1473 let ty = Typing_utils.mk_tany env p in
1474 make_result env p Aast.Omitted ty
1475 | Any -> expr_error env (Reason.Rwitness p) outer
1476 | Varray (th, el)
1477 | ValCollection (_, th, el) ->
1478 let (get_expected_kind, name, subtype_val, make_expr, make_ty) =
1479 match e with
1480 | ValCollection (kind, _, _) ->
1481 let class_name = Nast.vc_kind_to_name kind in
1482 let subtype_val =
1483 match kind with
1484 | Set
1485 | ImmSet
1486 | Keyset ->
1487 arraykey_value p class_name
1488 | Vector
1489 | ImmVector
1490 | Vec ->
1491 array_value
1493 ( get_vc_inst kind,
1494 class_name,
1495 subtype_val,
1496 (fun th elements -> Aast.ValCollection (kind, th, elements)),
1497 fun value_ty ->
1498 MakeType.class_type (Reason.Rwitness p) class_name [value_ty] )
1499 | Varray _ ->
1500 ( get_varray_inst,
1501 "varray",
1502 array_value,
1503 (fun th elements -> Aast.Varray (th, elements)),
1504 (fun value_ty -> MakeType.varray (Reason.Rwitness p) value_ty) )
1505 | _ ->
1506 (* The parent match makes this case impossible *)
1507 failwith "impossible match case"
1509 (* Use expected type to determine expected element type *)
1510 let (env, elem_expected, th) =
1511 match th with
1512 | Some (_, tv) ->
1513 let (env, tv, tv_expected) = localize_targ env tv in
1514 (env, Some tv_expected, Some tv)
1515 | _ ->
1516 begin
1517 match expand_expected_and_get_node env expected with
1518 | (env, Some (pos, ur, ety, _)) ->
1519 begin
1520 match get_expected_kind ety with
1521 | Some vty -> (env, Some (ExpectedTy.make pos ur vty), None)
1522 | None -> (env, None, None)
1524 | _ -> (env, None, None)
1527 let (env, tel, elem_ty) =
1528 compute_exprs_and_supertype
1529 ~expected:elem_expected
1530 ~use_pos:p
1531 ~reason:Reason.URvector
1532 (Reason.Rtype_variable_generics (p, "T", strip_ns name))
1535 subtype_val
1537 make_result env p (make_expr th tel) (make_ty elem_ty)
1538 | Darray (th, l)
1539 | KeyValCollection (_, th, l) ->
1540 let (get_expected_kind, name, make_expr, make_ty) =
1541 match e with
1542 | KeyValCollection (kind, _, _) ->
1543 let class_name = Nast.kvc_kind_to_name kind in
1544 ( get_kvc_inst p kind,
1545 class_name,
1546 (fun th pairs -> Aast.KeyValCollection (kind, th, pairs)),
1547 (fun k v -> MakeType.class_type (Reason.Rwitness p) class_name [k; v])
1549 | Darray _ ->
1550 ( get_darray_inst p,
1551 "darray",
1552 (fun th pairs -> Aast.Darray (th, pairs)),
1553 (fun k v -> MakeType.darray (Reason.Rwitness p) k v) )
1554 | _ ->
1555 (* The parent match makes this case impossible *)
1556 failwith "impossible match case"
1558 (* Use expected type to determine expected key and value types *)
1559 let (env, kexpected, vexpected, th) =
1560 match th with
1561 | Some ((_, tk), (_, tv)) ->
1562 let (env, tk, tk_expected) = localize_targ env tk in
1563 let (env, tv, tv_expected) = localize_targ env tv in
1564 (env, Some tk_expected, Some tv_expected, Some (tk, tv))
1565 | _ ->
1566 (* no explicit typehint, fallback to supplied expect *)
1567 begin
1568 match expand_expected_and_get_node env expected with
1569 | (env, Some (pos, reason, ety, _)) ->
1570 begin
1571 match get_expected_kind ety with
1572 | Some (kty, vty) ->
1573 let k_expected = ExpectedTy.make pos reason kty in
1574 let v_expected = ExpectedTy.make pos reason vty in
1575 (env, Some k_expected, Some v_expected, None)
1576 | None -> (env, None, None, None)
1578 | _ -> (env, None, None, None)
1581 let (kl, vl) = List.unzip l in
1582 let (env, tkl, k) =
1583 compute_exprs_and_supertype
1584 ~expected:kexpected
1585 ~use_pos:p
1586 ~reason:Reason.URkey
1587 (Reason.Rtype_variable_generics (p, "Tk", strip_ns name))
1590 (arraykey_value p name)
1592 let (env, tvl, v) =
1593 compute_exprs_and_supertype
1594 ~expected:vexpected
1595 ~use_pos:p
1596 ~reason:Reason.URvalue
1597 (Reason.Rtype_variable_generics (p, "Tv", strip_ns name))
1600 array_value
1602 let pairs = List.zip_exn tkl tvl in
1603 make_result env p (make_expr th pairs) (make_ty k v)
1604 | Clone e ->
1605 let (env, te, ty) = expr env e in
1606 (* Clone only works on objects; anything else fatals at runtime *)
1607 let tobj = mk (Reason.Rwitness p, Tobject) in
1608 let env = Type.sub_type p Reason.URclone env ty tobj Errors.unify_error in
1609 make_result env p (Aast.Clone te) ty
1610 | This ->
1611 if Option.is_none (Env.get_self_ty env) then Errors.this_var_outside_class p;
1612 if not accept_using_var then check_escaping_var env (p, this);
1613 let ty = Env.get_local env this in
1614 let r = Reason.Rwitness p in
1615 let ty = mk (r, TUtils.this_of (mk (r, get_node ty))) in
1616 make_result env p Aast.This ty
1617 | True -> make_result env p Aast.True (MakeType.bool (Reason.Rwitness p))
1618 | False -> make_result env p Aast.False (MakeType.bool (Reason.Rwitness p))
1619 (* TODO TAST: consider checking that the integer is in range. Right now
1620 * it's possible for HHVM to fail on well-typed Hack code
1622 | Int s -> make_result env p (Aast.Int s) (MakeType.int (Reason.Rwitness p))
1623 | Float s ->
1624 make_result env p (Aast.Float s) (MakeType.float (Reason.Rwitness p))
1625 (* TODO TAST: consider introducing a "null" type, and defining ?t to
1626 * be null | t
1628 | Null -> make_result env p Aast.Null (MakeType.null (Reason.Rwitness p))
1629 | String s ->
1630 make_result env p (Aast.String s) (MakeType.string (Reason.Rwitness p))
1631 | String2 idl ->
1632 let (env, tel) = string2 env idl in
1633 make_result env p (Aast.String2 tel) (MakeType.string (Reason.Rwitness p))
1634 | PrefixedString (n, e) ->
1635 if String.( <> ) n "re" then (
1636 Errors.experimental_feature
1638 "String prefixes other than `re` are not yet supported.";
1639 expr_error env Reason.Rnone outer
1640 ) else
1641 let (env, te, ty) = expr env e in
1642 let pe = fst e in
1643 let env = Typing_substring.sub_string pe env ty in
1644 (match snd e with
1645 | String _ ->
1646 begin
1648 make_result
1651 (Aast.PrefixedString (n, te))
1652 (Typing_regex.type_pattern e)
1653 with
1654 | Pcre.Error (Pcre.BadPattern (s, i)) ->
1655 let s = s ^ " [" ^ string_of_int i ^ "]" in
1656 Errors.bad_regex_pattern pe s;
1657 expr_error env (Reason.Rregex pe) e
1658 | Typing_regex.Empty_regex_pattern ->
1659 Errors.bad_regex_pattern pe "This pattern is empty";
1660 expr_error env (Reason.Rregex pe) e
1661 | Typing_regex.Missing_delimiter ->
1662 Errors.bad_regex_pattern pe "Missing delimiter(s)";
1663 expr_error env (Reason.Rregex pe) e
1664 | Typing_regex.Invalid_global_option ->
1665 Errors.bad_regex_pattern pe "Invalid global option(s)";
1666 expr_error env (Reason.Rregex pe) e
1668 | String2 _ ->
1669 Errors.re_prefixed_non_string pe "Strings with embedded expressions";
1670 expr_error env (Reason.Rregex pe) e
1671 | _ ->
1672 Errors.re_prefixed_non_string pe "Non-strings";
1673 expr_error env (Reason.Rregex pe) e)
1674 | Fun_id x ->
1675 let (env, fty, _tal) = fun_type_of_id env x [] [] in
1676 make_result env p (Aast.Fun_id x) fty
1677 | Id ((cst_pos, cst_name) as id) ->
1678 (match Env.get_gconst env cst_name with
1679 | None when Partial.should_check_error (Env.get_mode env) 4106 ->
1680 Errors.unbound_global cst_pos;
1681 let ty = err_witness env cst_pos in
1682 make_result env cst_pos (Aast.Id id) ty
1683 | None -> make_result env p (Aast.Id id) (Typing_utils.mk_tany env cst_pos)
1684 | Some ty ->
1685 let (env, ty) = Phase.localize_with_self ~pos:p env ty in
1686 make_result env p (Aast.Id id) ty)
1687 | Method_id (instance, meth) ->
1688 (* Method_id is used when creating a "method pointer" using the magic
1689 * inst_meth function.
1691 * Typing this is pretty simple, we just need to check that instance->meth
1692 * is public+not static and then return its type.
1694 let (env, te, ty1) = expr env instance in
1695 let (env, (result, _tal)) =
1696 TOG.obj_get_
1697 ~inst_meth:true
1698 ~obj_pos:p
1699 ~is_method:true
1700 ~nullsafe:None
1701 ~coerce_from_ty:None
1702 ~is_nonnull:false
1703 ~explicit_targs:[]
1706 (CIexpr instance)
1707 meth
1708 (fun x -> x)
1709 Errors.unify_error
1711 let (env, result) =
1712 Env.FakeMembers.check_instance_invalid env instance (snd meth) result
1714 make_result env p (Aast.Method_id (te, meth)) result
1715 | Method_caller (((pos, class_name) as pos_cname), meth_name) ->
1716 (* meth_caller('X', 'foo') desugars to:
1717 * $x ==> $x->foo()
1719 let class_ = Env.get_class env class_name in
1720 (match class_ with
1721 | None -> unbound_name env pos_cname outer
1722 | Some class_ ->
1723 (* Create a class type for the given object instantiated with unresolved
1724 * types for its type parameters.
1726 let () =
1727 if Ast_defs.is_c_trait (Cls.kind class_) then
1728 Errors.meth_caller_trait pos class_name
1730 let (env, tvarl) =
1731 List.map_env env (Cls.tparams class_) (fun env _ ->
1732 Env.fresh_type env p)
1734 let params =
1735 List.map (Cls.tparams class_) (fun { tp_name = (p, n); _ } ->
1736 (* TODO(T69551141) handle type arguments for Tgeneric *)
1737 MakeType.generic (Reason.Rwitness p) n)
1739 let obj_type = MakeType.apply (Reason.Rwitness p) pos_cname params in
1740 let ety_env =
1742 (Phase.env_with_self env) with
1743 substs = TUtils.make_locl_subst_for_class_tparams class_ tvarl;
1746 let (env, local_obj_ty) = Phase.localize ~ety_env env obj_type in
1747 let (env, (fty, _tal)) =
1748 TOG.obj_get
1749 ~obj_pos:pos
1750 ~is_method:true
1751 ~nullsafe:None
1752 ~coerce_from_ty:None
1753 ~explicit_targs:[]
1755 local_obj_ty
1756 (CI (pos, class_name))
1757 meth_name
1758 Errors.unify_error
1760 let (env, fty) = Env.expand_type env fty in
1761 (match deref fty with
1762 | (reason, Tfun ftype) ->
1763 (* We are creating a fake closure:
1764 * function(Class $x, arg_types_of(Class::meth_name))
1765 : return_type_of(Class::meth_name)
1767 let ety_env =
1769 ety_env with
1770 substs = TUtils.make_locl_subst_for_class_tparams class_ tvarl;
1773 let env =
1774 Phase.check_tparams_constraints
1775 ~use_pos:p
1776 ~ety_env
1778 (Cls.tparams class_)
1780 let (env, local_obj_ty) = Phase.localize ~ety_env env obj_type in
1781 let local_obj_fp = TUtils.default_fun_param local_obj_ty in
1782 let fty = { ftype with ft_params = local_obj_fp :: ftype.ft_params } in
1783 let caller =
1785 ft_arity = fty.ft_arity;
1786 ft_tparams = fty.ft_tparams;
1787 ft_where_constraints = fty.ft_where_constraints;
1788 ft_params = fty.ft_params;
1789 ft_implicit_params = fty.ft_implicit_params;
1790 ft_ret = fty.ft_ret;
1791 (* propagate 'is_coroutine' from the method being called*)
1792 ft_flags = fty.ft_flags;
1793 ft_reactive = fty.ft_reactive;
1794 ft_ifc_decl = fty.ft_ifc_decl;
1797 make_result
1800 (Aast.Method_caller (pos_cname, meth_name))
1801 (mk (reason, Tfun caller))
1802 | _ ->
1803 (* This can happen if the method lives in PHP *)
1804 make_result
1807 (Aast.Method_caller (pos_cname, meth_name))
1808 (Typing_utils.mk_tany env pos)))
1809 | FunctionPointer (FP_class_const ((cpos, cid), meth), targs) ->
1810 let (env, _, ce, cty) =
1811 static_class_id ~check_constraints:true cpos env [] cid
1813 let (env, (fpty, tal)) =
1814 class_get
1815 ~is_method:true
1816 ~is_const:false
1817 ~incl_tc:false (* What is this? *)
1818 ~coerce_from_ty:None (* What is this? *)
1819 ~explicit_targs:targs
1820 ~function_pointer:true
1823 meth
1826 let env = Env.set_tyvar_variance env fpty in
1827 let fpty = set_function_pointer fpty in
1828 make_result
1831 (Aast.FunctionPointer (FP_class_const (ce, meth), tal))
1832 fpty
1833 | Smethod_id ((pc, cid), meth) ->
1834 (* Smethod_id is used when creating a "method pointer" using the magic
1835 * class_meth function.
1837 * Typing this is pretty simple, we just need to check that c::meth is
1838 * public+static and then return its type.
1840 let (class_, classname) =
1841 match cid with
1842 | CIself
1843 | CIstatic ->
1844 (Env.get_self_class env, Env.get_self_id env)
1845 | CI (_, const) when String.equal const SN.PseudoConsts.g__CLASS__ ->
1846 (Env.get_self_class env, Env.get_self_id env)
1847 | CI (_, id) -> (Env.get_class env id, Some id)
1848 | _ -> (None, None)
1850 let classname = Option.value classname ~default:"" in
1851 (match class_ with
1852 | None ->
1853 (* The class given as a static string was not found. *)
1854 unbound_name env (pc, classname) outer
1855 | Some class_ ->
1856 let smethod = Env.get_static_member true env class_ (snd meth) in
1857 (match smethod with
1858 | None ->
1859 (* The static method wasn't found. *)
1860 TOG.smember_not_found
1861 (fst meth)
1862 ~is_const:false
1863 ~is_method:true
1864 class_
1865 (snd meth)
1866 Errors.unify_error;
1867 expr_error env Reason.Rnone outer
1868 | Some ({ ce_type = (lazy ty); ce_pos = (lazy ce_pos); _ } as ce) ->
1869 let () =
1870 if get_ce_abstract ce then
1871 match cid with
1872 | CIstatic -> ()
1873 | _ -> Errors.class_meth_abstract_call classname (snd meth) p ce_pos
1875 let ce_visibility = ce.ce_visibility in
1876 let ce_deprecated = ce.ce_deprecated in
1877 let (env, _tal, te, cid_ty) =
1878 static_class_id ~check_constraints:true pc env [] cid
1880 let (env, cid_ty) = Env.expand_type env cid_ty in
1881 let tyargs =
1882 match get_node cid_ty with
1883 | Tclass (_, _, tyargs) -> tyargs
1884 | _ -> []
1886 let ety_env =
1888 type_expansions = [];
1889 substs = TUtils.make_locl_subst_for_class_tparams class_ tyargs;
1890 this_ty = cid_ty;
1891 from_class = Some cid;
1892 quiet = true;
1893 on_error = Errors.unify_error_at p;
1896 (match deref ty with
1897 | (r, Tfun ft) ->
1898 let ft =
1899 Typing_enforceability.compute_enforced_and_pessimize_fun_type env ft
1901 let def_pos = ce_pos in
1902 let (env, tal) =
1903 Phase.localize_targs
1904 ~check_well_kinded:true
1905 ~is_method:true
1906 ~def_pos:ce_pos
1907 ~use_pos:p
1908 ~use_name:(strip_ns (snd meth))
1910 ft.ft_tparams
1913 let (env, ft) =
1914 Phase.(
1915 localize_ft
1916 ~instantiation:
1917 Phase.
1919 use_name = strip_ns (snd meth);
1920 use_pos = p;
1921 explicit_targs = tal;
1923 ~ety_env
1924 ~def_pos:ce_pos
1928 let ty = mk (r, Tfun ft) in
1929 let use_pos = fst meth in
1930 TVis.check_deprecated ~use_pos ~def_pos ce_deprecated;
1931 (match ce_visibility with
1932 | Vpublic -> make_result env p (Aast.Smethod_id (te, meth)) ty
1933 | Vprivate _ ->
1934 Errors.private_class_meth ~def_pos ~use_pos;
1935 expr_error env r outer
1936 | Vprotected _ ->
1937 Errors.protected_class_meth ~def_pos ~use_pos;
1938 expr_error env r outer)
1939 | (r, _) ->
1940 Errors.internal_error p "We have a method which isn't callable";
1941 expr_error env r outer)))
1942 | Lplaceholder p ->
1943 let r = Reason.Rplaceholder p in
1944 let ty = MakeType.void r in
1945 make_result env p (Aast.Lplaceholder p) ty
1946 | Dollardollar _ when phys_equal valkind `lvalue ->
1947 Errors.dollardollar_lvalue p;
1948 expr_error env (Reason.Rwitness p) outer
1949 | Dollardollar id ->
1950 let ty = Env.get_local_check_defined env id in
1951 let env = might_throw env in
1952 make_result env p (Aast.Dollardollar id) ty
1953 | Lvar ((_, x) as id) ->
1954 if not accept_using_var then check_escaping_var env id;
1955 let ty =
1956 if check_defined then
1957 Env.get_local_check_defined env id
1958 else
1959 Env.get_local env x
1961 make_result env p (Aast.Lvar id) ty
1962 | List el ->
1963 let (env, tel, tyl) =
1964 match valkind with
1965 | `lvalue
1966 | `lvalue_subexpr ->
1967 lvalues env el
1968 | `other ->
1969 let (env, expected) = expand_expected_and_get_node env expected in
1970 (match expected with
1971 | Some (pos, ur, _, Ttuple expected_tyl) ->
1972 exprs_expected (pos, ur, expected_tyl) env el
1973 | _ -> exprs env el)
1975 let ty = MakeType.tuple (Reason.Rwitness p) tyl in
1976 make_result env p (Aast.List tel) ty
1977 | Pair (th, e1, e2) ->
1978 let (env, expected1, expected2, th) =
1979 match th with
1980 | Some ((_, t1), (_, t2)) ->
1981 let (env, t1, t1_expected) = localize_targ env t1 in
1982 let (env, t2, t2_expected) = localize_targ env t2 in
1983 (env, Some t1_expected, Some t2_expected, Some (t1, t2))
1984 | None ->
1985 (* Use expected type to determine expected element types *)
1986 (match expand_expected_and_get_node env expected with
1987 | (env, Some (pos, reason, _ty, Tclass ((_, k), _, [ty1; ty2])))
1988 when String.equal k SN.Collections.cPair ->
1989 let ty1_expected = ExpectedTy.make pos reason ty1 in
1990 let ty2_expected = ExpectedTy.make pos reason ty2 in
1991 (env, Some ty1_expected, Some ty2_expected, None)
1992 | _ -> (env, None, None, None))
1994 let (env, te1, ty1) = expr ?expected:expected1 env e1 in
1995 let (env, te2, ty2) = expr ?expected:expected2 env e2 in
1996 let p1 = fst e1 in
1997 let p2 = fst e2 in
1998 let (env, ty1) =
1999 compute_supertype
2000 ~expected:expected1
2001 ~reason:Reason.URpair_value
2002 ~use_pos:p1
2003 (Reason.Rtype_variable_generics (p1, "T1", "Pair"))
2005 [ty1]
2007 let (env, ty2) =
2008 compute_supertype
2009 ~expected:expected2
2010 ~reason:Reason.URpair_value
2011 ~use_pos:p2
2012 (Reason.Rtype_variable_generics (p2, "T2", "Pair"))
2014 [ty2]
2016 let ty = MakeType.pair (Reason.Rwitness p) ty1 ty2 in
2017 make_result env p (Aast.Pair (th, te1, te2)) ty
2018 | Array_get (e, None) ->
2019 let (env, te, _) = update_array_type p env e valkind in
2020 let env = might_throw env in
2021 (* NAST check reports an error if [] is used for reading in an
2022 lvalue context. *)
2023 let ty = err_witness env p in
2024 make_result env p (Aast.Array_get (te, None)) ty
2025 | Array_get (e1, Some e2) ->
2026 let (env, te1, ty1) =
2027 update_array_type ?lhs_of_null_coalesce p env e1 valkind
2029 let (env, te2, ty2) = expr env e2 in
2030 let env = might_throw env in
2031 let is_lvalue = phys_equal valkind `lvalue in
2032 let (env, ty) =
2033 Typing_array_access.array_get
2034 ~array_pos:(fst e1)
2035 ~expr_pos:p
2036 ?lhs_of_null_coalesce
2037 is_lvalue
2043 make_result env p (Aast.Array_get (te1, Some te2)) ty
2044 | Call ((pos_id, Id ((_, s) as id)), [], el, None) when is_pseudo_function s
2046 let (env, tel, tys) = exprs ~accept_using_var:true env el in
2047 let env =
2048 if String.equal s SN.PseudoFunctions.hh_show then (
2049 List.iter tys (Typing_log.hh_show p env);
2051 ) else if String.equal s SN.PseudoFunctions.hh_show_env then (
2052 Typing_log.hh_show_env p env;
2054 ) else if String.equal s SN.PseudoFunctions.hh_log_level then
2055 match el with
2056 | [(_, String key_str); (_, Int level_str)] ->
2057 Env.set_log_level env key_str (int_of_string level_str)
2058 | _ -> env
2059 else if String.equal s SN.PseudoFunctions.hh_force_solve then
2060 Typing_solver.solve_all_unsolved_tyvars env Errors.unify_error
2061 else if String.equal s SN.PseudoFunctions.hh_loop_forever then (
2062 loop_forever env;
2064 ) else
2067 let ty = MakeType.void (Reason.Rwitness p) in
2068 make_result
2071 (Aast.Call
2072 ( Tast.make_typed_expr pos_id (TUtils.mk_tany env pos_id) (Aast.Id id),
2074 tel,
2075 None ))
2077 | Call (e, explicit_targs, el, unpacked_element) ->
2078 let env =
2079 match snd e with
2080 | Id (pos, f) when String.equal f SN.SpecialFunctions.echo ->
2081 Typing_local_ops.enforce_output pos env
2082 | _ -> env
2084 let env = might_throw env in
2085 let (env, te, ty) =
2086 check_call
2087 ~is_using_clause
2088 ~expected
2089 ?in_await
2093 explicit_targs
2095 unpacked_element
2097 (env, te, ty)
2098 | FunctionPointer (FP_id fid, targs) ->
2099 let (env, fty, targs) = fun_type_of_id env fid targs [] in
2100 let e = Aast.FunctionPointer (FP_id fid, targs) in
2101 let fty = set_function_pointer fty in
2102 make_result env p e fty
2103 | Binop (Ast_defs.QuestionQuestion, e1, e2) ->
2104 let (env, te1, ty1) = raw_expr ~lhs_of_null_coalesce:true env e1 in
2105 let (env, te2, ty2) = expr ?expected env e2 in
2106 let (env, ty1') = Env.fresh_type env (fst e1) in
2107 let env =
2108 SubType.sub_type
2111 (MakeType.nullable_locl Reason.Rnone ty1')
2112 Errors.unify_error
2114 (* Essentially mimic a call to
2115 * function coalesce<Tr, Ta as Tr, Tb as Tr>(?Ta, Tb): Tr
2116 * That way we let the constraint solver take care of the union logic.
2118 let (env, ty_result) = Env.fresh_type env (fst e2) in
2119 let env = SubType.sub_type env ty1' ty_result Errors.unify_error in
2120 let env = SubType.sub_type env ty2 ty_result Errors.unify_error in
2121 make_result
2124 (Aast.Binop (Ast_defs.QuestionQuestion, te1, te2))
2125 ty_result
2126 (* For example, e1 += e2. This is typed and translated as if
2127 * written e1 = e1 + e2.
2128 * TODO TAST: is this right? e1 will get evaluated more than once
2130 | Binop (Ast_defs.Eq (Some op), e1, e2) ->
2131 begin
2132 match (op, snd e1) with
2133 | (Ast_defs.QuestionQuestion, Class_get _) ->
2134 Errors.experimental_feature
2136 "null coalesce assignment operator with static properties";
2137 expr_error env Reason.Rnone outer
2138 | _ ->
2139 let e_fake =
2140 (p, Binop (Ast_defs.Eq None, e1, (p, Binop (op, e1, e2))))
2142 let (env, te_fake, ty) = raw_expr env e_fake in
2143 begin
2144 match snd te_fake with
2145 | Aast.Binop (_, te1, (_, Aast.Binop (_, _, te2))) ->
2146 let te = Aast.Binop (Ast_defs.Eq (Some op), te1, te2) in
2147 make_result env p te ty
2148 | _ -> assert false
2151 | Binop (Ast_defs.Eq None, e1, e2) ->
2152 let (env, te2, ty2) = raw_expr env e2 in
2153 let (env, te1, ty) = assign p env e1 ty2 in
2154 let env =
2155 if Env.env_local_reactive env then
2156 Typing_mutability.handle_assignment_mutability env te1 (Some (snd te2))
2157 else
2160 make_result env p (Aast.Binop (Ast_defs.Eq None, te1, te2)) ty
2161 | Binop (((Ast_defs.Ampamp | Ast_defs.Barbar) as bop), e1, e2) ->
2162 let c = Ast_defs.(equal_bop bop Ampamp) in
2163 let (env, te1, _) = expr env e1 in
2164 let lenv = env.lenv in
2165 let (env, _lset) = condition env c te1 in
2166 let (env, te2, _) = expr env e2 in
2167 let env = { env with lenv } in
2168 make_result
2171 (Aast.Binop (bop, te1, te2))
2172 (MakeType.bool (Reason.Rlogic_ret p))
2173 | Binop (bop, e1, e2) ->
2174 let (env, te1, ty1) = raw_expr env e1 in
2175 let (env, te2, ty2) = raw_expr env e2 in
2176 let env =
2177 match bop with
2178 (* TODO: This could be less conservative: we only need to account for
2179 * the possibility of exception if the operator is `/` or `/=`.
2181 | Ast_defs.Eqeqeq
2182 | Ast_defs.Diff2 ->
2184 | _ -> might_throw env
2186 let (env, te3, ty) =
2187 Typing_arithmetic.binop p env bop (fst e1) te1 ty1 (fst e2) te2 ty2
2189 (env, te3, ty)
2190 | Pipe (e0, e1, e2) ->
2191 (* If it weren't for local variable assignment or refinement the pipe
2192 * expression e1 |> e2 could be typed using this rule (E is environment with
2193 * types for locals):
2195 * E |- e1 : ty1 E[$$:ty1] |- e2 : ty2
2196 * --------------------------------------
2197 * E |- e1|>e2 : ty2
2199 * The possibility of e2 changing the types of locals in E means that E
2200 * can evolve, and so we need to restore $$ to its original state.
2202 let (env, te1, ty1) = expr env e1 in
2203 let dd_var = Local_id.make_unscoped SN.SpecialIdents.dollardollar in
2204 let dd_old_ty =
2205 if Env.is_local_defined env dd_var then
2206 Some (Env.get_local_pos env dd_var)
2207 else
2208 None
2210 let env = Env.set_local env dd_var ty1 Pos.none in
2211 let (env, te2, ty2) = expr env e2 in
2212 let env =
2213 match dd_old_ty with
2214 | None -> Env.unset_local env dd_var
2215 | Some (ty, pos) -> Env.set_local env dd_var ty pos
2217 make_result env p (Aast.Pipe (e0, te1, te2)) ty2
2218 | Unop (uop, e) ->
2219 let (env, te, ty) = raw_expr env e in
2220 let env = might_throw env in
2221 Typing_arithmetic.unop p env uop te ty
2222 | Eif (c, e1, e2) -> eif env ~expected ?in_await p c e1 e2
2223 | Class_const ((p, CI sid), pstr)
2224 when String.equal (snd pstr) "class" && Env.is_typedef env (snd sid) ->
2225 begin
2226 match Env.get_typedef env (snd sid) with
2227 | Some { td_tparams = tparaml; _ } ->
2228 (* Typedef type parameters cannot have constraints *)
2229 let params =
2230 List.map
2232 begin
2233 fun { tp_name = (p, x); _ } ->
2234 (* TODO(T69551141) handle type arguments for Tgeneric *)
2235 MakeType.generic (Reason.Rwitness p) x
2237 tparaml
2239 let tdef = mk (Reason.Rwitness p, Tapply (sid, params)) in
2240 let typename =
2241 mk (Reason.Rwitness p, Tapply ((p, SN.Classes.cTypename), [tdef]))
2243 let (env, tparams) =
2244 List.map_env env tparaml (fun env tp ->
2245 Env.fresh_type env (fst tp.tp_name))
2247 let ety_env =
2249 (Phase.env_with_self env) with
2250 substs = Subst.make_locl tparaml tparams;
2253 let env =
2254 Phase.check_tparams_constraints ~use_pos:p ~ety_env env tparaml
2256 let (env, ty) = Phase.localize ~ety_env env typename in
2257 make_result env p (Class_const (((p, ty), CI sid), pstr)) ty
2258 | None ->
2259 (* Should not expect None as we've checked whether the sid is a typedef *)
2260 expr_error env (Reason.Rwitness p) outer
2262 | Class_const (cid, mid) -> class_const env p (cid, mid)
2263 | Class_get ((cpos, cid), CGstring mid, in_parens)
2264 when Env.FakeMembers.is_valid_static env cid (snd mid) ->
2265 let (env, local) = Env.FakeMembers.make_static env cid (snd mid) p in
2266 let local = (p, Lvar (p, local)) in
2267 let (env, _, ty) = expr env local in
2268 let (env, _tal, te, _) =
2269 static_class_id ~check_constraints:false cpos env [] cid
2271 make_result env p (Aast.Class_get (te, Aast.CGstring mid, in_parens)) ty
2272 | Class_get ((cpos, cid), CGstring ((ppos, _) as mid), in_parens) ->
2273 let (env, _tal, te, cty) =
2274 static_class_id ~check_constraints:false cpos env [] cid
2276 let env = might_throw env in
2277 let (env, (ty, _tal)) =
2278 class_get
2279 ~is_method:false
2280 ~is_const:false
2281 ~coerce_from_ty:None
2287 let (env, ty) = Env.FakeMembers.check_static_invalid env cid (snd mid) ty in
2288 let env = Typing_local_ops.enforce_static_property_access ppos env in
2289 make_result env p (Aast.Class_get (te, Aast.CGstring mid, in_parens)) ty
2290 (* Fake member property access. For example:
2291 * if ($x->f !== null) { ...$x->f... }
2293 | Class_get (_, CGexpr _, _) ->
2294 failwith "AST should not have any CGexprs after naming"
2295 | Obj_get (e, (pid, Id (py, y)), nf, in_parens)
2296 when Env.FakeMembers.is_valid env e y ->
2297 let env = might_throw env in
2298 let (env, local) = Env.FakeMembers.make env e y p in
2299 let local = (p, Lvar (p, local)) in
2300 let (env, _, ty) = expr env local in
2301 let (env, t_lhs, _) = expr ~accept_using_var:true env e in
2302 let t_rhs = Tast.make_typed_expr pid ty (Aast.Id (py, y)) in
2303 make_result env p (Aast.Obj_get (t_lhs, t_rhs, nf, in_parens)) ty
2304 (* Statically-known instance property access e.g. $x->f *)
2305 | Obj_get (e1, (pm, Id m), nullflavor, in_parens) ->
2306 let nullsafe =
2307 match nullflavor with
2308 | OG_nullthrows -> None
2309 | OG_nullsafe -> Some p
2311 let (env, te1, ty1) = expr ~accept_using_var:true env e1 in
2312 let env = might_throw env in
2313 (* We typecheck Obj_get by checking whether it is a subtype of
2314 Thas_member(m, #1) where #1 is a fresh type variable. *)
2315 let (env, mem_ty) = Env.fresh_type env p in
2316 let r = Reason.Rwitness (fst e1) in
2317 let has_member_ty =
2318 MakeType.has_member
2320 ~name:m
2321 ~ty:mem_ty
2322 ~class_id:(CIexpr e1)
2323 ~explicit_targs:None
2325 let lty1 = LoclType ty1 in
2326 let (env, result_ty) =
2327 match nullsafe with
2328 | None ->
2329 let env =
2330 Type.sub_type_i
2331 (fst e1)
2332 Reason.URnone
2334 lty1
2335 has_member_ty
2336 Errors.unify_error
2338 (env, mem_ty)
2339 | Some _ ->
2340 (* In that case ty1 is a subtype of ?Thas_member(m, #1)
2341 and the result is ?#1 if ty1 is nullable. *)
2342 let r = Reason.Rnullsafe_op p in
2343 let null_ty = MakeType.null r in
2344 let (env, null_has_mem_ty) =
2345 Union.union_i env r has_member_ty null_ty
2347 let env =
2348 Type.sub_type_i
2349 (fst e1)
2350 Reason.URnone
2352 lty1
2353 null_has_mem_ty
2354 Errors.unify_error
2356 let (env, null_or_nothing_ty) = Inter.intersect env ~r null_ty ty1 in
2357 let (env, result_ty) = Union.union env null_or_nothing_ty mem_ty in
2358 (env, result_ty)
2360 let (env, result_ty) =
2361 Env.FakeMembers.check_instance_invalid env e1 (snd m) result_ty
2363 make_result
2366 (Aast.Obj_get
2367 ( te1,
2368 Tast.make_typed_expr pm result_ty (Aast.Id m),
2369 nullflavor,
2370 in_parens ))
2371 result_ty
2372 (* Dynamic instance property access e.g. $x->$f *)
2373 | Obj_get (e1, e2, nullflavor, in_parens) ->
2374 let (env, te1, ty1) = expr ~accept_using_var:true env e1 in
2375 let (env, te2, _) = expr env e2 in
2376 let ty =
2377 if TUtils.is_dynamic env ty1 then
2378 MakeType.dynamic (Reason.Rwitness p)
2379 else
2380 Typing_utils.mk_tany env p
2382 let ((pos, _), te2) = te2 in
2383 let env = might_throw env in
2384 let te2 = Tast.make_typed_expr pos ty te2 in
2385 make_result env p (Aast.Obj_get (te1, te2, nullflavor, in_parens)) ty
2386 | Yield_break ->
2387 make_result env p Aast.Yield_break (Typing_utils.mk_tany env p)
2388 | Yield af ->
2389 let (env, (taf, opt_key, value)) = array_field env af in
2390 let (env, send) = Env.fresh_type env p in
2391 let (env, key) =
2392 match (af, opt_key) with
2393 | (AFvalue (p, _), None) ->
2394 begin
2395 match Env.get_fn_kind env with
2396 | Ast_defs.FSync
2397 | Ast_defs.FAsync ->
2398 Errors.internal_error p "yield found in non-generator";
2399 (env, Typing_utils.mk_tany env p)
2400 | Ast_defs.FGenerator -> (env, MakeType.int (Reason.Rwitness p))
2401 | Ast_defs.FAsyncGenerator ->
2402 let (env, ty) = Env.fresh_type env p in
2403 (env, MakeType.nullable_locl (Reason.Ryield_asyncnull p) ty)
2405 | (_, Some x) -> (env, x)
2406 | (_, _) -> assert false
2408 let rty =
2409 match Env.get_fn_kind env with
2410 | Ast_defs.FGenerator ->
2411 MakeType.generator (Reason.Ryield_gen p) key value send
2412 | Ast_defs.FAsyncGenerator ->
2413 MakeType.async_generator (Reason.Ryield_asyncgen p) key value send
2414 | Ast_defs.FSync
2415 | Ast_defs.FAsync ->
2416 failwith "Parsing should never allow this"
2418 let Typing_env_return_info.{ return_type = expected_return; _ } =
2419 Env.get_return env
2421 let env =
2422 Typing_coercion.coerce_type
2424 Reason.URyield
2427 expected_return
2428 Errors.unify_error
2430 let env = Env.forget_members env Reason.(Blame (p, BScall)) in
2431 let env = LEnv.save_and_merge_next_in_cont env C.Exit in
2432 make_result
2435 (Aast.Yield taf)
2436 (MakeType.nullable_locl (Reason.Ryield_send p) send)
2437 | Await e ->
2438 let env = might_throw env in
2439 (* Await is permitted in a using clause e.g. using (await make_handle()) *)
2440 let (env, te, rty) =
2441 expr ~is_using_clause ~in_await:(Reason.Rwitness p) env e
2443 let (env, ty) = Async.overload_extract_from_awaitable env p rty in
2444 make_result env p (Aast.Await te) ty
2445 | New ((pos, c), explicit_targs, el, unpacked_element, p1) ->
2446 let env = might_throw env in
2447 let (env, tc, tal, tel, typed_unpack_element, ty, ctor_fty) =
2448 new_object
2449 ~expected
2450 ~is_using_clause
2451 ~check_parent:false
2452 ~check_not_abstract:true
2456 explicit_targs
2458 unpacked_element
2460 let env = Env.forget_members env Reason.(Blame (p, BScall)) in
2461 make_result
2464 (Aast.New (tc, tal, tel, typed_unpack_element, (p1, ctor_fty)))
2466 | Record ((pos, id), field_values) ->
2467 (match Decl_provider.get_record_def (Env.get_ctx env) id with
2468 | Some rd ->
2469 if rd.rdt_abstract then Errors.new_abstract_record (pos, id);
2471 let field_name (pos, expr_) =
2472 match expr_ with
2473 | Aast.String name -> Some (pos, name)
2474 | _ ->
2475 (* TODO T44306013: Ensure that other values for field names are banned. *)
2476 None
2478 let fields_declared = Typing_helpers.all_record_fields env rd in
2479 let fields_present =
2480 List.map field_values ~f:(fun (name, _value) -> field_name name)
2481 |> List.filter_opt
2483 (* Check for missing required fields. *)
2484 let fields_present_names =
2485 List.map ~f:snd fields_present |> SSet.of_list
2487 SMap.iter
2488 (fun field_name info ->
2489 let ((field_pos, _), req) = info in
2490 match req with
2491 | Typing_defs.ValueRequired
2492 when not (SSet.mem field_name fields_present_names) ->
2493 Errors.missing_record_field_name
2494 ~field_name
2495 ~new_pos:pos
2496 ~record_name:id
2497 ~field_decl_pos:field_pos
2498 | _ -> ())
2499 fields_declared;
2501 (* Check for unknown fields.*)
2502 List.iter fields_present ~f:(fun (pos, field_name) ->
2503 if not (SMap.mem field_name fields_declared) then
2504 Errors.unexpected_record_field_name
2505 ~field_name
2506 ~field_pos:pos
2507 ~record_name:id
2508 ~decl_pos:(fst rd.rdt_name))
2509 | None -> Errors.type_not_record id pos);
2511 expr_error env (Reason.Rwitness p) outer
2512 | Cast (hint, e) ->
2513 let (env, te, ty2) = expr ?in_await env e in
2514 let env = might_throw env in
2515 let env =
2517 TypecheckerOptions.experimental_feature_enabled
2518 (Env.get_tcopt env)
2519 TypecheckerOptions.experimental_forbid_nullable_cast
2520 && not (TUtils.is_mixed env ty2)
2521 then
2522 SubType.sub_type_or_fail
2525 (MakeType.nonnull (get_reason ty2))
2526 (fun () ->
2527 Errors.nullable_cast p (Typing_print.error env ty2) (get_pos ty2))
2528 else
2531 let (env, ty) = Phase.localize_hint_with_self env hint in
2532 make_result env p (Aast.Cast (hint, te)) ty
2533 | ExpressionTree et -> expression_tree { env with in_expr_tree = true } p et
2534 | Is (e, hint) ->
2535 Typing_kinding.Simple.check_well_kinded_hint env hint;
2536 let (env, te, _) = expr env e in
2537 make_result env p (Aast.Is (te, hint)) (MakeType.bool (Reason.Rwitness p))
2538 | As (e, hint, is_nullable) ->
2539 Typing_kinding.Simple.check_well_kinded_hint env hint;
2540 let refine_type env lpos lty rty =
2541 let reason = Reason.Ras lpos in
2542 let (env, rty) = Env.expand_type env rty in
2543 let (env, rty) = class_for_refinement env p reason lpos lty rty in
2544 Inter.intersect env reason lty rty
2546 let (env, te, expr_ty) = expr env e in
2547 let env = might_throw env in
2548 let ety_env =
2549 { (Phase.env_with_self env) with from_class = Some CIstatic }
2551 let (env, hint_ty) = Phase.localize_hint ~ety_env env hint in
2552 let enable_sound_dynamic =
2553 TypecheckerOptions.enable_sound_dynamic env.genv.tcopt
2555 let is_dyn = Typing_utils.is_dynamic env hint_ty in
2556 ( if enable_sound_dynamic && is_dyn then
2557 let (_ : env * locl_ty) =
2558 ( SubType.sub_type
2559 ~allow_subtype_of_dynamic:true
2561 expr_ty
2562 hint_ty
2563 Errors.unify_error,
2564 hint_ty )
2566 () );
2567 let (env, hint_ty) =
2568 if is_dyn && not enable_sound_dynamic then
2569 let env =
2570 if is_instance_var e then
2571 let (env, ivar) = get_instance_var env e in
2572 set_local env ivar hint_ty
2573 else
2576 (env, hint_ty)
2577 else if is_nullable && not is_dyn then
2578 let (env, hint_ty) = refine_type env (fst e) expr_ty hint_ty in
2579 (env, MakeType.nullable_locl (Reason.Rwitness p) hint_ty)
2580 else if is_instance_var e then
2581 let (env, _, ivar_ty) = raw_expr env e in
2582 let (env, ((ivar_pos, _) as ivar)) = get_instance_var env e in
2583 let (env, hint_ty) = refine_type env ivar_pos ivar_ty hint_ty in
2584 let env = set_local env ivar hint_ty in
2585 (env, hint_ty)
2586 else
2587 refine_type env (fst e) expr_ty hint_ty
2589 make_result env p (Aast.As (te, hint, is_nullable)) hint_ty
2590 | Efun (f, idl)
2591 | Lfun (f, idl) ->
2592 let is_anon =
2593 match e with
2594 | Efun _ -> true
2595 | Lfun _ -> false
2596 | _ -> assert false
2598 (* Check type annotations on the lambda *)
2599 Typing_check_decls.fun_ env f;
2600 (* Check attributes on the lambda *)
2601 let env =
2602 attributes_check_def env SN.AttributeKinds.lambda f.f_user_attributes
2604 (* This is the function type as declared on the lambda itself.
2605 * If type hints are absent then use Tany instead. *)
2606 let declared_fe =
2607 Decl_nast.fun_decl_in_env env.decl_env ~is_lambda:true f
2609 let { fe_type; fe_pos; _ } = declared_fe in
2610 let (declared_pos, declared_ft) =
2611 match get_node fe_type with
2612 | Tfun ft -> (fe_pos, ft)
2613 | _ -> failwith "Not a function"
2615 let declared_ft =
2616 Typing_enforceability.compute_enforced_and_pessimize_fun_type
2618 declared_ft
2620 (* When creating a closure, the 'this' type will mean the late bound type
2621 * of the current enclosing class
2623 let ety_env =
2624 { (Phase.env_with_self env) with from_class = Some CIstatic }
2626 let (env, declared_ft) =
2627 Phase.(
2628 localize_ft
2629 ~instantiation:
2630 { use_name = "lambda"; use_pos = p; explicit_targs = [] }
2631 ~ety_env
2632 ~def_pos:declared_pos
2634 declared_ft)
2636 List.iter idl (check_escaping_var env);
2638 (* Ensure lambda arity is not ellipsis in strict mode *)
2639 begin
2640 match declared_ft.ft_arity with
2641 | Fvariadic { fp_name = None; _ }
2642 when Partial.should_check_error (Env.get_mode env) 4223 ->
2643 Errors.ellipsis_strict_mode ~require:`Param_name p
2644 | _ -> ()
2645 end;
2647 (* Is the return type declared? *)
2648 let is_explicit_ret = Option.is_some (hint_of_type_hint f.f_ret) in
2649 let reactivity =
2650 Decl_fun_utils.fun_reactivity_opt env.decl_env f.f_user_attributes
2651 |> Option.value
2652 ~default:(TR.strip_conditional_reactivity (env_reactivity env))
2654 let check_body_under_known_params env ?ret_ty ft : env * _ * locl_ty =
2655 let old_reactivity = env_reactivity env in
2656 let env = Env.set_env_reactive env reactivity in
2657 let ft = { ft with ft_reactive = reactivity } in
2658 let (env, (tefun, ty, ft)) = anon_make ?ret_ty env p f ft idl is_anon in
2659 let env = Env.set_env_reactive env old_reactivity in
2660 let inferred_ty =
2662 ( Reason.Rwitness p,
2663 Tfun
2665 ft with
2666 ft_ret =
2667 ( if is_explicit_ret then
2668 declared_ft.ft_ret
2669 else
2670 MakeType.unenforced ty );
2673 (env, tefun, inferred_ty)
2675 let (env, eexpected) = expand_expected_and_get_node env expected in
2676 (* TODO: move this into the expand_expected_and_get_node function and prune its callsites
2677 * Strip like type from function type hint *)
2678 let eexpected =
2679 match eexpected with
2680 | Some (pos, ur, _, Tunion [ty1; ty2]) when is_dynamic ty1 && is_fun ty2
2682 Some (pos, ur, ty2, get_node ty2)
2683 | _ -> eexpected
2685 begin
2686 match eexpected with
2687 | Some (_pos, _ur, ty, Tfun expected_ft) ->
2688 (* First check that arities match up *)
2689 check_lambda_arity p (get_pos ty) declared_ft expected_ft;
2690 (* Use declared types for parameters in preference to those determined
2691 * by the context: they might be more general. *)
2692 let rec replace_non_declared_types
2693 params declared_ft_params expected_ft_params =
2694 match (params, declared_ft_params, expected_ft_params) with
2695 | ( param :: params,
2696 declared_ft_param :: declared_ft_params,
2697 expected_ft_param :: expected_ft_params ) ->
2698 let rest =
2699 replace_non_declared_types
2700 params
2701 declared_ft_params
2702 expected_ft_params
2704 let resolved_ft_param =
2705 if Option.is_some (hint_of_type_hint param.param_type_hint) then
2706 declared_ft_param
2707 else
2708 { declared_ft_param with fp_type = expected_ft_param.fp_type }
2710 resolved_ft_param :: rest
2711 | (_ :: params, declared_ft_param :: declared_ft_params, []) ->
2712 let rest =
2713 replace_non_declared_types
2714 params
2715 declared_ft_params
2716 expected_ft_params
2718 declared_ft_param :: rest
2719 | (_, _, _) ->
2720 (* This means the expected_ft params list can have more parameters
2721 * than declared parameters in the lambda. For variadics, this is OK.
2723 expected_ft_params
2725 let replace_non_declared_arity variadic declared_arity expected_arity =
2726 match variadic with
2727 | FVvariadicArg { param_type_hint = (_, Some _); _ } -> declared_arity
2728 | FVvariadicArg _ ->
2729 begin
2730 match (declared_arity, expected_arity) with
2731 | (Fvariadic declared, Fvariadic expected) ->
2732 Fvariadic { declared with fp_type = expected.fp_type }
2733 | (_, _) -> declared_arity
2735 | _ -> declared_arity
2737 let expected_ft =
2739 expected_ft with
2740 ft_arity =
2741 replace_non_declared_arity
2742 f.f_variadic
2743 declared_ft.ft_arity
2744 expected_ft.ft_arity;
2745 ft_params =
2746 replace_non_declared_types
2747 f.f_params
2748 declared_ft.ft_params
2749 expected_ft.ft_params;
2750 ft_implicit_params = declared_ft.ft_implicit_params;
2753 (* Don't bother passing in `void` if there is no explicit return *)
2754 let ret_ty =
2755 match get_node expected_ft.ft_ret.et_type with
2756 | Tprim Tvoid when not is_explicit_ret -> None
2757 | _ -> Some expected_ft.ft_ret.et_type
2759 Typing_log.increment_feature_count env FL.Lambda.contextual_params;
2760 check_body_under_known_params env ?ret_ty expected_ft
2761 | _ ->
2762 let explicit_variadic_param_or_non_variadic =
2763 match f.f_variadic with
2764 | FVvariadicArg { param_type_hint; _ } ->
2765 Option.is_some (hint_of_type_hint param_type_hint)
2766 | FVellipsis _ -> false
2767 | _ -> true
2769 (* If all parameters are annotated with explicit types, then type-check
2770 * the body under those assumptions and pick up the result type *)
2771 let all_explicit_params =
2772 List.for_all f.f_params (fun param ->
2773 Option.is_some (hint_of_type_hint param.param_type_hint))
2775 if all_explicit_params && explicit_variadic_param_or_non_variadic then (
2776 Typing_log.increment_feature_count
2778 ( if List.is_empty f.f_params then
2779 FL.Lambda.no_params
2780 else
2781 FL.Lambda.explicit_params );
2782 check_body_under_known_params env declared_ft
2783 ) else (
2784 match expected with
2785 | Some ExpectedTy.{ ty = { et_type; _ }; _ } when is_any et_type ->
2786 (* If the expected type is Tany env then we're passing a lambda to
2787 * an untyped function and we just assume every parameter has type
2788 * Tany.
2789 * Note: we should be using 'nothing' to type the arguments. *)
2790 Typing_log.increment_feature_count env FL.Lambda.untyped_context;
2791 check_body_under_known_params env declared_ft
2792 | Some _ ->
2793 (* If the expected type is something concrete but not a function
2794 * then we should reject in strict mode. Check body anyway.
2795 * Note: we should be using 'nothing' to type the arguments. *)
2796 if Partial.should_check_error (Env.get_mode env) 4224 then
2797 Errors.untyped_lambda_strict_mode p;
2798 Typing_log.increment_feature_count
2800 FL.Lambda.non_function_typed_context;
2801 check_body_under_known_params env declared_ft
2802 | None ->
2803 (* If we're in partial mode then type-check definition anyway,
2804 * so treating parameters without type hints as "untyped"
2806 if not (Env.is_strict env) then (
2807 Typing_log.increment_feature_count
2809 FL.Lambda.non_strict_unknown_params;
2810 check_body_under_known_params env declared_ft
2811 ) else (
2812 Typing_log.increment_feature_count
2814 FL.Lambda.fresh_tyvar_params;
2816 (* Replace uses of Tany that originated from "untyped" parameters or return type
2817 * with fresh type variables *)
2818 let freshen_ftype env ft =
2819 let freshen_ty env pos et =
2820 match get_node et.et_type with
2821 | Tany _ ->
2822 let (env, ty) = Env.fresh_type env pos in
2823 (env, { et with et_type = ty })
2824 | Tclass (id, e, [ty])
2825 when String.equal (snd id) SN.Classes.cAwaitable
2826 && is_any ty ->
2827 let (env, t) = Env.fresh_type env pos in
2828 ( env,
2830 et with
2831 et_type = mk (get_reason et.et_type, Tclass (id, e, [t]));
2833 | _ -> (env, et)
2835 let freshen_untyped_param env ft_param =
2836 let (env, fp_type) =
2837 freshen_ty env ft_param.fp_pos ft_param.fp_type
2839 (env, { ft_param with fp_type })
2841 let (env, ft_params) =
2842 List.map_env env ft.ft_params freshen_untyped_param
2844 let (env, ft_ret) = freshen_ty env declared_pos ft.ft_ret in
2845 (env, { ft with ft_params; ft_ret })
2847 let (env, declared_ft) = freshen_ftype env declared_ft in
2848 let env =
2849 Env.set_tyvar_variance env (mk (Reason.Rnone, Tfun declared_ft))
2851 (* TODO(jjwu): the declared_ft here is set to public,
2852 but is actually inferred from the surrounding context
2853 (don't think this matters in practice, since we check lambdas separately) *)
2854 check_body_under_known_params
2856 ~ret_ty:declared_ft.ft_ret.et_type
2857 declared_ft
2861 | Xml (sid, attrl, el) ->
2862 let cid = CI sid in
2863 let (env, _tal, _te, classes) =
2864 class_id_for_new ~exact:Nonexact p env cid []
2866 (* OK to ignore rest of list; class_info only used for errors, and
2867 * cid = CI sid cannot produce a union of classes anyhow *)
2868 let class_info =
2869 List.find_map classes ~f:(function
2870 | `Dynamic -> None
2871 | `Class (_, class_info, _) -> Some class_info)
2873 let (env, _te, obj) =
2874 expr env (fst sid, New ((fst sid, cid), [], [], None, fst sid))
2876 let (env, typed_attrs, attr_types) =
2877 xhp_attribute_exprs env class_info attrl
2879 let (env, tel) =
2880 List.map_env env el ~f:(fun env e ->
2881 let (env, te, _) = expr env e in
2882 (env, te))
2884 let txml = Aast.Xml (sid, typed_attrs, List.rev tel) in
2885 (match class_info with
2886 | None -> make_result env p txml (mk (Reason.Runknown_class p, Tobject))
2887 | Some class_info ->
2888 let env =
2889 List.fold_left
2890 attr_types
2892 begin
2893 fun env attr ->
2894 let (namepstr, valpty) = attr in
2895 let (valp, valty) = valpty in
2896 let (env, (declty, _tal)) =
2897 TOG.obj_get
2898 ~obj_pos:(fst sid)
2899 ~is_method:false
2900 ~nullsafe:None
2901 ~coerce_from_ty:None
2902 ~explicit_targs:[]
2906 namepstr
2907 Errors.unify_error
2909 let ureason = Reason.URxhp (Cls.name class_info, snd namepstr) in
2910 Typing_coercion.coerce_type
2911 valp
2912 ureason
2914 valty
2915 (MakeType.unenforced declty)
2916 Errors.xhp_attribute_does_not_match_hint
2918 ~init:env
2920 make_result env p txml obj)
2921 | Callconv (kind, e) ->
2922 let (env, te, ty) = expr env e in
2923 make_result env p (Aast.Callconv (kind, te)) ty
2924 | Shape fdm ->
2925 let (env, fdm_with_expected) =
2926 match expand_expected_and_get_node env expected with
2927 | (env, Some (pos, ur, _, Tshape (_, expected_fdm))) ->
2928 let fdme =
2929 List.map
2930 ~f:(fun (k, v) ->
2931 match ShapeMap.find_opt k expected_fdm with
2932 | None -> (k, (v, None))
2933 | Some sft -> (k, (v, Some (ExpectedTy.make pos ur sft.sft_ty))))
2936 (env, fdme)
2937 | _ -> (env, List.map ~f:(fun (k, v) -> (k, (v, None))) fdm)
2939 (* allow_inter adds a type-variable *)
2940 let (env, tfdm) =
2941 List.map_env
2942 ~f:(fun env (key, (e, expected)) ->
2943 let (env, te, ty) = expr ?expected env e in
2944 (env, (key, (te, ty))))
2946 fdm_with_expected
2948 let (env, fdm) =
2949 let convert_expr_and_type_to_shape_field_type env (key, (_, ty)) =
2950 (* An expression evaluation always corresponds to a shape_field_type
2951 with sft_optional = false. *)
2952 (env, (key, { sft_optional = false; sft_ty = ty }))
2954 List.map_env ~f:convert_expr_and_type_to_shape_field_type env tfdm
2956 let fdm =
2957 List.fold_left
2958 ~f:(fun acc (k, v) -> ShapeMap.add k v acc)
2959 ~init:ShapeMap.empty
2962 let env = check_shape_keys_validity env p (ShapeMap.keys fdm) in
2963 (* Fields are fully known, because this shape is constructed
2964 * using shape keyword and we know exactly what fields are set. *)
2965 make_result
2968 (Aast.Shape (List.map ~f:(fun (k, (te, _)) -> (k, te)) tfdm))
2969 (mk (Reason.Rwitness p, Tshape (Closed_shape, fdm)))
2970 | ET_Splice e -> et_splice { env with in_expr_tree = true } p e
2971 | EnumAtom s ->
2972 Errors.atom_as_expr p;
2973 make_result env p (Aast.EnumAtom s) (mk (Reason.Rwitness p, Terr))
2975 (* let ty = err_witness env cst_pos in *)
2976 and class_const ?(incl_tc = false) env p ((cpos, cid), mid) =
2977 let (env, _tal, ce, cty) =
2978 static_class_id ~check_constraints:true cpos env [] cid
2980 let (env, (const_ty, _tal)) =
2981 class_get
2982 ~is_method:false
2983 ~is_const:true
2984 ~incl_tc
2985 ~coerce_from_ty:None
2991 make_result env p (Aast.Class_const (ce, mid)) const_ty
2992 (*****************************************************************************)
2993 (* XHP attribute/body helpers. *)
2994 (*****************************************************************************)
2997 * Process a spread operator by computing the intersection of XHP attributes
2998 * between the spread expression and the XHP constructor onto which we're
2999 * spreading.
3001 and xhp_spread_attribute env c_onto valexpr =
3002 let (p, _) = valexpr in
3003 let (env, te, valty) = expr env valexpr in
3004 (* Build the typed attribute node *)
3005 let typed_attr = Aast.Xhp_spread te in
3006 let (env, attr_ptys) =
3007 match c_onto with
3008 | None -> (env, [])
3009 | Some class_info -> Typing_xhp.get_spread_attributes env p class_info valty
3011 (env, typed_attr, attr_ptys)
3014 * Simple XHP attributes (attr={expr} form) are simply interpreted as a member
3015 * variable prefixed with a colon, the types of which will be validated later
3017 and xhp_simple_attribute env id valexpr =
3018 let (p, _) = valexpr in
3019 let (env, te, valty) = expr env valexpr in
3020 (* This converts the attribute name to a member name. *)
3021 let name = ":" ^ snd id in
3022 let attr_pty = ((fst id, name), (p, valty)) in
3023 let typed_attr = Aast.Xhp_simple (id, te) in
3024 (env, typed_attr, [attr_pty])
3027 * Typecheck the attribute expressions - this just checks that the expressions are
3028 * valid, not that they match the declared type for the attribute and,
3029 * in case of spreads, makes sure they are XHP.
3031 and xhp_attribute_exprs env cid attrl =
3032 let handle_attr (env, typed_attrl, attr_ptyl) attr =
3033 let (env, typed_attr, attr_ptys) =
3034 match attr with
3035 | Xhp_simple (id, valexpr) -> xhp_simple_attribute env id valexpr
3036 | Xhp_spread valexpr -> xhp_spread_attribute env cid valexpr
3038 (env, typed_attr :: typed_attrl, attr_ptys @ attr_ptyl)
3040 let (env, typed_attrl, attr_ptyl) =
3041 List.fold_left ~f:handle_attr ~init:(env, [], []) attrl
3043 (env, List.rev typed_attrl, List.rev attr_ptyl)
3045 (*****************************************************************************)
3046 (* Anonymous functions. *)
3047 (*****************************************************************************)
3048 and anon_bind_param params (env, t_params) ty : env * Tast.fun_param list =
3049 match !params with
3050 | [] ->
3051 (* This code cannot be executed normally, because the arity is wrong
3052 * and it will error later. Bind as many parameters as we can and carry
3053 * on. *)
3054 (env, t_params)
3055 | param :: paraml ->
3056 params := paraml;
3057 (match hint_of_type_hint param.param_type_hint with
3058 | Some h ->
3059 let h = Decl_hint.hint env.decl_env h in
3060 (* When creating a closure, the 'this' type will mean the
3061 * late bound type of the current enclosing class
3063 let ety_env =
3064 { (Phase.env_with_self env) with from_class = Some CIstatic }
3066 let (env, h) = Phase.localize ~ety_env env h in
3067 let pos = get_pos h in
3068 let env =
3069 Typing_coercion.coerce_type
3071 Reason.URparam
3074 (MakeType.unenforced h)
3075 Errors.unify_error
3077 (* Closures are allowed to have explicit type-hints. When
3078 * that is the case we should check that the argument passed
3079 * is compatible with the type-hint.
3080 * The body of the function should be type-checked with the
3081 * hint and not the type of the argument passed.
3082 * Otherwise it leads to strange results where
3083 * foo(?string $x = null) is called with a string and fails to
3084 * type-check. If $x is a string instead of ?string, null is not
3085 * subtype of string ...
3087 let (env, t_param) = bind_param env (h, param) in
3088 (env, t_params @ [t_param])
3089 | None ->
3090 let ty =
3091 mk (Reason.Rlambda_param (param.param_pos, get_reason ty), get_node ty)
3093 let (env, t_param) = bind_param env (ty, param) in
3094 (env, t_params @ [t_param]))
3096 and anon_bind_variadic env vparam variadic_ty =
3097 let (env, ty, pos) =
3098 match hint_of_type_hint vparam.param_type_hint with
3099 | None ->
3100 (* if the hint is missing, use the type we expect *)
3101 (env, variadic_ty, get_pos variadic_ty)
3102 | Some hint ->
3103 let h = Decl_hint.hint env.decl_env hint in
3104 let ety_env =
3105 { (Phase.env_with_self env) with from_class = Some CIstatic }
3107 let (env, h) = Phase.localize ~ety_env env h in
3108 let pos = get_pos h in
3109 let env =
3110 Typing_coercion.coerce_type
3112 Reason.URparam
3114 variadic_ty
3115 (MakeType.unenforced h)
3116 Errors.unify_error
3118 (env, h, vparam.param_pos)
3120 let r = Reason.Rvar_param pos in
3121 let arr_values = mk (r, get_node ty) in
3122 let ty = MakeType.varray r arr_values in
3123 let (env, t_variadic) = bind_param env (ty, vparam) in
3124 (env, t_variadic)
3126 and anon_bind_opt_param env param : env =
3127 match param.param_expr with
3128 | None ->
3129 let ty = Typing_utils.mk_tany env param.param_pos in
3130 let (env, _) = bind_param env (ty, param) in
3132 | Some default ->
3133 let (env, _te, ty) = expr env default in
3134 Typing_sequencing.sequence_check_expr default;
3135 let (env, _) = bind_param env (ty, param) in
3138 and anon_check_param env param =
3139 match hint_of_type_hint param.param_type_hint with
3140 | None -> env
3141 | Some hty ->
3142 let (env, hty) = Phase.localize_hint_with_self env hty in
3143 let paramty = Env.get_local env (Local_id.make_unscoped param.param_name) in
3144 let hint_pos = get_pos hty in
3145 let env =
3146 Typing_coercion.coerce_type
3147 hint_pos
3148 Reason.URhint
3150 paramty
3151 (MakeType.unenforced hty)
3152 Errors.unify_error
3156 and stash_conts_for_anon env p is_anon captured f =
3157 let captured =
3158 if Env.is_local_defined env this then
3159 (Pos.none, this) :: captured
3160 else
3161 captured
3163 let init =
3164 Option.map (Env.next_cont_opt env) ~f:(fun next_cont ->
3165 let initial_locals =
3166 if is_anon then
3167 Env.get_locals env captured
3168 else
3169 next_cont.Typing_per_cont_env.local_types
3171 let initial_fakes =
3172 Fake.forget (Env.get_fake_members env) Reason.(Blame (p, BSlambda))
3174 let tpenv = Env.get_tpenv env in
3175 (initial_locals, initial_fakes, tpenv))
3177 Typing_lenv.stash_and_do env (Env.all_continuations env) (fun env ->
3178 let env =
3179 match init with
3180 | None -> env
3181 | Some (initial_locals, initial_fakes, tpenv) ->
3182 let env = Env.reinitialize_locals env in
3183 let env = Env.set_locals env initial_locals in
3184 let env = Env.set_fake_members env initial_fakes in
3185 let env = Env.env_with_tpenv env tpenv in
3188 f env)
3190 (* Make a type-checking function for an anonymous function. *)
3191 (* Here ret_ty should include Awaitable wrapper *)
3192 (* TODO: ?el is never set; so we need to fix variadic use of lambda *)
3193 and anon_make ?el ?ret_ty env lambda_pos f ft idl is_anon =
3194 let nb = Nast.assert_named_body f.f_body in
3195 Env.anon env.lenv env (fun env ->
3196 (* Extract capabilities from AAST and add them to the environment *)
3197 let (env, capability) =
3198 match (f.f_ctxs, f.f_unsafe_ctxs) with
3199 | (None, None) ->
3200 (* if the closure has no explicit coeffect annotations,
3201 do _not_ insert (unsafe) capabilities into the environment;
3202 instead, rely on the fact that a capability from an enclosing
3203 scope can simply be captured, which has the same semantics
3204 as redeclaring and shadowing with another same-typed capability.
3205 This avoid unnecessary overhead in the most common case, i.e.,
3206 when a closure does not need a different (usually smaller)
3207 set of capabilities. *)
3208 (env, Env.get_local env Typing_coeffects.local_capability_id)
3209 | (_, _) ->
3210 let (env, cap_ty, unsafe_cap_ty) =
3211 type_capability env f.f_ctxs f.f_unsafe_ctxs (fst f.f_name)
3213 Typing_coeffects.register_capabilities env cap_ty unsafe_cap_ty
3215 let ft =
3216 { ft with ft_implicit_params = { capability = CapTy capability } }
3218 stash_conts_for_anon env lambda_pos is_anon idl (fun env ->
3219 let env = Env.clear_params env in
3220 let make_variadic_arg env varg tyl =
3221 let remaining_types =
3222 (* It's possible the variadic arg will capture the variadic
3223 * parameter of the supplied arity (if arity is Fvariadic)
3224 * and additional supplied params.
3226 * For example in cases such as:
3227 * lambda1 = (int $a, string...$c) ==> {};
3228 * lambda1(1, "hello", ...$y); (where $y is a variadic string)
3229 * lambda1(1, "hello", "world");
3230 * then ...$c will contain "hello" and everything in $y in the first
3231 * example, and "hello" and "world" in the second example.
3233 * To account for a mismatch in arity, we take the remaining supplied
3234 * parameters and return a list of all their types. We'll use this
3235 * to create a union type when creating the typed variadic arg.
3237 let remaining_params =
3238 List.drop ft.ft_params (List.length f.f_params)
3240 List.map ~f:(fun param -> param.fp_type.et_type) remaining_params
3242 let r = Reason.Rvar_param varg.param_pos in
3243 let union = Tunion (tyl @ remaining_types) in
3244 let (env, t_param) = anon_bind_variadic env varg (mk (r, union)) in
3245 (env, Aast.FVvariadicArg t_param)
3247 let (env, t_variadic) =
3248 match (f.f_variadic, ft.ft_arity) with
3249 | (FVvariadicArg arg, Fvariadic variadic) ->
3250 make_variadic_arg env arg [variadic.fp_type.et_type]
3251 | (FVvariadicArg arg, Fstandard) -> make_variadic_arg env arg []
3252 | (FVellipsis pos, _) -> (env, Aast.FVellipsis pos)
3253 | (_, _) -> (env, Aast.FVnonVariadic)
3255 let params = ref f.f_params in
3256 let (env, t_params) =
3257 List.fold_left
3258 ~f:(anon_bind_param params)
3259 ~init:(env, [])
3260 (List.map ft.ft_params (fun x -> x.fp_type.et_type))
3262 let env = List.fold_left ~f:anon_bind_opt_param ~init:env !params in
3263 let env = List.fold_left ~f:anon_check_param ~init:env f.f_params in
3264 let env =
3265 match el with
3266 | None ->
3267 (*iter2_shortest
3268 Unify.unify_param_modes
3269 ft.ft_params
3270 supplied_params; *)
3272 | Some x ->
3273 let var_param =
3274 match f.f_variadic with
3275 | FVellipsis pos ->
3276 let param =
3277 TUtils.default_fun_param
3278 ~pos
3279 (mk (Reason.Rvar_param pos, Typing_defs.make_tany ()))
3281 Some param
3282 | _ -> None
3284 let rec iter l1 l2 =
3285 match (l1, l2, var_param) with
3286 | (_, [], _) -> ()
3287 | ([], _, None) -> ()
3288 | ([], x2 :: rl2, Some def1) ->
3289 param_modes ~is_variadic:true def1 x2;
3290 iter [] rl2
3291 | (x1 :: rl1, x2 :: rl2, _) ->
3292 param_modes x1 x2;
3293 iter rl1 rl2
3295 iter ft.ft_params x;
3296 wfold_left2 inout_write_back env ft.ft_params x
3298 let env = Env.set_fn_kind env f.f_fun_kind in
3299 let decl_ty =
3300 Option.map
3301 ~f:(Decl_hint.hint env.decl_env)
3302 (hint_of_type_hint f.f_ret)
3304 let (env, hret) =
3305 match decl_ty with
3306 | None ->
3307 (* Do we have a contextual return type? *)
3308 begin
3309 match ret_ty with
3310 | None ->
3311 let (env, ret_ty) = Env.fresh_type env lambda_pos in
3312 (env, Typing_return.wrap_awaitable env lambda_pos ret_ty)
3313 | Some ret_ty ->
3314 (* We might need to force it to be Awaitable if it is a type variable *)
3315 Typing_return.force_awaitable env lambda_pos ret_ty
3317 | Some ret ->
3318 (* If a 'this' type appears it needs to be compatible with the
3319 * late static type
3321 let ety_env =
3322 { (Phase.env_with_self env) with from_class = Some CIstatic }
3324 Typing_return.make_return_type (Phase.localize ~ety_env) env ret
3326 let env =
3327 Env.set_return
3329 (Typing_return.make_info
3330 f.f_fun_kind
3333 ~is_explicit:(Option.is_some ret_ty)
3334 hret
3335 decl_ty)
3337 let local_tpenv = Env.get_tpenv env in
3338 (* Outer pipe variables aren't available in closures. Note that
3339 * locals are restored by Env.anon after processing the closure
3341 let env =
3342 Env.unset_local
3344 (Local_id.make_unscoped SN.SpecialIdents.dollardollar)
3346 let (env, tb) = block env nb.fb_ast in
3347 let implicit_return = LEnv.has_next env in
3348 let env =
3349 if (not implicit_return) || Nast.named_body_is_unsafe nb then
3351 else
3352 fun_implicit_return env lambda_pos hret f.f_fun_kind
3354 let (env, tparams) = List.map_env env f.f_tparams type_param in
3355 let (env, user_attributes) =
3356 List.map_env env f.f_user_attributes user_attribute
3358 let tfun_ =
3360 Aast.f_annotation = Env.save local_tpenv env;
3361 Aast.f_span = f.f_span;
3362 Aast.f_mode = f.f_mode;
3363 Aast.f_ret = (hret, hint_of_type_hint f.f_ret);
3364 Aast.f_name = f.f_name;
3365 Aast.f_tparams = tparams;
3366 Aast.f_where_constraints = f.f_where_constraints;
3367 Aast.f_fun_kind = f.f_fun_kind;
3368 Aast.f_file_attributes = [];
3369 Aast.f_user_attributes = user_attributes;
3370 Aast.f_body = { Aast.fb_ast = tb; fb_annotation = () };
3371 Aast.f_ctxs = f.f_ctxs;
3372 Aast.f_unsafe_ctxs = f.f_unsafe_ctxs;
3373 Aast.f_params = t_params;
3374 Aast.f_variadic = t_variadic;
3375 (* TODO TAST: Variadic efuns *)
3376 Aast.f_external = f.f_external;
3377 Aast.f_namespace = f.f_namespace;
3378 Aast.f_doc_comment = f.f_doc_comment;
3379 Aast.f_static = f.f_static;
3382 let ty = mk (Reason.Rwitness lambda_pos, Tfun ft) in
3383 let te =
3384 Tast.make_typed_expr
3385 lambda_pos
3387 ( if is_anon then
3388 Aast.Efun (tfun_, idl)
3389 else
3390 Aast.Lfun (tfun_, idl) )
3392 let env = Env.set_tyvar_variance env ty in
3393 (env, (te, hret, ft))
3394 (* stash_conts_for_anon *))
3395 (* Env.anon *))
3397 (*****************************************************************************)
3398 (* End of anonymous functions. *)
3399 (*****************************************************************************)
3401 (*****************************************************************************)
3402 (* Expression trees *)
3403 (*****************************************************************************)
3404 and expression_tree env p et =
3405 let (_, t_src_expr, _) = expr_any env p et.et_src_expr in
3406 let (env, t_desugared_expr, ty_desugared) = expr env et.et_desugared_expr in
3407 make_result
3410 (Aast.ExpressionTree
3412 et_hint = et.et_hint;
3413 et_src_expr = t_src_expr;
3414 et_desugared_expr = t_desugared_expr;
3416 ty_desugared
3418 and et_splice env p e =
3419 let (env, te, ty) = expr env e in
3420 let (env, ty_visitor) = Env.fresh_type env p in
3421 let (env, ty_res) = Env.fresh_type env p in
3422 let (env, ty_infer) = Env.fresh_type env p in
3423 let expr_tree_type =
3424 MakeType.expr_tree (Reason.Rsplice p) ty_visitor ty_res ty_infer
3426 let env = SubType.sub_type env ty expr_tree_type Errors.unify_error in
3427 make_result env p (Aast.ET_Splice te) ty_infer
3429 (*****************************************************************************)
3430 (* End expression trees *)
3431 (*****************************************************************************)
3432 and type_capability env ctxs unsafe_ctxs default_pos =
3433 let cc = Decl_hint.aast_contexts_to_decl_capability in
3434 let (env, cap_ty) =
3435 match cc env.decl_env ctxs default_pos with
3436 | CapTy ty -> Phase.localize_with_self env ty
3437 | CapDefaults _p -> (env, MakeType.default_capability)
3439 let (env, unsafe_cap_ty) =
3440 match cc env.decl_env unsafe_ctxs default_pos with
3441 | CapTy ty -> Phase.localize_with_self env ty
3442 | CapDefaults p ->
3443 (* default is no unsafe capabilities *)
3444 (env, MakeType.mixed (Reason.Rhint p))
3446 (env, cap_ty, unsafe_cap_ty)
3448 and requires_consistent_construct = function
3449 | CIstatic -> true
3450 | CIexpr _ -> true
3451 | CIparent -> false
3452 | CIself -> false
3453 | CI _ -> false
3455 (* Caller will be looking for a particular form of expected type
3456 * e.g. a function type (when checking lambdas) or tuple type (when checking
3457 * tuples). First expand the expected type and elide single union; also
3458 * strip nullables, so ?t becomes t, as context will always accept a t if a ?t
3459 * is expected.
3461 and expand_expected_and_get_node env (expected : ExpectedTy.t option) =
3462 match expected with
3463 | None -> (env, None)
3464 | Some ExpectedTy.{ pos = p; reason = ur; ty = { et_type = ty; _ }; _ } ->
3465 let (env, ty) = Env.expand_type env ty in
3466 (match get_node ty with
3467 | Tunion [ty] -> (env, Some (p, ur, ty, get_node ty))
3468 | Toption ty -> (env, Some (p, ur, ty, get_node ty))
3469 | _ -> (env, Some (p, ur, ty, get_node ty)))
3471 (** Do a subtype check of inferred type against expected type *)
3472 and check_expected_ty message env inferred_ty (expected : ExpectedTy.t option) =
3473 match expected with
3474 | None -> env
3475 | Some ExpectedTy.{ pos = p; reason = ur; ty } ->
3476 Typing_log.(
3477 log_with_level env "typing" 1 (fun () ->
3478 log_types
3482 Log_head
3483 ( Printf.sprintf
3484 "Typing.check_expected_ty %s enforced=%b"
3485 message
3486 ty.et_enforced,
3488 Log_type ("inferred_ty", inferred_ty);
3489 Log_type ("expected_ty", ty.et_type);
3490 ] );
3491 ]));
3492 Typing_coercion.coerce_type p ur env inferred_ty ty Errors.unify_error
3494 and new_object
3495 ~(expected : ExpectedTy.t option)
3496 ~check_parent
3497 ~check_not_abstract
3498 ~is_using_clause
3502 explicit_targs
3504 unpacked_element =
3505 (* Obtain class info from the cid expression. We get multiple
3506 * results with a CIexpr that has a union type, e.g. in
3508 $classname = (mycond()? classname<A>: classname<B>);
3509 new $classname();
3511 let (env, tal, tcid, classes) =
3512 instantiable_cid ~exact:Exact p env cid explicit_targs
3514 let allow_abstract_bound_generic =
3515 match tcid with
3516 | ((_, ty), Aast.CI (_, tn)) -> is_generic_equal_to tn ty
3517 | _ -> false
3519 let gather (env, _tel, _typed_unpack_element) (cname, class_info, c_ty) =
3521 check_not_abstract
3522 && Cls.abstract class_info
3523 && (not (requires_consistent_construct cid))
3524 && not allow_abstract_bound_generic
3525 then
3526 uninstantiable_error
3530 (Cls.pos class_info)
3531 (Cls.name class_info)
3533 c_ty;
3534 let (env, obj_ty_, params) =
3535 let (env, c_ty) = Env.expand_type env c_ty in
3536 match (cid, tal, get_class_type c_ty) with
3537 (* Explicit type arguments *)
3538 | (CI _, _ :: _, Some (_, _, tyl)) -> (env, get_node c_ty, tyl)
3539 | (_, _, class_type_opt) ->
3540 let (env, params) =
3541 List.map_env env (Cls.tparams class_info) (fun env tparam ->
3542 let (env, tvar) =
3543 Env.fresh_type_reason
3545 (Reason.Rtype_variable_generics
3546 (p, snd tparam.tp_name, strip_ns (snd cname)))
3548 Typing_log.log_new_tvar_for_new_object env p tvar cname tparam;
3549 (env, tvar))
3551 begin
3552 match class_type_opt with
3553 | Some (_, Exact, _) -> (env, Tclass (cname, Exact, params), params)
3554 | _ -> (env, Tclass (cname, Nonexact, params), params)
3558 (not check_parent)
3559 && (not is_using_clause)
3560 && Cls.is_disposable class_info
3561 then
3562 Errors.invalid_new_disposable p;
3563 let r_witness = Reason.Rwitness p in
3564 let obj_ty = mk (r_witness, obj_ty_) in
3565 let c_ty =
3566 match cid with
3567 | CIstatic
3568 | CIexpr _ ->
3569 mk (r_witness, get_node c_ty)
3570 | _ -> obj_ty
3572 let (env, new_ty) =
3573 let ((_, cid_ty), _) = tcid in
3574 let (env, cid_ty) = Env.expand_type env cid_ty in
3575 if is_generic cid_ty then
3576 (env, cid_ty)
3577 else if check_parent then
3578 (env, c_ty)
3579 else
3580 ExprDepTy.make env cid c_ty
3582 (* Set variance according to type of `new` expression now. Lambda arguments
3583 * to the constructor might depend on it, and `call_construct` only uses
3584 * `ctor_fty` to set the variance which has void return type *)
3585 let env = Env.set_tyvar_variance env new_ty in
3586 let (env, tel, typed_unpack_element, ctor_fty) =
3587 let env = check_expected_ty "New" env new_ty expected in
3588 call_construct p env class_info params el unpacked_element cid new_ty
3590 ( if equal_consistent_kind (snd (Cls.construct class_info)) Inconsistent then
3591 match cid with
3592 | CIstatic -> Errors.new_inconsistent_construct p cname `static
3593 | CIexpr _ -> Errors.new_inconsistent_construct p cname `classname
3594 | _ -> () );
3595 match cid with
3596 | CIparent ->
3597 let (env, ctor_fty) =
3598 match fst (Cls.construct class_info) with
3599 | Some ({ ce_type = (lazy ty); _ } as ce) ->
3600 let ety_env =
3602 type_expansions = [];
3603 substs =
3604 TUtils.make_locl_subst_for_class_tparams class_info params;
3605 this_ty = obj_ty;
3606 from_class = None;
3607 quiet = false;
3608 on_error = Errors.unify_error_at p;
3611 if get_ce_abstract ce then
3612 Errors.parent_abstract_call
3613 SN.Members.__construct
3615 (get_pos ctor_fty);
3616 let (env, ctor_fty) = Phase.localize ~ety_env env ty in
3617 (env, ctor_fty)
3618 | None -> (env, ctor_fty)
3620 ((env, tel, typed_unpack_element), (obj_ty, ctor_fty))
3621 | CIstatic
3622 | CI _
3623 | CIself ->
3624 ((env, tel, typed_unpack_element), (c_ty, ctor_fty))
3625 | CIexpr _ ->
3626 (* When constructing from a (classname) variable, the variable
3627 * dictates what the constructed object is going to be. This allows
3628 * for generic and dependent types to be correctly carried
3629 * through the 'new $foo()' iff the constructed obj_ty is a
3630 * supertype of the variable-dictated c_ty *)
3631 let env =
3632 Typing_ops.sub_type p Reason.URnone env c_ty obj_ty Errors.unify_error
3634 ((env, tel, typed_unpack_element), (c_ty, ctor_fty))
3636 let (had_dynamic, classes) =
3637 List.fold classes ~init:(false, []) ~f:(fun (seen_dynamic, classes) ->
3638 function
3639 | `Dynamic -> (true, classes)
3640 | `Class (cname, class_info, c_ty) ->
3641 (seen_dynamic, (cname, class_info, c_ty) :: classes))
3643 let ((env, tel, typed_unpack_element), class_types_and_ctor_types) =
3644 List.fold_map classes ~init:(env, [], None) ~f:gather
3646 let class_types_and_ctor_types =
3647 let r = Reason.Rdynamic_construct p in
3648 let dyn = (mk (r, Tdynamic), mk (r, Tdynamic)) in
3649 if had_dynamic then
3650 dyn :: class_types_and_ctor_types
3651 else
3652 class_types_and_ctor_types
3654 let (env, tel, typed_unpack_element, ty, ctor_fty) =
3655 match class_types_and_ctor_types with
3656 | [] ->
3657 let (env, tel, _) = exprs env el in
3658 let (env, typed_unpack_element, _) =
3659 match unpacked_element with
3660 | None -> (env, None, MakeType.nothing Reason.Rnone)
3661 | Some unpacked_element ->
3662 let (env, e, ty) = expr env unpacked_element in
3663 (env, Some e, ty)
3665 let r = Reason.Runknown_class p in
3666 (env, tel, typed_unpack_element, mk (r, Tobject), TUtils.terr env r)
3667 | [(ty, ctor_fty)] -> (env, tel, typed_unpack_element, ty, ctor_fty)
3668 | l ->
3669 let (tyl, ctyl) = List.unzip l in
3670 let r = Reason.Rwitness p in
3671 (env, tel, typed_unpack_element, mk (r, Tunion tyl), mk (r, Tunion ctyl))
3673 let (env, new_ty) =
3674 let ((_, cid_ty), _) = tcid in
3675 let (env, cid_ty) = Env.expand_type env cid_ty in
3676 if is_generic cid_ty then
3677 (env, cid_ty)
3678 else if check_parent then
3679 (env, ty)
3680 else
3681 ExprDepTy.make env cid ty
3683 (env, tcid, tal, tel, typed_unpack_element, new_ty, ctor_fty)
3685 and attributes_check_def env kind attrs =
3686 Typing_attributes.check_def env new_object kind attrs
3688 (** Get class infos for a class expression (e.g. `parent`, `self` or
3689 regular classnames) - which might resolve to a union or intersection
3690 of classes - and check they are instantiable.
3692 FIXME: we need to separate our instantiability into two parts. Currently,
3693 all this function is doing is checking if a given type is inhabited --
3694 that is, whether there are runtime values of type Aast. However,
3695 instantiability should be the stricter notion that T has a runtime
3696 constructor; that is, `new T()` should be valid. In particular, interfaces
3697 are inhabited, but not instantiable.
3698 To make this work with classname, we likely need to add something like
3699 concrete_classname<T>, where T cannot be an interface. *)
3700 and instantiable_cid ?(exact = Nonexact) p env cid explicit_targs :
3701 newable_class_info =
3702 let (env, tal, te, classes) =
3703 class_id_for_new ~exact p env cid explicit_targs
3705 List.iter classes (function
3706 | `Dynamic -> ()
3707 | `Class ((pos, name), class_info, c_ty) ->
3709 Ast_defs.(equal_class_kind (Cls.kind class_info) Ctrait)
3710 || Ast_defs.(equal_class_kind (Cls.kind class_info) Cenum)
3711 then
3712 match cid with
3713 | CIexpr _
3714 | CI _ ->
3715 uninstantiable_error env p cid (Cls.pos class_info) name pos c_ty
3716 | CIstatic
3717 | CIparent
3718 | CIself ->
3720 else if
3721 Ast_defs.(equal_class_kind (Cls.kind class_info) Cabstract)
3722 && Cls.final class_info
3723 then
3724 uninstantiable_error env p cid (Cls.pos class_info) name pos c_ty
3725 else
3726 ());
3727 (env, tal, te, classes)
3729 and uninstantiable_error env reason_pos cid c_tc_pos c_name c_usage_pos c_ty =
3730 let reason_msgl =
3731 match cid with
3732 | CIexpr _ ->
3733 let ty_str = "This would be " ^ Typing_print.error env c_ty in
3734 [(reason_pos, ty_str)]
3735 | _ -> []
3737 Errors.uninstantiable_class c_usage_pos c_tc_pos c_name reason_msgl
3739 and coerce_to_throwable pos env exn_ty =
3740 let throwable_ty = MakeType.throwable (Reason.Rthrow pos) in
3741 Typing_coercion.coerce_type
3743 Reason.URthrow
3745 exn_ty
3746 { et_type = throwable_ty; et_enforced = false }
3747 Errors.unify_error
3749 and shape_field_pos = function
3750 | Ast_defs.SFlit_int (p, _)
3751 | Ast_defs.SFlit_str (p, _) ->
3753 | Ast_defs.SFclass_const ((cls_pos, _), (mem_pos, _)) ->
3754 Pos.btw cls_pos mem_pos
3756 and check_shape_keys_validity env pos keys =
3757 (* If the key is a class constant, get its class name and type. *)
3758 let get_field_info env key =
3759 let key_pos = shape_field_pos key in
3760 (* Empty strings or literals that start with numbers are not
3761 permitted as shape field names. *)
3762 match key with
3763 | Ast_defs.SFlit_int _ -> (env, key_pos, None)
3764 | Ast_defs.SFlit_str (_, key_name) ->
3765 if Int.equal 0 (String.length key_name) then
3766 Errors.invalid_shape_field_name_empty key_pos;
3767 (env, key_pos, None)
3768 | Ast_defs.SFclass_const (((p, cls) as x), y) ->
3769 let (env, _te, ty) = class_const env pos ((p, CI x), y) in
3770 let r = Reason.Rwitness key_pos in
3771 let env =
3772 Type.sub_type
3773 key_pos
3774 Reason.URnone
3777 (MakeType.arraykey r)
3778 (fun ?code:_ _ _ ->
3779 Errors.invalid_shape_field_type
3780 key_pos
3781 (get_pos ty)
3782 (Typing_print.error env ty)
3785 (env, key_pos, Some (cls, ty))
3787 let check_field witness_pos witness_info env key =
3788 let (env, key_pos, key_info) = get_field_info env key in
3789 match (witness_info, key_info) with
3790 | (Some _, None) ->
3791 Errors.invalid_shape_field_literal key_pos witness_pos;
3793 | (None, Some _) ->
3794 Errors.invalid_shape_field_const key_pos witness_pos;
3796 | (None, None) -> env
3797 | (Some (cls1, ty1), Some (cls2, ty2)) ->
3798 if String.( <> ) cls1 cls2 then
3799 Errors.shape_field_class_mismatch
3800 key_pos
3801 witness_pos
3802 (strip_ns cls2)
3803 (strip_ns cls1);
3806 ( Typing_solver.is_sub_type env ty1 ty2
3807 && Typing_solver.is_sub_type env ty2 ty1 )
3808 then
3809 Errors.shape_field_type_mismatch
3810 key_pos
3811 witness_pos
3812 (Typing_print.error env ty2)
3813 (Typing_print.error env ty1);
3816 (* Sort the keys by their positions since the error messages will make
3817 * more sense if we take the one that appears first as canonical and if
3818 * they are processed in source order. *)
3819 let cmp_keys x y = Pos.compare (shape_field_pos x) (shape_field_pos y) in
3820 let keys = List.sort ~compare:cmp_keys keys in
3821 match keys with
3822 | [] -> env
3823 | witness :: rest_keys ->
3824 let (env, pos, info) = get_field_info env witness in
3825 List.fold_left ~f:(check_field pos info) ~init:env rest_keys
3827 and set_valid_rvalue p env x ty =
3828 let env = set_local env (p, x) ty in
3829 (* We are assigning a new value to the local variable, so we need to
3830 * generate a new expression id
3832 Env.set_local_expr_id env x (Ident.tmp ())
3834 (* Produce an error if assignment is used in the scope of the |> operator, i.e.
3835 * if $$ is in scope *)
3836 and error_if_assign_in_pipe p env =
3837 let dd_var = Local_id.make_unscoped SN.SpecialIdents.dollardollar in
3838 let dd_defined = Env.is_local_defined env dd_var in
3839 if dd_defined then
3840 Errors.unimplemented_feature p "Assignment within pipe expressions"
3842 (* Deal with assignment of a value of type ty2 to lvalue e1 *)
3843 and assign p env e1 ty2 : _ * Tast.expr * Tast.ty =
3844 error_if_assign_in_pipe p env;
3845 assign_ p Reason.URassign env e1 ty2
3847 and is_hack_collection env ty =
3848 Typing_solver.is_sub_type
3851 (MakeType.const_collection Reason.Rnone (MakeType.mixed Reason.Rnone))
3853 and assign_ p ur env e1 ty2 =
3854 let env =
3855 match e1 with
3856 | (_, Lvar (_, x)) ->
3857 Env.forget_prefixed_members env x Reason.(Blame (p, BSassignment))
3858 (* If we ever extend fake members from $x->a to more complicated lvalues
3859 such as $x->a->b, we would need to call forget_prefixed_members on
3860 other lvalues as well. *)
3861 | (_, Obj_get (_, (_, Id (_, property)), _, _)) ->
3862 Env.forget_suffixed_members env property Reason.(Blame (p, BSassignment))
3863 | _ -> env
3865 match e1 with
3866 | (_, Lvar ((_, x) as id)) ->
3867 let env = set_valid_rvalue p env x ty2 in
3868 make_result env (fst e1) (Aast.Lvar id) ty2
3869 | (_, Lplaceholder id) ->
3870 let placeholder_ty = MakeType.void (Reason.Rplaceholder p) in
3871 make_result env (fst e1) (Aast.Lplaceholder id) placeholder_ty
3872 | (_, List el) ->
3873 let (env, tyl) =
3874 List.map_env env el ~f:(fun env _ -> Env.fresh_type env (get_pos ty2))
3876 let destructure_ty =
3877 MakeType.list_destructure (Reason.Rdestructure (fst e1)) tyl
3879 let lty2 = LoclType ty2 in
3880 let env = Type.sub_type_i p ur env lty2 destructure_ty Errors.unify_error in
3881 let env = Env.set_tyvar_variance_i env destructure_ty in
3882 let (env, reversed_tel) =
3883 List.fold2_exn el tyl ~init:(env, []) ~f:(fun (env, tel) lvalue ty2 ->
3884 let (env, te, _) = assign p env lvalue ty2 in
3885 (env, te :: tel))
3887 make_result env (fst e1) (Aast.List (List.rev reversed_tel)) ty2
3888 | ( pobj,
3889 Obj_get (obj, (pm, Id ((_, member_name) as m)), nullflavor, in_parens) )
3891 let lenv = env.lenv in
3892 let nullsafe =
3893 match nullflavor with
3894 | OG_nullthrows -> None
3895 | OG_nullsafe -> Some (Reason.Rnullsafe_op pobj)
3897 let (env, tobj, obj_ty) = expr ~accept_using_var:true env obj in
3898 let env = might_throw env in
3899 let (env, (result, _tal)) =
3900 TOG.obj_get
3901 ~obj_pos:(fst obj)
3902 ~is_method:false
3903 ~nullsafe
3904 ~coerce_from_ty:(Some (p, ur, ty2))
3905 ~explicit_targs:[]
3907 obj_ty
3908 (CIexpr e1)
3910 Errors.unify_error
3912 let te1 =
3913 Tast.make_typed_expr
3914 pobj
3915 result
3916 (Aast.Obj_get
3917 ( tobj,
3918 Tast.make_typed_expr pm result (Aast.Id m),
3919 nullflavor,
3920 in_parens ))
3922 let env = { env with lenv } in
3923 begin
3924 match obj with
3925 | (_, This) ->
3926 let (env, local) = Env.FakeMembers.make env obj member_name p in
3927 let env = set_valid_rvalue p env local ty2 in
3928 (env, te1, ty2)
3929 | (_, Lvar _) ->
3930 let (env, local) = Env.FakeMembers.make env obj member_name p in
3931 let env = set_valid_rvalue p env local ty2 in
3932 (env, te1, ty2)
3933 | _ -> (env, te1, ty2)
3935 | (_, Obj_get _) ->
3936 let lenv = env.lenv in
3937 let no_fakes = LEnv.env_with_empty_fakes env in
3938 let (env, te1, real_type) = lvalue no_fakes e1 in
3939 let (env, exp_real_type) = Env.expand_type env real_type in
3940 let env = { env with lenv } in
3941 let env =
3942 Typing_coercion.coerce_type
3947 (MakeType.unenforced exp_real_type)
3948 Errors.unify_error
3950 (env, te1, ty2)
3951 | (_, Class_get (_, CGexpr _, _)) ->
3952 failwith "AST should not have any CGexprs after naming"
3953 | (_, Class_get ((pos_classid, x), CGstring (pos_member, y), _)) ->
3954 let lenv = env.lenv in
3955 let no_fakes = LEnv.env_with_empty_fakes env in
3956 let (env, te1, _) = lvalue no_fakes e1 in
3957 let env = { env with lenv } in
3958 let (env, ety2) = Env.expand_type env ty2 in
3959 (* This defers the coercion check to class_get, which looks up the appropriate target type *)
3960 let (env, _tal, _, cty) =
3961 static_class_id ~check_constraints:false pos_classid env [] x
3963 let env = might_throw env in
3964 let (env, _) =
3965 class_get
3966 ~is_method:false
3967 ~is_const:false
3968 ~coerce_from_ty:(Some (p, ur, ety2))
3971 (pos_member, y)
3974 let (env, local) = Env.FakeMembers.make_static env x y p in
3975 let env = set_valid_rvalue p env local ty2 in
3976 (env, te1, ty2)
3977 | (pos, Array_get (e1, None)) ->
3978 let (env, te1, ty1) = update_array_type pos env e1 `lvalue in
3979 let (env, ty1') =
3980 Typing_array_access.assign_array_append
3981 ~array_pos:(fst e1)
3982 ~expr_pos:p
3988 let (env, te1) =
3989 if is_hack_collection env ty1 then
3990 (env, te1)
3991 else
3992 let (env, te1, _) = assign_ p ur env e1 ty1' in
3993 (env, te1)
3995 make_result env pos (Aast.Array_get (te1, None)) ty2
3996 | (pos, Array_get (e1, Some e)) ->
3997 let (env, te1, ty1) = update_array_type pos env e1 `lvalue in
3998 let (env, te, ty) = expr env e in
3999 let (env, ty1') =
4000 Typing_array_access.assign_array_get
4001 ~array_pos:(fst e1)
4002 ~expr_pos:p
4010 let (env, te1) =
4011 if is_hack_collection env ty1 then
4012 (env, te1)
4013 else
4014 let (env, te1, _) = assign_ p ur env e1 ty1' in
4015 (env, te1)
4017 (env, ((pos, ty2), Aast.Array_get (te1, Some te)), ty2)
4018 | _ -> assign_simple p ur env e1 ty2
4020 and assign_simple pos ur env e1 ty2 =
4021 let (env, te1, ty1) = lvalue env e1 in
4022 let env =
4023 Typing_coercion.coerce_type
4028 (MakeType.unenforced ty1)
4029 Errors.unify_error
4031 (env, te1, ty2)
4033 and array_field env = function
4034 | AFvalue ve ->
4035 let (env, tve, tv) = expr env ve in
4036 (env, (Aast.AFvalue tve, None, tv))
4037 | AFkvalue (ke, ve) ->
4038 let (env, tke, tk) = expr env ke in
4039 let (env, tve, tv) = expr env ve in
4040 (env, (Aast.AFkvalue (tke, tve), Some tk, tv))
4042 and array_value ~(expected : ExpectedTy.t option) env x =
4043 let (env, te, ty) = expr ?expected env x in
4044 (env, (te, ty))
4046 and arraykey_value
4047 p class_name ~(expected : ExpectedTy.t option) env ((pos, _) as x) =
4048 let (env, (te, ty)) = array_value ~expected env x in
4049 let ty_arraykey = MakeType.arraykey (Reason.Ridx_dict pos) in
4050 let env =
4051 Typing_coercion.coerce_type
4053 (Reason.index_class class_name)
4056 { et_type = ty_arraykey; et_enforced = true }
4057 Errors.unify_error
4059 (env, (te, ty))
4061 and check_parent_construct pos env el unpacked_element env_parent =
4062 let check_not_abstract = false in
4063 let (env, env_parent) = Phase.localize_with_self env env_parent in
4064 let (env, _tcid, _tal, tel, typed_unpack_element, parent, fty) =
4065 new_object
4066 ~expected:None
4067 ~check_parent:true
4068 ~check_not_abstract
4069 ~is_using_clause:false
4072 CIparent
4075 unpacked_element
4077 (* Not sure why we need to equate these types *)
4078 let env =
4079 Type.sub_type pos Reason.URnone env env_parent parent Errors.unify_error
4081 let env =
4082 Type.sub_type pos Reason.URnone env parent env_parent Errors.unify_error
4084 ( env,
4085 tel,
4086 typed_unpack_element,
4087 MakeType.void (Reason.Rwitness pos),
4088 parent,
4089 fty )
4091 and check_class_get env p def_pos cid mid ce e function_pointer =
4092 match e with
4093 | CIself when get_ce_abstract ce ->
4094 begin
4095 match get_class_type (Env.get_self env) with
4096 | Some ((_, self), _, _) ->
4097 (* at runtime, self:: in a trait is a call to whatever
4098 * self:: is in the context of the non-trait "use"-ing
4099 * the trait's code *)
4100 begin
4101 match Env.get_class env self with
4102 | Some cls when Ast_defs.(equal_class_kind (Cls.kind cls) Ctrait) ->
4103 (* Ban self::some_abstract_method() in a trait, if the
4104 * method is also defined in a trait.
4106 * Abstract methods from interfaces are fine: we'll check
4107 * in the child class that we actually have an
4108 * implementation. *)
4109 (match Decl_provider.get_class (Env.get_ctx env) ce.ce_origin with
4110 | Some meth_cls
4111 when Ast_defs.(equal_class_kind (Cls.kind meth_cls) Ctrait) ->
4112 Errors.self_abstract_call mid p def_pos
4113 | _ -> ())
4114 | _ ->
4115 (* Ban self::some_abstract_method() in a class. This will
4116 * always error. *)
4117 Errors.self_abstract_call mid p def_pos
4119 | None -> ()
4121 | CIparent when get_ce_abstract ce ->
4122 Errors.parent_abstract_call mid p def_pos
4123 | CI _ when get_ce_abstract ce && function_pointer ->
4124 Errors.abstract_function_pointer cid mid p def_pos
4125 | CI _ when get_ce_abstract ce ->
4126 Errors.classname_abstract_call cid mid p def_pos
4127 | CI (_, classname) when get_ce_synthesized ce ->
4128 Errors.static_synthetic_method classname mid p def_pos
4129 | _ -> ()
4131 and call_parent_construct pos env el unpacked_element =
4132 match Env.get_parent_ty env with
4133 | Some parent -> check_parent_construct pos env el unpacked_element parent
4134 | None ->
4135 (* continue here *)
4136 let ty = Typing_utils.mk_tany env pos in
4137 let default = (env, [], None, ty, ty, ty) in
4138 (match get_class_type (Env.get_self env) with
4139 | Some ((_, self), _, _) ->
4140 (match Env.get_class env self with
4141 | Some trait when Ast_defs.(equal_class_kind (Cls.kind trait) Ctrait) ->
4142 (match trait_most_concrete_req_class trait env with
4143 | None ->
4144 Errors.parent_in_trait pos;
4145 default
4146 | Some (_, parent_ty) ->
4147 check_parent_construct pos env el unpacked_element parent_ty)
4148 | Some self_tc ->
4149 if not (Cls.members_fully_known self_tc) then
4151 (* Don't know the hierarchy, assume it's correct *)
4152 else
4153 Errors.undefined_parent pos;
4154 default
4155 | None -> assert false)
4156 | None ->
4157 Errors.parent_outside_class pos;
4158 let ty = err_witness env pos in
4159 (env, [], None, ty, ty, ty))
4161 (* Depending on the kind of expression we are dealing with
4162 * The typing of call is different.
4164 and dispatch_call
4165 ~(expected : ExpectedTy.t option)
4166 ~is_using_clause
4167 ?in_await
4170 ((fpos, fun_expr) as e)
4171 explicit_targs
4173 unpacked_element =
4174 let make_call env te tal tel typed_unpack_element ty =
4175 make_result env p (Aast.Call (te, tal, tel, typed_unpack_element)) ty
4177 (* TODO: Avoid Tany annotations in TAST by eliminating `make_call_special` *)
4178 let make_call_special env id tel ty =
4179 make_call
4181 (Tast.make_typed_expr fpos (TUtils.mk_tany env fpos) (Aast.Id id))
4184 None
4187 (* For special functions and pseudofunctions with a definition in hhi. *)
4188 let make_call_special_from_def env id tel ty_ =
4189 let (env, fty, tal) = fun_type_of_id env id explicit_targs el in
4190 let ty =
4191 match get_node fty with
4192 | Tfun ft -> ft.ft_ret.et_type
4193 | _ -> ty_ (Reason.Rwitness p)
4195 make_call env (Tast.make_typed_expr fpos fty (Aast.Id id)) tal tel None ty
4197 let overload_function = overload_function make_call fpos in
4198 let check_disposable_in_return env fty =
4199 if is_return_disposable_fun_type env fty && not is_using_clause then
4200 Errors.invalid_new_disposable p
4202 match fun_expr with
4203 (* Special function `echo` *)
4204 | Id ((p, pseudo_func) as id)
4205 when String.equal pseudo_func SN.SpecialFunctions.echo ->
4206 let (env, tel, _) = exprs ~accept_using_var:true env el in
4207 make_call_special env id tel (MakeType.void (Reason.Rwitness p))
4208 (* Special function `isset` *)
4209 | Id ((_, pseudo_func) as id)
4210 when String.equal pseudo_func SN.PseudoFunctions.isset ->
4211 let (env, tel, _) =
4212 exprs ~accept_using_var:true ~check_defined:false env el
4214 if Option.is_some unpacked_element then
4215 Errors.unpacking_disallowed_builtin_function p pseudo_func;
4216 make_call_special_from_def env id tel MakeType.bool
4217 (* Special function `unset` *)
4218 | Id ((_, pseudo_func) as id)
4219 when String.equal pseudo_func SN.PseudoFunctions.unset ->
4220 let (env, tel, _) = exprs env el in
4221 if Option.is_some unpacked_element then
4222 Errors.unpacking_disallowed_builtin_function p pseudo_func;
4223 let checked_unset_error =
4224 if Partial.should_check_error (Env.get_mode env) 4135 then
4225 Errors.unset_nonidx_in_strict
4226 else
4227 fun _ _ ->
4230 let env =
4231 match (el, unpacked_element) with
4232 | ([(_, Array_get ((_, Class_const _), Some _))], None)
4233 when Partial.should_check_error (Env.get_mode env) 4011 ->
4234 Errors.const_mutation p Pos.none "";
4236 | ([(_, Array_get (ea, Some _))], None) ->
4237 let (env, _te, ty) = expr env ea in
4238 let r = Reason.Rwitness p in
4239 let tmixed = MakeType.mixed r in
4240 let super =
4242 ( Reason.Rnone,
4243 Tunion
4245 MakeType.dynamic r;
4246 MakeType.dict r tmixed tmixed;
4247 MakeType.keyset r tmixed;
4248 MakeType.darray r tmixed tmixed;
4251 SubType.sub_type_or_fail env ty super (fun () ->
4252 checked_unset_error
4254 (Reason.to_string
4255 ("This is " ^ Typing_print.error ~ignore_dynamic:true env ty)
4256 (get_reason ty)))
4257 | _ ->
4258 checked_unset_error p [];
4261 (match el with
4262 | [(p, Obj_get (_, _, OG_nullsafe, _))] ->
4263 Errors.nullsafe_property_write_context p;
4264 make_call_special_from_def env id tel (TUtils.terr env)
4265 | _ -> make_call_special_from_def env id tel MakeType.void)
4266 (* Special function `array_filter` *)
4267 | Id ((_, array_filter) as id)
4268 when String.equal array_filter SN.StdlibFunctions.array_filter
4269 && (not (List.is_empty el))
4270 && Option.is_none unpacked_element ->
4271 (* dispatch the call to typecheck the arguments *)
4272 let (env, fty, tal) = fun_type_of_id env id explicit_targs el in
4273 let (env, (tel, typed_unpack_element, res)) =
4274 call ~expected p env fty el unpacked_element
4276 (* but ignore the result and overwrite it with custom return type *)
4277 let x = List.hd_exn el in
4278 let (env, _tx, ty) = expr env x in
4279 let explain_array_filter ty =
4280 map_reason ty ~f:(fun r -> Reason.Rarray_filter (p, r))
4282 let get_value_type env tv =
4283 let (env, tv) =
4284 if List.length el > 1 then
4285 (env, tv)
4286 else
4287 Typing_solver.non_null env p tv
4289 (env, explain_array_filter tv)
4291 let rec get_array_filter_return_type env ty =
4292 let (env, ety) = Env.expand_type env ty in
4293 match deref ety with
4294 | (r, Tvarray tv) ->
4295 let (env, tv) = get_value_type env tv in
4296 (env, MakeType.varray r tv)
4297 | (r, Tunion tyl) ->
4298 let (env, tyl) = List.map_env env tyl get_array_filter_return_type in
4299 Typing_union.union_list env r tyl
4300 | (r, Tintersection tyl) ->
4301 let (env, tyl) = List.map_env env tyl get_array_filter_return_type in
4302 Inter.intersect_list env r tyl
4303 | (r, Tany _) -> (env, mk (r, Typing_utils.tany env))
4304 | (r, Terr) -> (env, TUtils.terr env r)
4305 | (r, _) ->
4306 let (env, tk) = Env.fresh_type env p in
4307 let (env, tv) = Env.fresh_type env p in
4308 Errors.try_
4309 (fun () ->
4310 let keyed_container_type =
4311 MakeType.keyed_container Reason.Rnone tk tv
4313 let env =
4314 SubType.sub_type env ety keyed_container_type Errors.unify_error
4316 let (env, tv) = get_value_type env tv in
4317 (env, MakeType.darray r (explain_array_filter tk) tv))
4318 (fun _ ->
4319 Errors.try_
4320 (fun () ->
4321 let container_type = MakeType.container Reason.Rnone tv in
4322 let env =
4323 SubType.sub_type env ety container_type Errors.unify_error
4325 let (env, tv) = get_value_type env tv in
4326 ( env,
4327 MakeType.darray
4329 (explain_array_filter (MakeType.arraykey r))
4330 tv ))
4331 (fun _ -> (env, res)))
4333 let (env, rty) = get_array_filter_return_type env ty in
4334 let fty =
4335 map_ty fty ~f:(function
4336 | Tfun ft -> Tfun { ft with ft_ret = MakeType.unenforced rty }
4337 | ty -> ty)
4339 make_call
4341 (Tast.make_typed_expr fpos fty (Aast.Id id))
4344 typed_unpack_element
4346 (* Special function `type_structure` *)
4347 | Id (p, type_structure)
4348 when String.equal type_structure SN.StdlibFunctions.type_structure
4349 && Int.equal (List.length el) 2
4350 && Option.is_none unpacked_element ->
4351 (match el with
4352 | [e1; e2] ->
4353 (match e2 with
4354 | (p, String cst) ->
4355 (* find the class constant implicitly defined by the typeconst *)
4356 let cid =
4357 match e1 with
4358 | (_, Class_const (cid, (_, x)))
4359 | (_, Class_get (cid, CGstring (_, x), _))
4360 when String.equal x SN.Members.mClass ->
4362 | _ -> (fst e1, CIexpr e1)
4364 class_const ~incl_tc:true env p (cid, (p, cst))
4365 | _ ->
4366 Errors.illegal_type_structure p "second argument is not a string";
4367 expr_error env (Reason.Rwitness p) e)
4368 | _ -> assert false)
4369 (* Special function `array_map` *)
4370 | Id ((_, array_map) as x)
4371 when String.equal array_map SN.StdlibFunctions.array_map
4372 && (not (List.is_empty el))
4373 && Option.is_none unpacked_element ->
4374 (* This uses the arity to determine a signature for array_map. But there
4375 * is more: for two-argument use of array_map, we specialize the return
4376 * type to the collection that's passed in, below. *)
4377 let (env, fty, tal) = fun_type_of_id env x explicit_targs el in
4378 let (env, fty) = Env.expand_type env fty in
4379 let r_fty = get_reason fty in
4381 Takes a Container type and returns a function that can "pack" a type
4382 into an array of appropriate shape, preserving the key type, i.e.:
4383 array -> f, where f R = array
4384 array<X> -> f, where f R = array<R>
4385 array<X, Y> -> f, where f R = array<X, R>
4386 Vector<X> -> f where f R = array<R>
4387 KeyedContainer<X, Y> -> f, where f R = array<X, R>
4388 Container<X> -> f, where f R = array<arraykey, R>
4389 X -> f, where f R = Y
4391 let rec build_output_container env (x : locl_ty) :
4392 env * (env -> locl_ty -> env * locl_ty) =
4393 let (env, x) = Env.expand_type env x in
4394 match deref x with
4395 | (r, Tvarray _) -> (env, (fun env tr -> (env, MakeType.varray r tr)))
4396 | (r, Tany _) -> (env, (fun env _ -> (env, mk (r, Typing_utils.tany env))))
4397 | (r, Terr) -> (env, (fun env _ -> (env, TUtils.terr env r)))
4398 | (r, Tunion tyl) ->
4399 let (env, builders) = List.map_env env tyl build_output_container in
4400 ( env,
4401 fun env tr ->
4402 let (env, tyl) =
4403 List.map_env env builders (fun env f -> f env tr)
4405 Typing_union.union_list env r tyl )
4406 | (r, Tintersection tyl) ->
4407 let (env, builders) = List.map_env env tyl build_output_container in
4408 ( env,
4409 fun env tr ->
4410 let (env, tyl) =
4411 List.map_env env builders (fun env f -> f env tr)
4413 Typing_intersection.intersect_list env r tyl )
4414 | (r, _) ->
4415 let (env, tk) = Env.fresh_type env p in
4416 let (env, tv) = Env.fresh_type env p in
4417 let try_vector env =
4418 let vector_type = MakeType.const_vector r_fty tv in
4419 let env = SubType.sub_type env x vector_type Errors.unify_error in
4420 (env, (fun env tr -> (env, MakeType.varray r tr)))
4422 let try_keyed_container env =
4423 let keyed_container_type = MakeType.keyed_container r_fty tk tv in
4424 let env =
4425 SubType.sub_type env x keyed_container_type Errors.unify_error
4427 (env, (fun env tr -> (env, MakeType.darray r tk tr)))
4429 let try_container env =
4430 let container_type = MakeType.container r_fty tv in
4431 let env = SubType.sub_type env x container_type Errors.unify_error in
4432 ( env,
4433 (fun env tr -> (env, MakeType.darray r (MakeType.arraykey r) tr)) )
4435 let (env, tr) =
4436 Errors.try_
4437 (fun () -> try_vector env)
4438 (fun _ ->
4439 Errors.try_
4440 (fun () -> try_keyed_container env)
4441 (fun _ ->
4442 Errors.try_
4443 (fun () -> try_container env)
4444 (fun _ ->
4445 (env, (fun env _ -> (env, Typing_utils.mk_tany env p))))))
4447 (env, tr)
4449 let (env, fty) =
4450 match (deref fty, el) with
4451 | ((_, Tfun funty), [_; x]) ->
4452 let (env, _tx, x) = expr env x in
4453 let (env, output_container) = build_output_container env x in
4454 begin
4455 match get_varray_inst funty.ft_ret.et_type with
4456 | None -> (env, fty)
4457 | Some elem_ty ->
4458 let (env, elem_ty) = output_container env elem_ty in
4459 let ft_ret = MakeType.unenforced elem_ty in
4460 (env, mk (r_fty, Tfun { funty with ft_ret }))
4462 | _ -> (env, fty)
4464 let (env, (tel, typed_unpack_element, ty)) =
4465 call ~expected p env fty el None
4467 make_call
4469 (Tast.make_typed_expr fpos fty (Aast.Id x))
4472 typed_unpack_element
4474 (* Special function `Shapes::idx` *)
4475 | Class_const (((_, CI (_, shapes)) as class_id), ((_, idx) as method_id))
4476 when String.equal shapes SN.Shapes.cShapes && String.equal idx SN.Shapes.idx
4478 overload_function
4481 class_id
4482 method_id
4484 unpacked_element
4485 (fun env fty res el ->
4486 match el with
4487 | [shape; field] ->
4488 let (env, _ts, shape_ty) = expr env shape in
4489 Typing_shapes.idx
4491 shape_ty
4492 field
4493 None
4494 ~expr_pos:p
4495 ~fun_pos:(get_reason fty)
4496 ~shape_pos:(fst shape)
4497 | [shape; field; default] ->
4498 let (env, _ts, shape_ty) = expr env shape in
4499 let (env, _td, default_ty) = expr env default in
4500 Typing_shapes.idx
4502 shape_ty
4503 field
4504 (Some (fst default, default_ty))
4505 ~expr_pos:p
4506 ~fun_pos:(get_reason fty)
4507 ~shape_pos:(fst shape)
4508 | _ -> (env, res))
4509 (* Special function `Shapes::at` *)
4510 | Class_const (((_, CI (_, shapes)) as class_id), ((_, at) as method_id))
4511 when String.equal shapes SN.Shapes.cShapes && String.equal at SN.Shapes.at
4513 overload_function
4516 class_id
4517 method_id
4519 unpacked_element
4520 (fun env _fty res el ->
4521 match el with
4522 | [shape; field] ->
4523 let (env, _te, shape_ty) = expr env shape in
4524 Typing_shapes.at env ~expr_pos:p ~shape_pos:(fst shape) shape_ty field
4525 | _ -> (env, res))
4526 (* Special function `Shapes::keyExists` *)
4527 | Class_const
4528 (((_, CI (_, shapes)) as class_id), ((_, key_exists) as method_id))
4529 when String.equal shapes SN.Shapes.cShapes
4530 && String.equal key_exists SN.Shapes.keyExists ->
4531 overload_function
4534 class_id
4535 method_id
4537 unpacked_element
4538 (fun env fty res el ->
4539 match el with
4540 | [shape; field] ->
4541 let (env, _te, shape_ty) = expr env shape in
4542 (* try accessing the field, to verify existence, but ignore
4543 * the returned type and keep the one coming from function
4544 * return type hint *)
4545 let (env, _) =
4546 Typing_shapes.idx
4548 shape_ty
4549 field
4550 None
4551 ~expr_pos:p
4552 ~fun_pos:(get_reason fty)
4553 ~shape_pos:(fst shape)
4555 (env, res)
4556 | _ -> (env, res))
4557 (* Special function `Shapes::removeKey` *)
4558 | Class_const
4559 (((_, CI (_, shapes)) as class_id), ((_, remove_key) as method_id))
4560 when String.equal shapes SN.Shapes.cShapes
4561 && String.equal remove_key SN.Shapes.removeKey ->
4562 overload_function
4565 class_id
4566 method_id
4568 unpacked_element
4569 (fun env _ res el ->
4570 match el with
4571 | [shape; field] ->
4572 begin
4573 match shape with
4574 | (_, Lvar (_, lvar))
4575 | (_, Callconv (Ast_defs.Pinout, (_, Lvar (_, lvar)))) ->
4576 let (env, _te, shape_ty) = expr env shape in
4577 let (env, shape_ty) =
4578 Typing_shapes.remove_key p env shape_ty field
4580 let env = set_valid_rvalue p env lvar shape_ty in
4581 (env, res)
4582 | _ ->
4583 Errors.invalid_shape_remove_key (fst shape);
4584 (env, res)
4586 | _ -> (env, res))
4587 (* Special function `Shapes::toArray` *)
4588 | Class_const (((_, CI (_, shapes)) as class_id), ((_, to_array) as method_id))
4589 when String.equal shapes SN.Shapes.cShapes
4590 && String.equal to_array SN.Shapes.toArray ->
4591 overload_function
4594 class_id
4595 method_id
4597 unpacked_element
4598 (fun env _ res el ->
4599 match el with
4600 | [shape] ->
4601 let (env, _te, shape_ty) = expr env shape in
4602 Typing_shapes.to_array env p shape_ty res
4603 | _ -> (env, res))
4604 (* Special function `Shapes::toDict` *)
4605 | Class_const (((_, CI (_, shapes)) as class_id), ((_, to_array) as method_id))
4606 when String.equal shapes SN.Shapes.cShapes
4607 && String.equal to_array SN.Shapes.toDict ->
4608 overload_function
4611 class_id
4612 method_id
4614 unpacked_element
4615 (fun env _ res el ->
4616 match el with
4617 | [shape] ->
4618 let (env, _te, shape_ty) = expr env shape in
4619 Typing_shapes.to_dict env p shape_ty res
4620 | _ -> (env, res))
4621 (* Special function `parent::__construct` *)
4622 | Class_const ((pos, CIparent), ((_, construct) as id))
4623 when String.equal construct SN.Members.__construct ->
4624 let (env, tel, typed_unpack_element, ty, pty, ctor_fty) =
4625 call_parent_construct p env el unpacked_element
4627 make_call
4629 (Tast.make_typed_expr
4630 fpos
4631 ctor_fty
4632 (Aast.Class_const (((pos, pty), Aast.CIparent), id)))
4633 [] (* tal: no type arguments to constructor *)
4635 typed_unpack_element
4637 (* Calling parent / class method *)
4638 | Class_const ((pos, e1), m) ->
4639 let (env, _tal, tcid, ty1) =
4640 static_class_id
4641 ~check_constraints:(not (Nast.equal_class_id_ e1 CIparent))
4647 let this_ty =
4648 mk (Reason.Rwitness fpos, TUtils.this_of (Env.get_self env))
4650 (* In static context, you can only call parent::foo() on static methods.
4651 * In instance context, you can call parent:foo() on static
4652 * methods as well as instance methods
4654 let is_static =
4655 (not (Nast.equal_class_id_ e1 CIparent))
4656 || Env.is_static env
4657 || class_contains_smethod env ty1 m
4659 let (env, (fty, tal)) =
4660 if is_static then
4661 class_get
4662 ~coerce_from_ty:None
4663 ~is_method:true
4664 ~is_const:false
4665 ~explicit_targs
4670 else
4671 (* parent::nonStaticFunc() is really weird. It's calling a method
4672 * defined on the parent class, but $this is still the child class.
4673 * We can deal with this by hijacking the continuation that
4674 * calculates the SN.Typehints.this type *)
4675 let k_lhs _ = this_ty in
4676 TOG.obj_get_
4677 ~inst_meth:false
4678 ~is_method:true
4679 ~nullsafe:None
4680 ~obj_pos:pos
4681 ~coerce_from_ty:None
4682 ~is_nonnull:false
4683 ~explicit_targs:[]
4688 k_lhs
4689 Errors.unify_error
4691 check_disposable_in_return env fty;
4692 let ty =
4693 if Nast.equal_class_id_ e1 CIparent then
4694 this_ty
4695 else
4698 let (env, (tel, typed_unpack_element, ty)) =
4699 call
4700 ~expected
4701 ~method_call_info:
4702 (TR.make_call_info
4703 ~receiver_is_self:(Nast.equal_class_id_ e1 CIself)
4704 ~is_static
4706 (snd m))
4711 unpacked_element
4713 make_call
4715 (Tast.make_typed_expr fpos fty (Aast.Class_const (tcid, m)))
4718 typed_unpack_element
4720 (* Call instance method *)
4721 | Obj_get (e1, (pos_id, Id m), nullflavor, false)
4722 when not (TypecheckerOptions.method_call_inference (Env.get_tcopt env)) ->
4723 let (env, te1, ty1) = expr ~accept_using_var:true env e1 in
4724 let nullsafe =
4725 match nullflavor with
4726 | OG_nullthrows -> None
4727 | OG_nullsafe -> Some p
4729 let (env, (tfty, tal)) =
4730 TOG.obj_get
4731 ~obj_pos:(fst e1)
4732 ~is_method:true
4733 ~nullsafe:(Option.map ~f:(fun p -> Reason.Rnullsafe_op p) nullsafe)
4734 ~coerce_from_ty:None
4735 ~explicit_targs
4738 (CIexpr e1)
4740 Errors.unify_error
4742 check_disposable_in_return env tfty;
4743 let (env, (tel, typed_unpack_element, ty)) =
4744 call
4745 ~nullsafe
4746 ~expected
4747 ~method_call_info:
4748 (TR.make_call_info
4749 ~receiver_is_self:false
4750 ~is_static:false
4752 (snd m))
4755 tfty
4757 unpacked_element
4759 make_call
4761 (Tast.make_typed_expr
4762 fpos
4763 tfty
4764 (Aast.Obj_get
4765 ( te1,
4766 Tast.make_typed_expr pos_id tfty (Aast.Id m),
4767 nullflavor,
4768 false )))
4771 typed_unpack_element
4773 (* Call instance method using new method call inference *)
4774 | Obj_get (receiver, (pos_id, Id meth), nullflavor, false) ->
4775 (*****
4776 Typecheck `Obj_get` by enforcing that:
4777 - `<instance_type>` <: `Thas_member(m, #1)`
4778 where #1 is a fresh type variable.
4779 *****)
4780 let (env, typed_receiver, receiver_ty) =
4781 expr ~accept_using_var:true env receiver
4783 let env = might_throw env in
4784 let nullsafe =
4785 match nullflavor with
4786 | OG_nullthrows -> None
4787 | OG_nullsafe -> Some p
4789 (* Generate a fresh type `method_ty` for the type of the
4790 instance method, i.e. #1 *)
4791 let (env, method_ty) = Env.fresh_type env p in
4792 (* Create `Thas_member` constraint type *)
4793 let reason = Reason.Rwitness (fst receiver) in
4794 let has_method_ty =
4795 MakeType.has_member
4796 reason
4797 ~name:meth
4798 ~ty:method_ty
4799 ~class_id:(CIexpr receiver)
4800 ~explicit_targs:(Some explicit_targs)
4802 let env = Env.set_tyvar_variance env method_ty in
4803 let (env, has_method_super_ty) =
4804 if Option.is_none nullsafe then
4805 (env, has_method_ty)
4806 else
4807 (* If null-safe, then `receiver_ty` <: `?Thas_member(m, #1)`,
4808 but *unlike* property access typing in `expr_`, we still use `#1` as
4809 our "result" if `receiver_ty` is nullable (as opposed to `?#1`),
4810 deferring null-safety handling to after `call` *)
4811 let r = Reason.Rnullsafe_op p in
4812 let null_ty = MakeType.null r in
4813 Union.union_i env r has_method_ty null_ty
4815 let env =
4816 Type.sub_type_i
4817 (fst receiver)
4818 Reason.URnone
4820 (LoclType receiver_ty)
4821 has_method_super_ty
4822 Errors.unify_error
4824 (* Perhaps solve for `method_ty`. Opening and closing a scope is too coarse
4825 here - type parameters are localised to fresh type variables over the
4826 course of subtyping above, and we do not want to solve these until later.
4827 Once we typecheck all function calls with a subtyping of function types,
4828 we should not need to solve early at all - transitive closure of
4829 subtyping should give enough information. *)
4830 let env =
4831 match get_var method_ty with
4832 | Some var ->
4833 Typing_solver.solve_to_equal_bound_or_wrt_variance
4835 Reason.Rnone
4837 Errors.unify_error
4838 | None -> env
4840 let localize_targ env (_, targ) = Phase.localize_targ env targ in
4841 let (env, typed_targs) =
4842 List.map_env env ~f:(localize_targ ~check_well_kinded:true) explicit_targs
4844 check_disposable_in_return env method_ty;
4845 let (env, (typed_params, typed_unpack_element, ret_ty)) =
4846 call
4847 ~nullsafe
4848 ~expected
4849 ~method_call_info:
4850 (TR.make_call_info
4851 ~receiver_is_self:false
4852 ~is_static:false
4853 receiver_ty
4854 (snd meth))
4855 ?in_await
4858 method_ty
4860 unpacked_element
4862 (* If the call is nullsafe AND the receiver is nullable,
4863 make the return type nullable too *)
4864 let (env, ret_ty) =
4865 if Option.is_some nullsafe then
4866 let r = Reason.Rnullsafe_op p in
4867 let null_ty = MakeType.null r in
4868 let (env, null_or_nothing_ty) =
4869 Inter.intersect env ~r null_ty receiver_ty
4871 let (env, ret_option_ty) = Union.union env null_or_nothing_ty ret_ty in
4872 (env, ret_option_ty)
4873 else
4874 (env, ret_ty)
4876 make_call
4878 (Tast.make_typed_expr
4879 fpos
4880 method_ty
4881 (Aast.Obj_get
4882 ( typed_receiver,
4883 Tast.make_typed_expr pos_id method_ty (Aast.Id meth),
4884 nullflavor,
4885 false )))
4886 typed_targs
4887 typed_params
4888 typed_unpack_element
4889 ret_ty
4890 (* Function invocation *)
4891 | Fun_id x ->
4892 let (env, fty, tal) = fun_type_of_id env x explicit_targs el in
4893 check_disposable_in_return env fty;
4894 let (env, (tel, typed_unpack_element, ty)) =
4895 call ~expected p env fty el unpacked_element
4897 make_call
4899 (Tast.make_typed_expr fpos fty (Aast.Fun_id x))
4902 typed_unpack_element
4904 | Id ((_, id) as x) ->
4905 let (env, fty, tal) = fun_type_of_id env x explicit_targs el in
4906 check_disposable_in_return env fty;
4907 let (env, (tel, typed_unpack_element, ty)) =
4908 call ~expected p env fty el unpacked_element
4910 let is_mutable = String.equal id SN.Rx.mutable_ in
4911 let is_move = String.equal id SN.Rx.move in
4912 let is_freeze = String.equal id SN.Rx.freeze in
4913 (* error when rx builtins are used in non-reactive context *)
4914 if not (Env.env_local_reactive env) then
4915 if is_mutable then
4916 Errors.mutable_in_nonreactive_context p
4917 else if is_move then
4918 Errors.move_in_nonreactive_context p
4919 else if is_freeze then
4920 Errors.freeze_in_nonreactive_context p;
4922 (* ban unpacking when calling builtings *)
4923 if (is_mutable || is_move || is_freeze) && Option.is_some unpacked_element
4924 then
4925 Errors.unpacking_disallowed_builtin_function p id;
4927 (* adjust env for Rx\freeze or Rx\move calls *)
4928 let env =
4929 if is_freeze then
4930 Typing_mutability.freeze_local p env tel
4931 else if is_move then
4932 Typing_mutability.move_local p env tel
4933 else
4936 make_call
4938 (Tast.make_typed_expr fpos fty (Aast.Id x))
4941 typed_unpack_element
4943 | _ ->
4944 let (env, te, fty) = expr env e in
4945 let (env, fty) =
4946 Typing_solver.expand_type_and_solve
4947 ~description_of_expected:"a function value"
4949 fpos
4951 Errors.unify_error
4953 check_disposable_in_return env fty;
4954 let (env, (tel, typed_unpack_element, ty)) =
4955 call ~expected p env fty el unpacked_element
4957 make_call
4960 (* tal: no type arguments to function values, as they are non-generic *)
4963 typed_unpack_element
4966 and fun_type_of_id env x tal el =
4967 match Env.get_fun env (snd x) with
4968 | None ->
4969 let (env, _, ty) = unbound_name env x (Pos.none, Aast.Null) in
4970 (env, ty, [])
4971 | Some { fe_type; fe_pos; fe_deprecated; _ } ->
4972 (match get_node fe_type with
4973 | Tfun ft ->
4974 let ft =
4975 Typing_special_fun.transform_special_fun_ty ft x (List.length el)
4977 let ety_env = Phase.env_with_self env in
4978 let (env, tal) =
4979 Phase.localize_targs
4980 ~check_well_kinded:true
4981 ~is_method:true
4982 ~def_pos:fe_pos
4983 ~use_pos:(fst x)
4984 ~use_name:(strip_ns (snd x))
4986 ft.ft_tparams
4987 (List.map ~f:snd tal)
4989 let ft =
4990 Typing_enforceability.compute_enforced_and_pessimize_fun_type env ft
4992 let use_pos = fst x in
4993 let def_pos = fe_pos in
4994 let (env, ft) =
4995 Phase.(
4996 localize_ft
4997 ~instantiation:
4998 { use_name = strip_ns (snd x); use_pos; explicit_targs = tal }
4999 ~def_pos
5000 ~ety_env
5004 let fty = mk (get_reason fe_type, Tfun ft) in
5005 TVis.check_deprecated ~use_pos ~def_pos fe_deprecated;
5006 (env, fty, tal)
5007 | _ -> failwith "Expected function type")
5010 * Checks if a class (given by cty) contains a given static method.
5012 * We could refactor this + class_get
5014 and class_contains_smethod env cty (_pos, mid) =
5015 let lookup_member ty =
5016 match get_class_type ty with
5017 | Some ((_, c), _, _) ->
5018 (match Env.get_class env c with
5019 | None -> false
5020 | Some class_ ->
5021 Option.is_some @@ Env.get_static_member true env class_ mid)
5022 | None -> false
5024 let (_env, tyl) = TUtils.get_concrete_supertypes env cty in
5025 List.exists tyl ~f:lookup_member
5027 and class_get
5028 ~is_method
5029 ~is_const
5030 ~coerce_from_ty
5031 ?(explicit_targs = [])
5032 ?(incl_tc = false)
5033 ?(function_pointer = false)
5036 (p, mid)
5037 cid =
5038 let (env, this_ty) =
5039 if is_method then
5040 this_for_method env cid cty
5041 else
5042 (env, cty)
5044 class_get_
5045 ~is_method
5046 ~is_const
5047 ~this_ty
5048 ~explicit_targs
5049 ~incl_tc
5050 ~coerce_from_ty
5051 ~function_pointer
5055 (p, mid)
5057 and class_get_
5058 ~is_method
5059 ~is_const
5060 ~this_ty
5061 ~coerce_from_ty
5062 ?(explicit_targs = [])
5063 ?(incl_tc = false)
5064 ?(function_pointer = false)
5068 (p, mid) =
5069 let (env, cty) = Env.expand_type env cty in
5070 match deref cty with
5071 | (r, Tany _) -> (env, (mk (r, Typing_utils.tany env), []))
5072 | (r, Terr) -> (env, (err_witness env (Reason.to_pos r), []))
5073 | (_, Tdynamic) -> (env, (cty, []))
5074 | (_, Tunion tyl) ->
5075 let (env, pairs) =
5076 List.map_env env tyl (fun env ty ->
5077 class_get
5078 ~is_method
5079 ~is_const
5080 ~explicit_targs
5081 ~incl_tc
5082 ~coerce_from_ty
5085 (p, mid)
5086 cid)
5088 let (env, ty) =
5089 Union.union_list env (get_reason cty) (List.map ~f:fst pairs)
5091 (env, (ty, []))
5092 | (_, Tintersection tyl) ->
5093 let (env, pairs) =
5094 TUtils.run_on_intersection env tyl ~f:(fun env ty ->
5095 class_get
5096 ~is_method
5097 ~is_const
5098 ~explicit_targs
5099 ~incl_tc
5100 ~coerce_from_ty
5103 (p, mid)
5104 cid)
5106 let (env, ty) =
5107 Inter.intersect_list env (get_reason cty) (List.map ~f:fst pairs)
5109 (env, (ty, []))
5110 | (_, Tnewtype (_, _, ty))
5111 | (_, Tdependent (_, ty)) ->
5112 class_get_
5113 ~is_method
5114 ~is_const
5115 ~this_ty
5116 ~explicit_targs
5117 ~incl_tc
5118 ~coerce_from_ty
5122 (p, mid)
5123 | (r, Tgeneric _) ->
5124 let (env, tyl) = TUtils.get_concrete_supertypes env cty in
5125 if List.is_empty tyl then begin
5126 Errors.non_class_member
5127 ~is_method
5130 (Typing_print.error env cty)
5131 (get_pos cty);
5132 (env, (err_witness env p, []))
5133 end else
5134 let (env, ty) = Typing_intersection.intersect_list env r tyl in
5135 class_get_
5136 ~is_method
5137 ~is_const
5138 ~this_ty
5139 ~explicit_targs
5140 ~incl_tc
5141 ~coerce_from_ty
5145 (p, mid)
5146 | (_, Tclass ((_, c), _, paraml)) ->
5147 let class_ = Env.get_class env c in
5148 (match class_ with
5149 | None -> (env, (Typing_utils.mk_tany env p, []))
5150 | Some class_ ->
5151 (* We need to instantiate generic parameters in the method signature *)
5152 let ety_env =
5154 type_expansions = [];
5155 this_ty;
5156 substs = TUtils.make_locl_subst_for_class_tparams class_ paraml;
5157 from_class = Some cid;
5158 quiet = true;
5159 on_error = Errors.unify_error_at p;
5162 let get_smember_from_constraints env class_info =
5163 let upper_bounds =
5164 Cls.upper_bounds_on_this_from_constraints class_info
5166 let (env, upper_bounds) =
5167 List.map_env env upper_bounds ~f:(fun env up ->
5168 Phase.localize ~ety_env env up)
5170 let (env, inter_ty) =
5171 Inter.intersect_list env (Reason.Rwitness p) upper_bounds
5173 class_get_
5174 ~is_method
5175 ~is_const
5176 ~this_ty
5177 ~explicit_targs
5178 ~incl_tc
5179 ~coerce_from_ty
5182 inter_ty
5183 (p, mid)
5185 let try_get_smember_from_constraints env class_info =
5186 Errors.try_with_error
5187 (fun () -> get_smember_from_constraints env class_info)
5188 (fun () ->
5189 TOG.smember_not_found
5191 ~is_const
5192 ~is_method
5193 class_info
5195 Errors.unify_error;
5196 (env, (TUtils.terr env Reason.Rnone, [])))
5198 if is_const then (
5199 let const =
5200 if incl_tc then
5201 Env.get_const env class_ mid
5202 else
5203 match Env.get_typeconst env class_ mid with
5204 | Some _ ->
5205 Errors.illegal_typeconst_direct_access p;
5206 None
5207 | None -> Env.get_const env class_ mid
5209 match const with
5210 | None when Cls.has_upper_bounds_on_this_from_constraints class_ ->
5211 try_get_smember_from_constraints env class_
5212 | None ->
5213 TOG.smember_not_found
5215 ~is_const
5216 ~is_method
5217 class_
5219 Errors.unify_error;
5220 (env, (TUtils.terr env Reason.Rnone, []))
5221 | Some { cc_type; cc_abstract; cc_pos; _ } ->
5222 let (env, cc_locl_type) = Phase.localize ~ety_env env cc_type in
5223 ( if cc_abstract then
5224 match cid with
5225 | CIstatic
5226 | CIexpr _ ->
5228 | _ ->
5229 let cc_name = Cls.name class_ ^ "::" ^ mid in
5230 Errors.abstract_const_usage p cc_pos cc_name );
5231 (env, (cc_locl_type, []))
5232 ) else
5233 let static_member_opt =
5234 Env.get_static_member is_method env class_ mid
5236 (match static_member_opt with
5237 | None when Cls.has_upper_bounds_on_this_from_constraints class_ ->
5238 try_get_smember_from_constraints env class_
5239 | None ->
5240 TOG.smember_not_found
5242 ~is_const
5243 ~is_method
5244 class_
5246 Errors.unify_error;
5247 (env, (TUtils.terr env Reason.Rnone, []))
5248 | Some
5250 ce_visibility = vis;
5251 ce_type = (lazy member_decl_ty);
5252 ce_deprecated;
5254 } as ce ) ->
5255 let def_pos = get_pos member_decl_ty in
5256 TVis.check_class_access
5257 ~use_pos:p
5258 ~def_pos
5260 (vis, get_ce_lsb ce)
5262 class_;
5263 TVis.check_deprecated ~use_pos:p ~def_pos ce_deprecated;
5264 check_class_get env p def_pos c mid ce cid function_pointer;
5265 let (env, member_ty, et_enforced, tal) =
5266 match deref member_decl_ty with
5267 (* We special case Tfun here to allow passing in explicit tparams to localize_ft. *)
5268 | (r, Tfun ft) when is_method ->
5269 let (env, explicit_targs) =
5270 Phase.localize_targs
5271 ~check_well_kinded:true
5272 ~is_method:true
5273 ~def_pos
5274 ~use_pos:p
5275 ~use_name:(strip_ns mid)
5277 ft.ft_tparams
5278 (List.map ~f:snd explicit_targs)
5280 let ft =
5281 Typing_enforceability.compute_enforced_and_pessimize_fun_type
5285 let (env, ft) =
5286 Phase.(
5287 localize_ft
5288 ~instantiation:
5289 { use_name = strip_ns mid; use_pos = p; explicit_targs }
5290 ~ety_env
5291 ~def_pos
5295 (env, mk (r, Tfun ft), false, explicit_targs)
5296 (* unused *)
5297 | _ ->
5298 let { et_type; et_enforced } =
5299 Typing_enforceability.compute_enforced_and_pessimize_ty
5301 member_decl_ty
5303 let (env, member_ty) = Phase.localize ~ety_env env et_type in
5304 (* TODO(T52753871) make function just return possibly_enforced_ty
5305 * after considering intersection case *)
5306 (env, member_ty, et_enforced, [])
5308 let (env, member_ty) =
5309 if Cls.has_upper_bounds_on_this_from_constraints class_ then
5310 let ((env, (member_ty', _)), succeed) =
5311 Errors.try_with_error
5312 (fun () -> (get_smember_from_constraints env class_, true))
5313 (fun () ->
5314 (* No eligible functions found in constraints *)
5315 ((env, (MakeType.mixed Reason.Rnone, [])), false))
5317 if succeed then
5318 Inter.intersect env (Reason.Rwitness p) member_ty member_ty'
5319 else
5320 (env, member_ty)
5321 else
5322 (env, member_ty)
5324 let env =
5325 match coerce_from_ty with
5326 | None -> env
5327 | Some (p, ur, ty) ->
5328 Typing_coercion.coerce_type
5333 { et_type = member_ty; et_enforced }
5334 Errors.unify_error
5336 (env, (member_ty, tal))))
5337 | (_, Tunapplied_alias _) ->
5338 Typing_defs.error_Tunapplied_alias_in_illegal_context ()
5339 | ( _,
5340 ( Tvar _ | Tnonnull | Tvarray _ | Tdarray _ | Tvarray_or_darray _
5341 | Toption _ | Tprim _ | Tfun _ | Ttuple _ | Tobject | Tshape _ | Taccess _
5342 ) ) ->
5343 Errors.non_class_member
5344 ~is_method
5347 (Typing_print.error env cty)
5348 (get_pos cty);
5349 (env, (err_witness env p, []))
5351 and class_id_for_new
5352 ~exact p env (cid : Nast.class_id_) (explicit_targs : Nast.targ list) :
5353 newable_class_info =
5354 let (env, tal, te, cid_ty) =
5355 static_class_id
5356 ~check_targs_well_kinded:true
5357 ~check_explicit_targs:true
5358 ~exact
5359 ~check_constraints:false
5362 explicit_targs
5365 (* Need to deal with union case *)
5366 let rec get_info res tyl =
5367 match tyl with
5368 | [] -> (env, tal, te, res)
5369 | ty :: tyl ->
5370 (match get_node ty with
5371 | Tunion tyl'
5372 | Tintersection tyl' ->
5373 get_info res (tyl' @ tyl)
5374 | _ ->
5375 (* Instantiation on an abstract class (e.g. from classname<T>) is
5376 * via the base type (to check constructor args), but the actual
5377 * type `ty` must be preserved. *)
5378 (match get_node (TUtils.get_base_type env ty) with
5379 | Tdynamic -> get_info (`Dynamic :: res) tyl
5380 | Tclass (sid, _, _) ->
5381 let class_ = Env.get_class env (snd sid) in
5382 (match class_ with
5383 | None -> get_info res tyl
5384 | Some class_info ->
5385 (match (te, cid_ty) with
5386 (* When computing the classes for a new T() where T is a generic,
5387 * the class must be consistent (final, final constructor, or
5388 * <<__ConsistentConstruct>>) for its constructor to be considered *)
5389 | ((_, Aast.CI (_, c)), ty) when is_generic_equal_to c ty ->
5390 (* Only have this choosing behavior for new T(), not all generic types
5391 * i.e. new classname<T>, TODO: T41190512 *)
5392 if Tast_utils.valid_newable_class class_info then
5393 get_info (`Class (sid, class_info, ty) :: res) tyl
5394 else
5395 get_info res tyl
5396 | _ -> get_info (`Class (sid, class_info, ty) :: res) tyl))
5397 | _ -> get_info res tyl))
5399 get_info [] [cid_ty]
5401 (* To be a valid trait declaration, all of its 'require extends' must
5402 * match; since there's no multiple inheritance, it follows that all of
5403 * the 'require extends' must belong to the same inheritance hierarchy
5404 * and one of them should be the child of all the others *)
5405 and trait_most_concrete_req_class trait env =
5406 List.fold
5407 (Cls.all_ancestor_reqs trait)
5409 begin
5410 fun acc (_p, ty) ->
5411 let (_r, (_p, name), _paraml) = TUtils.unwrap_class_type ty in
5412 let keep =
5413 match acc with
5414 | Some (c, _ty) -> Cls.has_ancestor c name
5415 | None -> false
5417 if keep then
5419 else
5420 let class_ = Env.get_class env name in
5421 match class_ with
5422 | None -> acc
5423 | Some c when Ast_defs.(equal_class_kind (Cls.kind c) Cinterface) ->
5425 | Some c when Ast_defs.(equal_class_kind (Cls.kind c) Ctrait) ->
5426 (* this is an error case for which Typing_check_decls spits out
5427 * an error, but does *not* currently remove the offending
5428 * 'require extends' or 'require implements' *)
5430 | Some c -> Some (c, ty)
5432 ~init:None
5434 (* When invoking a method the class_id is used to determine what class we
5435 * lookup the method in, but the type of 'this' will be the late bound type.
5436 * For example:
5438 * class C {
5439 * public static function get(): this { return new static(); }
5441 * public static function alias(): this { return self::get(); }
5444 * In C::alias, when we invoke self::get(), 'self' is resolved to the class
5445 * in the lexical scope (C), so call C::get. However the method is executed in
5446 * the current context, so static inside C::get will be resolved to the late
5447 * bound type (get_called_class() within C::alias).
5449 * This means when determining the type of this, CIparent and CIself should be
5450 * changed to CIstatic. For the other cases of C::get() or $c::get(), we only
5451 * look at the left hand side of the '::' and use the type type associated
5452 * with it.
5454 * Thus C::get() will return a type C, while $c::get() will return the same
5455 * type as $c.
5457 and this_for_method env cid default_ty =
5458 match cid with
5459 | CIparent
5460 | CIself
5461 | CIstatic ->
5462 let p = get_pos default_ty in
5463 let (env, _tal, _te, ty) =
5464 static_class_id ~check_constraints:false p env [] CIstatic
5466 ExprDepTy.make env CIstatic ty
5467 | _ -> (env, default_ty)
5469 (** Resolve class expressions like `parent`, `self`, `static`, classnames
5470 and others. *)
5471 and static_class_id
5472 ?(check_targs_well_kinded = false)
5473 ?(exact = Nonexact)
5474 ?(check_explicit_targs = false)
5475 ~(check_constraints : bool)
5476 (p : pos)
5477 (env : env)
5478 (tal : Nast.targ list) :
5479 Nast.class_id_ -> env * Tast.targ list * Tast.class_id * locl_ty =
5480 let make_result env tal te ty = (env, tal, ((p, ty), te), ty) in
5481 function
5482 | CIparent ->
5483 (match get_class_type (Env.get_self env) with
5484 | Some ((_, self), _, _) ->
5485 (match Env.get_class env self with
5486 | Some trait when Ast_defs.(equal_class_kind (Cls.kind trait) Ctrait) ->
5487 (match trait_most_concrete_req_class trait env with
5488 | None ->
5489 Errors.parent_in_trait p;
5490 make_result env [] Aast.CIparent (err_witness env p)
5491 | Some (_, parent_ty) ->
5492 (* inside a trait, parent is SN.Typehints.this, but with the
5493 * type of the most concrete class that the trait has
5494 * "require extend"-ed *)
5495 let r = Reason.Rwitness p in
5496 let (env, parent_ty) = Phase.localize_with_self env parent_ty in
5497 make_result env [] Aast.CIparent (mk (r, TUtils.this_of parent_ty)))
5498 | _ ->
5499 let parent =
5500 match Env.get_parent_ty env with
5501 | None ->
5502 Errors.parent_undefined p;
5503 mk (Reason.none, Typing_defs.make_tany ())
5504 | Some parent -> parent
5506 let r = Reason.Rwitness p in
5507 let (env, parent) = Phase.localize_with_self env parent in
5508 (* parent is still technically the same object. *)
5509 make_result
5512 Aast.CIparent
5513 (mk (r, TUtils.this_of (mk (r, get_node parent)))))
5514 | None ->
5515 let parent =
5516 match Env.get_parent_ty env with
5517 | None ->
5518 Errors.parent_undefined p;
5519 mk (Reason.none, Typing_defs.make_tany ())
5520 | Some parent -> parent
5522 let r = Reason.Rwitness p in
5523 let (env, parent) = Phase.localize_with_self env parent in
5524 (* parent is still technically the same object. *)
5525 make_result
5528 Aast.CIparent
5529 (mk (r, TUtils.this_of (mk (r, get_node parent)))))
5530 | CIstatic ->
5531 let this = mk (Reason.Rwitness p, TUtils.this_of (Env.get_self env)) in
5532 make_result env [] Aast.CIstatic this
5533 | CIself ->
5534 let self =
5535 match get_node (Env.get_self env) with
5536 | Tclass (c, _, tyl) -> Tclass (c, exact, tyl)
5537 | self -> self
5539 make_result env [] Aast.CIself (mk (Reason.Rwitness p, self))
5540 | CI ((p, id) as c) as e1 ->
5541 begin
5542 match Env.get_pos_and_kind_of_generic env id with
5543 | Some (def_pos, kind) ->
5544 let simple_kind = Typing_kinding_defs.Simple.from_full_kind kind in
5545 let param_nkinds =
5546 Typing_kinding_defs.Simple.get_named_parameter_kinds simple_kind
5548 let (env, tal) =
5549 Phase.localize_targs_with_kinds
5550 ~check_well_kinded:check_targs_well_kinded
5551 ~is_method:true
5552 ~def_pos
5553 ~use_pos:p
5554 ~use_name:(strip_ns (snd c))
5555 ~check_explicit_targs
5557 param_nkinds
5558 (List.map ~f:snd tal)
5560 let r = Reason.Rhint p in
5561 let type_args = List.map tal fst in
5562 let tgeneric = MakeType.generic ~type_args r id in
5563 make_result env tal (Aast.CI c) tgeneric
5564 | None ->
5565 (* Not a type parameter *)
5566 let class_ = Env.get_class env id in
5567 (match class_ with
5568 | None -> make_result env [] (Aast.CI c) (Typing_utils.mk_tany env p)
5569 | Some class_ ->
5570 let (env, ty, tal) =
5571 List.map ~f:snd tal
5572 |> Phase.localize_targs_and_check_constraints
5573 ~exact
5574 ~check_well_kinded:check_targs_well_kinded
5575 ~check_constraints
5576 ~def_pos:(Cls.pos class_)
5577 ~use_pos:p
5578 ~check_explicit_targs
5582 (Cls.tparams class_)
5584 make_result env tal (Aast.CI c) ty)
5586 | CIexpr ((p, _) as e) ->
5587 let (env, te, ty) = expr env e in
5588 let rec resolve_ety env ty =
5589 let (env, ty) =
5590 Typing_solver.expand_type_and_solve
5591 ~description_of_expected:"an object"
5595 Errors.unify_error
5597 let base_ty = TUtils.get_base_type env ty in
5598 match deref base_ty with
5599 | (_, Tnewtype (classname, [the_cls], _))
5600 when String.equal classname SN.Classes.cClassname ->
5601 resolve_ety env the_cls
5602 | (_, Tgeneric _)
5603 | (_, Tclass _) ->
5604 (env, ty)
5605 | (r, Tunion tyl) ->
5606 let (env, tyl) = List.map_env env tyl resolve_ety in
5607 (env, MakeType.union r tyl)
5608 | (r, Tintersection tyl) ->
5609 let (env, tyl) = TUtils.run_on_intersection env tyl ~f:resolve_ety in
5610 Inter.intersect_list env r tyl
5611 | (_, Tdynamic) -> (env, base_ty)
5612 | (_, (Tany _ | Tprim Tstring | Tobject)) when not (Env.is_strict env) ->
5613 (env, Typing_utils.mk_tany env p)
5614 | (_, Terr) -> (env, err_witness env p)
5615 | (r, Tvar _) ->
5616 Errors.unknown_type "an object" p (Reason.to_string "It is unknown" r);
5617 (env, err_witness env p)
5618 | (_, Tunapplied_alias _) ->
5619 Typing_defs.error_Tunapplied_alias_in_illegal_context ()
5620 | ( _,
5621 ( Tany _ | Tnonnull | Tvarray _ | Tdarray _ | Tvarray_or_darray _
5622 | Toption _ | Tprim _ | Tfun _ | Ttuple _ | Tnewtype _ | Tdependent _
5623 | Tobject | Tshape _ | Taccess _ ) ) ->
5624 Errors.expected_class
5625 ~suffix:(", but got " ^ Typing_print.error env base_ty)
5627 (env, err_witness env p)
5629 let (env, result_ty) = resolve_ety env ty in
5630 make_result env [] (Aast.CIexpr te) result_ty
5632 and call_construct p env class_ params el unpacked_element cid cid_ty =
5633 let (cid, cid_ty) =
5634 if Nast.equal_class_id_ cid CIparent then
5635 (CIstatic, mk (Reason.Rwitness p, TUtils.this_of (Env.get_self env)))
5636 else
5637 (cid, cid_ty)
5639 let ety_env =
5641 type_expansions = [];
5642 this_ty = cid_ty;
5643 substs = TUtils.make_locl_subst_for_class_tparams class_ params;
5644 from_class = Some cid;
5645 quiet = true;
5646 on_error = Errors.unify_error_at p;
5649 let env =
5650 Phase.check_tparams_constraints ~use_pos:p ~ety_env env (Cls.tparams class_)
5652 let env =
5653 Phase.check_where_constraints
5654 ~in_class:true
5655 ~use_pos:p
5656 ~definition_pos:(Cls.pos class_)
5657 ~ety_env
5659 (Cls.where_constraints class_)
5661 if Cls.is_xhp class_ then
5662 (env, [], None, TUtils.mk_tany env p)
5663 else
5664 let cstr = Env.get_construct env class_ in
5665 let mode = Env.get_mode env in
5666 match fst cstr with
5667 | None ->
5669 ((not (List.is_empty el)) || Option.is_some unpacked_element)
5670 && (FileInfo.is_strict mode || FileInfo.(equal_mode mode Mpartial))
5671 && Cls.members_fully_known class_
5672 then
5673 Errors.constructor_no_args p;
5674 let (env, tel, _tyl) = exprs env el in
5675 (env, tel, None, TUtils.terr env Reason.Rnone)
5676 | Some { ce_visibility = vis; ce_type = (lazy m); ce_deprecated; _ } ->
5677 let def_pos = get_pos m in
5678 TVis.check_obj_access ~use_pos:p ~def_pos env vis;
5679 TVis.check_deprecated ~use_pos:p ~def_pos ce_deprecated;
5680 (* Obtain the type of the constructor *)
5681 let (env, m) =
5682 match deref m with
5683 | (r, Tfun ft) ->
5684 let ft =
5685 Typing_enforceability.compute_enforced_and_pessimize_fun_type env ft
5687 let (env, ft) =
5688 Phase.(
5689 localize_ft
5690 ~instantiation:
5691 { use_name = "constructor"; use_pos = p; explicit_targs = [] }
5692 ~ety_env
5693 ~def_pos
5697 (env, mk (r, Tfun ft))
5698 | (r, _) ->
5699 Errors.internal_error p "Expected function type for constructor";
5700 let ty = TUtils.terr env r in
5701 (env, ty)
5703 let (env, (tel, typed_unpack_element, _ty)) =
5704 call ~expected:None p env m el unpacked_element
5706 (env, tel, typed_unpack_element, m)
5708 and check_arity ?(did_unpack = false) pos pos_def ft (arity : int) =
5709 let exp_min = Typing_defs.arity_min ft in
5710 if arity < exp_min then
5711 Errors.typing_too_few_args exp_min arity pos pos_def None;
5712 match ft.ft_arity with
5713 | Fstandard ->
5714 let exp_max = List.length ft.ft_params in
5715 let arity =
5716 if did_unpack then
5717 arity + 1
5718 else
5719 arity
5721 if arity > exp_max then
5722 Errors.typing_too_many_args exp_max arity pos pos_def None
5723 | Fvariadic _ -> ()
5725 and check_lambda_arity lambda_pos def_pos lambda_ft expected_ft =
5726 match (lambda_ft.ft_arity, expected_ft.ft_arity) with
5727 | (Fstandard, Fstandard) ->
5728 let expected_min = Typing_defs.arity_min expected_ft in
5729 let lambda_min = Typing_defs.arity_min lambda_ft in
5730 if lambda_min < expected_min then
5731 Errors.typing_too_few_args expected_min lambda_min lambda_pos def_pos None;
5732 if lambda_min > expected_min then
5733 Errors.typing_too_many_args
5734 expected_min
5735 lambda_min
5736 lambda_pos
5737 def_pos
5738 None
5739 | (_, _) -> ()
5741 (* The variadic capture argument is an array listing the passed
5742 * variable arguments for the purposes of the function body; callsites
5743 * should not unify with it *)
5744 and variadic_param env ft =
5745 match ft.ft_arity with
5746 | Fvariadic param -> (env, Some param)
5747 | Fstandard -> (env, None)
5749 and param_modes ?(is_variadic = false) ({ fp_pos; _ } as fp) (pos, e) =
5750 match (get_fp_mode fp, e) with
5751 | (FPnormal, Callconv _) ->
5752 Errors.inout_annotation_unexpected pos fp_pos is_variadic
5753 | (FPnormal, _) -> ()
5754 | (FPinout, Callconv (Ast_defs.Pinout, _)) -> ()
5755 | (FPinout, _) -> Errors.inout_annotation_missing pos fp_pos
5757 and inout_write_back env { fp_type; _ } (_, e) =
5758 match e with
5759 | Callconv (Ast_defs.Pinout, e1) ->
5760 (* Translate the write-back semantics of inout parameters.
5762 * This matters because we want to:
5763 * (1) make sure we can write to the original argument
5764 * (modifiable lvalue check)
5765 * (2) allow for growing of locals / Tunions (type side effect)
5766 * but otherwise unify the argument type with the parameter hint
5768 let (env, _te, _ty) =
5769 assign_ (fst e1) Reason.URparam_inout env e1 fp_type.et_type
5772 | _ -> env
5774 (** Typechecks a call.
5775 Returns in this order the typed expressions for the arguments, for the variadic arguments, and the return type. *)
5776 and call
5777 ~(expected : ExpectedTy.t option)
5778 ?(method_call_info : TR.method_call_info option)
5779 ?(nullsafe : Pos.t option = None)
5780 ?in_await
5784 (el : Nast.expr list)
5785 (unpacked_element : Nast.expr option) :
5786 env * (Tast.expr list * Tast.expr option * locl_ty) =
5787 let resl =
5788 TUtils.try_over_concrete_supertypes env fty (fun env fty ->
5789 let (env, efty) =
5790 if TypecheckerOptions.method_call_inference (Env.get_tcopt env) then
5791 Env.expand_type env fty
5792 else
5793 Typing_solver.expand_type_and_solve
5794 ~description_of_expected:"a function value"
5798 Errors.unify_error
5800 match deref efty with
5801 | (r, ((Tprim Tnull | Tdynamic | Terr | Tany _ | Tunion []) as ty))
5802 when match ty with
5803 | Tprim Tnull -> Option.is_some nullsafe
5804 | _ -> true ->
5805 let el =
5806 Option.value_map ~f:(fun u -> el @ [u]) ~default:el unpacked_element
5808 let expected_arg_ty =
5809 (* Note: We ought to be using 'mixed' here *)
5810 ExpectedTy.make pos Reason.URparam (Typing_utils.mk_tany env pos)
5812 let (env, tel) =
5813 List.map_env env el (fun env elt ->
5814 let (env, te, ty) = expr ~expected:expected_arg_ty env elt in
5815 let env =
5816 if TCO.global_inference (Env.get_tcopt env) then
5817 match get_node efty with
5818 | Terr
5819 | Tany _
5820 | Tdynamic ->
5821 Typing_coercion.coerce_type
5823 Reason.URparam
5826 (MakeType.unenforced efty)
5827 Errors.unify_error
5828 | _ -> env
5829 else
5832 let env =
5833 match elt with
5834 | (_, Callconv (Ast_defs.Pinout, e1)) ->
5835 let (env, _te, _ty) =
5836 assign_ (fst e1) Reason.URparam_inout env e1 efty
5839 | _ -> env
5841 (env, te))
5843 let env =
5844 call_untyped_unpack env (Reason.to_pos r) unpacked_element
5846 let ty =
5847 match ty with
5848 | Tprim Tnull -> mk (r, Tprim Tnull)
5849 | Tdynamic -> MakeType.dynamic (Reason.Rdynamic_call pos)
5850 | Terr
5851 | Tany _ ->
5852 Typing_utils.mk_tany env pos
5853 | Tunion []
5854 | _ (* _ should not happen! *) ->
5855 mk (r, Tunion [])
5857 (env, (tel, None, ty))
5858 | (_, Tunion [ty]) ->
5859 call ~expected ~nullsafe ?in_await pos env ty el unpacked_element
5860 | (r, Tunion tyl) ->
5861 let (env, resl) =
5862 List.map_env env tyl (fun env ty ->
5863 call
5864 ~expected
5865 ~nullsafe
5866 ?in_await
5871 unpacked_element)
5873 let retl = List.map resl ~f:(fun (_, _, x) -> x) in
5874 let (env, ty) = Union.union_list env r retl in
5875 (* We shouldn't be picking arbitrarily for the TAST here, as TAST checks
5876 * depend on the types inferred. Here's we're preserving legacy behaviour
5877 * by picking the last one.
5878 * TODO: don't do this, instead use subtyping to push unions
5879 * through function types
5881 let (tel, typed_unpack_element, _) = List.hd_exn (List.rev resl) in
5882 (env, (tel, typed_unpack_element, ty))
5883 | (r, Tintersection tyl) ->
5884 let (env, resl) =
5885 TUtils.run_on_intersection env tyl ~f:(fun env ty ->
5886 call
5887 ~expected
5888 ~nullsafe
5889 ?in_await
5894 unpacked_element)
5896 let retl = List.map resl ~f:(fun (_, _, x) -> x) in
5897 let (env, ty) = Inter.intersect_list env r retl in
5898 (* We shouldn't be picking arbitrarily for the TAST here, as TAST checks
5899 * depend on the types inferred. Here we're preserving legacy behaviour
5900 * by picking the last one.
5901 * TODO: don't do this, instead use subtyping to push intersections
5902 * through function types
5904 let (tel, typed_unpack_element, _) = List.hd_exn (List.rev resl) in
5905 (env, (tel, typed_unpack_element, ty))
5906 | (r2, Tfun ft) ->
5907 (* Typing of format string functions. It is dependent on the arguments (el)
5908 * so it cannot be done earlier.
5910 let pos_def = Reason.to_pos r2 in
5911 let (env, ft) = Typing_exts.retype_magic_func env ft el in
5912 let (env, var_param) = variadic_param env ft in
5913 (* Force subtype with expected result *)
5914 let env =
5915 check_expected_ty "Call result" env ft.ft_ret.et_type expected
5917 let env = Env.set_tyvar_variance env ft.ft_ret.et_type in
5918 let is_lambda e =
5919 match snd e with
5920 | Efun _
5921 | Lfun _ ->
5922 true
5923 | _ -> false
5925 let get_next_param_info paraml =
5926 match paraml with
5927 | param :: paraml -> (false, Some param, paraml)
5928 | [] -> (true, var_param, paraml)
5930 (* TODO: We're using plain String at the moment, until we
5931 * introduce actual atom notation (#A instead of "A")
5933 let expand_atom_in_enum env enum_name atom_name =
5934 let cls = Env.get_class env enum_name in
5935 match cls with
5936 | Some cls ->
5937 (match Env.get_const env cls atom_name with
5938 | Some const_def ->
5939 let dty = const_def.cc_type in
5940 let (env, lty) = Phase.localize_with_self env dty in
5941 let hi = (pos, lty) in
5942 let te = (hi, EnumAtom atom_name) in
5943 (env, Some (te, lty))
5944 | None ->
5945 Errors.atom_unknown pos atom_name enum_name;
5946 (env, None))
5947 | None -> (env, None)
5949 let check_arg env ((pos, arg) as e) opt_param ~is_variadic =
5950 match opt_param with
5951 | Some param ->
5952 (* First check if __Atom is used *)
5953 let (env, atom_type) =
5954 let is_atom = get_fp_is_atom param in
5955 let ety = param.fp_type.et_type in
5956 match arg with
5957 | EnumAtom atom_name when is_atom ->
5958 (match get_node ety with
5959 | Tclass ((_, name), _, [ty_enum; _ty_interface])
5960 when String.equal name SN.Classes.cEnumMember ->
5961 (match get_node ty_enum with
5962 | Tclass ((_, enum_name), _, _)
5963 when Env.is_enum_class env enum_name ->
5964 expand_atom_in_enum env enum_name atom_name
5965 | Tgeneric (name, _) ->
5966 let upper_bounds =
5967 Typing_utils.collect_enum_class_upper_bounds env name
5969 (* To avoid ambiguity, we only support the case where
5970 * there is a single upper bound that is an EnumClass.
5971 * We might want to relax that later (e.g. with the
5972 * support for intersections.
5973 * See Typing_check_decls.check_atom_on_param.
5975 if SSet.cardinal upper_bounds = 1 then
5976 let enum_name = SSet.choose upper_bounds in
5977 expand_atom_in_enum env enum_name atom_name
5978 else
5979 (env, None)
5980 | _ ->
5981 (* Already reported, see Typing_check_decls *)
5982 (env, None))
5983 | _ ->
5984 (* Already reported, see Typing_check_decls *)
5985 (env, None))
5986 | Class_const _ when is_atom ->
5987 Errors.atom_invalid_argument pos;
5988 (env, None)
5989 | _ -> (env, None)
5991 let (env, te, ty) =
5992 match atom_type with
5993 | Some (te, ty) -> (env, te, ty)
5994 | None ->
5995 let expected =
5996 ExpectedTy.make_and_allow_coercion
5998 Reason.URparam
5999 param.fp_type
6001 expr
6002 ~accept_using_var:(get_fp_accept_disposable param)
6003 ~expected
6007 let env = call_param env param (e, ty) ~is_variadic in
6008 (env, Some (te, ty))
6009 | None ->
6010 let expected =
6011 ExpectedTy.make
6013 Reason.URparam
6014 (Typing_utils.mk_tany env pos)
6016 let (env, te, ty) = expr ~expected env e in
6017 (env, Some (te, ty))
6019 let set_tyvar_variance_from_lambda_param env opt_param =
6020 match opt_param with
6021 | Some param ->
6022 let rec set_params_variance env ty =
6023 let (env, ty) = Env.expand_type env ty in
6024 match get_node ty with
6025 | Tunion [ty] -> set_params_variance env ty
6026 | Toption ty -> set_params_variance env ty
6027 | Tfun { ft_params; ft_ret; _ } ->
6028 let env =
6029 List.fold
6030 ~init:env
6031 ~f:(fun env param ->
6032 Env.set_tyvar_variance env param.fp_type.et_type)
6033 ft_params
6035 Env.set_tyvar_variance env ft_ret.et_type ~flip:true
6036 | _ -> env
6038 set_params_variance env param.fp_type.et_type
6039 | None -> env
6041 (* Given an expected function type ft, check types for the non-unpacked
6042 * arguments. Don't check lambda expressions if check_lambdas=false *)
6043 let rec check_args check_lambdas env el paraml =
6044 match el with
6045 (* We've got an argument *)
6046 | (e, opt_result) :: el ->
6047 (* Pick up next parameter type info *)
6048 let (is_variadic, opt_param, paraml) =
6049 get_next_param_info paraml
6051 let (env, one_result) =
6052 match (check_lambdas, is_lambda e) with
6053 | (false, false)
6054 | (true, true) ->
6055 check_arg env e opt_param ~is_variadic
6056 | (false, true) ->
6057 let env =
6058 set_tyvar_variance_from_lambda_param env opt_param
6060 (env, opt_result)
6061 | (true, false) -> (env, opt_result)
6063 let (env, rl, paraml) = check_args check_lambdas env el paraml in
6064 (env, (e, one_result) :: rl, paraml)
6065 | [] -> (env, [], paraml)
6067 (* Same as above, but checks the types of the implicit arguments, which are
6068 * read from the context *)
6069 let check_implicit_args env =
6070 let capability =
6071 Typing_coeffects.get_type ft.ft_implicit_params.capability
6073 if not (TypecheckerOptions.call_coeffects (Env.get_tcopt env)) then
6075 else
6076 let env_capability =
6077 Env.get_local_check_defined
6079 (pos, Typing_coeffects.capability_id)
6081 Type.sub_type
6083 Reason.URnone
6085 env_capability
6086 capability
6087 (fun ?code:_c _ _ ->
6088 Errors.call_coeffect_error
6090 ~available_incl_unsafe:
6091 (Typing_print.coeffects env env_capability)
6092 ~available_pos:(Typing_defs.get_pos env_capability)
6093 ~required_pos:(Typing_defs.get_pos capability)
6094 ~required:(Typing_print.coeffects env capability))
6097 (* First check the non-lambda arguments. For generic functions, this
6098 * is likely to resolve type variables to concrete types *)
6099 let rl = List.map el (fun e -> (e, None)) in
6100 let (env, rl, _) = check_args false env rl ft.ft_params in
6101 (* Now check the lambda arguments, hopefully with type variables resolved *)
6102 let (env, rl, paraml) = check_args true env rl ft.ft_params in
6103 (* We expect to see results for all arguments after this second pass *)
6104 let get_param opt =
6105 match opt with
6106 | Some x -> x
6107 | None -> failwith "missing parameter in check_args"
6109 let (tel, tys) =
6110 let l = List.map rl (fun (_, opt) -> get_param opt) in
6111 List.unzip l
6113 let env = check_implicit_args env in
6114 let env = TR.check_call env method_call_info pos r2 ft tys in
6115 let (env, typed_unpack_element, arity, did_unpack) =
6116 match unpacked_element with
6117 | None -> (env, None, List.length el, false)
6118 | Some e ->
6119 (* Now that we're considering an splat (Some e) we need to construct a type that
6120 * represents the remainder of the function's parameters. `paraml` represents those
6121 * remaining parameters, and the variadic parameter is stored in `var_param`. For example, given
6123 * function f(int $i, string $j, float $k = 3.14, mixed ...$m): void {}
6124 * function g((string, float, bool) $t): void {
6125 * f(3, ...$t);
6128 * the constraint type we want is splat([#1], [opt#2], #3).
6130 let (consumed, required_params, optional_params) =
6131 split_remaining_params_required_optional ft paraml
6133 let (env, (d_required, d_optional, d_variadic)) =
6134 generate_splat_type_vars
6136 (fst e)
6137 required_params
6138 optional_params
6139 var_param
6141 let destructure_ty =
6142 ConstraintType
6143 (mk_constraint_type
6144 ( Reason.Runpack_param (fst e, pos_def, consumed),
6145 Tdestructure
6147 d_required;
6148 d_optional;
6149 d_variadic;
6150 d_kind = SplatUnpack;
6151 } ))
6153 let (env, te, ty) = expr env e in
6154 (* Populate the type variables from the expression in the splat *)
6155 let env =
6156 Type.sub_type_i
6157 (fst e)
6158 Reason.URparam
6160 (LoclType ty)
6161 destructure_ty
6162 Errors.unify_error
6164 (* Use the type variables for the remaining parameters *)
6165 let env =
6166 List.fold2_exn
6167 ~init:env
6168 d_required
6169 required_params
6170 ~f:(fun env elt param ->
6171 call_param env param (e, elt) ~is_variadic:false)
6173 let env =
6174 List.fold2_exn
6175 ~init:env
6176 d_optional
6177 optional_params
6178 ~f:(fun env elt param ->
6179 call_param env param (e, elt) ~is_variadic:false)
6181 let env =
6182 Option.map2 d_variadic var_param ~f:(fun v vp ->
6183 call_param env vp (e, v) ~is_variadic:true)
6184 |> Option.value ~default:env
6186 ( env,
6187 Some te,
6188 List.length el + List.length d_required,
6189 Option.is_some d_variadic )
6191 (* If we unpacked an array, we don't check arity exactly. Since each
6192 * unpacked array consumes 1 or many parameters, it is nonsensical to say
6193 * that not enough args were passed in (so we don't do the min check).
6195 let () = check_arity ~did_unpack pos pos_def ft arity in
6196 (* Variadic params cannot be inout so we can stop early *)
6197 let env = wfold_left2 inout_write_back env ft.ft_params el in
6198 let (env, ret_ty) =
6199 TR.get_adjusted_return_type env method_call_info ft.ft_ret.et_type
6201 (env, (tel, typed_unpack_element, ret_ty))
6202 | (r, Tvar _)
6203 when TypecheckerOptions.method_call_inference (Env.get_tcopt env) ->
6205 Typecheck calls with unresolved function type by constructing a
6206 suitable function type from the arguments and invoking subtyping.
6208 let (env, typed_el, type_of_el) =
6209 exprs ~accept_using_var:true env el
6211 let (env, typed_unpacked_element, type_of_unpacked_element) =
6212 match unpacked_element with
6213 | Some unpacked ->
6214 let (env, typed_unpacked, type_of_unpacked) =
6215 expr ~accept_using_var:true env unpacked
6217 (env, Some typed_unpacked, Some type_of_unpacked)
6218 | None -> (env, None, None)
6220 let mk_function_supertype
6221 env pos (type_of_el, type_of_unpacked_element) =
6222 let mk_fun_param ty =
6223 let flags =
6224 (* Keep supertype as permissive as possible: *)
6225 make_fp_flags
6226 ~mode:FPnormal (* TODO: deal with `inout` parameters *)
6227 ~accept_disposable:false (* TODO: deal with disposables *)
6228 ~mutability:(Some Param_maybe_mutable)
6229 ~has_default:false
6230 ~ifc_external:false
6231 ~ifc_can_call:false
6232 ~is_atom:false
6235 fp_pos = pos;
6236 fp_name = None;
6237 fp_type = MakeType.enforced ty;
6238 fp_rx_annotation = None;
6239 fp_flags = flags;
6242 let ft_arity =
6243 match type_of_unpacked_element with
6244 | Some type_of_unpacked ->
6245 let fun_param = mk_fun_param type_of_unpacked in
6246 Fvariadic fun_param
6247 | None -> Fstandard
6249 (* TODO: ensure `ft_params`/`ft_where_constraints` don't affect subtyping *)
6250 let ft_tparams = [] in
6251 let ft_where_constraints = [] in
6252 let ft_params = List.map ~f:mk_fun_param type_of_el in
6253 let ft_implicit_params =
6255 capability =
6256 CapDefaults pos
6257 (* TODO(coeffects) should this be a different type? *);
6260 let (env, return_ty) = Env.fresh_type env pos in
6261 let return_ty =
6262 match in_await with
6263 | None -> return_ty
6264 | Some r -> MakeType.awaitable r return_ty
6266 let ft_ret = MakeType.enforced return_ty in
6267 (* A non-reactive supertype is most permissive: *)
6268 let ft_reactive = Nonreactive in
6269 let ft_flags =
6270 (* Keep supertype as permissive as possible: *)
6271 make_ft_flags
6272 Ast_defs.FSync (* `FSync` fun can still return `Awaitable<_>` *)
6273 (Some Param_maybe_mutable)
6274 ~return_disposable:false (* TODO: deal with disposable return *)
6275 ~returns_mutable:false
6276 ~returns_void_to_rx:false
6278 let ft_ifc_decl = Typing_defs_core.default_ifc_fun_decl in
6279 let fun_locl_type =
6281 ft_arity;
6282 ft_tparams;
6283 ft_where_constraints;
6284 ft_params;
6285 ft_implicit_params;
6286 ft_ret;
6287 ft_reactive;
6288 ft_flags;
6289 ft_ifc_decl;
6292 let fun_type = mk (r, Tfun fun_locl_type) in
6293 let env = Env.set_tyvar_variance env fun_type in
6294 (env, fun_type, return_ty)
6296 let (env, fun_type, return_ty) =
6297 mk_function_supertype env pos (type_of_el, type_of_unpacked_element)
6299 let env =
6300 Type.sub_type pos Reason.URnone env efty fun_type Errors.unify_error
6302 (env, (typed_el, typed_unpacked_element, return_ty))
6303 | _ ->
6304 bad_call env pos efty;
6305 let env = call_untyped_unpack env (get_pos efty) unpacked_element in
6306 (env, ([], None, err_witness env pos)))
6308 match resl with
6309 | [res] -> res
6310 | _ ->
6311 bad_call env pos fty;
6312 let env = call_untyped_unpack env (get_pos fty) unpacked_element in
6313 (env, ([], None, err_witness env pos))
6315 and split_remaining_params_required_optional ft remaining_params =
6316 (* Same example as above
6318 * function f(int $i, string $j, float $k = 3.14, mixed ...$m): void {}
6319 * function g((string, float, bool) $t): void {
6320 * f(3, ...$t);
6323 * `remaining_params` will contain [string, float] and there has been 1 parameter consumed. The min_arity
6324 * of this function is 2, so there is 1 required parameter remaining and 1 optional parameter.
6326 let min_arity =
6327 List.count
6328 ~f:(fun fp -> not (Typing_defs.get_fp_has_default fp))
6329 ft.ft_params
6331 let original_params = ft.ft_params in
6332 let consumed = List.length original_params - List.length remaining_params in
6333 let required_remaining = Int.max (min_arity - consumed) 0 in
6334 let (required_params, optional_params) =
6335 List.split_n remaining_params required_remaining
6337 (consumed, required_params, optional_params)
6339 and generate_splat_type_vars
6340 env p required_params optional_params variadic_param =
6341 let (env, d_required) =
6342 List.map_env env required_params ~f:(fun env _ -> Env.fresh_type env p)
6344 let (env, d_optional) =
6345 List.map_env env optional_params ~f:(fun env _ -> Env.fresh_type env p)
6347 let (env, d_variadic) =
6348 match variadic_param with
6349 | None -> (env, None)
6350 | Some _ ->
6351 let (env, ty) = Env.fresh_type env p in
6352 (env, Some ty)
6354 (env, (d_required, d_optional, d_variadic))
6356 and call_param env param (((pos, _) as e), arg_ty) ~is_variadic =
6357 param_modes ~is_variadic param e;
6359 (* When checking params, the type 'x' may be expression dependent. Since
6360 * we store the expression id in the local env for Lvar, we want to apply
6361 * it in this case.
6363 let (env, dep_ty) =
6364 match snd e with
6365 | Lvar _ -> ExprDepTy.make env (CIexpr e) arg_ty
6366 | _ -> (env, arg_ty)
6368 Typing_coercion.coerce_type
6370 Reason.URparam
6372 dep_ty
6373 param.fp_type
6374 Errors.unify_error
6376 and call_untyped_unpack env f_pos unpacked_element =
6377 match unpacked_element with
6378 (* In the event that we don't have a known function call type, we can still
6379 * verify that any unpacked arguments (`...$args`) are something that can
6380 * be actually unpacked. *)
6381 | None -> env
6382 | Some e ->
6383 let (env, _, ety) = expr env e in
6384 let (env, ty) = Env.fresh_type env (fst e) in
6385 let destructure_ty =
6386 MakeType.simple_variadic_splat (Reason.Runpack_param (fst e, f_pos, 0)) ty
6388 Type.sub_type_i
6389 f_pos
6390 Reason.URnone
6392 (LoclType ety)
6393 destructure_ty
6394 Errors.unify_error
6396 and bad_call env p ty = Errors.bad_call p (Typing_print.error env ty)
6398 and make_a_local_of env e =
6399 match e with
6400 | (p, Class_get ((_, cname), CGstring (_, member_name), _)) ->
6401 let (env, local) = Env.FakeMembers.make_static env cname member_name p in
6402 (env, Some (p, local))
6403 | ( p,
6404 Obj_get
6405 ((((_, This) | (_, Lvar _)) as obj), (_, Id (_, member_name)), _, _) )
6407 let (env, local) = Env.FakeMembers.make env obj member_name p in
6408 (env, Some (p, local))
6409 | (_, Lvar x)
6410 | (_, Dollardollar x) ->
6411 (env, Some x)
6412 | _ -> (env, None)
6414 (* This function captures the common bits of logic behind refinement
6415 * of the type of a local variable or a class member variable as a
6416 * result of a dynamic check (e.g., nullity check, simple type check
6417 * using functions like is_int, is_string, is_array etc.). The
6418 * argument refine is a function that takes the type of the variable
6419 * and returns a refined type (making necessary changes to the
6420 * environment, which is threaded through).
6422 * All refinement functions return, in addition to the updated
6423 * environment, a (conservative) set of all the locals that got
6424 * refined. This set is used to construct AssertEnv statmements in
6425 * the typed AST.
6427 and refine_lvalue_type env (((_p, ty), _) as te) ~refine =
6428 let (env, ty) = refine env ty in
6429 let e = Tast.to_nast_expr te in
6430 let (env, localopt) = make_a_local_of env e in
6431 (* TODO TAST: generate an assignment to the fake local in the TAST *)
6432 match localopt with
6433 | Some lid -> (set_local env lid ty, Local_id.Set.singleton (snd lid))
6434 | None -> (env, Local_id.Set.empty)
6436 and condition_nullity ~nonnull (env : env) te =
6437 match te with
6438 (* assignment: both the rhs and lhs of the '=' must be made null/non-null *)
6439 | (_, Aast.Binop (Ast_defs.Eq None, var, te)) ->
6440 let (env, lset1) = condition_nullity ~nonnull env te in
6441 let (env, lset2) = condition_nullity ~nonnull env var in
6442 (env, Local_id.Set.union lset1 lset2)
6443 (* case where `Shapes::idx(...)` must be made null/non-null *)
6444 | ( _,
6445 Aast.Call
6446 ( (_, Aast.Class_const ((_, Aast.CI (_, shapes)), (_, idx))),
6448 [shape; field],
6449 _ ) )
6450 when String.equal shapes SN.Shapes.cShapes && String.equal idx SN.Shapes.idx
6452 let field = Tast.to_nast_expr field in
6453 let refine env shape_ty =
6454 if nonnull then
6455 Typing_shapes.shapes_idx_not_null env shape_ty field
6456 else
6457 (env, shape_ty)
6459 refine_lvalue_type env shape ~refine
6460 | ((p, _), _) ->
6461 let refine env ty =
6462 if nonnull then
6463 Typing_solver.non_null env p ty
6464 else
6465 let r = Reason.Rwitness (get_pos ty) in
6466 Inter.intersect env r ty (MakeType.null r)
6468 refine_lvalue_type env te ~refine
6470 and condition_isset env = function
6471 | (_, Aast.Array_get (x, _)) -> condition_isset env x
6472 | v -> condition_nullity ~nonnull:true env v
6475 * Build an environment for the true or false branch of
6476 * conditional statements.
6478 and condition
6479 ?lhs_of_null_coalesce env tparamet ((((p, ty) as pty), e) as te : Tast.expr)
6481 let condition = condition ?lhs_of_null_coalesce in
6482 match e with
6483 | Aast.True when not tparamet ->
6484 (LEnv.drop_cont env C.Next, Local_id.Set.empty)
6485 | Aast.False when tparamet -> (LEnv.drop_cont env C.Next, Local_id.Set.empty)
6486 | Aast.Call ((_, Aast.Id (_, func)), _, [param], None)
6487 when String.equal SN.PseudoFunctions.isset func
6488 && tparamet
6489 && not (Env.is_strict env) ->
6490 condition_isset env param
6491 | Aast.Call ((_, Aast.Id (_, func)), _, [te], None)
6492 when String.equal SN.StdlibFunctions.is_null func ->
6493 condition_nullity ~nonnull:(not tparamet) env te
6494 | Aast.Binop ((Ast_defs.Eqeq | Ast_defs.Eqeqeq), (_, Aast.Null), e)
6495 | Aast.Binop ((Ast_defs.Eqeq | Ast_defs.Eqeqeq), e, (_, Aast.Null)) ->
6496 condition_nullity ~nonnull:(not tparamet) env e
6497 | Aast.Lvar _
6498 | Aast.Obj_get _
6499 | Aast.Class_get _
6500 | Aast.Binop (Ast_defs.Eq None, _, _) ->
6501 let (env, ety) = Env.expand_type env ty in
6502 (match get_node ety with
6503 | Tprim Tbool -> (env, Local_id.Set.empty)
6504 | _ -> condition_nullity ~nonnull:tparamet env te)
6505 | Aast.Binop (((Ast_defs.Diff | Ast_defs.Diff2) as op), e1, e2) ->
6506 let op =
6507 if Ast_defs.(equal_bop op Diff) then
6508 Ast_defs.Eqeq
6509 else
6510 Ast_defs.Eqeqeq
6512 condition env (not tparamet) (pty, Aast.Binop (op, e1, e2))
6513 | Aast.Id (_, s) when SN.Rx.is_enabled s ->
6514 (* when Rx\IS_ENABLED is false - switch env to non-reactive *)
6515 let env =
6516 if not tparamet then
6517 Env.set_env_reactive env Nonreactive
6518 else
6521 (env, Local_id.Set.empty)
6522 (* Conjunction of conditions. Matches the two following forms:
6523 if (cond1 && cond2)
6524 if (!(cond1 || cond2))
6526 | Aast.Binop (((Ast_defs.Ampamp | Ast_defs.Barbar) as bop), e1, e2)
6527 when Bool.equal tparamet Ast_defs.(equal_bop bop Ampamp) ->
6528 let (env, lset1) = condition env tparamet e1 in
6529 (* This is necessary in case there is an assignment in e2
6530 * We essentially redo what has been undone in the
6531 * `Binop (Ampamp|Barbar)` case of `expr` *)
6532 let (env, _, _) = expr env (Tast.to_nast_expr e2) in
6533 let (env, lset2) = condition env tparamet e2 in
6534 (env, Local_id.Set.union lset1 lset2)
6535 (* Disjunction of conditions. Matches the two following forms:
6536 if (cond1 || cond2)
6537 if (!(cond1 && cond2))
6539 | Aast.Binop (((Ast_defs.Ampamp | Ast_defs.Barbar) as bop), e1, e2)
6540 when Bool.equal tparamet Ast_defs.(equal_bop bop Barbar) ->
6541 let (env, lset1, lset2) =
6542 branch
6544 (fun env ->
6545 (* Either cond1 is true and we don't know anything about cond2... *)
6546 condition env tparamet e1)
6547 (fun env ->
6548 (* ... Or cond1 is false and therefore cond2 must be true *)
6549 let (env, _lset) = condition env (not tparamet) e1 in
6550 (* Similarly to the conjunction case, there might be an assignment in
6551 cond2 which we must account for. Again we redo what has been undone in
6552 the `Binop (Ampamp|Barbar)` case of `expr` *)
6553 let (env, _, _) = expr env (Tast.to_nast_expr e2) in
6554 condition env tparamet e2)
6556 (env, Local_id.Set.union lset1 lset2)
6557 | Aast.Call (((p, _), Aast.Id (_, f)), _, [lv], None)
6558 when tparamet && String.equal f SN.StdlibFunctions.is_dict_or_darray ->
6559 safely_refine_is_array env `HackDictOrDArray p f lv
6560 | Aast.Call (((p, _), Aast.Id (_, f)), _, [lv], None)
6561 when tparamet && String.equal f SN.StdlibFunctions.is_vec_or_varray ->
6562 safely_refine_is_array env `HackVecOrVArray p f lv
6563 | Aast.Call (((p, _), Aast.Id (_, f)), _, [lv], None)
6564 when tparamet && String.equal f SN.StdlibFunctions.is_any_array ->
6565 safely_refine_is_array env `AnyArray p f lv
6566 | Aast.Call (((p, _), Aast.Id (_, f)), _, [lv], None)
6567 when tparamet && String.equal f SN.StdlibFunctions.is_php_array ->
6568 safely_refine_is_array env `PHPArray p f lv
6569 | Aast.Call
6570 ( (_, Aast.Class_const ((_, Aast.CI (_, class_name)), (_, method_name))),
6572 [shape; field],
6573 None )
6574 when tparamet
6575 && String.equal class_name SN.Shapes.cShapes
6576 && String.equal method_name SN.Shapes.keyExists ->
6577 key_exists env p shape field
6578 | Aast.Unop (Ast_defs.Unot, e) -> condition env (not tparamet) e
6579 | Aast.Is (ivar, h) when is_instance_var (Tast.to_nast_expr ivar) ->
6580 let ety_env =
6581 { (Phase.env_with_self env) with from_class = Some CIstatic }
6583 let (env, hint_ty) = Phase.localize_hint ~ety_env env h in
6584 let reason = Reason.Ris (fst h) in
6585 let refine_type env hint_ty =
6586 let (ivar_pos, ivar_ty) = fst ivar in
6587 let (env, ivar) = get_instance_var env (Tast.to_nast_expr ivar) in
6588 let (env, hint_ty) =
6589 class_for_refinement env p reason ivar_pos ivar_ty hint_ty
6591 let (env, refined_ty) = Inter.intersect env reason ivar_ty hint_ty in
6592 (set_local env ivar refined_ty, Local_id.Set.singleton (snd ivar))
6594 let (env, hint_ty) =
6595 if not tparamet then
6596 Inter.non env reason hint_ty ~approx:TUtils.ApproxUp
6597 else
6598 (env, hint_ty)
6600 refine_type env hint_ty
6601 | _ -> (env, Local_id.Set.empty)
6603 (** Transform a hint like `A<_>` to a localized type like `A<T#1>` for refinment of
6604 an instance variable. ivar_ty is the previous type of that instance variable. *)
6605 and class_for_refinement env p reason ivar_pos ivar_ty hint_ty =
6606 let (env, hint_ty) = Env.expand_type env hint_ty in
6607 match (get_node ivar_ty, get_node hint_ty) with
6608 | (_, Tclass (((_, cid) as _c), _, tyl)) ->
6609 begin
6610 match Env.get_class env cid with
6611 | Some class_info ->
6612 let (env, tparams_with_new_names, tyl_fresh) =
6613 generate_fresh_tparams env class_info reason tyl
6615 safely_refine_class_type
6619 class_info
6620 ivar_ty
6621 hint_ty
6622 reason
6623 tparams_with_new_names
6624 tyl_fresh
6625 | None -> (env, mk (Reason.Rwitness ivar_pos, Tobject))
6627 | (Ttuple ivar_tyl, Ttuple hint_tyl)
6628 when Int.equal (List.length ivar_tyl) (List.length hint_tyl) ->
6629 let (env, tyl) =
6630 List.map2_env env ivar_tyl hint_tyl (fun env ivar_ty hint_ty ->
6631 class_for_refinement env p reason ivar_pos ivar_ty hint_ty)
6633 (env, MakeType.tuple reason tyl)
6634 | _ -> (env, hint_ty)
6636 (** If we are dealing with a refinement like
6637 $x is MyClass<A, B>
6638 then class_info is the class info of MyClass and hint_tyl corresponds
6639 to A, B. *)
6640 and generate_fresh_tparams env class_info reason hint_tyl =
6641 let tparams_len = List.length (Cls.tparams class_info) in
6642 let hint_tyl = List.take hint_tyl tparams_len in
6643 let pad_len = tparams_len - List.length hint_tyl in
6644 let hint_tyl =
6645 List.map hint_tyl (fun x -> Some x) @ List.init pad_len (fun _ -> None)
6647 let replace_wildcard env hint_ty tp =
6648 let {
6649 tp_name = (_, tparam_name);
6650 tp_reified = reified;
6651 tp_user_attributes;
6656 let enforceable =
6657 Attributes.mem SN.UserAttributes.uaEnforceable tp_user_attributes
6659 let newable =
6660 Attributes.mem SN.UserAttributes.uaNewable tp_user_attributes
6662 match hint_ty with
6663 | Some ty ->
6664 begin
6665 match get_node ty with
6666 | Tgeneric (name, _targs) when Env.is_fresh_generic_parameter name ->
6667 (* TODO(T69551141) handle type arguments above and below *)
6668 (env, (Some (tp, name), MakeType.generic reason name))
6669 | _ -> (env, (None, ty))
6671 | None ->
6672 let (env, new_name) =
6673 Env.add_fresh_generic_parameter
6675 tparam_name
6676 ~reified
6677 ~enforceable
6678 ~newable
6680 (* TODO(T69551141) handle type arguments for Tgeneric *)
6681 (env, (Some (tp, new_name), MakeType.generic reason new_name))
6683 let (env, tparams_and_tyl) =
6684 List.map2_env env hint_tyl (Cls.tparams class_info) ~f:replace_wildcard
6686 let (tparams_with_new_names, tyl_fresh) = List.unzip tparams_and_tyl in
6687 (env, tparams_with_new_names, tyl_fresh)
6689 and safely_refine_class_type
6692 class_name
6693 class_info
6694 ivar_ty
6695 obj_ty
6696 reason
6697 (tparams_with_new_names : (decl_tparam * string) option list)
6698 tyl_fresh =
6699 (* Type of variable in block will be class name
6700 * with fresh type parameters *)
6701 let obj_ty =
6702 mk (get_reason obj_ty, Tclass (class_name, Nonexact, tyl_fresh))
6704 let tparams = Cls.tparams class_info in
6705 (* Add in constraints as assumptions on those type parameters *)
6706 let ety_env =
6708 type_expansions = [];
6709 substs = Subst.make_locl tparams tyl_fresh;
6710 this_ty = obj_ty;
6711 (* In case `this` appears in constraints *)
6712 from_class = None;
6713 quiet = true;
6714 on_error = Errors.unify_error_at p;
6717 let add_bounds env (t, ty_fresh) =
6718 List.fold_left t.tp_constraints ~init:env ~f:(fun env (ck, ty) ->
6719 (* Substitute fresh type parameters for
6720 * original formals in constraint *)
6721 let (env, ty) = Phase.localize ~ety_env env ty in
6722 SubType.add_constraint p env ck ty_fresh ty)
6724 let env =
6725 List.fold_left (List.zip_exn tparams tyl_fresh) ~f:add_bounds ~init:env
6727 (* Finally, if we have a class-test on something with static classish type,
6728 * then we can chase the hierarchy and decompose the types to deduce
6729 * further assumptions on type parameters. For example, we might have
6730 * class B<Tb> { ... }
6731 * class C extends B<int>
6732 * and have obj_ty = C and x_ty = B<T> for a generic parameter Aast.
6733 * Then SubType.add_constraint will deduce that T=int and add int as
6734 * both lower and upper bound on T in env.lenv.tpenv
6736 let (env, supertypes) = TUtils.get_concrete_supertypes env ivar_ty in
6737 let env =
6738 List.fold_left supertypes ~init:env ~f:(fun env ty ->
6739 SubType.add_constraint p env Ast_defs.Constraint_as obj_ty ty)
6741 (* It's often the case that the fresh name isn't necessary. For
6742 * example, if C<T> extends B<T>, and we have $x:B<t> for some type t
6743 * then $x is C should refine to $x:C<t>.
6744 * We take a simple approach:
6745 * For a fresh type parameter T#1, if
6746 * - There is an eqality constraint T#1 = t,
6747 * - T#1 is covariant, and T#1 has upper bound t (or mixed if absent)
6748 * - T#1 is contravariant, and T#1 has lower bound t (or nothing if absent)
6749 * then replace T#1 with t.
6750 * This is done in Type_parameter_env_ops.simplify_tpenv
6752 let (env, tparam_substs) =
6753 Type_parameter_env_ops.simplify_tpenv
6755 (List.zip_exn tparams_with_new_names tyl_fresh)
6756 reason
6758 let tyl_fresh =
6759 List.map2_exn tyl_fresh tparams_with_new_names ~f:(fun orig_ty tparam_opt ->
6760 match tparam_opt with
6761 | None -> orig_ty
6762 | Some (_tp, name) -> SMap.find name tparam_substs)
6764 let obj_ty_simplified =
6765 mk (get_reason obj_ty, Tclass (class_name, Nonexact, tyl_fresh))
6767 (env, obj_ty_simplified)
6769 and is_instance_var = function
6770 | (_, (Lvar _ | This | Dollardollar _)) -> true
6771 | (_, Obj_get ((_, This), (_, Id _), _, _)) -> true
6772 | (_, Obj_get ((_, Lvar _), (_, Id _), _, _)) -> true
6773 | (_, Class_get (_, _, _)) -> true
6774 | _ -> false
6776 and get_instance_var env = function
6777 | (p, Class_get ((_, cname), CGstring (_, member_name), _)) ->
6778 let (env, local) = Env.FakeMembers.make_static env cname member_name p in
6779 (env, (p, local))
6780 | ( p,
6781 Obj_get
6782 ((((_, This) | (_, Lvar _)) as obj), (_, Id (_, member_name)), _, _) )
6784 let (env, local) = Env.FakeMembers.make env obj member_name p in
6785 (env, (p, local))
6786 | (_, Dollardollar (p, x))
6787 | (_, Lvar (p, x)) ->
6788 (env, (p, x))
6789 | (p, This) -> (env, (p, this))
6790 | _ -> failwith "Should only be called when is_instance_var is true"
6792 (* Refine type for is_array, is_vec, is_keyset and is_dict tests
6793 * `pred_name` is the function name itself (e.g. 'is_vec')
6794 * `p` is position of the function name in the source
6795 * `arg_expr` is the argument to the function
6797 and safely_refine_is_array env ty p pred_name arg_expr =
6798 refine_lvalue_type env arg_expr ~refine:(fun env arg_ty ->
6799 let r = Reason.Rpredicated (p, pred_name) in
6800 let (env, tarrkey_name) =
6801 Env.add_fresh_generic_parameter
6803 "Tk"
6804 ~reified:Erased
6805 ~enforceable:false
6806 ~newable:false
6808 (* TODO(T69551141) handle type arguments for Tgeneric *)
6809 let tarrkey = MakeType.generic r tarrkey_name in
6810 let env =
6811 SubType.add_constraint
6814 Ast_defs.Constraint_as
6815 tarrkey
6816 (MakeType.arraykey r)
6818 let (env, tfresh_name) =
6819 Env.add_fresh_generic_parameter
6822 ~reified:Erased
6823 ~enforceable:false
6824 ~newable:false
6826 (* TODO(T69551141) handle type arguments for Tgeneric *)
6827 let tfresh = MakeType.generic r tfresh_name in
6828 (* If we're refining the type for `is_array` we have a slightly more
6829 * involved process. Let's separate out that logic so we can re-use it.
6831 let array_ty =
6832 let safe_isarray_enabled =
6833 TypecheckerOptions.experimental_feature_enabled
6834 (Env.get_tcopt env)
6835 TypecheckerOptions.experimental_isarray
6837 let tk = MakeType.arraykey Reason.(Rvarray_or_darray_key (to_pos r)) in
6838 let tv =
6839 if safe_isarray_enabled then
6840 tfresh
6841 else
6842 mk (r, TUtils.tany env)
6844 MakeType.varray_or_darray r tk tv
6846 (* This is the refined type of e inside the branch *)
6847 let hint_ty =
6848 match ty with
6849 | `HackDict -> MakeType.dict r tarrkey tfresh
6850 | `HackVec -> MakeType.vec r tfresh
6851 | `HackKeyset -> MakeType.keyset r tarrkey
6852 | `PHPArray -> array_ty
6853 | `AnyArray -> MakeType.any_array r tarrkey tfresh
6854 | `HackDictOrDArray ->
6855 MakeType.union
6857 [MakeType.dict r tarrkey tfresh; MakeType.darray r tarrkey tfresh]
6858 | `HackVecOrVArray ->
6859 MakeType.union r [MakeType.vec r tfresh; MakeType.varray r tfresh]
6861 let ((arg_pos, _), _) = arg_expr in
6862 let (env, hint_ty) =
6863 class_for_refinement env p r arg_pos arg_ty hint_ty
6865 (* Add constraints on generic parameters that must
6866 * hold for refined_ty <:arg_ty. For example, if arg_ty is Traversable<T>
6867 * and refined_ty is keyset<T#1> then we know T#1 <: T.
6868 * See analogous code in safely_refine_class_type.
6870 let (env, supertypes) = TUtils.get_concrete_supertypes env arg_ty in
6871 let env =
6872 List.fold_left supertypes ~init:env ~f:(fun env ty ->
6873 SubType.add_constraint p env Ast_defs.Constraint_as hint_ty ty)
6875 Inter.intersect ~r env hint_ty arg_ty)
6877 and key_exists env pos shape field =
6878 let field = Tast.to_nast_expr field in
6879 refine_lvalue_type env shape ~refine:(fun env shape_ty ->
6880 match TUtils.shape_field_name env field with
6881 | None -> (env, shape_ty)
6882 | Some field_name ->
6883 Typing_shapes.refine_shape field_name pos env shape_ty)
6885 and string2 env idl =
6886 let (env, tel) =
6887 List.fold_left idl ~init:(env, []) ~f:(fun (env, tel) x ->
6888 let (env, te, ty) = expr env x in
6889 let p = fst x in
6890 let env = Typing_substring.sub_string p env ty in
6891 (env, te :: tel))
6893 (env, List.rev tel)
6895 and user_attribute env ua =
6896 let (env, typed_ua_params) =
6897 List.map_env env ua.ua_params (fun env e ->
6898 let (env, te, _) = expr env e in
6899 (env, te))
6901 (env, { Aast.ua_name = ua.ua_name; Aast.ua_params = typed_ua_params })
6903 and file_attributes env file_attrs =
6904 (* Disable checking of error positions, as file attributes have spans that
6905 * aren't subspans of the class or function into which they are copied *)
6906 Errors.run_with_span Pos.none @@ fun () ->
6907 let uas = List.concat_map ~f:(fun fa -> fa.fa_user_attributes) file_attrs in
6908 let env = attributes_check_def env SN.AttributeKinds.file uas in
6909 List.map_env env file_attrs (fun env fa ->
6910 let (env, user_attributes) =
6911 List.map_env env fa.fa_user_attributes user_attribute
6913 let env = set_tcopt_unstable_features env fa in
6914 ( env,
6916 Aast.fa_user_attributes = user_attributes;
6917 Aast.fa_namespace = fa.fa_namespace;
6918 } ))
6920 and type_param env t =
6921 let env =
6922 attributes_check_def env SN.AttributeKinds.typeparam t.tp_user_attributes
6924 let (env, user_attributes) =
6925 List.map_env env t.tp_user_attributes user_attribute
6927 let (env, tp_parameters) = List.map_env env t.tp_parameters type_param in
6928 ( env,
6930 Aast.tp_variance = t.tp_variance;
6931 Aast.tp_name = t.tp_name;
6932 Aast.tp_parameters;
6933 Aast.tp_constraints = t.tp_constraints;
6934 Aast.tp_reified = reify_kind t.tp_reified;
6935 Aast.tp_user_attributes = user_attributes;
6938 and typedef_def ctx typedef =
6939 let env = EnvFromDef.typedef_env ~origin:Decl_counters.TopLevel ctx typedef in
6940 let env =
6941 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
6942 (fst typedef.t_name)
6944 typedef.t_tparams
6947 Typing_check_decls.typedef env typedef;
6948 Typing_variance.typedef env (snd typedef.t_name);
6949 let {
6950 t_annotation = ();
6951 t_name = (t_pos, t_name);
6952 t_tparams = _;
6953 t_constraint = tcstr;
6954 t_kind = hint;
6955 t_user_attributes = _;
6956 t_vis = _;
6957 t_mode = _;
6958 t_namespace = _;
6959 t_span = _;
6960 t_emit_id = _;
6962 typedef
6964 let ty = Decl_hint.hint env.decl_env hint in
6965 (* We want to report cycles through the definition *)
6966 let (env, ty) =
6967 Phase.localize_with_self env ~pos:t_pos ~report_cycle:(t_pos, t_name) ty
6969 let env =
6970 match tcstr with
6971 | Some tcstr ->
6972 let cstr = Decl_hint.hint env.decl_env tcstr in
6973 let (env, cstr) = Phase.localize_with_self ~pos:t_pos env cstr in
6974 Typing_ops.sub_type
6975 t_pos
6976 Reason.URnewtype_cstr
6979 cstr
6980 Errors.newtype_alias_must_satisfy_constraint
6981 | _ -> env
6983 let env =
6984 match hint with
6985 | (pos, Hshape { nsi_allows_unknown_fields = _; nsi_field_map }) ->
6986 let get_name sfi = sfi.sfi_name in
6987 check_shape_keys_validity env pos (List.map ~f:get_name nsi_field_map)
6988 | _ -> env
6990 let env =
6991 attributes_check_def
6993 SN.AttributeKinds.typealias
6994 typedef.t_user_attributes
6996 let (env, tparams) = List.map_env env typedef.t_tparams type_param in
6997 let (env, user_attributes) =
6998 List.map_env env typedef.t_user_attributes user_attribute
7001 Aast.t_annotation = Env.save (Env.get_tpenv env) env;
7002 Aast.t_name = typedef.t_name;
7003 Aast.t_mode = typedef.t_mode;
7004 Aast.t_vis = typedef.t_vis;
7005 Aast.t_user_attributes = user_attributes;
7006 Aast.t_constraint = typedef.t_constraint;
7007 Aast.t_kind = typedef.t_kind;
7008 Aast.t_tparams = tparams;
7009 Aast.t_namespace = typedef.t_namespace;
7010 Aast.t_span = typedef.t_span;
7011 Aast.t_emit_id = typedef.t_emit_id;
7014 (* Calls the method of a class, but allows the f callback to override the
7015 * return value type *)
7016 and overload_function
7017 make_call fpos p env (cpos, class_id) method_id el unpacked_element f =
7018 let (env, _tal, tcid, ty) =
7019 static_class_id ~check_constraints:false cpos env [] class_id
7021 let (env, _tel, _) = exprs env el in
7022 let (env, (fty, tal)) =
7023 class_get
7024 ~is_method:true
7025 ~is_const:false
7026 ~coerce_from_ty:None
7029 method_id
7030 class_id
7032 let (env, (tel, typed_unpack_element, res)) =
7033 call ~expected:None p env fty el unpacked_element
7035 let (env, ty) = f env fty res el in
7036 let (env, fty) = Env.expand_type env fty in
7037 let fty =
7038 map_ty fty ~f:(function
7039 | Tfun ft -> Tfun { ft with ft_ret = MakeType.unenforced ty }
7040 | ty -> ty)
7042 let te = Tast.make_typed_expr fpos fty (Aast.Class_const (tcid, method_id)) in
7043 make_call env te tal tel typed_unpack_element ty
7045 and update_array_type ?lhs_of_null_coalesce p env e1 valkind =
7046 match valkind with
7047 | `lvalue
7048 | `lvalue_subexpr ->
7049 let (env, te1, ty1) =
7050 raw_expr ~valkind:`lvalue_subexpr ~check_defined:true env e1
7052 begin
7053 match e1 with
7054 | (_, Lvar (_, x)) ->
7055 (* type_mapper has updated the type in ty1 typevars, but we
7056 need to update the local variable type too *)
7057 let env = set_valid_rvalue p env x ty1 in
7058 (env, te1, ty1)
7059 | _ -> (env, te1, ty1)
7061 | _ -> raw_expr ?lhs_of_null_coalesce env e1
7063 (* External API *)
7064 let expr ?expected env e =
7065 Typing_env.with_origin2 env Decl_counters.Body (fun env ->
7066 expr ?expected env e)
7068 let stmt env st =
7069 Typing_env.with_origin env Decl_counters.Body (fun env -> stmt env st)