Fix position for enum atoms in Tast
[hiphop-php.git] / hphp / hack / src / typing / typing.ml
blobc124c00763b27d723d44bf4cfdc8001ee505792c
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 FL = FeatureLogging
46 module MakeType = Typing_make_type
47 module Cls = Decl_provider.Class
48 module Partial = Partial_provider
49 module Fake = Typing_fake_members
50 module ExpectedTy = Typing_helpers.ExpectedTy
52 type newable_class_info =
53 env
54 * Tast.targ list
55 * Tast.class_id
56 * [ `Class of sid * Cls.t * locl_ty | `Dynamic ] list
58 (*****************************************************************************)
59 (* Debugging *)
60 (*****************************************************************************)
62 (* A guess as to the last position we were typechecking, for use in debugging,
63 * such as figuring out what a runaway hh_server thread is doing. Updated
64 * only best-effort -- it's an approximation to point debugging in the right
65 * direction, nothing more. *)
66 let debug_last_pos = ref Pos.none
68 let debug_print_last_pos _ =
69 Hh_logger.info
70 "Last typecheck pos: %s"
71 (Pos.string (Pos.to_absolute !debug_last_pos))
73 (*****************************************************************************)
74 (* Helpers *)
75 (*****************************************************************************)
77 let err_witness env p = TUtils.terr env (Reason.Rwitness p)
79 let triple_to_pair (env, te, ty) = (env, (te, ty))
81 let with_special_coeffects env cap_ty unsafe_cap_ty f =
82 let init =
83 Option.map (Env.next_cont_opt env) ~f:(fun next_cont ->
84 let initial_locals = next_cont.Typing_per_cont_env.local_types in
85 let tpenv = Env.get_tpenv env in
86 (initial_locals, tpenv))
88 Typing_lenv.stash_and_do env (Env.all_continuations env) (fun env ->
89 let env =
90 match init with
91 | None -> env
92 | Some (initial_locals, tpenv) ->
93 let env = Env.reinitialize_locals env in
94 let env = Env.set_locals env initial_locals in
95 let env = Env.env_with_tpenv env tpenv in
96 env
98 let (env, _ty) =
99 Typing_coeffects.register_capabilities env cap_ty unsafe_cap_ty
101 f env)
103 (* Set all the types in an expression to the given type. *)
104 let with_type ty env (e : Nast.expr) : Tast.expr =
105 let visitor =
106 object
107 inherit [_] Aast.map
109 method on_'ex _ p = (p, ty)
111 method on_'fb _ _ = ()
113 method on_'en _ _ = env
115 method on_'hi _ _ = ty
118 visitor#on_expr () e
120 let expr_error env (r : Reason.t) (e : Nast.expr) =
121 let ty = TUtils.terr env r in
122 (env, with_type ty Tast.dummy_saved_env e, ty)
124 let expr_any env p e =
125 let ty = Typing_utils.mk_tany env p in
126 (env, with_type ty Tast.dummy_saved_env e, ty)
128 let unbound_name env (pos, name) e =
129 let strictish = Partial.should_check_error (Env.get_mode env) 4107 in
130 match Env.get_mode env with
131 | FileInfo.Mstrict ->
132 Errors.unbound_name_typing pos name;
133 expr_error env (Reason.Rwitness pos) e
134 | FileInfo.Mpartial when strictish ->
135 Errors.unbound_name_typing pos name;
136 expr_error env (Reason.Rwitness pos) e
137 | FileInfo.Mhhi
138 | FileInfo.Mpartial ->
139 expr_any env pos e
141 (* Is this type Traversable<vty> or Container<vty> for some vty? *)
142 let get_value_collection_inst ty =
143 match get_node ty with
144 | Tclass ((_, c), _, [vty])
145 when String.equal c SN.Collections.cTraversable
146 || String.equal c SN.Collections.cContainer ->
147 Some vty
148 (* If we're expecting a mixed or a nonnull then we can just assume
149 * that the element type is mixed *)
150 | Tnonnull -> Some (MakeType.mixed Reason.Rnone)
151 | Tany _ -> Some ty
152 | _ -> None
154 (* Is this type KeyedTraversable<kty,vty>
155 * or KeyedContainer<kty,vty>
156 * for some kty, vty?
158 let get_key_value_collection_inst p ty =
159 match get_node ty with
160 | Tclass ((_, c), _, [kty; vty])
161 when String.equal c SN.Collections.cKeyedTraversable
162 || String.equal c SN.Collections.cKeyedContainer ->
163 Some (kty, vty)
164 (* If we're expecting a mixed or a nonnull then we can just assume
165 * that the key type is arraykey and the value type is mixed *)
166 | Tnonnull ->
167 let arraykey = MakeType.arraykey (Reason.Rkey_value_collection_key p) in
168 let mixed = MakeType.mixed Reason.Rnone in
169 Some (arraykey, mixed)
170 | Tany _ -> Some (ty, ty)
171 | _ -> None
173 (* Is this type varray<vty> or a supertype for some vty? *)
174 let get_varray_inst ty =
175 match get_node ty with
176 (* It's varray<vty> *)
177 | Tvarray vty -> Some vty
178 | _ -> get_value_collection_inst ty
180 (* Is this type one of the value collection types with element type vty? *)
181 let get_vc_inst vc_kind ty =
182 match get_node ty with
183 | Tclass ((_, c), _, [vty]) when String.equal c (Nast.vc_kind_to_name vc_kind)
185 Some vty
186 | _ -> get_value_collection_inst ty
188 (* Is this type one of the three key-value collection types
189 * e.g. dict<kty,vty> or a supertype for some kty and vty? *)
190 let get_kvc_inst p kvc_kind ty =
191 match get_node ty with
192 | Tclass ((_, c), _, [kty; vty])
193 when String.equal c (Nast.kvc_kind_to_name kvc_kind) ->
194 Some (kty, vty)
195 | _ -> get_key_value_collection_inst p ty
197 (* Is this type darray<kty, vty> or a supertype for some kty and vty? *)
198 let get_darray_inst p ty =
199 match get_node ty with
200 (* It's darray<kty, vty> *)
201 | Tdarray (kty, vty) -> Some (kty, vty)
202 | _ -> get_key_value_collection_inst p ty
204 (* Check whether this is a function type that (a) either returns a disposable
205 * or (b) has the <<__ReturnDisposable>> attribute
207 let is_return_disposable_fun_type env ty =
208 let (_env, ty) = Env.expand_type env ty in
209 match get_node ty with
210 | Tfun ft ->
211 get_ft_return_disposable ft
212 || Option.is_some
213 (Typing_disposable.is_disposable_type env ft.ft_ret.et_type)
214 | _ -> false
216 (* Turn an environment into a local_id_map suitable to be embedded
217 * into an AssertEnv statement
219 let annot_map env =
220 match Env.next_cont_opt env with
221 | Some { Typing_per_cont_env.local_types; _ } ->
222 Some (Local_id.Map.map (fun (ty, pos, _expr_id) -> (pos, ty)) local_types)
223 | None -> None
225 (* Similar to annot_map above, but filters the map to only contain
226 * information about locals in lset
228 let refinement_annot_map env lset =
229 match annot_map env with
230 | Some map ->
231 let map =
232 Local_id.Map.filter (fun lid _ -> Local_id.Set.mem lid lset) map
234 if Local_id.Map.is_empty map then
235 None
236 else
237 Some map
238 | None -> None
240 let assert_env_blk ~pos ~at annotation_kind env_map_opt blk =
241 let mk_assert map = (pos, Aast.AssertEnv (annotation_kind, map)) in
242 let annot_blk = Option.to_list (Option.map ~f:mk_assert env_map_opt) in
243 match at with
244 | `Start -> annot_blk @ blk
245 | `End -> blk @ annot_blk
247 let assert_env_stmt ~pos ~at annotation_kind env_map_opt stmt =
248 let mk_assert map = (pos, Aast.AssertEnv (annotation_kind, map)) in
249 match env_map_opt with
250 | Some env_map ->
251 let stmt = (pos, stmt) in
252 let blk =
253 match at with
254 | `Start -> [mk_assert env_map; stmt]
255 | `End -> [stmt; mk_assert env_map]
257 Aast.Block blk
258 | None -> stmt
260 let set_tcopt_unstable_features env { fa_user_attributes; _ } =
261 match
262 Naming_attributes.find
263 SN.UserAttributes.uaEnableUnstableFeatures
264 fa_user_attributes
265 with
266 | None -> env
267 | Some { ua_name = _; ua_params } ->
268 let ( = ) = String.equal in
269 List.fold ua_params ~init:env ~f:(fun env feature ->
270 match snd feature with
271 | Aast.String s when s = SN.UnstableFeatures.ifc ->
272 Env.map_tcopt ~f:TypecheckerOptions.enable_ifc env
273 | Aast.String s when s = SN.UnstableFeatures.readonly ->
274 Env.map_tcopt ~f:(fun t -> TypecheckerOptions.set_readonly t true) env
275 | Aast.String s when s = SN.UnstableFeatures.expression_trees ->
276 Env.map_tcopt
277 ~f:(fun t ->
278 TypecheckerOptions.set_tco_enable_expression_trees t true)
280 | _ -> env)
282 (* Given a localized parameter type and parameter information, infer
283 * a type for the parameter default expression (if present) and check that
284 * it is a subtype of the parameter type (if present). If no parameter type
285 * is specified, then union with Tany. (So it's as though we did a conditional
286 * assignment of the default expression to the parameter).
287 * Set the type of the parameter in the locals environment *)
288 let rec bind_param env ?(immutable = false) (ty1, param) =
289 let (env, param_te, ty1) =
290 match param.param_expr with
291 | None -> (env, None, ty1)
292 | Some e ->
293 let decl_hint =
294 Option.map
295 ~f:(Decl_hint.hint env.decl_env)
296 (hint_of_type_hint param.param_type_hint)
298 let enforced =
299 match decl_hint with
300 | None -> Unenforced
301 | Some ty -> Typing_enforceability.get_enforcement env ty
303 let ty1_enforced = { et_type = ty1; et_enforced = enforced } in
304 let expected =
305 ExpectedTy.make_and_allow_coercion_opt
307 param.param_pos
308 Reason.URparam
309 ty1_enforced
311 let (env, (te, ty2)) =
312 let r = Reason.Rwitness_from_decl param.param_pos in
313 let pure = MakeType.mixed r in
314 let (env, cap) =
315 MakeType.apply
317 (* Accessing statics for default arguments is allowed *)
318 (param.param_pos, SN.Capabilities.accessStaticVariable)
320 |> Phase.localize_with_self env ~ignore_errors:false
322 with_special_coeffects env cap pure @@ fun env ->
323 expr ?expected env e ~allow_awaitable:(*?*) false |> triple_to_pair
325 Typing_sequencing.sequence_check_expr e;
326 let (env, ty1) =
328 Option.is_none (hint_of_type_hint param.param_type_hint)
329 && (not @@ TCO.global_inference (Env.get_tcopt env))
330 (* ty1 will be Tany iff we have no type hint and we are not in
331 * 'infer missing mode'. When it ty1 is Tany we just union it with
332 * the type of the default expression *)
333 then
334 Union.union env ty1 ty2
335 (* Otherwise we have an explicit type, and the default expression type
336 * must be a subtype *)
337 else
338 let env =
339 Typing_coercion.coerce_type
340 param.param_pos
341 Reason.URhint
344 ty1_enforced
345 Errors.parameter_default_value_wrong_type
347 (env, ty1)
349 (env, Some te, ty1)
351 let (env, user_attributes) =
352 List.map_env env param.param_user_attributes user_attribute
354 let tparam =
356 Aast.param_annotation = Tast.make_expr_annotation param.param_pos ty1;
357 Aast.param_type_hint = (ty1, hint_of_type_hint param.param_type_hint);
358 Aast.param_is_variadic = param.param_is_variadic;
359 Aast.param_pos = param.param_pos;
360 Aast.param_name = param.param_name;
361 Aast.param_expr = param_te;
362 Aast.param_callconv = param.param_callconv;
363 Aast.param_readonly = param.param_readonly;
364 Aast.param_user_attributes = user_attributes;
365 Aast.param_visibility = param.param_visibility;
368 let mode = get_param_mode param.param_callconv in
369 let id = Local_id.make_unscoped param.param_name in
370 let env = Env.set_local ~immutable env id ty1 param.param_pos in
371 let env = Env.set_param env id (ty1, param.param_pos, mode) in
372 let env =
373 if has_accept_disposable_attribute param then
374 Env.set_using_var env id
375 else
378 (env, tparam)
380 and check_inout_return ret_pos env =
381 let params = Local_id.Map.elements (Env.get_params env) in
382 List.fold params ~init:env ~f:(fun env (id, (ty, param_pos, mode)) ->
383 match mode with
384 | FPinout ->
385 (* Whenever the function exits normally, we require that each local
386 * corresponding to an inout parameter be compatible with the original
387 * type for the parameter (under subtyping rules). *)
388 let (local_ty, local_pos) = Env.get_local_pos env id in
389 let (env, ety) = Env.expand_type env local_ty in
390 let pos =
391 if not (Pos.equal Pos.none local_pos) then
392 local_pos
393 else if not (Pos.equal Pos.none ret_pos) then
394 ret_pos
395 else
396 param_pos
398 let param_ty = mk (Reason.Rinout_param (get_pos ty), get_node ty) in
399 Type.sub_type
401 Reason.URassign_inout
404 param_ty
405 Errors.inout_return_type_mismatch
406 | _ -> env)
408 (*****************************************************************************)
409 (* function used to type closures, functions and methods *)
410 (*****************************************************************************)
411 and fun_ ?(abstract = false) ?(disable = false) env return pos named_body f_kind
413 Env.with_env env (fun env ->
414 debug_last_pos := pos;
415 let env = Env.set_return env return in
416 let (env, tb) =
417 if disable then
418 let () =
419 Errors.internal_error
421 ( "Type inference for this function has been disabled by the "
422 ^ SN.UserAttributes.uaDisableTypecheckerInternal
423 ^ " attribute" )
425 block env []
426 else
427 block env named_body.fb_ast
429 Typing_sequencing.sequence_check_block named_body.fb_ast;
430 let { Typing_env_return_info.return_type = ret; _ } =
431 Env.get_return env
433 let has_implicit_return = LEnv.has_next env in
434 let named_body_is_unsafe = Nast.named_body_is_unsafe named_body in
435 let env =
436 if (not has_implicit_return) || abstract || named_body_is_unsafe then
438 else
439 fun_implicit_return env pos ret.et_type f_kind
441 let env =
442 Typing_env.set_fun_tast_info
444 { Tast.has_implicit_return; Tast.named_body_is_unsafe }
446 debug_last_pos := Pos.none;
447 (env, tb))
449 and fun_implicit_return env pos ret = function
450 | Ast_defs.FGenerator
451 | Ast_defs.FAsyncGenerator ->
453 | Ast_defs.FSync ->
454 (* A function without a terminal block has an implicit return; the
455 * "void" type *)
456 let env = check_inout_return Pos.none env in
457 let r = Reason.Rno_return pos in
458 let rty = MakeType.void r in
459 Typing_return.implicit_return env pos ~expected:ret ~actual:rty
460 | Ast_defs.FAsync ->
461 (* An async function without a terminal block has an implicit return;
462 * the Awaitable<void> type *)
463 let r = Reason.Rno_return_async pos in
464 let rty = MakeType.awaitable r (MakeType.void r) in
465 Typing_return.implicit_return env pos ~expected:ret ~actual:rty
467 and block env stl =
468 Typing_env.with_origin env Decl_counters.Body @@ fun env ->
469 (* To insert an `AssertEnv`, `stmt` might return a `Block`. We eliminate it here
470 to keep ASTs `Block`-free. *)
471 let (env, stl) =
472 List.fold ~init:(env, []) stl ~f:(fun (env, stl) st ->
473 let (env, st) = stmt env st in
474 (* Accumulate statements in reverse order *)
475 let stl =
476 match st with
477 | (_, Aast.Block stl') -> List.rev stl' @ stl
478 | _ -> st :: stl
480 (env, stl))
482 (env, List.rev stl)
484 (* Set a local; must not be already assigned if it is a using variable *)
485 and set_local ?(is_using_clause = false) env (pos, x) ty =
486 if Env.is_using_var env x then
487 if is_using_clause then
488 Errors.duplicate_using_var pos
489 else
490 Errors.illegal_disposable pos "assigned";
491 let env = Env.set_local env x ty pos in
492 if is_using_clause then
493 Env.set_using_var env x
494 else
497 (* Ensure that `ty` is a subtype of IDisposable (for `using`) or
498 * IAsyncDisposable (for `await using`)
500 and has_dispose_method env has_await p e ty =
501 let meth =
502 if has_await then
503 SN.Members.__disposeAsync
504 else
505 SN.Members.__dispose
507 let (env, (tfty, _tal)) =
508 TOG.obj_get
509 ~obj_pos:(fst e)
510 ~is_method:true
511 ~inst_meth:false
512 ~nullsafe:None
513 ~coerce_from_ty:None
514 ~explicit_targs:[]
515 ~class_id:(CIexpr e)
516 ~member_id:(p, meth)
517 ~on_error:(Errors.using_error p has_await)
521 let (env, (_tel, _typed_unpack_element, _ty)) =
522 call ~expected:None p env tfty [] None
526 (* Check an individual component in the expression `e` in the
527 * `using (e) { ... }` statement.
528 * This consists of either
529 * a simple assignment `$x = e`, in which `$x` is the using variable, or
530 * an arbitrary expression `e`, in which case a temporary is the using
531 * variable, inaccessible in the source.
532 * Return the typed expression and its type, and any variables that must
533 * be designated as "using variables" for avoiding escapes.
535 and check_using_expr has_await env ((pos, content) as using_clause) =
536 match content with
537 (* Simple assignment to local of form `$lvar = e` *)
538 | Binop (Ast_defs.Eq None, (lvar_pos, Lvar lvar), e) ->
539 let (env, te, ty) =
540 expr ~is_using_clause:true env e ~allow_awaitable:(*?*) false
542 let env = has_dispose_method env has_await pos e ty in
543 let env = set_local ~is_using_clause:true env lvar ty in
544 (* We are assigning a new value to the local variable, so we need to
545 * generate a new expression id
547 let env = Env.set_local_expr_id env (snd lvar) (Ident.tmp ()) in
548 ( env,
549 ( Tast.make_typed_expr
552 (Aast.Binop
553 ( Ast_defs.Eq None,
554 Tast.make_typed_expr lvar_pos ty (Aast.Lvar lvar),
555 te )),
556 [snd lvar] ) )
557 (* Arbitrary expression. This will be assigned to a temporary *)
558 | _ ->
559 let (env, typed_using_clause, ty) =
560 expr ~is_using_clause:true env using_clause ~allow_awaitable:(*?*) false
562 let env = has_dispose_method env has_await pos using_clause ty in
563 (env, (typed_using_clause, []))
565 (* Check the using clause e in
566 * `using (e) { ... }` statement (`has_await = false`) or
567 * `await using (e) { ... }` statement (`has_await = true`).
568 * `using_clauses` is a list of expressions.
569 * Return the typed expression, and any variables that must
570 * be designated as "using variables" for avoiding escapes.
572 and check_using_clause env has_await using_clauses =
573 let (env, pairs) =
574 List.map_env env using_clauses (check_using_expr has_await)
576 let (typed_using_clauses, vars) = List.unzip pairs in
577 (env, typed_using_clauses, List.concat vars)
579 (* Require a new construct with disposable *)
580 and enforce_return_disposable _env e =
581 match e with
582 | (_, New _) -> ()
583 | (_, Call _) -> ()
584 | (_, Await (_, Call _)) -> ()
585 | (p, _) -> Errors.invalid_return_disposable p
587 (* Wrappers around the function with the same name in Typing_lenv, which only
588 * performs the move/save and merge operation if we are in a try block or in a
589 * function with return type 'noreturn'.
590 * This enables significant perf improvement, because this is called at every
591 * function of method call, when most calls are outside of a try block. *)
592 and move_and_merge_next_in_catch env =
593 if env.in_try || TFTerm.is_noreturn env then
594 LEnv.move_and_merge_next_in_cont env C.Catch
595 else
596 LEnv.drop_cont env C.Next
598 and save_and_merge_next_in_catch env =
599 if env.in_try || TFTerm.is_noreturn env then
600 LEnv.save_and_merge_next_in_cont env C.Catch
601 else
604 and might_throw env = save_and_merge_next_in_catch env
606 and stmt env (pos, st) =
607 let (env, st) = stmt_ env pos st in
608 Typing_debug.log_env_if_too_big pos env;
609 (env, (pos, st))
611 and stmt_ env pos st =
612 let expr ?(allow_awaitable = (*?*) false) = expr ~allow_awaitable in
613 let exprs = exprs ~allow_awaitable:(*?*) false in
614 (* Type check a loop. f env = (env, result) checks the body of the loop.
615 * We iterate over the loop until the "next" continuation environment is
616 * stable. alias_depth is supposed to be an upper bound on this; but in
617 * certain cases this fails (e.g. a generic type grows unboundedly). TODO:
618 * fix this.
620 let infer_loop env f =
621 let in_loop_outer = env.in_loop in
622 let alias_depth =
623 if in_loop_outer then
625 else
626 Typing_alias.get_depth (pos, st)
628 let env = { env with in_loop = true } in
629 let rec loop env n =
630 (* Remember the old environment *)
631 let old_next_entry = Env.next_cont_opt env in
632 let (env, result) = f env in
633 let new_next_entry = Env.next_cont_opt env in
634 (* Finish if we reach the bound, or if the environments match *)
636 Int.equal n alias_depth
637 || Typing_per_cont_ops.is_sub_opt_entry
638 Typing_subtype.is_sub_type
640 new_next_entry
641 old_next_entry
642 then
643 let env = { env with in_loop = in_loop_outer } in
644 (env, result)
645 else
646 loop env (n + 1)
648 loop env 1
650 let env = Env.open_tyvars env pos in
651 (fun (env, tb) ->
652 (Typing_solver.close_tyvars_and_solve env Errors.unify_error, tb))
654 match st with
655 | Fallthrough ->
656 let env =
657 if env.in_case then
658 LEnv.move_and_merge_next_in_cont env C.Fallthrough
659 else
662 (env, Aast.Fallthrough)
663 | Noop -> (env, Aast.Noop)
664 | AssertEnv _ -> (env, Aast.Noop)
665 | Yield_break ->
666 let env = LEnv.move_and_merge_next_in_cont env C.Exit in
667 (env, Aast.Yield_break)
668 | Expr e ->
669 let (env, te, _) = expr env e in
670 let env =
671 if TFTerm.typed_expression_exits te then
672 LEnv.move_and_merge_next_in_cont env C.Exit
673 else
676 (env, Aast.Expr te)
677 | If (e, b1, b2) ->
678 let assert_refinement_env =
679 assert_env_blk ~pos ~at:`Start Aast.Refinement
681 let (env, te, _) = expr env e in
682 let (env, tb1, tb2) =
683 branch
685 (fun env ->
686 let (env, lset) = condition env true te in
687 let refinement_map = refinement_annot_map env lset in
688 let (env, b1) = block env b1 in
689 let b1 = assert_refinement_env refinement_map b1 in
690 (env, b1))
691 (fun env ->
692 let (env, lset) = condition env false te in
693 let refinement_map = refinement_annot_map env lset in
694 let (env, b2) = block env b2 in
695 let b2 = assert_refinement_env refinement_map b2 in
696 (env, b2))
698 (* TODO TAST: annotate with joined types *)
699 (env, Aast.If (te, tb1, tb2))
700 | Return None ->
701 let env = check_inout_return pos env in
702 let rty = MakeType.void (Reason.Rwitness pos) in
703 let { Typing_env_return_info.return_type = expected_return; _ } =
704 Env.get_return env
706 let expected_return =
707 Typing_return.strip_awaitable (Env.get_fn_kind env) env expected_return
709 let env =
710 match Env.get_fn_kind env with
711 | Ast_defs.FGenerator
712 | Ast_defs.FAsyncGenerator ->
714 | _ ->
715 Typing_return.implicit_return
718 ~expected:expected_return.et_type
719 ~actual:rty
721 let env = LEnv.move_and_merge_next_in_cont env C.Exit in
722 (env, Aast.Return None)
723 | Return (Some e) ->
724 let env = check_inout_return pos env in
725 let expr_pos = fst e in
726 let Typing_env_return_info.
728 return_type;
729 return_disposable;
730 return_explicit;
731 return_dynamically_callable = _;
733 Env.get_return env
735 let return_type =
736 Typing_return.strip_awaitable (Env.get_fn_kind env) env return_type
738 let expected =
739 if return_explicit then
740 Some
741 (ExpectedTy.make_and_allow_coercion
742 expr_pos
743 Reason.URreturn
744 return_type)
745 else
746 None
748 if return_disposable then enforce_return_disposable env e;
749 let (env, te, rty) =
750 expr ~is_using_clause:return_disposable ?expected env e
752 (* This is a unify_error rather than a return_type_mismatch because the return
753 * statement is the problem, not the return type itself. *)
754 let env =
755 Typing_coercion.coerce_type
756 expr_pos
757 Reason.URreturn
760 return_type
761 Errors.unify_error
763 let env = LEnv.move_and_merge_next_in_cont env C.Exit in
764 (env, Aast.Return (Some te))
765 | Do (b, e) ->
766 (* NOTE: leaks scope as currently implemented; this matches
767 the behavior in naming (cf. `do_stmt` in naming/naming.ml).
769 let (env, (tb, te)) =
770 LEnv.stash_and_do env [C.Continue; C.Break; C.Do] (fun env ->
771 let env = LEnv.save_and_merge_next_in_cont env C.Do in
772 let (env, _) = block env b in
773 (* saving the locals in continue here even if there is no continue
774 * statement because they must be merged at the end of the loop, in
775 * case there is no iteration *)
776 let env = LEnv.save_and_merge_next_in_cont env C.Continue in
777 let (env, tb) =
778 infer_loop env (fun env ->
779 let env =
780 LEnv.update_next_from_conts env [C.Continue; C.Next]
782 (* The following is necessary in case there is an assignment in the
783 * expression *)
784 let (env, te, _) = expr env e in
785 let (env, _lset) = condition env true te in
786 let env = LEnv.update_next_from_conts env [C.Do; C.Next] in
787 let (env, tb) = block env b in
788 (env, tb))
790 let env = LEnv.update_next_from_conts env [C.Continue; C.Next] in
791 let (env, te, _) = expr env e in
792 let (env, _lset) = condition env false te in
793 let env = LEnv.update_next_from_conts env [C.Break; C.Next] in
794 (env, (tb, te)))
796 (env, Aast.Do (tb, te))
797 | While (e, b) ->
798 let (env, (te, tb, refinement_map)) =
799 LEnv.stash_and_do env [C.Continue; C.Break] (fun env ->
800 let env = LEnv.save_and_merge_next_in_cont env C.Continue in
801 let (env, tb) =
802 infer_loop env (fun env ->
803 let env =
804 LEnv.update_next_from_conts env [C.Continue; C.Next]
806 let join_map = annot_map env in
807 (* The following is necessary in case there is an assignment in the
808 * expression *)
809 let (env, te, _) = expr env e in
810 let (env, lset) = condition env true te in
811 let refinement_map = refinement_annot_map env lset in
812 (* TODO TAST: avoid repeated generation of block *)
813 let (env, tb) = block env b in
815 (* Annotate loop body with join and refined environments *)
816 let assert_env_blk = assert_env_blk ~pos ~at:`Start in
817 let tb = assert_env_blk Aast.Refinement refinement_map tb in
818 let tb = assert_env_blk Aast.Join join_map tb in
820 (env, tb))
822 let env = LEnv.update_next_from_conts env [C.Continue; C.Next] in
823 let (env, te, _) = expr env e in
824 let (env, lset) = condition env false te in
825 let refinement_map_at_exit = refinement_annot_map env lset in
826 let env = LEnv.update_next_from_conts env [C.Break; C.Next] in
827 (env, (te, tb, refinement_map_at_exit)))
829 let while_st = Aast.While (te, tb) in
830 (* Export the refined environment after the exit condition holds *)
831 let while_st =
832 assert_env_stmt ~pos ~at:`End Aast.Refinement refinement_map while_st
834 (env, while_st)
835 | Using
837 us_has_await = has_await;
838 us_exprs = (loc, using_clause);
839 us_block = using_block;
840 us_is_block_scoped;
841 } ->
842 let (env, typed_using_clause, using_vars) =
843 check_using_clause env has_await using_clause
845 let (env, typed_using_block) = block env using_block in
846 (* Remove any using variables from the environment, as they should not
847 * be in scope outside the block *)
848 let env = List.fold_left using_vars ~init:env ~f:Env.unset_local in
849 ( env,
850 Aast.Using
851 Aast.
853 us_has_await = has_await;
854 us_exprs = (loc, typed_using_clause);
855 us_block = typed_using_block;
856 us_is_block_scoped;
858 | For (e1, e2, e3, b) ->
859 let e2 =
860 match e2 with
861 | Some e2 -> e2
862 | None -> (Pos.none, True)
864 let (env, (te1, te2, te3, tb, refinement_map)) =
865 LEnv.stash_and_do env [C.Continue; C.Break] (fun env ->
866 (* For loops leak their initalizer, but nothing that's defined in the
867 body
869 let (env, te1, _) = exprs env e1 in
870 (* initializer *)
871 let env = LEnv.save_and_merge_next_in_cont env C.Continue in
872 let (env, (tb, te3)) =
873 infer_loop env (fun env ->
874 (* The following is necessary in case there is an assignment in the
875 * expression *)
876 let (env, te2, _) = expr env e2 in
877 let (env, lset) = condition env true te2 in
878 let refinement_map = refinement_annot_map env lset in
879 let (env, tb) = block env b in
880 let env =
881 LEnv.update_next_from_conts env [C.Continue; C.Next]
883 let join_map = annot_map env in
884 let (env, te3, _) = exprs env e3 in
886 (* Export the join and refinement environments *)
887 let assert_env_blk = assert_env_blk ~pos ~at:`Start in
888 let tb = assert_env_blk Aast.Refinement refinement_map tb in
889 let tb = assert_env_blk Aast.Join join_map tb in
891 (env, (tb, te3)))
893 let env = LEnv.update_next_from_conts env [C.Continue; C.Next] in
894 let (env, te2, _) = expr env e2 in
895 let (env, lset) = condition env false te2 in
896 let refinement_map_at_exit = refinement_annot_map env lset in
897 let env = LEnv.update_next_from_conts env [C.Break; C.Next] in
898 (env, (te1, te2, te3, tb, refinement_map_at_exit)))
900 let for_st = Aast.For (te1, Some te2, te3, tb) in
901 let for_st =
902 assert_env_stmt ~pos ~at:`End Aast.Refinement refinement_map for_st
904 (env, for_st)
905 | Switch (((pos, _) as e), cl) ->
906 let (env, te, ty) = expr env e in
907 (* NB: A 'continue' inside a 'switch' block is equivalent to a 'break'.
908 * See the note in
909 * http://php.net/manual/en/control-structures.continue.php *)
910 let (env, (te, tcl)) =
911 LEnv.stash_and_do env [C.Continue; C.Break] (fun env ->
912 let parent_locals = LEnv.get_all_locals env in
913 let case_list env = case_list parent_locals ty env pos cl in
914 let (env, tcl) = Env.in_case env case_list in
915 let env =
916 LEnv.update_next_from_conts env [C.Continue; C.Break; C.Next]
918 (env, (te, tcl)))
920 (env, Aast.Switch (te, tcl))
921 | Foreach (e1, e2, b) ->
922 (* It's safe to do foreach over a disposable, as no leaking is possible *)
923 let (env, te1, ty1) = expr ~accept_using_var:true env e1 in
924 let (env, (te1, te2, tb)) =
925 LEnv.stash_and_do env [C.Continue; C.Break] (fun env ->
926 let env = LEnv.save_and_merge_next_in_cont env C.Continue in
927 let (env, tk, tv) = as_expr env ty1 (fst e1) e2 in
928 let (env, (te2, tb)) =
929 infer_loop env (fun env ->
930 let env =
931 LEnv.update_next_from_conts env [C.Continue; C.Next]
933 let join_map = annot_map env in
934 let (env, te2) = bind_as_expr env (fst e1) tk tv e2 in
935 let (env, tb) = block env b in
936 (* Export the join environment *)
937 let tb = assert_env_blk ~pos ~at:`Start Aast.Join join_map tb in
938 (env, (te2, tb)))
940 let env =
941 LEnv.update_next_from_conts env [C.Continue; C.Break; C.Next]
943 (env, (te1, te2, tb)))
945 (env, Aast.Foreach (te1, te2, tb))
946 | Try (tb, cl, fb) ->
947 let (env, ttb, tcl, tfb) = try_catch env tb cl fb in
948 (env, Aast.Try (ttb, tcl, tfb))
949 | Awaitall (el, b) ->
950 let env = might_throw env in
951 let (env, el) =
952 List.fold_left el ~init:(env, []) ~f:(fun (env, tel) (e1, e2) ->
953 let (env, te2, ty2) = expr env e2 ~allow_awaitable:true in
954 let (env, ty2) =
955 Async.overload_extract_from_awaitable env (fst e2) ty2
957 match e1 with
958 | Some e1 ->
959 let (env, _, _) = assign (fst e1) env (fst e1, Lvar e1) ty2 in
960 (env, (Some e1, te2) :: tel)
961 | None -> (env, (None, te2) :: tel))
963 let (env, b) = block env b in
964 (env, Aast.Awaitall (el, b))
965 | Throw e ->
966 let p = fst e in
967 let (env, te, ty) = expr env e in
968 let env = coerce_to_throwable p env ty in
969 let env = move_and_merge_next_in_catch env in
970 (env, Aast.Throw te)
971 | Continue ->
972 let env = LEnv.move_and_merge_next_in_cont env C.Continue in
973 (env, Aast.Continue)
974 | Break ->
975 let env = LEnv.move_and_merge_next_in_cont env C.Break in
976 (env, Aast.Break)
977 | Block _
978 | Markup _ ->
979 failwith
980 "Unexpected nodes in AST. These nodes should have been removed in naming."
982 and branch :
983 type res. env -> (env -> env * res) -> (env -> env * res) -> env * res * res
985 fun env branch1 branch2 ->
986 let parent_lenv = env.lenv in
987 let (env, tbr1) = branch1 env in
988 let lenv1 = env.lenv in
989 let env = { env with lenv = parent_lenv } in
990 let (env, tbr2) = branch2 env in
991 let lenv2 = env.lenv in
992 let env = LEnv.union_lenvs env parent_lenv lenv1 lenv2 in
993 (env, tbr1, tbr2)
995 and finally_cont fb env ctx =
996 (* The only locals in scope are the ones from the current continuation *)
997 let env = Env.env_with_locals env @@ CMap.singleton C.Next ctx in
998 let (env, _tfb) = block env fb in
999 (env, LEnv.get_all_locals env)
1001 and finally env fb =
1002 match fb with
1003 | [] ->
1004 let env = LEnv.update_next_from_conts env [C.Next; C.Finally] in
1005 (env, [])
1006 | _ ->
1007 let parent_locals = LEnv.get_all_locals env in
1008 (* First typecheck the finally block against all continuations merged
1009 * together.
1010 * During this phase, record errors found in the finally block, but discard
1011 * the resulting environment. *)
1012 let all_conts = Env.all_continuations env in
1013 let env = LEnv.update_next_from_conts env all_conts in
1014 let (env, tfb) = block env fb in
1015 let env = LEnv.restore_conts_from env parent_locals all_conts in
1016 (* Second, typecheck the finally block once against each continuation. This
1017 * helps be more clever about what each continuation will be after the
1018 * finally block.
1019 * We don't want to record errors during this phase, because certain types
1020 * of errors will fire wrongly. For example, if $x is nullable in some
1021 * continuations but not in others, then we must use `?->` on $x, but an
1022 * error will fire when typechecking the finally block againts continuations
1023 * where $x is non-null. *)
1024 let finally_cont env _key = finally_cont fb env in
1025 let (env, locals_map) =
1026 Errors.ignore_ (fun () -> CMap.map_env finally_cont env parent_locals)
1028 let union env _key = LEnv.union_contextopts env in
1029 let (env, locals) = Try.finally_merge union env locals_map all_conts in
1030 (Env.env_with_locals env locals, tfb)
1032 and try_catch env tb cl fb =
1033 let parent_locals = LEnv.get_all_locals env in
1034 let env =
1035 LEnv.drop_conts env [C.Break; C.Continue; C.Exit; C.Catch; C.Finally]
1037 let (env, (ttb, tcb)) =
1038 Env.in_try env (fun env ->
1039 let (env, ttb) = block env tb in
1040 let env = LEnv.move_and_merge_next_in_cont env C.Finally in
1041 let catchctx = LEnv.get_cont_option env C.Catch in
1042 let (env, lenvtcblist) = List.map_env env ~f:(catch catchctx) cl in
1043 let (lenvl, tcb) = List.unzip lenvtcblist in
1044 let env = LEnv.union_lenv_list env env.lenv lenvl in
1045 let env = LEnv.move_and_merge_next_in_cont env C.Finally in
1046 (env, (ttb, tcb)))
1048 let (env, tfb) = finally env fb in
1049 let env = LEnv.update_next_from_conts env [C.Finally] in
1050 let env = LEnv.drop_cont env C.Finally in
1051 let env =
1052 LEnv.restore_and_merge_conts_from
1054 parent_locals
1055 [C.Break; C.Continue; C.Exit; C.Catch; C.Finally]
1057 (env, ttb, tcb, tfb)
1059 and case_list parent_locals ty env switch_pos cl =
1060 let initialize_next_cont env =
1061 let env = LEnv.restore_conts_from env parent_locals [C.Next] in
1062 let env = LEnv.update_next_from_conts env [C.Next; C.Fallthrough] in
1063 LEnv.drop_cont env C.Fallthrough
1065 let check_fallthrough env switch_pos case_pos block rest_of_list ~is_default =
1066 if (not (List.is_empty block)) && not (List.is_empty rest_of_list) then
1067 match LEnv.get_cont_option env C.Next with
1068 | Some _ ->
1069 if is_default then
1070 Errors.default_fallthrough switch_pos
1071 else
1072 Errors.case_fallthrough switch_pos case_pos
1073 | None -> ()
1075 let env =
1076 (* below, we try to find out if the switch is exhaustive *)
1077 let has_default =
1078 List.exists cl ~f:(function
1079 | Default _ -> true
1080 | _ -> false)
1082 let (env, ty) =
1083 (* If it hasn't got a default clause then we need to solve type variables
1084 * in order to check for an enum *)
1085 if has_default then
1086 Env.expand_type env ty
1087 else
1088 Typing_solver.expand_type_and_solve
1090 ~description_of_expected:"a value"
1091 switch_pos
1093 Errors.unify_error
1095 (* leverage that enums are checked for exhaustivity *)
1096 let is_enum =
1097 let top_type =
1098 MakeType.class_type
1099 Reason.Rnone
1100 SN.Classes.cHH_BuiltinEnum
1101 [MakeType.mixed Reason.Rnone]
1103 Typing_subtype.is_sub_type_for_coercion env ty top_type
1105 (* register that the runtime may throw in case we cannot prove
1106 that the switch is exhaustive *)
1107 if has_default || is_enum then
1109 else
1110 might_throw env
1112 let rec case_list env = function
1113 | [] -> (env, [])
1114 | Default (pos, b) :: rl ->
1115 let env = initialize_next_cont env in
1116 let (env, tb) = block env b in
1117 check_fallthrough env switch_pos pos b rl ~is_default:true;
1118 let (env, tcl) = case_list env rl in
1119 (env, Aast.Default (pos, tb) :: tcl)
1120 | Case (((pos, _) as e), b) :: rl ->
1121 let env = initialize_next_cont env in
1122 let (env, te, _) = expr env e ~allow_awaitable:(*?*) false in
1123 let (env, tb) = block env b in
1124 check_fallthrough env switch_pos pos b rl ~is_default:false;
1125 let (env, tcl) = case_list env rl in
1126 (env, Aast.Case (te, tb) :: tcl)
1128 case_list env cl
1130 and catch catchctx env (sid, exn_lvar, b) =
1131 let env = LEnv.replace_cont env C.Next catchctx in
1132 let cid = CI sid in
1133 let ety_p = fst sid in
1134 let (env, _, _, _) = instantiable_cid ety_p env cid [] in
1135 let (env, _tal, _te, ety) =
1136 static_class_id ~check_constraints:false ety_p env [] cid
1138 let env = coerce_to_throwable ety_p env ety in
1139 let (p, x) = exn_lvar in
1140 let env = set_valid_rvalue p env x ety in
1141 let (env, tb) = block env b in
1142 (env, (env.lenv, (sid, exn_lvar, tb)))
1144 and as_expr env ty1 pe e =
1145 let env = Env.open_tyvars env pe in
1146 let (env, tv) = Env.fresh_type env pe in
1147 let (env, expected_ty, tk, tv) =
1148 match e with
1149 | As_v _ ->
1150 let tk = MakeType.mixed Reason.Rnone in
1151 (env, MakeType.traversable (Reason.Rforeach pe) tv, tk, tv)
1152 | As_kv _ ->
1153 let (env, tk) = Env.fresh_type env pe in
1154 (env, MakeType.keyed_traversable (Reason.Rforeach pe) tk tv, tk, tv)
1155 | Await_as_v _ ->
1156 let tk = MakeType.mixed Reason.Rnone in
1157 (env, MakeType.async_iterator (Reason.Rasyncforeach pe) tv, tk, tv)
1158 | Await_as_kv _ ->
1159 let (env, tk) = Env.fresh_type env pe in
1160 ( env,
1161 MakeType.async_keyed_iterator (Reason.Rasyncforeach pe) tk tv,
1163 tv )
1165 let rec distribute_union env ty =
1166 let (env, ty) = Env.expand_type env ty in
1167 match get_node ty with
1168 | Tunion tyl -> List.fold tyl ~init:env ~f:distribute_union
1169 | _ ->
1170 if SubType.is_sub_type_for_union env ty (MakeType.dynamic Reason.Rnone)
1171 then
1172 let env = SubType.sub_type env ty tk Errors.unify_error in
1173 let env = SubType.sub_type env ty tv Errors.unify_error in
1175 else
1176 let ur = Reason.URforeach in
1177 Type.sub_type pe ur env ty expected_ty Errors.unify_error
1179 let env = distribute_union env ty1 in
1180 let env = Env.set_tyvar_variance env expected_ty in
1181 (Typing_solver.close_tyvars_and_solve env Errors.unify_error, tk, tv)
1183 and bind_as_expr env p ty1 ty2 aexpr =
1184 match aexpr with
1185 | As_v ev ->
1186 let (env, te, _) = assign p env ev ty2 in
1187 (env, Aast.As_v te)
1188 | Await_as_v (p, ev) ->
1189 let (env, te, _) = assign p env ev ty2 in
1190 (env, Aast.Await_as_v (p, te))
1191 | As_kv ((p, Lvar ((_, k) as id)), ev) ->
1192 let env = set_valid_rvalue p env k ty1 in
1193 let (env, te, _) = assign p env ev ty2 in
1194 let tk = Tast.make_typed_expr p ty1 (Aast.Lvar id) in
1195 (env, Aast.As_kv (tk, te))
1196 | Await_as_kv (p, (p1, Lvar ((_, k) as id)), ev) ->
1197 let env = set_valid_rvalue p env k ty1 in
1198 let (env, te, _) = assign p env ev ty2 in
1199 let tk = Tast.make_typed_expr p1 ty1 (Aast.Lvar id) in
1200 (env, Aast.Await_as_kv (p, tk, te))
1201 | _ ->
1202 (* TODO Probably impossible, should check that *)
1203 assert false
1205 and expr
1206 ?(expected : ExpectedTy.t option)
1207 ?(accept_using_var = false)
1208 ?(is_using_clause = false)
1209 ?(valkind = `other)
1210 ?(check_defined = true)
1211 ?in_await
1212 ~allow_awaitable
1214 ((p, _) as e) =
1216 begin
1217 match expected with
1218 | None -> ()
1219 | Some ExpectedTy.{ reason = r; ty = { et_type = ty; _ }; _ } ->
1220 Typing_log.(
1221 log_with_level env "typing" 1 (fun () ->
1222 log_types
1226 Log_head
1227 ( "Typing.expr " ^ Typing_reason.string_of_ureason r,
1228 [Log_type ("expected_ty", ty)] );
1230 end;
1231 raw_expr
1232 ~accept_using_var
1233 ~is_using_clause
1234 ~valkind
1235 ~check_defined
1236 ?in_await
1237 ?expected
1238 ~allow_awaitable
1241 with Inf.InconsistentTypeVarState _ as e ->
1242 (* we don't want to catch unwanted exceptions here, eg Timeouts *)
1243 Errors.exception_occurred p (Exception.wrap e);
1244 make_result env p Aast.Any @@ err_witness env p
1246 (* Some (legacy) special functions are allowed in initializers,
1247 therefore treat them as pure and insert the matching capabilities. *)
1248 and expr_with_pure_coeffects
1249 ?(expected : ExpectedTy.t option) ~allow_awaitable env e =
1250 let pure = MakeType.mixed (Reason.Rwitness (fst e)) in
1251 let (env, (te, ty)) =
1252 with_special_coeffects env pure pure @@ fun env ->
1253 expr env e ?expected ~allow_awaitable |> triple_to_pair
1255 (env, te, ty)
1257 and raw_expr
1258 ?(accept_using_var = false)
1259 ?(is_using_clause = false)
1260 ?(expected : ExpectedTy.t option)
1261 ?lhs_of_null_coalesce
1262 ?(valkind = `other)
1263 ?(check_defined = true)
1264 ?in_await
1265 ~allow_awaitable
1268 debug_last_pos := fst e;
1269 expr_
1270 ~accept_using_var
1271 ~is_using_clause
1272 ?expected
1273 ?lhs_of_null_coalesce
1274 ?in_await
1275 ~allow_awaitable
1276 ~valkind
1277 ~check_defined
1281 and lvalue env e =
1282 let valkind = `lvalue in
1283 expr_ ~valkind ~check_defined:false env e ~allow_awaitable:(*?*) false
1285 and lvalues env el =
1286 match el with
1287 | [] -> (env, [], [])
1288 | e :: el ->
1289 let (env, te, ty) = lvalue env e in
1290 let (env, tel, tyl) = lvalues env el in
1291 (env, te :: tel, ty :: tyl)
1293 (* These functions invoke special printing functions for Typing_env. They do not
1294 * appear in user code, but we still check top level function calls against their
1295 * names. *)
1296 and typing_env_pseudofunctions =
1297 SN.PseudoFunctions.(
1298 String.Hash_set.of_list
1299 ~growth_allowed:false
1300 [hh_show; hh_show_env; hh_log_level; hh_force_solve; hh_loop_forever])
1302 and loop_forever env =
1303 (* forever = up to 10 minutes, to avoid accidentally stuck processes *)
1304 for i = 1 to 600 do
1305 (* Look up things in shared memory occasionally to have a chance to be
1306 * interrupted *)
1307 match Env.get_class env "FOR_TEST_ONLY" with
1308 | None -> Unix.sleep 1
1309 | _ -> assert false
1310 done;
1311 Utils.assert_false_log_backtrace
1312 (Some "hh_loop_forever was looping for more than 10 minutes")
1314 (* $x ?? 0 is handled similarly to $x ?: 0, except that the latter will also
1315 * look for sketchy null checks in the condition. *)
1316 (* TODO TAST: type refinement should be made explicit in the typed AST *)
1317 and eif env ~(expected : ExpectedTy.t option) ?in_await p c e1 e2 =
1318 let condition = condition ~lhs_of_null_coalesce:false in
1319 let (env, tc, tyc) =
1320 raw_expr ~lhs_of_null_coalesce:false env c ~allow_awaitable:false
1322 let parent_lenv = env.lenv in
1323 let (env, _lset) = condition env true tc in
1324 let (env, te1, ty1) =
1325 match e1 with
1326 | None ->
1327 let (env, ty) = Typing_solver.non_null env p tyc in
1328 (env, None, ty)
1329 | Some e1 ->
1330 let (env, te1, ty1) =
1331 expr ?expected ?in_await env e1 ~allow_awaitable:true
1333 (env, Some te1, ty1)
1335 let lenv1 = env.lenv in
1336 let env = { env with lenv = parent_lenv } in
1337 let (env, _lset) = condition env false tc in
1338 let (env, te2, ty2) = expr ?expected ?in_await env e2 ~allow_awaitable:true in
1339 let lenv2 = env.lenv in
1340 let env = LEnv.union_lenvs env parent_lenv lenv1 lenv2 in
1341 let (env, ty) = Union.union env ty1 ty2 in
1342 make_result env p (Aast.Eif (tc, te1, te2)) ty
1344 and is_parameter env x = Local_id.Map.mem x (Env.get_params env)
1346 and check_escaping_var env (pos, x) =
1347 if Env.is_using_var env x then
1348 if Local_id.equal x this then
1349 Errors.escaping_this pos
1350 else if is_parameter env x then
1351 Errors.escaping_disposable_parameter pos
1352 else
1353 Errors.escaping_disposable pos
1354 else
1357 and exprs
1358 ?(accept_using_var = false)
1359 ?(expected : ExpectedTy.t option)
1360 ?(valkind = `other)
1361 ?(check_defined = true)
1362 ~allow_awaitable
1364 el =
1365 match el with
1366 | [] -> (env, [], [])
1367 | e :: el ->
1368 let (env, te, ty) =
1369 expr
1370 ~accept_using_var
1371 ?expected
1372 ~valkind
1373 ~check_defined
1376 ~allow_awaitable
1378 let (env, tel, tyl) =
1379 exprs
1380 ~accept_using_var
1381 ?expected
1382 ~valkind
1383 ~check_defined
1386 ~allow_awaitable
1388 (env, te :: tel, ty :: tyl)
1390 and exprs_expected (pos, ur, expected_tyl) env el =
1391 match (el, expected_tyl) with
1392 | ([], _) -> (env, [], [])
1393 | (e :: el, expected_ty :: expected_tyl) ->
1394 let expected = ExpectedTy.make pos ur expected_ty in
1395 let (env, te, ty) = expr ~expected env e ~allow_awaitable:(*?*) false in
1396 let (env, tel, tyl) = exprs_expected (pos, ur, expected_tyl) env el in
1397 (env, te :: tel, ty :: tyl)
1398 | (el, []) -> exprs env el ~allow_awaitable:(*?*) false
1400 and make_result env p te ty =
1401 (* Set the variance of any type variables that were generated according
1402 * to how they appear in the expression type *)
1403 let env = Env.set_tyvar_variance env ty in
1404 (env, Tast.make_typed_expr p ty te, ty)
1406 and localize_targ env ta =
1407 let pos = fst ta in
1408 let (env, targ) = Phase.localize_targ ~check_well_kinded:true env ta in
1409 (env, targ, ExpectedTy.make pos Reason.URhint (fst targ))
1411 and set_function_pointer ty =
1412 match get_node ty with
1413 | Tfun ft ->
1414 let ft = set_ft_is_function_pointer ft true in
1415 mk (get_reason ty, Tfun ft)
1416 | _ -> ty
1418 and expr_
1419 ?(expected : ExpectedTy.t option)
1420 ?(accept_using_var = false)
1421 ?(is_using_clause = false)
1422 ?lhs_of_null_coalesce
1423 ?in_await
1424 ~allow_awaitable
1425 ~(valkind : [> `lvalue | `lvalue_subexpr | `other ])
1426 ~check_defined
1428 ((p, e) as outer) =
1429 let env = Env.open_tyvars env p in
1430 (fun (env, te, ty) ->
1431 let env = Typing_solver.close_tyvars_and_solve env Errors.unify_error in
1432 (env, te, ty))
1434 let expr ?(allow_awaitable = allow_awaitable) =
1435 expr ~check_defined ~allow_awaitable
1437 let exprs = exprs ~check_defined ~allow_awaitable in
1438 let raw_expr ?(allow_awaitable = allow_awaitable) =
1439 raw_expr ~check_defined ~allow_awaitable
1442 * Given a list of types, computes their supertype. If any of the types are
1443 * unknown (e.g., comes from PHP), the supertype will be Typing_utils.tany env.
1445 let compute_supertype
1446 ~(expected : ExpectedTy.t option) ~reason ~use_pos r env tys =
1447 let (env, supertype) =
1448 match expected with
1449 | None -> Env.fresh_type_reason env r
1450 | Some ExpectedTy.{ ty = { et_type = ty; _ }; _ } -> (env, ty)
1452 match get_node supertype with
1453 (* No need to check individual subtypes if expected type is mixed or any! *)
1454 | Tany _ -> (env, supertype)
1455 | _ ->
1456 let subtype_value env ty =
1457 Type.sub_type use_pos reason env ty supertype Errors.unify_error
1459 let env = List.fold_left tys ~init:env ~f:subtype_value in
1461 List.exists tys (fun ty ->
1462 equal_locl_ty_ (get_node ty) (Typing_utils.tany env))
1463 then
1464 (* If one of the values comes from PHP land, we have to be conservative
1465 * and consider that we don't know what the type of the values are. *)
1466 (env, Typing_utils.mk_tany env p)
1467 else
1468 (env, supertype)
1471 * Given a 'a list and a method to extract an expr and its ty from a 'a, this
1472 * function extracts a list of exprs from the list, and computes the supertype
1473 * of all of the expressions' tys.
1475 let compute_exprs_and_supertype
1476 ~(expected : ExpectedTy.t option)
1477 ?(reason = Reason.URarray_value)
1478 ~use_pos
1482 extract_expr_and_ty =
1483 let (env, exprs_and_tys) =
1484 List.map_env env l (extract_expr_and_ty ~expected)
1486 let (exprs, tys) = List.unzip exprs_and_tys in
1487 let (env, supertype) =
1488 compute_supertype ~expected ~reason ~use_pos r env tys
1490 (env, exprs, supertype)
1492 let forget_fake_members env p callexpr =
1493 (* Some functions are well known to not change the types of members, e.g.
1494 * `is_null`.
1495 * There are a lot of usages like
1496 * if (!is_null($x->a) && !is_null($x->a->b))
1497 * where the second is_null call invalidates the first condition.
1498 * This function is a bit best effort. Add stuff here when you want
1499 * To avoid adding too many undue HH_FIXMEs. *)
1500 match callexpr with
1501 | (_, Id (_, func))
1502 when String.equal func SN.StdlibFunctions.is_null
1503 || String.equal func SN.PseudoFunctions.isset ->
1505 | _ -> Env.forget_members env Reason.(Blame (p, BScall))
1507 let check_call
1508 ~is_using_clause
1509 ~(expected : ExpectedTy.t option)
1510 ?in_await
1514 explicit_targs
1516 unpacked_element =
1517 let (env, te, ty) =
1518 dispatch_call
1519 ~is_using_clause
1520 ~expected
1521 ?in_await
1525 explicit_targs
1527 unpacked_element
1529 let env = forget_fake_members env p e in
1530 (env, te, ty)
1532 match e with
1533 | Hole _
1534 | Import _
1535 | Collection _ ->
1536 failwith "AST should not contain these nodes"
1537 | Omitted ->
1538 let ty = Typing_utils.mk_tany env p in
1539 make_result env p Aast.Omitted ty
1540 | Any -> expr_error env (Reason.Rwitness p) outer
1541 | Varray (th, el)
1542 | ValCollection (_, th, el) ->
1543 let (get_expected_kind, name, subtype_val, make_expr, make_ty) =
1544 match e with
1545 | ValCollection (kind, _, _) ->
1546 let class_name = Nast.vc_kind_to_name kind in
1547 let subtype_val =
1548 match kind with
1549 | Set
1550 | ImmSet
1551 | Keyset ->
1552 arraykey_value p class_name true
1553 | Vector
1554 | ImmVector
1555 | Vec ->
1556 array_value
1558 ( get_vc_inst kind,
1559 class_name,
1560 subtype_val,
1561 (fun th elements -> Aast.ValCollection (kind, th, elements)),
1562 fun value_ty ->
1563 MakeType.class_type (Reason.Rwitness p) class_name [value_ty] )
1564 | Varray _ ->
1565 let unification =
1566 TypecheckerOptions.hack_arr_dv_arrs (Env.get_tcopt env)
1568 if unification then
1569 ( get_vc_inst Vec,
1570 "varray",
1571 array_value,
1572 (fun th elements -> Aast.ValCollection (Vec, th, elements)),
1573 fun value_ty ->
1574 MakeType.varray ~unification (Reason.Rhack_arr_dv_arrs p) value_ty
1576 else
1577 ( get_varray_inst,
1578 "varray",
1579 array_value,
1580 (fun th elements -> Aast.Varray (th, elements)),
1581 fun value_ty ->
1582 MakeType.varray ~unification (Reason.Rwitness p) value_ty )
1583 | _ ->
1584 (* The parent match makes this case impossible *)
1585 failwith "impossible match case"
1587 (* Use expected type to determine expected element type *)
1588 let (env, elem_expected, th) =
1589 match th with
1590 | Some (_, tv) ->
1591 let (env, tv, tv_expected) = localize_targ env tv in
1592 (env, Some tv_expected, Some tv)
1593 | _ ->
1594 begin
1595 match expand_expected_and_get_node env expected with
1596 | (env, Some (pos, ur, ety, _)) ->
1597 begin
1598 match get_expected_kind ety with
1599 | Some vty -> (env, Some (ExpectedTy.make pos ur vty), None)
1600 | None -> (env, None, None)
1602 | _ -> (env, None, None)
1605 let (env, tel, elem_ty) =
1606 compute_exprs_and_supertype
1607 ~expected:elem_expected
1608 ~use_pos:p
1609 ~reason:Reason.URvector
1610 (Reason.Rtype_variable_generics (p, "T", strip_ns name))
1613 subtype_val
1615 make_result env p (make_expr th tel) (make_ty elem_ty)
1616 | Darray (th, l)
1617 | KeyValCollection (_, th, l) ->
1618 let (get_expected_kind, name, make_expr, make_ty) =
1619 match e with
1620 | KeyValCollection (kind, _, _) ->
1621 let class_name = Nast.kvc_kind_to_name kind in
1622 ( get_kvc_inst p kind,
1623 class_name,
1624 (fun th pairs -> Aast.KeyValCollection (kind, th, pairs)),
1625 (fun k v -> MakeType.class_type (Reason.Rwitness p) class_name [k; v])
1627 | Darray _ ->
1628 let unification =
1629 TypecheckerOptions.hack_arr_dv_arrs (Env.get_tcopt env)
1631 let name = "darray" in
1632 if unification then
1633 ( get_kvc_inst p Dict,
1634 name,
1635 (fun th pairs -> Aast.KeyValCollection (Dict, th, pairs)),
1636 fun k v ->
1637 MakeType.darray ~unification (Reason.Rhack_arr_dv_arrs p) k v )
1638 else
1639 ( get_darray_inst p,
1640 name,
1641 (fun th pairs -> Aast.Darray (th, pairs)),
1642 (fun k v -> MakeType.darray ~unification (Reason.Rwitness p) k v) )
1643 | _ ->
1644 (* The parent match makes this case impossible *)
1645 failwith "impossible match case"
1647 (* Use expected type to determine expected key and value types *)
1648 let (env, kexpected, vexpected, th) =
1649 match th with
1650 | Some ((_, tk), (_, tv)) ->
1651 let (env, tk, tk_expected) = localize_targ env tk in
1652 let (env, tv, tv_expected) = localize_targ env tv in
1653 (env, Some tk_expected, Some tv_expected, Some (tk, tv))
1654 | _ ->
1655 (* no explicit typehint, fallback to supplied expect *)
1656 begin
1657 match expand_expected_and_get_node env expected with
1658 | (env, Some (pos, reason, ety, _)) ->
1659 begin
1660 match get_expected_kind ety with
1661 | Some (kty, vty) ->
1662 let k_expected = ExpectedTy.make pos reason kty in
1663 let v_expected = ExpectedTy.make pos reason vty in
1664 (env, Some k_expected, Some v_expected, None)
1665 | None -> (env, None, None, None)
1667 | _ -> (env, None, None, None)
1670 let (kl, vl) = List.unzip l in
1671 let (env, tkl, k) =
1672 compute_exprs_and_supertype
1673 ~expected:kexpected
1674 ~use_pos:p
1675 ~reason:Reason.URkey
1676 (Reason.Rtype_variable_generics (p, "Tk", strip_ns name))
1679 (arraykey_value p name false)
1681 let (env, tvl, v) =
1682 compute_exprs_and_supertype
1683 ~expected:vexpected
1684 ~use_pos:p
1685 ~reason:Reason.URvalue
1686 (Reason.Rtype_variable_generics (p, "Tv", strip_ns name))
1689 array_value
1691 let pairs = List.zip_exn tkl tvl in
1692 make_result env p (make_expr th pairs) (make_ty k v)
1693 | Clone e ->
1694 let (env, te, ty) = expr env e in
1695 (* Clone only works on objects; anything else fatals at runtime.
1696 * Constructing a call `e`->__clone() checks that `e` is an object and
1697 * checks coeffects on __clone *)
1698 let (env, (tfty, _tal)) =
1699 TOG.obj_get
1700 ~obj_pos:(fst e)
1701 ~is_method:true
1702 ~inst_meth:false
1703 ~nullsafe:None
1704 ~coerce_from_ty:None
1705 ~explicit_targs:[]
1706 ~class_id:(CIexpr e)
1707 ~member_id:(p, SN.Members.__clone)
1708 ~on_error:Errors.unify_error
1712 let (env, (_tel, _typed_unpack_element, _ty)) =
1713 call ~expected:None p env tfty [] None
1715 make_result env p (Aast.Clone te) ty
1716 | This ->
1717 if Option.is_none (Env.get_self_ty env) then Errors.this_var_outside_class p;
1718 if not accept_using_var then check_escaping_var env (p, this);
1719 let ty = Env.get_local env this in
1720 let r = Reason.Rwitness p in
1721 let ty = mk (r, TUtils.this_of (mk (r, get_node ty))) in
1722 make_result env p Aast.This ty
1723 | True -> make_result env p Aast.True (MakeType.bool (Reason.Rwitness p))
1724 | False -> make_result env p Aast.False (MakeType.bool (Reason.Rwitness p))
1725 (* TODO TAST: consider checking that the integer is in range. Right now
1726 * it's possible for HHVM to fail on well-typed Hack code
1728 | Int s -> make_result env p (Aast.Int s) (MakeType.int (Reason.Rwitness p))
1729 | Float s ->
1730 make_result env p (Aast.Float s) (MakeType.float (Reason.Rwitness p))
1731 (* TODO TAST: consider introducing a "null" type, and defining ?t to
1732 * be null | t
1734 | Null -> make_result env p Aast.Null (MakeType.null (Reason.Rwitness p))
1735 | String s ->
1736 make_result env p (Aast.String s) (MakeType.string (Reason.Rwitness p))
1737 | String2 idl ->
1738 let (env, tel) = string2 env idl in
1739 make_result env p (Aast.String2 tel) (MakeType.string (Reason.Rwitness p))
1740 | PrefixedString (n, e) ->
1741 if String.( <> ) n "re" then (
1742 Errors.experimental_feature
1744 "String prefixes other than `re` are not yet supported.";
1745 expr_error env Reason.Rnone outer
1746 ) else
1747 let (env, te, ty) = expr env e in
1748 let pe = fst e in
1749 let env = Typing_substring.sub_string pe env ty in
1750 (match snd e with
1751 | String _ ->
1752 begin
1754 make_result
1757 (Aast.PrefixedString (n, te))
1758 (Typing_regex.type_pattern e)
1759 with
1760 | Pcre.Error (Pcre.BadPattern (s, i)) ->
1761 let s = s ^ " [" ^ string_of_int i ^ "]" in
1762 Errors.bad_regex_pattern pe s;
1763 expr_error env (Reason.Rregex pe) e
1764 | Typing_regex.Empty_regex_pattern ->
1765 Errors.bad_regex_pattern pe "This pattern is empty";
1766 expr_error env (Reason.Rregex pe) e
1767 | Typing_regex.Missing_delimiter ->
1768 Errors.bad_regex_pattern pe "Missing delimiter(s)";
1769 expr_error env (Reason.Rregex pe) e
1770 | Typing_regex.Invalid_global_option ->
1771 Errors.bad_regex_pattern pe "Invalid global option(s)";
1772 expr_error env (Reason.Rregex pe) e
1774 | String2 _ ->
1775 Errors.re_prefixed_non_string pe "Strings with embedded expressions";
1776 expr_error env (Reason.Rregex pe) e
1777 | _ ->
1778 Errors.re_prefixed_non_string pe "Non-strings";
1779 expr_error env (Reason.Rregex pe) e)
1780 | Fun_id x ->
1781 let (env, fty, _tal) = fun_type_of_id env x [] [] in
1782 make_result env p (Aast.Fun_id x) fty
1783 | Id ((cst_pos, cst_name) as id) ->
1784 (match Env.get_gconst env cst_name with
1785 | None when Partial.should_check_error (Env.get_mode env) 4106 ->
1786 Errors.unbound_global cst_pos;
1787 let ty = err_witness env cst_pos in
1788 make_result env cst_pos (Aast.Id id) ty
1789 | None -> make_result env p (Aast.Id id) (Typing_utils.mk_tany env cst_pos)
1790 | Some const ->
1791 let (env, ty) =
1792 Phase.localize_with_self env ~ignore_errors:true const.cd_type
1794 make_result env p (Aast.Id id) ty)
1795 | Method_id (instance, meth) ->
1796 (* Method_id is used when creating a "method pointer" using the magic
1797 * inst_meth function.
1799 * Typing this is pretty simple, we just need to check that instance->meth
1800 * is public+not static and then return its type.
1802 let (env, te, ty1) = expr env instance in
1803 let (env, (result, _tal)) =
1804 TOG.obj_get
1805 ~inst_meth:true
1806 ~obj_pos:p
1807 ~is_method:true
1808 ~nullsafe:None
1809 ~coerce_from_ty:None
1810 ~explicit_targs:[]
1811 ~class_id:(CIexpr instance)
1812 ~member_id:meth
1813 ~on_error:Errors.unify_error
1817 let (env, result) =
1818 Env.FakeMembers.check_instance_invalid env instance (snd meth) result
1820 make_result env p (Aast.Method_id (te, meth)) result
1821 | Method_caller (((pos, class_name) as pos_cname), meth_name) ->
1822 (* meth_caller('X', 'foo') desugars to:
1823 * $x ==> $x->foo()
1825 let class_ = Env.get_class env class_name in
1826 (match class_ with
1827 | None -> unbound_name env pos_cname outer
1828 | Some class_ ->
1829 (* Create a class type for the given object instantiated with unresolved
1830 * types for its type parameters.
1832 let () =
1833 if Ast_defs.is_c_trait (Cls.kind class_) then
1834 Errors.meth_caller_trait pos class_name
1836 let (env, tvarl) =
1837 List.map_env env (Cls.tparams class_) (fun env _ ->
1838 Env.fresh_type env p)
1840 let params =
1841 List.map (Cls.tparams class_) (fun { tp_name = (p, n); _ } ->
1842 (* TODO(T69551141) handle type arguments for Tgeneric *)
1843 MakeType.generic (Reason.Rwitness_from_decl p) n)
1845 let obj_type =
1846 MakeType.apply (Reason.Rwitness_from_decl p) pos_cname params
1848 let ety_env =
1850 (Phase.env_with_self env ~on_error:(Errors.invalid_type_hint pos)) with
1851 substs = TUtils.make_locl_subst_for_class_tparams class_ tvarl;
1854 let (env, local_obj_ty) = Phase.localize ~ety_env env obj_type in
1855 let (env, (fty, _tal)) =
1856 TOG.obj_get
1857 ~obj_pos:pos
1858 ~is_method:true
1859 ~nullsafe:None
1860 ~inst_meth:false
1861 ~coerce_from_ty:None
1862 ~explicit_targs:[]
1863 ~class_id:(CI (pos, class_name))
1864 ~member_id:meth_name
1865 ~on_error:Errors.unify_error
1867 local_obj_ty
1869 let (env, fty) = Env.expand_type env fty in
1870 (match deref fty with
1871 | (reason, Tfun ftype) ->
1872 (* We are creating a fake closure:
1873 * function(Class $x, arg_types_of(Class::meth_name))
1874 : return_type_of(Class::meth_name)
1876 let ety_env =
1878 ety_env with
1879 on_error = Errors.leave_unchanged_default_invalid_type_hint_code;
1882 let env =
1883 Phase.check_tparams_constraints
1884 ~use_pos:p
1885 ~ety_env
1887 (Cls.tparams class_)
1889 let local_obj_fp = TUtils.default_fun_param local_obj_ty in
1890 let fty = { ftype with ft_params = local_obj_fp :: ftype.ft_params } in
1891 let caller =
1893 ft_arity = fty.ft_arity;
1894 ft_tparams = fty.ft_tparams;
1895 ft_where_constraints = fty.ft_where_constraints;
1896 ft_params = fty.ft_params;
1897 ft_implicit_params = fty.ft_implicit_params;
1898 ft_ret = fty.ft_ret;
1899 (* propagate 'is_coroutine' from the method being called*)
1900 ft_flags = fty.ft_flags;
1901 ft_ifc_decl = fty.ft_ifc_decl;
1904 make_result
1907 (Aast.Method_caller (pos_cname, meth_name))
1908 (mk (reason, Tfun caller))
1909 | _ ->
1910 (* This can happen if the method lives in PHP *)
1911 make_result
1914 (Aast.Method_caller (pos_cname, meth_name))
1915 (Typing_utils.mk_tany env pos)))
1916 | FunctionPointer (FP_class_const ((cpos, cid), meth), targs) ->
1917 let (env, _, ce, cty) =
1918 static_class_id ~check_constraints:true cpos env [] cid
1920 let (env, (fpty, tal)) =
1921 class_get
1922 ~is_method:true
1923 ~is_const:false
1924 ~incl_tc:false (* What is this? *)
1925 ~coerce_from_ty:None (* What is this? *)
1926 ~explicit_targs:targs
1927 ~is_function_pointer:true
1930 meth
1933 let env = Env.set_tyvar_variance env fpty in
1934 let fpty = set_function_pointer fpty in
1935 make_result
1938 (Aast.FunctionPointer (FP_class_const (ce, meth), tal))
1939 fpty
1940 | Smethod_id ((pc, cid), meth) ->
1941 (* Smethod_id is used when creating a "method pointer" using the magic
1942 * class_meth function.
1944 * Typing this is pretty simple, we just need to check that c::meth is
1945 * public+static and then return its type.
1947 let (class_, classname) =
1948 match cid with
1949 | CIself
1950 | CIstatic ->
1951 (Env.get_self_class env, Env.get_self_id env)
1952 | CI (_, const) when String.equal const SN.PseudoConsts.g__CLASS__ ->
1953 (Env.get_self_class env, Env.get_self_id env)
1954 | CI (_, id) -> (Env.get_class env id, Some id)
1955 | _ -> (None, None)
1957 let classname = Option.value classname ~default:"" in
1958 (match class_ with
1959 | None ->
1960 (* The class given as a static string was not found. *)
1961 unbound_name env (pc, classname) outer
1962 | Some class_ ->
1963 let smethod = Env.get_static_member true env class_ (snd meth) in
1964 (match smethod with
1965 | None ->
1966 (* The static method wasn't found. *)
1967 TOG.smember_not_found
1968 (fst meth)
1969 ~is_const:false
1970 ~is_method:true
1971 ~is_function_pointer:false
1972 class_
1973 (snd meth)
1974 Errors.unify_error;
1975 expr_error env Reason.Rnone outer
1976 | Some ({ ce_type = (lazy ty); ce_pos = (lazy ce_pos); _ } as ce) ->
1977 let () =
1978 if get_ce_abstract ce then
1979 match cid with
1980 | CIstatic -> ()
1981 | _ -> Errors.class_meth_abstract_call classname (snd meth) p ce_pos
1983 let ce_visibility = ce.ce_visibility in
1984 let ce_deprecated = ce.ce_deprecated in
1985 let (env, _tal, te, cid_ty) =
1986 static_class_id ~exact:Exact ~check_constraints:true pc env [] cid
1988 let (env, cid_ty) = Env.expand_type env cid_ty in
1989 let tyargs =
1990 match get_node cid_ty with
1991 | Tclass (_, _, tyargs) -> tyargs
1992 | _ -> []
1994 let ety_env =
1996 type_expansions = [];
1997 substs = TUtils.make_locl_subst_for_class_tparams class_ tyargs;
1998 this_ty = cid_ty;
1999 on_error = Errors.ignore_error;
2002 let r = get_reason ty |> Typing_reason.localize in
2003 (match get_node ty with
2004 | Tfun ft ->
2005 let ft =
2006 Typing_enforceability.compute_enforced_and_pessimize_fun_type env ft
2008 let def_pos = ce_pos in
2009 let (env, tal) =
2010 Phase.localize_targs
2011 ~check_well_kinded:true
2012 ~is_method:true
2013 ~def_pos:ce_pos
2014 ~use_pos:p
2015 ~use_name:(strip_ns (snd meth))
2017 ft.ft_tparams
2020 let (env, ft) =
2021 Phase.(
2022 localize_ft
2023 ~instantiation:
2024 Phase.
2026 use_name = strip_ns (snd meth);
2027 use_pos = p;
2028 explicit_targs = tal;
2030 ~ety_env
2031 ~def_pos:ce_pos
2035 let ty = mk (r, Tfun ft) in
2036 let use_pos = fst meth in
2037 TVis.check_deprecated ~use_pos ~def_pos ce_deprecated;
2038 (match ce_visibility with
2039 | Vpublic -> make_result env p (Aast.Smethod_id (te, meth)) ty
2040 | Vprivate _ ->
2041 Errors.private_class_meth ~def_pos ~use_pos;
2042 expr_error env r outer
2043 | Vprotected _ ->
2044 Errors.protected_class_meth ~def_pos ~use_pos;
2045 expr_error env r outer)
2046 | _ ->
2047 Errors.internal_error p "We have a method which isn't callable";
2048 expr_error env r outer)))
2049 | Lplaceholder p ->
2050 let r = Reason.Rplaceholder p in
2051 let ty = MakeType.void r in
2052 make_result env p (Aast.Lplaceholder p) ty
2053 | Dollardollar _ when phys_equal valkind `lvalue ->
2054 Errors.dollardollar_lvalue p;
2055 expr_error env (Reason.Rwitness p) outer
2056 | Dollardollar id ->
2057 let ty = Env.get_local_check_defined env id in
2058 let env = might_throw env in
2059 make_result env p (Aast.Dollardollar id) ty
2060 | Lvar ((_, x) as id) ->
2061 if not accept_using_var then check_escaping_var env id;
2062 let ty =
2063 if check_defined then
2064 Env.get_local_check_defined env id
2065 else
2066 Env.get_local env x
2068 make_result env p (Aast.Lvar id) ty
2069 | List el ->
2070 let (env, tel, tyl) =
2071 match valkind with
2072 | `lvalue
2073 | `lvalue_subexpr ->
2074 lvalues env el
2075 | `other ->
2076 let (env, expected) = expand_expected_and_get_node env expected in
2077 (match expected with
2078 | Some (pos, ur, _, Ttuple expected_tyl) ->
2079 exprs_expected (pos, ur, expected_tyl) env el
2080 | _ -> exprs env el)
2082 let ty = MakeType.tuple (Reason.Rwitness p) tyl in
2083 make_result env p (Aast.List tel) ty
2084 | Pair (th, e1, e2) ->
2085 let (env, expected1, expected2, th) =
2086 match th with
2087 | Some ((_, t1), (_, t2)) ->
2088 let (env, t1, t1_expected) = localize_targ env t1 in
2089 let (env, t2, t2_expected) = localize_targ env t2 in
2090 (env, Some t1_expected, Some t2_expected, Some (t1, t2))
2091 | None ->
2092 (* Use expected type to determine expected element types *)
2093 (match expand_expected_and_get_node env expected with
2094 | (env, Some (pos, reason, _ty, Tclass ((_, k), _, [ty1; ty2])))
2095 when String.equal k SN.Collections.cPair ->
2096 let ty1_expected = ExpectedTy.make pos reason ty1 in
2097 let ty2_expected = ExpectedTy.make pos reason ty2 in
2098 (env, Some ty1_expected, Some ty2_expected, None)
2099 | _ -> (env, None, None, None))
2101 let (env, te1, ty1) = expr ?expected:expected1 env e1 in
2102 let (env, te2, ty2) = expr ?expected:expected2 env e2 in
2103 let p1 = fst e1 in
2104 let p2 = fst e2 in
2105 let (env, ty1) =
2106 compute_supertype
2107 ~expected:expected1
2108 ~reason:Reason.URpair_value
2109 ~use_pos:p1
2110 (Reason.Rtype_variable_generics (p1, "T1", "Pair"))
2112 [ty1]
2114 let (env, ty2) =
2115 compute_supertype
2116 ~expected:expected2
2117 ~reason:Reason.URpair_value
2118 ~use_pos:p2
2119 (Reason.Rtype_variable_generics (p2, "T2", "Pair"))
2121 [ty2]
2123 let ty = MakeType.pair (Reason.Rwitness p) ty1 ty2 in
2124 make_result env p (Aast.Pair (th, te1, te2)) ty
2125 | Array_get (e, None) ->
2126 let (env, te, _) = update_array_type p env e valkind in
2127 let env = might_throw env in
2128 (* NAST check reports an error if [] is used for reading in an
2129 lvalue context. *)
2130 let ty = err_witness env p in
2131 make_result env p (Aast.Array_get (te, None)) ty
2132 | Array_get (e1, Some e2) ->
2133 let (env, te1, ty1) =
2134 update_array_type ?lhs_of_null_coalesce p env e1 valkind
2136 let (env, te2, ty2) = expr env e2 in
2137 let env = might_throw env in
2138 let is_lvalue = phys_equal valkind `lvalue in
2139 let (env, ty) =
2140 Typing_array_access.array_get
2141 ~array_pos:(fst e1)
2142 ~expr_pos:p
2143 ?lhs_of_null_coalesce
2144 is_lvalue
2150 make_result env p (Aast.Array_get (te1, Some te2)) ty
2151 | Call ((pos_id, Id ((_, s) as id)), [], el, None)
2152 when Hash_set.mem typing_env_pseudofunctions s ->
2153 let (env, tel, tys) = exprs ~accept_using_var:true env el in
2154 let env =
2155 if String.equal s SN.PseudoFunctions.hh_show then (
2156 List.iter tys (Typing_log.hh_show p env);
2158 ) else if String.equal s SN.PseudoFunctions.hh_show_env then (
2159 Typing_log.hh_show_env p env;
2161 ) else if String.equal s SN.PseudoFunctions.hh_log_level then
2162 match el with
2163 | [(_, String key_str); (_, Int level_str)] ->
2164 Env.set_log_level env key_str (int_of_string level_str)
2165 | _ -> env
2166 else if String.equal s SN.PseudoFunctions.hh_force_solve then
2167 Typing_solver.solve_all_unsolved_tyvars env Errors.unify_error
2168 else if String.equal s SN.PseudoFunctions.hh_loop_forever then (
2169 loop_forever env;
2171 ) else
2174 let ty = MakeType.void (Reason.Rwitness p) in
2175 make_result
2178 (Aast.Call
2179 ( Tast.make_typed_expr pos_id (TUtils.mk_tany env pos_id) (Aast.Id id),
2181 tel,
2182 None ))
2184 | Call (e, explicit_targs, el, unpacked_element) ->
2185 let env =
2186 match snd e with
2187 | Id (pos, f) when String.equal f SN.SpecialFunctions.echo ->
2188 Typing_local_ops.enforce_io pos env
2189 | _ -> env
2191 let env = might_throw env in
2192 check_call
2193 ~is_using_clause
2194 ~expected
2195 ?in_await
2199 explicit_targs
2201 unpacked_element
2202 | FunctionPointer (FP_id fid, targs) ->
2203 let (env, fty, targs) = fun_type_of_id env fid targs [] in
2204 let e = Aast.FunctionPointer (FP_id fid, targs) in
2205 let fty = set_function_pointer fty in
2206 make_result env p e fty
2207 | Binop (Ast_defs.QuestionQuestion, e1, e2) ->
2208 let (env, te1, ty1) =
2209 raw_expr ~lhs_of_null_coalesce:true env e1 ~allow_awaitable:true
2211 let (env, te2, ty2) = expr ?expected env e2 ~allow_awaitable:true in
2212 let (env, ty1') = Env.fresh_type env (fst e1) in
2213 let env =
2214 SubType.sub_type
2217 (MakeType.nullable_locl Reason.Rnone ty1')
2218 Errors.unify_error
2220 (* Essentially mimic a call to
2221 * function coalesce<Tr, Ta as Tr, Tb as Tr>(?Ta, Tb): Tr
2222 * That way we let the constraint solver take care of the union logic.
2224 let (env, ty_result) = Env.fresh_type env (fst e2) in
2225 let env = SubType.sub_type env ty1' ty_result Errors.unify_error in
2226 let env = SubType.sub_type env ty2 ty_result Errors.unify_error in
2227 make_result
2230 (Aast.Binop (Ast_defs.QuestionQuestion, te1, te2))
2231 ty_result
2232 | Binop (Ast_defs.Eq op_opt, e1, e2) ->
2233 let make_result env p te ty =
2234 let (env, te, ty) = make_result env p te ty in
2235 let env = Typing_local_ops.check_assignment env te in
2236 (env, te, ty)
2238 (match op_opt with
2239 (* For example, e1 += e2. This is typed and translated as if
2240 * written e1 = e1 + e2.
2241 * TODO TAST: is this right? e1 will get evaluated more than once
2243 | Some op ->
2244 begin
2245 match (op, snd e1) with
2246 | (Ast_defs.QuestionQuestion, Class_get _) ->
2247 Errors.experimental_feature
2249 "null coalesce assignment operator with static properties";
2250 expr_error env Reason.Rnone outer
2251 | _ ->
2252 let e_fake =
2253 (p, Binop (Ast_defs.Eq None, e1, (p, Binop (op, e1, e2))))
2255 let (env, te_fake, ty) = raw_expr env e_fake in
2256 begin
2257 match snd te_fake with
2258 | Aast.Binop (_, te1, (_, Aast.Binop (_, _, te2))) ->
2259 let te = Aast.Binop (Ast_defs.Eq (Some op), te1, te2) in
2260 make_result env p te ty
2261 | _ -> assert false
2264 | None ->
2265 let (env, te2, ty2) = raw_expr env e2 in
2266 let (env, te1, ty) = assign p env e1 ty2 in
2267 make_result env p (Aast.Binop (Ast_defs.Eq None, te1, te2)) ty)
2268 | Binop (((Ast_defs.Ampamp | Ast_defs.Barbar) as bop), e1, e2) ->
2269 let c = Ast_defs.(equal_bop bop Ampamp) in
2270 let (env, te1, _) = expr env e1 in
2271 let lenv = env.lenv in
2272 let (env, _lset) = condition env c te1 in
2273 let (env, te2, _) = expr env e2 in
2274 let env = { env with lenv } in
2275 make_result
2278 (Aast.Binop (bop, te1, te2))
2279 (MakeType.bool (Reason.Rlogic_ret p))
2280 | Binop (bop, e1, e2) ->
2281 let (env, te1, ty1) = raw_expr env e1 in
2282 let (env, te2, ty2) = raw_expr env e2 in
2283 let env =
2284 match bop with
2285 (* TODO: This could be less conservative: we only need to account for
2286 * the possibility of exception if the operator is `/` or `/=`.
2288 | Ast_defs.Eqeqeq
2289 | Ast_defs.Diff2 ->
2291 | _ -> might_throw env
2293 let (env, te3, ty) =
2294 Typing_arithmetic.binop p env bop (fst e1) te1 ty1 (fst e2) te2 ty2
2296 (env, te3, ty)
2297 | Pipe (e0, e1, e2) ->
2298 (* If it weren't for local variable assignment or refinement the pipe
2299 * expression e1 |> e2 could be typed using this rule (E is environment with
2300 * types for locals):
2302 * E |- e1 : ty1 E[$$:ty1] |- e2 : ty2
2303 * --------------------------------------
2304 * E |- e1|>e2 : ty2
2306 * The possibility of e2 changing the types of locals in E means that E
2307 * can evolve, and so we need to restore $$ to its original state.
2309 let (env, te1, ty1) = expr env e1 in
2310 let dd_var = Local_id.make_unscoped SN.SpecialIdents.dollardollar in
2311 let dd_old_ty =
2312 if Env.is_local_defined env dd_var then
2313 Some (Env.get_local_pos env dd_var)
2314 else
2315 None
2317 let env = Env.set_local env dd_var ty1 Pos.none in
2318 let (env, te2, ty2) = expr env e2 ~allow_awaitable:true in
2319 let env =
2320 match dd_old_ty with
2321 | None -> Env.unset_local env dd_var
2322 | Some (ty, pos) -> Env.set_local env dd_var ty pos
2324 let (env, te, ty) = make_result env p (Aast.Pipe (e0, te1, te2)) ty2 in
2325 (env, te, ty)
2326 | Unop (uop, e) ->
2327 let (env, te, ty) = raw_expr env e in
2328 let env = might_throw env in
2329 let (env, tuop, ty) = Typing_arithmetic.unop p env uop te ty in
2330 let env = Typing_local_ops.check_assignment env te in
2331 (env, tuop, ty)
2332 | Eif (c, e1, e2) -> eif env ~expected ?in_await p c e1 e2
2333 | Class_const ((p, CI sid), pstr)
2334 when String.equal (snd pstr) "class" && Env.is_typedef env (snd sid) ->
2335 begin
2336 match Env.get_typedef env (snd sid) with
2337 | Some { td_tparams = tparaml; _ } ->
2338 (* Typedef type parameters cannot have constraints *)
2339 let params =
2340 List.map
2342 begin
2343 fun { tp_name = (p, x); _ } ->
2344 (* TODO(T69551141) handle type arguments for Tgeneric *)
2345 MakeType.generic (Reason.Rwitness_from_decl p) x
2347 tparaml
2349 let tdef = mk (Reason.Rwitness_from_decl p, Tapply (sid, params)) in
2350 let typename =
2352 ( Reason.Rwitness_from_decl p,
2353 Tapply ((p, SN.Classes.cTypename), [tdef]) )
2355 let (env, tparams) =
2356 List.map_env env tparaml (fun env tp ->
2357 Env.fresh_type env (fst tp.tp_name))
2359 let ety_env =
2361 (Phase.env_with_self
2363 ~on_error:Errors.leave_unchanged_default_invalid_type_hint_code)
2364 with
2365 substs = Subst.make_locl tparaml tparams;
2368 let env =
2369 Phase.check_tparams_constraints ~use_pos:p ~ety_env env tparaml
2371 let (env, ty) = Phase.localize ~ety_env env typename in
2372 make_result env p (Class_const (((p, ty), CI sid), pstr)) ty
2373 | None ->
2374 (* Should not expect None as we've checked whether the sid is a typedef *)
2375 expr_error env (Reason.Rwitness p) outer
2377 | Class_const (cid, mid) -> class_const env p (cid, mid)
2378 | Class_get ((cpos, cid), CGstring mid, in_parens)
2379 when Env.FakeMembers.is_valid_static env cid (snd mid) ->
2380 let (env, local) = Env.FakeMembers.make_static env cid (snd mid) p in
2381 let local = (p, Lvar (p, local)) in
2382 let (env, _, ty) = expr env local in
2383 let (env, _tal, te, _) =
2384 static_class_id ~check_constraints:false cpos env [] cid
2386 make_result env p (Aast.Class_get (te, Aast.CGstring mid, in_parens)) ty
2387 | Class_get ((cpos, cid), CGstring ((ppos, _) as mid), in_parens) ->
2388 let (env, _tal, te, cty) =
2389 static_class_id ~check_constraints:false cpos env [] cid
2391 let env = might_throw env in
2392 let (env, (ty, _tal)) =
2393 class_get
2394 ~is_method:false
2395 ~is_const:false
2396 ~coerce_from_ty:None
2402 let (env, ty) = Env.FakeMembers.check_static_invalid env cid (snd mid) ty in
2403 let env = Typing_local_ops.enforce_static_property_access ppos env in
2404 make_result env p (Aast.Class_get (te, Aast.CGstring mid, in_parens)) ty
2405 (* Fake member property access. For example:
2406 * if ($x->f !== null) { ...$x->f... }
2408 | Class_get (_, CGexpr _, _) ->
2409 failwith "AST should not have any CGexprs after naming"
2410 | Obj_get (e, (pid, Id (py, y)), nf, in_parens)
2411 when Env.FakeMembers.is_valid env e y ->
2412 let env = might_throw env in
2413 let (env, local) = Env.FakeMembers.make env e y p in
2414 let local = (p, Lvar (p, local)) in
2415 let (env, _, ty) = expr env local in
2416 let (env, t_lhs, _) = expr ~accept_using_var:true env e in
2417 let t_rhs = Tast.make_typed_expr pid ty (Aast.Id (py, y)) in
2418 make_result env p (Aast.Obj_get (t_lhs, t_rhs, nf, in_parens)) ty
2419 (* Statically-known instance property access e.g. $x->f *)
2420 | Obj_get (e1, (pm, Id m), nullflavor, in_parens) ->
2421 let nullsafe =
2422 match nullflavor with
2423 | OG_nullthrows -> None
2424 | OG_nullsafe -> Some p
2426 let (env, te1, ty1) = expr ~accept_using_var:true env e1 in
2427 let env = might_throw env in
2428 (* We typecheck Obj_get by checking whether it is a subtype of
2429 Thas_member(m, #1) where #1 is a fresh type variable. *)
2430 let (env, mem_ty) = Env.fresh_type env p in
2431 let r = Reason.Rwitness (fst e1) in
2432 let has_member_ty =
2433 MakeType.has_member
2435 ~name:m
2436 ~ty:mem_ty
2437 ~class_id:(CIexpr e1)
2438 ~explicit_targs:None
2440 let lty1 = LoclType ty1 in
2441 let (env, result_ty) =
2442 match nullsafe with
2443 | None ->
2444 let env =
2445 Type.sub_type_i
2446 (fst e1)
2447 Reason.URnone
2449 lty1
2450 has_member_ty
2451 Errors.unify_error
2453 (env, mem_ty)
2454 | Some _ ->
2455 (* In that case ty1 is a subtype of ?Thas_member(m, #1)
2456 and the result is ?#1 if ty1 is nullable. *)
2457 let r = Reason.Rnullsafe_op p in
2458 let null_ty = MakeType.null r in
2459 let (env, null_has_mem_ty) =
2460 Union.union_i env r has_member_ty null_ty
2462 let env =
2463 Type.sub_type_i
2464 (fst e1)
2465 Reason.URnone
2467 lty1
2468 null_has_mem_ty
2469 Errors.unify_error
2471 let (env, null_or_nothing_ty) = Inter.intersect env ~r null_ty ty1 in
2472 let (env, result_ty) = Union.union env null_or_nothing_ty mem_ty in
2473 (env, result_ty)
2475 let (env, result_ty) =
2476 Env.FakeMembers.check_instance_invalid env e1 (snd m) result_ty
2478 make_result
2481 (Aast.Obj_get
2482 ( te1,
2483 Tast.make_typed_expr pm result_ty (Aast.Id m),
2484 nullflavor,
2485 in_parens ))
2486 result_ty
2487 (* Dynamic instance property access e.g. $x->$f *)
2488 | Obj_get (e1, e2, nullflavor, in_parens) ->
2489 let (env, te1, ty1) = expr ~accept_using_var:true env e1 in
2490 let (env, te2, _) = expr env e2 in
2491 let ty =
2492 if TUtils.is_dynamic env ty1 then
2493 MakeType.dynamic (Reason.Rwitness p)
2494 else
2495 Typing_utils.mk_tany env p
2497 let ((pos, _), te2) = te2 in
2498 let env = might_throw env in
2499 let te2 = Tast.make_typed_expr pos ty te2 in
2500 make_result env p (Aast.Obj_get (te1, te2, nullflavor, in_parens)) ty
2501 | Yield af ->
2502 let (env, (taf, opt_key, value)) = array_field ~allow_awaitable env af in
2503 let (env, send) = Env.fresh_type env p in
2504 let (env, key) =
2505 match (af, opt_key) with
2506 | (AFvalue (p, _), None) ->
2507 begin
2508 match Env.get_fn_kind env with
2509 | Ast_defs.FSync
2510 | Ast_defs.FAsync ->
2511 Errors.internal_error p "yield found in non-generator";
2512 (env, Typing_utils.mk_tany env p)
2513 | Ast_defs.FGenerator -> (env, MakeType.int (Reason.Rwitness p))
2514 | Ast_defs.FAsyncGenerator ->
2515 let (env, ty) = Env.fresh_type env p in
2516 (env, MakeType.nullable_locl (Reason.Ryield_asyncnull p) ty)
2518 | (_, Some x) -> (env, x)
2519 | (_, _) -> assert false
2521 let rty =
2522 match Env.get_fn_kind env with
2523 | Ast_defs.FGenerator ->
2524 MakeType.generator (Reason.Ryield_gen p) key value send
2525 | Ast_defs.FAsyncGenerator ->
2526 MakeType.async_generator (Reason.Ryield_asyncgen p) key value send
2527 | Ast_defs.FSync
2528 | Ast_defs.FAsync ->
2529 failwith "Parsing should never allow this"
2531 let Typing_env_return_info.{ return_type = expected_return; _ } =
2532 Env.get_return env
2534 let env =
2535 Typing_coercion.coerce_type
2537 Reason.URyield
2540 expected_return
2541 Errors.unify_error
2543 let env = Env.forget_members env Reason.(Blame (p, BScall)) in
2544 let env = LEnv.save_and_merge_next_in_cont env C.Exit in
2545 make_result
2548 (Aast.Yield taf)
2549 (MakeType.nullable_locl (Reason.Ryield_send p) send)
2550 | Await e ->
2551 let env = might_throw env in
2552 (* Await is permitted in a using clause e.g. using (await make_handle()) *)
2553 let (env, te, rty) =
2554 expr
2555 ~is_using_clause
2556 ~in_await:(Reason.Rwitness p)
2559 ~allow_awaitable:true
2561 let (env, ty) = Async.overload_extract_from_awaitable env p rty in
2562 make_result env p (Aast.Await te) ty
2563 | ReadonlyExpr e ->
2564 (* Basically ignore the readonly since it does not affect the type of the result *)
2565 let (env, te, rty) = expr ~is_using_clause env e in
2566 make_result env p (Aast.ReadonlyExpr te) rty
2567 | New ((pos, c), explicit_targs, el, unpacked_element, p1) ->
2568 let env = might_throw env in
2569 let (env, tc, tal, tel, typed_unpack_element, ty, ctor_fty) =
2570 new_object
2571 ~expected
2572 ~is_using_clause
2573 ~check_parent:false
2574 ~check_not_abstract:true
2578 explicit_targs
2580 unpacked_element
2582 let env = Env.forget_members env Reason.(Blame (p, BScall)) in
2583 make_result
2586 (Aast.New (tc, tal, tel, typed_unpack_element, (p1, ctor_fty)))
2588 | Record ((pos, id), field_values) ->
2589 (match Decl_provider.get_record_def (Env.get_ctx env) id with
2590 | Some rd ->
2591 if rd.rdt_abstract then Errors.new_abstract_record (pos, id);
2593 let field_name (pos, expr_) =
2594 match expr_ with
2595 | Aast.String name -> Some (pos, name)
2596 | _ ->
2597 (* TODO T44306013: Ensure that other values for field names are banned. *)
2598 None
2600 let fields_declared = Typing_helpers.all_record_fields env rd in
2601 let fields_present =
2602 List.map field_values ~f:(fun (name, _value) -> field_name name)
2603 |> List.filter_opt
2605 (* Check for missing required fields. *)
2606 let fields_present_names =
2607 List.map ~f:snd fields_present |> SSet.of_list
2609 SMap.iter
2610 (fun field_name info ->
2611 let ((field_pos, _), req) = info in
2612 match req with
2613 | Typing_defs.ValueRequired
2614 when not (SSet.mem field_name fields_present_names) ->
2615 Errors.missing_record_field_name
2616 ~field_name
2617 ~new_pos:pos
2618 ~record_name:id
2619 ~field_decl_pos:field_pos
2620 | _ -> ())
2621 fields_declared;
2623 (* Check for unknown fields.*)
2624 List.iter fields_present ~f:(fun (pos, field_name) ->
2625 if not (SMap.mem field_name fields_declared) then
2626 Errors.unexpected_record_field_name
2627 ~field_name
2628 ~field_pos:pos
2629 ~record_name:id
2630 ~decl_pos:(fst rd.rdt_name))
2631 | None -> Errors.type_not_record id pos);
2633 expr_error env (Reason.Rwitness p) outer
2634 | Cast (hint, e) ->
2635 let (env, te, ty2) = expr ?in_await env e in
2636 let env = might_throw env in
2637 let env =
2639 TypecheckerOptions.experimental_feature_enabled
2640 (Env.get_tcopt env)
2641 TypecheckerOptions.experimental_forbid_nullable_cast
2642 && not (TUtils.is_mixed env ty2)
2643 then
2644 SubType.sub_type_or_fail
2647 (MakeType.nonnull (get_reason ty2))
2648 (fun () ->
2649 Errors.nullable_cast p (Typing_print.error env ty2) (get_pos ty2))
2650 else
2653 let (env, ty) =
2654 Phase.localize_hint_with_self env ~ignore_errors:false hint
2656 make_result env p (Aast.Cast (hint, te)) ty
2657 | ExpressionTree et -> expression_tree { env with in_expr_tree = true } p et
2658 | Is (e, hint) ->
2659 Typing_kinding.Simple.check_well_kinded_hint env hint;
2660 let (env, te, _) = expr env e in
2661 make_result env p (Aast.Is (te, hint)) (MakeType.bool (Reason.Rwitness p))
2662 | As (e, hint, is_nullable) ->
2663 Typing_kinding.Simple.check_well_kinded_hint env hint;
2664 let refine_type env lpos lty rty =
2665 let reason = Reason.Ras lpos in
2666 let (env, rty) = Env.expand_type env rty in
2667 let (env, rty) = class_for_refinement env p reason lpos lty rty in
2668 Inter.intersect env reason lty rty
2670 let (env, te, expr_ty) = expr env e in
2671 let env = might_throw env in
2672 let (env, hint_ty) =
2673 Phase.localize_hint_with_self env ~ignore_errors:false hint
2675 let enable_sound_dynamic =
2676 TypecheckerOptions.enable_sound_dynamic env.genv.tcopt
2678 let is_dyn = Typing_utils.is_dynamic env hint_ty in
2679 ( if enable_sound_dynamic && is_dyn then
2680 let (_ : env * locl_ty) =
2681 ( SubType.sub_type
2682 ~coerce:(Some Typing_logic.CoerceToDynamic)
2684 expr_ty
2685 hint_ty
2686 Errors.unify_error,
2687 hint_ty )
2689 () );
2690 let (env, hint_ty) =
2691 if is_dyn && not enable_sound_dynamic then
2692 let env =
2693 if is_instance_var e then
2694 let (env, ivar) = get_instance_var env e in
2695 set_local env ivar hint_ty
2696 else
2699 (env, hint_ty)
2700 else if is_nullable && not is_dyn then
2701 let (env, hint_ty) = refine_type env (fst e) expr_ty hint_ty in
2702 (env, MakeType.nullable_locl (Reason.Rwitness p) hint_ty)
2703 else if is_instance_var e then
2704 let (env, _, ivar_ty) = raw_expr env e in
2705 let (env, ((ivar_pos, _) as ivar)) = get_instance_var env e in
2706 let (env, hint_ty) = refine_type env ivar_pos ivar_ty hint_ty in
2707 let env = set_local env ivar hint_ty in
2708 (env, hint_ty)
2709 else
2710 refine_type env (fst e) expr_ty hint_ty
2712 make_result env p (Aast.As (te, hint, is_nullable)) hint_ty
2713 | Efun (f, idl)
2714 | Lfun (f, idl) ->
2715 let is_anon =
2716 match e with
2717 | Efun _ -> true
2718 | Lfun _ -> false
2719 | _ -> assert false
2721 (* Check type annotations on the lambda *)
2722 Typing_check_decls.fun_ env f;
2723 (* Check attributes on the lambda *)
2724 let env =
2725 attributes_check_def env SN.AttributeKinds.lambda f.f_user_attributes
2727 (* This is the function type as declared on the lambda itself.
2728 * If type hints are absent then use Tany instead. *)
2729 let declared_fe =
2730 Decl_nast.fun_decl_in_env env.decl_env ~is_lambda:true f
2732 let { fe_type; fe_pos; _ } = declared_fe in
2733 let (declared_pos, declared_ft) =
2734 match get_node fe_type with
2735 | Tfun ft -> (fe_pos, ft)
2736 | _ -> failwith "Not a function"
2738 let declared_ft =
2739 Typing_enforceability.compute_enforced_and_pessimize_fun_type
2741 declared_ft
2743 (* When creating a closure, the 'this' type will mean the late bound type
2744 * of the current enclosing class
2746 let ety_env =
2747 Phase.env_with_self
2749 ~on_error:Errors.leave_unchanged_default_invalid_type_hint_code
2751 let (env, declared_ft) =
2752 Phase.(
2753 localize_ft
2754 ~instantiation:
2755 { use_name = "lambda"; use_pos = p; explicit_targs = [] }
2756 ~ety_env
2757 ~def_pos:declared_pos
2759 declared_ft)
2761 List.iter idl (check_escaping_var env);
2763 (* Ensure lambda arity is not ellipsis in strict mode *)
2764 begin
2765 match declared_ft.ft_arity with
2766 | Fvariadic { fp_name = None; _ }
2767 when Partial.should_check_error (Env.get_mode env) 4223 ->
2768 Errors.ellipsis_strict_mode ~require:`Param_name p
2769 | _ -> ()
2770 end;
2772 (* Is the return type declared? *)
2773 let is_explicit_ret = Option.is_some (hint_of_type_hint f.f_ret) in
2774 let check_body_under_known_params env ?ret_ty ft : env * _ * locl_ty =
2775 let (env, (tefun, ty, ft)) =
2776 closure_make ?ret_ty env p f ft idl is_anon
2778 let inferred_ty =
2780 ( Reason.Rwitness p,
2781 Tfun
2783 ft with
2784 ft_ret =
2785 ( if is_explicit_ret then
2786 declared_ft.ft_ret
2787 else
2788 MakeType.unenforced ty );
2791 (env, tefun, inferred_ty)
2793 let (env, eexpected) = expand_expected_and_get_node env expected in
2794 (* TODO: move this into the expand_expected_and_get_node function and prune its callsites
2795 * Strip like type from function type hint *)
2796 let eexpected =
2797 match eexpected with
2798 | Some (pos, ur, _, Tunion [ty1; ty2]) when is_dynamic ty1 && is_fun ty2
2800 Some (pos, ur, ty2, get_node ty2)
2801 | _ -> eexpected
2803 begin
2804 match eexpected with
2805 | Some (_pos, _ur, ty, Tfun expected_ft) ->
2806 (* First check that arities match up *)
2807 check_lambda_arity p (get_pos ty) declared_ft expected_ft;
2808 (* Use declared types for parameters in preference to those determined
2809 * by the context (expected parameters): they might be more general. *)
2810 let rec replace_non_declared_types declared_ft_params expected_ft_params
2812 match (declared_ft_params, expected_ft_params) with
2813 | ( declared_ft_param :: declared_ft_params,
2814 expected_ft_param :: expected_ft_params ) ->
2815 let rest =
2816 replace_non_declared_types declared_ft_params expected_ft_params
2818 (* If the type parameter did not have a type hint, it is Tany and
2819 we use the expected type instead. Otherwise, declared type takes
2820 precedence. *)
2821 let resolved_ft_param =
2822 if TUtils.is_any env declared_ft_param.fp_type.et_type then
2823 { declared_ft_param with fp_type = expected_ft_param.fp_type }
2824 else
2825 declared_ft_param
2827 resolved_ft_param :: rest
2828 | (_, []) ->
2829 (* Morally, this case should match on ([],[]) because we already
2830 check arity mismatch between declared and expected types. We
2831 handle it more generally here to be graceful. *)
2832 declared_ft_params
2833 | ([], _) ->
2834 (* This means the expected_ft params list can have more parameters
2835 * than declared parameters in the lambda. For variadics, this is OK.
2837 expected_ft_params
2839 let replace_non_declared_arity variadic declared_arity expected_arity =
2840 match variadic with
2841 | FVvariadicArg { param_type_hint = (_, Some _); _ } -> declared_arity
2842 | FVvariadicArg _ ->
2843 begin
2844 match (declared_arity, expected_arity) with
2845 | (Fvariadic declared, Fvariadic expected) ->
2846 Fvariadic { declared with fp_type = expected.fp_type }
2847 | (_, _) -> declared_arity
2849 | _ -> declared_arity
2851 let expected_ft =
2853 expected_ft with
2854 ft_arity =
2855 replace_non_declared_arity
2856 f.f_variadic
2857 declared_ft.ft_arity
2858 expected_ft.ft_arity;
2859 ft_params =
2860 replace_non_declared_types
2861 declared_ft.ft_params
2862 expected_ft.ft_params;
2863 ft_implicit_params = declared_ft.ft_implicit_params;
2866 (* Don't bother passing in `void` if there is no explicit return *)
2867 let ret_ty =
2868 match get_node expected_ft.ft_ret.et_type with
2869 | Tprim Tvoid when not is_explicit_ret -> None
2870 | _ -> Some expected_ft.ft_ret.et_type
2872 Typing_log.increment_feature_count env FL.Lambda.contextual_params;
2873 check_body_under_known_params env ?ret_ty expected_ft
2874 | _ ->
2875 let explicit_variadic_param_or_non_variadic =
2876 match f.f_variadic with
2877 | FVvariadicArg { param_type_hint; _ } ->
2878 Option.is_some (hint_of_type_hint param_type_hint)
2879 | FVellipsis _ -> false
2880 | _ -> true
2882 (* If all parameters are annotated with explicit types, then type-check
2883 * the body under those assumptions and pick up the result type *)
2884 let all_explicit_params =
2885 List.for_all f.f_params (fun param ->
2886 Option.is_some (hint_of_type_hint param.param_type_hint))
2888 if all_explicit_params && explicit_variadic_param_or_non_variadic then (
2889 Typing_log.increment_feature_count
2891 ( if List.is_empty f.f_params then
2892 FL.Lambda.no_params
2893 else
2894 FL.Lambda.explicit_params );
2895 check_body_under_known_params env declared_ft
2896 ) else (
2897 match expected with
2898 | Some ExpectedTy.{ ty = { et_type; _ }; _ } when is_any et_type ->
2899 (* If the expected type is Tany env then we're passing a lambda to
2900 * an untyped function and we just assume every parameter has type
2901 * Tany.
2902 * Note: we should be using 'nothing' to type the arguments. *)
2903 Typing_log.increment_feature_count env FL.Lambda.untyped_context;
2904 check_body_under_known_params env declared_ft
2905 | Some ExpectedTy.{ ty = { et_type; _ }; _ }
2906 when TUtils.is_mixed env et_type || TUtils.is_dynamic env et_type ->
2907 (* If the expected type of a lambda is mixed or dynamic, we
2908 * decompose the expected type into a function type where the
2909 * undeclared parameters and the return type are set to the expected
2910 * type of lambda, i.e., mixed or dynamic.
2912 * For an expected mixed type, one could argue that the lambda
2913 * doesn't even need to be checked as it can't be called (there is
2914 * no downcast to function type). Thus, we should be using nothing
2915 * to type the arguments. But generally users are very confused by
2916 * the use of nothing and would expect the lambda body to be
2917 * checked as though it could be called.
2919 let replace_non_declared_type declared_ft_param =
2920 let is_undeclared =
2921 TUtils.is_any env declared_ft_param.fp_type.et_type
2923 if is_undeclared then
2924 let enforced_ty = { et_enforced = Unenforced; et_type } in
2925 { declared_ft_param with fp_type = enforced_ty }
2926 else
2927 declared_ft_param
2929 let expected_ft =
2930 let ft_params =
2931 List.map ~f:replace_non_declared_type declared_ft.ft_params
2933 { declared_ft with ft_params }
2935 let ret_ty = et_type in
2936 check_body_under_known_params env ~ret_ty expected_ft
2937 | Some _ ->
2938 (* If the expected type is something concrete but not a function
2939 * then we should reject in strict mode. Check body anyway.
2940 * Note: we should be using 'nothing' to type the arguments. *)
2941 if Partial.should_check_error (Env.get_mode env) 4224 then
2942 Errors.untyped_lambda_strict_mode p;
2943 Typing_log.increment_feature_count
2945 FL.Lambda.non_function_typed_context;
2946 check_body_under_known_params env declared_ft
2947 | None ->
2948 (* If we're in partial mode then type-check definition anyway,
2949 * so treating parameters without type hints as "untyped"
2951 if not (Env.is_strict env) then (
2952 Typing_log.increment_feature_count
2954 FL.Lambda.non_strict_unknown_params;
2955 check_body_under_known_params env declared_ft
2956 ) else (
2957 Typing_log.increment_feature_count
2959 FL.Lambda.fresh_tyvar_params;
2961 (* Replace uses of Tany that originated from "untyped" parameters or return type
2962 * with fresh type variables *)
2963 let freshen_ftype env ft =
2964 let freshen_ty env pos et =
2965 match get_node et.et_type with
2966 | Tany _ ->
2967 let (env, ty) = Env.fresh_type env pos in
2968 (env, { et with et_type = ty })
2969 | Tclass (id, e, [ty])
2970 when String.equal (snd id) SN.Classes.cAwaitable
2971 && is_any ty ->
2972 let (env, t) = Env.fresh_type env pos in
2973 ( env,
2975 et with
2976 et_type = mk (get_reason et.et_type, Tclass (id, e, [t]));
2978 | _ -> (env, et)
2980 let freshen_untyped_param env ft_param =
2981 let (env, fp_type) =
2982 freshen_ty env ft_param.fp_pos ft_param.fp_type
2984 (env, { ft_param with fp_type })
2986 let (env, ft_params) =
2987 List.map_env env ft.ft_params freshen_untyped_param
2989 let (env, ft_ret) = freshen_ty env declared_pos ft.ft_ret in
2990 (env, { ft with ft_params; ft_ret })
2992 let (env, declared_ft) = freshen_ftype env declared_ft in
2993 let env =
2994 Env.set_tyvar_variance env (mk (Reason.Rnone, Tfun declared_ft))
2996 (* TODO(jjwu): the declared_ft here is set to public,
2997 but is actually inferred from the surrounding context
2998 (don't think this matters in practice, since we check lambdas separately) *)
2999 check_body_under_known_params
3001 ~ret_ty:declared_ft.ft_ret.et_type
3002 declared_ft
3006 | Xml (sid, attrl, el) ->
3007 let cid = CI sid in
3008 let (env, _tal, _te, classes) =
3009 class_id_for_new ~exact:Nonexact p env cid []
3011 (* OK to ignore rest of list; class_info only used for errors, and
3012 * cid = CI sid cannot produce a union of classes anyhow *)
3013 let class_info =
3014 List.find_map classes ~f:(function
3015 | `Dynamic -> None
3016 | `Class (_, class_info, _) -> Some class_info)
3018 let (env, te, obj) =
3019 (* New statements derived from Xml literals are of the following form:
3021 * __construct(
3022 * darray<string,mixed> $attributes,
3023 * varray<mixed> $children,
3024 * string $file,
3025 * int $line
3026 * );
3028 let new_exp = Typing_xhp.rewrite_xml_into_new p sid attrl el in
3029 expr ?expected env new_exp
3031 let tchildren =
3032 match te with
3033 | (_, New (_, _, [_; (_, Varray (_, children)); _; _], _, _)) -> children
3034 | _ ->
3035 (* We end up in this case when the cosntructed new expression does
3036 not typecheck. *)
3039 let (env, typed_attrs) = xhp_attribute_exprs env class_info attrl sid obj in
3040 let txml = Aast.Xml (sid, typed_attrs, tchildren) in
3041 (match class_info with
3042 | None -> make_result env p txml (mk (Reason.Runknown_class p, Tobject))
3043 | Some _ -> make_result env p txml obj)
3044 | Callconv (kind, e) ->
3045 let (env, te, ty) = expr env e in
3046 make_result env p (Aast.Callconv (kind, te)) ty
3047 | Shape fdm ->
3048 let (env, fdm_with_expected) =
3049 match expand_expected_and_get_node env expected with
3050 | (env, Some (pos, ur, _, Tshape (_, expected_fdm))) ->
3051 let fdme =
3052 List.map
3053 ~f:(fun (k, v) ->
3054 let tk = TShapeField.of_ast (fun p -> p) k in
3055 match TShapeMap.find_opt tk expected_fdm with
3056 | None -> (k, (v, None))
3057 | Some sft -> (k, (v, Some (ExpectedTy.make pos ur sft.sft_ty))))
3060 (env, fdme)
3061 | _ -> (env, List.map ~f:(fun (k, v) -> (k, (v, None))) fdm)
3063 (* allow_inter adds a type-variable *)
3064 let (env, tfdm) =
3065 List.map_env
3066 ~f:(fun env (key, (e, expected)) ->
3067 let (env, te, ty) = expr ?expected env e in
3068 (env, (key, (te, ty))))
3070 fdm_with_expected
3072 let (env, fdm) =
3073 let convert_expr_and_type_to_shape_field_type env (key, (_, ty)) =
3074 (* An expression evaluation always corresponds to a shape_field_type
3075 with sft_optional = false. *)
3076 (env, (key, { sft_optional = false; sft_ty = ty }))
3078 List.map_env ~f:convert_expr_and_type_to_shape_field_type env tfdm
3080 let fdm =
3081 List.fold_left
3082 ~f:(fun acc (k, v) ->
3083 let tk = TShapeField.of_ast (fun p -> p) k in
3084 TShapeMap.add tk v acc)
3085 ~init:TShapeMap.empty
3088 let env = check_shape_keys_validity env p (List.map tfdm ~f:fst) in
3089 (* Fields are fully known, because this shape is constructed
3090 * using shape keyword and we know exactly what fields are set. *)
3091 make_result
3094 (Aast.Shape (List.map ~f:(fun (k, (te, _)) -> (k, te)) tfdm))
3095 (mk (Reason.Rwitness p, Tshape (Closed_shape, fdm)))
3096 | ET_Splice e -> et_splice { env with in_expr_tree = true } p e
3097 | EnumAtom s ->
3098 Errors.atom_as_expr p;
3099 make_result env p (Aast.EnumAtom s) (mk (Reason.Rwitness p, Terr))
3101 (* let ty = err_witness env cst_pos in *)
3102 and class_const ?(incl_tc = false) env p ((cpos, cid), mid) =
3103 let (env, _tal, ce, cty) =
3104 static_class_id ~check_constraints:true cpos env [] cid
3106 let env =
3107 match get_node cty with
3108 | Tclass ((_, n), _, _) when Env.is_enum_class env n ->
3109 Typing_local_ops.enforce_enum_class_variant p env
3110 | _ -> env
3112 let (env, (const_ty, _tal)) =
3113 class_get
3114 ~is_method:false
3115 ~is_const:true
3116 ~incl_tc
3117 ~coerce_from_ty:None
3123 make_result env p (Aast.Class_const (ce, mid)) const_ty
3125 (*****************************************************************************)
3126 (* XHP attribute/body helpers. *)
3127 (*****************************************************************************)
3128 and xhp_attribute_decl_ty env sid obj attr =
3129 let (namepstr, valpty) = attr in
3130 let (valp, valty) = valpty in
3131 let (env, (declty, _tal)) =
3132 TOG.obj_get
3133 ~obj_pos:(fst sid)
3134 ~is_method:false
3135 ~inst_meth:false
3136 ~nullsafe:None
3137 ~coerce_from_ty:None
3138 ~explicit_targs:[]
3139 ~class_id:(CI sid)
3140 ~member_id:namepstr
3141 ~on_error:Errors.unify_error
3145 let ureason = Reason.URxhp (snd sid, snd namepstr) in
3146 let env =
3147 Typing_coercion.coerce_type
3148 valp
3149 ureason
3151 valty
3152 (MakeType.unenforced declty)
3153 Errors.xhp_attribute_does_not_match_hint
3155 (env, declty)
3158 * Process a spread operator by computing the intersection of XHP attributes
3159 * between the spread expression and the XHP constructor onto which we're
3160 * spreading.
3162 and xhp_spread_attribute env c_onto valexpr sid obj =
3163 let (p, _) = valexpr in
3164 let (env, te, valty) = expr env valexpr ~allow_awaitable:(*?*) false in
3165 (* Build the typed attribute node *)
3166 let typed_attr = Aast.Xhp_spread te in
3167 let (env, attr_ptys) =
3168 match c_onto with
3169 | None -> (env, [])
3170 | Some class_info -> Typing_xhp.get_spread_attributes env p class_info valty
3173 let env =
3174 List.fold_left
3175 attr_ptys
3176 ~f:(fun env attr ->
3177 let (env, _) = xhp_attribute_decl_ty env sid obj attr in
3178 env)
3179 ~init:env
3181 (env, typed_attr)
3184 * Simple XHP attributes (attr={expr} form) are simply interpreted as a member
3185 * variable prefixed with a colon.
3187 and xhp_simple_attribute env id valexpr sid obj =
3188 let (p, _) = valexpr in
3189 let (env, te, valty) = expr env valexpr ~allow_awaitable:(*?*) false in
3190 (* This converts the attribute name to a member name. *)
3191 let name = ":" ^ snd id in
3192 let attr_pty = ((fst id, name), (p, valty)) in
3193 let (env, decl_ty) = xhp_attribute_decl_ty env sid obj attr_pty in
3194 let typed_attr =
3195 Aast.Xhp_simple { xs_name = id; xs_type = decl_ty; xs_expr = te }
3197 (env, typed_attr)
3200 * Typecheck the attribute expressions - this just checks that the expressions are
3201 * valid, not that they match the declared type for the attribute and,
3202 * in case of spreads, makes sure they are XHP.
3204 and xhp_attribute_exprs env cls_decl attrl sid obj =
3205 let handle_attr (env, typed_attrl) attr =
3206 let (env, typed_attr) =
3207 match attr with
3208 | Xhp_simple { xs_name = id; xs_expr = valexpr; _ } ->
3209 xhp_simple_attribute env id valexpr sid obj
3210 | Xhp_spread valexpr -> xhp_spread_attribute env cls_decl valexpr sid obj
3212 (env, typed_attr :: typed_attrl)
3214 let (env, typed_attrl) =
3215 List.fold_left ~f:handle_attr ~init:(env, []) attrl
3217 (env, List.rev typed_attrl)
3219 (*****************************************************************************)
3220 (* Anonymous functions & lambdas. *)
3221 (*****************************************************************************)
3222 and closure_bind_param params (env, t_params) ty : env * Tast.fun_param list =
3223 match !params with
3224 | [] ->
3225 (* This code cannot be executed normally, because the arity is wrong
3226 * and it will error later. Bind as many parameters as we can and carry
3227 * on. *)
3228 (env, t_params)
3229 | param :: paraml ->
3230 params := paraml;
3231 (match hint_of_type_hint param.param_type_hint with
3232 | Some h ->
3233 let (pos, _) = h in
3234 (* When creating a closure, the 'this' type will mean the
3235 * late bound type of the current enclosing class
3237 let (env, h) = Phase.localize_hint_with_self env ~ignore_errors:false h in
3238 let env =
3239 Typing_coercion.coerce_type
3241 Reason.URparam
3244 (MakeType.unenforced h)
3245 Errors.unify_error
3247 (* Closures are allowed to have explicit type-hints. When
3248 * that is the case we should check that the argument passed
3249 * is compatible with the type-hint.
3250 * The body of the function should be type-checked with the
3251 * hint and not the type of the argument passed.
3252 * Otherwise it leads to strange results where
3253 * foo(?string $x = null) is called with a string and fails to
3254 * type-check. If $x is a string instead of ?string, null is not
3255 * subtype of string ...
3257 let (env, t_param) = bind_param env (h, param) in
3258 (env, t_params @ [t_param])
3259 | None ->
3260 let ty =
3261 mk (Reason.Rlambda_param (param.param_pos, get_reason ty), get_node ty)
3263 let (env, t_param) = bind_param env (ty, param) in
3264 (env, t_params @ [t_param]))
3266 and closure_bind_variadic env vparam variadic_ty =
3267 let (env, ty, pos) =
3268 match hint_of_type_hint vparam.param_type_hint with
3269 | None ->
3270 (* if the hint is missing, use the type we expect *)
3271 (env, variadic_ty, get_pos variadic_ty)
3272 | Some hint ->
3273 let (env, h) =
3274 Phase.localize_hint_with_self env ~ignore_errors:false hint
3276 let pos = get_pos h in
3277 let env =
3278 Typing_coercion.coerce_type
3280 Reason.URparam
3282 variadic_ty
3283 (MakeType.unenforced h)
3284 Errors.unify_error
3286 (env, h, vparam.param_pos)
3288 let r = Reason.Rvar_param pos in
3289 let arr_values = mk (r, get_node ty) in
3290 let unification = TypecheckerOptions.hack_arr_dv_arrs (Env.get_tcopt env) in
3291 let ty = MakeType.varray ~unification r arr_values in
3292 let (env, t_variadic) = bind_param env (ty, vparam) in
3293 (env, t_variadic)
3295 and closure_bind_opt_param env param : env =
3296 match param.param_expr with
3297 | None ->
3298 let ty = Typing_utils.mk_tany env param.param_pos in
3299 let (env, _) = bind_param env (ty, param) in
3301 | Some default ->
3302 let (env, _te, ty) = expr env default ~allow_awaitable:(*?*) false in
3303 Typing_sequencing.sequence_check_expr default;
3304 let (env, _) = bind_param env (ty, param) in
3307 and closure_check_param env param =
3308 match hint_of_type_hint param.param_type_hint with
3309 | None -> env
3310 | Some hty ->
3311 let (env, hty) =
3312 Phase.localize_hint_with_self env ~ignore_errors:false hty
3314 let paramty = Env.get_local env (Local_id.make_unscoped param.param_name) in
3315 let hint_pos = get_pos hty in
3316 let env =
3317 Typing_coercion.coerce_type
3318 hint_pos
3319 Reason.URhint
3321 paramty
3322 (MakeType.unenforced hty)
3323 Errors.unify_error
3327 and stash_conts_for_closure env p is_anon captured f =
3328 let captured =
3329 if is_anon && TypecheckerOptions.any_coeffects (Env.get_tcopt env) then
3330 Typing_coeffects.(
3331 (Pos.none, local_capability_id) :: (Pos.none, capability_id) :: captured)
3332 else
3333 captured
3335 let captured =
3336 if Env.is_local_defined env this then
3337 (Pos.none, this) :: captured
3338 else
3339 captured
3341 let init =
3342 Option.map (Env.next_cont_opt env) ~f:(fun next_cont ->
3343 let initial_locals =
3344 if is_anon then
3345 Env.get_locals env captured
3346 else
3347 next_cont.Typing_per_cont_env.local_types
3349 let initial_fakes =
3350 Fake.forget (Env.get_fake_members env) Reason.(Blame (p, BSlambda))
3352 let tpenv = Env.get_tpenv env in
3353 (initial_locals, initial_fakes, tpenv))
3355 Typing_lenv.stash_and_do env (Env.all_continuations env) (fun env ->
3356 let env =
3357 match init with
3358 | None -> env
3359 | Some (initial_locals, initial_fakes, tpenv) ->
3360 let env = Env.reinitialize_locals env in
3361 let env = Env.set_locals env initial_locals in
3362 let env = Env.set_fake_members env initial_fakes in
3363 let env = Env.env_with_tpenv env tpenv in
3366 f env)
3368 (* Make a type-checking function for an anonymous function or lambda. *)
3369 (* Here ret_ty should include Awaitable wrapper *)
3370 (* TODO: ?el is never set; so we need to fix variadic use of lambda *)
3371 and closure_make ?el ?ret_ty env lambda_pos f ft idl is_anon =
3372 let nb = Nast.assert_named_body f.f_body in
3373 Env.closure env.lenv env (fun env ->
3374 (* Extract capabilities from AAST and add them to the environment *)
3375 let (env, capability) =
3376 match (f.f_ctxs, f.f_unsafe_ctxs) with
3377 | (None, None) ->
3378 (* if the closure has no explicit coeffect annotations,
3379 do _not_ insert (unsafe) capabilities into the environment;
3380 instead, rely on the fact that a capability from an enclosing
3381 scope can simply be captured, which has the same semantics
3382 as redeclaring and shadowing with another same-typed capability.
3383 This avoid unnecessary overhead in the most common case, i.e.,
3384 when a closure does not need a different (usually smaller)
3385 set of capabilities. *)
3386 (env, Env.get_local env Typing_coeffects.local_capability_id)
3387 | (_, _) ->
3388 let (env, cap_ty, unsafe_cap_ty) =
3389 type_capability env f.f_ctxs f.f_unsafe_ctxs (fst f.f_name)
3391 Typing_coeffects.register_capabilities env cap_ty unsafe_cap_ty
3393 let ft =
3394 { ft with ft_implicit_params = { capability = CapTy capability } }
3396 stash_conts_for_closure env lambda_pos is_anon idl (fun env ->
3397 let env = Env.clear_params env in
3398 let make_variadic_arg env varg tyl =
3399 let remaining_types =
3400 (* It's possible the variadic arg will capture the variadic
3401 * parameter of the supplied arity (if arity is Fvariadic)
3402 * and additional supplied params.
3404 * For example in cases such as:
3405 * lambda1 = (int $a, string...$c) ==> {};
3406 * lambda1(1, "hello", ...$y); (where $y is a variadic string)
3407 * lambda1(1, "hello", "world");
3408 * then ...$c will contain "hello" and everything in $y in the first
3409 * example, and "hello" and "world" in the second example.
3411 * To account for a mismatch in arity, we take the remaining supplied
3412 * parameters and return a list of all their types. We'll use this
3413 * to create a union type when creating the typed variadic arg.
3415 let remaining_params =
3416 List.drop ft.ft_params (List.length f.f_params)
3418 List.map ~f:(fun param -> param.fp_type.et_type) remaining_params
3420 let r = Reason.Rvar_param varg.param_pos in
3421 let union = Tunion (tyl @ remaining_types) in
3422 let (env, t_param) =
3423 closure_bind_variadic env varg (mk (r, union))
3425 (env, Aast.FVvariadicArg t_param)
3427 let (env, t_variadic) =
3428 match (f.f_variadic, ft.ft_arity) with
3429 | (FVvariadicArg arg, Fvariadic variadic) ->
3430 make_variadic_arg env arg [variadic.fp_type.et_type]
3431 | (FVvariadicArg arg, Fstandard) -> make_variadic_arg env arg []
3432 | (FVellipsis pos, _) -> (env, Aast.FVellipsis pos)
3433 | (_, _) -> (env, Aast.FVnonVariadic)
3435 let params = ref f.f_params in
3436 let (env, t_params) =
3437 List.fold_left
3438 ~f:(closure_bind_param params)
3439 ~init:(env, [])
3440 (List.map ft.ft_params (fun x -> x.fp_type.et_type))
3442 let env =
3443 List.fold_left ~f:closure_bind_opt_param ~init:env !params
3445 let env =
3446 List.fold_left ~f:closure_check_param ~init:env f.f_params
3448 let env =
3449 match el with
3450 | None ->
3451 (*iter2_shortest
3452 Unify.unify_param_modes
3453 ft.ft_params
3454 supplied_params; *)
3456 | Some x ->
3457 let var_param =
3458 match f.f_variadic with
3459 | FVellipsis pos ->
3460 let param =
3461 TUtils.default_fun_param
3462 ~pos
3463 (mk (Reason.Rvar_param pos, Typing_defs.make_tany ()))
3465 Some param
3466 | _ -> None
3468 let rec iter l1 l2 =
3469 match (l1, l2, var_param) with
3470 | (_, [], _) -> ()
3471 | ([], _, None) -> ()
3472 | ([], x2 :: rl2, Some def1) ->
3473 param_modes ~is_variadic:true def1 x2;
3474 iter [] rl2
3475 | (x1 :: rl1, x2 :: rl2, _) ->
3476 param_modes x1 x2;
3477 iter rl1 rl2
3479 iter ft.ft_params x;
3480 wfold_left2 inout_write_back env ft.ft_params x
3482 let env = Env.set_fn_kind env f.f_fun_kind in
3483 let decl_ty =
3484 Option.map
3485 ~f:(Decl_hint.hint env.decl_env)
3486 (hint_of_type_hint f.f_ret)
3488 let (env, hret) =
3489 match decl_ty with
3490 | None ->
3491 (* Do we have a contextual return type? *)
3492 begin
3493 match ret_ty with
3494 | None ->
3495 let (env, ret_ty) = Env.fresh_type env lambda_pos in
3496 (env, Typing_return.wrap_awaitable env lambda_pos ret_ty)
3497 | Some ret_ty ->
3498 (* We might need to force it to be Awaitable if it is a type variable *)
3499 Typing_return.force_awaitable env lambda_pos ret_ty
3501 | Some ret ->
3502 (* If a 'this' type appears it needs to be compatible with the
3503 * late static type
3505 let ety_env =
3506 Phase.env_with_self
3508 ~on_error:
3509 Errors.leave_unchanged_default_invalid_type_hint_code
3511 Typing_return.make_return_type (Phase.localize ~ety_env) env ret
3513 let env =
3514 Env.set_return
3516 (Typing_return.make_info
3517 f.f_fun_kind
3520 ~is_explicit:(Option.is_some ret_ty)
3521 hret
3522 decl_ty)
3524 let local_tpenv = Env.get_tpenv env in
3525 (* Outer pipe variables aren't available in closures. Note that
3526 * locals are restored by Env.closure after processing the closure
3528 let env =
3529 Env.unset_local
3531 (Local_id.make_unscoped SN.SpecialIdents.dollardollar)
3533 let (env, tb) = block env nb.fb_ast in
3534 let has_implicit_return = LEnv.has_next env in
3535 let named_body_is_unsafe = Nast.named_body_is_unsafe nb in
3536 let env =
3537 if (not has_implicit_return) || Nast.named_body_is_unsafe nb then
3539 else
3540 fun_implicit_return env lambda_pos hret f.f_fun_kind
3542 let env =
3543 Typing_env.set_fun_tast_info
3545 { Tast.has_implicit_return; Tast.named_body_is_unsafe }
3547 let (env, tparams) = List.map_env env f.f_tparams type_param in
3548 let (env, user_attributes) =
3549 List.map_env env f.f_user_attributes user_attribute
3551 let tfun_ =
3553 Aast.f_annotation = Env.save local_tpenv env;
3554 Aast.f_span = f.f_span;
3555 Aast.f_mode = f.f_mode;
3556 Aast.f_ret = (hret, hint_of_type_hint f.f_ret);
3557 Aast.f_readonly_ret = f.f_readonly_ret;
3558 Aast.f_name = f.f_name;
3559 Aast.f_tparams = tparams;
3560 Aast.f_where_constraints = f.f_where_constraints;
3561 Aast.f_fun_kind = f.f_fun_kind;
3562 Aast.f_file_attributes = [];
3563 Aast.f_user_attributes = user_attributes;
3564 Aast.f_body = { Aast.fb_ast = tb; fb_annotation = () };
3565 Aast.f_ctxs = f.f_ctxs;
3566 Aast.f_unsafe_ctxs = f.f_unsafe_ctxs;
3567 Aast.f_params = t_params;
3568 Aast.f_variadic = t_variadic;
3569 (* TODO TAST: Variadic efuns *)
3570 Aast.f_external = f.f_external;
3571 Aast.f_namespace = f.f_namespace;
3572 Aast.f_doc_comment = f.f_doc_comment;
3573 Aast.f_static = f.f_static;
3576 let ty = mk (Reason.Rwitness lambda_pos, Tfun ft) in
3577 let te =
3578 Tast.make_typed_expr
3579 lambda_pos
3581 ( if is_anon then
3582 Aast.Efun (tfun_, idl)
3583 else
3584 Aast.Lfun (tfun_, idl) )
3586 let env = Env.set_tyvar_variance env ty in
3587 (env, (te, hret, ft))
3588 (* stash_conts_for_anon *))
3589 (* Env.closure *))
3591 (*****************************************************************************)
3592 (* End of anonymous functions & lambdas. *)
3593 (*****************************************************************************)
3595 (*****************************************************************************)
3596 (* Expression trees *)
3597 (*****************************************************************************)
3598 and expression_tree env p et =
3599 let (env, t_desugared_expr, ty_desugared) =
3600 expr env et.et_desugared_expr ~allow_awaitable:(*?*) false
3602 make_result
3605 (Aast.ExpressionTree
3606 { et_hint = et.et_hint; et_desugared_expr = t_desugared_expr })
3607 ty_desugared
3609 and et_splice env p e =
3610 let (env, te, ty) = expr env e ~allow_awaitable:(*?*) false in
3611 let (env, ty_visitor) = Env.fresh_type env p in
3612 let (env, ty_res) = Env.fresh_type env p in
3613 let (env, ty_infer) = Env.fresh_type env p in
3614 let spliceable_type =
3615 MakeType.spliceable (Reason.Rsplice p) ty_visitor ty_res ty_infer
3617 let env = SubType.sub_type env ty spliceable_type Errors.unify_error in
3618 make_result env p (Aast.ET_Splice te) ty_infer
3620 (*****************************************************************************)
3621 (* End expression trees *)
3622 (*****************************************************************************)
3623 and type_capability env ctxs unsafe_ctxs default_pos =
3624 (* No need to repeat the following check (saves time) for unsafe_ctx
3625 because it's synthetic and well-kinded by construction *)
3626 Option.iter ctxs ~f:(fun (_pos, hl) ->
3627 List.iter hl (Typing_kinding.Simple.check_well_kinded_hint env));
3629 let cc = Decl_hint.aast_contexts_to_decl_capability in
3630 let (decl_pos, (env, cap_ty)) =
3631 match cc env.decl_env ctxs default_pos with
3632 | CapTy ty ->
3633 (get_pos ty, Phase.localize_with_self env ~ignore_errors:false ty)
3634 | CapDefaults p -> (p, (env, MakeType.default_capability p))
3636 if TypecheckerOptions.strict_contexts (Env.get_tcopt env) then
3637 Typing_coeffects.validate_capability env decl_pos cap_ty;
3638 let (env, unsafe_cap_ty) =
3639 match cc env.decl_env unsafe_ctxs default_pos with
3640 | CapTy ty -> Phase.localize_with_self env ~ignore_errors:false ty
3641 | CapDefaults p ->
3642 (* default is no unsafe capabilities *)
3643 (env, MakeType.mixed (Reason.Rhint p))
3645 (env, cap_ty, unsafe_cap_ty)
3647 and requires_consistent_construct = function
3648 | CIstatic -> true
3649 | CIexpr _ -> true
3650 | CIparent -> false
3651 | CIself -> false
3652 | CI _ -> false
3654 (* Caller will be looking for a particular form of expected type
3655 * e.g. a function type (when checking lambdas) or tuple type (when checking
3656 * tuples). First expand the expected type and elide single union; also
3657 * strip nullables, so ?t becomes t, as context will always accept a t if a ?t
3658 * is expected.
3660 and expand_expected_and_get_node env (expected : ExpectedTy.t option) =
3661 match expected with
3662 | None -> (env, None)
3663 | Some ExpectedTy.{ pos = p; reason = ur; ty = { et_type = ty; _ }; _ } ->
3664 let (env, ty) = Env.expand_type env ty in
3665 (match get_node ty with
3666 | Tunion [ty] -> (env, Some (p, ur, ty, get_node ty))
3667 | Toption ty -> (env, Some (p, ur, ty, get_node ty))
3668 | _ -> (env, Some (p, ur, ty, get_node ty)))
3670 (** Do a subtype check of inferred type against expected type *)
3671 and check_expected_ty message env inferred_ty (expected : ExpectedTy.t option) =
3672 match expected with
3673 | None -> env
3674 | Some ExpectedTy.{ pos = p; reason = ur; ty } ->
3675 Typing_log.(
3676 log_with_level env "typing" 1 (fun () ->
3677 log_types
3681 Log_head
3682 ( Printf.sprintf
3683 "Typing.check_expected_ty %s enforced=%s"
3684 message
3685 (match ty.et_enforced with
3686 | Unenforced -> "unenforced"
3687 | Enforced -> "enforced"
3688 | PartiallyEnforced -> "partially enforced"),
3690 Log_type ("inferred_ty", inferred_ty);
3691 Log_type ("expected_ty", ty.et_type);
3692 ] );
3693 ]));
3694 Typing_coercion.coerce_type p ur env inferred_ty ty Errors.unify_error
3696 and new_object
3697 ~(expected : ExpectedTy.t option)
3698 ~check_parent
3699 ~check_not_abstract
3700 ~is_using_clause
3704 explicit_targs
3706 unpacked_element =
3707 (* Obtain class info from the cid expression. We get multiple
3708 * results with a CIexpr that has a union type, e.g. in
3710 $classname = (mycond()? classname<A>: classname<B>);
3711 new $classname();
3713 let (env, tal, tcid, classes) =
3714 instantiable_cid ~exact:Exact p env cid explicit_targs
3716 let allow_abstract_bound_generic =
3717 match tcid with
3718 | ((_, ty), Aast.CI (_, tn)) -> is_generic_equal_to tn ty
3719 | _ -> false
3721 let gather (env, _tel, _typed_unpack_element) (cname, class_info, c_ty) =
3723 check_not_abstract
3724 && Cls.abstract class_info
3725 && (not (requires_consistent_construct cid))
3726 && not allow_abstract_bound_generic
3727 then
3728 uninstantiable_error
3732 (Cls.pos class_info)
3733 (Cls.name class_info)
3735 c_ty;
3736 let (env, obj_ty_, params) =
3737 let (env, c_ty) = Env.expand_type env c_ty in
3738 match (cid, tal, get_class_type c_ty) with
3739 (* Explicit type arguments *)
3740 | (CI _, _ :: _, Some (_, _, tyl)) -> (env, get_node c_ty, tyl)
3741 | (_, _, class_type_opt) ->
3742 let (env, params) =
3743 List.map_env env (Cls.tparams class_info) (fun env tparam ->
3744 let (env, tvar) =
3745 Env.fresh_type_reason
3747 (Reason.Rtype_variable_generics
3748 (p, snd tparam.tp_name, strip_ns (snd cname)))
3750 Typing_log.log_new_tvar_for_new_object env p tvar cname tparam;
3751 (env, tvar))
3753 begin
3754 match class_type_opt with
3755 | Some (_, Exact, _) -> (env, Tclass (cname, Exact, params), params)
3756 | _ -> (env, Tclass (cname, Nonexact, params), params)
3760 (not check_parent)
3761 && (not is_using_clause)
3762 && Cls.is_disposable class_info
3763 then
3764 Errors.invalid_new_disposable p;
3765 let r_witness = Reason.Rwitness p in
3766 let obj_ty = mk (r_witness, obj_ty_) in
3767 let c_ty =
3768 match cid with
3769 | CIstatic
3770 | CIexpr _ ->
3771 mk (r_witness, get_node c_ty)
3772 | _ -> obj_ty
3774 let (env, new_ty) =
3775 let ((_, cid_ty), _) = tcid in
3776 let (env, cid_ty) = Env.expand_type env cid_ty in
3777 if is_generic cid_ty then
3778 (env, cid_ty)
3779 else if check_parent then
3780 (env, c_ty)
3781 else
3782 ExprDepTy.make env cid c_ty
3784 (* Set variance according to type of `new` expression now. Lambda arguments
3785 * to the constructor might depend on it, and `call_construct` only uses
3786 * `ctor_fty` to set the variance which has void return type *)
3787 let env = Env.set_tyvar_variance env new_ty in
3788 let (env, tel, typed_unpack_element, ctor_fty) =
3789 let env = check_expected_ty "New" env new_ty expected in
3790 call_construct p env class_info params el unpacked_element cid new_ty
3792 ( if equal_consistent_kind (snd (Cls.construct class_info)) Inconsistent then
3793 match cid with
3794 | CIstatic -> Errors.new_inconsistent_construct p cname `static
3795 | CIexpr _ -> Errors.new_inconsistent_construct p cname `classname
3796 | _ -> () );
3797 match cid with
3798 | CIparent ->
3799 let (env, ctor_fty) =
3800 match fst (Cls.construct class_info) with
3801 | Some ({ ce_type = (lazy ty); _ } as ce) ->
3802 let ety_env =
3804 type_expansions = [];
3805 substs =
3806 TUtils.make_locl_subst_for_class_tparams class_info params;
3807 this_ty = obj_ty;
3808 on_error = Errors.ignore_error;
3811 if get_ce_abstract ce then
3812 Errors.parent_abstract_call
3813 SN.Members.__construct
3815 (get_pos ctor_fty);
3816 let (env, ctor_fty) = Phase.localize ~ety_env env ty in
3817 (env, ctor_fty)
3818 | None -> (env, ctor_fty)
3820 ((env, tel, typed_unpack_element), (obj_ty, ctor_fty))
3821 | CIstatic
3822 | CI _
3823 | CIself ->
3824 ((env, tel, typed_unpack_element), (c_ty, ctor_fty))
3825 | CIexpr _ ->
3826 (* When constructing from a (classname) variable, the variable
3827 * dictates what the constructed object is going to be. This allows
3828 * for generic and dependent types to be correctly carried
3829 * through the 'new $foo()' iff the constructed obj_ty is a
3830 * supertype of the variable-dictated c_ty *)
3831 let env =
3832 Typing_ops.sub_type p Reason.URnone env c_ty obj_ty Errors.unify_error
3834 ((env, tel, typed_unpack_element), (c_ty, ctor_fty))
3836 let (had_dynamic, classes) =
3837 List.fold classes ~init:(false, []) ~f:(fun (seen_dynamic, classes) ->
3838 function
3839 | `Dynamic -> (true, classes)
3840 | `Class (cname, class_info, c_ty) ->
3841 (seen_dynamic, (cname, class_info, c_ty) :: classes))
3843 let ((env, tel, typed_unpack_element), class_types_and_ctor_types) =
3844 List.fold_map classes ~init:(env, [], None) ~f:gather
3846 let class_types_and_ctor_types =
3847 let r = Reason.Rdynamic_construct p in
3848 let dyn = (mk (r, Tdynamic), mk (r, Tdynamic)) in
3849 if had_dynamic then
3850 dyn :: class_types_and_ctor_types
3851 else
3852 class_types_and_ctor_types
3854 let (env, tel, typed_unpack_element, ty, ctor_fty) =
3855 match class_types_and_ctor_types with
3856 | [] ->
3857 let (env, tel, _) = exprs env el ~allow_awaitable:(*?*) false in
3858 let (env, typed_unpack_element, _) =
3859 match unpacked_element with
3860 | None -> (env, None, MakeType.nothing Reason.Rnone)
3861 | Some unpacked_element ->
3862 let (env, e, ty) =
3863 expr env unpacked_element ~allow_awaitable:(*?*) false
3865 (env, Some e, ty)
3867 let r = Reason.Runknown_class p in
3868 (env, tel, typed_unpack_element, mk (r, Tobject), TUtils.terr env r)
3869 | [(ty, ctor_fty)] -> (env, tel, typed_unpack_element, ty, ctor_fty)
3870 | l ->
3871 let (tyl, ctyl) = List.unzip l in
3872 let r = Reason.Rwitness p in
3873 (env, tel, typed_unpack_element, mk (r, Tunion tyl), mk (r, Tunion ctyl))
3875 let (env, new_ty) =
3876 let ((_, cid_ty), _) = tcid in
3877 let (env, cid_ty) = Env.expand_type env cid_ty in
3878 if is_generic cid_ty then
3879 (env, cid_ty)
3880 else if check_parent then
3881 (env, ty)
3882 else
3883 ExprDepTy.make env cid ty
3885 (env, tcid, tal, tel, typed_unpack_element, new_ty, ctor_fty)
3887 and attributes_check_def env kind attrs =
3888 (* TODO(coeffects) change to mixed after changing those constructors to pure *)
3889 let defaults = MakeType.default_capability Pos.none in
3890 let (env, _) =
3891 Typing_lenv.stash_and_do env (Env.all_continuations env) (fun env ->
3892 let env =
3893 fst @@ Typing_coeffects.register_capabilities env defaults defaults
3895 (Typing_attributes.check_def env new_object kind attrs, ()))
3899 (** Get class infos for a class expression (e.g. `parent`, `self` or
3900 regular classnames) - which might resolve to a union or intersection
3901 of classes - and check they are instantiable.
3903 FIXME: we need to separate our instantiability into two parts. Currently,
3904 all this function is doing is checking if a given type is inhabited --
3905 that is, whether there are runtime values of type Aast. However,
3906 instantiability should be the stricter notion that T has a runtime
3907 constructor; that is, `new T()` should be valid. In particular, interfaces
3908 are inhabited, but not instantiable.
3909 To make this work with classname, we likely need to add something like
3910 concrete_classname<T>, where T cannot be an interface. *)
3911 and instantiable_cid ?(exact = Nonexact) p env cid explicit_targs :
3912 newable_class_info =
3913 let (env, tal, te, classes) =
3914 class_id_for_new ~exact p env cid explicit_targs
3916 List.iter classes (function
3917 | `Dynamic -> ()
3918 | `Class ((pos, name), class_info, c_ty) ->
3920 Ast_defs.(equal_class_kind (Cls.kind class_info) Ctrait)
3921 || Ast_defs.(equal_class_kind (Cls.kind class_info) Cenum)
3922 then
3923 match cid with
3924 | CIexpr _
3925 | CI _ ->
3926 uninstantiable_error env p cid (Cls.pos class_info) name pos c_ty
3927 | CIstatic
3928 | CIparent
3929 | CIself ->
3931 else if
3932 Ast_defs.(equal_class_kind (Cls.kind class_info) Cabstract)
3933 && Cls.final class_info
3934 then
3935 uninstantiable_error env p cid (Cls.pos class_info) name pos c_ty
3936 else
3937 ());
3938 (env, tal, te, classes)
3940 and uninstantiable_error env reason_pos cid c_tc_pos c_name c_usage_pos c_ty =
3941 let reason =
3942 match cid with
3943 | CIexpr _ ->
3944 let ty_str = "This would be " ^ Typing_print.error env c_ty in
3945 Some (reason_pos, ty_str)
3946 | _ -> None
3948 Errors.uninstantiable_class c_usage_pos c_tc_pos c_name reason
3950 and coerce_to_throwable pos env exn_ty =
3951 let throwable_ty = MakeType.throwable (Reason.Rthrow pos) in
3952 Typing_coercion.coerce_type
3954 Reason.URthrow
3956 exn_ty
3957 { et_type = throwable_ty; et_enforced = Unenforced }
3958 Errors.unify_error
3960 and shape_field_pos = function
3961 | Ast_defs.SFlit_int (p, _)
3962 | Ast_defs.SFlit_str (p, _) ->
3964 | Ast_defs.SFclass_const ((cls_pos, _), (mem_pos, _)) ->
3965 Pos.btw cls_pos mem_pos
3967 and check_shape_keys_validity :
3968 env -> pos -> Ast_defs.shape_field_name list -> env =
3969 fun env pos keys ->
3970 (* If the key is a class constant, get its class name and type. *)
3971 let get_field_info env key =
3972 let key_pos = shape_field_pos key in
3973 (* Empty strings or literals that start with numbers are not
3974 permitted as shape field names. *)
3975 match key with
3976 | Ast_defs.SFlit_int _ -> (env, key_pos, None)
3977 | Ast_defs.SFlit_str (_, key_name) ->
3978 if Int.equal 0 (String.length key_name) then
3979 Errors.invalid_shape_field_name_empty key_pos;
3980 (env, key_pos, None)
3981 | Ast_defs.SFclass_const (((p, cls) as x), y) ->
3982 let (env, _te, ty) = class_const env pos ((p, CI x), y) in
3983 let r = Reason.Rwitness key_pos in
3984 let env =
3985 Type.sub_type
3986 key_pos
3987 Reason.URnone
3990 (MakeType.arraykey r)
3991 (fun ?code:_ _ _ ->
3992 Errors.invalid_shape_field_type
3993 key_pos
3994 (get_pos ty)
3995 (Typing_print.error env ty)
3998 (env, key_pos, Some (cls, ty))
4000 let check_field witness_pos witness_info env key =
4001 let (env, key_pos, key_info) = get_field_info env key in
4002 match (witness_info, key_info) with
4003 | (Some _, None) ->
4004 Errors.invalid_shape_field_literal key_pos witness_pos;
4006 | (None, Some _) ->
4007 Errors.invalid_shape_field_const key_pos witness_pos;
4009 | (None, None) -> env
4010 | (Some (cls1, ty1), Some (cls2, ty2)) ->
4011 if String.( <> ) cls1 cls2 then
4012 Errors.shape_field_class_mismatch
4013 key_pos
4014 witness_pos
4015 (strip_ns cls2)
4016 (strip_ns cls1);
4019 ( Typing_solver.is_sub_type env ty1 ty2
4020 && Typing_solver.is_sub_type env ty2 ty1 )
4021 then
4022 Errors.shape_field_type_mismatch
4023 key_pos
4024 witness_pos
4025 (Typing_print.error env ty2)
4026 (Typing_print.error env ty1);
4029 (* Sort the keys by their positions since the error messages will make
4030 * more sense if we take the one that appears first as canonical and if
4031 * they are processed in source order. *)
4032 let cmp_keys x y = Pos.compare (shape_field_pos x) (shape_field_pos y) in
4033 let keys = List.sort ~compare:cmp_keys keys in
4034 match keys with
4035 | [] -> env
4036 | witness :: rest_keys ->
4037 let (env, pos, info) = get_field_info env witness in
4038 List.fold_left ~f:(check_field pos info) ~init:env rest_keys
4040 and set_valid_rvalue p env x ty =
4041 let env = set_local env (p, x) ty in
4042 (* We are assigning a new value to the local variable, so we need to
4043 * generate a new expression id
4045 Env.set_local_expr_id env x (Ident.tmp ())
4047 (* Produce an error if assignment is used in the scope of the |> operator, i.e.
4048 * if $$ is in scope *)
4049 and error_if_assign_in_pipe p env =
4050 let dd_var = Local_id.make_unscoped SN.SpecialIdents.dollardollar in
4051 let dd_defined = Env.is_local_defined env dd_var in
4052 if dd_defined then
4053 Errors.unimplemented_feature p "Assignment within pipe expressions"
4055 (* Deal with assignment of a value of type ty2 to lvalue e1 *)
4056 and assign p env e1 ty2 : _ * Tast.expr * Tast.ty =
4057 error_if_assign_in_pipe p env;
4058 assign_ p Reason.URassign env e1 ty2
4060 and is_hack_collection env ty =
4061 (* TODO(like types) This fails if a collection is used as a parameter under
4062 * pessimization, because ~Vector<int> </: ConstCollection<mixed>. This is the
4063 * test we use to see whether to update the expression id for expressions
4064 * $vector[0] = $x and $vector[] = $x. If this is false, the receiver is assumed
4065 * to be a Hack array which are COW. This approximation breaks down in the presence
4066 * of dynamic. It is unclear whether we should change an expression id if the
4067 * receiver is dynamic. *)
4068 Typing_solver.is_sub_type
4071 (MakeType.const_collection Reason.Rnone (MakeType.mixed Reason.Rnone))
4073 and assign_ p ur env e1 ty2 =
4074 let allow_awaitable = (*?*) false in
4075 let env =
4076 match e1 with
4077 | (_, Lvar (_, x)) ->
4078 Env.forget_prefixed_members env x Reason.(Blame (p, BSassignment))
4079 (* If we ever extend fake members from $x->a to more complicated lvalues
4080 such as $x->a->b, we would need to call forget_prefixed_members on
4081 other lvalues as well. *)
4082 | (_, Obj_get (_, (_, Id (_, property)), _, _)) ->
4083 Env.forget_suffixed_members env property Reason.(Blame (p, BSassignment))
4084 | _ -> env
4086 match e1 with
4087 | (_, Lvar ((_, x) as id)) ->
4088 let env = set_valid_rvalue p env x ty2 in
4089 make_result env (fst e1) (Aast.Lvar id) ty2
4090 | (_, Lplaceholder id) ->
4091 let placeholder_ty = MakeType.void (Reason.Rplaceholder p) in
4092 make_result env (fst e1) (Aast.Lplaceholder id) placeholder_ty
4093 | (_, List el) ->
4094 let (env, tyl) =
4095 List.map_env env el ~f:(fun env _ -> Env.fresh_type env (get_pos ty2))
4097 let destructure_ty =
4098 MakeType.list_destructure (Reason.Rdestructure (fst e1)) tyl
4100 let lty2 = LoclType ty2 in
4101 let env = Type.sub_type_i p ur env lty2 destructure_ty Errors.unify_error in
4102 let env = Env.set_tyvar_variance_i env destructure_ty in
4103 let (env, reversed_tel) =
4104 List.fold2_exn el tyl ~init:(env, []) ~f:(fun (env, tel) lvalue ty2 ->
4105 let (env, te, _) = assign p env lvalue ty2 in
4106 (env, te :: tel))
4108 make_result env (fst e1) (Aast.List (List.rev reversed_tel)) ty2
4109 | ( pobj,
4110 Obj_get (obj, (pm, Id ((_, member_name) as m)), nullflavor, in_parens) )
4112 let lenv = env.lenv in
4113 let nullsafe =
4114 match nullflavor with
4115 | OG_nullthrows -> None
4116 | OG_nullsafe -> Some (Reason.Rnullsafe_op pobj)
4118 let (env, tobj, obj_ty) =
4119 expr ~accept_using_var:true env obj ~allow_awaitable
4121 let env = might_throw env in
4122 let (env, (result, _tal)) =
4123 TOG.obj_get
4124 ~obj_pos:(fst obj)
4125 ~is_method:false
4126 ~nullsafe
4127 ~inst_meth:false
4128 ~coerce_from_ty:(Some (p, ur, ty2))
4129 ~explicit_targs:[]
4130 ~class_id:(CIexpr e1)
4131 ~member_id:m
4132 ~on_error:Errors.unify_error
4134 obj_ty
4136 let te1 =
4137 Tast.make_typed_expr
4138 pobj
4139 result
4140 (Aast.Obj_get
4141 ( tobj,
4142 Tast.make_typed_expr pm result (Aast.Id m),
4143 nullflavor,
4144 in_parens ))
4146 let env = { env with lenv } in
4147 begin
4148 match obj with
4149 | (_, This) ->
4150 let (env, local) = Env.FakeMembers.make env obj member_name p in
4151 let env = set_valid_rvalue p env local ty2 in
4152 (env, te1, ty2)
4153 | (_, Lvar _) ->
4154 let (env, local) = Env.FakeMembers.make env obj member_name p in
4155 let env = set_valid_rvalue p env local ty2 in
4156 (env, te1, ty2)
4157 | _ -> (env, te1, ty2)
4159 | (_, Obj_get _) ->
4160 let lenv = env.lenv in
4161 let no_fakes = LEnv.env_with_empty_fakes env in
4162 let (env, te1, real_type) = lvalue no_fakes e1 in
4163 let (env, exp_real_type) = Env.expand_type env real_type in
4164 let env = { env with lenv } in
4165 let env =
4166 Typing_coercion.coerce_type
4171 (MakeType.unenforced exp_real_type)
4172 Errors.unify_error
4174 (env, te1, ty2)
4175 | (_, Class_get (_, CGexpr _, _)) ->
4176 failwith "AST should not have any CGexprs after naming"
4177 | (_, Class_get ((pos_classid, x), CGstring (pos_member, y), _)) ->
4178 let lenv = env.lenv in
4179 let no_fakes = LEnv.env_with_empty_fakes env in
4180 let (env, te1, _) = lvalue no_fakes e1 in
4181 let env = { env with lenv } in
4182 let (env, ety2) = Env.expand_type env ty2 in
4183 (* This defers the coercion check to class_get, which looks up the appropriate target type *)
4184 let (env, _tal, _, cty) =
4185 static_class_id ~check_constraints:false pos_classid env [] x
4187 let env = might_throw env in
4188 let (env, _) =
4189 class_get
4190 ~is_method:false
4191 ~is_const:false
4192 ~coerce_from_ty:(Some (p, ur, ety2))
4195 (pos_member, y)
4198 let (env, local) = Env.FakeMembers.make_static env x y p in
4199 let env = set_valid_rvalue p env local ty2 in
4200 (env, te1, ty2)
4201 | (pos, Array_get (e1, None)) ->
4202 let (env, te1, ty1) = update_array_type pos env e1 `lvalue in
4203 let (env, ty1') =
4204 Typing_array_access.assign_array_append
4205 ~array_pos:(fst e1)
4206 ~expr_pos:p
4212 let (env, te1) =
4213 if is_hack_collection env ty1 then
4214 (env, te1)
4215 else
4216 let (env, te1, _) = assign_ p ur env e1 ty1' in
4217 (env, te1)
4219 make_result env pos (Aast.Array_get (te1, None)) ty2
4220 | (pos, Array_get (e1, Some e)) ->
4221 let (env, te1, ty1) = update_array_type pos env e1 `lvalue in
4222 let (env, te, ty) = expr env e ~allow_awaitable in
4223 let (env, ty1') =
4224 Typing_array_access.assign_array_get
4225 ~array_pos:(fst e1)
4226 ~expr_pos:p
4234 let (env, te1) =
4235 if is_hack_collection env ty1 then
4236 (env, te1)
4237 else
4238 let (env, te1, _) = assign_ p ur env e1 ty1' in
4239 (env, te1)
4241 (env, ((pos, ty2), Aast.Array_get (te1, Some te)), ty2)
4242 | _ -> assign_simple p ur env e1 ty2
4244 and assign_simple pos ur env e1 ty2 =
4245 let (env, te1, ty1) = lvalue env e1 in
4246 let env =
4247 Typing_coercion.coerce_type
4252 (MakeType.unenforced ty1)
4253 Errors.unify_error
4255 (env, te1, ty2)
4257 and array_field env ~allow_awaitable = function
4258 | AFvalue ve ->
4259 let (env, tve, tv) = expr env ve ~allow_awaitable in
4260 (env, (Aast.AFvalue tve, None, tv))
4261 | AFkvalue (ke, ve) ->
4262 let (env, tke, tk) = expr env ke ~allow_awaitable in
4263 let (env, tve, tv) = expr env ve ~allow_awaitable in
4264 (env, (Aast.AFkvalue (tke, tve), Some tk, tv))
4266 and array_value ~(expected : ExpectedTy.t option) env x =
4267 let (env, te, ty) = expr ?expected env x ~allow_awaitable:(*?*) false in
4268 (env, (te, ty))
4270 and arraykey_value
4271 p class_name is_set ~(expected : ExpectedTy.t option) env ((pos, _) as x) =
4272 let (env, (te, ty)) = array_value ~expected env x in
4273 let (ty_arraykey, reason) =
4274 if is_set then
4275 ( MakeType.arraykey (Reason.Rset_element pos),
4276 Reason.set_element class_name )
4277 else
4278 (MakeType.arraykey (Reason.Ridx_dict pos), Reason.index_class class_name)
4280 let env =
4281 Typing_coercion.coerce_type
4283 reason
4286 { et_type = ty_arraykey; et_enforced = Enforced }
4287 Errors.unify_error
4289 (env, (te, ty))
4291 and check_parent_construct pos env el unpacked_element env_parent =
4292 let check_not_abstract = false in
4293 let (env, env_parent) =
4294 Phase.localize_with_self env ~ignore_errors:true env_parent
4296 let (env, _tcid, _tal, tel, typed_unpack_element, parent, fty) =
4297 new_object
4298 ~expected:None
4299 ~check_parent:true
4300 ~check_not_abstract
4301 ~is_using_clause:false
4304 CIparent
4307 unpacked_element
4309 (* Not sure why we need to equate these types *)
4310 let env =
4311 Type.sub_type pos Reason.URnone env env_parent parent Errors.unify_error
4313 let env =
4314 Type.sub_type pos Reason.URnone env parent env_parent Errors.unify_error
4316 ( env,
4317 tel,
4318 typed_unpack_element,
4319 MakeType.void (Reason.Rwitness pos),
4320 parent,
4321 fty )
4323 and check_class_get env p def_pos cid mid ce e function_pointer =
4324 match e with
4325 | CIself when get_ce_abstract ce ->
4326 begin
4327 match Env.get_self_id env with
4328 | Some self ->
4329 (* at runtime, self:: in a trait is a call to whatever
4330 * self:: is in the context of the non-trait "use"-ing
4331 * the trait's code *)
4332 begin
4333 match Env.get_class env self with
4334 | Some cls when Ast_defs.(equal_class_kind (Cls.kind cls) Ctrait) ->
4335 (* Ban self::some_abstract_method() in a trait, if the
4336 * method is also defined in a trait.
4338 * Abstract methods from interfaces are fine: we'll check
4339 * in the child class that we actually have an
4340 * implementation. *)
4341 (match Decl_provider.get_class (Env.get_ctx env) ce.ce_origin with
4342 | Some meth_cls
4343 when Ast_defs.(equal_class_kind (Cls.kind meth_cls) Ctrait) ->
4344 Errors.self_abstract_call mid p def_pos
4345 | _ -> ())
4346 | _ ->
4347 (* Ban self::some_abstract_method() in a class. This will
4348 * always error. *)
4349 Errors.self_abstract_call mid p def_pos
4351 | None -> ()
4353 | CIparent when get_ce_abstract ce ->
4354 Errors.parent_abstract_call mid p def_pos
4355 | CI _ when get_ce_abstract ce && function_pointer ->
4356 Errors.abstract_function_pointer cid mid p def_pos
4357 | CI _ when get_ce_abstract ce ->
4358 Errors.classname_abstract_call cid mid p def_pos
4359 | CI (_, classname) when get_ce_synthesized ce ->
4360 Errors.static_synthetic_method classname mid p def_pos
4361 | _ -> ()
4363 and call_parent_construct pos env el unpacked_element =
4364 match Env.get_parent_ty env with
4365 | Some parent -> check_parent_construct pos env el unpacked_element parent
4366 | None ->
4367 (* continue here *)
4368 let ty = Typing_utils.mk_tany env pos in
4369 let default = (env, [], None, ty, ty, ty) in
4370 (match Env.get_self_id env with
4371 | Some self ->
4372 (match Env.get_class env self with
4373 | Some trait when Ast_defs.(equal_class_kind (Cls.kind trait) Ctrait) ->
4374 (match trait_most_concrete_req_class trait env with
4375 | None ->
4376 Errors.parent_in_trait pos;
4377 default
4378 | Some (_, parent_ty) ->
4379 check_parent_construct pos env el unpacked_element parent_ty)
4380 | Some self_tc ->
4381 if not (Cls.members_fully_known self_tc) then
4383 (* Don't know the hierarchy, assume it's correct *)
4384 else
4385 Errors.undefined_parent pos;
4386 default
4387 | None -> assert false)
4388 | None ->
4389 Errors.parent_outside_class pos;
4390 let ty = err_witness env pos in
4391 (env, [], None, ty, ty, ty))
4393 (* Depending on the kind of expression we are dealing with
4394 * The typing of call is different.
4396 and dispatch_call
4397 ~(expected : ExpectedTy.t option)
4398 ~is_using_clause
4399 ?in_await
4402 ((fpos, fun_expr) as e)
4403 explicit_targs
4405 unpacked_element =
4406 let expr = expr ~allow_awaitable:(*?*) false in
4407 let exprs = exprs ~allow_awaitable:(*?*) false in
4408 let make_call env te tal tel typed_unpack_element ty =
4409 make_result env p (Aast.Call (te, tal, tel, typed_unpack_element)) ty
4411 (* TODO: Avoid Tany annotations in TAST by eliminating `make_call_special` *)
4412 let make_call_special env id tel ty =
4413 make_call
4415 (Tast.make_typed_expr fpos (TUtils.mk_tany env fpos) (Aast.Id id))
4418 None
4421 (* For special functions and pseudofunctions with a definition in hhi. *)
4422 let make_call_special_from_def env id tel ty_ =
4423 let (env, fty, tal) = fun_type_of_id env id explicit_targs el in
4424 let ty =
4425 match get_node fty with
4426 | Tfun ft -> ft.ft_ret.et_type
4427 | _ -> ty_ (Reason.Rwitness p)
4429 make_call env (Tast.make_typed_expr fpos fty (Aast.Id id)) tal tel None ty
4431 let overload_function = overload_function make_call fpos in
4432 let check_disposable_in_return env fty =
4433 if is_return_disposable_fun_type env fty && not is_using_clause then
4434 Errors.invalid_new_disposable p
4436 let dispatch_id env ((_, _) as id) =
4437 let (env, fty, tal) = fun_type_of_id env id explicit_targs el in
4438 check_disposable_in_return env fty;
4439 let (env, (tel, typed_unpack_element, ty)) =
4440 call ~expected p env fty el unpacked_element
4442 make_call
4444 (Tast.make_typed_expr fpos fty (Aast.Id id))
4447 typed_unpack_element
4450 let dispatch_class_const env (pos, e1) m =
4451 let (env, _tal, tcid, ty1) =
4452 static_class_id
4453 ~check_constraints:(not (Nast.equal_class_id_ e1 CIparent))
4459 (* In static context, you can only call parent::foo() on static methods.
4460 * In instance context, you can call parent:foo() on static
4461 * methods as well as instance methods
4463 let is_static =
4464 (not (Nast.equal_class_id_ e1 CIparent))
4465 || Env.is_static env
4466 || class_contains_smethod env ty1 m
4468 let (env, (fty, tal)) =
4469 match Env.get_self_ty env with
4470 | Some this_ty when not is_static ->
4471 (* parent::nonStaticFunc() is really weird. It's calling a method
4472 * defined on the parent class, but $this is still the child class.
4474 TOG.obj_get
4475 ~inst_meth:false
4476 ~is_method:true
4477 ~nullsafe:None
4478 ~obj_pos:pos
4479 ~coerce_from_ty:None
4480 ~explicit_targs:[]
4481 ~class_id:e1
4482 ~member_id:m
4483 ~on_error:Errors.unify_error
4484 ~parent_ty:ty1
4486 this_ty
4487 | _ ->
4488 class_get
4489 ~coerce_from_ty:None
4490 ~is_method:true
4491 ~is_const:false
4492 ~explicit_targs
4498 check_disposable_in_return env fty;
4499 let (env, (tel, typed_unpack_element, ty)) =
4500 call ~expected p env fty el unpacked_element
4502 make_call
4504 (Tast.make_typed_expr fpos fty (Aast.Class_const (tcid, m)))
4507 typed_unpack_element
4510 match fun_expr with
4511 (* Special top-level function *)
4512 | Id ((pos, x) as id) when SN.StdlibFunctions.needs_special_dispatch x ->
4513 begin
4514 match x with
4515 (* Special function `echo` *)
4516 | echo when String.equal echo SN.SpecialFunctions.echo ->
4517 let (env, tel, _) = exprs ~accept_using_var:true env el in
4518 make_call_special env id tel (MakeType.void (Reason.Rwitness pos))
4519 (* `unsafe_cast` *)
4520 | unsafe_cast when String.equal unsafe_cast SN.PseudoFunctions.unsafe_cast
4523 Int.(List.length el = 1)
4524 && TypecheckerOptions.ignore_unsafe_cast (Env.get_tcopt env)
4525 then
4526 let original_expr = List.hd_exn el in
4527 expr env original_expr
4528 else (
4529 Errors.unsafe_cast p;
4530 (* dispatch_id also covers arity errors *)
4531 dispatch_id env id
4533 (* Special function `isset` *)
4534 | isset when String.equal isset SN.PseudoFunctions.isset ->
4535 let (env, tel, _) =
4536 exprs ~accept_using_var:true ~check_defined:false env el
4538 if Option.is_some unpacked_element then
4539 Errors.unpacking_disallowed_builtin_function p isset;
4540 make_call_special_from_def env id tel MakeType.bool
4541 (* Special function `unset` *)
4542 | unset when String.equal unset SN.PseudoFunctions.unset ->
4543 let (env, tel, _) = exprs env el in
4544 if Option.is_some unpacked_element then
4545 Errors.unpacking_disallowed_builtin_function p unset;
4546 let env = Typing_local_ops.check_unset_target env tel in
4547 let checked_unset_error =
4548 if Partial.should_check_error (Env.get_mode env) 4135 then
4549 Errors.unset_nonidx_in_strict
4550 else
4551 fun _ _ ->
4554 let env =
4555 match (el, unpacked_element) with
4556 | ([(_, Array_get ((_, Class_const _), Some _))], None)
4557 when Partial.should_check_error (Env.get_mode env) 4011 ->
4558 Errors.const_mutation p Pos.none "";
4560 | ([(_, Array_get (ea, Some _))], None) ->
4561 let (env, _te, ty) = expr env ea in
4562 let r = Reason.Rwitness p in
4563 let tmixed = MakeType.mixed r in
4564 let unification =
4565 TypecheckerOptions.hack_arr_dv_arrs (Env.get_tcopt env)
4567 let super =
4569 ( Reason.Rnone,
4570 Tunion
4572 MakeType.dynamic r;
4573 MakeType.dict r tmixed tmixed;
4574 MakeType.keyset r tmixed;
4575 MakeType.darray ~unification r tmixed tmixed;
4578 SubType.sub_type_or_fail env ty super (fun () ->
4579 checked_unset_error
4581 (Reason.to_string
4582 ( "This is "
4583 ^ Typing_print.error ~ignore_dynamic:true env ty )
4584 (get_reason ty)))
4585 | _ ->
4586 checked_unset_error p [];
4589 (match el with
4590 | [(p, Obj_get (_, _, OG_nullsafe, _))] ->
4591 Errors.nullsafe_property_write_context p;
4592 make_call_special_from_def env id tel (TUtils.terr env)
4593 | _ -> make_call_special_from_def env id tel MakeType.void)
4594 (* Special function `array_filter` *)
4595 | array_filter
4596 when String.equal array_filter SN.StdlibFunctions.array_filter
4597 && (not (List.is_empty el))
4598 && Option.is_none unpacked_element ->
4599 (* dispatch the call to typecheck the arguments *)
4600 let (env, fty, tal) = fun_type_of_id env id explicit_targs el in
4601 let (env, (tel, typed_unpack_element, res)) =
4602 call ~expected p env fty el unpacked_element
4604 (* but ignore the result and overwrite it with custom return type *)
4605 let x = List.hd_exn el in
4606 let (env, _tx, ty) = expr env x in
4607 let explain_array_filter ty =
4608 map_reason ty ~f:(fun r -> Reason.Rarray_filter (p, r))
4610 let get_value_type env tv =
4611 let (env, tv) =
4612 if List.length el > 1 then
4613 (env, tv)
4614 else
4615 Typing_solver.non_null env p tv
4617 (env, explain_array_filter tv)
4619 let rec get_array_filter_return_type env ty =
4620 let (env, ety) = Env.expand_type env ty in
4621 match deref ety with
4622 | (r, Tvarray tv) ->
4623 let (env, tv) = get_value_type env tv in
4624 let unification =
4625 TypecheckerOptions.hack_arr_dv_arrs (Env.get_tcopt env)
4627 (env, MakeType.varray ~unification r tv)
4628 | (r, Tunion tyl) ->
4629 let (env, tyl) =
4630 List.map_env env tyl get_array_filter_return_type
4632 Typing_union.union_list env r tyl
4633 | (r, Tintersection tyl) ->
4634 let (env, tyl) =
4635 List.map_env env tyl get_array_filter_return_type
4637 Inter.intersect_list env r tyl
4638 | (r, Tany _) -> (env, mk (r, Typing_utils.tany env))
4639 | (r, Terr) -> (env, TUtils.terr env r)
4640 | (r, _) ->
4641 let (env, tk) = Env.fresh_type env p in
4642 let (env, tv) = Env.fresh_type env p in
4643 let unification =
4644 TypecheckerOptions.hack_arr_dv_arrs (Env.get_tcopt env)
4646 Errors.try_
4647 (fun () ->
4648 let keyed_container_type =
4649 MakeType.keyed_container Reason.Rnone tk tv
4651 let env =
4652 SubType.sub_type
4655 keyed_container_type
4656 Errors.unify_error
4658 let (env, tv) = get_value_type env tv in
4659 ( env,
4660 MakeType.darray ~unification r (explain_array_filter tk) tv ))
4661 (fun _ ->
4662 Errors.try_
4663 (fun () ->
4664 let container_type = MakeType.container Reason.Rnone tv in
4665 let env =
4666 SubType.sub_type env ety container_type Errors.unify_error
4668 let (env, tv) = get_value_type env tv in
4669 ( env,
4670 MakeType.darray
4671 ~unification
4673 (explain_array_filter (MakeType.arraykey r))
4674 tv ))
4675 (fun _ -> (env, res)))
4677 let (env, rty) = get_array_filter_return_type env ty in
4678 let fty =
4679 map_ty fty ~f:(function
4680 | Tfun ft -> Tfun { ft with ft_ret = MakeType.unenforced rty }
4681 | ty -> ty)
4683 make_call
4685 (Tast.make_typed_expr fpos fty (Aast.Id id))
4688 typed_unpack_element
4690 (* Special function `type_structure` *)
4691 | type_structure
4692 when String.equal type_structure SN.StdlibFunctions.type_structure
4693 && Int.equal (List.length el) 2
4694 && Option.is_none unpacked_element ->
4695 (match el with
4696 | [e1; e2] ->
4697 (match e2 with
4698 | (p, String cst) ->
4699 (* find the class constant implicitly defined by the typeconst *)
4700 let cid =
4701 match e1 with
4702 | (_, Class_const (cid, (_, x)))
4703 | (_, Class_get (cid, CGstring (_, x), _))
4704 when String.equal x SN.Members.mClass ->
4706 | _ -> (fst e1, CIexpr e1)
4708 class_const ~incl_tc:true env p (cid, (p, cst))
4709 | _ ->
4710 Errors.illegal_type_structure pos "second argument is not a string";
4711 expr_error env (Reason.Rwitness pos) e)
4712 | _ -> assert false)
4713 (* Special function `array_map` *)
4714 | array_map
4715 when String.equal array_map SN.StdlibFunctions.array_map
4716 && (not (List.is_empty el))
4717 && Option.is_none unpacked_element ->
4718 (* This uses the arity to determine a signature for array_map. But there
4719 * is more: for two-argument use of array_map, we specialize the return
4720 * type to the collection that's passed in, below. *)
4721 let (env, fty, tal) = fun_type_of_id env id explicit_targs el in
4722 let (env, fty) = Env.expand_type env fty in
4723 let r_fty = get_reason fty in
4725 Takes a Container type and returns a function that can "pack" a type
4726 into an array of appropriate shape, preserving the key type, i.e.:
4727 array -> f, where f R = array
4728 array<X> -> f, where f R = array<R>
4729 array<X, Y> -> f, where f R = array<X, R>
4730 Vector<X> -> f where f R = array<R>
4731 KeyedContainer<X, Y> -> f, where f R = array<X, R>
4732 Container<X> -> f, where f R = array<arraykey, R>
4733 X -> f, where f R = Y
4735 let rec build_output_container env (x : locl_ty) :
4736 env * (env -> locl_ty -> env * locl_ty) =
4737 let (env, x) = Env.expand_type env x in
4738 match deref x with
4739 | (r, Tvarray _) ->
4740 ( env,
4741 fun env tr ->
4742 let unification =
4743 TypecheckerOptions.hack_arr_dv_arrs (Env.get_tcopt env)
4745 (env, MakeType.varray ~unification r tr) )
4746 | (r, Tany _) ->
4747 (env, (fun env _ -> (env, mk (r, Typing_utils.tany env))))
4748 | (r, Terr) -> (env, (fun env _ -> (env, TUtils.terr env r)))
4749 | (r, Tunion tyl) ->
4750 let (env, builders) = List.map_env env tyl build_output_container in
4751 ( env,
4752 fun env tr ->
4753 let (env, tyl) =
4754 List.map_env env builders (fun env f -> f env tr)
4756 Typing_union.union_list env r tyl )
4757 | (r, Tintersection tyl) ->
4758 let (env, builders) = List.map_env env tyl build_output_container in
4759 ( env,
4760 fun env tr ->
4761 let (env, tyl) =
4762 List.map_env env builders (fun env f -> f env tr)
4764 Typing_intersection.intersect_list env r tyl )
4765 | (r, _) ->
4766 let (env, tk) = Env.fresh_type env p in
4767 let (env, tv) = Env.fresh_type env p in
4768 let unification =
4769 TypecheckerOptions.hack_arr_dv_arrs (Env.get_tcopt env)
4771 let try_vector env =
4772 let vector_type = MakeType.const_vector r_fty tv in
4773 let env = SubType.sub_type env x vector_type Errors.unify_error in
4774 (env, (fun env tr -> (env, MakeType.varray ~unification r tr)))
4776 let try_keyed_container env =
4777 let keyed_container_type = MakeType.keyed_container r_fty tk tv in
4778 let env =
4779 SubType.sub_type env x keyed_container_type Errors.unify_error
4781 (env, (fun env tr -> (env, MakeType.darray ~unification r tk tr)))
4783 let try_container env =
4784 let container_type = MakeType.container r_fty tv in
4785 let env =
4786 SubType.sub_type env x container_type Errors.unify_error
4788 ( env,
4789 fun env tr ->
4790 (env, MakeType.darray ~unification r (MakeType.arraykey r) tr)
4793 let (env, tr) =
4794 Errors.try_
4795 (fun () -> try_vector env)
4796 (fun _ ->
4797 Errors.try_
4798 (fun () -> try_keyed_container env)
4799 (fun _ ->
4800 Errors.try_
4801 (fun () -> try_container env)
4802 (fun _ ->
4803 (env, (fun env _ -> (env, Typing_utils.mk_tany env p))))))
4805 (env, tr)
4807 let (env, fty) =
4808 match (deref fty, el) with
4809 | ((_, Tfun funty), [_; x]) ->
4810 let (env, _tx, x) = expr env x in
4811 let (env, output_container) = build_output_container env x in
4812 begin
4813 match get_varray_inst funty.ft_ret.et_type with
4814 | None -> (env, fty)
4815 | Some elem_ty ->
4816 let (env, elem_ty) = output_container env elem_ty in
4817 let ft_ret = MakeType.unenforced elem_ty in
4818 (env, mk (r_fty, Tfun { funty with ft_ret }))
4820 | _ -> (env, fty)
4822 let (env, (tel, typed_unpack_element, ty)) =
4823 call ~expected p env fty el None
4825 make_call
4827 (Tast.make_typed_expr fpos fty (Aast.Id id))
4830 typed_unpack_element
4832 | _ -> dispatch_id env id
4834 (* Special Shapes:: function *)
4835 | Class_const (((_, CI (_, shapes)) as class_id), ((_, x) as method_id))
4836 when String.equal shapes SN.Shapes.cShapes ->
4837 begin
4838 match x with
4839 (* Special function `Shapes::idx` *)
4840 | idx when String.equal idx SN.Shapes.idx ->
4841 overload_function
4844 class_id
4845 method_id
4847 unpacked_element
4848 (fun env fty res el ->
4849 match el with
4850 | [shape; field] ->
4851 let (env, _ts, shape_ty) = expr env shape in
4852 Typing_shapes.idx
4854 shape_ty
4855 field
4856 None
4857 ~expr_pos:p
4858 ~fun_pos:(get_reason fty)
4859 ~shape_pos:(fst shape)
4860 | [shape; field; default] ->
4861 let (env, _ts, shape_ty) = expr env shape in
4862 let (env, _td, default_ty) = expr env default in
4863 Typing_shapes.idx
4865 shape_ty
4866 field
4867 (Some (fst default, default_ty))
4868 ~expr_pos:p
4869 ~fun_pos:(get_reason fty)
4870 ~shape_pos:(fst shape)
4871 | _ -> (env, res))
4872 (* Special function `Shapes::at` *)
4873 | at when String.equal at SN.Shapes.at ->
4874 overload_function
4877 class_id
4878 method_id
4880 unpacked_element
4881 (fun env _fty res el ->
4882 match el with
4883 | [shape; field] ->
4884 let (env, _te, shape_ty) = expr env shape in
4885 Typing_shapes.at
4887 ~expr_pos:p
4888 ~shape_pos:(fst shape)
4889 shape_ty
4890 field
4891 | _ -> (env, res))
4892 (* Special function `Shapes::keyExists` *)
4893 | key_exists when String.equal key_exists SN.Shapes.keyExists ->
4894 overload_function
4897 class_id
4898 method_id
4900 unpacked_element
4901 (fun env fty res el ->
4902 match el with
4903 | [shape; field] ->
4904 let (env, _te, shape_ty) = expr env shape in
4905 (* try accessing the field, to verify existence, but ignore
4906 * the returned type and keep the one coming from function
4907 * return type hint *)
4908 let (env, _) =
4909 Typing_shapes.idx
4911 shape_ty
4912 field
4913 None
4914 ~expr_pos:p
4915 ~fun_pos:(get_reason fty)
4916 ~shape_pos:(fst shape)
4918 (env, res)
4919 | _ -> (env, res))
4920 (* Special function `Shapes::removeKey` *)
4921 | remove_key when String.equal remove_key SN.Shapes.removeKey ->
4922 overload_function
4925 class_id
4926 method_id
4928 unpacked_element
4929 (fun env _ res el ->
4930 match el with
4931 | [shape; field] ->
4932 begin
4933 match shape with
4934 | (_, Lvar (_, lvar))
4935 | (_, Callconv (Ast_defs.Pinout, (_, Lvar (_, lvar)))) ->
4936 let (env, _te, shape_ty) = expr env shape in
4937 let (env, shape_ty) =
4938 Typing_shapes.remove_key p env shape_ty field
4940 let env = set_valid_rvalue p env lvar shape_ty in
4941 (env, res)
4942 | _ ->
4943 Errors.invalid_shape_remove_key (fst shape);
4944 (env, res)
4946 | _ -> (env, res))
4947 (* Special function `Shapes::toArray` *)
4948 | to_array when String.equal to_array SN.Shapes.toArray ->
4949 overload_function
4952 class_id
4953 method_id
4955 unpacked_element
4956 (fun env _ res el ->
4957 match el with
4958 | [shape] ->
4959 let (env, _te, shape_ty) = expr env shape in
4960 Typing_shapes.to_array env p shape_ty res
4961 | _ -> (env, res))
4962 (* Special function `Shapes::toDict` *)
4963 | to_dict when String.equal to_dict SN.Shapes.toDict ->
4964 overload_function
4967 class_id
4968 method_id
4970 unpacked_element
4971 (fun env _ res el ->
4972 match el with
4973 | [shape] ->
4974 let (env, _te, shape_ty) = expr env shape in
4975 Typing_shapes.to_dict env p shape_ty res
4976 | _ -> (env, res))
4977 | _ -> dispatch_class_const env class_id method_id
4979 (* Special function `parent::__construct` *)
4980 | Class_const ((pos, CIparent), ((_, construct) as id))
4981 when String.equal construct SN.Members.__construct ->
4982 let (env, tel, typed_unpack_element, ty, pty, ctor_fty) =
4983 call_parent_construct p env el unpacked_element
4985 make_call
4987 (Tast.make_typed_expr
4988 fpos
4989 ctor_fty
4990 (Aast.Class_const (((pos, pty), Aast.CIparent), id)))
4991 [] (* tal: no type arguments to constructor *)
4993 typed_unpack_element
4995 (* Calling parent / class method *)
4996 | Class_const (class_id, m) -> dispatch_class_const env class_id m
4997 (* Call instance method *)
4998 | Obj_get (e1, (pos_id, Id m), nullflavor, false)
4999 when not (TypecheckerOptions.method_call_inference (Env.get_tcopt env)) ->
5000 let (env, te1, ty1) = expr ~accept_using_var:true env e1 in
5001 let nullsafe =
5002 match nullflavor with
5003 | OG_nullthrows -> None
5004 | OG_nullsafe -> Some p
5006 let (env, (tfty, tal)) =
5007 TOG.obj_get
5008 ~obj_pos:(fst e1)
5009 ~is_method:true
5010 ~inst_meth:false
5011 ~nullsafe:(Option.map ~f:(fun p -> Reason.Rnullsafe_op p) nullsafe)
5012 ~coerce_from_ty:None
5013 ~explicit_targs
5014 ~class_id:(CIexpr e1)
5015 ~member_id:m
5016 ~on_error:Errors.unify_error
5020 check_disposable_in_return env tfty;
5021 let (env, (tel, typed_unpack_element, ty)) =
5022 call ~nullsafe ~expected p env tfty el unpacked_element
5024 make_call
5026 (Tast.make_typed_expr
5027 fpos
5028 tfty
5029 (Aast.Obj_get
5030 ( te1,
5031 Tast.make_typed_expr pos_id tfty (Aast.Id m),
5032 nullflavor,
5033 false )))
5036 typed_unpack_element
5038 (* Call instance method using new method call inference *)
5039 | Obj_get (receiver, (pos_id, Id meth), nullflavor, false) ->
5040 (*****
5041 Typecheck `Obj_get` by enforcing that:
5042 - `<instance_type>` <: `Thas_member(m, #1)`
5043 where #1 is a fresh type variable.
5044 *****)
5045 let (env, typed_receiver, receiver_ty) =
5046 expr ~accept_using_var:true env receiver
5048 let env = might_throw env in
5049 let nullsafe =
5050 match nullflavor with
5051 | OG_nullthrows -> None
5052 | OG_nullsafe -> Some p
5054 (* Generate a fresh type `method_ty` for the type of the
5055 instance method, i.e. #1 *)
5056 let (env, method_ty) = Env.fresh_type env p in
5057 (* Create `Thas_member` constraint type *)
5058 let reason = Reason.Rwitness (fst receiver) in
5059 let has_method_ty =
5060 MakeType.has_member
5061 reason
5062 ~name:meth
5063 ~ty:method_ty
5064 ~class_id:(CIexpr receiver)
5065 ~explicit_targs:(Some explicit_targs)
5067 let env = Env.set_tyvar_variance env method_ty in
5068 let (env, has_method_super_ty) =
5069 if Option.is_none nullsafe then
5070 (env, has_method_ty)
5071 else
5072 (* If null-safe, then `receiver_ty` <: `?Thas_member(m, #1)`,
5073 but *unlike* property access typing in `expr_`, we still use `#1` as
5074 our "result" if `receiver_ty` is nullable (as opposed to `?#1`),
5075 deferring null-safety handling to after `call` *)
5076 let r = Reason.Rnullsafe_op p in
5077 let null_ty = MakeType.null r in
5078 Union.union_i env r has_method_ty null_ty
5080 let env =
5081 Type.sub_type_i
5082 (fst receiver)
5083 Reason.URnone
5085 (LoclType receiver_ty)
5086 has_method_super_ty
5087 Errors.unify_error
5089 (* Perhaps solve for `method_ty`. Opening and closing a scope is too coarse
5090 here - type parameters are localised to fresh type variables over the
5091 course of subtyping above, and we do not want to solve these until later.
5092 Once we typecheck all function calls with a subtyping of function types,
5093 we should not need to solve early at all - transitive closure of
5094 subtyping should give enough information. *)
5095 let env =
5096 match get_var method_ty with
5097 | Some var ->
5098 Typing_solver.solve_to_equal_bound_or_wrt_variance
5100 Reason.Rnone
5102 Errors.unify_error
5103 | None -> env
5105 let localize_targ env (_, targ) = Phase.localize_targ env targ in
5106 let (env, typed_targs) =
5107 List.map_env env ~f:(localize_targ ~check_well_kinded:true) explicit_targs
5109 check_disposable_in_return env method_ty;
5110 let (env, (typed_params, typed_unpack_element, ret_ty)) =
5111 call ~nullsafe ~expected ?in_await p env method_ty el unpacked_element
5113 (* If the call is nullsafe AND the receiver is nullable,
5114 make the return type nullable too *)
5115 let (env, ret_ty) =
5116 if Option.is_some nullsafe then
5117 let r = Reason.Rnullsafe_op p in
5118 let null_ty = MakeType.null r in
5119 let (env, null_or_nothing_ty) =
5120 Inter.intersect env ~r null_ty receiver_ty
5122 let (env, ret_option_ty) = Union.union env null_or_nothing_ty ret_ty in
5123 (env, ret_option_ty)
5124 else
5125 (env, ret_ty)
5127 make_call
5129 (Tast.make_typed_expr
5130 fpos
5131 method_ty
5132 (Aast.Obj_get
5133 ( typed_receiver,
5134 Tast.make_typed_expr pos_id method_ty (Aast.Id meth),
5135 nullflavor,
5136 false )))
5137 typed_targs
5138 typed_params
5139 typed_unpack_element
5140 ret_ty
5141 (* Function invocation *)
5142 | Fun_id x ->
5143 let (env, fty, tal) = fun_type_of_id env x explicit_targs el in
5144 check_disposable_in_return env fty;
5145 let (env, (tel, typed_unpack_element, ty)) =
5146 call ~expected p env fty el unpacked_element
5148 make_call
5150 (Tast.make_typed_expr fpos fty (Aast.Fun_id x))
5153 typed_unpack_element
5155 | Id id -> dispatch_id env id
5156 | _ ->
5157 let (env, te, fty) = expr env e in
5158 let (env, fty) =
5159 Typing_solver.expand_type_and_solve
5160 ~description_of_expected:"a function value"
5162 fpos
5164 Errors.unify_error
5166 check_disposable_in_return env fty;
5167 let (env, (tel, typed_unpack_element, ty)) =
5168 call ~expected p env fty el unpacked_element
5170 make_call
5173 (* tal: no type arguments to function values, as they are non-generic *)
5176 typed_unpack_element
5179 and fun_type_of_id env x tal el =
5180 match Env.get_fun env (snd x) with
5181 | None ->
5182 let (env, _, ty) = unbound_name env x (Pos.none, Aast.Null) in
5183 (env, ty, [])
5184 | Some { fe_type; fe_pos; fe_deprecated; _ } ->
5185 (match get_node fe_type with
5186 | Tfun ft ->
5187 let ft =
5188 Typing_special_fun.transform_special_fun_ty ft x (List.length el)
5190 let ety_env = Phase.env_with_self env ~on_error:Errors.ignore_error in
5191 let (env, tal) =
5192 Phase.localize_targs
5193 ~check_well_kinded:true
5194 ~is_method:true
5195 ~def_pos:fe_pos
5196 ~use_pos:(fst x)
5197 ~use_name:(strip_ns (snd x))
5199 ft.ft_tparams
5200 (List.map ~f:snd tal)
5202 let ft =
5203 Typing_enforceability.compute_enforced_and_pessimize_fun_type env ft
5205 let use_pos = fst x in
5206 let def_pos = fe_pos in
5207 let (env, ft) =
5208 Phase.(
5209 localize_ft
5210 ~instantiation:
5211 { use_name = strip_ns (snd x); use_pos; explicit_targs = tal }
5212 ~def_pos
5213 ~ety_env
5217 let fty = mk (get_reason fe_type |> Typing_reason.localize, Tfun ft) in
5218 TVis.check_deprecated ~use_pos ~def_pos fe_deprecated;
5219 (env, fty, tal)
5220 | _ -> failwith "Expected function type")
5223 * Checks if a class (given by cty) contains a given static method.
5225 * We could refactor this + class_get
5227 and class_contains_smethod env cty (_pos, mid) =
5228 let lookup_member ty =
5229 match get_class_type ty with
5230 | Some ((_, c), _, _) ->
5231 (match Env.get_class env c with
5232 | None -> false
5233 | Some class_ ->
5234 Option.is_some @@ Env.get_static_member true env class_ mid)
5235 | None -> false
5237 let (_env, tyl) = TUtils.get_concrete_supertypes env cty in
5238 List.exists tyl ~f:lookup_member
5240 and class_get
5241 ~is_method
5242 ~is_const
5243 ~coerce_from_ty
5244 ?(explicit_targs = [])
5245 ?(incl_tc = false)
5246 ?(is_function_pointer = false)
5249 (p, mid)
5250 cid =
5251 let (env, this_ty) =
5252 if is_method then
5253 this_for_method env cid cty
5254 else
5255 (env, cty)
5257 class_get_
5258 ~is_method
5259 ~is_const
5260 ~this_ty
5261 ~explicit_targs
5262 ~incl_tc
5263 ~coerce_from_ty
5264 ~is_function_pointer
5268 (p, mid)
5270 and class_get_
5271 ~is_method
5272 ~is_const
5273 ~this_ty
5274 ~coerce_from_ty
5275 ?(explicit_targs = [])
5276 ?(incl_tc = false)
5277 ?(is_function_pointer = false)
5281 (p, mid) =
5282 let (env, cty) = Env.expand_type env cty in
5283 match deref cty with
5284 | (r, Tany _) -> (env, (mk (r, Typing_utils.tany env), []))
5285 | (r, Terr) -> (env, (err_witness env (Reason.to_pos r), []))
5286 | (_, Tdynamic) -> (env, (cty, []))
5287 | (_, Tunion tyl) ->
5288 let (env, pairs) =
5289 List.map_env env tyl (fun env ty ->
5290 class_get
5291 ~is_method
5292 ~is_const
5293 ~explicit_targs
5294 ~incl_tc
5295 ~coerce_from_ty
5296 ~is_function_pointer
5299 (p, mid)
5300 cid)
5302 let (env, ty) =
5303 Union.union_list env (get_reason cty) (List.map ~f:fst pairs)
5305 (env, (ty, []))
5306 | (_, Tintersection tyl) ->
5307 let (env, pairs) =
5308 TUtils.run_on_intersection env tyl ~f:(fun env ty ->
5309 class_get
5310 ~is_method
5311 ~is_const
5312 ~explicit_targs
5313 ~incl_tc
5314 ~coerce_from_ty
5315 ~is_function_pointer
5318 (p, mid)
5319 cid)
5321 let (env, ty) =
5322 Inter.intersect_list env (get_reason cty) (List.map ~f:fst pairs)
5324 (env, (ty, []))
5325 | (_, Tnewtype (_, _, ty))
5326 | (_, Tdependent (_, ty)) ->
5327 class_get_
5328 ~is_method
5329 ~is_const
5330 ~this_ty
5331 ~explicit_targs
5332 ~incl_tc
5333 ~coerce_from_ty
5334 ~is_function_pointer
5338 (p, mid)
5339 | (r, Tgeneric _) ->
5340 let (env, tyl) = TUtils.get_concrete_supertypes env cty in
5341 if List.is_empty tyl then begin
5342 Errors.non_class_member
5343 ~is_method
5346 (Typing_print.error env cty)
5347 (get_pos cty);
5348 (env, (err_witness env p, []))
5349 end else
5350 let (env, ty) = Typing_intersection.intersect_list env r tyl in
5351 class_get_
5352 ~is_method
5353 ~is_const
5354 ~this_ty
5355 ~explicit_targs
5356 ~incl_tc
5357 ~coerce_from_ty
5358 ~is_function_pointer
5362 (p, mid)
5363 | (_, Tclass ((_, c), _, paraml)) ->
5364 let class_ = Env.get_class env c in
5365 (match class_ with
5366 | None -> (env, (Typing_utils.mk_tany env p, []))
5367 | Some class_ ->
5368 let (env, this_ty) = ExprDepTy.make env cid this_ty in
5369 (* We need to instantiate generic parameters in the method signature *)
5370 let ety_env =
5372 type_expansions = [];
5373 this_ty;
5374 substs = TUtils.make_locl_subst_for_class_tparams class_ paraml;
5375 on_error = Errors.ignore_error;
5378 let get_smember_from_constraints env class_info =
5379 let upper_bounds =
5380 Cls.upper_bounds_on_this_from_constraints class_info
5382 let (env, upper_bounds) =
5383 List.map_env env upper_bounds ~f:(fun env up ->
5384 Phase.localize ~ety_env env up)
5386 let (env, inter_ty) =
5387 Inter.intersect_list env (Reason.Rwitness p) upper_bounds
5389 class_get_
5390 ~is_method
5391 ~is_const
5392 ~this_ty
5393 ~explicit_targs
5394 ~incl_tc
5395 ~coerce_from_ty
5396 ~is_function_pointer
5399 inter_ty
5400 (p, mid)
5402 let try_get_smember_from_constraints env class_info =
5403 Errors.try_with_error
5404 (fun () -> get_smember_from_constraints env class_info)
5405 (fun () ->
5406 TOG.smember_not_found
5408 ~is_const
5409 ~is_method
5410 ~is_function_pointer
5411 class_info
5413 Errors.unify_error;
5414 (env, (TUtils.terr env Reason.Rnone, [])))
5416 if is_const then (
5417 let const =
5418 if incl_tc then
5419 Env.get_const env class_ mid
5420 else
5421 match Env.get_typeconst env class_ mid with
5422 | Some _ ->
5423 Errors.illegal_typeconst_direct_access p;
5424 None
5425 | None -> Env.get_const env class_ mid
5427 match const with
5428 | None when Cls.has_upper_bounds_on_this_from_constraints class_ ->
5429 try_get_smember_from_constraints env class_
5430 | None ->
5431 TOG.smember_not_found
5433 ~is_const
5434 ~is_method
5435 ~is_function_pointer
5436 class_
5438 Errors.unify_error;
5439 (env, (TUtils.terr env Reason.Rnone, []))
5440 | Some { cc_type; cc_abstract; cc_pos; _ } ->
5441 let (env, cc_locl_type) = Phase.localize ~ety_env env cc_type in
5442 ( if cc_abstract then
5443 match cid with
5444 | CIstatic
5445 | CIexpr _ ->
5447 | _ ->
5448 let cc_name = Cls.name class_ ^ "::" ^ mid in
5449 Errors.abstract_const_usage p cc_pos cc_name );
5450 (env, (cc_locl_type, []))
5451 ) else
5452 let static_member_opt =
5453 Env.get_static_member is_method env class_ mid
5455 (match static_member_opt with
5456 | None when Cls.has_upper_bounds_on_this_from_constraints class_ ->
5457 try_get_smember_from_constraints env class_
5458 | None ->
5459 TOG.smember_not_found
5461 ~is_const
5462 ~is_method
5463 ~is_function_pointer
5464 class_
5466 Errors.unify_error;
5467 (env, (TUtils.terr env Reason.Rnone, []))
5468 | Some
5470 ce_visibility = vis;
5471 ce_type = (lazy member_decl_ty);
5472 ce_deprecated;
5474 } as ce ) ->
5475 let def_pos = get_pos member_decl_ty in
5476 TVis.check_class_access
5477 ~use_pos:p
5478 ~def_pos
5480 (vis, get_ce_lsb ce)
5482 class_;
5483 TVis.check_deprecated ~use_pos:p ~def_pos ce_deprecated;
5484 check_class_get env p def_pos c mid ce cid is_function_pointer;
5485 let (env, member_ty, et_enforced, tal) =
5486 match deref member_decl_ty with
5487 (* We special case Tfun here to allow passing in explicit tparams to localize_ft. *)
5488 | (r, Tfun ft) when is_method ->
5489 let (env, explicit_targs) =
5490 Phase.localize_targs
5491 ~check_well_kinded:true
5492 ~is_method:true
5493 ~def_pos
5494 ~use_pos:p
5495 ~use_name:(strip_ns mid)
5497 ft.ft_tparams
5498 (List.map ~f:snd explicit_targs)
5500 let ft =
5501 Typing_enforceability.compute_enforced_and_pessimize_fun_type
5505 let (env, ft) =
5506 Phase.(
5507 localize_ft
5508 ~instantiation:
5509 { use_name = strip_ns mid; use_pos = p; explicit_targs }
5510 ~ety_env
5511 ~def_pos
5515 ( env,
5516 mk (Typing_reason.localize r, Tfun ft),
5517 Unenforced,
5518 explicit_targs )
5519 (* unused *)
5520 | _ ->
5521 let { et_type; et_enforced } =
5522 Typing_enforceability.compute_enforced_and_pessimize_ty
5524 member_decl_ty
5526 let (env, member_ty) = Phase.localize ~ety_env env et_type in
5527 (* TODO(T52753871) make function just return possibly_enforced_ty
5528 * after considering intersection case *)
5529 (env, member_ty, et_enforced, [])
5531 let (env, member_ty) =
5532 if Cls.has_upper_bounds_on_this_from_constraints class_ then
5533 let ((env, (member_ty', _)), succeed) =
5534 Errors.try_with_error
5535 (fun () -> (get_smember_from_constraints env class_, true))
5536 (fun () ->
5537 (* No eligible functions found in constraints *)
5538 ((env, (MakeType.mixed Reason.Rnone, [])), false))
5540 if succeed then
5541 Inter.intersect env (Reason.Rwitness p) member_ty member_ty'
5542 else
5543 (env, member_ty)
5544 else
5545 (env, member_ty)
5547 let env =
5548 match coerce_from_ty with
5549 | None -> env
5550 | Some (p, ur, ty) ->
5551 Typing_coercion.coerce_type
5556 { et_type = member_ty; et_enforced }
5557 Errors.unify_error
5559 (env, (member_ty, tal))))
5560 | (_, Tunapplied_alias _) ->
5561 Typing_defs.error_Tunapplied_alias_in_illegal_context ()
5562 | ( _,
5563 ( Tvar _ | Tnonnull | Tvarray _ | Tdarray _ | Tvarray_or_darray _
5564 | Tvec_or_dict _ | Toption _ | Tprim _ | Tfun _ | Ttuple _ | Tobject
5565 | Tshape _ | Taccess _ ) ) ->
5566 Errors.non_class_member
5567 ~is_method
5570 (Typing_print.error env cty)
5571 (get_pos cty);
5572 (env, (err_witness env p, []))
5574 and class_id_for_new
5575 ~exact p env (cid : Nast.class_id_) (explicit_targs : Nast.targ list) :
5576 newable_class_info =
5577 let (env, tal, te, cid_ty) =
5578 static_class_id
5579 ~check_targs_well_kinded:true
5580 ~check_explicit_targs:true
5581 ~exact
5582 ~check_constraints:false
5585 explicit_targs
5588 (* Need to deal with union case *)
5589 let rec get_info res tyl =
5590 match tyl with
5591 | [] -> (env, tal, te, res)
5592 | ty :: tyl ->
5593 (match get_node ty with
5594 | Tunion tyl'
5595 | Tintersection tyl' ->
5596 get_info res (tyl' @ tyl)
5597 | _ ->
5598 (* Instantiation on an abstract class (e.g. from classname<T>) is
5599 * via the base type (to check constructor args), but the actual
5600 * type `ty` must be preserved. *)
5601 (match get_node (TUtils.get_base_type env ty) with
5602 | Tdynamic -> get_info (`Dynamic :: res) tyl
5603 | Tclass (sid, _, _) ->
5604 let class_ = Env.get_class env (snd sid) in
5605 (match class_ with
5606 | None -> get_info res tyl
5607 | Some class_info ->
5608 (match (te, cid_ty) with
5609 (* When computing the classes for a new T() where T is a generic,
5610 * the class must be consistent (final, final constructor, or
5611 * <<__ConsistentConstruct>>) for its constructor to be considered *)
5612 | ((_, Aast.CI (_, c)), ty) when is_generic_equal_to c ty ->
5613 (* Only have this choosing behavior for new T(), not all generic types
5614 * i.e. new classname<T>, TODO: T41190512 *)
5615 if Tast_utils.valid_newable_class class_info then
5616 get_info (`Class (sid, class_info, ty) :: res) tyl
5617 else
5618 get_info res tyl
5619 | _ -> get_info (`Class (sid, class_info, ty) :: res) tyl))
5620 | _ -> get_info res tyl))
5622 get_info [] [cid_ty]
5624 (* To be a valid trait declaration, all of its 'require extends' must
5625 * match; since there's no multiple inheritance, it follows that all of
5626 * the 'require extends' must belong to the same inheritance hierarchy
5627 * and one of them should be the child of all the others *)
5628 and trait_most_concrete_req_class trait env =
5629 List.fold
5630 (Cls.all_ancestor_reqs trait)
5632 begin
5633 fun acc (_p, ty) ->
5634 let (_r, (_p, name), _paraml) = TUtils.unwrap_class_type ty in
5635 let keep =
5636 match acc with
5637 | Some (c, _ty) -> Cls.has_ancestor c name
5638 | None -> false
5640 if keep then
5642 else
5643 let class_ = Env.get_class env name in
5644 match class_ with
5645 | None -> acc
5646 | Some c when Ast_defs.(equal_class_kind (Cls.kind c) Cinterface) ->
5648 | Some c when Ast_defs.(equal_class_kind (Cls.kind c) Ctrait) ->
5649 (* this is an error case for which Typing_check_decls spits out
5650 * an error, but does *not* currently remove the offending
5651 * 'require extends' or 'require implements' *)
5653 | Some c -> Some (c, ty)
5655 ~init:None
5657 (* When invoking a method the class_id is used to determine what class we
5658 * lookup the method in, but the type of 'this' will be the late bound type.
5659 * For example:
5661 * class C {
5662 * public static function get(): this { return new static(); }
5664 * public static function alias(): this { return self::get(); }
5667 * In C::alias, when we invoke self::get(), 'self' is resolved to the class
5668 * in the lexical scope (C), so call C::get. However the method is executed in
5669 * the current context, so static inside C::get will be resolved to the late
5670 * bound type (get_called_class() within C::alias).
5672 * This means when determining the type of this, CIparent and CIself should be
5673 * changed to CIstatic. For the other cases of C::get() or $c::get(), we only
5674 * look at the left hand side of the '::' and use the type type associated
5675 * with it.
5677 * Thus C::get() will return a type C, while $c::get() will return the same
5678 * type as $c.
5680 and this_for_method env cid default_ty =
5681 match cid with
5682 | CIparent
5683 | CIself
5684 | CIstatic ->
5685 let p = get_pos default_ty in
5686 let (env, _tal, _te, ty) =
5687 static_class_id ~check_constraints:false p env [] CIstatic
5689 ExprDepTy.make env CIstatic ty
5690 | _ -> (env, default_ty)
5692 (** Resolve class expressions like `parent`, `self`, `static`, classnames
5693 and others. *)
5694 and static_class_id
5695 ?(check_targs_well_kinded = false)
5696 ?(exact = Nonexact)
5697 ?(check_explicit_targs = false)
5698 ~(check_constraints : bool)
5699 (p : pos)
5700 (env : env)
5701 (tal : Nast.targ list) :
5702 Nast.class_id_ -> env * Tast.targ list * Tast.class_id * locl_ty =
5703 let make_result env tal te ty = (env, tal, ((p, ty), te), ty) in
5704 function
5705 | CIparent ->
5706 (match Env.get_self_id env with
5707 | Some self ->
5708 (match Env.get_class env self with
5709 | Some trait when Ast_defs.(equal_class_kind (Cls.kind trait) Ctrait) ->
5710 (match trait_most_concrete_req_class trait env with
5711 | None ->
5712 Errors.parent_in_trait p;
5713 make_result env [] Aast.CIparent (err_witness env p)
5714 | Some (_, parent_ty) ->
5715 (* inside a trait, parent is SN.Typehints.this, but with the
5716 * type of the most concrete class that the trait has
5717 * "require extend"-ed *)
5718 let r = Reason.Rwitness p in
5719 let (env, parent_ty) =
5720 Phase.localize_with_self env ~ignore_errors:true parent_ty
5722 make_result env [] Aast.CIparent (mk (r, TUtils.this_of parent_ty)))
5723 | _ ->
5724 let parent =
5725 match Env.get_parent_ty env with
5726 | None ->
5727 Errors.parent_undefined p;
5728 mk (Reason.none, Typing_defs.make_tany ())
5729 | Some parent -> parent
5731 let r = Reason.Rwitness p in
5732 let (env, parent) =
5733 Phase.localize_with_self env ~ignore_errors:true parent
5735 (* parent is still technically the same object. *)
5736 make_result
5739 Aast.CIparent
5740 (mk (r, TUtils.this_of (mk (r, get_node parent)))))
5741 | None ->
5742 let parent =
5743 match Env.get_parent_ty env with
5744 | None ->
5745 Errors.parent_undefined p;
5746 mk (Reason.none, Typing_defs.make_tany ())
5747 | Some parent -> parent
5749 let r = Reason.Rwitness p in
5750 let (env, parent) =
5751 Phase.localize_with_self env ~ignore_errors:true parent
5753 (* parent is still technically the same object. *)
5754 make_result
5757 Aast.CIparent
5758 (mk (r, TUtils.this_of (mk (r, get_node parent)))))
5759 | CIstatic ->
5760 let ty =
5761 match Env.get_self_ty env with
5762 | Some ty -> mk (Reason.Rwitness p, TUtils.this_of ty)
5763 | None ->
5764 (* Naming phase has already checked and replaced CIstatic with CI if outside a class *)
5765 Errors.internal_error p "Unexpected CIstatic";
5766 Typing_utils.mk_tany env p
5768 make_result env [] Aast.CIstatic ty
5769 | CIself ->
5770 let ty =
5771 match Env.get_self_class_type env with
5772 | Some (c, _, tyl) -> mk (Reason.Rwitness p, Tclass (c, exact, tyl))
5773 | None ->
5774 (* Naming phase has already checked and replaced CIself with CI if outside a class *)
5775 Errors.internal_error p "Unexpected CIself";
5776 Typing_utils.mk_tany env p
5778 make_result env [] Aast.CIself ty
5779 | CI ((p, id) as c) ->
5780 begin
5781 match Env.get_pos_and_kind_of_generic env id with
5782 | Some (def_pos, kind) ->
5783 let simple_kind = Typing_kinding_defs.Simple.from_full_kind kind in
5784 let param_nkinds =
5785 Typing_kinding_defs.Simple.get_named_parameter_kinds simple_kind
5787 let (env, tal) =
5788 Phase.localize_targs_with_kinds
5789 ~check_well_kinded:check_targs_well_kinded
5790 ~is_method:true
5791 ~def_pos
5792 ~use_pos:p
5793 ~use_name:(strip_ns (snd c))
5794 ~check_explicit_targs
5796 param_nkinds
5797 (List.map ~f:snd tal)
5799 let r = Reason.Rhint p in
5800 let type_args = List.map tal fst in
5801 let tgeneric = MakeType.generic ~type_args r id in
5802 make_result env tal (Aast.CI c) tgeneric
5803 | None ->
5804 (* Not a type parameter *)
5805 let class_ = Env.get_class env id in
5806 (match class_ with
5807 | None -> make_result env [] (Aast.CI c) (Typing_utils.mk_tany env p)
5808 | Some class_ ->
5809 let (env, ty, tal) =
5810 List.map ~f:snd tal
5811 |> Phase.localize_targs_and_check_constraints
5812 ~exact
5813 ~check_well_kinded:check_targs_well_kinded
5814 ~check_constraints
5815 ~def_pos:(Cls.pos class_)
5816 ~use_pos:p
5817 ~check_explicit_targs
5820 (Cls.tparams class_)
5822 make_result env tal (Aast.CI c) ty)
5824 | CIexpr ((p, _) as e) ->
5825 let (env, te, ty) = expr env e ~allow_awaitable:(*?*) false in
5826 let rec resolve_ety env ty =
5827 let (env, ty) =
5828 Typing_solver.expand_type_and_solve
5829 ~description_of_expected:"an object"
5833 Errors.unify_error
5835 let base_ty = TUtils.get_base_type env ty in
5836 match deref base_ty with
5837 | (_, Tnewtype (classname, [the_cls], _))
5838 when String.equal classname SN.Classes.cClassname ->
5839 resolve_ety env the_cls
5840 | (_, Tgeneric _)
5841 | (_, Tclass _) ->
5842 (env, ty)
5843 | (r, Tunion tyl) ->
5844 let (env, tyl) = List.map_env env tyl resolve_ety in
5845 (env, MakeType.union r tyl)
5846 | (r, Tintersection tyl) ->
5847 let (env, tyl) = TUtils.run_on_intersection env tyl ~f:resolve_ety in
5848 Inter.intersect_list env r tyl
5849 | (_, Tdynamic) -> (env, base_ty)
5850 | (_, (Tany _ | Tprim Tstring | Tobject)) when not (Env.is_strict env) ->
5851 (env, Typing_utils.mk_tany env p)
5852 | (_, Terr) -> (env, err_witness env p)
5853 | (r, Tvar _) ->
5854 Errors.unknown_type "an object" p (Reason.to_string "It is unknown" r);
5855 (env, err_witness env p)
5856 | (_, Tunapplied_alias _) ->
5857 Typing_defs.error_Tunapplied_alias_in_illegal_context ()
5858 | ( _,
5859 ( Tany _ | Tnonnull | Tvarray _ | Tdarray _ | Tvarray_or_darray _
5860 | Tvec_or_dict _ | Toption _ | Tprim _ | Tfun _ | Ttuple _
5861 | Tnewtype _ | Tdependent _ | Tobject | Tshape _ | Taccess _ ) ) ->
5862 Errors.expected_class
5863 ~suffix:(", but got " ^ Typing_print.error env base_ty)
5865 (env, err_witness env p)
5867 let (env, result_ty) = resolve_ety env ty in
5868 make_result env [] (Aast.CIexpr te) result_ty
5870 and call_construct p env class_ params el unpacked_element cid cid_ty =
5871 let cid_ty =
5872 match Env.get_self_ty env with
5873 | Some ty when Nast.equal_class_id_ cid CIparent ->
5874 mk (Reason.Rwitness p, TUtils.this_of ty)
5875 | _ -> cid_ty
5877 let ety_env =
5879 type_expansions = [];
5880 this_ty = cid_ty;
5881 substs = TUtils.make_locl_subst_for_class_tparams class_ params;
5882 on_error = Errors.unify_error_at p;
5885 let env =
5886 Phase.check_tparams_constraints ~use_pos:p ~ety_env env (Cls.tparams class_)
5888 let env =
5889 Phase.check_where_constraints
5890 ~in_class:true
5891 ~use_pos:p
5892 ~definition_pos:(Cls.pos class_)
5893 ~ety_env
5895 (Cls.where_constraints class_)
5897 let cstr = Env.get_construct env class_ in
5898 let mode = Env.get_mode env in
5899 match fst cstr with
5900 | None ->
5902 ((not (List.is_empty el)) || Option.is_some unpacked_element)
5903 && (FileInfo.is_strict mode || FileInfo.(equal_mode mode Mpartial))
5904 && Cls.members_fully_known class_
5905 then
5906 Errors.constructor_no_args p;
5907 let (env, tel, _tyl) = exprs env el ~allow_awaitable:(*?*) false in
5908 (env, tel, None, TUtils.terr env Reason.Rnone)
5909 | Some { ce_visibility = vis; ce_type = (lazy m); ce_deprecated; _ } ->
5910 let def_pos = get_pos m in
5911 TVis.check_obj_access ~use_pos:p ~def_pos env vis;
5912 TVis.check_deprecated ~use_pos:p ~def_pos ce_deprecated;
5913 (* Obtain the type of the constructor *)
5914 let (env, m) =
5915 let r = get_reason m |> Typing_reason.localize in
5916 match get_node m with
5917 | Tfun ft ->
5918 let ft =
5919 Typing_enforceability.compute_enforced_and_pessimize_fun_type env ft
5921 (* This creates type variables for non-denotable type parameters on constructors.
5922 * These are notably different from the tparams on the class, which are handled
5923 * at the top of this function. User-written type parameters on constructors
5924 * are still a parse error. This is a no-op if ft.ft_tparams is empty. *)
5925 let (env, implicit_constructor_targs) =
5926 Phase.localize_targs
5927 ~check_well_kinded:true
5928 ~is_method:true
5929 ~def_pos
5930 ~use_pos:p
5931 ~use_name:"constructor"
5933 ft.ft_tparams
5936 let (env, ft) =
5937 Phase.(
5938 localize_ft
5939 ~instantiation:
5941 use_name = "constructor";
5942 use_pos = p;
5943 explicit_targs = implicit_constructor_targs;
5945 ~ety_env
5946 ~def_pos
5950 (env, mk (r, Tfun ft))
5951 | _ ->
5952 Errors.internal_error p "Expected function type for constructor";
5953 let ty = TUtils.terr env r in
5954 (env, ty)
5956 let (env, (tel, typed_unpack_element, _ty)) =
5957 call ~expected:None p env m el unpacked_element
5959 (env, tel, typed_unpack_element, m)
5961 and check_arity ?(did_unpack = false) pos pos_def ft (arity : int) =
5962 let exp_min = Typing_defs.arity_min ft in
5963 if arity < exp_min then
5964 Errors.typing_too_few_args exp_min arity pos pos_def None;
5965 match ft.ft_arity with
5966 | Fstandard ->
5967 let exp_max = List.length ft.ft_params in
5968 let arity =
5969 if did_unpack then
5970 arity + 1
5971 else
5972 arity
5974 if arity > exp_max then
5975 Errors.typing_too_many_args exp_max arity pos pos_def None
5976 | Fvariadic _ -> ()
5978 and check_lambda_arity lambda_pos def_pos lambda_ft expected_ft =
5979 match (lambda_ft.ft_arity, expected_ft.ft_arity) with
5980 | (Fstandard, Fstandard) ->
5981 let expected_min = Typing_defs.arity_min expected_ft in
5982 let lambda_min = Typing_defs.arity_min lambda_ft in
5983 if lambda_min < expected_min then
5984 Errors.typing_too_few_args expected_min lambda_min lambda_pos def_pos None;
5985 if lambda_min > expected_min then
5986 Errors.typing_too_many_args
5987 expected_min
5988 lambda_min
5989 lambda_pos
5990 def_pos
5991 None
5992 | (_, _) -> ()
5994 (* The variadic capture argument is an array listing the passed
5995 * variable arguments for the purposes of the function body; callsites
5996 * should not unify with it *)
5997 and variadic_param env ft =
5998 match ft.ft_arity with
5999 | Fvariadic param -> (env, Some param)
6000 | Fstandard -> (env, None)
6002 and param_modes ?(is_variadic = false) ({ fp_pos; _ } as fp) (pos, e) =
6003 match (get_fp_mode fp, e) with
6004 | (FPnormal, Callconv _) ->
6005 Errors.inout_annotation_unexpected pos fp_pos is_variadic
6006 | (FPnormal, _) -> ()
6007 | (FPinout, Callconv (Ast_defs.Pinout, _)) -> ()
6008 | (FPinout, _) -> Errors.inout_annotation_missing pos fp_pos
6010 and inout_write_back env { fp_type; _ } (_, e) =
6011 match e with
6012 | Callconv (Ast_defs.Pinout, e1) ->
6013 (* Translate the write-back semantics of inout parameters.
6015 * This matters because we want to:
6016 * (1) make sure we can write to the original argument
6017 * (modifiable lvalue check)
6018 * (2) allow for growing of locals / Tunions (type side effect)
6019 * but otherwise unify the argument type with the parameter hint
6021 let (env, _te, _ty) =
6022 assign_ (fst e1) Reason.URparam_inout env e1 fp_type.et_type
6025 | _ -> env
6027 (** Typechecks a call.
6028 Returns in this order the typed expressions for the arguments, for the variadic arguments, and the return type. *)
6029 and call
6030 ~(expected : ExpectedTy.t option)
6031 ?(nullsafe : Pos.t option = None)
6032 ?in_await
6036 (el : Nast.expr list)
6037 (unpacked_element : Nast.expr option) :
6038 env * (Tast.expr list * Tast.expr option * locl_ty) =
6039 let expr = expr ~allow_awaitable:(*?*) false in
6040 let exprs = exprs ~allow_awaitable:(*?*) false in
6041 let (env, tyl) = TUtils.get_concrete_supertypes env fty in
6042 if List.is_empty tyl then begin
6043 bad_call env pos fty;
6044 let env = call_untyped_unpack env (get_pos fty) unpacked_element in
6045 (env, ([], None, err_witness env pos))
6046 end else
6047 let (env, fty) =
6048 Typing_intersection.intersect_list env (get_reason fty) tyl
6050 let (env, efty) =
6051 if TypecheckerOptions.method_call_inference (Env.get_tcopt env) then
6052 Env.expand_type env fty
6053 else
6054 Typing_solver.expand_type_and_solve
6055 ~description_of_expected:"a function value"
6059 Errors.unify_error
6061 match deref efty with
6062 | (r, Tdynamic) when TCO.enable_sound_dynamic (Env.get_tcopt env) ->
6063 let ty = MakeType.dynamic (Reason.Rdynamic_call pos) in
6064 let el =
6065 (* Need to check that the type of the unpacked_element can be,
6066 * coerced to dynamic, just like all of the other arguments, in addition
6067 * to the check below in call_untyped_unpack, that it is unpackable.
6068 * We don't need to unpack and check each type because a tuple is
6069 * coercible iff it's constituent types are. *)
6070 Option.value_map ~f:(fun u -> el @ [u]) ~default:el unpacked_element
6072 let (env, tel) =
6073 List.map_env env el (fun env elt ->
6074 (* TODO(sowens): Pass the expected type to expr *)
6075 let (env, te, e_ty) = expr env elt in
6076 let env =
6077 match elt with
6078 | (_, Callconv (Ast_defs.Pinout, e1)) ->
6079 let (env, _te, _ty) =
6080 assign_ (fst e1) Reason.URparam_inout env e1 efty
6083 | _ -> env
6085 let env =
6086 Typing_coercion.coerce_type
6088 Reason.URnone
6090 e_ty
6092 Typing_defs_core.et_type = ty;
6093 Typing_defs_core.et_enforced = Unenforced;
6095 Errors.unify_error
6097 (env, te))
6099 let env = call_untyped_unpack env (Reason.to_pos r) unpacked_element in
6100 (env, (tel, None, ty))
6101 | (r, ((Tprim Tnull | Tdynamic | Terr | Tany _ | Tunion []) as ty))
6102 when match ty with
6103 | Tprim Tnull -> Option.is_some nullsafe
6104 | _ -> true ->
6105 let el =
6106 Option.value_map ~f:(fun u -> el @ [u]) ~default:el unpacked_element
6108 let expected_arg_ty =
6109 (* Note: We ought to be using 'mixed' here *)
6110 ExpectedTy.make pos Reason.URparam (Typing_utils.mk_tany env pos)
6112 let (env, tel) =
6113 List.map_env env el (fun env elt ->
6114 let (env, te, ty) = expr ~expected:expected_arg_ty env elt in
6115 let env =
6116 if TCO.global_inference (Env.get_tcopt env) then
6117 match get_node efty with
6118 | Terr
6119 | Tany _
6120 | Tdynamic ->
6121 Typing_coercion.coerce_type
6123 Reason.URparam
6126 (MakeType.unenforced efty)
6127 Errors.unify_error
6128 | _ -> env
6129 else
6132 let env =
6133 match elt with
6134 | (_, Callconv (Ast_defs.Pinout, e1)) ->
6135 let (env, _te, _ty) =
6136 assign_ (fst e1) Reason.URparam_inout env e1 efty
6139 | _ -> env
6141 (env, te))
6143 let env = call_untyped_unpack env (Reason.to_pos r) unpacked_element in
6144 let ty =
6145 match ty with
6146 | Tprim Tnull -> mk (r, Tprim Tnull)
6147 | Tdynamic -> MakeType.dynamic (Reason.Rdynamic_call pos)
6148 | Terr
6149 | Tany _ ->
6150 Typing_utils.mk_tany env pos
6151 | Tunion []
6152 | _ (* _ should not happen! *) ->
6153 mk (r, Tunion [])
6155 (env, (tel, None, ty))
6156 | (_, Tunion [ty]) ->
6157 call ~expected ~nullsafe ?in_await pos env ty el unpacked_element
6158 | (r, Tunion tyl) ->
6159 let (env, resl) =
6160 List.map_env env tyl (fun env ty ->
6161 call ~expected ~nullsafe ?in_await pos env ty el unpacked_element)
6163 let retl = List.map resl ~f:(fun (_, _, x) -> x) in
6164 let (env, ty) = Union.union_list env r retl in
6165 (* We shouldn't be picking arbitrarily for the TAST here, as TAST checks
6166 * depend on the types inferred. Here's we're preserving legacy behaviour
6167 * by picking the last one.
6168 * TODO: don't do this, instead use subtyping to push unions
6169 * through function types
6171 let (tel, typed_unpack_element, _) = List.hd_exn (List.rev resl) in
6172 (env, (tel, typed_unpack_element, ty))
6173 | (r, Tintersection tyl) ->
6174 let (env, resl) =
6175 TUtils.run_on_intersection env tyl ~f:(fun env ty ->
6176 call ~expected ~nullsafe ?in_await pos env ty el unpacked_element)
6178 let retl = List.map resl ~f:(fun (_, _, x) -> x) in
6179 let (env, ty) = Inter.intersect_list env r retl in
6180 (* We shouldn't be picking arbitrarily for the TAST here, as TAST checks
6181 * depend on the types inferred. Here we're preserving legacy behaviour
6182 * by picking the last one.
6183 * TODO: don't do this, instead use subtyping to push intersections
6184 * through function types
6186 let (tel, typed_unpack_element, _) = List.hd_exn (List.rev resl) in
6187 (env, (tel, typed_unpack_element, ty))
6188 | (r2, Tfun ft) ->
6189 (* Typing of format string functions. It is dependent on the arguments (el)
6190 * so it cannot be done earlier.
6192 let pos_def = Reason.to_pos r2 in
6193 let (env, ft) = Typing_exts.retype_magic_func env ft el in
6194 let (env, var_param) = variadic_param env ft in
6195 (* Force subtype with expected result *)
6196 let env =
6197 check_expected_ty "Call result" env ft.ft_ret.et_type expected
6199 let env = Env.set_tyvar_variance env ft.ft_ret.et_type in
6200 let is_lambda e =
6201 match snd e with
6202 | Efun _
6203 | Lfun _ ->
6204 true
6205 | _ -> false
6207 let get_next_param_info paraml =
6208 match paraml with
6209 | param :: paraml -> (false, Some param, paraml)
6210 | [] -> (true, var_param, paraml)
6212 let expand_atom_in_enum pos env enum_name atom_name =
6213 let cls = Env.get_class env enum_name in
6214 match cls with
6215 | Some cls ->
6216 (match Env.get_const env cls atom_name with
6217 | Some const_def ->
6218 let dty = const_def.cc_type in
6219 let (env, lty) =
6220 Phase.localize_with_self env ~ignore_errors:true dty
6222 let hi = (pos, lty) in
6223 let te = (hi, EnumAtom atom_name) in
6224 (env, Some (te, lty))
6225 | None ->
6226 Errors.atom_unknown pos atom_name enum_name;
6227 let r = Reason.Rwitness pos in
6228 let ty = Typing_utils.terr env r in
6229 let te = ((pos, ty), EnumAtom atom_name) in
6230 (env, Some (te, ty)))
6231 | None -> (env, None)
6233 let check_arg env ((pos, arg) as e) opt_param ~is_variadic =
6234 match opt_param with
6235 | Some param ->
6236 (* First check if __Atom is used *)
6237 let (env, atom_type) =
6238 let is_atom = get_fp_is_atom param in
6239 let ety = param.fp_type.et_type in
6240 match arg with
6241 | EnumAtom atom_name when is_atom ->
6242 (match get_node ety with
6243 | Tnewtype (name, [ty_enum; _ty_interface], _)
6244 when String.equal name SN.Classes.cMemberOf ->
6245 (match get_node ty_enum with
6246 | Tclass ((_, enum_name), _, _)
6247 when Env.is_enum_class env enum_name ->
6248 expand_atom_in_enum pos env enum_name atom_name
6249 | Tgeneric (name, _) ->
6250 let upper_bounds =
6251 Typing_utils.collect_enum_class_upper_bounds env name
6253 (* To avoid ambiguity, we only support the case where
6254 * there is a single upper bound that is an EnumClass.
6255 * We might want to relax that later (e.g. with the
6256 * support for intersections.
6257 * See Typing_check_decls.check_atom_on_param.
6259 if SSet.cardinal upper_bounds = 1 then
6260 let enum_name = SSet.choose upper_bounds in
6261 expand_atom_in_enum pos env enum_name atom_name
6262 else
6263 (env, None)
6264 | _ ->
6265 (* Already reported, see Typing_check_decls *)
6266 (env, None))
6267 | _ ->
6268 (* Already reported, see Typing_check_decls *)
6269 (env, None))
6270 | Class_const _ when is_atom ->
6271 Errors.atom_invalid_argument pos;
6272 (env, None)
6273 | _ -> (env, None)
6275 let (env, te, ty) =
6276 match atom_type with
6277 | Some (te, ty) -> (env, te, ty)
6278 | None ->
6279 let expected =
6280 ExpectedTy.make_and_allow_coercion_opt
6283 Reason.URparam
6284 param.fp_type
6286 expr
6287 ~accept_using_var:(get_fp_accept_disposable param)
6288 ?expected
6292 let env = call_param env param (e, ty) ~is_variadic in
6293 (env, Some (te, ty))
6294 | None ->
6295 let expected =
6296 ExpectedTy.make pos Reason.URparam (Typing_utils.mk_tany env pos)
6298 let (env, te, ty) = expr ~expected env e in
6299 (env, Some (te, ty))
6301 let set_tyvar_variance_from_lambda_param env opt_param =
6302 match opt_param with
6303 | Some param ->
6304 let rec set_params_variance env ty =
6305 let (env, ty) = Env.expand_type env ty in
6306 match get_node ty with
6307 | Tunion [ty] -> set_params_variance env ty
6308 | Toption ty -> set_params_variance env ty
6309 | Tfun { ft_params; ft_ret; _ } ->
6310 let env =
6311 List.fold
6312 ~init:env
6313 ~f:(fun env param ->
6314 Env.set_tyvar_variance env param.fp_type.et_type)
6315 ft_params
6317 Env.set_tyvar_variance env ft_ret.et_type ~flip:true
6318 | _ -> env
6320 set_params_variance env param.fp_type.et_type
6321 | None -> env
6323 (* Given an expected function type ft, check types for the non-unpacked
6324 * arguments. Don't check lambda expressions if check_lambdas=false *)
6325 let rec check_args check_lambdas env el paraml =
6326 match el with
6327 (* We've got an argument *)
6328 | (e, opt_result) :: el ->
6329 (* Pick up next parameter type info *)
6330 let (is_variadic, opt_param, paraml) = get_next_param_info paraml in
6331 let (env, one_result) =
6332 match (check_lambdas, is_lambda e) with
6333 | (false, false)
6334 | (true, true) ->
6335 check_arg env e opt_param ~is_variadic
6336 | (false, true) ->
6337 let env = set_tyvar_variance_from_lambda_param env opt_param in
6338 (env, opt_result)
6339 | (true, false) -> (env, opt_result)
6341 let (env, rl, paraml) = check_args check_lambdas env el paraml in
6342 (env, (e, one_result) :: rl, paraml)
6343 | [] -> (env, [], paraml)
6345 (* Same as above, but checks the types of the implicit arguments, which are
6346 * read from the context *)
6347 let check_implicit_args env =
6348 let capability =
6349 Typing_coeffects.get_type ft.ft_implicit_params.capability
6351 if not (TypecheckerOptions.call_coeffects (Env.get_tcopt env)) then
6353 else
6354 let env_capability =
6355 Env.get_local_check_defined env (pos, Typing_coeffects.capability_id)
6357 Type.sub_type
6359 Reason.URnone
6361 env_capability
6362 capability
6363 (fun ?code:_c _ _ ->
6364 Errors.call_coeffect_error
6366 ~available_incl_unsafe:
6367 (Typing_print.coeffects env env_capability)
6368 ~available_pos:(Typing_defs.get_pos env_capability)
6369 ~required_pos:(Typing_defs.get_pos capability)
6370 ~required:(Typing_print.coeffects env capability))
6373 (* First check the non-lambda arguments. For generic functions, this
6374 * is likely to resolve type variables to concrete types *)
6375 let rl = List.map el (fun e -> (e, None)) in
6376 let (env, rl, _) = check_args false env rl ft.ft_params in
6377 (* Now check the lambda arguments, hopefully with type variables resolved *)
6378 let (env, rl, paraml) = check_args true env rl ft.ft_params in
6379 (* We expect to see results for all arguments after this second pass *)
6380 let get_param opt =
6381 match opt with
6382 | Some x -> x
6383 | None -> failwith "missing parameter in check_args"
6385 let (tel, _) =
6386 let l = List.map rl (fun (_, opt) -> get_param opt) in
6387 List.unzip l
6389 let env = check_implicit_args env in
6390 let (env, typed_unpack_element, arity, did_unpack) =
6391 match unpacked_element with
6392 | None -> (env, None, List.length el, false)
6393 | Some e ->
6394 (* Now that we're considering an splat (Some e) we need to construct a type that
6395 * represents the remainder of the function's parameters. `paraml` represents those
6396 * remaining parameters, and the variadic parameter is stored in `var_param`. For example, given
6398 * function f(int $i, string $j, float $k = 3.14, mixed ...$m): void {}
6399 * function g((string, float, bool) $t): void {
6400 * f(3, ...$t);
6403 * the constraint type we want is splat([#1], [opt#2], #3).
6405 let (consumed, required_params, optional_params) =
6406 split_remaining_params_required_optional ft paraml
6408 let (env, (d_required, d_optional, d_variadic)) =
6409 generate_splat_type_vars
6411 (fst e)
6412 required_params
6413 optional_params
6414 var_param
6416 let destructure_ty =
6417 ConstraintType
6418 (mk_constraint_type
6419 ( Reason.Runpack_param (fst e, pos_def, consumed),
6420 Tdestructure
6422 d_required;
6423 d_optional;
6424 d_variadic;
6425 d_kind = SplatUnpack;
6426 } ))
6428 let (env, te, ty) = expr env e in
6429 (* Populate the type variables from the expression in the splat *)
6430 let env =
6431 Type.sub_type_i
6432 (fst e)
6433 Reason.URparam
6435 (LoclType ty)
6436 destructure_ty
6437 Errors.unify_error
6439 (* Use the type variables for the remaining parameters *)
6440 let env =
6441 List.fold2_exn
6442 ~init:env
6443 d_required
6444 required_params
6445 ~f:(fun env elt param ->
6446 call_param env param (e, elt) ~is_variadic:false)
6448 let env =
6449 List.fold2_exn
6450 ~init:env
6451 d_optional
6452 optional_params
6453 ~f:(fun env elt param ->
6454 call_param env param (e, elt) ~is_variadic:false)
6456 let env =
6457 Option.map2 d_variadic var_param ~f:(fun v vp ->
6458 call_param env vp (e, v) ~is_variadic:true)
6459 |> Option.value ~default:env
6461 ( env,
6462 Some te,
6463 List.length el + List.length d_required,
6464 Option.is_some d_variadic )
6466 (* If we unpacked an array, we don't check arity exactly. Since each
6467 * unpacked array consumes 1 or many parameters, it is nonsensical to say
6468 * that not enough args were passed in (so we don't do the min check).
6470 let () = check_arity ~did_unpack pos pos_def ft arity in
6471 (* Variadic params cannot be inout so we can stop early *)
6472 let env = wfold_left2 inout_write_back env ft.ft_params el in
6473 (env, (tel, typed_unpack_element, ft.ft_ret.et_type))
6474 | (r, Tvar _)
6475 when TypecheckerOptions.method_call_inference (Env.get_tcopt env) ->
6477 Typecheck calls with unresolved function type by constructing a
6478 suitable function type from the arguments and invoking subtyping.
6480 let (env, typed_el, type_of_el) = exprs ~accept_using_var:true env el in
6481 let (env, typed_unpacked_element, type_of_unpacked_element) =
6482 match unpacked_element with
6483 | Some unpacked ->
6484 let (env, typed_unpacked, type_of_unpacked) =
6485 expr ~accept_using_var:true env unpacked
6487 (env, Some typed_unpacked, Some type_of_unpacked)
6488 | None -> (env, None, None)
6490 let mk_function_supertype env pos (type_of_el, type_of_unpacked_element) =
6491 let mk_fun_param ty =
6492 let flags =
6493 (* Keep supertype as permissive as possible: *)
6494 make_fp_flags
6495 ~mode:FPnormal (* TODO: deal with `inout` parameters *)
6496 ~accept_disposable:false (* TODO: deal with disposables *)
6497 ~has_default:false
6498 ~ifc_external:false
6499 ~ifc_can_call:false
6500 ~is_atom:false
6501 ~readonly:false
6502 ~const_function:false
6505 fp_pos = pos;
6506 fp_name = None;
6507 fp_type = MakeType.enforced ty;
6508 fp_flags = flags;
6511 let ft_arity =
6512 match type_of_unpacked_element with
6513 | Some type_of_unpacked ->
6514 let fun_param = mk_fun_param type_of_unpacked in
6515 Fvariadic fun_param
6516 | None -> Fstandard
6518 (* TODO: ensure `ft_params`/`ft_where_constraints` don't affect subtyping *)
6519 let ft_tparams = [] in
6520 let ft_where_constraints = [] in
6521 let ft_params = List.map ~f:mk_fun_param type_of_el in
6522 let ft_implicit_params =
6524 capability =
6525 CapDefaults pos
6526 (* TODO(coeffects) should this be a different type? *);
6529 let (env, return_ty) = Env.fresh_type env pos in
6530 let return_ty =
6531 match in_await with
6532 | None -> return_ty
6533 | Some r -> MakeType.awaitable r return_ty
6535 let ft_ret = MakeType.enforced return_ty in
6536 let ft_flags =
6537 (* Keep supertype as permissive as possible: *)
6538 make_ft_flags
6539 Ast_defs.FSync (* `FSync` fun can still return `Awaitable<_>` *)
6540 ~return_disposable:false (* TODO: deal with disposable return *)
6541 ~returns_readonly:false
6542 ~readonly_this:false
6543 ~const:false
6545 let ft_ifc_decl = Typing_defs_core.default_ifc_fun_decl in
6546 let fun_locl_type =
6548 ft_arity;
6549 ft_tparams;
6550 ft_where_constraints;
6551 ft_params;
6552 ft_implicit_params;
6553 ft_ret;
6554 ft_flags;
6555 ft_ifc_decl;
6558 let fun_type = mk (r, Tfun fun_locl_type) in
6559 let env = Env.set_tyvar_variance env fun_type in
6560 (env, fun_type, return_ty)
6562 let (env, fun_type, return_ty) =
6563 mk_function_supertype env pos (type_of_el, type_of_unpacked_element)
6565 let env =
6566 Type.sub_type pos Reason.URnone env efty fun_type Errors.unify_error
6568 (env, (typed_el, typed_unpacked_element, return_ty))
6569 | _ ->
6570 bad_call env pos efty;
6571 let env = call_untyped_unpack env (get_pos efty) unpacked_element in
6572 (env, ([], None, err_witness env pos))
6574 and split_remaining_params_required_optional ft remaining_params =
6575 (* Same example as above
6577 * function f(int $i, string $j, float $k = 3.14, mixed ...$m): void {}
6578 * function g((string, float, bool) $t): void {
6579 * f(3, ...$t);
6582 * `remaining_params` will contain [string, float] and there has been 1 parameter consumed. The min_arity
6583 * of this function is 2, so there is 1 required parameter remaining and 1 optional parameter.
6585 let min_arity =
6586 List.count
6587 ~f:(fun fp -> not (Typing_defs.get_fp_has_default fp))
6588 ft.ft_params
6590 let original_params = ft.ft_params in
6591 let consumed = List.length original_params - List.length remaining_params in
6592 let required_remaining = Int.max (min_arity - consumed) 0 in
6593 let (required_params, optional_params) =
6594 List.split_n remaining_params required_remaining
6596 (consumed, required_params, optional_params)
6598 and generate_splat_type_vars
6599 env p required_params optional_params variadic_param =
6600 let (env, d_required) =
6601 List.map_env env required_params ~f:(fun env _ -> Env.fresh_type env p)
6603 let (env, d_optional) =
6604 List.map_env env optional_params ~f:(fun env _ -> Env.fresh_type env p)
6606 let (env, d_variadic) =
6607 match variadic_param with
6608 | None -> (env, None)
6609 | Some _ ->
6610 let (env, ty) = Env.fresh_type env p in
6611 (env, Some ty)
6613 (env, (d_required, d_optional, d_variadic))
6615 and call_param env param (((pos, _) as e), arg_ty) ~is_variadic =
6616 param_modes ~is_variadic param e;
6618 (* When checking params, the type 'x' may be expression dependent. Since
6619 * we store the expression id in the local env for Lvar, we want to apply
6620 * it in this case.
6622 let (env, dep_ty) =
6623 match snd e with
6624 | Lvar _ -> ExprDepTy.make env (CIexpr e) arg_ty
6625 | _ -> (env, arg_ty)
6627 Typing_coercion.coerce_type
6629 Reason.URparam
6631 dep_ty
6632 param.fp_type
6633 Errors.unify_error
6635 and call_untyped_unpack env f_pos unpacked_element =
6636 match unpacked_element with
6637 (* In the event that we don't have a known function call type, we can still
6638 * verify that any unpacked arguments (`...$args`) are something that can
6639 * be actually unpacked. *)
6640 | None -> env
6641 | Some e ->
6642 let (env, _, ety) = expr env e ~allow_awaitable:(*?*) false in
6643 let (env, ty) = Env.fresh_type env (fst e) in
6644 let destructure_ty =
6645 MakeType.simple_variadic_splat (Reason.Runpack_param (fst e, f_pos, 0)) ty
6647 Type.sub_type_i
6648 f_pos
6649 Reason.URnone
6651 (LoclType ety)
6652 destructure_ty
6653 Errors.unify_error
6655 and bad_call env p ty = Errors.bad_call p (Typing_print.error env ty)
6657 and make_a_local_of env e =
6658 match e with
6659 | (p, Class_get ((_, cname), CGstring (_, member_name), _)) ->
6660 let (env, local) = Env.FakeMembers.make_static env cname member_name p in
6661 (env, Some (p, local))
6662 | ( p,
6663 Obj_get
6664 ((((_, This) | (_, Lvar _)) as obj), (_, Id (_, member_name)), _, _) )
6666 let (env, local) = Env.FakeMembers.make env obj member_name p in
6667 (env, Some (p, local))
6668 | (_, Lvar x)
6669 | (_, Dollardollar x) ->
6670 (env, Some x)
6671 | _ -> (env, None)
6673 (* This function captures the common bits of logic behind refinement
6674 * of the type of a local variable or a class member variable as a
6675 * result of a dynamic check (e.g., nullity check, simple type check
6676 * using functions like is_int, is_string, is_array etc.). The
6677 * argument refine is a function that takes the type of the variable
6678 * and returns a refined type (making necessary changes to the
6679 * environment, which is threaded through).
6681 * All refinement functions return, in addition to the updated
6682 * environment, a (conservative) set of all the locals that got
6683 * refined. This set is used to construct AssertEnv statmements in
6684 * the typed AST.
6686 and refine_lvalue_type env (((_p, ty), _) as te) ~refine =
6687 let (env, ty) = refine env ty in
6688 let e = Tast.to_nast_expr te in
6689 let (env, localopt) = make_a_local_of env e in
6690 (* TODO TAST: generate an assignment to the fake local in the TAST *)
6691 match localopt with
6692 | Some lid -> (set_local env lid ty, Local_id.Set.singleton (snd lid))
6693 | None -> (env, Local_id.Set.empty)
6695 and condition_nullity ~nonnull (env : env) te =
6696 match te with
6697 (* assignment: both the rhs and lhs of the '=' must be made null/non-null *)
6698 | (_, Aast.Binop (Ast_defs.Eq None, var, te)) ->
6699 let (env, lset1) = condition_nullity ~nonnull env te in
6700 let (env, lset2) = condition_nullity ~nonnull env var in
6701 (env, Local_id.Set.union lset1 lset2)
6702 (* case where `Shapes::idx(...)` must be made null/non-null *)
6703 | ( _,
6704 Aast.Call
6705 ( (_, Aast.Class_const ((_, Aast.CI (_, shapes)), (_, idx))),
6707 [shape; field],
6708 _ ) )
6709 when String.equal shapes SN.Shapes.cShapes && String.equal idx SN.Shapes.idx
6711 let field = Tast.to_nast_expr field in
6712 let refine env shape_ty =
6713 if nonnull then
6714 Typing_shapes.shapes_idx_not_null env shape_ty field
6715 else
6716 (env, shape_ty)
6718 refine_lvalue_type env shape ~refine
6719 | ((p, _), _) ->
6720 let refine env ty =
6721 if nonnull then
6722 Typing_solver.non_null env p ty
6723 else
6724 let r = Reason.Rwitness (get_pos ty) in
6725 Inter.intersect env r ty (MakeType.null r)
6727 refine_lvalue_type env te ~refine
6729 and condition_isset env = function
6730 | (_, Aast.Array_get (x, _)) -> condition_isset env x
6731 | v -> condition_nullity ~nonnull:true env v
6734 * Build an environment for the true or false branch of
6735 * conditional statements.
6737 and condition
6738 ?lhs_of_null_coalesce env tparamet ((((p, ty) as pty), e) as te : Tast.expr)
6740 let condition = condition ?lhs_of_null_coalesce in
6741 match e with
6742 | Aast.True when not tparamet ->
6743 (LEnv.drop_cont env C.Next, Local_id.Set.empty)
6744 | Aast.False when tparamet -> (LEnv.drop_cont env C.Next, Local_id.Set.empty)
6745 | Aast.Call ((_, Aast.Id (_, func)), _, [param], None)
6746 when String.equal SN.PseudoFunctions.isset func
6747 && tparamet
6748 && not (Env.is_strict env) ->
6749 condition_isset env param
6750 | Aast.Call ((_, Aast.Id (_, func)), _, [te], None)
6751 when String.equal SN.StdlibFunctions.is_null func ->
6752 condition_nullity ~nonnull:(not tparamet) env te
6753 | Aast.Binop ((Ast_defs.Eqeq | Ast_defs.Eqeqeq), (_, Aast.Null), e)
6754 | Aast.Binop ((Ast_defs.Eqeq | Ast_defs.Eqeqeq), e, (_, Aast.Null)) ->
6755 condition_nullity ~nonnull:(not tparamet) env e
6756 | Aast.Lvar _
6757 | Aast.Obj_get _
6758 | Aast.Class_get _
6759 | Aast.Binop (Ast_defs.Eq None, _, _) ->
6760 let (env, ety) = Env.expand_type env ty in
6761 (match get_node ety with
6762 | Tprim Tbool -> (env, Local_id.Set.empty)
6763 | _ -> condition_nullity ~nonnull:tparamet env te)
6764 | Aast.Binop (((Ast_defs.Diff | Ast_defs.Diff2) as op), e1, e2) ->
6765 let op =
6766 if Ast_defs.(equal_bop op Diff) then
6767 Ast_defs.Eqeq
6768 else
6769 Ast_defs.Eqeqeq
6771 condition env (not tparamet) (pty, Aast.Binop (op, e1, e2))
6772 | Aast.Id (p, s) when String.equal s SN.Rx.is_enabled ->
6773 (* when Rx\IS_ENABLED is false - switch env to non-reactive *)
6774 let env =
6775 if not tparamet then
6776 if TypecheckerOptions.any_coeffects (Env.get_tcopt env) then
6777 let env = Typing_local_ops.enforce_rx_is_enabled p env in
6778 let defaults = MakeType.default_capability Pos.none in
6779 fst @@ Typing_coeffects.register_capabilities env defaults defaults
6780 else
6782 else
6785 (env, Local_id.Set.empty)
6786 (* Conjunction of conditions. Matches the two following forms:
6787 if (cond1 && cond2)
6788 if (!(cond1 || cond2))
6790 | Aast.Binop (((Ast_defs.Ampamp | Ast_defs.Barbar) as bop), e1, e2)
6791 when Bool.equal tparamet Ast_defs.(equal_bop bop Ampamp) ->
6792 let (env, lset1) = condition env tparamet e1 in
6793 (* This is necessary in case there is an assignment in e2
6794 * We essentially redo what has been undone in the
6795 * `Binop (Ampamp|Barbar)` case of `expr` *)
6796 let (env, _, _) =
6797 expr env (Tast.to_nast_expr e2) ~allow_awaitable:(*?*) false
6799 let (env, lset2) = condition env tparamet e2 in
6800 (env, Local_id.Set.union lset1 lset2)
6801 (* Disjunction of conditions. Matches the two following forms:
6802 if (cond1 || cond2)
6803 if (!(cond1 && cond2))
6805 | Aast.Binop (((Ast_defs.Ampamp | Ast_defs.Barbar) as bop), e1, e2)
6806 when Bool.equal tparamet Ast_defs.(equal_bop bop Barbar) ->
6807 let (env, lset1, lset2) =
6808 branch
6810 (fun env ->
6811 (* Either cond1 is true and we don't know anything about cond2... *)
6812 condition env tparamet e1)
6813 (fun env ->
6814 (* ... Or cond1 is false and therefore cond2 must be true *)
6815 let (env, _lset) = condition env (not tparamet) e1 in
6816 (* Similarly to the conjunction case, there might be an assignment in
6817 cond2 which we must account for. Again we redo what has been undone in
6818 the `Binop (Ampamp|Barbar)` case of `expr` *)
6819 let (env, _, _) =
6820 expr env (Tast.to_nast_expr e2) ~allow_awaitable:(*?*) false
6822 condition env tparamet e2)
6824 (env, Local_id.Set.union lset1 lset2)
6825 | Aast.Call (((p, _), Aast.Id (_, f)), _, [lv], None)
6826 when tparamet && String.equal f SN.StdlibFunctions.is_dict_or_darray ->
6827 safely_refine_is_array env `HackDictOrDArray p f lv
6828 | Aast.Call (((p, _), Aast.Id (_, f)), _, [lv], None)
6829 when tparamet && String.equal f SN.StdlibFunctions.is_vec_or_varray ->
6830 safely_refine_is_array env `HackVecOrVArray p f lv
6831 | Aast.Call (((p, _), Aast.Id (_, f)), _, [lv], None)
6832 when tparamet && String.equal f SN.StdlibFunctions.is_any_array ->
6833 safely_refine_is_array env `AnyArray p f lv
6834 | Aast.Call (((p, _), Aast.Id (_, f)), _, [lv], None)
6835 when tparamet && String.equal f SN.StdlibFunctions.is_php_array ->
6836 safely_refine_is_array env `PHPArray p f lv
6837 | Aast.Call
6838 ( (_, Aast.Class_const ((_, Aast.CI (_, class_name)), (_, method_name))),
6840 [shape; field],
6841 None )
6842 when tparamet
6843 && String.equal class_name SN.Shapes.cShapes
6844 && String.equal method_name SN.Shapes.keyExists ->
6845 key_exists env p shape field
6846 | Aast.Unop (Ast_defs.Unot, e) -> condition env (not tparamet) e
6847 | Aast.Is (ivar, h) when is_instance_var (Tast.to_nast_expr ivar) ->
6848 let (env, hint_ty) =
6849 Phase.localize_hint_with_self env ~ignore_errors:false h
6851 let reason = Reason.Ris (fst h) in
6852 let refine_type env hint_ty =
6853 let (ivar_pos, ivar_ty) = fst ivar in
6854 let (env, ivar) = get_instance_var env (Tast.to_nast_expr ivar) in
6855 let (env, hint_ty) =
6856 class_for_refinement env p reason ivar_pos ivar_ty hint_ty
6858 let (env, refined_ty) = Inter.intersect env reason ivar_ty hint_ty in
6859 (set_local env ivar refined_ty, Local_id.Set.singleton (snd ivar))
6861 let (env, hint_ty) =
6862 if not tparamet then
6863 Inter.non env reason hint_ty ~approx:TUtils.ApproxUp
6864 else
6865 (env, hint_ty)
6867 refine_type env hint_ty
6868 | _ -> (env, Local_id.Set.empty)
6870 (** Transform a hint like `A<_>` to a localized type like `A<T#1>` for refinement of
6871 an instance variable. ivar_ty is the previous type of that instance variable. *)
6872 and class_for_refinement env p reason ivar_pos ivar_ty hint_ty =
6873 let (env, hint_ty) = Env.expand_type env hint_ty in
6874 match (get_node ivar_ty, get_node hint_ty) with
6875 | (_, Tclass (((_, cid) as _c), _, tyl)) ->
6876 begin
6877 match Env.get_class env cid with
6878 | Some class_info ->
6879 let (env, tparams_with_new_names, tyl_fresh) =
6880 generate_fresh_tparams env class_info reason tyl
6882 safely_refine_class_type
6886 class_info
6887 ivar_ty
6888 hint_ty
6889 reason
6890 tparams_with_new_names
6891 tyl_fresh
6892 | None -> (env, mk (Reason.Rwitness ivar_pos, Tobject))
6894 | (Ttuple ivar_tyl, Ttuple hint_tyl)
6895 when Int.equal (List.length ivar_tyl) (List.length hint_tyl) ->
6896 let (env, tyl) =
6897 List.map2_env env ivar_tyl hint_tyl (fun env ivar_ty hint_ty ->
6898 class_for_refinement env p reason ivar_pos ivar_ty hint_ty)
6900 (env, MakeType.tuple reason tyl)
6901 | _ -> (env, hint_ty)
6903 (** If we are dealing with a refinement like
6904 $x is MyClass<A, B>
6905 then class_info is the class info of MyClass and hint_tyl corresponds
6906 to A, B. *)
6907 and generate_fresh_tparams env class_info reason hint_tyl =
6908 let tparams_len = List.length (Cls.tparams class_info) in
6909 let hint_tyl = List.take hint_tyl tparams_len in
6910 let pad_len = tparams_len - List.length hint_tyl in
6911 let hint_tyl =
6912 List.map hint_tyl (fun x -> Some x) @ List.init pad_len (fun _ -> None)
6914 let replace_wildcard env hint_ty tp =
6915 let {
6916 tp_name = (_, tparam_name);
6917 tp_reified = reified;
6918 tp_user_attributes;
6923 let enforceable =
6924 Attributes.mem SN.UserAttributes.uaEnforceable tp_user_attributes
6926 let newable =
6927 Attributes.mem SN.UserAttributes.uaNewable tp_user_attributes
6929 match hint_ty with
6930 | Some ty ->
6931 begin
6932 match get_node ty with
6933 | Tgeneric (name, _targs) when Env.is_fresh_generic_parameter name ->
6934 (* TODO(T69551141) handle type arguments above and below *)
6935 (env, (Some (tp, name), MakeType.generic reason name))
6936 | _ -> (env, (None, ty))
6938 | None ->
6939 let (env, new_name) =
6940 Env.add_fresh_generic_parameter
6942 tparam_name
6943 ~reified
6944 ~enforceable
6945 ~newable
6947 (* TODO(T69551141) handle type arguments for Tgeneric *)
6948 (env, (Some (tp, new_name), MakeType.generic reason new_name))
6950 let (env, tparams_and_tyl) =
6951 List.map2_env env hint_tyl (Cls.tparams class_info) ~f:replace_wildcard
6953 let (tparams_with_new_names, tyl_fresh) = List.unzip tparams_and_tyl in
6954 (env, tparams_with_new_names, tyl_fresh)
6956 and safely_refine_class_type
6959 class_name
6960 class_info
6961 ivar_ty
6962 obj_ty
6963 reason
6964 (tparams_with_new_names : (decl_tparam * string) option list)
6965 tyl_fresh =
6966 (* Type of variable in block will be class name
6967 * with fresh type parameters *)
6968 let obj_ty =
6969 mk (get_reason obj_ty, Tclass (class_name, Nonexact, tyl_fresh))
6971 let tparams = Cls.tparams class_info in
6972 (* Add in constraints as assumptions on those type parameters *)
6973 let ety_env =
6975 type_expansions = [];
6976 substs = Subst.make_locl tparams tyl_fresh;
6977 this_ty = obj_ty;
6978 on_error = Errors.ignore_error;
6981 let add_bounds env (t, ty_fresh) =
6982 List.fold_left t.tp_constraints ~init:env ~f:(fun env (ck, ty) ->
6983 (* Substitute fresh type parameters for
6984 * original formals in constraint *)
6985 let (env, ty) = Phase.localize ~ety_env env ty in
6986 SubType.add_constraint p env ck ty_fresh ty)
6988 let env =
6989 List.fold_left (List.zip_exn tparams tyl_fresh) ~f:add_bounds ~init:env
6991 (* Finally, if we have a class-test on something with static classish type,
6992 * then we can chase the hierarchy and decompose the types to deduce
6993 * further assumptions on type parameters. For example, we might have
6994 * class B<Tb> { ... }
6995 * class C extends B<int>
6996 * and have obj_ty = C and x_ty = B<T> for a generic parameter Aast.
6997 * Then SubType.add_constraint will deduce that T=int and add int as
6998 * both lower and upper bound on T in env.lenv.tpenv
7000 let (env, supertypes) = TUtils.get_concrete_supertypes env ivar_ty in
7001 let env =
7002 List.fold_left supertypes ~init:env ~f:(fun env ty ->
7003 SubType.add_constraint p env Ast_defs.Constraint_as obj_ty ty)
7005 (* It's often the case that the fresh name isn't necessary. For
7006 * example, if C<T> extends B<T>, and we have $x:B<t> for some type t
7007 * then $x is C should refine to $x:C<t>.
7008 * We take a simple approach:
7009 * For a fresh type parameter T#1, if
7010 * - There is an eqality constraint T#1 = t,
7011 * - T#1 is covariant, and T#1 has upper bound t (or mixed if absent)
7012 * - T#1 is contravariant, and T#1 has lower bound t (or nothing if absent)
7013 * then replace T#1 with t.
7014 * This is done in Type_parameter_env_ops.simplify_tpenv
7016 let (env, tparam_substs) =
7017 Type_parameter_env_ops.simplify_tpenv
7019 (List.zip_exn tparams_with_new_names tyl_fresh)
7020 reason
7022 let tyl_fresh =
7023 List.map2_exn tyl_fresh tparams_with_new_names ~f:(fun orig_ty tparam_opt ->
7024 match tparam_opt with
7025 | None -> orig_ty
7026 | Some (_tp, name) -> SMap.find name tparam_substs)
7028 let obj_ty_simplified =
7029 mk (get_reason obj_ty, Tclass (class_name, Nonexact, tyl_fresh))
7031 (env, obj_ty_simplified)
7033 and is_instance_var = function
7034 | (_, (Lvar _ | This | Dollardollar _)) -> true
7035 | (_, Obj_get ((_, This), (_, Id _), _, _)) -> true
7036 | (_, Obj_get ((_, Lvar _), (_, Id _), _, _)) -> true
7037 | (_, Class_get (_, _, _)) -> true
7038 | _ -> false
7040 and get_instance_var env = function
7041 | (p, Class_get ((_, cname), CGstring (_, member_name), _)) ->
7042 let (env, local) = Env.FakeMembers.make_static env cname member_name p in
7043 (env, (p, local))
7044 | ( p,
7045 Obj_get
7046 ((((_, This) | (_, Lvar _)) as obj), (_, Id (_, member_name)), _, _) )
7048 let (env, local) = Env.FakeMembers.make env obj member_name p in
7049 (env, (p, local))
7050 | (_, Dollardollar (p, x))
7051 | (_, Lvar (p, x)) ->
7052 (env, (p, x))
7053 | (p, This) -> (env, (p, this))
7054 | _ -> failwith "Should only be called when is_instance_var is true"
7056 (* Refine type for is_array, is_vec, is_keyset and is_dict tests
7057 * `pred_name` is the function name itself (e.g. 'is_vec')
7058 * `p` is position of the function name in the source
7059 * `arg_expr` is the argument to the function
7061 and safely_refine_is_array env ty p pred_name arg_expr =
7062 refine_lvalue_type env arg_expr ~refine:(fun env arg_ty ->
7063 let r = Reason.Rpredicated (p, pred_name) in
7064 let (env, tarrkey_name) =
7065 Env.add_fresh_generic_parameter
7067 "Tk"
7068 ~reified:Erased
7069 ~enforceable:false
7070 ~newable:false
7072 (* TODO(T69551141) handle type arguments for Tgeneric *)
7073 let tarrkey = MakeType.generic r tarrkey_name in
7074 let env =
7075 SubType.add_constraint
7078 Ast_defs.Constraint_as
7079 tarrkey
7080 (MakeType.arraykey r)
7082 let (env, tfresh_name) =
7083 Env.add_fresh_generic_parameter
7086 ~reified:Erased
7087 ~enforceable:false
7088 ~newable:false
7090 (* TODO(T69551141) handle type arguments for Tgeneric *)
7091 let tfresh = MakeType.generic r tfresh_name in
7092 (* If we're refining the type for `is_array` we have a slightly more
7093 * involved process. Let's separate out that logic so we can re-use it.
7095 let unification =
7096 TypecheckerOptions.hack_arr_dv_arrs (Env.get_tcopt env)
7098 let array_ty =
7099 let safe_isarray_enabled =
7100 TypecheckerOptions.experimental_feature_enabled
7101 (Env.get_tcopt env)
7102 TypecheckerOptions.experimental_isarray
7104 let tk = MakeType.arraykey Reason.(Rvarray_or_darray_key (to_pos r)) in
7105 let tv =
7106 if safe_isarray_enabled then
7107 tfresh
7108 else
7109 mk (r, TUtils.tany env)
7111 MakeType.varray_or_darray ~unification r tk tv
7113 (* This is the refined type of e inside the branch *)
7114 let hint_ty =
7115 match ty with
7116 | `HackDict -> MakeType.dict r tarrkey tfresh
7117 | `HackVec -> MakeType.vec r tfresh
7118 | `HackKeyset -> MakeType.keyset r tarrkey
7119 | `PHPArray -> array_ty
7120 | `AnyArray -> MakeType.any_array r tarrkey tfresh
7121 | `HackDictOrDArray ->
7122 MakeType.union
7125 MakeType.dict r tarrkey tfresh;
7126 MakeType.darray ~unification r tarrkey tfresh;
7128 | `HackVecOrVArray ->
7129 MakeType.union
7131 [MakeType.vec r tfresh; MakeType.varray ~unification r tfresh]
7133 let ((arg_pos, _), _) = arg_expr in
7134 let (env, hint_ty) =
7135 class_for_refinement env p r arg_pos arg_ty hint_ty
7137 (* Add constraints on generic parameters that must
7138 * hold for refined_ty <:arg_ty. For example, if arg_ty is Traversable<T>
7139 * and refined_ty is keyset<T#1> then we know T#1 <: T.
7140 * See analogous code in safely_refine_class_type.
7142 let (env, supertypes) = TUtils.get_concrete_supertypes env arg_ty in
7143 let env =
7144 List.fold_left supertypes ~init:env ~f:(fun env ty ->
7145 SubType.add_constraint p env Ast_defs.Constraint_as hint_ty ty)
7147 Inter.intersect ~r env hint_ty arg_ty)
7149 and key_exists env pos shape field =
7150 let field = Tast.to_nast_expr field in
7151 refine_lvalue_type env shape ~refine:(fun env shape_ty ->
7152 match TUtils.shape_field_name env field with
7153 | None -> (env, shape_ty)
7154 | Some field_name ->
7155 let field_name = TShapeField.of_ast (fun p -> p) field_name in
7156 Typing_shapes.refine_shape field_name pos env shape_ty)
7158 and string2 env idl =
7159 let (env, tel) =
7160 List.fold_left idl ~init:(env, []) ~f:(fun (env, tel) x ->
7161 let (env, te, ty) = expr env x ~allow_awaitable:(*?*) false in
7162 let p = fst x in
7164 TypecheckerOptions.enable_strict_string_concat_interp
7165 (Env.get_tcopt env)
7166 then
7167 let r = Reason.Rinterp_operand p in
7168 let (env, formatter_tyvar) = Env.fresh_invariant_type_var env p in
7169 let stringlike =
7170 MakeType.union
7173 MakeType.arraykey r;
7174 MakeType.new_type r SN.Classes.cHHFormatString [formatter_tyvar];
7177 let env =
7178 Typing_ops.sub_type
7180 Reason.URstr_interp
7183 stringlike
7184 Errors.strict_str_interp_type_mismatch
7186 (env, te :: tel)
7187 else
7188 let env = Typing_substring.sub_string p env ty in
7189 (env, te :: tel))
7191 (env, List.rev tel)
7193 and user_attribute env ua =
7194 let (env, typed_ua_params) =
7195 List.map_env env ua.ua_params (fun env e ->
7196 let (env, te, _) = expr env e ~allow_awaitable:(*?*) false in
7197 (env, te))
7199 (env, { Aast.ua_name = ua.ua_name; Aast.ua_params = typed_ua_params })
7201 and file_attributes env file_attrs =
7202 (* Disable checking of error positions, as file attributes have spans that
7203 * aren't subspans of the class or function into which they are copied *)
7204 Errors.run_with_span Pos.none @@ fun () ->
7205 let uas = List.concat_map ~f:(fun fa -> fa.fa_user_attributes) file_attrs in
7206 let env = attributes_check_def env SN.AttributeKinds.file uas in
7207 List.map_env env file_attrs (fun env fa ->
7208 let (env, user_attributes) =
7209 List.map_env env fa.fa_user_attributes user_attribute
7211 let env = set_tcopt_unstable_features env fa in
7212 ( env,
7214 Aast.fa_user_attributes = user_attributes;
7215 Aast.fa_namespace = fa.fa_namespace;
7216 } ))
7218 and type_param env t =
7219 let env =
7220 attributes_check_def env SN.AttributeKinds.typeparam t.tp_user_attributes
7222 let (env, user_attributes) =
7223 List.map_env env t.tp_user_attributes user_attribute
7225 let (env, tp_parameters) = List.map_env env t.tp_parameters type_param in
7226 ( env,
7228 Aast.tp_variance = t.tp_variance;
7229 Aast.tp_name = t.tp_name;
7230 Aast.tp_parameters;
7231 Aast.tp_constraints = t.tp_constraints;
7232 Aast.tp_reified = reify_kind t.tp_reified;
7233 Aast.tp_user_attributes = user_attributes;
7236 and typedef_def ctx typedef =
7237 let env = EnvFromDef.typedef_env ~origin:Decl_counters.TopLevel ctx typedef in
7238 let env =
7239 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
7240 (fst typedef.t_name)
7242 ~ignore_errors:false
7243 typedef.t_tparams
7246 Typing_check_decls.typedef env typedef;
7247 Typing_variance.typedef env typedef;
7248 let {
7249 t_annotation = ();
7250 t_name = (t_pos, t_name);
7251 t_tparams = _;
7252 t_constraint = tcstr;
7253 t_kind = hint;
7254 t_user_attributes = _;
7255 t_vis = _;
7256 t_mode = _;
7257 t_namespace = _;
7258 t_span = _;
7259 t_emit_id = _;
7261 typedef
7263 let (env, ty) =
7264 Phase.localize_hint_with_self
7266 ~ignore_errors:false
7267 ~report_cycle:(t_pos, t_name)
7268 hint
7270 let env =
7271 match tcstr with
7272 | Some tcstr ->
7273 let (env, cstr) =
7274 Phase.localize_hint_with_self env ~ignore_errors:false tcstr
7276 Typing_ops.sub_type
7277 t_pos
7278 Reason.URnewtype_cstr
7281 cstr
7282 Errors.newtype_alias_must_satisfy_constraint
7283 | _ -> env
7285 let env =
7286 match hint with
7287 | (pos, Hshape { nsi_allows_unknown_fields = _; nsi_field_map }) ->
7288 let get_name sfi = sfi.sfi_name in
7289 check_shape_keys_validity env pos (List.map ~f:get_name nsi_field_map)
7290 | _ -> env
7292 let env =
7293 attributes_check_def
7295 SN.AttributeKinds.typealias
7296 typedef.t_user_attributes
7298 let (env, tparams) = List.map_env env typedef.t_tparams type_param in
7299 let (env, user_attributes) =
7300 List.map_env env typedef.t_user_attributes user_attribute
7303 Aast.t_annotation = Env.save (Env.get_tpenv env) env;
7304 Aast.t_name = typedef.t_name;
7305 Aast.t_mode = typedef.t_mode;
7306 Aast.t_vis = typedef.t_vis;
7307 Aast.t_user_attributes = user_attributes;
7308 Aast.t_constraint = typedef.t_constraint;
7309 Aast.t_kind = typedef.t_kind;
7310 Aast.t_tparams = tparams;
7311 Aast.t_namespace = typedef.t_namespace;
7312 Aast.t_span = typedef.t_span;
7313 Aast.t_emit_id = typedef.t_emit_id;
7316 (* Calls the method of a class, but allows the f callback to override the
7317 * return value type *)
7318 and overload_function
7319 make_call fpos p env (cpos, class_id) method_id el unpacked_element f =
7320 let (env, _tal, tcid, ty) =
7321 static_class_id ~check_constraints:false cpos env [] class_id
7323 let (env, _tel, _) = exprs env el ~allow_awaitable:(*?*) false in
7324 let (env, (fty, tal)) =
7325 class_get
7326 ~is_method:true
7327 ~is_const:false
7328 ~coerce_from_ty:None
7331 method_id
7332 class_id
7334 let (env, (tel, typed_unpack_element, res)) =
7335 call ~expected:None p env fty el unpacked_element
7337 let (env, ty) = f env fty res el in
7338 let (env, fty) = Env.expand_type env fty in
7339 let fty =
7340 map_ty fty ~f:(function
7341 | Tfun ft -> Tfun { ft with ft_ret = MakeType.unenforced ty }
7342 | ty -> ty)
7344 let te = Tast.make_typed_expr fpos fty (Aast.Class_const (tcid, method_id)) in
7345 make_call env te tal tel typed_unpack_element ty
7347 and update_array_type ?lhs_of_null_coalesce p env e1 valkind =
7348 match valkind with
7349 | `lvalue
7350 | `lvalue_subexpr ->
7351 let (env, te1, ty1) =
7352 raw_expr
7353 ~valkind:`lvalue_subexpr
7354 ~check_defined:true
7357 ~allow_awaitable:(*?*) false
7359 begin
7360 match e1 with
7361 | (_, Lvar (_, x)) ->
7362 (* type_mapper has updated the type in ty1 typevars, but we
7363 need to update the local variable type too *)
7364 let env = set_local env (p, x) ty1 in
7365 (env, te1, ty1)
7366 | _ -> (env, te1, ty1)
7368 | _ -> raw_expr ?lhs_of_null_coalesce env e1 ~allow_awaitable:(*?*) false
7370 (* External API *)
7371 let expr ?expected env e =
7372 Typing_env.with_origin2 env Decl_counters.Body (fun env ->
7373 expr ?expected env e ~allow_awaitable:(*?*) false)
7375 let expr_with_pure_coeffects ?expected env e =
7376 Typing_env.with_origin2 env Decl_counters.Body (fun env ->
7377 expr_with_pure_coeffects ?expected env e ~allow_awaitable:(*?*) false)
7379 let stmt env st =
7380 Typing_env.with_origin env Decl_counters.Body (fun env -> stmt env st)