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