Default `disable_unset_class_const` to `true` and remove
[hiphop-php.git] / hphp / hack / src / typing / typing.ml
blob7628a561479b8d490ea246c2e21267735bc769df
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 C = Typing_continuations
42 module CMap = C.Map
43 module Try = Typing_try
44 module FL = FeatureLogging
45 module MakeType = Typing_make_type
46 module Cls = Decl_provider.Class
47 module Fake = Typing_fake_members
48 module ExpectedTy = Typing_helpers.ExpectedTy
49 module ITySet = Internal_type_set
51 type newable_class_info =
52 env
53 * Tast.targ list
54 * Tast.class_id
55 * [ `Class of pos_id * Cls.t * locl_ty | `Dynamic ] list
57 (*****************************************************************************)
58 (* Debugging *)
59 (*****************************************************************************)
61 (* A guess as to the last position we were typechecking, for use in debugging,
62 * such as figuring out what a runaway hh_server thread is doing. Updated
63 * only best-effort -- it's an approximation to point debugging in the right
64 * direction, nothing more. *)
65 let debug_last_pos = ref Pos.none
67 let debug_print_last_pos _ =
68 Hh_logger.info
69 "Last typecheck pos: %s"
70 (Pos.string (Pos.to_absolute !debug_last_pos))
72 (*****************************************************************************)
73 (* Helpers *)
74 (*****************************************************************************)
76 let mk_hole ?(source = Aast.Typing) ((_, pos, _) as expr) ~ty_have ~ty_expect =
77 if equal_locl_ty ty_have ty_expect then
78 expr
79 else
80 (* if the hole is generated from typing, we leave the type unchanged,
81 if it is a call to `[unsafe|enforced]_cast`, we give it the expected type
83 let ty_hole =
84 match source with
85 | Aast.Typing -> ty_have
86 | UnsafeCast _
87 | EnforcedCast _ ->
88 ty_expect
90 make_typed_expr pos ty_hole @@ Aast.Hole (expr, ty_have, ty_expect, source)
92 let hole_on_err (te : Tast.expr) ~err_opt =
93 Option.value_map err_opt ~default:te ~f:(fun (ty_have, ty_expect) ->
94 mk_hole te ~ty_have ~ty_expect)
96 (* When typing compound assignments we generate a 'fake' expression which
97 desugars it to the operation on the rhs of the assignment. If there
98 was a subtyping error, we end up with the Hole on the fake rhs
99 rather than the original rhs. This function rewrites the
100 desugared expression with the Hole in the correct place *)
101 let resugar_binop expr =
102 match expr with
103 | ( topt,
105 Aast.(
106 Binop
107 ( _,
108 te1,
109 (_, _, Hole ((_, _, Binop (op, _, te2)), ty_have, ty_expect, source))
110 )) ) ->
111 let hte2 = mk_hole te2 ~ty_have ~ty_expect ~source in
112 let te = Aast.Binop (Ast_defs.Eq (Some op), te1, hte2) in
113 Some (topt, p, te)
114 | (topt, p, Aast.Binop (_, te1, (_, _, Aast.Binop (op, _, te2)))) ->
115 let te = Aast.Binop (Ast_defs.Eq (Some op), te1, te2) in
116 Some (topt, p, te)
117 | _ -> None
119 (* When recording subtyping or coercion errors for union and intersection types
120 we need to look at the error for each element and then reconstruct any
121 errors into a union or intersection. If there were no errors for any
122 element, the result if also `Ok`; if there was an error for at least
123 on element we have `Error` with list of actual and expected types *)
124 let fold_coercion_errs errs =
125 List.fold_left errs ~init:(Ok []) ~f:(fun acc err ->
126 match (acc, err) with
127 | (Ok xs, Ok x) -> Ok (x :: xs)
128 | (Ok xs, Error (x, y)) -> Error (x :: xs, y :: xs)
129 | (Error (xs, ys), Ok x) -> Error (x :: xs, x :: ys)
130 | (Error (xs, ys), Error (x, y)) -> Error (x :: xs, y :: ys))
132 let union_coercion_errs errs =
133 Result.fold
134 ~ok:(fun tys -> Ok (MakeType.union Reason.Rnone tys))
135 ~error:(fun (acts, exps) ->
136 Error (MakeType.union Reason.Rnone acts, MakeType.union Reason.Rnone exps))
137 @@ fold_coercion_errs errs
139 let intersect_coercion_errs errs =
140 Result.fold
141 ~ok:(fun tys -> Ok (MakeType.intersection Reason.Rnone tys))
142 ~error:(fun (acts, exps) ->
143 Error
144 ( MakeType.intersection Reason.Rnone acts,
145 MakeType.intersection Reason.Rnone exps ))
146 @@ fold_coercion_errs errs
148 (** Given the type of an argument that has been unpacked and typed against
149 positional and variadic function parameter types, apply the subtyping /
150 coercion errors back to the original packed type. *)
151 let pack_errs pos ty subtyping_errs =
152 let nothing =
153 MakeType.nothing @@ Reason.Rsolve_fail (Pos_or_decl.of_raw_pos pos)
155 let rec aux ~k = function
156 (* Case 1: we have a type error at this positional parameter so
157 replace the type parameter which caused it with the expected type *)
158 | ((Some (_, ty) :: rest, var_opt), _ :: tys)
159 (* Case 2: there was no type error here so retain the original type
160 parameter *)
161 | ((None :: rest, var_opt), ty :: tys) ->
162 (* recurse for any remaining positional parameters and add the
163 corrected (case 1) or original (case 2) type to the front of the
164 list of type parameters in the continuation *)
165 aux ((rest, var_opt), tys) ~k:(fun tys -> k (ty :: tys))
166 (* Case 3: we have a type error at the variadic parameter so replace
167 the type parameter which cased it with the expected type *)
168 | ((_, (Some (_, ty) as var_opt)), _ :: tys) ->
169 (* recurse with the variadic parameter error and add the
170 corrected type to the front of the list of type parameters in the
171 continuation *)
172 aux (([], var_opt), tys) ~k:(fun tys -> k (ty :: tys))
173 (* Case 4: we have a variadic parameter but no error - we're done so
174 pass the remaining unchanged type parameters into the contination
175 to rebuild corrected type params in the right order *)
176 | ((_, None), tys) -> k tys
177 (* Case 5: no more type parameters - again we're done so pass empty
178 list to continuation and rebuild corrected type params in the right
179 order *)
180 | (_, []) -> k []
182 (* The only types that _can_ be upacked are tuples and pairs; match on the
183 type to get the type parameters, pass them to our recursive function
184 aux to subsitute the expected type where we have a type error
185 then reconstruct the type in the continuation *)
186 match deref ty with
187 | (r, Ttuple tys) ->
188 aux (subtyping_errs, tys) ~k:(fun tys -> mk (r, Ttuple tys))
189 | (r, Tclass (pos_id, exact, tys)) ->
190 aux (subtyping_errs, tys) ~k:(fun tys ->
191 mk (r, Tclass (pos_id, exact, tys)))
192 | _ -> nothing
194 let err_witness env p = TUtils.terr env (Reason.Rwitness p)
196 let triple_to_pair (env, te, ty) = (env, (te, ty))
198 let with_special_coeffects env cap_ty unsafe_cap_ty f =
199 let init =
200 Option.map (Env.next_cont_opt env) ~f:(fun next_cont ->
201 let initial_locals = next_cont.Typing_per_cont_env.local_types in
202 let tpenv = Env.get_tpenv env in
203 (initial_locals, tpenv))
205 Typing_lenv.stash_and_do env (Env.all_continuations env) (fun env ->
206 let env =
207 match init with
208 | None -> env
209 | Some (initial_locals, tpenv) ->
210 let env = Env.reinitialize_locals env in
211 let env = Env.set_locals env initial_locals in
212 let env = Env.env_with_tpenv env tpenv in
215 let (env, _ty) =
216 Typing_coeffects.register_capabilities env cap_ty unsafe_cap_ty
218 f env)
220 (* Set all the types in an expression to the given type. *)
221 let with_type ty env (e : Nast.expr) : Tast.expr =
222 let visitor =
223 object (self)
224 inherit [_] Aast.map
226 method! on_expr env ((), p, expr_) = (ty, p, self#on_expr_ env expr_)
228 method on_'ex _ () = ty
230 method on_'en _ _ = env
233 visitor#on_expr () e
235 let invalid_expr_ env p : Tast.expr_ =
236 let expr = ((), p, Naming.invalid_expr_ p) in
237 let ty = TUtils.terr env Reason.Rnone in
238 let (_, _, expr_) = with_type ty Tast.dummy_saved_env expr in
239 expr_
241 let expr_error env (r : Reason.t) (e : Nast.expr) =
242 let ty = TUtils.terr env r in
243 (env, with_type ty Tast.dummy_saved_env e, ty)
245 let expr_any env p e =
246 let ty = Typing_utils.mk_tany env p in
247 (env, with_type ty Tast.dummy_saved_env e, ty)
249 let unbound_name env (pos, name) e =
250 match Env.get_mode env with
251 | FileInfo.Mstrict ->
252 Errors.add_typing_error
253 Typing_error.(primary @@ Primary.Unbound_name { pos; name });
254 expr_error env (Reason.Rwitness pos) e
255 | FileInfo.Mhhi -> expr_any env pos e
257 (* Is this type Traversable<vty> or Container<vty> for some vty? *)
258 let get_value_collection_inst env ty =
259 match get_node ty with
260 | Tclass ((_, c), _, [vty])
261 when String.equal c SN.Collections.cTraversable
262 || String.equal c SN.Collections.cContainer ->
263 Some vty
264 (* If we're expecting a mixed or a nonnull then we can just assume
265 * that the element type is mixed *)
266 | Tnonnull -> Some (MakeType.mixed (get_reason ty))
267 | Tany _ -> Some ty
268 | Tdynamic when env.in_support_dynamic_type_method_check ->
269 Some ty (* interpret dynamic as Traversable<dynamic> *)
270 | _ -> None
272 (* Is this type KeyedTraversable<kty,vty>
273 * or KeyedContainer<kty,vty>
274 * for some kty, vty?
276 let get_key_value_collection_inst env p ty =
277 match get_node ty with
278 | Tclass ((_, c), _, [kty; vty])
279 when String.equal c SN.Collections.cKeyedTraversable
280 || String.equal c SN.Collections.cKeyedContainer ->
281 Some (kty, vty)
282 (* If we're expecting a mixed or a nonnull then we can just assume
283 * that the key type is arraykey and the value type is mixed *)
284 | Tnonnull ->
285 let arraykey = MakeType.arraykey (Reason.Rkey_value_collection_key p) in
286 let mixed = MakeType.mixed (Reason.Rwitness p) in
287 Some (arraykey, mixed)
288 | Tany _ -> Some (ty, ty)
289 | Tdynamic when env.in_support_dynamic_type_method_check ->
290 (* interpret dynamic as KeyedTraversable<arraykey, dynamic> *)
291 let arraykey = MakeType.arraykey (Reason.Rkey_value_collection_key p) in
292 Some (arraykey, ty)
293 | _ -> None
295 (* Is this type varray<vty> or a supertype for some vty? *)
296 let vc_kind_to_supers kind =
297 match kind with
298 | Vector -> [SN.Collections.cVector; SN.Collections.cMutableVector]
299 | ImmVector -> [SN.Collections.cImmVector; SN.Collections.cConstVector]
300 | Vec -> [SN.Collections.cVec]
301 | Set -> [SN.Collections.cSet; SN.Collections.cMutableSet]
302 | ImmSet -> [SN.Collections.cImmSet; SN.Collections.cConstSet]
303 | Keyset -> [SN.Collections.cKeyset]
305 let kvc_kind_to_supers kind =
306 match kind with
307 | Map -> [SN.Collections.cMap; SN.Collections.cMutableMap]
308 | ImmMap -> [SN.Collections.cImmMap; SN.Collections.cConstMap]
309 | Dict -> [SN.Collections.cDict]
311 (* Is this type one of the value collection types with element type vty? *)
312 let get_vc_inst env vc_kind ty =
313 let classnames = vc_kind_to_supers vc_kind in
314 match get_node ty with
315 | Tclass ((_, c), _, [vty]) when List.exists classnames ~f:(String.equal c) ->
316 Some vty
317 | _ -> get_value_collection_inst env ty
319 (* Is this type one of the three key-value collection types
320 * e.g. dict<kty,vty> or a supertype for some kty and vty? *)
321 let get_kvc_inst env p kvc_kind ty =
322 let classnames = kvc_kind_to_supers kvc_kind in
323 match get_node ty with
324 | Tclass ((_, c), _, [kty; vty])
325 when List.exists classnames ~f:(String.equal c) ->
326 Some (kty, vty)
327 | _ -> get_key_value_collection_inst env p ty
329 (* Check whether this is a function type that (a) either returns a disposable
330 * or (b) has the <<__ReturnDisposable>> attribute
332 let is_return_disposable_fun_type env ty =
333 let (_env, ty) = Env.expand_type env ty in
334 match get_node ty with
335 | Tfun ft ->
336 get_ft_return_disposable ft
337 || Option.is_some
338 (Typing_disposable.is_disposable_type env ft.ft_ret.et_type)
339 | _ -> false
341 (* Turn an environment into a local_id_map suitable to be embedded
342 * into an AssertEnv statement
344 let annot_map env =
345 match Env.next_cont_opt env with
346 | Some { Typing_per_cont_env.local_types; _ } ->
347 Some (Local_id.Map.map (fun (ty, pos, _expr_id) -> (pos, ty)) local_types)
348 | None -> None
350 (* Similar to annot_map above, but filters the map to only contain
351 * information about locals in lset
353 let refinement_annot_map env lset =
354 match annot_map env with
355 | Some map ->
356 let map =
357 Local_id.Map.filter (fun lid _ -> Local_id.Set.mem lid lset) map
359 if Local_id.Map.is_empty map then
360 None
361 else
362 Some map
363 | None -> None
365 let assert_env_blk ~pos ~at annotation_kind env_map_opt blk =
366 let mk_assert map = (pos, Aast.AssertEnv (annotation_kind, map)) in
367 let annot_blk = Option.to_list (Option.map ~f:mk_assert env_map_opt) in
368 match at with
369 | `Start -> annot_blk @ blk
370 | `End -> blk @ annot_blk
372 let assert_env_stmt ~pos ~at annotation_kind env_map_opt stmt =
373 let mk_assert map = (pos, Aast.AssertEnv (annotation_kind, map)) in
374 match env_map_opt with
375 | Some env_map ->
376 let stmt = (pos, stmt) in
377 let blk =
378 match at with
379 | `Start -> [mk_assert env_map; stmt]
380 | `End -> [stmt; mk_assert env_map]
382 Aast.Block blk
383 | None -> stmt
385 let set_tcopt_unstable_features env { fa_user_attributes; _ } =
386 match
387 Naming_attributes.find
388 SN.UserAttributes.uaEnableUnstableFeatures
389 fa_user_attributes
390 with
391 | None -> env
392 | Some { ua_name = _; ua_params } ->
393 let ( = ) = String.equal in
394 List.fold ua_params ~init:env ~f:(fun env (_, _, feature) ->
395 match feature with
396 | Aast.String s when s = SN.UnstableFeatures.ifc ->
397 Env.map_tcopt ~f:TypecheckerOptions.enable_ifc env
398 | Aast.String s when s = SN.UnstableFeatures.modules ->
399 Env.map_tcopt ~f:(fun t -> TypecheckerOptions.set_modules t true) env
400 | Aast.String s when s = SN.UnstableFeatures.expression_trees ->
401 Env.map_tcopt
402 ~f:(fun t ->
403 TypecheckerOptions.set_tco_enable_expression_trees t true)
405 | _ -> env)
407 (** Do a subtype check of inferred type against expected type.
408 * The optional coerce_for_op parameter controls whether any arguments of type
409 * dynamic can be coerced to enforceable types because they are arguments to a
410 * built-in operator.
412 let check_expected_ty_res
413 ~(coerce_for_op : bool)
414 (message : string)
415 (env : env)
416 (inferred_ty : locl_ty)
417 (expected : ExpectedTy.t option) : (env, env) result =
418 match expected with
419 | None -> Ok env
420 | Some ExpectedTy.{ pos = p; reason = ur; ty; coerce } ->
421 Typing_log.(
422 log_with_level env "typing" ~level:1 (fun () ->
423 log_types
424 (Pos_or_decl.of_raw_pos p)
427 Log_head
428 ( Printf.sprintf
429 "Typing.check_expected_ty %s enforced=%s"
430 message
431 (match ty.et_enforced with
432 | Unenforced -> "unenforced"
433 | Enforced -> "enforced"),
435 Log_type ("inferred_ty", inferred_ty);
436 Log_type ("expected_ty", ty.et_type);
437 ] );
438 ]));
439 Typing_coercion.coerce_type_res
440 ~coerce_for_op
441 ~coerce
445 inferred_ty
447 Typing_error.Callback.unify_error
449 let check_expected_ty message env inferred_ty expected =
450 Result.fold ~ok:Fn.id ~error:Fn.id
451 @@ check_expected_ty_res ~coerce_for_op:false message env inferred_ty expected
453 (* Set a local; must not be already assigned if it is a using variable *)
454 let set_local ?(is_using_clause = false) env (pos, x) ty =
455 if Env.is_using_var env x then
456 Errors.add_typing_error
457 Typing_error.(
458 primary
459 (if is_using_clause then
460 Primary.Duplicate_using_var pos
461 else
462 Primary.Illegal_disposable { pos; verb = `assigned }));
463 let env = Env.set_local env x ty pos in
464 if is_using_clause then
465 Env.set_using_var env x
466 else
469 (* Require a new construct with disposable *)
470 let rec enforce_return_disposable _env e =
471 match e with
472 | (_, _, New _) -> ()
473 | (_, _, Call _) -> ()
474 | (_, _, Await (_, _, Call _)) -> ()
475 | (_, _, Hole (e, _, _, _)) -> enforce_return_disposable _env e
476 | (_, p, _) ->
477 Errors.add_typing_error
478 Typing_error.(primary @@ Primary.Invalid_return_disposable p)
480 (* Wrappers around the function with the same name in Typing_lenv, which only
481 * performs the move/save and merge operation if we are in a try block or in a
482 * function with return type 'noreturn'.
483 * This enables significant perf improvement, because this is called at every
484 * function of method call, when most calls are outside of a try block. *)
485 let move_and_merge_next_in_catch env =
486 if env.in_try || TFTerm.is_noreturn env then
487 LEnv.move_and_merge_next_in_cont env C.Catch
488 else
489 LEnv.drop_cont env C.Next
491 let save_and_merge_next_in_catch env =
492 if env.in_try || TFTerm.is_noreturn env then
493 LEnv.save_and_merge_next_in_cont env C.Catch
494 else
497 let might_throw env = save_and_merge_next_in_catch env
499 let branch :
500 type res. env -> (env -> env * res) -> (env -> env * res) -> env * res * res
502 fun env branch1 branch2 ->
503 let parent_lenv = env.lenv in
504 let (env, tbr1) = branch1 env in
505 let lenv1 = env.lenv in
506 let env = { env with lenv = parent_lenv } in
507 let (env, tbr2) = branch2 env in
508 let lenv2 = env.lenv in
509 let env = LEnv.union_lenvs env parent_lenv lenv1 lenv2 in
510 (env, tbr1, tbr2)
512 let as_expr env ty1 pe e =
513 let env = Env.open_tyvars env pe in
514 let (env, tv) = Env.fresh_type env pe in
515 let (env, expected_ty, tk, tv) =
516 match e with
517 | As_v _ ->
518 let tk = MakeType.mixed Reason.Rnone in
519 (env, MakeType.traversable (Reason.Rforeach pe) tv, tk, tv)
520 | As_kv _ ->
521 let (env, tk) = Env.fresh_type env pe in
522 (env, MakeType.keyed_traversable (Reason.Rforeach pe) tk tv, tk, tv)
523 | Await_as_v _ ->
524 let tk = MakeType.mixed Reason.Rnone in
525 (env, MakeType.async_iterator (Reason.Rasyncforeach pe) tv, tk, tv)
526 | Await_as_kv _ ->
527 let (env, tk) = Env.fresh_type env pe in
528 ( env,
529 MakeType.async_keyed_iterator (Reason.Rasyncforeach pe) tk tv,
531 tv )
533 let rec distribute_union env ty =
534 let (env, ty) = Env.expand_type env ty in
535 match get_node ty with
536 | Tunion tyl ->
537 let (env, errs) =
538 List.fold tyl ~init:(env, []) ~f:(fun (env, errs) ty ->
539 let (env, err) = distribute_union env ty in
540 (env, err :: errs))
542 (env, union_coercion_errs errs)
543 | _ ->
544 if SubType.is_sub_type_for_union env ty (MakeType.dynamic Reason.Rnone)
545 then
546 let env =
547 SubType.sub_type
551 (Typing_error.Reasons_callback.unify_error_at pe)
553 let env =
554 SubType.sub_type
558 (Typing_error.Reasons_callback.unify_error_at pe)
560 (env, Ok ty)
561 else
562 let ur = Reason.URforeach in
563 let (env, err) =
564 Result.fold
565 ~ok:(fun env -> (env, Ok ty))
566 ~error:(fun env -> (env, Error (ty, expected_ty)))
567 @@ Type.sub_type_res
572 expected_ty
573 Typing_error.Callback.unify_error
575 (env, err)
578 let (env, err_res) = distribute_union env ty1 in
579 let err_opt =
580 match err_res with
581 | Ok _ -> None
582 | Error (act, exp) -> Some (act, exp)
584 let env = Env.set_tyvar_variance env expected_ty in
585 (Typing_solver.close_tyvars_and_solve env, tk, tv, err_opt)
587 (* These functions invoke special printing functions for Typing_env. They do not
588 * appear in user code, but we still check top level function calls against their
589 * names. *)
590 let typing_env_pseudofunctions =
591 SN.PseudoFunctions.(
592 String.Hash_set.of_list
593 ~growth_allowed:false
595 hh_show;
596 hh_expect;
597 hh_expect_equivalent;
598 hh_show_env;
599 hh_log_level;
600 hh_force_solve;
601 hh_loop_forever;
604 let do_hh_expect ~equivalent env use_pos explicit_targs p tys =
605 match explicit_targs with
606 | [targ] ->
607 let (env, (expected_ty, _)) =
608 Phase.localize_targ ~check_well_kinded:true env (snd targ)
610 let right_expected_ty =
611 if TypecheckerOptions.pessimise_builtins (Env.get_tcopt env) then
612 MakeType.locl_like
613 (Reason.Renforceable (get_pos expected_ty))
614 expected_ty
615 else
616 expected_ty
618 (match tys with
619 | [expr_ty] ->
620 let res =
621 SubType.sub_type_res
623 expr_ty
624 right_expected_ty
625 Typing_error.(
626 Reasons_callback.of_primary_error
627 @@ Primary.Hh_expect { pos = p; equivalent })
629 (match res with
630 | Ok env ->
631 if equivalent then
632 SubType.sub_type
634 expected_ty
635 expr_ty
636 Typing_error.(
637 Reasons_callback.of_primary_error
638 @@ Primary.Hh_expect { pos = p; equivalent })
639 else
641 | Error env -> env)
642 | _ -> env)
643 | _ ->
644 (Errors.add_typing_error
645 @@ Typing_error.(
646 primary
647 @@ Primary.Expected_tparam
648 { pos = use_pos; decl_pos = Pos_or_decl.none; n = 1 }));
651 let loop_forever env =
652 (* forever = up to 10 minutes, to avoid accidentally stuck processes *)
653 for i = 1 to 600 do
654 (* Look up things in shared memory occasionally to have a chance to be
655 * interrupted *)
656 match Env.get_class env "FOR_TEST_ONLY" with
657 | None -> Unix.sleep 1
658 | _ -> assert false
659 done;
660 Utils.assert_false_log_backtrace
661 (Some "hh_loop_forever was looping for more than 10 minutes")
663 let is_parameter env x = Local_id.Map.mem x (Env.get_params env)
665 let check_escaping_var env (pos, x) =
666 let err_opt =
667 if Env.is_using_var env x then
668 let open Typing_error.Primary in
669 Some
670 (if Local_id.equal x this then
671 Escaping_this pos
672 else if is_parameter env x then
673 Escaping_disposable_param pos
674 else
675 Escaping_disposable pos)
676 else
677 None
679 Option.iter err_opt ~f:(fun err ->
680 Errors.add_typing_error @@ Typing_error.primary err)
682 let make_result env p te ty =
683 (* Set the variance of any type variables that were generated according
684 * to how they appear in the expression type *)
685 let env = Env.set_tyvar_variance env ty in
686 (env, Tast.make_typed_expr p ty te, ty)
688 let localize_targ env ta =
689 let pos = fst ta in
690 let (env, targ) = Phase.localize_targ ~check_well_kinded:true env ta in
691 (env, targ, ExpectedTy.make pos Reason.URhint (fst targ))
693 let set_function_pointer ty =
694 match get_node ty with
695 | Tfun ft ->
696 let ft = set_ft_is_function_pointer ft true in
697 mk (get_reason ty, Tfun ft)
698 | _ -> ty
700 let set_readonly_this ty =
701 match get_node ty with
702 | Tfun ft ->
703 let ft = set_ft_readonly_this ft true in
704 mk (get_reason ty, Tfun ft)
705 | _ -> ty
707 let xhp_attribute_decl_ty env sid obj attr =
708 let (namepstr, valpty) = attr in
709 let (valp, valty) = valpty in
710 let (env, (declty, _tal)) =
711 TOG.obj_get
712 ~obj_pos:(fst sid)
713 ~is_method:false
714 ~inst_meth:false
715 ~meth_caller:false
716 ~nullsafe:None
717 ~coerce_from_ty:None
718 ~explicit_targs:[]
719 ~class_id:(CI sid)
720 ~member_id:namepstr
721 ~on_error:Typing_error.Callback.unify_error
725 let ureason = Reason.URxhp (snd sid, snd namepstr) in
726 let (env, err_opt) =
727 Result.fold
728 ~ok:(fun env -> (env, None))
729 ~error:(fun env -> (env, Some (valty, declty)))
730 @@ Typing_coercion.coerce_type_res
731 valp
732 ureason
734 valty
735 (MakeType.unenforced declty)
736 Typing_error.Callback.xhp_attribute_does_not_match_hint
738 (env, declty, err_opt)
740 let closure_check_param env param =
741 match hint_of_type_hint param.param_type_hint with
742 | None -> env
743 | Some hty ->
744 let hint_pos = fst hty in
745 let (env, hty) =
746 Phase.localize_hint_no_subst env ~ignore_errors:false hty
748 let paramty = Env.get_local env (Local_id.make_unscoped param.param_name) in
749 let env =
750 Typing_coercion.coerce_type
751 hint_pos
752 Reason.URhint
754 paramty
755 (MakeType.unenforced hty)
756 Typing_error.Callback.unify_error
760 let stash_conts_for_closure env p is_anon captured f =
761 let captured =
762 if is_anon && TypecheckerOptions.any_coeffects (Env.get_tcopt env) then
763 Typing_coeffects.(
764 (Pos.none, local_capability_id) :: (Pos.none, capability_id) :: captured)
765 else
766 captured
768 let captured =
769 if Env.is_local_defined env this && not (Env.is_in_expr_tree env) then
770 (Pos.none, this) :: captured
771 else
772 captured
774 let init =
775 Option.map (Env.next_cont_opt env) ~f:(fun next_cont ->
776 let initial_locals =
777 if is_anon then
778 Env.get_locals env captured
779 else
780 next_cont.Typing_per_cont_env.local_types
782 let initial_fakes =
783 Fake.forget (Env.get_fake_members env) Reason.(Blame (p, BSlambda))
785 let tpenv = Env.get_tpenv env in
786 (initial_locals, initial_fakes, tpenv))
788 Typing_lenv.stash_and_do env (Env.all_continuations env) (fun env ->
789 let env =
790 match init with
791 | None -> env
792 | Some (initial_locals, initial_fakes, tpenv) ->
793 let env = Env.reinitialize_locals env in
794 let env = Env.set_locals env initial_locals in
795 let env = Env.set_fake_members env initial_fakes in
796 let env = Env.env_with_tpenv env tpenv in
799 f env)
801 let requires_consistent_construct = function
802 | CIstatic -> true
803 | CIexpr _ -> true
804 | CIparent -> false
805 | CIself -> false
806 | CI _ -> false
808 (* Caller will be looking for a particular form of expected type
809 * e.g. a function type (when checking lambdas) or tuple type (when checking
810 * tuples). First expand the expected type and elide single union; also
811 * strip nullables, so ?t becomes t, as context will always accept a t if a ?t
812 * is expected.
814 * If allow_supportdyn is true, then decompose supportdyn<t> and return true to
815 * indicate that the type supports dynamic.
817 * Note: we currently do not generally expand ?t into (null | t), so ~?t is (dynamic | Toption t).
819 let expand_expected_and_get_node
820 ?(allow_supportdyn = false) env (expected : ExpectedTy.t option) =
821 let rec unbox env ty =
822 match TUtils.try_strip_dynamic env ty with
823 | Some stripped_ty ->
824 if TypecheckerOptions.enable_sound_dynamic env.genv.tcopt then
825 let (env, opt_ty) = Typing_dynamic.try_push_like env stripped_ty in
826 match opt_ty with
827 | None -> unbox env stripped_ty
828 | Some ty ->
829 let dyn = MakeType.dynamic Reason.Rnone in
831 SubType.is_sub_type_for_union
832 ~coerce:(Some Typing_logic.CoerceToDynamic)
836 then
837 unbox env ty
838 else
839 unbox env stripped_ty
840 else
841 unbox env stripped_ty
842 | None ->
843 begin
844 match get_node ty with
845 | Tunion [ty] -> unbox env ty
846 | Toption ty -> unbox env ty
847 | Tnewtype (name, [ty], _) when String.equal name SN.Classes.cSupportDyn
849 let (env, ty, _) = unbox env ty in
850 (env, ty, true)
851 | _ -> (env, ty, false)
854 match expected with
855 | None -> (env, None)
856 | Some ExpectedTy.{ pos = p; reason = ur; ty = { et_type = ty; _ }; _ } ->
857 let (env, ty) = Env.expand_type env ty in
858 let (env, uty, supportdyn) = unbox env ty in
859 if supportdyn && not allow_supportdyn then
860 (env, None)
861 else
862 (env, Some (p, ur, supportdyn, uty, get_node uty))
864 let uninstantiable_error env reason_pos cid c_tc_pos c_name c_usage_pos c_ty =
865 let reason_ty_opt =
866 match cid with
867 | CIexpr _ -> Some (reason_pos, lazy (Typing_print.error env c_ty))
868 | _ -> None
870 let err =
871 Typing_error.(
872 primary
873 @@ Primary.Uninstantiable_class
875 pos = c_usage_pos;
876 class_name = c_name;
877 reason_ty_opt;
878 decl_pos = c_tc_pos;
881 Errors.add_typing_error err
883 let coerce_to_throwable pos env exn_ty =
884 let throwable_ty = MakeType.throwable (Reason.Rthrow pos) in
885 Typing_coercion.coerce_type
886 ~coerce_for_op:true
888 Reason.URthrow
890 exn_ty
891 { et_type = throwable_ty; et_enforced = Enforced }
892 Typing_error.Callback.unify_error
894 let set_valid_rvalue p env x ty =
895 let env = set_local env (p, x) ty in
896 (* We are assigning a new value to the local variable, so we need to
897 * generate a new expression id
899 Env.set_local_expr_id env x (Ident.tmp ())
901 let is_hack_collection env ty =
902 (* TODO(like types) This fails if a collection is used as a parameter under
903 * pessimization, because ~Vector<int> </: ConstCollection<mixed>. This is the
904 * test we use to see whether to update the expression id for expressions
905 * $vector[0] = $x and $vector[] = $x. If this is false, the receiver is assumed
906 * to be a Hack array which are COW. This approximation breaks down in the presence
907 * of dynamic. It is unclear whether we should change an expression id if the
908 * receiver is dynamic. *)
909 Typing_solver.is_sub_type
912 (MakeType.const_collection Reason.Rnone (MakeType.mixed Reason.Rnone))
914 let check_class_get env p def_pos cid mid ce (_, _cid_pos, e) function_pointer =
915 match e with
916 | CIself when get_ce_abstract ce ->
917 begin
918 match Env.get_self_id env with
919 | Some self ->
920 (* at runtime, self:: in a trait is a call to whatever
921 * self:: is in the context of the non-trait "use"-ing
922 * the trait's code *)
923 begin
924 match Env.get_class env self with
925 | Some cls when Ast_defs.is_c_trait (Cls.kind cls) ->
926 (* Ban self::some_abstract_method() in a trait, if the
927 * method is also defined in a trait.
929 * Abstract methods from interfaces are fine: we'll check
930 * in the child class that we actually have an
931 * implementation. *)
932 (match Decl_provider.get_class (Env.get_ctx env) ce.ce_origin with
933 | Some meth_cls when Ast_defs.is_c_trait (Cls.kind meth_cls) ->
934 Errors.add_typing_error
935 Typing_error.(
936 primary
937 @@ Primary.Self_abstract_call
939 meth_name = mid;
940 self_pos = _cid_pos;
941 pos = p;
942 decl_pos = def_pos;
944 | _ -> ())
945 | _ ->
946 (* Ban self::some_abstract_method() in a class. This will
947 * always error. *)
948 Errors.add_typing_error
949 Typing_error.(
950 primary
951 @@ Primary.Self_abstract_call
953 meth_name = mid;
954 self_pos = _cid_pos;
955 pos = p;
956 decl_pos = def_pos;
959 | None -> ()
961 | CIparent when get_ce_abstract ce ->
962 Errors.add_typing_error
963 Typing_error.(
964 primary
965 @@ Primary.Parent_abstract_call
966 { meth_name = mid; pos = p; decl_pos = def_pos })
967 | CI _ when get_ce_abstract ce && function_pointer ->
968 Errors.add_typing_error
969 Typing_error.(
970 primary
971 @@ Primary.Abstract_function_pointer
972 { class_name = cid; meth_name = mid; pos = p; decl_pos = def_pos })
973 | CI _ when get_ce_abstract ce ->
974 Errors.add_typing_error
975 Typing_error.(
976 primary
977 @@ Primary.Classname_abstract_call
978 { class_name = cid; meth_name = mid; pos = p; decl_pos = def_pos })
979 | CI (_, class_name) when get_ce_synthesized ce ->
980 Errors.add_typing_error
981 Typing_error.(
982 primary
983 @@ Primary.Static_synthetic_method
984 { class_name; meth_name = mid; pos = p; decl_pos = def_pos })
985 | _ -> ()
987 (** Given an identifier for a function, find its function type in the
988 * environment and localise it with the input type parameters. If the function
989 * cannot be found, return [Terr].
991 let fun_type_of_id env x tal el =
992 match Env.get_fun env (snd x) with
993 | None ->
994 let (env, _, ty) = unbound_name env x ((), Pos.none, Aast.Null) in
995 (env, ty, [])
996 | Some
998 fe_type;
999 fe_pos;
1000 fe_deprecated;
1001 fe_support_dynamic_type;
1002 fe_internal;
1003 fe_module;
1005 } ->
1006 (match get_node fe_type with
1007 | Tfun ft ->
1008 let ft =
1009 let pessimise =
1010 TypecheckerOptions.pessimise_builtins (Env.get_tcopt env)
1012 Typing_special_fun.transform_special_fun_ty
1013 ~pessimise
1016 (List.length el)
1018 let ety_env = empty_expand_env in
1019 let (env, tal) =
1020 Phase.localize_targs
1021 ~check_well_kinded:true
1022 ~is_method:true
1023 ~def_pos:fe_pos
1024 ~use_pos:(fst x)
1025 ~use_name:(strip_ns (snd x))
1027 ft.ft_tparams
1028 (List.map ~f:snd tal)
1030 let ft =
1031 Typing_enforceability.compute_enforced_and_pessimize_fun_type env ft
1033 let use_pos = fst x in
1034 let def_pos = fe_pos in
1035 let (env, ft) =
1036 Phase.(
1037 localize_ft
1038 ~instantiation:
1039 { use_name = strip_ns (snd x); use_pos; explicit_targs = tal }
1040 ~def_pos
1041 ~ety_env
1045 let fty =
1046 Typing_dynamic.relax_method_type
1048 fe_support_dynamic_type
1049 (get_reason fe_type)
1052 Option.iter
1053 ~f:Errors.add_typing_error
1054 (TVis.check_deprecated ~use_pos ~def_pos fe_deprecated);
1055 let err_opt =
1056 let open Typing_error.Primary.Modules in
1057 if fe_internal then
1058 match
1059 Typing_modules.can_access
1060 ~current:(Env.get_module env)
1061 ~target:(Option.map fe_module ~f:snd)
1062 with
1063 | `Yes -> None
1064 | `Disjoint (current, target) ->
1065 Some
1066 (Module_mismatch
1068 pos = fst x;
1069 decl_pos = fe_pos;
1070 current_module_opt = Some current;
1071 target_module = target;
1073 | `Outside target ->
1074 Some
1075 (Module_mismatch
1077 pos = fst x;
1078 decl_pos = fe_pos;
1079 current_module_opt = None;
1080 target_module = target;
1082 else
1083 None
1085 Option.iter err_opt ~f:(fun err ->
1086 Errors.add_typing_error @@ Typing_error.modules err);
1087 (env, fty, tal)
1088 | _ -> failwith "Expected function type")
1091 * Checks if a class (given by cty) contains a given static method.
1093 * We could refactor this + class_get
1095 let class_contains_smethod env cty (_pos, mid) =
1096 let lookup_member ty =
1097 match get_class_type ty with
1098 | Some ((_, c), _, _) ->
1099 (match Env.get_class env c with
1100 | None -> false
1101 | Some class_ ->
1102 Option.is_some @@ Env.get_static_member true env class_ mid)
1103 | None -> false
1105 let (_env, tyl) =
1106 TUtils.get_concrete_supertypes ~abstract_enum:true env cty
1108 List.exists tyl ~f:lookup_member
1110 (* To be a valid trait declaration, all of its 'require extends' must
1111 * match; since there's no multiple inheritance, it follows that all of
1112 * the 'require extends' must belong to the same inheritance hierarchy
1113 * and one of them should be the child of all the others *)
1114 let trait_most_concrete_req_class trait env =
1115 List.fold
1116 (Cls.all_ancestor_reqs trait)
1118 begin
1119 fun acc (_p, ty) ->
1120 let (_r, (_p, name), _paraml) = TUtils.unwrap_class_type ty in
1121 let keep =
1122 match acc with
1123 | Some (c, _ty) -> Cls.has_ancestor c name
1124 | None -> false
1126 if keep then
1128 else
1129 let class_ = Env.get_class env name in
1130 match class_ with
1131 | None -> acc
1132 | Some c when Ast_defs.is_c_interface (Cls.kind c) -> acc
1133 | Some c when Ast_defs.is_c_trait (Cls.kind c) ->
1134 (* this is an error case for which Typing_type_wellformedness spits out
1135 * an error, but does *not* currently remove the offending
1136 * 'require extends' or 'require implements' *)
1138 | Some c -> Some (c, ty)
1140 ~init:None
1142 let check_arity ?(did_unpack = false) pos pos_def ft (arity : int) =
1143 let exp_min = Typing_defs.arity_min ft in
1144 if arity < exp_min then
1145 Errors.add_typing_error
1146 Typing_error.(
1147 primary
1148 @@ Primary.Typing_too_few_args
1149 { expected = exp_min; actual = arity; pos; decl_pos = pos_def });
1150 if get_ft_variadic ft then
1152 else
1153 (* No variadics *)
1154 let exp_max = List.length ft.ft_params in
1155 let arity =
1156 if did_unpack then
1157 arity + 1
1158 else
1159 arity
1161 if arity > exp_max then
1162 Errors.add_typing_error
1163 Typing_error.(
1164 primary
1165 @@ Primary.Typing_too_many_args
1166 { expected = exp_max; actual = arity; pos; decl_pos = pos_def })
1168 let check_lambda_arity lambda_pos def_pos lambda_ft expected_ft =
1169 match (get_ft_variadic lambda_ft, get_ft_variadic expected_ft) with
1170 | (false, false) ->
1171 let expected = Typing_defs.arity_min expected_ft in
1172 let actual = Typing_defs.arity_min lambda_ft in
1173 let prim_err_opt =
1174 if actual < expected then
1175 Some
1176 (Typing_error.Primary.Typing_too_few_args
1177 { expected; actual; pos = lambda_pos; decl_pos = def_pos })
1178 (* Errors.typing_too_few_args expected_min lambda_min lambda_pos def_pos; *)
1179 else if actual > expected then
1180 Some
1181 (Typing_error.Primary.Typing_too_many_args
1182 { expected; actual; pos = lambda_pos; decl_pos = def_pos })
1183 (* Errors.typing_too_many_args expected_minlambda_min lambda_pos def_pos *)
1184 else
1185 None
1187 Option.iter
1188 prim_err_opt
1189 ~f:Fn.(compose Errors.add_typing_error Typing_error.primary)
1190 | (_, _) -> ()
1192 (* The variadic capture argument is an array listing the passed
1193 * variable arguments for the purposes of the function body; callsites
1194 * should not unify with it *)
1195 let variadic_param env ft =
1196 if get_ft_variadic ft then
1197 (env, List.last ft.ft_params)
1198 else
1199 (env, None)
1201 let param_modes
1202 ?(is_variadic = false) ({ fp_pos; _ } as fp) (_, pos, _) param_kind =
1203 let err_opt =
1204 let open Typing_error.Primary in
1205 match (get_fp_mode fp, param_kind) with
1206 | (FPnormal, Ast_defs.Pnormal) -> None
1207 | (FPinout, Ast_defs.Pinout _) -> None
1208 | (FPnormal, Ast_defs.Pinout p) ->
1209 Some
1210 (Inout_annotation_unexpected
1212 pos = Pos.merge p pos;
1213 decl_pos = fp_pos;
1214 param_is_variadic = is_variadic;
1215 qfx_pos = p;
1217 | (FPinout, Ast_defs.Pnormal) ->
1218 Some (Inout_annotation_missing { pos; decl_pos = fp_pos })
1221 Option.iter err_opt ~f:(fun err ->
1222 Errors.add_typing_error @@ Typing_error.primary err)
1224 let split_remaining_params_required_optional ft remaining_params =
1225 (* Same example as above
1227 * function f(int $i, string $j, float $k = 3.14, mixed ...$m): void {}
1228 * function g((string, float, bool) $t): void {
1229 * f(3, ...$t);
1232 * `remaining_params` will contain [string, float] and there has been 1 parameter consumed. The min_arity
1233 * of this function is 2, so there is 1 required parameter remaining and 1 optional parameter.
1235 let original_params =
1236 if get_ft_variadic ft then
1237 List.drop_last_exn ft.ft_params
1238 else
1239 ft.ft_params
1241 let min_arity =
1242 List.count
1243 ~f:(fun fp -> not (Typing_defs.get_fp_has_default fp))
1244 original_params
1246 let consumed = List.length original_params - List.length remaining_params in
1247 let required_remaining = Int.max (min_arity - consumed) 0 in
1248 let (required_params, optional_params) =
1249 List.split_n remaining_params required_remaining
1251 (consumed, required_params, optional_params)
1253 let generate_splat_type_vars
1254 env p required_params optional_params variadic_param =
1255 let (env, d_required) =
1256 List.map_env env required_params ~f:(fun env _ -> Env.fresh_type env p)
1258 let (env, d_optional) =
1259 List.map_env env optional_params ~f:(fun env _ -> Env.fresh_type env p)
1261 let (env, d_variadic) =
1262 match variadic_param with
1263 | None -> (env, None)
1264 | Some _ ->
1265 let (env, ty) = Env.fresh_type env p in
1266 (env, Some ty)
1268 (env, (d_required, d_optional, d_variadic))
1270 let strip_dynamic env ty =
1271 let (env, ty) = Env.expand_type env ty in
1272 match get_node ty with
1273 | Tdynamic -> Typing_make_type.nothing (get_reason ty)
1274 | _ -> Typing_utils.strip_dynamic env ty
1276 let call_param
1277 ~in_supportdyn
1279 param
1280 param_kind
1281 (((_, pos, expr_) as e : Nast.expr), arg_ty)
1282 ~is_variadic : env * (locl_ty * locl_ty) option =
1283 param_modes ~is_variadic param e param_kind;
1284 (* When checking params, the type 'x' may be expression dependent. Since
1285 * we store the expression id in the local env for Lvar, we want to apply
1286 * it in this case.
1288 let (env, dep_ty) =
1289 match expr_ with
1290 | Hole ((_, _, Lvar _), _, _, _)
1291 | Lvar _ ->
1292 ExprDepTy.make env ~cid:(CIexpr e) arg_ty
1293 | _ -> (env, arg_ty)
1295 let pos =
1296 match param_kind with
1297 | Ast_defs.Pnormal -> pos
1298 | Ast_defs.Pinout pk_pos -> Pos.merge pk_pos pos
1300 let (env, dep_ty) =
1301 if in_supportdyn then
1302 let dyn_ty = MakeType.dynamic (get_reason dep_ty) in
1303 let env =
1304 (* If in_supportdyn is set, then the function type is supportdyn<t1 ... tn -> t>
1305 and we are trying to call it as though it were dynamic. Hence all of the
1306 arguments must be subtypes of dynamic, regardless of whether they have
1307 a like to be stripped. *)
1308 Typing_subtype.sub_type
1310 ~coerce:(Some Typing_logic.CoerceToDynamic)
1311 dep_ty
1312 dyn_ty
1313 (Typing_error.Reasons_callback.unify_error_at pos)
1315 (env, strip_dynamic env dep_ty)
1316 else
1317 (env, dep_ty)
1319 let eff () =
1320 if env.in_support_dynamic_type_method_check then
1321 Typing_log.log_pessimise_param env param.fp_pos param.fp_name
1323 Result.fold
1324 ~ok:(fun env -> (env, None))
1325 ~error:(fun env -> (env, Some (dep_ty, param.fp_type.et_type)))
1326 @@ Typing_coercion.coerce_type_res
1328 Reason.URparam
1330 dep_ty
1331 param.fp_type
1332 Typing_error.Callback.(
1333 (with_side_effect ~eff unify_error [@alert "-deprecated"]))
1335 let bad_call env p ty =
1336 Errors.add_typing_error
1337 Typing_error.(
1338 primary
1339 @@ Primary.Bad_call
1340 { pos = p; ty_name = lazy (Typing_print.error env ty) })
1342 let rec make_a_local_of ~include_this env e =
1343 match e with
1344 | (_, p, Class_get ((_, _, cname), CGstring (_, member_name), _)) ->
1345 let (env, local) = Env.FakeMembers.make_static env cname member_name p in
1346 (env, Some (p, local))
1347 | ( _,
1349 Obj_get
1350 ( (((_, _, This) | (_, _, Lvar _)) as obj),
1351 (_, _, Id (_, member_name)),
1353 _ ) ) ->
1354 let (env, local) = Env.FakeMembers.make env obj member_name p in
1355 (env, Some (p, local))
1356 | (_, _, Lvar x)
1357 | (_, _, Dollardollar x) ->
1358 (env, Some x)
1359 | (_, p, This) when include_this -> (env, Some (p, this))
1360 | (_, _, Hole (e, _, _, _)) -> make_a_local_of ~include_this env e
1361 | _ -> (env, None)
1363 (* This function captures the common bits of logic behind refinement
1364 * of the type of a local variable or a class member variable as a
1365 * result of a dynamic check (e.g., nullity check, simple type check
1366 * using functions like is_int, is_string, is_array etc.). The
1367 * argument refine is a function that takes the type of the variable
1368 * and returns a refined type (making necessary changes to the
1369 * environment, which is threaded through).
1371 * All refinement functions return, in addition to the updated
1372 * environment, a (conservative) set of all the locals that got
1373 * refined. This set is used to construct AssertEnv statmements in
1374 * the typed AST.
1376 let refine_lvalue_type env ((ty, _, _) as te) ~refine =
1377 let (env, ty) = refine env ty in
1378 let e = Tast.to_nast_expr te in
1379 let (env, localopt) = make_a_local_of ~include_this:false env e in
1380 (* TODO TAST: generate an assignment to the fake local in the TAST *)
1381 match localopt with
1382 | Some lid -> (set_local env lid ty, Local_id.Set.singleton (snd lid))
1383 | None -> (env, Local_id.Set.empty)
1385 let rec condition_nullity ~nonnull (env : env) te =
1386 match te with
1387 (* assignment: both the rhs and lhs of the '=' must be made null/non-null *)
1388 | (_, _, Aast.Binop (Ast_defs.Eq None, var, te)) ->
1389 let (env, lset1) = condition_nullity ~nonnull env te in
1390 let (env, lset2) = condition_nullity ~nonnull env var in
1391 (env, Local_id.Set.union lset1 lset2)
1392 (* case where `Shapes::idx(...)` must be made null/non-null *)
1393 | ( _,
1395 Aast.Call
1396 ( (_, _, Aast.Class_const ((_, _, Aast.CI (_, shapes)), (_, idx))),
1398 [(Ast_defs.Pnormal, shape); (Ast_defs.Pnormal, field)],
1399 _ ) )
1400 when String.equal shapes SN.Shapes.cShapes && String.equal idx SN.Shapes.idx
1402 let field = Tast.to_nast_expr field in
1403 let refine env shape_ty =
1404 if nonnull then
1405 Typing_shapes.shapes_idx_not_null env shape_ty field
1406 else
1407 (env, shape_ty)
1409 refine_lvalue_type env shape ~refine
1410 | (_, _, Hole (te, _, _, _)) -> condition_nullity ~nonnull env te
1411 | (_, p, _) ->
1412 let refine env ty =
1413 if nonnull then
1414 Typing_solver.non_null env (Pos_or_decl.of_raw_pos p) ty
1415 else
1416 let r = Reason.Rwitness_from_decl (get_pos ty) in
1417 Inter.intersect env ~r ty (MakeType.null r)
1419 refine_lvalue_type env te ~refine
1421 (** If we are dealing with a refinement like
1422 $x is MyClass<A, B>
1423 then class_info is the class info of MyClass and hint_tyl corresponds
1424 to A, B. *)
1425 let generate_fresh_tparams env class_info p reason hint_tyl =
1426 let tparams_len = List.length (Cls.tparams class_info) in
1427 let hint_tyl = List.take hint_tyl tparams_len in
1428 let pad_len = tparams_len - List.length hint_tyl in
1429 let hint_tyl =
1430 List.map hint_tyl ~f:(fun x -> Some x)
1431 @ List.init pad_len ~f:(fun _ -> None)
1433 let replace_wildcard env hint_ty tp =
1434 let {
1435 tp_name = (_, tparam_name);
1436 tp_reified = reified;
1437 tp_user_attributes;
1442 let enforceable =
1443 Attributes.mem SN.UserAttributes.uaEnforceable tp_user_attributes
1445 let newable =
1446 Attributes.mem SN.UserAttributes.uaNewable tp_user_attributes
1448 match hint_ty with
1449 | Some ty ->
1450 begin
1451 match get_node ty with
1452 | Tgeneric (name, _targs) when Env.is_fresh_generic_parameter name ->
1453 (* TODO(T69551141) handle type arguments above and below *)
1454 (env, (Some (tp, name), MakeType.generic reason name))
1455 | _ -> (env, (None, ty))
1457 | None ->
1458 let (env, new_name) =
1459 Env.add_fresh_generic_parameter
1461 (Pos_or_decl.of_raw_pos p)
1462 tparam_name
1463 ~reified
1464 ~enforceable
1465 ~newable
1467 (* TODO(T69551141) handle type arguments for Tgeneric *)
1468 (env, (Some (tp, new_name), MakeType.generic reason new_name))
1470 let (env, tparams_and_tyl) =
1471 List.map2_env env hint_tyl (Cls.tparams class_info) ~f:replace_wildcard
1473 let (tparams_with_new_names, tyl_fresh) = List.unzip tparams_and_tyl in
1474 (env, tparams_with_new_names, tyl_fresh)
1476 let safely_refine_class_type
1479 class_name
1480 class_info
1481 ivar_ty
1482 obj_ty
1483 reason
1484 (tparams_with_new_names : (decl_tparam * string) option list)
1485 tyl_fresh =
1486 (* Type of variable in block will be class name
1487 * with fresh type parameters *)
1488 let obj_ty =
1489 mk (get_reason obj_ty, Tclass (class_name, Nonexact, tyl_fresh))
1491 let tparams = Cls.tparams class_info in
1492 (* Add in constraints as assumptions on those type parameters *)
1493 let ety_env =
1495 empty_expand_env with
1496 substs = Subst.make_locl tparams tyl_fresh;
1497 this_ty = obj_ty;
1500 let add_bounds env (t, ty_fresh) =
1501 List.fold_left t.tp_constraints ~init:env ~f:(fun env (ck, ty) ->
1502 (* Substitute fresh type parameters for
1503 * original formals in constraint *)
1504 let (env, ty) = Phase.localize ~ety_env env ty in
1505 SubType.add_constraint
1508 ty_fresh
1510 (Typing_error.Reasons_callback.unify_error_at p))
1512 let env =
1513 List.fold_left (List.zip_exn tparams tyl_fresh) ~f:add_bounds ~init:env
1515 (* Finally, if we have a class-test on something with static classish type,
1516 * then we can chase the hierarchy and decompose the types to deduce
1517 * further assumptions on type parameters. For example, we might have
1518 * class B<Tb> { ... }
1519 * class C extends B<int>
1520 * and have obj_ty = C and x_ty = B<T> for a generic parameter Aast.
1521 * Then SubType.add_constraint will deduce that T=int and add int as
1522 * both lower and upper bound on T in env.lenv.tpenv
1524 * We only wish to do this if the types are in a possible subtype relationship.
1526 let (env, supertypes) =
1527 TUtils.get_concrete_supertypes ~abstract_enum:true env ivar_ty
1529 let rec might_be_supertype ty =
1530 let (_env, ty) = Env.expand_type env ty in
1531 match get_node ty with
1532 | Tclass ((_, name), _, _)
1533 when String.equal name (Cls.name class_info)
1534 || Cls.has_ancestor class_info name
1535 || Cls.requires_ancestor class_info name ->
1536 true
1537 | Tdynamic -> true
1538 | Toption ty -> might_be_supertype ty
1539 | Tunion tyl -> List.for_all tyl ~f:might_be_supertype
1540 | _ -> false
1542 let env =
1543 List.fold_left supertypes ~init:env ~f:(fun env ty ->
1544 if might_be_supertype ty then
1545 SubType.add_constraint
1547 Ast_defs.Constraint_as
1548 obj_ty
1550 (Typing_error.Reasons_callback.unify_error_at p)
1551 else
1552 env)
1554 (* It's often the case that the fresh name isn't necessary. For
1555 * example, if C<T> extends B<T>, and we have $x:B<t> for some type t
1556 * then $x is C should refine to $x:C<t>.
1557 * We take a simple approach:
1558 * For a fresh type parameter T#1, if
1559 * - There is an eqality constraint T#1 = t,
1560 * - T#1 is covariant, and T#1 has upper bound t (or mixed if absent)
1561 * - T#1 is contravariant, and T#1 has lower bound t (or nothing if absent)
1562 * then replace T#1 with t.
1563 * This is done in Type_parameter_env_ops.simplify_tpenv
1565 let (env, tparam_substs) =
1566 Type_parameter_env_ops.simplify_tpenv
1568 (List.zip_exn tparams_with_new_names tyl_fresh)
1569 reason
1571 let tyl_fresh =
1572 List.map2_exn tyl_fresh tparams_with_new_names ~f:(fun orig_ty tparam_opt ->
1573 match tparam_opt with
1574 | None -> orig_ty
1575 | Some (_tp, name) -> SMap.find name tparam_substs)
1577 let obj_ty_simplified =
1578 mk (get_reason obj_ty, Tclass (class_name, Nonexact, tyl_fresh))
1580 (env, obj_ty_simplified)
1582 (** Transform a hint like `A<_>` to a localized type like `A<T#1>` for refinement of
1583 an instance variable. ivar_ty is the previous type of that instance variable. Return
1584 the intersection of the hint and variable. *)
1585 let rec class_for_refinement env p reason ivar_pos ivar_ty hint_ty =
1586 let (env, hint_ty) = Env.expand_type env hint_ty in
1587 match (get_node ivar_ty, get_node hint_ty) with
1588 | (_, Tclass (((_, cid) as _c), _, tyl)) ->
1589 begin
1590 match Env.get_class env cid with
1591 | Some class_info ->
1592 let (env, tparams_with_new_names, tyl_fresh) =
1593 generate_fresh_tparams env class_info p reason tyl
1595 safely_refine_class_type
1599 class_info
1600 ivar_ty
1601 hint_ty
1602 reason
1603 tparams_with_new_names
1604 tyl_fresh
1605 | None -> (env, TUtils.terr env (Reason.Rwitness ivar_pos))
1607 | (Ttuple ivar_tyl, Ttuple hint_tyl)
1608 when Int.equal (List.length ivar_tyl) (List.length hint_tyl) ->
1609 let (env, tyl) =
1610 List.map2_env env ivar_tyl hint_tyl ~f:(fun env ivar_ty hint_ty ->
1611 class_for_refinement env p reason ivar_pos ivar_ty hint_ty)
1613 (env, MakeType.tuple reason tyl)
1614 | _ -> (env, hint_ty)
1616 let refine_and_simplify_intersection
1617 ~hint_first env p reason ivar_pos ivar_ty hint_ty =
1618 match get_node ivar_ty with
1619 | Tunion [ty1; ty2]
1620 when Typing_defs.is_dynamic ty1 || Typing_defs.is_dynamic ty2 ->
1621 (* Distribute the intersection over the union *)
1622 let (env, hint_ty1) =
1623 class_for_refinement env p reason ivar_pos ty1 hint_ty
1625 let (env, hint_ty2) =
1626 class_for_refinement env p reason ivar_pos ty2 hint_ty
1628 let (env, ty1) = Inter.intersect env ~r:reason ty1 hint_ty1 in
1629 let (env, ty2) = Inter.intersect env ~r:reason ty2 hint_ty2 in
1630 Typing_union.union env ty1 ty2
1631 | _ ->
1632 let (env, hint_ty) =
1633 class_for_refinement env p reason ivar_pos ivar_ty hint_ty
1635 (* Sometimes the type checker is sensitive to the ordering of intersections *)
1636 if hint_first then
1637 Inter.intersect env ~r:reason hint_ty ivar_ty
1638 else
1639 Inter.intersect env ~r:reason ivar_ty hint_ty
1641 let refine_for_is ~hint_first env tparamet ivar reason hint =
1642 let (env, lset) =
1643 match snd hint with
1644 | Aast.Hnonnull -> condition_nullity ~nonnull:tparamet env ivar
1645 | Aast.Hprim Tnull -> condition_nullity ~nonnull:(not tparamet) env ivar
1646 | _ -> (env, Local_id.Set.empty)
1648 let (env, locl) =
1649 make_a_local_of ~include_this:true env (Tast.to_nast_expr ivar)
1651 match locl with
1652 | Some locl_ivar ->
1653 let (env, hint_ty) =
1654 Phase.localize_hint_no_subst env ~ignore_errors:false hint
1656 let (env, hint_ty) =
1657 if not tparamet then
1658 Inter.negate_type env reason hint_ty ~approx:TUtils.ApproxUp
1659 else
1660 (env, hint_ty)
1662 let (env, refined_ty) =
1663 refine_and_simplify_intersection
1664 ~hint_first
1666 (fst hint)
1667 reason
1668 (fst locl_ivar)
1669 (fst3 ivar)
1670 hint_ty
1672 (set_local env locl_ivar refined_ty, Local_id.Set.singleton (snd locl_ivar))
1673 | None -> (env, lset)
1675 type legacy_arrays =
1676 | PHPArray
1677 | HackDictOrDArray
1678 | HackVecOrVArray
1680 (* Refine type for is_array, is_vec, is_keyset and is_dict tests
1681 * `pred_name` is the function name itself (e.g. 'is_vec')
1682 * `p` is position of the function name in the source
1683 * `arg_expr` is the argument to the function
1685 let safely_refine_is_array env ty p pred_name arg_expr =
1686 refine_lvalue_type env arg_expr ~refine:(fun env arg_ty ->
1687 let r = Reason.Rpredicated (p, pred_name) in
1688 let (env, tarrkey_name) =
1689 Env.add_fresh_generic_parameter
1691 (Pos_or_decl.of_raw_pos p)
1692 "Tk"
1693 ~reified:Erased
1694 ~enforceable:false
1695 ~newable:false
1697 (* TODO(T69551141) handle type arguments for Tgeneric *)
1698 let tarrkey = MakeType.generic r tarrkey_name in
1699 let env =
1700 SubType.add_constraint
1702 Ast_defs.Constraint_as
1703 tarrkey
1704 (MakeType.arraykey r)
1705 (Typing_error.Reasons_callback.unify_error_at p)
1707 let (env, tfresh_name) =
1708 Env.add_fresh_generic_parameter
1710 (Pos_or_decl.of_raw_pos p)
1712 ~reified:Erased
1713 ~enforceable:false
1714 ~newable:false
1716 (* TODO(T69551141) handle type arguments for Tgeneric *)
1717 let tfresh = MakeType.generic r tfresh_name in
1718 (* If we're refining the type for `is_array` we have a slightly more
1719 * involved process. Let's separate out that logic so we can re-use it.
1721 let array_ty =
1722 let tk = MakeType.arraykey Reason.(Rvarray_or_darray_key (to_pos r)) in
1723 let tv = tfresh in
1724 MakeType.varray_or_darray r tk tv
1726 (* This is the refined type of e inside the branch *)
1727 let hint_ty =
1728 match ty with
1729 | PHPArray -> array_ty
1730 | HackDictOrDArray ->
1731 MakeType.union
1733 [MakeType.dict r tarrkey tfresh; MakeType.darray r tarrkey tfresh]
1734 | HackVecOrVArray ->
1735 MakeType.union r [MakeType.vec r tfresh; MakeType.varray r tfresh]
1737 let (_, arg_pos, _) = arg_expr in
1738 let (env, refined_ty) =
1739 class_for_refinement env p r arg_pos arg_ty hint_ty
1741 (* Add constraints on generic parameters that must
1742 * hold for refined_ty <:arg_ty. For example, if arg_ty is Traversable<T>
1743 * and refined_ty is keyset<T#1> then we know T#1 <: T.
1744 * See analogous code in safely_refine_class_type.
1746 let (env, supertypes) =
1747 TUtils.get_concrete_supertypes ~abstract_enum:true env arg_ty
1749 let env =
1750 List.fold_left supertypes ~init:env ~f:(fun env ty ->
1751 SubType.add_constraint
1753 Ast_defs.Constraint_as
1754 hint_ty
1756 (Typing_error.Reasons_callback.unify_error_at p))
1758 Inter.intersect ~r env refined_ty arg_ty)
1760 let key_exists env pos shape field =
1761 let field = Tast.to_nast_expr field in
1762 refine_lvalue_type env shape ~refine:(fun env shape_ty ->
1763 match TUtils.shape_field_name env field with
1764 | None -> (env, shape_ty)
1765 | Some field_name ->
1766 let field_name = TShapeField.of_ast Pos_or_decl.of_raw_pos field_name in
1767 Typing_shapes.refine_shape field_name pos env shape_ty)
1769 (** Add a fresh type parameter to [env] with a name starting [prefix]
1770 and a constraint on [ty]. *)
1771 let synthesize_type_param env p prefix ty =
1772 let (env, name) = Env.fresh_param_name env prefix in
1773 let env = Env.add_upper_bound_global env name ty in
1774 let env = Env.add_lower_bound_global env name ty in
1776 let hint = (p, Aast.Habstr (name, [])) in
1777 (hint, env)
1779 (** Transform calls to MyVisitor::makeTree with [f]. *)
1780 let rec rewrite_expr_tree_maketree env expr f =
1781 let (pos, p, expr_) = expr in
1782 let (env, expr_) =
1783 match expr_ with
1784 | Call
1785 ( (fun_pos, p, (Lfun (fun_, idl) | Efun (fun_, idl))),
1786 targs,
1787 args,
1788 variadic ) ->
1789 (* Express tree literals containing splices use an anonymous
1790 function that returns the makeTree call.
1792 (function() {
1793 $0splice1 = "whatever";
1794 return MyVisitor::makeTree(...);
1795 })()
1797 let map_stmt env s =
1798 match s with
1799 | (pos, Return (Some expr)) ->
1800 let (env, expr) = rewrite_expr_tree_maketree env expr f in
1801 (env, (pos, Return (Some expr)))
1802 | _ -> (env, s)
1805 let (env, body_ast) = List.map_env env fun_.f_body.fb_ast ~f:map_stmt in
1806 let fun_ = { fun_ with f_body = { fb_ast = body_ast } } in
1808 (env, Call ((fun_pos, p, Lfun (fun_, idl)), targs, args, variadic))
1809 | Call _ ->
1810 (* The desugarer might give us a simple call to makeTree, so we
1811 can process it immediately. *)
1812 f env expr_
1813 | _ -> (env, expr_)
1815 (env, (pos, p, expr_))
1817 (** Given [expr], a runtime expression for an expression tree, add a
1818 type parameter to the makeTree call.
1820 This enables expression tree visitors to use phantom type
1821 parameters. The visitor can be defined with __Explicit.
1823 public static function makeTree<<<__Explicit>> TInfer>(...) { ... }
1825 Userland calls to this method must provide an explicit type.
1827 MyVisitor::makeTree<MyVisitorInt>(...);
1829 For expression tree literals, we run type inference and provide a
1830 synthesized type parameter to the desugared runtime expression.
1832 MyVisitor`1`; // we infer MyVisitorInt
1833 // we add this constrained type parameter:
1834 MyVisitor::makeTree<TInfer#1>(...) where TInfer#1 = MyVisitorInt
1837 let maketree_with_type_param env p expr expected_ty =
1838 let (hint_virtual, env) = synthesize_type_param env p "TInfer" expected_ty in
1839 let rewrite_expr env expr =
1840 match expr with
1841 | Call (e, _, el, unpacked_element) ->
1842 (env, Call (e, [((), hint_virtual)], el, unpacked_element))
1843 | e -> (env, e)
1846 rewrite_expr_tree_maketree env expr rewrite_expr
1848 module EnumClassLabelOps = struct
1849 type result =
1850 | Success of Tast.expr * locl_ty
1851 | ClassNotFound
1852 | LabelNotFound of Tast.expr * locl_ty
1853 | Invalid
1854 | Skip
1856 (** Given an [enum_name] and an [label], tries to see if
1857 [enum_name] has a constant named [label].
1858 In such case, creates the expected typed expression.
1860 If [label] is not there, it will register and error.
1862 [ctor] is either `MemberOf` or `Label`
1863 [full] describe if the original expression was a full
1864 label, as in E#A, or a short version, as in #A
1866 let expand pos env ~full ~ctor enum_name label_name =
1867 let cls = Env.get_class env enum_name in
1868 match cls with
1869 | Some cls ->
1870 (match Env.get_const env cls label_name with
1871 | Some const_def ->
1872 let dty = const_def.cc_type in
1873 (* the enum constant has type MemberOf<X, Y>. If we are
1874 * processing a Label argument, we just switch MemberOf for
1875 * Label.
1877 let dty =
1878 match deref dty with
1879 | (r, Tapply ((p, _), args)) -> mk (r, Tapply ((p, ctor), args))
1880 | _ -> dty
1882 let (env, lty) = Phase.localize_no_subst env ~ignore_errors:true dty in
1883 let hi = lty in
1884 let qualifier =
1885 if full then
1886 Some (pos, enum_name)
1887 else
1888 None
1890 let te = (hi, pos, EnumClassLabel (qualifier, label_name)) in
1891 (env, Success (te, lty))
1892 | None ->
1893 Errors.add_typing_error
1894 Typing_error.(
1895 enum
1896 @@ Primary.Enum.Enum_class_label_unknown
1897 { pos; label_name; class_name = enum_name });
1898 let r = Reason.Rwitness pos in
1899 let ty = Typing_utils.terr env r in
1900 let te = (ty, pos, EnumClassLabel (None, label_name)) in
1901 (env, LabelNotFound (te, ty)))
1902 | None -> (env, ClassNotFound)
1905 let is_lvalue = function
1906 | `lvalue -> true
1907 | _ -> false
1909 (* Given a localized parameter type and parameter information, infer
1910 * a type for the parameter default expression (if present) and check that
1911 * it is a subtype of the parameter type (if present). If no parameter type
1912 * is specified, then union with Tany. (So it's as though we did a conditional
1913 * assignment of the default expression to the parameter).
1914 * Set the type of the parameter in the locals environment *)
1915 let rec bind_param
1916 env ?(immutable = false) ?(can_read_globals = false) (ty1, param) =
1917 let (env, param_te, ty1) =
1918 match param.param_expr with
1919 | None -> (env, None, ty1)
1920 | Some e ->
1921 let decl_hint =
1922 Option.map
1923 ~f:(Decl_hint.hint env.decl_env)
1924 (hint_of_type_hint param.param_type_hint)
1926 let enforced =
1927 match decl_hint with
1928 | None -> Unenforced
1929 | Some ty -> Typing_enforceability.get_enforcement env ty
1931 let ty1_enforced = { et_type = ty1; et_enforced = enforced } in
1932 let expected =
1933 ExpectedTy.make_and_allow_coercion_opt
1935 param.param_pos
1936 Reason.URparam
1937 ty1_enforced
1939 let (env, (te, ty2)) =
1940 let reason = Reason.Rwitness param.param_pos in
1941 let pure = MakeType.mixed reason in
1942 let cap =
1943 if can_read_globals then
1944 MakeType.capability reason SN.Capabilities.accessGlobals
1945 else
1946 pure
1948 with_special_coeffects env cap pure @@ fun env ->
1949 expr ?expected env e ~allow_awaitable:(*?*) false |> triple_to_pair
1951 Typing_sequencing.sequence_check_expr e;
1952 let (env, ty1) =
1954 Option.is_none (hint_of_type_hint param.param_type_hint)
1955 && (not @@ TCO.global_inference (Env.get_tcopt env))
1956 (* ty1 will be Tany iff we have no type hint and we are not in
1957 * 'infer missing mode'. When it ty1 is Tany we just union it with
1958 * the type of the default expression *)
1959 then
1960 Union.union env ty1 ty2
1961 (* Otherwise we have an explicit type, and the default expression type
1962 * must be a subtype *)
1963 else
1964 let env =
1965 Typing_coercion.coerce_type
1966 param.param_pos
1967 Reason.URhint
1970 ty1_enforced
1971 Typing_error.Callback.parameter_default_value_wrong_type
1973 (env, ty1)
1975 (env, Some te, ty1)
1977 let (env, user_attributes) =
1978 attributes_check_def
1980 SN.AttributeKinds.parameter
1981 param.param_user_attributes
1983 let tparam =
1985 Aast.param_annotation = Tast.make_expr_annotation param.param_pos ty1;
1986 Aast.param_type_hint = (ty1, hint_of_type_hint param.param_type_hint);
1987 Aast.param_is_variadic = param.param_is_variadic;
1988 Aast.param_pos = param.param_pos;
1989 Aast.param_name = param.param_name;
1990 Aast.param_expr = param_te;
1991 Aast.param_callconv = param.param_callconv;
1992 Aast.param_readonly = param.param_readonly;
1993 Aast.param_user_attributes = user_attributes;
1994 Aast.param_visibility = param.param_visibility;
1997 let mode = get_param_mode param.param_callconv in
1998 let id = Local_id.make_unscoped param.param_name in
2000 let env = Env.set_local ~immutable env id ty1 param.param_pos in
2001 let env = Env.set_param env id (ty1, param.param_pos, mode) in
2002 let env =
2003 if has_accept_disposable_attribute param then
2004 Env.set_using_var env id
2005 else
2008 (env, tparam)
2010 (*****************************************************************************)
2011 (* function used to type closures, functions and methods *)
2012 (*****************************************************************************)
2013 and fun_ ?(abstract = false) ?(disable = false) env return pos named_body f_kind
2015 Env.with_env env (fun env ->
2016 debug_last_pos := pos;
2017 let env = Env.set_return env return in
2018 let (env, tb) =
2019 if disable then
2020 let () =
2021 Errors.internal_error
2023 ("Type inference for this function has been disabled by the "
2024 ^ SN.UserAttributes.uaDisableTypecheckerInternal
2025 ^ " attribute")
2027 block env []
2028 else
2029 block env named_body.fb_ast
2031 Typing_sequencing.sequence_check_block named_body.fb_ast;
2032 let { Typing_env_return_info.return_type = ret; _ } =
2033 Env.get_return env
2035 let has_implicit_return = LEnv.has_next env in
2036 let has_readonly = Env.get_readonly env in
2037 let env =
2038 if (not has_implicit_return) || abstract || Env.is_hhi env then
2040 else
2041 Typing_return.fun_implicit_return env pos ret.et_type f_kind
2043 let env =
2044 Typing_env.set_fun_tast_info
2046 Tast.{ has_implicit_return; has_readonly }
2048 debug_last_pos := Pos.none;
2049 (env, tb))
2051 and block env stl =
2052 Typing_env.with_origin env Decl_counters.Body @@ fun env ->
2053 (* To insert an `AssertEnv`, `stmt` might return a `Block`. We eliminate it here
2054 to keep ASTs `Block`-free. *)
2055 let (env, stl) =
2056 List.fold ~init:(env, []) stl ~f:(fun (env, stl) st ->
2057 let (env, st) = stmt env st in
2058 (* Accumulate statements in reverse order *)
2059 let stl =
2060 match st with
2061 | (_, Aast.Block stl') -> List.rev stl' @ stl
2062 | _ -> st :: stl
2064 (env, stl))
2066 (env, List.rev stl)
2068 (* Ensure that `ty` is a subtype of IDisposable (for `using`) or
2069 * IAsyncDisposable (for `await using`)
2071 and has_dispose_method env has_await p e ty =
2072 let meth =
2073 if has_await then
2074 SN.Members.__disposeAsync
2075 else
2076 SN.Members.__dispose
2078 let (_, obj_pos, _) = e in
2079 let (env, (tfty, _tal)) =
2080 TOG.obj_get
2081 ~obj_pos
2082 ~is_method:true
2083 ~inst_meth:false
2084 ~meth_caller:false
2085 ~nullsafe:None
2086 ~coerce_from_ty:None
2087 ~explicit_targs:[]
2088 ~class_id:(CIexpr e)
2089 ~member_id:(p, meth)
2090 ~on_error:(Typing_error.Callback.using_error p ~has_await)
2094 let (env, (_tel, _typed_unpack_element, _ty, _should_forget_fakes)) =
2095 call ~expected:None p env tfty [] None
2099 (* Check an individual component in the expression `e` in the
2100 * `using (e) { ... }` statement.
2101 * This consists of either
2102 * a simple assignment `$x = e`, in which `$x` is the using variable, or
2103 * an arbitrary expression `e`, in which case a temporary is the using
2104 * variable, inaccessible in the source.
2105 * Return the typed expression and its type, and any variables that must
2106 * be designated as "using variables" for avoiding escapes.
2108 and check_using_expr has_await env ((_, pos, content) as using_clause) =
2109 match content with
2110 (* Simple assignment to local of form `$lvar = e` *)
2111 | Binop (Ast_defs.Eq None, (_, lvar_pos, Lvar lvar), e) ->
2112 let (env, te, ty) =
2113 expr ~is_using_clause:true env e ~allow_awaitable:(*?*) false
2115 let env = has_dispose_method env has_await pos e ty in
2116 let env = set_local ~is_using_clause:true env lvar ty in
2117 (* We are assigning a new value to the local variable, so we need to
2118 * generate a new expression id
2120 let env = Env.set_local_expr_id env (snd lvar) (Ident.tmp ()) in
2121 ( env,
2122 ( Tast.make_typed_expr
2125 (Aast.Binop
2126 ( Ast_defs.Eq None,
2127 Tast.make_typed_expr lvar_pos ty (Aast.Lvar lvar),
2128 te )),
2129 [snd lvar] ) )
2130 (* Arbitrary expression. This will be assigned to a temporary *)
2131 | _ ->
2132 let (env, typed_using_clause, ty) =
2133 expr ~is_using_clause:true env using_clause ~allow_awaitable:(*?*) false
2135 let env = has_dispose_method env has_await pos using_clause ty in
2136 (env, (typed_using_clause, []))
2138 (* Check the using clause e in
2139 * `using (e) { ... }` statement (`has_await = false`) or
2140 * `await using (e) { ... }` statement (`has_await = true`).
2141 * `using_clauses` is a list of expressions.
2142 * Return the typed expression, and any variables that must
2143 * be designated as "using variables" for avoiding escapes.
2145 and check_using_clause env has_await using_clauses =
2146 let (env, pairs) =
2147 List.map_env env using_clauses ~f:(check_using_expr has_await)
2149 let (typed_using_clauses, vars) = List.unzip pairs in
2150 (env, typed_using_clauses, List.concat vars)
2152 and stmt env (pos, st) =
2153 let (env, st) = stmt_ env pos st in
2154 Typing_debug.log_env_if_too_big pos env;
2155 (env, (pos, st))
2157 and stmt_ env pos st =
2158 let expr ?(allow_awaitable = (*?*) false) = expr ~allow_awaitable in
2159 let exprs = exprs ~allow_awaitable:(*?*) false in
2160 (* Type check a loop. f env = (env, result) checks the body of the loop.
2161 * We iterate over the loop until the "next" continuation environment is
2162 * stable. alias_depth is supposed to be an upper bound on this; but in
2163 * certain cases this fails (e.g. a generic type grows unboundedly). TODO:
2164 * fix this.
2166 let infer_loop env f =
2167 let in_loop_outer = env.in_loop in
2168 let alias_depth =
2169 if in_loop_outer then
2171 else
2172 Typing_alias.get_depth (pos, st)
2174 let env = { env with in_loop = true } in
2175 let rec loop env n =
2176 (* Remember the old environment *)
2177 let old_next_entry = Env.next_cont_opt env in
2178 let (env, result) = f env in
2179 let new_next_entry = Env.next_cont_opt env in
2180 (* Finish if we reach the bound, or if the environments match *)
2182 Int.equal n alias_depth
2183 || Typing_per_cont_ops.is_sub_opt_entry
2184 Typing_subtype.is_sub_type
2186 new_next_entry
2187 old_next_entry
2188 then
2189 let env = { env with in_loop = in_loop_outer } in
2190 (env, result)
2191 else
2192 loop env (n + 1)
2194 loop env 1
2196 let env = Env.open_tyvars env pos in
2197 (fun (env, tb) -> (Typing_solver.close_tyvars_and_solve env, tb))
2199 match st with
2200 | Fallthrough ->
2201 let env = LEnv.move_and_merge_next_in_cont env C.Fallthrough in
2202 (env, Aast.Fallthrough)
2203 | Noop -> (env, Aast.Noop)
2204 | AssertEnv _ -> (env, Aast.Noop)
2205 | Yield_break ->
2206 let env = LEnv.move_and_merge_next_in_cont env C.Exit in
2207 (env, Aast.Yield_break)
2208 | Expr e ->
2209 let (env, te, _) = expr env e in
2210 let env =
2211 if TFTerm.typed_expression_exits te then
2212 LEnv.move_and_merge_next_in_cont env C.Exit
2213 else
2216 (env, Aast.Expr te)
2217 | If (e, b1, b2) ->
2218 let assert_refinement_env =
2219 assert_env_blk ~pos ~at:`Start Aast.Refinement
2221 let (env, te, _) = expr env e in
2222 let (env, tb1, tb2) =
2223 branch
2225 (fun env ->
2226 let (env, lset) = condition env true te in
2227 let refinement_map = refinement_annot_map env lset in
2228 let (env, b1) = block env b1 in
2229 let b1 = assert_refinement_env refinement_map b1 in
2230 (env, b1))
2231 (fun env ->
2232 let (env, lset) = condition env false te in
2233 let refinement_map = refinement_annot_map env lset in
2234 let (env, b2) = block env b2 in
2235 let b2 = assert_refinement_env refinement_map b2 in
2236 (env, b2))
2238 (* TODO TAST: annotate with joined types *)
2239 (env, Aast.If (te, tb1, tb2))
2240 | Return None ->
2241 let env = Typing_return.check_inout_return pos env in
2242 let rty = MakeType.void (Reason.Rwitness pos) in
2243 let { Typing_env_return_info.return_type = expected_return; _ } =
2244 Env.get_return env
2246 let expected_return =
2247 Typing_return.strip_awaitable (Env.get_fn_kind env) env expected_return
2249 let env =
2250 match Env.get_fn_kind env with
2251 | Ast_defs.FGenerator
2252 | Ast_defs.FAsyncGenerator ->
2254 | _ ->
2255 Typing_return.implicit_return
2258 ~expected:expected_return.et_type
2259 ~actual:rty
2261 let env = LEnv.move_and_merge_next_in_cont env C.Exit in
2262 (env, Aast.Return None)
2263 | Return (Some e) ->
2264 let env = Typing_return.check_inout_return pos env in
2265 let (_, expr_pos, _) = e in
2266 let Typing_env_return_info.
2268 return_type;
2269 return_disposable;
2270 return_explicit;
2271 return_dynamically_callable = _;
2273 Env.get_return env
2275 let return_type =
2276 Typing_return.strip_awaitable (Env.get_fn_kind env) env return_type
2278 let expected =
2279 if return_explicit then
2280 Some
2281 (ExpectedTy.make_and_allow_coercion
2282 expr_pos
2283 Reason.URreturn
2284 return_type)
2285 else
2286 None
2288 if return_disposable then enforce_return_disposable env e;
2289 let (env, te, rty) =
2290 expr ~is_using_clause:return_disposable ?expected env e
2292 (* This is a unify_error rather than a return_type_mismatch because the return
2293 * statement is the problem, not the return type itself. *)
2294 let (env, err_opt) =
2295 Result.fold
2296 ~ok:(fun env -> (env, None))
2297 ~error:(fun env -> (env, Some (rty, return_type.et_type)))
2298 @@ Typing_coercion.coerce_type_res
2299 expr_pos
2300 Reason.URreturn
2303 return_type
2304 Typing_error.Callback.unify_error
2306 let env = LEnv.move_and_merge_next_in_cont env C.Exit in
2307 (env, Aast.Return (Some (hole_on_err ~err_opt te)))
2308 | Do (b, e) ->
2309 (* NOTE: leaks scope as currently implemented; this matches
2310 the behavior in naming (cf. `do_stmt` in naming/naming.ml).
2312 let (env, (tb, te)) =
2313 LEnv.stash_and_do env [C.Continue; C.Break; C.Do] (fun env ->
2314 let env = LEnv.save_and_merge_next_in_cont env C.Do in
2315 let (env, _) = block env b in
2316 (* saving the locals in continue here even if there is no continue
2317 * statement because they must be merged at the end of the loop, in
2318 * case there is no iteration *)
2319 let env = LEnv.save_and_merge_next_in_cont env C.Continue in
2320 let (env, tb) =
2321 infer_loop env (fun env ->
2322 let env =
2323 LEnv.update_next_from_conts env [C.Continue; C.Next]
2325 (* The following is necessary in case there is an assignment in the
2326 * expression *)
2327 let (env, te, _) = expr env e in
2328 let (env, _lset) = condition env true te in
2329 let env = LEnv.update_next_from_conts env [C.Do; C.Next] in
2330 let (env, tb) = block env b in
2331 (env, tb))
2333 let env = LEnv.update_next_from_conts env [C.Continue; C.Next] in
2334 let (env, te, _) = expr env e in
2335 let (env, _lset) = condition env false te in
2336 let env = LEnv.update_next_from_conts env [C.Break; C.Next] in
2337 (env, (tb, te)))
2339 (env, Aast.Do (tb, te))
2340 | While (e, b) ->
2341 let (env, (te, tb, refinement_map)) =
2342 LEnv.stash_and_do env [C.Continue; C.Break] (fun env ->
2343 let env = LEnv.save_and_merge_next_in_cont env C.Continue in
2344 let (env, tb) =
2345 infer_loop env (fun env ->
2346 let env =
2347 LEnv.update_next_from_conts env [C.Continue; C.Next]
2349 let join_map = annot_map env in
2350 (* The following is necessary in case there is an assignment in the
2351 * expression *)
2352 let (env, te, _) = expr env e in
2353 let (env, lset) = condition env true te in
2354 let refinement_map = refinement_annot_map env lset in
2355 (* TODO TAST: avoid repeated generation of block *)
2356 let (env, tb) = block env b in
2358 (* Annotate loop body with join and refined environments *)
2359 let assert_env_blk = assert_env_blk ~pos ~at:`Start in
2360 let tb = assert_env_blk Aast.Refinement refinement_map tb in
2361 let tb = assert_env_blk Aast.Join join_map tb in
2363 (env, tb))
2365 let env = LEnv.update_next_from_conts env [C.Continue; C.Next] in
2366 let (env, te, _) = expr env e in
2367 let (env, lset) = condition env false te in
2368 let refinement_map_at_exit = refinement_annot_map env lset in
2369 let env = LEnv.update_next_from_conts env [C.Break; C.Next] in
2370 (env, (te, tb, refinement_map_at_exit)))
2372 let while_st = Aast.While (te, tb) in
2373 (* Export the refined environment after the exit condition holds *)
2374 let while_st =
2375 assert_env_stmt ~pos ~at:`End Aast.Refinement refinement_map while_st
2377 (env, while_st)
2378 | Using
2380 us_has_await = has_await;
2381 us_exprs = (loc, using_clause);
2382 us_block = using_block;
2383 us_is_block_scoped;
2384 } ->
2385 let (env, typed_using_clause, using_vars) =
2386 check_using_clause env has_await using_clause
2388 let (env, typed_using_block) = block env using_block in
2389 (* Remove any using variables from the environment, as they should not
2390 * be in scope outside the block *)
2391 let env = List.fold_left using_vars ~init:env ~f:Env.unset_local in
2392 ( env,
2393 Aast.Using
2394 Aast.
2396 us_has_await = has_await;
2397 us_exprs = (loc, typed_using_clause);
2398 us_block = typed_using_block;
2399 us_is_block_scoped;
2401 | For (e1, e2, e3, b) ->
2402 let e2 =
2403 match e2 with
2404 | Some e2 -> e2
2405 | None -> ((), Pos.none, True)
2407 let (env, (te1, te2, te3, tb, refinement_map)) =
2408 LEnv.stash_and_do env [C.Continue; C.Break] (fun env ->
2409 (* For loops leak their initalizer, but nothing that's defined in the
2410 body
2412 let (env, te1, _) = exprs env e1 in
2413 (* initializer *)
2414 let env = LEnv.save_and_merge_next_in_cont env C.Continue in
2415 let (env, (tb, te3)) =
2416 infer_loop env (fun env ->
2417 (* The following is necessary in case there is an assignment in the
2418 * expression *)
2419 let (env, te2, _) = expr env e2 in
2420 let (env, lset) = condition env true te2 in
2421 let refinement_map = refinement_annot_map env lset in
2422 let (env, tb) = block env b in
2423 let env =
2424 LEnv.update_next_from_conts env [C.Continue; C.Next]
2426 let join_map = annot_map env in
2427 let (env, te3, _) = exprs env e3 in
2429 (* Export the join and refinement environments *)
2430 let assert_env_blk = assert_env_blk ~pos ~at:`Start in
2431 let tb = assert_env_blk Aast.Refinement refinement_map tb in
2432 let tb = assert_env_blk Aast.Join join_map tb in
2434 (env, (tb, te3)))
2436 let env = LEnv.update_next_from_conts env [C.Continue; C.Next] in
2437 let (env, te2, _) = expr env e2 in
2438 let (env, lset) = condition env false te2 in
2439 let refinement_map_at_exit = refinement_annot_map env lset in
2440 let env = LEnv.update_next_from_conts env [C.Break; C.Next] in
2441 (env, (te1, te2, te3, tb, refinement_map_at_exit)))
2443 let for_st = Aast.For (te1, Some te2, te3, tb) in
2444 let for_st =
2445 assert_env_stmt ~pos ~at:`End Aast.Refinement refinement_map for_st
2447 (env, for_st)
2448 | Switch (((_, pos, _) as e), cl, dfl) ->
2449 let (env, te, ty) = expr env e in
2450 (* NB: A 'continue' inside a 'switch' block is equivalent to a 'break'.
2451 * See the note in
2452 * http://php.net/manual/en/control-structures.continue.php *)
2453 let (env, (te, tcl, tdfl)) =
2454 LEnv.stash_and_do env [C.Continue; C.Break] (fun env ->
2455 let parent_locals = LEnv.get_all_locals env in
2456 let (env, tcl, tdfl) = case_list parent_locals ty env pos cl dfl in
2457 let env =
2458 LEnv.update_next_from_conts env [C.Continue; C.Break; C.Next]
2460 (env, (te, tcl, tdfl)))
2462 (env, Aast.Switch (te, tcl, tdfl))
2463 | Foreach (e1, e2, b) ->
2464 (* It's safe to do foreach over a disposable, as no leaking is possible *)
2465 let (env, te1, ty1) = expr ~accept_using_var:true env e1 in
2466 let (env, (te1, te2, tb)) =
2467 LEnv.stash_and_do env [C.Continue; C.Break] (fun env ->
2468 let env = LEnv.save_and_merge_next_in_cont env C.Continue in
2469 let (_, p1, _) = e1 in
2470 let (env, tk, tv, err_opt) = as_expr env ty1 p1 e2 in
2471 let (env, (te2, tb)) =
2472 infer_loop env (fun env ->
2473 let env =
2474 LEnv.update_next_from_conts env [C.Continue; C.Next]
2476 let join_map = annot_map env in
2477 let (env, te2) = bind_as_expr env p1 tk tv e2 in
2478 let (env, tb) = block env b in
2479 (* Export the join environment *)
2480 let tb = assert_env_blk ~pos ~at:`Start Aast.Join join_map tb in
2481 (env, (te2, tb)))
2483 let env =
2484 LEnv.update_next_from_conts env [C.Continue; C.Break; C.Next]
2486 (env, (hole_on_err ~err_opt te1, te2, tb)))
2488 (env, Aast.Foreach (te1, te2, tb))
2489 | Try (tb, cl, fb) ->
2490 let (env, ttb, tcl, tfb) = try_catch env tb cl fb in
2491 (env, Aast.Try (ttb, tcl, tfb))
2492 | Awaitall (el, b) ->
2493 let env = might_throw env in
2494 let (env, el) =
2495 List.fold_left el ~init:(env, []) ~f:(fun (env, tel) (e1, e2) ->
2496 let (env, te2, ty2) = expr env e2 ~allow_awaitable:true in
2497 let (_, pos2, _) = e2 in
2498 let (env, ty2) =
2499 Async.overload_extract_from_awaitable env ~p:pos2 ty2
2501 match e1 with
2502 | Some e1 ->
2503 let pos = fst e1 in
2504 let (env, _, _, err_opt) =
2505 assign pos env ((), pos, Lvar e1) pos2 ty2
2507 (env, (Some e1, hole_on_err ~err_opt te2) :: tel)
2508 | None -> (env, (None, te2) :: tel))
2510 let (env, b) = block env b in
2511 (env, Aast.Awaitall (el, b))
2512 | Throw e ->
2513 let (_, p, _) = e in
2514 let (env, te, ty) = expr env e in
2515 let env = coerce_to_throwable p env ty in
2516 let env = move_and_merge_next_in_catch env in
2517 (env, Aast.Throw te)
2518 | Continue ->
2519 let env = LEnv.move_and_merge_next_in_cont env C.Continue in
2520 (env, Aast.Continue)
2521 | Break ->
2522 let env = LEnv.move_and_merge_next_in_cont env C.Break in
2523 (env, Aast.Break)
2524 | Block _
2525 | Markup _ ->
2526 failwith
2527 "Unexpected nodes in AST. These nodes should have been removed in naming."
2529 and finally_cont fb env ctx =
2530 (* The only locals in scope are the ones from the current continuation *)
2531 let env = Env.env_with_locals env @@ CMap.singleton C.Next ctx in
2532 let (env, _tfb) = block env fb in
2533 (env, LEnv.get_all_locals env)
2535 and finally env fb =
2536 match fb with
2537 | [] ->
2538 let env = LEnv.update_next_from_conts env [C.Next; C.Finally] in
2539 (env, [])
2540 | _ ->
2541 let parent_locals = LEnv.get_all_locals env in
2542 (* First typecheck the finally block against all continuations merged
2543 * together.
2544 * During this phase, record errors found in the finally block, but discard
2545 * the resulting environment. *)
2546 let all_conts = Env.all_continuations env in
2547 let env = LEnv.update_next_from_conts env all_conts in
2548 let (env, tfb) = block env fb in
2549 let env = LEnv.restore_conts_from env parent_locals all_conts in
2550 (* Second, typecheck the finally block once against each continuation. This
2551 * helps be more clever about what each continuation will be after the
2552 * finally block.
2553 * We don't want to record errors during this phase, because certain types
2554 * of errors will fire wrongly. For example, if $x is nullable in some
2555 * continuations but not in others, then we must use `?->` on $x, but an
2556 * error will fire when typechecking the finally block againts continuations
2557 * where $x is non-null. *)
2558 let finally_cont env _key = finally_cont fb env in
2559 let (env, locals_map) =
2560 Errors.ignore_ (fun () -> CMap.map_env finally_cont env parent_locals)
2562 let union env _key = LEnv.union_contextopts env in
2563 let (env, locals) = Try.finally_merge union env locals_map all_conts in
2564 (Env.env_with_locals env locals, tfb)
2566 and try_catch env tb cl fb =
2567 let parent_locals = LEnv.get_all_locals env in
2568 let env =
2569 LEnv.drop_conts env [C.Break; C.Continue; C.Exit; C.Catch; C.Finally]
2571 let (env, (ttb, tcb)) =
2572 Env.in_try env (fun env ->
2573 let (env, ttb) = block env tb in
2574 let env = LEnv.move_and_merge_next_in_cont env C.Finally in
2575 let catchctx = LEnv.get_cont_option env C.Catch in
2576 let (env, lenvtcblist) = List.map_env env ~f:(catch catchctx) cl in
2577 let (lenvl, tcb) = List.unzip lenvtcblist in
2578 let env = LEnv.union_lenv_list env env.lenv lenvl in
2579 let env = LEnv.move_and_merge_next_in_cont env C.Finally in
2580 (env, (ttb, tcb)))
2582 let (env, tfb) = finally env fb in
2583 let env = LEnv.update_next_from_conts env [C.Finally] in
2584 let env = LEnv.drop_cont env C.Finally in
2585 let env =
2586 LEnv.restore_and_merge_conts_from
2588 parent_locals
2589 [C.Break; C.Continue; C.Exit; C.Catch; C.Finally]
2591 (env, ttb, tcb, tfb)
2593 and case_list parent_locals ty env switch_pos cl dfl =
2594 let initialize_next_cont env =
2595 let env = LEnv.restore_conts_from env parent_locals [C.Next] in
2596 let env = LEnv.update_next_from_conts env [C.Next; C.Fallthrough] in
2597 LEnv.drop_cont env C.Fallthrough
2599 let check_fallthrough env switch_pos case_pos block ~last ~is_default =
2600 if (not (List.is_empty block)) && not last then
2601 match LEnv.get_cont_option env C.Next with
2602 | Some _ ->
2603 Errors.add_nast_check_error
2605 if is_default then
2606 Nast_check_error.Default_fallthrough switch_pos
2607 else
2608 Nast_check_error.Case_fallthrough { switch_pos; case_pos }
2609 | None -> ()
2611 let env =
2612 (* below, we try to find out if the switch is exhaustive *)
2613 let has_default = Option.is_some dfl in
2614 let (env, ty) =
2615 (* If it hasn't got a default clause then we need to solve type variables
2616 * in order to check for an enum *)
2617 if has_default then
2618 Env.expand_type env ty
2619 else
2620 Typing_solver.expand_type_and_solve
2622 ~description_of_expected:"a value"
2623 switch_pos
2626 (* leverage that enums are checked for exhaustivity *)
2627 let is_enum =
2628 let top_type =
2629 MakeType.class_type
2630 Reason.Rnone
2631 SN.Classes.cHH_BuiltinEnum
2632 [MakeType.mixed Reason.Rnone]
2634 Typing_subtype.is_sub_type_for_coercion env ty top_type
2636 (* register that the runtime may throw in case we cannot prove
2637 that the switch is exhaustive *)
2638 if has_default || is_enum then
2640 else
2641 might_throw env
2643 let (env, tcl) =
2644 let rec case_list env = function
2645 | [] -> (env, [])
2646 | (((_, pos, _) as e), b) :: rl ->
2647 let env = initialize_next_cont env in
2648 let (env, te, _) = expr env e ~allow_awaitable:(*?*) false in
2649 let (env, tb) = block env b in
2650 let last = List.is_empty rl && Option.is_none dfl in
2651 check_fallthrough env switch_pos pos b ~last ~is_default:false;
2652 let (env, tcl) = case_list env rl in
2653 (env, (te, tb) :: tcl)
2655 case_list env cl
2657 let (env, tdfl) =
2658 match dfl with
2659 | None -> (env, None)
2660 | Some (pos, b) ->
2661 let env = initialize_next_cont env in
2662 let (env, tb) = block env b in
2663 check_fallthrough env switch_pos pos b ~last:true ~is_default:true;
2664 (env, Some (pos, tb))
2666 (env, tcl, tdfl)
2668 and catch catchctx env (sid, exn_lvar, b) =
2669 let env = LEnv.replace_cont env C.Next catchctx in
2670 let cid = CI sid in
2671 let ety_p = fst sid in
2672 let (env, _, _, _) = instantiable_cid ety_p env cid [] in
2673 let (env, _tal, _te, ety) = class_expr env [] ((), ety_p, cid) in
2674 let env = coerce_to_throwable ety_p env ety in
2675 let (p, x) = exn_lvar in
2676 let env = set_valid_rvalue p env x ety in
2677 let (env, tb) = block env b in
2678 (env, (env.lenv, (sid, exn_lvar, tb)))
2680 and bind_as_expr env p ty1 ty2 aexpr =
2681 match aexpr with
2682 | As_v ev ->
2683 let (env, te, _, _) = assign p env ev p ty2 in
2684 (env, Aast.As_v te)
2685 | Await_as_v (p, ev) ->
2686 let (env, te, _, _) = assign p env ev p ty2 in
2687 (env, Aast.Await_as_v (p, te))
2688 | As_kv ((_, p, Lvar ((_, k) as id)), ev) ->
2689 let env = set_valid_rvalue p env k ty1 in
2690 let (env, te, _, _) = assign p env ev p ty2 in
2691 let tk = Tast.make_typed_expr p ty1 (Aast.Lvar id) in
2692 (env, Aast.As_kv (tk, te))
2693 | Await_as_kv (p, (_, p1, Lvar ((_, k) as id)), ev) ->
2694 let env = set_valid_rvalue p env k ty1 in
2695 let (env, te, _, _) = assign p env ev p ty2 in
2696 let tk = Tast.make_typed_expr p1 ty1 (Aast.Lvar id) in
2697 (env, Aast.Await_as_kv (p, tk, te))
2698 | _ ->
2699 (* TODO Probably impossible, should check that *)
2700 assert false
2702 and expr
2703 ?(expected : ExpectedTy.t option)
2704 ?(accept_using_var = false)
2705 ?(is_using_clause = false)
2706 ?(in_readonly_expr = false)
2707 ?(valkind = `other)
2708 ?(check_defined = true)
2709 ?in_await
2710 ~allow_awaitable
2712 ((_, p, _) as e) =
2714 begin
2715 match expected with
2716 | None -> ()
2717 | Some ExpectedTy.{ reason = r; ty = { et_type = ty; _ }; _ } ->
2718 Typing_log.(
2719 log_with_level env "typing" ~level:1 (fun () ->
2720 log_types
2721 (Pos_or_decl.of_raw_pos p)
2724 Log_head
2725 ( "Typing.expr " ^ Typing_reason.string_of_ureason r,
2726 [Log_type ("expected_ty", ty)] );
2728 end;
2729 raw_expr
2730 ~accept_using_var
2731 ~is_using_clause
2732 ~in_readonly_expr
2733 ~valkind
2734 ~check_defined
2735 ?in_await
2736 ?expected
2737 ~allow_awaitable
2740 with
2741 | Inf.InconsistentTypeVarState _ as e ->
2742 (* we don't want to catch unwanted exceptions here, eg Timeouts *)
2743 Errors.add_typing_error
2744 Typing_error.(
2745 primary
2746 @@ Primary.Exception_occurred { pos = p; exn = Exception.wrap e });
2747 make_result env p (invalid_expr_ env p) @@ err_witness env p
2749 (* Some (legacy) special functions are allowed in initializers,
2750 therefore treat them as pure and insert the matching capabilities. *)
2751 and expr_with_pure_coeffects
2752 ?(expected : ExpectedTy.t option) ~allow_awaitable env e =
2753 let (_, p, _) = e in
2754 let pure = MakeType.mixed (Reason.Rwitness p) in
2755 let (env, (te, ty)) =
2756 with_special_coeffects env pure pure @@ fun env ->
2757 expr env e ?expected ~allow_awaitable |> triple_to_pair
2759 (env, te, ty)
2761 and raw_expr
2762 ?(accept_using_var = false)
2763 ?(is_using_clause = false)
2764 ?(in_readonly_expr = false)
2765 ?(expected : ExpectedTy.t option)
2766 ?lhs_of_null_coalesce
2767 ?(valkind = `other)
2768 ?(check_defined = true)
2769 ?in_await
2770 ~allow_awaitable
2773 let (_, p, _) = e in
2774 debug_last_pos := p;
2775 expr_
2776 ~accept_using_var
2777 ~is_using_clause
2778 ~in_readonly_expr
2779 ?expected
2780 ?lhs_of_null_coalesce
2781 ?in_await
2782 ~allow_awaitable
2783 ~valkind
2784 ~check_defined
2788 and lvalue env e =
2789 let valkind = `lvalue in
2790 expr_ ~valkind ~check_defined:false env e ~allow_awaitable:(*?*) false
2792 and lvalues env el =
2793 match el with
2794 | [] -> (env, [], [])
2795 | e :: el ->
2796 let (env, te, ty) = lvalue env e in
2797 let (env, tel, tyl) = lvalues env el in
2798 (env, te :: tel, ty :: tyl)
2800 (* $x ?? 0 is handled similarly to $x ?: 0, except that the latter will also
2801 * look for sketchy null checks in the condition. *)
2802 (* TODO TAST: type refinement should be made explicit in the typed AST *)
2803 and eif env ~(expected : ExpectedTy.t option) ?in_await p c e1 e2 =
2804 let condition = condition ~lhs_of_null_coalesce:false in
2805 let (env, tc, tyc) =
2806 raw_expr ~lhs_of_null_coalesce:false env c ~allow_awaitable:false
2808 let parent_lenv = env.lenv in
2809 let (env, _lset) = condition env true tc in
2810 let (env, te1, ty1) =
2811 match e1 with
2812 | None ->
2813 let (env, ty) =
2814 Typing_solver.non_null env (Pos_or_decl.of_raw_pos p) tyc
2816 (env, None, ty)
2817 | Some e1 ->
2818 let (env, te1, ty1) =
2819 expr ?expected ?in_await env e1 ~allow_awaitable:true
2821 (env, Some te1, ty1)
2823 let lenv1 = env.lenv in
2824 let env = { env with lenv = parent_lenv } in
2825 let (env, _lset) = condition env false tc in
2826 let (env, te2, ty2) = expr ?expected ?in_await env e2 ~allow_awaitable:true in
2827 let lenv2 = env.lenv in
2828 let env = LEnv.union_lenvs env parent_lenv lenv1 lenv2 in
2829 let (env, ty) = Union.union ~approx_cancel_neg:true env ty1 ty2 in
2830 make_result env p (Aast.Eif (tc, te1, te2)) ty
2832 and exprs
2833 ?(accept_using_var = false)
2834 ?(expected : ExpectedTy.t option)
2835 ?(valkind = `other)
2836 ?(check_defined = true)
2837 ~allow_awaitable
2839 el =
2840 match el with
2841 | [] -> (env, [], [])
2842 | e :: el ->
2843 let (env, te, ty) =
2844 expr
2845 ~accept_using_var
2846 ?expected
2847 ~valkind
2848 ~check_defined
2851 ~allow_awaitable
2853 let (env, tel, tyl) =
2854 exprs
2855 ~accept_using_var
2856 ?expected
2857 ~valkind
2858 ~check_defined
2861 ~allow_awaitable
2863 (env, te :: tel, ty :: tyl)
2865 and argument_list_exprs expr_cb env el =
2866 match el with
2867 | [] -> (env, [], [])
2868 | (pk, e) :: el ->
2869 let (env, te, ty) = expr_cb env e in
2870 let (env, tel, tyl) = argument_list_exprs expr_cb env el in
2871 (env, (pk, te) :: tel, ty :: tyl)
2873 and exprs_expected (pos, ur, expected_tyl) env el =
2874 match (el, expected_tyl) with
2875 | ([], _) -> (env, [], [])
2876 | (e :: el, expected_ty :: expected_tyl) ->
2877 let expected = ExpectedTy.make pos ur expected_ty in
2878 let (env, te, ty) = expr ~expected env e ~allow_awaitable:(*?*) false in
2879 let (env, tel, tyl) = exprs_expected (pos, ur, expected_tyl) env el in
2880 (env, te :: tel, ty :: tyl)
2881 | (el, []) -> exprs env el ~allow_awaitable:(*?*) false
2883 and expr_
2884 ?(expected : ExpectedTy.t option)
2885 ?(accept_using_var = false)
2886 ?(is_using_clause = false)
2887 ?(in_readonly_expr = false)
2888 ?lhs_of_null_coalesce
2889 ?in_await
2890 ~allow_awaitable
2891 ~(valkind : [> `lvalue | `lvalue_subexpr | `other ])
2892 ~check_defined
2894 ((_, p, e) as outer) =
2895 let env = Env.open_tyvars env p in
2896 (fun (env, te, ty) ->
2897 let env = Typing_solver.close_tyvars_and_solve env in
2898 (env, te, ty))
2900 let expr ?(allow_awaitable = allow_awaitable) =
2901 expr ~check_defined ~allow_awaitable
2903 let exprs = exprs ~check_defined ~allow_awaitable in
2904 let raw_expr ?(allow_awaitable = allow_awaitable) =
2905 raw_expr ~check_defined ~allow_awaitable
2908 * Given a list of types, computes their supertype. If any of the types are
2909 * unknown (e.g., comes from PHP), the supertype will be Typing_utils.tany env.
2910 * The optional coerce_for_op parameter controls whether any arguments of type
2911 * dynamic can be coerced to enforceable types because they are arguments to a
2912 * built-in operator.
2914 let compute_supertype
2915 ~(expected : ExpectedTy.t option)
2916 ~reason
2917 ~use_pos
2918 ?bound
2919 ?(coerce_for_op = false)
2920 ?(can_pessimise = false)
2923 tys =
2924 let (env, supertype) =
2925 match expected with
2926 | None ->
2927 let (env, supertype) = Env.fresh_type_reason env use_pos r in
2928 let error =
2929 Typing_error.(
2930 primary
2931 @@ Primary.Internal_error
2932 { pos = use_pos; msg = "Subtype of fresh type variable" })
2934 let env =
2935 match bound with
2936 | None -> env
2937 | Some ty ->
2938 (* There can't be an error because the type is fresh *)
2939 SubType.sub_type env supertype ty
2940 @@ Typing_error.Reasons_callback.always error
2942 (env, supertype)
2943 | Some ExpectedTy.{ ty = { et_type = ty; _ }; _ } -> (env, ty)
2945 match get_node supertype with
2946 (* No need to check individual subtypes if expected type is mixed or any! *)
2947 | Tany _ -> (env, supertype, List.map tys ~f:(fun _ -> None))
2948 | _ ->
2949 let (env, expected_supertype) =
2950 if coerce_for_op then
2951 ( env,
2952 Some
2953 (ExpectedTy.make_and_allow_coercion
2954 use_pos
2955 reason
2956 { et_type = supertype; et_enforced = Enforced }) )
2957 else
2958 let (env, pess_supertype) =
2959 if can_pessimise then
2960 Typing_array_access.maybe_pessimise_type env supertype
2961 else
2962 (env, supertype)
2964 (env, Some (ExpectedTy.make use_pos reason pess_supertype))
2966 let dyn_t = MakeType.dynamic (Reason.Rwitness use_pos) in
2967 let subtype_value env ty =
2968 let (env, ty) =
2969 if coerce_for_op && Typing_utils.is_sub_type_for_union env dyn_t ty
2970 then
2971 (* if we're coercing for a primop, and we're going to use the coercion
2972 (because the type of the arg is a supertype of dynamic), then we want
2973 to force the expected_supertype to the bound.
2975 match bound with
2976 | None -> (env, ty)
2977 | Some bound_ty ->
2978 Typing_union.union env ty (mk (get_reason ty, get_node bound_ty))
2979 else
2980 (env, ty)
2982 check_expected_ty_res
2983 ~coerce_for_op
2984 "Collection"
2987 expected_supertype
2989 let (env, rev_ty_err_opts) =
2990 List.fold_left tys ~init:(env, []) ~f:(fun (env, errs) ty ->
2991 Result.fold
2992 ~ok:(fun env -> (env, None :: errs))
2993 ~error:(fun env -> (env, Some (ty, supertype) :: errs))
2994 @@ subtype_value env ty)
2998 List.exists tys ~f:(fun ty ->
2999 equal_locl_ty_ (get_node ty) (Typing_utils.tany env))
3000 then
3001 (* If one of the values comes from PHP land, we have to be conservative
3002 * and consider that we don't know what the type of the values are. *)
3003 (env, Typing_utils.mk_tany env p, List.rev rev_ty_err_opts)
3004 else
3005 (env, supertype, List.rev rev_ty_err_opts)
3008 * Given a 'a list and a method to extract an expr and its ty from a 'a, this
3009 * function extracts a list of exprs from the list, and computes the supertype
3010 * of all of the expressions' tys.
3012 let compute_exprs_and_supertype
3013 ~(expected : ExpectedTy.t option)
3014 ?(reason = Reason.URarray_value)
3015 ?(can_pessimise = false)
3016 ~bound
3017 ~coerce_for_op
3018 ~use_pos
3022 extract_expr_and_ty =
3023 let (env, pess_expected) =
3024 if can_pessimise then
3025 match expected with
3026 | None -> (env, None)
3027 | Some ety ->
3028 let (env, ty) =
3029 Typing_array_access.maybe_pessimise_type
3031 ety.ExpectedTy.ty.et_type
3033 (env, Some ExpectedTy.(make ety.pos ety.reason ty))
3034 else
3035 (env, expected)
3037 let (env, exprs_and_tys) =
3038 List.map_env env l ~f:(extract_expr_and_ty ~expected:pess_expected)
3040 let (exprs, tys) = List.unzip exprs_and_tys in
3041 let (env, supertype, err_opts) =
3042 compute_supertype
3043 ~expected
3044 ~reason
3045 ~use_pos
3046 ?bound
3047 ~coerce_for_op
3048 ~can_pessimise
3053 ( env,
3054 List.map2_exn
3055 ~f:(fun te err_opt -> hole_on_err te ~err_opt)
3056 exprs
3057 err_opts,
3058 supertype )
3060 let check_collection_tparams env name tys =
3061 (* varrays and darrays are not classes but they share the same
3062 constraints with vec and dict respectively *)
3063 let name =
3064 if String.equal name SN.Typehints.varray then
3065 SN.Collections.cVec
3066 else if String.equal name SN.Typehints.darray then
3067 SN.Collections.cDict
3068 else
3069 name
3071 (* Class retrieval always succeeds because we're fetching a
3072 collection decl from an HHI file. *)
3073 match Env.get_class env name with
3074 | Some class_ ->
3075 let ety_env =
3077 (empty_expand_env_with_on_error
3078 (Env.invalid_type_hint_assert_primary_pos_in_current_decl env))
3079 with
3080 substs = TUtils.make_locl_subst_for_class_tparams class_ tys;
3083 Phase.check_tparams_constraints
3084 ~use_pos:p
3085 ~ety_env
3087 (Cls.tparams class_)
3088 | None ->
3089 let desc = "Missing collection decl during type parameter check"
3090 and telemetry =
3091 Telemetry.(create () |> string_ ~key:"class name" ~value:name)
3093 let err =
3094 Typing_error.(
3095 primary
3096 @@ Primary.Invariant_violation
3097 { pos = p; desc; telemetry; report_to_user = false })
3099 Errors.add_typing_error err;
3100 (* Continue typechecking without performing the check on a best effort
3101 basis. *)
3104 List.iter ~f:Errors.add_typing_error
3105 @@ Typing_type_wellformedness.expr env outer;
3106 match e with
3107 | Import _
3108 | Collection _ ->
3109 failwith "AST should not contain these nodes"
3110 | Hole (e, _, _, _) ->
3111 expr_
3112 ?expected
3113 ~accept_using_var
3114 ~is_using_clause
3115 ?lhs_of_null_coalesce
3116 ?in_await
3117 ~allow_awaitable
3118 ~valkind
3119 ~check_defined
3122 | Omitted ->
3123 let ty = Typing_utils.mk_tany env p in
3124 make_result env p Aast.Omitted ty
3125 | Varray (th, el)
3126 | ValCollection (_, th, el) ->
3127 let (get_expected_kind, name, subtype_val, coerce_for_op, make_expr, make_ty)
3129 match e with
3130 | ValCollection (kind, _, _) ->
3131 let class_name = Nast.vc_kind_to_name kind in
3132 let (subtype_val, coerce_for_op) =
3133 match kind with
3134 | Set
3135 | ImmSet
3136 | Keyset ->
3137 (arraykey_value ~add_hole:true p class_name true, true)
3138 | Vector
3139 | ImmVector
3140 | Vec ->
3141 (array_value, false)
3143 ( get_vc_inst env kind,
3144 class_name,
3145 subtype_val,
3146 coerce_for_op,
3147 (fun th elements -> Aast.ValCollection (kind, th, elements)),
3148 fun value_ty ->
3149 MakeType.class_type (Reason.Rwitness p) class_name [value_ty] )
3150 | Varray _ ->
3151 ( get_vc_inst env Vec,
3152 "varray",
3153 array_value,
3154 false,
3155 (fun th elements -> Aast.ValCollection (Vec, th, elements)),
3156 (fun value_ty -> MakeType.varray (Reason.Rwitness p) value_ty) )
3157 | _ ->
3158 (* The parent match makes this case impossible *)
3159 failwith "impossible match case"
3161 (* Use expected type to determine expected element type *)
3162 let (env, elem_expected, th) =
3163 match th with
3164 | Some (_, tv) ->
3165 let (env, tv, tv_expected) = localize_targ env tv in
3166 let env = check_collection_tparams env name [fst tv] in
3167 (env, Some tv_expected, Some tv)
3168 | _ ->
3169 begin
3170 match expand_expected_and_get_node env expected with
3171 | (env, Some (pos, ur, _, ety, _)) ->
3172 begin
3173 match get_expected_kind ety with
3174 | Some vty -> (env, Some (ExpectedTy.make pos ur vty), None)
3175 | None -> (env, None, None)
3177 | _ -> (env, None, None)
3180 let bound =
3181 (* TODO We ought to apply the bound even when not in sound dynamic mode,
3182 to avoid getting Set<dynamic> etc which are unsafe "nothing" factories. *)
3183 if coerce_for_op && TypecheckerOptions.enable_sound_dynamic env.genv.tcopt
3184 then
3185 Some
3186 (MakeType.arraykey
3187 (Reason.Rtype_variable_generics (p, "Tk", strip_ns name)))
3188 else
3189 None
3191 let (env, tel, elem_ty) =
3192 compute_exprs_and_supertype
3193 ~expected:elem_expected
3194 ~use_pos:p
3195 ~reason:Reason.URvector
3196 ~can_pessimise:true
3197 ~coerce_for_op
3198 ~bound
3199 (Reason.Rtype_variable_generics (p, "T", strip_ns name))
3202 subtype_val
3204 make_result env p (make_expr th tel) (make_ty elem_ty)
3205 | Darray (th, l)
3206 | KeyValCollection (_, th, l) ->
3207 let (get_expected_kind, name, make_expr, make_ty) =
3208 match e with
3209 | KeyValCollection (kind, _, _) ->
3210 let class_name = Nast.kvc_kind_to_name kind in
3211 ( get_kvc_inst env p kind,
3212 class_name,
3213 (fun th pairs -> Aast.KeyValCollection (kind, th, pairs)),
3214 (fun k v -> MakeType.class_type (Reason.Rwitness p) class_name [k; v])
3216 | Darray _ ->
3217 let name = "darray" in
3218 ( get_kvc_inst env p Dict,
3219 name,
3220 (fun th pairs -> Aast.KeyValCollection (Dict, th, pairs)),
3221 (fun k v -> MakeType.darray (Reason.Rwitness p) k v) )
3222 | _ ->
3223 (* The parent match makes this case impossible *)
3224 failwith "impossible match case"
3226 (* Use expected type to determine expected key and value types *)
3227 let (env, kexpected, vexpected, th) =
3228 match th with
3229 | Some ((_, tk), (_, tv)) ->
3230 let (env, tk, tk_expected) = localize_targ env tk in
3231 let (env, tv, tv_expected) = localize_targ env tv in
3232 let env = check_collection_tparams env name [fst tk; fst tv] in
3233 (env, Some tk_expected, Some tv_expected, Some (tk, tv))
3234 | _ ->
3235 (* no explicit typehint, fallback to supplied expect *)
3236 begin
3237 match expand_expected_and_get_node env expected with
3238 | (env, Some (pos, reason, _, ety, _)) ->
3239 begin
3240 match get_expected_kind ety with
3241 | Some (kty, vty) ->
3242 let k_expected = ExpectedTy.make pos reason kty in
3243 let v_expected = ExpectedTy.make pos reason vty in
3244 (env, Some k_expected, Some v_expected, None)
3245 | None -> (env, None, None, None)
3247 | _ -> (env, None, None, None)
3250 let (kl, vl) = List.unzip l in
3251 let r = Reason.Rtype_variable_generics (p, "Tk", strip_ns name) in
3252 let (env, tkl, k) =
3253 compute_exprs_and_supertype
3254 ~expected:kexpected
3255 ~use_pos:p
3256 ~reason:(Reason.URkey name)
3257 ~bound:(Some (MakeType.arraykey r))
3258 ~coerce_for_op:true
3262 (arraykey_value p name false)
3264 let (env, tvl, v) =
3265 compute_exprs_and_supertype
3266 ~expected:vexpected
3267 ~use_pos:p
3268 ~reason:(Reason.URvalue name)
3269 ~can_pessimise:true
3270 ~coerce_for_op:false
3271 ~bound:None
3272 (Reason.Rtype_variable_generics (p, "Tv", strip_ns name))
3275 array_value
3277 let pairs = List.zip_exn tkl tvl in
3278 make_result env p (make_expr th pairs) (make_ty k v)
3279 | Clone e ->
3280 let (env, te, ty) = expr env e in
3281 (* Clone only works on objects; anything else fatals at runtime.
3282 * Constructing a call `e`->__clone() checks that `e` is an object and
3283 * checks coeffects on __clone *)
3284 let (_, pe, _) = e in
3285 let (env, (tfty, _tal)) =
3286 TOG.obj_get
3287 ~obj_pos:pe
3288 ~is_method:true
3289 ~inst_meth:false
3290 ~meth_caller:false
3291 ~nullsafe:None
3292 ~coerce_from_ty:None
3293 ~explicit_targs:[]
3294 ~class_id:(CIexpr e)
3295 ~member_id:(p, SN.Members.__clone)
3296 ~on_error:Typing_error.Callback.unify_error
3300 let (env, (_tel, _typed_unpack_element, _ty, _should_forget_fakes)) =
3301 call ~expected:None p env tfty [] None
3303 make_result env p (Aast.Clone te) ty
3304 | This ->
3305 if Option.is_none (Env.get_self_ty env) then
3306 Errors.add_typing_error
3307 Typing_error.(primary @@ Primary.This_var_outside_class p);
3308 if Env.is_in_expr_tree env then
3309 Errors.add_typing_error
3310 Typing_error.(expr_tree @@ Primary.Expr_tree.This_var_in_expr_tree p);
3311 if not accept_using_var then check_escaping_var env (p, this);
3312 let ty = Env.get_local env this in
3313 let r = Reason.Rwitness p in
3314 let ty = mk (r, get_node ty) in
3315 make_result env p Aast.This ty
3316 | True -> make_result env p Aast.True (MakeType.bool (Reason.Rwitness p))
3317 | False -> make_result env p Aast.False (MakeType.bool (Reason.Rwitness p))
3318 (* TODO TAST: consider checking that the integer is in range. Right now
3319 * it's possible for HHVM to fail on well-typed Hack code
3321 | Int s -> make_result env p (Aast.Int s) (MakeType.int (Reason.Rwitness p))
3322 | Float s ->
3323 make_result env p (Aast.Float s) (MakeType.float (Reason.Rwitness p))
3324 (* TODO TAST: consider introducing a "null" type, and defining ?t to
3325 * be null | t
3327 | Null -> make_result env p Aast.Null (MakeType.null (Reason.Rwitness p))
3328 | String s ->
3329 make_result env p (Aast.String s) (MakeType.string (Reason.Rwitness p))
3330 | String2 idl ->
3331 let (env, tel) = string2 env idl in
3332 make_result env p (Aast.String2 tel) (MakeType.string (Reason.Rwitness p))
3333 | PrefixedString (n, e) ->
3334 if String.( <> ) n "re" then (
3335 Errors.experimental_feature
3337 "String prefixes other than `re` are not yet supported.";
3338 expr_error env Reason.Rnone outer
3339 ) else
3340 let (env, te, ty) = expr env e in
3341 let (_, pe, expr_) = e in
3342 let env = Typing_substring.sub_string pe env ty in
3343 (match expr_ with
3344 | String _ ->
3345 begin
3347 make_result
3350 (Aast.PrefixedString (n, te))
3351 (Typing_regex.type_pattern e)
3352 with
3353 | Pcre.Error (Pcre.BadPattern (s, i)) ->
3354 let reason = `bad_patt (s ^ " [" ^ string_of_int i ^ "]") in
3355 Errors.add_typing_error
3356 Typing_error.(
3357 primary @@ Primary.Bad_regex_pattern { pos = pe; reason });
3358 expr_error env (Reason.Rregex pe) e
3359 | Typing_regex.Empty_regex_pattern ->
3360 Errors.add_typing_error
3361 Typing_error.(
3362 primary
3363 @@ Primary.Bad_regex_pattern { pos = pe; reason = `empty_patt });
3364 expr_error env (Reason.Rregex pe) e
3365 | Typing_regex.Missing_delimiter ->
3366 Errors.add_typing_error
3367 Typing_error.(
3368 primary
3369 @@ Primary.Bad_regex_pattern
3370 { pos = pe; reason = `missing_delim });
3371 expr_error env (Reason.Rregex pe) e
3372 | Typing_regex.Invalid_global_option ->
3373 Errors.add_typing_error
3374 Typing_error.(
3375 primary
3376 @@ Primary.Bad_regex_pattern
3377 { pos = pe; reason = `invalid_option });
3378 expr_error env (Reason.Rregex pe) e
3380 | String2 _ ->
3381 Errors.add_typing_error
3382 Typing_error.(
3383 primary
3384 @@ Primary.Re_prefixed_non_string
3385 { pos = pe; reason = `embedded_expr });
3386 expr_error env (Reason.Rregex pe) e
3387 | _ ->
3388 Errors.add_typing_error
3389 Typing_error.(
3390 primary
3391 @@ Primary.Re_prefixed_non_string { pos = pe; reason = `non_string });
3392 expr_error env (Reason.Rregex pe) e)
3393 | Fun_id x ->
3394 let (env, fty, _tal) = fun_type_of_id env x [] [] in
3395 make_result env p (Aast.Fun_id x) fty
3396 | Id ((cst_pos, cst_name) as id) ->
3397 (match Env.get_gconst env cst_name with
3398 | None ->
3399 Errors.add_typing_error
3400 Typing_error.(primary @@ Primary.Unbound_global cst_pos);
3401 let ty = err_witness env cst_pos in
3402 make_result env cst_pos (Aast.Id id) ty
3403 | Some const ->
3404 let (env, ty) =
3405 Phase.localize_no_subst env ~ignore_errors:true const.cd_type
3407 make_result env p (Aast.Id id) ty)
3408 | Method_id (instance, meth) ->
3409 (* Method_id is used when creating a "method pointer" using the magic
3410 * inst_meth function.
3412 * Typing this is pretty simple, we just need to check that instance->meth
3413 * is public+not static and then return its type.
3415 let (env, te, ty1) = expr env instance in
3416 let (env, (result, _tal)) =
3417 TOG.obj_get
3418 ~inst_meth:true
3419 ~meth_caller:false
3420 ~obj_pos:p
3421 ~is_method:true
3422 ~nullsafe:None
3423 ~coerce_from_ty:None
3424 ~explicit_targs:[]
3425 ~class_id:(CIexpr instance)
3426 ~member_id:meth
3427 ~on_error:Typing_error.Callback.unify_error
3431 let (env, result) =
3432 Env.FakeMembers.check_instance_invalid env instance (snd meth) result
3434 make_result env p (Aast.Method_id (te, meth)) result
3435 | Method_caller (((pos, class_name) as pos_cname), meth_name) ->
3436 (* meth_caller('X', 'foo') desugars to:
3437 * $x ==> $x->foo()
3439 let class_ = Env.get_class env class_name in
3440 (match class_ with
3441 | None -> unbound_name env pos_cname outer
3442 | Some class_ ->
3443 (* Create a class type for the given object instantiated with unresolved
3444 * types for its type parameters.
3446 let () =
3447 if Ast_defs.is_c_trait (Cls.kind class_) then
3448 Errors.add_typing_error
3449 Typing_error.(
3450 primary
3451 @@ Primary.Meth_caller_trait { pos; trait_name = class_name })
3453 let (env, tvarl) =
3454 List.map_env env (Cls.tparams class_) ~f:(fun env _ ->
3455 Env.fresh_type env p)
3457 let params =
3458 List.map (Cls.tparams class_) ~f:(fun { tp_name = (p, n); _ } ->
3459 (* TODO(T69551141) handle type arguments for Tgeneric *)
3460 MakeType.generic (Reason.Rwitness_from_decl p) n)
3462 let obj_type =
3463 MakeType.apply
3464 (Reason.Rwitness_from_decl (Pos_or_decl.of_raw_pos p))
3465 (Positioned.of_raw_positioned pos_cname)
3466 params
3468 let ety_env =
3470 (empty_expand_env_with_on_error
3471 (Typing_error.Reasons_callback.invalid_type_hint pos))
3472 with
3473 substs = TUtils.make_locl_subst_for_class_tparams class_ tvarl;
3476 let (env, local_obj_ty) = Phase.localize ~ety_env env obj_type in
3477 let (env, (fty, _tal)) =
3478 TOG.obj_get
3479 ~obj_pos:pos
3480 ~is_method:true
3481 ~nullsafe:None
3482 ~inst_meth:false
3483 ~meth_caller:true
3484 ~coerce_from_ty:None
3485 ~explicit_targs:[]
3486 ~class_id:(CI (pos, class_name))
3487 ~member_id:meth_name
3488 ~on_error:Typing_error.Callback.unify_error
3490 local_obj_ty
3492 let (env, fty) = Env.expand_type env fty in
3493 (match deref fty with
3494 | (reason, Tfun ftype) ->
3495 (* We are creating a fake closure:
3496 * function(Class $x, arg_types_of(Class::meth_name))
3497 : return_type_of(Class::meth_name)
3499 let ety_env =
3501 ety_env with
3502 on_error = Env.unify_error_assert_primary_pos_in_current_decl env;
3505 let env =
3506 Phase.check_tparams_constraints
3507 ~use_pos:p
3508 ~ety_env
3510 (Cls.tparams class_)
3512 let local_obj_fp = TUtils.default_fun_param local_obj_ty in
3513 let fty = { ftype with ft_params = local_obj_fp :: ftype.ft_params } in
3514 let caller =
3516 ft_tparams = fty.ft_tparams;
3517 ft_where_constraints = fty.ft_where_constraints;
3518 ft_params = fty.ft_params;
3519 ft_implicit_params = fty.ft_implicit_params;
3520 ft_ret = fty.ft_ret;
3521 ft_flags = fty.ft_flags;
3522 ft_ifc_decl = fty.ft_ifc_decl;
3525 make_result
3528 (Aast.Method_caller (pos_cname, meth_name))
3529 (mk (reason, Tfun caller))
3530 | _ ->
3531 (* This can happen if the method lives in PHP *)
3532 make_result
3535 (Aast.Method_caller (pos_cname, meth_name))
3536 (Typing_utils.mk_tany env pos)))
3537 | FunctionPointer (FP_class_const (cid, meth), targs) ->
3538 let (env, _, ce, cty) = class_expr env [] cid in
3539 let (env, (fpty, tal)) =
3540 class_get
3541 ~is_method:true
3542 ~is_const:false
3543 ~incl_tc:false (* What is this? *)
3544 ~coerce_from_ty:None (* What is this? *)
3545 ~explicit_targs:targs
3546 ~is_function_pointer:true
3549 meth
3552 let env = Env.set_tyvar_variance env fpty in
3553 let fpty = set_function_pointer fpty in
3554 (* All function pointers are readonly_this since they are either toplevel or static *)
3555 let fpty = set_readonly_this fpty in
3556 make_result
3559 (Aast.FunctionPointer (FP_class_const (ce, meth), tal))
3560 fpty
3561 | Smethod_id (((_, pc, cid_) as cid), meth) ->
3562 (* Smethod_id is used when creating a "method pointer" using the magic
3563 * class_meth function.
3565 * Typing this is pretty simple, we just need to check that c::meth is
3566 * public+static and then return its type.
3568 let (class_, classname) =
3569 match cid_ with
3570 | CIself
3571 | CIstatic ->
3572 (Env.get_self_class env, Env.get_self_id env)
3573 | CI (_, const) when String.equal const SN.PseudoConsts.g__CLASS__ ->
3574 (Env.get_self_class env, Env.get_self_id env)
3575 | CI (_, id) -> (Env.get_class env id, Some id)
3576 | _ -> (None, None)
3578 let classname = Option.value classname ~default:"" in
3579 (match class_ with
3580 | None ->
3581 (* The class given as a static string was not found. *)
3582 unbound_name env (pc, classname) outer
3583 | Some class_ ->
3584 let smethod = Env.get_static_member true env class_ (snd meth) in
3585 (match smethod with
3586 | None ->
3587 (* The static method wasn't found. *)
3588 Errors.add_typing_error
3589 @@ TOG.smember_not_found
3590 (fst meth)
3591 ~is_const:false
3592 ~is_method:true
3593 ~is_function_pointer:false
3594 class_
3595 (snd meth)
3596 Typing_error.Callback.unify_error;
3597 expr_error env Reason.Rnone outer
3598 | Some ({ ce_type = (lazy ty); ce_pos = (lazy ce_pos); _ } as ce) ->
3599 let () =
3600 if get_ce_abstract ce then
3601 match cid_ with
3602 | CIstatic -> ()
3603 | _ ->
3604 Errors.add_typing_error
3605 Typing_error.(
3606 primary
3607 @@ Primary.Class_meth_abstract_call
3609 class_name = classname;
3610 meth_name = snd meth;
3611 pos = p;
3612 decl_pos = ce_pos;
3615 let ce_visibility = ce.ce_visibility in
3616 let ce_deprecated = ce.ce_deprecated in
3617 let (env, _tal, te, cid_ty) = class_expr ~exact:Exact env [] cid in
3618 let (env, cid_ty) = Env.expand_type env cid_ty in
3619 let tyargs =
3620 match get_node cid_ty with
3621 | Tclass (_, _, tyargs) -> tyargs
3622 | _ -> []
3624 let ety_env =
3626 empty_expand_env with
3627 substs = TUtils.make_locl_subst_for_class_tparams class_ tyargs;
3628 this_ty = cid_ty;
3631 let r = get_reason ty |> Typing_reason.localize in
3632 (match get_node ty with
3633 | Tfun ft ->
3634 let ft =
3635 Typing_enforceability.compute_enforced_and_pessimize_fun_type env ft
3637 let def_pos = ce_pos in
3638 let (env, tal) =
3639 Phase.localize_targs
3640 ~check_well_kinded:true
3641 ~is_method:true
3642 ~def_pos:ce_pos
3643 ~use_pos:p
3644 ~use_name:(strip_ns (snd meth))
3646 ft.ft_tparams
3649 let (env, ft) =
3650 Phase.(
3651 localize_ft
3652 ~instantiation:
3653 Phase.
3655 use_name = strip_ns (snd meth);
3656 use_pos = p;
3657 explicit_targs = tal;
3659 ~ety_env
3660 ~def_pos:ce_pos
3664 let ty = mk (r, Tfun ft) in
3665 let use_pos = fst meth in
3666 Option.iter
3667 ~f:Errors.add_typing_error
3668 (TVis.check_deprecated ~use_pos ~def_pos ce_deprecated);
3669 (match ce_visibility with
3670 | Vpublic
3671 | Vinternal _ ->
3672 make_result env p (Aast.Smethod_id (te, meth)) ty
3673 | Vprivate _ ->
3674 Errors.add_typing_error
3675 Typing_error.(
3676 primary
3677 @@ Primary.Private_class_meth
3678 { decl_pos = def_pos; pos = use_pos });
3679 expr_error env r outer
3680 | Vprotected _ ->
3681 Errors.add_typing_error
3682 Typing_error.(
3683 primary
3684 @@ Primary.Protected_class_meth
3685 { decl_pos = def_pos; pos = use_pos });
3686 expr_error env r outer)
3687 | _ ->
3688 Errors.internal_error p "We have a method which isn't callable";
3689 expr_error env r outer)))
3690 | Lplaceholder p ->
3691 let r = Reason.Rplaceholder p in
3692 let ty = MakeType.void r in
3693 make_result env p (Aast.Lplaceholder p) ty
3694 | Dollardollar _ when is_lvalue valkind ->
3695 Errors.add_typing_error
3696 Typing_error.(
3697 wellformedness @@ Primary.Wellformedness.Dollardollar_lvalue p);
3698 expr_error env (Reason.Rwitness p) outer
3699 | Dollardollar id ->
3700 let ty = Env.get_local_check_defined env id in
3701 let env = might_throw env in
3702 make_result env p (Aast.Dollardollar id) ty
3703 | Lvar ((_, x) as id) ->
3704 if not accept_using_var then check_escaping_var env id;
3705 let ty =
3706 if check_defined then
3707 Env.get_local_check_defined env id
3708 else
3709 Env.get_local env x
3711 make_result env p (Aast.Lvar id) ty
3712 | Tuple el ->
3713 let (env, expected) = expand_expected_and_get_node env expected in
3714 let (env, tel, tyl) =
3715 match expected with
3716 | Some (pos, ur, _, _, Ttuple expected_tyl) ->
3717 let (env, pess_expected_tyl) =
3718 if TypecheckerOptions.pessimise_builtins (Env.get_tcopt env) then
3719 List.map_env env expected_tyl ~f:Typing_array_access.pessimise_type
3720 else
3721 (env, expected_tyl)
3723 exprs_expected (pos, ur, pess_expected_tyl) env el
3724 | _ -> exprs env el
3726 let (env, pess_tyl) =
3727 if TypecheckerOptions.pessimise_builtins (Env.get_tcopt env) then
3728 List.map_env env tyl ~f:(Typing_array_access.pessimised_tup_assign p)
3729 else
3730 (env, tyl)
3732 let ty = MakeType.tuple (Reason.Rwitness p) pess_tyl in
3733 make_result env p (Aast.Tuple tel) ty
3734 | List el ->
3735 let (env, tel, tyl) =
3736 match valkind with
3737 | `lvalue
3738 | `lvalue_subexpr ->
3739 lvalues env el
3740 | `other ->
3741 let (env, expected) = expand_expected_and_get_node env expected in
3742 (match expected with
3743 | Some (pos, ur, _, _, Ttuple expected_tyl) ->
3744 exprs_expected (pos, ur, expected_tyl) env el
3745 | _ -> exprs env el)
3747 let ty = MakeType.tuple (Reason.Rwitness p) tyl in
3748 make_result env p (Aast.List tel) ty
3749 | Pair (th, e1, e2) ->
3750 let (env, expected1, expected2, th) =
3751 match th with
3752 | Some ((_, t1), (_, t2)) ->
3753 let (env, t1, t1_expected) = localize_targ env t1 in
3754 let (env, t2, t2_expected) = localize_targ env t2 in
3755 (env, Some t1_expected, Some t2_expected, Some (t1, t2))
3756 | None ->
3757 (* Use expected type to determine expected element types *)
3758 (match expand_expected_and_get_node env expected with
3759 | (env, Some (pos, reason, _, _ty, Tclass ((_, k), _, [ty1; ty2])))
3760 when String.equal k SN.Collections.cPair ->
3761 let ty1_expected = ExpectedTy.make pos reason ty1 in
3762 let ty2_expected = ExpectedTy.make pos reason ty2 in
3763 (env, Some ty1_expected, Some ty2_expected, None)
3764 | _ -> (env, None, None, None))
3766 let (env, te1, ty1) = expr ?expected:expected1 env e1 in
3767 let (env, te2, ty2) = expr ?expected:expected2 env e2 in
3768 let (_, p1, _) = e1 in
3769 let (_, p2, _) = e2 in
3770 let (env, ty1, err_opt1) =
3771 compute_supertype
3772 ~expected:expected1
3773 ~reason:Reason.URpair_value
3774 ~use_pos:p1
3775 (Reason.Rtype_variable_generics (p1, "T1", "Pair"))
3777 [ty1]
3779 let (env, ty2, err_opt2) =
3780 compute_supertype
3781 ~expected:expected2
3782 ~reason:Reason.URpair_value
3783 ~use_pos:p2
3784 (Reason.Rtype_variable_generics (p2, "T2", "Pair"))
3786 [ty2]
3788 let ty = MakeType.pair (Reason.Rwitness p) ty1 ty2 in
3789 make_result
3792 (Aast.Pair
3793 ( th,
3794 hole_on_err te1 ~err_opt:(Option.join @@ List.hd err_opt1),
3795 hole_on_err te2 ~err_opt:(Option.join @@ List.hd err_opt2) ))
3797 | Array_get (e, None) ->
3798 let (env, te, _) = update_array_type p env e valkind in
3799 let env = might_throw env in
3800 (* NAST check reports an error if [] is used for reading in an
3801 lvalue context. *)
3802 let ty = err_witness env p in
3803 make_result env p (Aast.Array_get (te, None)) ty
3804 | Array_get (e1, Some e2) ->
3805 let (env, te1, ty1) =
3806 update_array_type ?lhs_of_null_coalesce p env e1 valkind
3808 let (env, te2, ty2) = expr env e2 in
3809 let env = might_throw env in
3810 let is_lvalue = is_lvalue valkind in
3811 let (_, p1, _) = e1 in
3812 let (env, ty, arr_err_opt, key_err_opt) =
3813 Typing_array_access.array_get
3814 ~array_pos:p1
3815 ~expr_pos:p
3816 ?lhs_of_null_coalesce
3817 is_lvalue
3823 make_result
3826 (Aast.Array_get
3827 ( hole_on_err ~err_opt:arr_err_opt te1,
3828 Some (hole_on_err ~err_opt:key_err_opt te2) ))
3830 | Call ((_, pos_id, Id ((_, s) as id)), explicit_targs, el, None)
3831 when Hash_set.mem typing_env_pseudofunctions s ->
3832 let (env, tel, tys) =
3833 argument_list_exprs (expr ~accept_using_var:true) env el
3835 let env =
3836 if String.equal s SN.PseudoFunctions.hh_expect then
3837 do_hh_expect ~equivalent:false env pos_id explicit_targs p tys
3838 else if String.equal s SN.PseudoFunctions.hh_expect_equivalent then
3839 do_hh_expect ~equivalent:true env pos_id explicit_targs p tys
3840 else if not (List.is_empty explicit_targs) then (
3841 Errors.add_typing_error
3842 Typing_error.(
3843 primary
3844 @@ Primary.Expected_tparam
3845 { decl_pos = Pos_or_decl.none; pos = pos_id; n = 0 });
3847 ) else if String.equal s SN.PseudoFunctions.hh_show then (
3848 List.iter tys ~f:(Typing_log.hh_show p env);
3850 ) else if String.equal s SN.PseudoFunctions.hh_show_env then (
3851 Typing_log.hh_show_env p env;
3853 ) else if String.equal s SN.PseudoFunctions.hh_log_level then
3854 match el with
3856 (Ast_defs.Pnormal, (_, _, String key_str));
3857 (Ast_defs.Pnormal, (_, _, Int level_str));
3858 ] ->
3859 Env.set_log_level env key_str (int_of_string level_str)
3860 | _ -> env
3861 else if String.equal s SN.PseudoFunctions.hh_force_solve then
3862 Typing_solver.solve_all_unsolved_tyvars env
3863 else if String.equal s SN.PseudoFunctions.hh_loop_forever then
3864 let _ = loop_forever env in
3866 else
3869 let ty = MakeType.void (Reason.Rwitness p) in
3870 make_result
3873 (Aast.Call
3874 ( Tast.make_typed_expr pos_id (TUtils.mk_tany env pos_id) (Aast.Id id),
3876 tel,
3877 None ))
3879 | Call (e, explicit_targs, el, unpacked_element) ->
3880 let env = might_throw env in
3881 let ((env, te, ty), should_forget_fakes) =
3882 dispatch_call
3883 ~is_using_clause
3884 ~expected
3885 ~valkind
3886 ?in_await
3890 explicit_targs
3892 unpacked_element
3894 let env =
3895 if should_forget_fakes then
3896 Env.forget_members env Reason.(Blame (p, BScall))
3897 else
3900 (env, te, ty)
3901 | FunctionPointer (FP_id fid, targs) ->
3902 let (env, fty, targs) = fun_type_of_id env fid targs [] in
3903 let e = Aast.FunctionPointer (FP_id fid, targs) in
3904 let fty = set_function_pointer fty in
3905 (* All function pointers are readonly_this since they are always a toplevel function or static method *)
3906 let fty = set_readonly_this fty in
3907 make_result env p e fty
3908 | Binop (Ast_defs.QuestionQuestion, e1, e2) ->
3909 let (_, e1_pos, _) = e1 in
3910 let (_, e2_pos, _) = e2 in
3911 let (env, te1, ty1) =
3912 raw_expr ~lhs_of_null_coalesce:true env e1 ~allow_awaitable:true
3914 let (env, te2, ty2) = expr ?expected env e2 ~allow_awaitable:true in
3915 let (env, ty1') = Env.fresh_type env e1_pos in
3916 let env =
3917 SubType.sub_type
3920 (MakeType.nullable_locl Reason.Rnone ty1')
3921 (Typing_error.Reasons_callback.unify_error_at e1_pos)
3923 (* Essentially mimic a call to
3924 * function coalesce<Tr, Ta as Tr, Tb as Tr>(?Ta, Tb): Tr
3925 * That way we let the constraint solver take care of the union logic.
3927 let (env, ty_result) = Env.fresh_type env e2_pos in
3928 let env =
3929 SubType.sub_type
3931 ty1'
3932 ty_result
3933 (Typing_error.Reasons_callback.unify_error_at p)
3935 let env =
3936 SubType.sub_type
3939 ty_result
3940 (Typing_error.Reasons_callback.unify_error_at p)
3942 make_result
3945 (Aast.Binop (Ast_defs.QuestionQuestion, te1, te2))
3946 ty_result
3947 | Binop (Ast_defs.Eq op_opt, e1, e2) ->
3948 let make_result env p te ty =
3949 let (env, te, ty) = make_result env p te ty in
3950 let env = Typing_local_ops.check_assignment env te in
3951 (env, te, ty)
3953 (match op_opt with
3954 (* For example, e1 += e2. This is typed and translated as if
3955 * written e1 = e1 + e2.
3956 * TODO TAST: is this right? e1 will get evaluated more than once
3958 | Some op ->
3959 let (_, _, expr_) = e1 in
3960 (match (op, expr_) with
3961 | (Ast_defs.QuestionQuestion, Class_get _) ->
3962 Errors.experimental_feature
3964 "null coalesce assignment operator with static properties";
3965 expr_error env Reason.Rnone outer
3966 | _ ->
3967 let e_fake =
3968 ((), p, Binop (Ast_defs.Eq None, e1, ((), p, Binop (op, e1, e2))))
3970 let (env, te_fake, ty) = raw_expr env e_fake in
3971 let te_opt = resugar_binop te_fake in
3972 begin
3973 match te_opt with
3974 | Some (_, _, te) -> make_result env p te ty
3975 | _ -> assert false
3976 end)
3977 | None ->
3978 let (env, te2, ty2) = raw_expr env e2 in
3979 let (_, pos2, _) = te2 in
3980 let (env, te1, ty, err_opt) = assign p env e1 pos2 ty2 in
3981 let te = Aast.Binop (Ast_defs.Eq None, te1, hole_on_err ~err_opt te2) in
3982 make_result env p te ty)
3983 | Binop (((Ast_defs.Ampamp | Ast_defs.Barbar) as bop), e1, e2) ->
3984 let c = Ast_defs.(equal_bop bop Ampamp) in
3985 let (env, te1, _) = expr env e1 in
3986 let lenv = env.lenv in
3987 let (env, _lset) = condition env c te1 in
3988 let (env, te2, _) = expr env e2 in
3989 let env = { env with lenv } in
3990 make_result
3993 (Aast.Binop (bop, te1, te2))
3994 (MakeType.bool (Reason.Rlogic_ret p))
3995 | Binop (bop, e1, e2) ->
3996 let (env, te1, ty1) = raw_expr env e1 in
3997 let (env, te2, ty2) = raw_expr env e2 in
3998 let env =
3999 match bop with
4000 (* TODO: This could be less conservative: we only need to account for
4001 * the possibility of exception if the operator is `/` or `/=`.
4003 | Ast_defs.Eqeqeq
4004 | Ast_defs.Diff2 ->
4006 | _ -> might_throw env
4008 let (_, p1, _) = e1 in
4009 let (_, p2, _) = e2 in
4010 let (env, te3, ty) =
4011 Typing_arithmetic.binop p env bop p1 te1 ty1 p2 te2 ty2
4013 (env, te3, ty)
4014 | Pipe (e0, e1, e2) ->
4015 (* If it weren't for local variable assignment or refinement the pipe
4016 * expression e1 |> e2 could be typed using this rule (E is environment with
4017 * types for locals):
4019 * E |- e1 : ty1 E[$$:ty1] |- e2 : ty2
4020 * --------------------------------------
4021 * E |- e1|>e2 : ty2
4023 * The possibility of e2 changing the types of locals in E means that E
4024 * can evolve, and so we need to restore $$ to its original state.
4026 let (env, te1, ty1) = expr env e1 in
4027 let dd_var = Local_id.make_unscoped SN.SpecialIdents.dollardollar in
4028 let dd_old_ty =
4029 if Env.is_local_defined env dd_var then
4030 Some (Env.get_local_pos env dd_var)
4031 else
4032 None
4034 let env = Env.set_local env dd_var ty1 Pos.none in
4035 let (env, te2, ty2) = expr env e2 ~allow_awaitable:true in
4036 let env =
4037 match dd_old_ty with
4038 | None -> Env.unset_local env dd_var
4039 | Some (ty, pos) -> Env.set_local env dd_var ty pos
4041 let (env, te, ty) = make_result env p (Aast.Pipe (e0, te1, te2)) ty2 in
4042 (env, te, ty)
4043 | Unop (uop, e) ->
4044 let (env, te, ty) = raw_expr env e in
4045 let env = might_throw env in
4046 let (env, tuop, ty) = Typing_arithmetic.unop p env uop te ty in
4047 let env = Typing_local_ops.check_assignment env te in
4048 (env, tuop, ty)
4049 | Eif (c, e1, e2) -> eif env ~expected ?in_await p c e1 e2
4050 | Class_const ((_, p, CI sid), pstr)
4051 when String.equal (snd pstr) "class" && Env.is_typedef env (snd sid) ->
4052 begin
4053 match Env.get_typedef env (snd sid) with
4054 | Some { td_tparams = tparaml; _ } ->
4055 (* Typedef type parameters cannot have constraints *)
4056 let params =
4057 List.map
4059 begin
4060 fun { tp_name = (p, x); _ } ->
4061 (* TODO(T69551141) handle type arguments for Tgeneric *)
4062 MakeType.generic (Reason.Rwitness_from_decl p) x
4064 tparaml
4066 let p_ = Pos_or_decl.of_raw_pos p in
4067 let tdef =
4069 ( Reason.Rwitness_from_decl p_,
4070 Tapply (Positioned.of_raw_positioned sid, params) )
4072 let typename =
4074 ( Reason.Rwitness_from_decl p_,
4075 Tapply ((p_, SN.Classes.cTypename), [tdef]) )
4077 let (env, tparams) =
4078 List.map_env env tparaml ~f:(fun env _tp -> Env.fresh_type env p)
4080 let ety_env =
4082 (empty_expand_env_with_on_error
4083 (Env.invalid_type_hint_assert_primary_pos_in_current_decl env))
4084 with
4085 substs = Subst.make_locl tparaml tparams;
4088 let env =
4089 Phase.check_tparams_constraints ~use_pos:p ~ety_env env tparaml
4091 let (env, ty) = Phase.localize ~ety_env env typename in
4092 make_result env p (Class_const ((ty, p, CI sid), pstr)) ty
4093 | None ->
4094 (* Should not expect None as we've checked whether the sid is a typedef *)
4095 expr_error env (Reason.Rwitness p) outer
4097 | Class_const (cid, mid) -> class_const env p (cid, mid)
4098 | Class_get (((_, _, cid_) as cid), CGstring mid, prop_or_method)
4099 when Env.FakeMembers.is_valid_static env cid_ (snd mid) ->
4100 let (env, local) = Env.FakeMembers.make_static env cid_ (snd mid) p in
4101 let local = ((), p, Lvar (p, local)) in
4102 let (env, _, ty) = expr env local in
4103 let (env, _tal, te, _) = class_expr env [] cid in
4104 make_result
4107 (Aast.Class_get (te, Aast.CGstring mid, prop_or_method))
4109 | Class_get
4110 (((_, _, cid_) as cid), CGstring ((ppos, _) as mid), prop_or_method) ->
4111 let (env, _tal, te, cty) = class_expr env [] cid in
4112 let env = might_throw env in
4113 let (env, (ty, _tal)) =
4114 class_get
4115 ~is_method:false
4116 ~is_const:false
4117 ~coerce_from_ty:None
4123 let (env, ty) =
4124 Env.FakeMembers.check_static_invalid env cid_ (snd mid) ty
4126 let env =
4127 Errors.try_if_no_errors
4128 (fun () -> Typing_local_ops.enforce_static_property_access ppos env)
4129 (fun env ->
4130 let is_lvalue = is_lvalue valkind in
4131 (* If it's an lvalue we throw an error in a separate check in check_assign *)
4132 if in_readonly_expr || is_lvalue then
4134 else
4135 Typing_local_ops.enforce_mutable_static_variable
4136 ppos
4138 (* This msg only appears if we have access to ReadStaticVariables,
4139 since otherwise we would have errored in the first function *)
4140 ~msg:"Please enclose the static in a readonly expression")
4142 make_result
4145 (Aast.Class_get (te, Aast.CGstring mid, prop_or_method))
4147 (* Fake member property access. For example:
4148 * if ($x->f !== null) { ...$x->f... }
4150 | Class_get (_, CGexpr _, _) ->
4151 failwith "AST should not have any CGexprs after naming"
4152 | Obj_get (e, (_, pid, Id (py, y)), nf, is_prop)
4153 when Env.FakeMembers.is_valid env e y ->
4154 let env = might_throw env in
4155 let (env, local) = Env.FakeMembers.make env e y p in
4156 let local = ((), p, Lvar (p, local)) in
4157 let (env, _, ty) = expr env local in
4158 let (env, t_lhs, _) = expr ~accept_using_var:true env e in
4159 let t_rhs = Tast.make_typed_expr pid ty (Aast.Id (py, y)) in
4160 make_result env p (Aast.Obj_get (t_lhs, t_rhs, nf, is_prop)) ty
4161 (* Statically-known instance property access e.g. $x->f *)
4162 | Obj_get (e1, (_, pm, Id m), nullflavor, prop_or_method) ->
4163 let nullsafe =
4164 match nullflavor with
4165 | OG_nullthrows -> None
4166 | OG_nullsafe -> Some p
4168 let (env, te1, ty1) = expr ~accept_using_var:true env e1 in
4169 let env = might_throw env in
4170 (* We typecheck Obj_get by checking whether it is a subtype of
4171 Thas_member(m, #1) where #1 is a fresh type variable. *)
4172 let (env, mem_ty) = Env.fresh_type env p in
4173 let (_, p1, _) = e1 in
4174 let r = Reason.Rwitness p1 in
4175 let has_member_ty =
4176 MakeType.has_member
4178 ~name:m
4179 ~ty:mem_ty
4180 ~class_id:(CIexpr e1)
4181 ~explicit_targs:None
4183 let lty1 = LoclType ty1 in
4184 let (env, result_ty, err_opt) =
4185 match nullsafe with
4186 | None ->
4187 let env_res =
4188 Type.sub_type_i_res
4190 Reason.URnone
4192 lty1
4193 has_member_ty
4194 Typing_error.Callback.unify_error
4196 let (env, err_opt) =
4197 Result.fold
4198 env_res
4199 ~ok:(fun env -> (env, None))
4200 ~error:(fun env -> (env, Some (ty1, MakeType.nothing Reason.none)))
4202 (env, mem_ty, err_opt)
4203 | Some _ ->
4204 (* In that case ty1 is a subtype of ?Thas_member(m, #1)
4205 and the result is ?#1 if ty1 is nullable. *)
4206 let r = Reason.Rnullsafe_op p in
4207 let null_ty = MakeType.null r in
4208 let (env, null_has_mem_ty) =
4209 Union.union_i env r has_member_ty null_ty
4211 let env_res =
4212 Type.sub_type_i_res
4214 Reason.URnone
4216 lty1
4217 null_has_mem_ty
4218 Typing_error.Callback.unify_error
4220 let (env, err_opt) =
4221 Result.fold
4222 env_res
4223 ~ok:(fun env -> (env, None))
4224 ~error:(fun env -> (env, Some (ty1, MakeType.nothing Reason.none)))
4226 let (env, null_or_nothing_ty) = Inter.intersect env ~r null_ty ty1 in
4227 let (env, result_ty) = Union.union env null_or_nothing_ty mem_ty in
4228 (env, result_ty, err_opt)
4230 let (env, result_ty) =
4231 Env.FakeMembers.check_instance_invalid env e1 (snd m) result_ty
4233 make_result
4236 (Aast.Obj_get
4237 ( hole_on_err ~err_opt te1,
4238 Tast.make_typed_expr pm result_ty (Aast.Id m),
4239 nullflavor,
4240 prop_or_method ))
4241 result_ty
4242 (* Dynamic instance property access e.g. $x->$f *)
4243 | Obj_get (e1, e2, nullflavor, prop_or_method) ->
4244 let (env, te1, ty1) = expr ~accept_using_var:true env e1 in
4245 let (env, te2, _) = expr env e2 in
4246 let ty =
4247 if TUtils.is_dynamic env ty1 then
4248 MakeType.dynamic (Reason.Rwitness p)
4249 else
4250 Typing_utils.mk_tany env p
4252 let (_, pos, te2) = te2 in
4253 let env = might_throw env in
4254 let te2 = Tast.make_typed_expr pos ty te2 in
4255 make_result env p (Aast.Obj_get (te1, te2, nullflavor, prop_or_method)) ty
4256 | Yield af ->
4257 let (env, (taf, opt_key, value)) = array_field ~allow_awaitable env af in
4258 let Typing_env_return_info.{ return_type = expected_return; _ } =
4259 Env.get_return env
4261 let send =
4262 match get_node expected_return.et_type with
4263 | Tclass (_, _, _ :: _ :: send :: _) -> send
4264 | Tdynamic when env.in_support_dynamic_type_method_check ->
4265 expected_return.et_type
4266 | _ ->
4267 Errors.internal_error p "Return type is not a generator";
4268 Typing_utils.terr env (Reason.Ryield_send p)
4270 let is_async =
4271 match Env.get_fn_kind env with
4272 | Ast_defs.FGenerator -> false
4273 (* This could also catch sync/async non-generators, but an error would
4274 * have already been generated elsewhere *)
4275 | _ -> true
4277 let (env, key) =
4278 match (af, opt_key) with
4279 | (AFvalue (_, p, _), None) ->
4280 if is_async then
4281 let (env, ty) = Env.fresh_type env p in
4282 (env, MakeType.nullable_locl (Reason.Ryield_asyncnull p) ty)
4283 else
4284 (env, MakeType.int (Reason.Rwitness p))
4285 | (_, Some x) -> (env, x)
4286 | (_, _) -> assert false
4288 let rty =
4289 if is_async then
4290 MakeType.async_generator (Reason.Ryield_asyncgen p) key value send
4291 else
4292 MakeType.generator (Reason.Ryield_gen p) key value send
4294 let Typing_env_return_info.{ return_type = expected_return; _ } =
4295 Env.get_return env
4297 let env =
4298 Typing_coercion.coerce_type
4300 Reason.URyield
4303 expected_return
4304 Typing_error.Callback.unify_error
4306 let env = Env.forget_members env Reason.(Blame (p, BScall)) in
4307 let env = LEnv.save_and_merge_next_in_cont env C.Exit in
4308 make_result
4311 (Aast.Yield taf)
4312 (MakeType.nullable_locl (Reason.Ryield_send p) send)
4313 | Await e ->
4314 begin
4315 match e with
4316 | (_, p, Aast.Call ((_, _, Aast.Id (_, func)), _, _, _))
4317 when String.equal func SN.PseudoFunctions.unsafe_cast ->
4318 Errors.add_typing_error
4319 Typing_error.(primary @@ Primary.Unsafe_cast_await p)
4320 | _ -> ()
4321 end;
4322 let env = might_throw env in
4323 (* Await is permitted in a using clause e.g. using (await make_handle()) *)
4324 let (env, te, rty) =
4325 expr
4326 ~is_using_clause
4327 ~in_await:(Reason.Rwitness p)
4330 ~allow_awaitable:true
4332 let (env, ty) = Async.overload_extract_from_awaitable env ~p rty in
4333 make_result env p (Aast.Await te) ty
4334 | ReadonlyExpr e ->
4335 let env = Env.set_readonly env true in
4336 let (env, te, rty) = expr ~is_using_clause ~in_readonly_expr:true env e in
4337 make_result env p (Aast.ReadonlyExpr te) rty
4338 | New ((_, pos, c), explicit_targs, el, unpacked_element, ()) ->
4339 let env = might_throw env in
4340 let ( env,
4342 tal,
4343 tel,
4344 typed_unpack_element,
4346 ctor_fty,
4347 should_forget_fakes ) =
4348 new_object
4349 ~expected
4350 ~is_using_clause
4351 ~check_parent:false
4352 ~check_not_abstract:true
4356 explicit_targs
4357 (List.map ~f:(fun e -> (Ast_defs.Pnormal, e)) el)
4358 unpacked_element
4360 let env =
4361 if should_forget_fakes then
4362 Env.forget_members env Reason.(Blame (p, BScall))
4363 else
4366 make_result
4369 (Aast.New (tc, tal, List.map ~f:snd tel, typed_unpack_element, ctor_fty))
4371 | Cast (hint, e) ->
4372 let (env, te, ty2) = expr ?in_await env e in
4373 let env = might_throw env in
4374 let env =
4376 TypecheckerOptions.experimental_feature_enabled
4377 (Env.get_tcopt env)
4378 TypecheckerOptions.experimental_forbid_nullable_cast
4379 && not (TUtils.is_mixed env ty2)
4380 then
4381 SubType.sub_type_or_fail env ty2 (MakeType.nonnull (get_reason ty2))
4382 @@ Some
4383 Typing_error.(
4384 primary
4385 @@ Primary.Nullable_cast
4387 pos = p;
4388 ty_name = lazy (Typing_print.error env ty2);
4389 ty_pos = get_pos ty2;
4391 else
4394 let (env, ty) =
4395 Phase.localize_hint_no_subst env ~ignore_errors:false hint
4397 make_result env p (Aast.Cast (hint, te)) ty
4398 | ExpressionTree et -> expression_tree env p et
4399 | Is (e, hint) ->
4400 let (env, te, _) = expr env e in
4401 make_result env p (Aast.Is (te, hint)) (MakeType.bool (Reason.Rwitness p))
4402 | As (e, hint, is_nullable) ->
4403 let refine_type env lpos lty rty =
4404 let reason = Reason.Ras lpos in
4405 let (env, rty) = Env.expand_type env rty in
4406 refine_and_simplify_intersection
4407 ~hint_first:false
4410 reason
4411 lpos
4415 let (env, te, expr_ty) = expr env e in
4416 let env = might_throw env in
4417 let (env, hint_ty) =
4418 Phase.localize_hint_no_subst env ~ignore_errors:false hint
4420 let enable_sound_dynamic =
4421 TypecheckerOptions.enable_sound_dynamic env.genv.tcopt
4423 let (env, hint_ty) =
4424 if Typing_defs.is_dynamic hint_ty then
4425 let env =
4426 if enable_sound_dynamic then
4427 SubType.sub_type
4428 ~coerce:(Some Typing_logic.CoerceToDynamic)
4430 expr_ty
4431 hint_ty
4432 (Typing_error.Reasons_callback.unify_error_at p)
4433 else
4436 let (env, locl) = make_a_local_of ~include_this:true env e in
4437 let env =
4438 match locl with
4439 | Some ivar -> set_local env ivar hint_ty
4440 | None -> env
4442 (env, hint_ty)
4443 else if is_nullable then
4444 let (_, e_p, _) = e in
4445 let (env, hint_ty) = refine_type env e_p expr_ty hint_ty in
4446 (env, MakeType.nullable_locl (Reason.Rwitness p) hint_ty)
4447 else
4448 let (env, locl) = make_a_local_of ~include_this:true env e in
4449 match locl with
4450 | Some ((ivar_pos, _) as ivar) ->
4451 let (env, hint_ty) = refine_type env ivar_pos expr_ty hint_ty in
4452 let env = set_local env ivar hint_ty in
4453 (env, hint_ty)
4454 | None ->
4455 let (_, e_p, _) = e in
4456 refine_type env e_p expr_ty hint_ty
4458 make_result env p (Aast.As (te, hint, is_nullable)) hint_ty
4459 | Upcast (e, hint) ->
4460 let (env, te, expr_ty) = expr env e in
4461 let (env, hint_ty) =
4462 Phase.localize_hint_no_subst env ~ignore_errors:false hint
4464 let env =
4465 SubType.sub_type
4466 ~coerce:(Some Typing_logic.CoerceToDynamic)
4468 expr_ty
4469 hint_ty
4470 (Typing_error.Reasons_callback.unify_error_at p)
4472 make_result env p (Aast.Upcast (te, hint)) hint_ty
4473 | Efun (f, idl) -> lambda ~is_anon:true ?expected p env f idl
4474 | Lfun (f, idl) -> lambda ~is_anon:false ?expected p env f idl
4475 | Xml (sid, attrl, el) ->
4476 let cid = CI sid in
4477 let (env, _tal, _te, classes) =
4478 class_id_for_new ~exact:Nonexact p env cid []
4480 (* OK to ignore rest of list; class_info only used for errors, and
4481 * cid = CI sid cannot produce a union of classes anyhow *)
4482 let class_info =
4483 List.find_map classes ~f:(function
4484 | `Dynamic -> None
4485 | `Class (_, class_info, _) -> Some class_info)
4487 let (env, te, obj) =
4488 (* New statements derived from Xml literals are of the following form:
4490 * __construct(
4491 * darray<string,mixed> $attributes,
4492 * varray<mixed> $children,
4493 * string $file,
4494 * int $line
4495 * );
4497 let new_exp = Typing_xhp.rewrite_xml_into_new p sid attrl el in
4498 expr ?expected env new_exp
4500 let tchildren =
4501 match te with
4502 | ( _,
4505 ( _,
4509 (_, _, (Varray (_, children) | ValCollection (Vec, _, children)));
4514 _ ) ) ->
4515 (* Typing_xhp.rewrite_xml_into_new generates an AST node for a `varray[]` literal, which is interpreted as a vec[] *)
4516 children
4517 | _ ->
4518 (* We end up in this case when the cosntructed new expression does
4519 not typecheck. *)
4522 let (env, typed_attrs) = xhp_attribute_exprs env class_info attrl sid obj in
4523 let txml = Aast.Xml (sid, typed_attrs, tchildren) in
4524 (match class_info with
4525 | None -> make_result env p txml (TUtils.terr env (Reason.Runknown_class p))
4526 | Some _ -> make_result env p txml obj)
4527 | Shape fdm ->
4528 let expr_helper ?expected env (k, e) =
4529 let (env, et, ty) = expr ?expected env e in
4530 if TypecheckerOptions.pessimise_builtins (Env.get_tcopt env) then
4531 let (env, ty) = Typing_array_access.pessimised_tup_assign p env ty in
4532 (env, (k, et, ty))
4533 else
4534 (env, (k, et, ty))
4536 let (env, tfdm) =
4537 match expand_expected_and_get_node env expected with
4538 | (env, Some (pos, ur, _, _, Tshape (_, expected_fdm))) ->
4539 List.map_env
4541 ~f:(fun env ((k, _) as ke) ->
4542 let tk = TShapeField.of_ast Pos_or_decl.of_raw_pos k in
4543 match TShapeMap.find_opt tk expected_fdm with
4544 | None -> expr_helper env ke
4545 | Some sft ->
4546 let (env, ty) =
4547 Typing_array_access.maybe_pessimise_type env sft.sft_ty
4549 expr_helper ~expected:(ExpectedTy.make pos ur ty) env ke)
4551 | _ -> List.map_env env ~f:expr_helper fdm
4553 let fdm =
4554 List.fold_left
4555 ~f:(fun acc (k, _, ty) ->
4556 let tk = TShapeField.of_ast Pos_or_decl.of_raw_pos k in
4557 TShapeMap.add tk { sft_optional = false; sft_ty = ty } acc)
4558 ~init:TShapeMap.empty
4559 tfdm
4561 let env =
4562 Typing_shapes.check_shape_keys_validity env (List.map tfdm ~f:fst3)
4564 (* Fields are fully known, because this shape is constructed
4565 * using shape keyword and we know exactly what fields are set. *)
4566 make_result
4569 (Aast.Shape (List.map ~f:(fun (k, te, _) -> (k, te)) tfdm))
4570 (mk (Reason.Rwitness p, Tshape (Closed_shape, fdm)))
4571 | ET_Splice e ->
4572 Typing_env.with_in_expr_tree env false (fun env -> et_splice env p e)
4573 | EnumClassLabel (None, s) ->
4574 let (env, expect_label, lty_opt) =
4575 match expected with
4576 | Some ety ->
4577 let (env, lty) = Env.expand_type env ety.ExpectedTy.ty.et_type in
4578 let expect_label =
4579 match get_node (TUtils.strip_dynamic env lty) with
4580 | Tnewtype (name, _, _) ->
4581 String.equal SN.Classes.cEnumClassLabel name
4582 | _ -> false
4584 (env, expect_label, Some lty)
4585 | None -> (env, false, None)
4587 let () =
4588 if expect_label then
4589 Errors.add_typing_error
4590 Typing_error.(enum @@ Primary.Enum.Enum_class_label_as_expr p)
4591 else
4592 let expected_ty_msg_opt =
4593 Option.map lty_opt ~f:(fun lty ->
4594 let ty_str = lazy (Typing_print.error env lty) in
4595 let r = get_reason lty in
4596 Lazy.map ty_str ~f:(fun ty_str ->
4597 Reason.to_string (Format.sprintf "Expected %s" ty_str) r))
4599 Errors.add_typing_error
4600 Typing_error.(
4601 enum
4602 @@ Primary.Enum.Enum_class_label_member_mismatch
4603 { pos = p; label = s; expected_ty_msg_opt })
4605 make_result
4608 (Aast.EnumClassLabel (None, s))
4609 (mk (Reason.Rwitness p, Terr))
4610 | EnumClassLabel ((Some (pos, cname) as e), name) ->
4611 let (env, res) =
4612 EnumClassLabelOps.expand
4615 ~full:true
4616 ~ctor:SN.Classes.cEnumClassLabel
4617 cname
4618 name
4620 let error () =
4621 make_result
4624 (Aast.EnumClassLabel (e, name))
4625 (mk (Reason.Rwitness p, Terr))
4627 (match res with
4628 | EnumClassLabelOps.Success ((_, _, texpr), lty) ->
4629 make_result env p texpr lty
4630 | EnumClassLabelOps.ClassNotFound ->
4631 (* Error registered in nast_check/unbound_name_check *)
4632 error ()
4633 | EnumClassLabelOps.LabelNotFound _ ->
4634 (* Error registered in EnumClassLabelOps.expand *)
4635 error ()
4636 | EnumClassLabelOps.Invalid
4637 | EnumClassLabelOps.Skip ->
4638 Errors.add_typing_error
4639 Typing_error.(enum @@ Primary.Enum.Enum_class_label_as_expr p);
4640 error ())
4642 and class_const ?(incl_tc = false) env p (cid, mid) =
4643 let (env, _tal, ce, cty) = class_expr env [] cid in
4644 let env =
4645 match get_node cty with
4646 | Tclass ((_, n), _, _)
4647 when Env.is_enum_class env n && String.(SN.Members.mClass <> snd mid) ->
4648 Typing_local_ops.enforce_enum_class_variant p env
4649 | _ -> env
4651 let (env, (const_ty, _tal)) =
4652 class_get
4653 ~is_method:false
4654 ~is_const:true
4655 ~incl_tc
4656 ~coerce_from_ty:None
4662 make_result env p (Aast.Class_const (ce, mid)) const_ty
4664 and function_dynamically_callable env f params_decl_ty ret_locl_ty =
4665 let env = { env with in_support_dynamic_type_method_check = true } in
4666 (* If any of the parameters doesn't have an explicit hint, then we have
4667 * to treat this is non-enforceable and therefore not dynamically callable
4668 * based purely on the signature *)
4669 let interface_check =
4670 List.for_all f.f_params ~f:(fun param ->
4671 Option.is_some (snd param.param_type_hint))
4672 && Typing_dynamic.sound_dynamic_interface_check
4674 params_decl_ty
4675 ret_locl_ty
4677 let function_body_check () =
4678 (* Here the body of the function is typechecked again to ensure it is safe
4679 * to call it from a dynamic context (eg. under dyn..dyn->dyn assumptions).
4680 * The code below must be kept in sync with with the fun_def checks.
4682 let make_dynamic pos =
4683 Typing_make_type.dynamic (Reason.Rsupport_dynamic_type pos)
4685 let dynamic_return_ty = make_dynamic (get_pos ret_locl_ty) in
4686 let dynamic_return_info =
4687 Typing_env_return_info.
4689 return_type = MakeType.unenforced dynamic_return_ty;
4690 return_disposable = false;
4691 return_explicit = true;
4692 return_dynamically_callable = true;
4695 let (env, param_tys) =
4696 List.zip_exn f.f_params params_decl_ty
4697 |> List.map_env env ~f:(fun env (param, hint) ->
4698 let dyn_ty =
4699 make_dynamic @@ Pos_or_decl.of_raw_pos param.param_pos
4701 let ty =
4702 match hint with
4703 | Some ty when Typing_enforceability.is_enforceable env ty ->
4704 Typing_make_type.intersection
4705 (Reason.Rsupport_dynamic_type Pos_or_decl.none)
4706 [ty; dyn_ty]
4707 | _ -> dyn_ty
4709 Typing_param.make_param_local_ty env (Some ty) param)
4711 let params_need_immutable = Typing_coeffects.get_ctx_vars f.f_ctxs in
4712 let (env, _) =
4713 (* In this pass, bind_param_and_check receives a pair where the lhs is
4714 * either Tdynamic or TInstersection of the original type and TDynamic,
4715 * but the fun_param is still referencing the source hint. We amend
4716 * the source hint to keep in in sync before calling bind_param
4717 * so the right enforcement is computed.
4719 let bind_param_and_check env lty_and_param =
4720 let (ty, param) = lty_and_param in
4721 let name = param.param_name in
4722 let (hi, hopt) = param.param_type_hint in
4723 let hopt =
4724 Option.map hopt ~f:(fun (p, h) ->
4725 if Typing_utils.is_tintersection env ty then
4726 (p, Hintersection [(p, h); (p, Hdynamic)])
4727 else
4728 (p, Hdynamic))
4730 let param_type_hint = (hi, hopt) in
4731 let param = (ty, { param with param_type_hint }) in
4732 let immutable =
4733 List.exists ~f:(String.equal name) params_need_immutable
4735 let (env, fun_param) = bind_param ~immutable env param in
4736 (env, fun_param)
4738 List.map_env
4740 (List.zip_exn param_tys f.f_params)
4741 ~f:bind_param_and_check
4744 let pos = fst f.f_name in
4745 let env = set_tyvars_variance_in_callable env dynamic_return_ty param_tys in
4746 let disable =
4747 Naming_attributes.mem
4748 SN.UserAttributes.uaDisableTypecheckerInternal
4749 f.f_user_attributes
4752 Errors.try_
4753 (fun () ->
4754 let (_ : env * Tast.stmt list) =
4755 fun_ ~disable env dynamic_return_info pos f.f_body f.f_fun_kind
4758 (fun error ->
4759 Errors.function_is_not_dynamically_callable pos (snd f.f_name) error)
4761 if not interface_check then function_body_check ()
4763 and lambda ~is_anon ?expected p env f idl =
4764 (* This is the function type as declared on the lambda itself.
4765 * If type hints are absent then use Tany instead. *)
4766 let declared_fe = Decl_nast.lambda_decl_in_env env.decl_env f in
4767 let { fe_type; fe_pos; _ } = declared_fe in
4768 let (declared_pos, declared_ft) =
4769 match get_node fe_type with
4770 | Tfun ft -> (fe_pos, ft)
4771 | _ -> failwith "Not a function"
4773 let declared_decl_ft =
4774 Typing_enforceability.compute_enforced_and_pessimize_fun_type
4776 declared_ft
4778 (* When creating a closure, the 'this' type will mean the late bound type
4779 * of the current enclosing class
4781 let ety_env =
4782 empty_expand_env_with_on_error
4783 (Env.invalid_type_hint_assert_primary_pos_in_current_decl env)
4785 let (env, declared_ft) =
4786 Phase.(
4787 localize_ft
4788 ~instantiation:{ use_name = "lambda"; use_pos = p; explicit_targs = [] }
4789 ~ety_env
4790 ~def_pos:declared_pos
4792 declared_decl_ft)
4795 (* Check that none of the explicit capture variables are from a using clause *)
4796 List.iter idl ~f:(check_escaping_var env);
4798 (* Ensure that variadic parameter has a name *)
4799 (if get_ft_variadic declared_ft then
4800 match List.last declared_ft.ft_params with
4801 | Some { fp_name = None; _ } ->
4802 Errors.add_typing_error
4803 Typing_error.(
4804 primary
4805 @@ Primary.Ellipsis_strict_mode { require = `Param_name; pos = p })
4806 | _ -> ());
4808 (* Is the return type declared? *)
4809 let is_explicit_ret = Option.is_some (hint_of_type_hint f.f_ret) in
4810 let check_body_under_known_params ~supportdyn env ?ret_ty ft :
4811 env * _ * locl_ty =
4812 let (env, (tefun, ty, ft)) =
4813 closure_make ~supportdyn ?ret_ty env p declared_decl_ft f ft idl is_anon
4815 let inferred_ty =
4817 ( Reason.Rwitness p,
4818 Tfun
4820 ft with
4821 ft_ret =
4822 (if is_explicit_ret then
4823 declared_ft.ft_ret
4824 else
4825 MakeType.unenforced ty);
4828 (env, tefun, inferred_ty)
4830 let (env, eexpected) =
4831 expand_expected_and_get_node ~allow_supportdyn:true env expected
4833 match eexpected with
4834 | Some (_pos, _ur, _, tdyn, Tdynamic)
4835 when env.in_support_dynamic_type_method_check ->
4836 let make_dynamic { et_type; et_enforced } =
4837 let et_type =
4838 match (get_node et_type, et_enforced) with
4839 | (Tany _, _) (* lambda param without type hint *)
4840 | (_, Unenforced) ->
4841 tdyn
4842 | (_, Enforced) ->
4843 MakeType.intersection
4844 (Reason.Rsupport_dynamic_type (get_pos tdyn))
4845 [tdyn; et_type]
4847 { et_type; et_enforced }
4849 let ft_params =
4850 List.map declared_ft.ft_params ~f:(function param ->
4851 { param with fp_type = make_dynamic param.fp_type })
4853 check_body_under_known_params
4855 ~ret_ty:tdyn
4856 ~supportdyn:false
4857 { declared_ft with ft_params }
4858 | Some (_pos, _ur, supportdyn, ty, Tfun expected_ft) ->
4859 (* First check that arities match up *)
4860 check_lambda_arity p (get_pos ty) declared_ft expected_ft;
4861 (* Use declared types for parameters in preference to those determined
4862 * by the context (expected parameters): they might be more general. *)
4863 let rec replace_non_declared_types declared_ft_params expected_ft_params =
4864 match (declared_ft_params, expected_ft_params) with
4865 | ( declared_ft_param :: declared_ft_params,
4866 expected_ft_param :: expected_ft_params ) ->
4867 let rest =
4868 replace_non_declared_types declared_ft_params expected_ft_params
4870 (* If the type parameter did not have a type hint, it is Tany and
4871 we use the expected type instead. Otherwise, declared type takes
4872 precedence. *)
4873 let resolved_ft_param =
4874 if TUtils.is_any env declared_ft_param.fp_type.et_type then
4875 { declared_ft_param with fp_type = expected_ft_param.fp_type }
4876 else
4877 declared_ft_param
4879 resolved_ft_param :: rest
4880 | (_, []) ->
4881 (* Morally, this case should match on ([],[]) because we already
4882 check arity mismatch between declared and expected types. We
4883 handle it more generally here to be graceful. *)
4884 declared_ft_params
4885 | ([], _) ->
4886 if (not (get_ft_variadic declared_ft)) && get_ft_variadic expected_ft
4887 then
4889 else
4890 (* This means the expected_ft params list can have more parameters
4891 * than declared parameters in the lambda. For variadics, this is OK.
4893 expected_ft_params
4895 let expected_ft =
4897 expected_ft with
4898 ft_params =
4899 replace_non_declared_types declared_ft.ft_params expected_ft.ft_params;
4900 ft_implicit_params = declared_ft.ft_implicit_params;
4901 ft_flags = declared_ft.ft_flags;
4904 (* Don't bother passing in `void` if there is no explicit return *)
4905 let ret_ty =
4906 match get_node expected_ft.ft_ret.et_type with
4907 | Tprim Tvoid when not is_explicit_ret -> None
4908 | _ -> Some expected_ft.ft_ret.et_type
4910 Typing_log.increment_feature_count env FL.Lambda.contextual_params;
4911 check_body_under_known_params ~supportdyn env ?ret_ty expected_ft
4912 | _ ->
4913 (* If all parameters are annotated with explicit types, then type-check
4914 * the body under those assumptions and pick up the result type *)
4915 let all_explicit_params =
4916 List.for_all f.f_params ~f:(fun param ->
4917 Option.is_some (hint_of_type_hint param.param_type_hint))
4919 if all_explicit_params then (
4920 Typing_log.increment_feature_count
4922 (if List.is_empty f.f_params then
4923 FL.Lambda.no_params
4924 else
4925 FL.Lambda.explicit_params);
4926 check_body_under_known_params ~supportdyn:false env declared_ft
4927 ) else (
4928 match expected with
4929 | Some ExpectedTy.{ ty = { et_type; _ }; _ } when is_any et_type ->
4930 (* If the expected type is Tany env then we're passing a lambda to
4931 * an untyped function and we just assume every parameter has type
4932 * Tany.
4933 * Note: we should be using 'nothing' to type the arguments. *)
4934 Typing_log.increment_feature_count env FL.Lambda.untyped_context;
4935 check_body_under_known_params ~supportdyn:false env declared_ft
4936 | Some ExpectedTy.{ ty = { et_type; _ }; _ }
4937 when TUtils.is_mixed env et_type || is_dynamic et_type ->
4938 (* If the expected type of a lambda is mixed or dynamic, we
4939 * decompose the expected type into a function type where the
4940 * undeclared parameters and the return type are set to the expected
4941 * type of lambda, i.e., mixed or dynamic.
4943 * For an expected mixed type, one could argue that the lambda
4944 * doesn't even need to be checked as it can't be called (there is
4945 * no downcast to function type). Thus, we should be using nothing
4946 * to type the arguments. But generally users are very confused by
4947 * the use of nothing and would expect the lambda body to be
4948 * checked as though it could be called.
4950 let replace_non_declared_type declared_ft_param =
4951 let is_undeclared =
4952 TUtils.is_any env declared_ft_param.fp_type.et_type
4954 if is_undeclared then
4955 let enforced_ty = { et_enforced = Unenforced; et_type } in
4956 { declared_ft_param with fp_type = enforced_ty }
4957 else
4958 declared_ft_param
4960 let expected_ft =
4961 let ft_params =
4962 List.map ~f:replace_non_declared_type declared_ft.ft_params
4964 { declared_ft with ft_params }
4966 let ret_ty = et_type in
4967 check_body_under_known_params ~supportdyn:false env ~ret_ty expected_ft
4968 | Some _ ->
4969 (* If the expected type is something concrete but not a function
4970 * then we should reject in strict mode. Check body anyway.
4971 * Note: we should be using 'nothing' to type the arguments. *)
4972 Errors.add_typing_error
4973 Typing_error.(primary @@ Primary.Untyped_lambda_strict_mode p);
4974 Typing_log.increment_feature_count
4976 FL.Lambda.non_function_typed_context;
4977 check_body_under_known_params ~supportdyn:false env declared_ft
4978 | None ->
4979 Typing_log.increment_feature_count env FL.Lambda.fresh_tyvar_params;
4981 (* Replace uses of Tany that originated from "untyped" parameters or return type
4982 * with fresh type variables *)
4983 let freshen_ftype env ft =
4984 let freshen_ty env pos et =
4985 match get_node et.et_type with
4986 | Tany _ ->
4987 let (env, ty) = Env.fresh_type env pos in
4988 (env, { et with et_type = ty })
4989 | Tclass (id, e, [ty])
4990 when String.equal (snd id) SN.Classes.cAwaitable && is_any ty ->
4991 let (env, t) = Env.fresh_type env pos in
4992 ( env,
4994 et with
4995 et_type = mk (get_reason et.et_type, Tclass (id, e, [t]));
4997 | _ -> (env, et)
4999 let freshen_untyped_param env ft_param =
5000 let (env, fp_type) =
5001 freshen_ty
5003 (Pos_or_decl.unsafe_to_raw_pos ft_param.fp_pos)
5004 ft_param.fp_type
5006 (env, { ft_param with fp_type })
5008 let (env, ft_params) =
5009 List.map_env env ft.ft_params ~f:freshen_untyped_param
5011 let (env, ft_ret) = freshen_ty env f.f_span ft.ft_ret in
5012 (env, { ft with ft_params; ft_ret })
5014 let (env, declared_ft) = freshen_ftype env declared_ft in
5015 let env =
5016 Env.set_tyvar_variance env (mk (Reason.Rnone, Tfun declared_ft))
5018 (* TODO(jjwu): the declared_ft here is set to public,
5019 but is actually inferred from the surrounding context
5020 (don't think this matters in practice, since we check lambdas separately) *)
5021 check_body_under_known_params
5022 ~supportdyn:false
5024 ~ret_ty:declared_ft.ft_ret.et_type
5025 declared_ft
5029 * Process a spread operator by computing the intersection of XHP attributes
5030 * between the spread expression and the XHP constructor onto which we're
5031 * spreading.
5033 and xhp_spread_attribute env c_onto valexpr sid obj =
5034 let (_, p, _) = valexpr in
5035 let (env, te, valty) = expr env valexpr ~allow_awaitable:(*?*) false in
5036 let (env, attr_ptys) =
5037 match c_onto with
5038 | None -> (env, [])
5039 | Some class_info -> Typing_xhp.get_spread_attributes env p class_info valty
5041 let (env, has_err) =
5042 List.fold_left
5043 attr_ptys
5044 ~f:(fun (env, has_err) attr ->
5045 let (env, _, err_opt) = xhp_attribute_decl_ty env sid obj attr in
5046 (env, has_err || Option.is_some err_opt))
5047 ~init:(env, false)
5049 (* If we have a subtyping error for any attribute, the best we can do here
5050 is give an expected type of dynamic *)
5051 let err_opt =
5052 if has_err then
5053 Some (valty, MakeType.nothing Reason.Rnone)
5054 else
5055 None
5057 (* Build the typed attribute node *)
5058 let typed_attr = Aast.Xhp_spread (hole_on_err ~err_opt te) in
5059 (env, typed_attr)
5062 * Simple XHP attributes (attr={expr} form) are simply interpreted as a member
5063 * variable prefixed with a colon.
5065 and xhp_simple_attribute env id valexpr sid obj =
5066 let (_, p, _) = valexpr in
5067 let (env, te, valty) = expr env valexpr ~allow_awaitable:(*?*) false in
5068 (* This converts the attribute name to a member name. *)
5069 let name = ":" ^ snd id in
5070 let attr_pty = ((fst id, name), (p, valty)) in
5071 let (env, decl_ty, err_opt) = xhp_attribute_decl_ty env sid obj attr_pty in
5072 let typed_attr =
5073 Aast.Xhp_simple
5074 { xs_name = id; xs_type = decl_ty; xs_expr = hole_on_err ~err_opt te }
5076 (env, typed_attr)
5079 * Typecheck the attribute expressions - this just checks that the expressions are
5080 * valid, not that they match the declared type for the attribute and,
5081 * in case of spreads, makes sure they are XHP.
5083 and xhp_attribute_exprs env cls_decl attrl sid obj =
5084 let handle_attr (env, typed_attrl) attr =
5085 let (env, typed_attr) =
5086 match attr with
5087 | Xhp_simple { xs_name = id; xs_expr = valexpr; _ } ->
5088 xhp_simple_attribute env id valexpr sid obj
5089 | Xhp_spread valexpr -> xhp_spread_attribute env cls_decl valexpr sid obj
5091 (env, typed_attr :: typed_attrl)
5093 let (env, typed_attrl) =
5094 List.fold_left ~f:handle_attr ~init:(env, []) attrl
5096 (env, List.rev typed_attrl)
5098 (*****************************************************************************)
5099 (* Anonymous functions & lambdas. *)
5100 (*****************************************************************************)
5101 and closure_bind_param params (env, t_params) ty : env * Tast.fun_param list =
5102 match !params with
5103 | [] ->
5104 (* This code cannot be executed normally, because the arity is wrong
5105 * and it will error later. Bind as many parameters as we can and carry
5106 * on. *)
5107 (env, t_params)
5108 | param :: paraml ->
5109 params := paraml;
5110 (match hint_of_type_hint param.param_type_hint with
5111 | Some h ->
5112 let (pos, _) = h in
5113 (* When creating a closure, the 'this' type will mean the
5114 * late bound type of the current enclosing class
5116 let (env, h) = Phase.localize_hint_no_subst env ~ignore_errors:false h in
5117 let env =
5118 Typing_coercion.coerce_type
5120 Reason.URparam
5123 (MakeType.unenforced h)
5124 Typing_error.Callback.unify_error
5126 (* Closures are allowed to have explicit type-hints. When
5127 * that is the case we should check that the argument passed
5128 * is compatible with the type-hint.
5129 * The body of the function should be type-checked with the
5130 * hint and not the type of the argument passed.
5131 * Otherwise it leads to strange results where
5132 * foo(?string $x = null) is called with a string and fails to
5133 * type-check. If $x is a string instead of ?string, null is not
5134 * subtype of string ...
5136 let (env, t_param) = bind_param env (h, param) in
5137 (env, t_params @ [t_param])
5138 | None ->
5139 let ty =
5140 mk (Reason.Rlambda_param (param.param_pos, get_reason ty), get_node ty)
5142 let (env, t_param) = bind_param env (ty, param) in
5143 (env, t_params @ [t_param]))
5145 and closure_bind_variadic env vparam variadic_ty =
5146 let (env, ty, pos) =
5147 match hint_of_type_hint vparam.param_type_hint with
5148 | None ->
5149 (* if the hint is missing, use the type we expect *)
5150 (env, variadic_ty, get_pos variadic_ty)
5151 | Some hint ->
5152 let pos = fst hint in
5153 let (env, h) =
5154 Phase.localize_hint_no_subst env ~ignore_errors:false hint
5156 let env =
5157 Typing_coercion.coerce_type
5159 Reason.URparam
5161 variadic_ty
5162 (MakeType.unenforced h)
5163 Typing_error.Callback.unify_error
5165 (env, h, Pos_or_decl.of_raw_pos vparam.param_pos)
5167 let r = Reason.Rvar_param_from_decl pos in
5168 let arr_values = mk (r, get_node ty) in
5169 let ty = MakeType.varray r arr_values in
5170 let (env, t_variadic) = bind_param env (ty, vparam) in
5171 (env, t_variadic)
5173 and closure_bind_opt_param env param : env =
5174 match param.param_expr with
5175 | None ->
5176 let ty = Typing_utils.mk_tany env param.param_pos in
5177 let (env, _) = bind_param env (ty, param) in
5179 | Some default ->
5180 let (env, _te, ty) = expr env default ~allow_awaitable:(*?*) false in
5181 Typing_sequencing.sequence_check_expr default;
5182 let (env, _) = bind_param env (ty, param) in
5185 (* Make a type-checking function for an anonymous function or lambda. *)
5186 (* Here ret_ty should include Awaitable wrapper *)
5187 (* TODO: ?el is never set; so we need to fix variadic use of lambda *)
5188 and closure_make
5190 ?ret_ty
5191 ?(check_escapes = true)
5192 ~supportdyn
5194 lambda_pos
5195 decl_ft
5199 is_anon =
5200 let type_closure f =
5201 (* Wrap the function f so that it can freely clobber function-specific
5202 parts of the environment; the clobbered parts are restored before
5203 returning the result. Additionally, we also prevent type parameters
5204 created in the closure from unsoundly leaking into the environment
5205 of the enclosing function. *)
5206 let snap = Typing_escape.snapshot_env env in
5207 let (env, (escaping, (te, hret, ft))) =
5208 Env.closure env (fun env ->
5209 stash_conts_for_closure env lambda_pos is_anon idl (fun env ->
5210 let (env, res) = f env in
5211 let escaping = Typing_escape.escaping_from_snapshot snap env in
5212 (env, (escaping, res))))
5214 (* After the body of the function is checked, erase all the type parameters
5215 created from the env and the return type. *)
5216 let (env, hret) =
5217 if check_escapes then
5218 Typing_escape.refresh_env_and_type
5219 ~remove:escaping
5220 ~pos:lambda_pos
5222 hret
5223 else
5224 (env, hret)
5226 (env, (te, hret, ft))
5228 type_closure @@ fun env ->
5229 let nb = f.f_body in
5230 (* Extract capabilities from AAST and add them to the environment *)
5231 let (env, capability) =
5232 match (f.f_ctxs, f.f_unsafe_ctxs) with
5233 | (None, None) ->
5234 (* if the closure has no explicit coeffect annotations,
5235 do _not_ insert (unsafe) capabilities into the environment;
5236 instead, rely on the fact that a capability from an enclosing
5237 scope can simply be captured, which has the same semantics
5238 as redeclaring and shadowing with another same-typed capability.
5239 This avoid unnecessary overhead in the most common case, i.e.,
5240 when a closure does not need a different (usually smaller)
5241 set of capabilities. *)
5242 (env, Env.get_local env Typing_coeffects.local_capability_id)
5243 | (_, _) ->
5244 let (env, cap_ty, unsafe_cap_ty) =
5245 Typing_coeffects.type_capability
5247 f.f_ctxs
5248 f.f_unsafe_ctxs
5249 (fst f.f_name)
5251 let (env, _) =
5252 Typing_coeffects.register_capabilities env cap_ty unsafe_cap_ty
5254 (env, cap_ty)
5256 let ft = { ft with ft_implicit_params = { capability = CapTy capability } } in
5257 let env = Env.clear_params env in
5258 let non_variadic_ft_params =
5259 if get_ft_variadic ft then
5260 List.drop_last_exn ft.ft_params
5261 else
5262 ft.ft_params
5264 let make_variadic_arg env varg tyl =
5265 let remaining_types =
5266 (* It's possible the variadic arg will capture the variadic
5267 * parameter of the supplied arity (if arity is Fvariadic)
5268 * and additional supplied params.
5270 * For example in cases such as:
5271 * lambda1 = (int $a, string...$c) ==> {};
5272 * lambda1(1, "hello", ...$y); (where $y is a variadic string)
5273 * lambda1(1, "hello", "world");
5274 * then ...$c will contain "hello" and everything in $y in the first
5275 * example, and "hello" and "world" in the second example.
5277 * To account for a mismatch in arity, we take the remaining supplied
5278 * parameters and return a list of all their types. We'll use this
5279 * to create a union type when creating the typed variadic arg.
5281 let remaining_params =
5282 List.drop non_variadic_ft_params (List.length f.f_params - 1)
5284 List.map ~f:(fun param -> param.fp_type.et_type) remaining_params
5286 let r = Reason.Rvar_param varg.param_pos in
5287 let union = Tunion (tyl @ remaining_types) in
5288 let (env, t_param) = closure_bind_variadic env varg (mk (r, union)) in
5289 (env, [t_param])
5291 let (env, t_variadic_params) =
5292 match
5293 ( List.find f.f_params ~f:(fun p -> p.param_is_variadic),
5294 get_ft_variadic ft )
5295 with
5296 | (Some arg, true) ->
5297 make_variadic_arg env arg [(List.last_exn ft.ft_params).fp_type.et_type]
5298 | (Some arg, false) -> make_variadic_arg env arg []
5299 | (_, _) -> (env, [])
5301 let non_variadic_params =
5302 List.filter f.f_params ~f:(fun p -> not p.param_is_variadic)
5304 let params = ref non_variadic_params in
5305 let (env, t_params) =
5306 List.fold_left
5307 ~f:(closure_bind_param params)
5308 ~init:(env, [])
5309 (List.map non_variadic_ft_params ~f:(fun x -> x.fp_type.et_type))
5311 (* Check attributes on the lambda *)
5312 let (env, user_attributes) =
5313 attributes_check_def env SN.AttributeKinds.lambda f.f_user_attributes
5315 (* Regard a lambda as supporting dynamic if
5316 * it has the attribute <<__SupportDynamicType>>;
5317 * or its enclosing method, function or class has the attribute <<__SupportDynamicType>>;
5318 * or it must support dynamic because of the expected type
5320 let support_dynamic_type =
5321 Naming_attributes.mem SN.UserAttributes.uaSupportDynamicType user_attributes
5322 || Env.get_support_dynamic_type env
5323 || supportdyn
5325 let env = List.fold_left ~f:closure_bind_opt_param ~init:env !params in
5326 let env =
5327 List.fold_left ~f:closure_check_param ~init:env non_variadic_params
5329 let env =
5330 match el with
5331 | None -> env
5332 | Some x ->
5333 let rec iter l1 l2 =
5334 match (l1, l2) with
5335 | (_, []) -> ()
5336 | ([], _) -> ()
5337 | (x1 :: rl1, (pkx_2, x2) :: rl2) ->
5338 param_modes x1 x2 pkx_2;
5339 iter rl1 rl2
5341 iter non_variadic_ft_params x;
5342 wfold_left2 inout_write_back env non_variadic_ft_params x
5344 let env = Env.set_fn_kind env f.f_fun_kind in
5345 let decl_ty =
5346 Option.map ~f:(Decl_hint.hint env.decl_env) (hint_of_type_hint f.f_ret)
5348 let ret_pos =
5349 match snd f.f_ret with
5350 | Some (ret_pos, _) -> ret_pos
5351 | None -> lambda_pos
5353 let (env, hret) =
5354 match decl_ty with
5355 | None ->
5356 (* Do we have a contextual return type? *)
5357 begin
5358 match ret_ty with
5359 | None -> Typing_return.make_fresh_return_type env ret_pos
5360 | Some ret_ty -> (env, ret_ty)
5362 | Some ret ->
5363 (* If a 'this' type appears it needs to be compatible with the
5364 * late static type
5366 let ety_env =
5367 empty_expand_env_with_on_error
5368 (Env.invalid_type_hint_assert_primary_pos_in_current_decl env)
5370 Typing_return.make_return_type (Phase.localize ~ety_env) env ret
5372 let (env, hret) =
5373 Typing_return.force_return_kind ~is_toplevel:false env ret_pos hret
5375 let ft =
5377 ft with
5378 ft_ret = { ft.ft_ret with et_type = hret };
5379 ft_flags =
5380 Typing_defs_flags.set_bit
5381 Typing_defs_flags.ft_flags_support_dynamic_type
5382 support_dynamic_type
5383 ft.ft_flags;
5386 let env =
5387 Env.set_return
5389 (Typing_return.make_info
5390 ret_pos
5391 f.f_fun_kind
5394 ~is_explicit:(Option.is_some ret_ty)
5395 hret
5396 decl_ty)
5398 let local_tpenv = Env.get_tpenv env in
5399 (* Outer pipe variables aren't available in closures. Note that
5400 * locals are restored by Env.closure after processing the closure
5402 let env =
5403 Env.unset_local env (Local_id.make_unscoped SN.SpecialIdents.dollardollar)
5405 let sound_dynamic_check_saved_env = env in
5406 let (env, tb) = block env nb.fb_ast in
5407 let has_implicit_return = LEnv.has_next env in
5408 let env =
5409 if not has_implicit_return then
5411 else
5412 Typing_return.fun_implicit_return env lambda_pos hret f.f_fun_kind
5414 let has_readonly = Env.get_readonly env in
5415 let env =
5416 Typing_env.set_fun_tast_info env Tast.{ has_implicit_return; has_readonly }
5418 let (env, tparams) = List.map_env env f.f_tparams ~f:type_param in
5419 let params_decl_ty =
5420 List.map decl_ft.ft_params ~f:(fun { fp_type = { et_type; _ }; _ } ->
5421 match get_node et_type with
5422 | Tany _ -> None
5423 | _ -> Some et_type)
5426 TypecheckerOptions.enable_sound_dynamic
5427 (Provider_context.get_tcopt (Env.get_ctx env))
5428 && support_dynamic_type
5429 then
5430 function_dynamically_callable
5431 sound_dynamic_check_saved_env
5433 params_decl_ty
5434 hret;
5435 let tfun_ =
5437 Aast.f_annotation = Env.save local_tpenv env;
5438 Aast.f_readonly_this = f.f_readonly_this;
5439 Aast.f_span = f.f_span;
5440 Aast.f_ret = (hret, hint_of_type_hint f.f_ret);
5441 Aast.f_readonly_ret = f.f_readonly_ret;
5442 Aast.f_name = f.f_name;
5443 Aast.f_tparams = tparams;
5444 Aast.f_where_constraints = f.f_where_constraints;
5445 Aast.f_fun_kind = f.f_fun_kind;
5446 Aast.f_user_attributes = user_attributes;
5447 Aast.f_body = { Aast.fb_ast = tb };
5448 Aast.f_ctxs = f.f_ctxs;
5449 Aast.f_unsafe_ctxs = f.f_unsafe_ctxs;
5450 Aast.f_params = t_params @ t_variadic_params;
5451 Aast.f_external = f.f_external;
5452 Aast.f_doc_comment = f.f_doc_comment;
5455 let ty = mk (Reason.Rwitness lambda_pos, Tfun ft) in
5456 let te =
5457 Tast.make_typed_expr
5458 lambda_pos
5460 (if is_anon then
5461 Aast.Efun (tfun_, idl)
5462 else
5463 Aast.Lfun (tfun_, idl))
5465 let env = Env.set_tyvar_variance env ty in
5466 (env, (te, hret, ft))
5468 (*****************************************************************************)
5469 (* End of anonymous functions & lambdas. *)
5470 (*****************************************************************************)
5472 (*****************************************************************************)
5473 (* Expression trees *)
5474 (*****************************************************************************)
5475 and expression_tree env p et =
5476 let {
5477 et_hint;
5478 et_splices;
5479 et_function_pointers;
5480 et_virtualized_expr;
5481 et_runtime_expr;
5482 et_dollardollar_pos;
5487 (* Slight hack to deal with |> $$ support *)
5488 let env =
5489 match et_dollardollar_pos with
5490 | Some dd_pos ->
5491 let dollardollar_var =
5492 Local_id.make_unscoped SN.ExpressionTrees.dollardollarTmpVar
5494 let dd_var = Local_id.make_unscoped SN.SpecialIdents.dollardollar in
5495 let dd_defined = Env.is_local_defined env dd_var in
5496 if not dd_defined then
5497 let () =
5498 Errors.add_naming_error
5499 @@ Naming_error.Undefined
5501 pos = dd_pos;
5502 var_name = SN.SpecialIdents.dollardollar;
5503 did_you_mean = None;
5506 let nothing_ty = MakeType.nothing Reason.Rnone in
5507 Env.set_local env dollardollar_var nothing_ty Pos.none
5508 else
5509 let (dd_ty, dd_pos) = Env.get_local_pos env dd_var in
5510 Env.set_local env dollardollar_var dd_ty dd_pos
5511 | None -> env
5514 (* Given the expression tree literal:
5516 MyVisitor`1 + ${ foo() }`
5518 First, type check the expressions that are spliced in, so foo() in
5519 this example. *)
5520 let (env, t_splices) = block env et_splices in
5522 (* Next, typecheck the function pointer assignments *)
5523 let (env, _, t_function_pointers) =
5524 Typing_env.with_in_expr_tree env true (fun env ->
5525 let (env, t_function_pointers) = block env et_function_pointers in
5526 (env, (), t_function_pointers))
5529 (* Type check the virtualized expression, which will look
5530 roughly like this:
5532 function() {
5533 $0splice0 = foo();
5534 return MyVisitor::intType()->__plus($0splice0);
5537 let (env, t_virtualized_expr, ty_virtual) =
5538 Typing_env.with_in_expr_tree env true (fun env ->
5539 expr env et_virtualized_expr ~allow_awaitable:false)
5542 (* Given the runtime expression:
5544 MyVisitor::makeTree(...)
5546 add the inferred type as a type parameter:
5548 MyVisitor::makeTree<MyVisitorInt>(...)
5550 and then typecheck. *)
5551 let (env, runtime_expr) =
5552 maketree_with_type_param env p et_runtime_expr ty_virtual
5554 let (env, t_runtime_expr, ty_runtime_expr) =
5555 expr env runtime_expr ~allow_awaitable:false
5558 make_result
5561 (Aast.ExpressionTree
5563 et_hint;
5564 et_splices = t_splices;
5565 et_function_pointers = t_function_pointers;
5566 et_virtualized_expr = t_virtualized_expr;
5567 et_runtime_expr = t_runtime_expr;
5568 et_dollardollar_pos;
5570 ty_runtime_expr
5572 and et_splice env p e =
5573 let (env, te, ty) = expr env e ~allow_awaitable:(*?*) false in
5574 let (env, ty_visitor) = Env.fresh_type env p in
5575 let (env, ty_res) = Env.fresh_type env p in
5576 let (env, ty_infer) = Env.fresh_type env p in
5577 let spliceable_type =
5578 MakeType.spliceable (Reason.Rsplice p) ty_visitor ty_res ty_infer
5580 let env =
5581 SubType.sub_type
5584 spliceable_type
5585 (Typing_error.Reasons_callback.unify_error_at p)
5587 make_result env p (Aast.ET_Splice te) ty_infer
5589 (*****************************************************************************)
5590 (* End expression trees *)
5591 (*****************************************************************************)
5592 and new_object
5593 ~(expected : ExpectedTy.t option)
5594 ~check_parent
5595 ~check_not_abstract
5596 ~is_using_clause
5600 explicit_targs
5602 unpacked_element =
5603 (* Obtain class info from the cid expression. We get multiple
5604 * results with a CIexpr that has a union type, e.g. in
5606 $classname = (mycond()? classname<A>: classname<B>);
5607 new $classname();
5609 let (env, tal, tcid, classes) =
5610 instantiable_cid ~exact:Exact p env cid explicit_targs
5612 let allow_abstract_bound_generic =
5613 match tcid with
5614 | (ty, _, Aast.CI (_, tn)) -> is_generic_equal_to tn ty
5615 | _ -> false
5617 let gather
5618 (env, _tel, _typed_unpack_element, should_forget_fakes_acc)
5619 (cname, class_info, c_ty) =
5621 check_not_abstract
5622 && Cls.abstract class_info
5623 && (not (requires_consistent_construct cid))
5624 && not allow_abstract_bound_generic
5625 then
5626 uninstantiable_error
5630 (Cls.pos class_info)
5631 (Cls.name class_info)
5633 c_ty;
5634 let (env, obj_ty_, params) =
5635 let (env, c_ty) = Env.expand_type env c_ty in
5636 match (cid, tal, get_class_type c_ty) with
5637 (* Explicit type arguments *)
5638 | (CI _, _ :: _, Some (_, _, tyl)) -> (env, get_node c_ty, tyl)
5639 | (_, _, class_type_opt) ->
5640 let (env, params) =
5641 List.map_env env (Cls.tparams class_info) ~f:(fun env tparam ->
5642 let (env, tvar) =
5643 Env.fresh_type_reason
5646 (Reason.Rtype_variable_generics
5647 (p, snd tparam.tp_name, strip_ns (snd cname)))
5649 Typing_log.log_new_tvar_for_new_object env p tvar cname tparam;
5650 (env, tvar))
5652 begin
5653 match class_type_opt with
5654 | Some (_, Exact, _) -> (env, Tclass (cname, Exact, params), params)
5655 | _ -> (env, Tclass (cname, Nonexact, params), params)
5659 (not check_parent)
5660 && (not is_using_clause)
5661 && Typing_disposable.is_disposable_class env class_info
5662 then
5663 Errors.add_typing_error
5664 Typing_error.(primary @@ Primary.Invalid_new_disposable p);
5665 let r_witness = Reason.Rwitness p in
5666 let obj_ty = mk (r_witness, obj_ty_) in
5667 let c_ty =
5668 match cid with
5669 | CIstatic
5670 | CIexpr _ ->
5671 mk (r_witness, get_node c_ty)
5672 | _ -> obj_ty
5674 let (env, new_ty) =
5675 let (cid_ty, _, _) = tcid in
5676 let (env, cid_ty) = Env.expand_type env cid_ty in
5677 if is_generic cid_ty then
5678 (env, cid_ty)
5679 else if check_parent then
5680 (env, c_ty)
5681 else
5682 ExprDepTy.make env ~cid c_ty
5684 (* Set variance according to type of `new` expression now. Lambda arguments
5685 * to the constructor might depend on it, and `call_construct` only uses
5686 * `ctor_fty` to set the variance which has void return type *)
5687 let env = Env.set_tyvar_variance env new_ty in
5688 let (env, tel, typed_unpack_element, ctor_fty, should_forget_fakes) =
5689 let env = check_expected_ty "New" env new_ty expected in
5690 call_construct p env class_info params el unpacked_element cid new_ty
5692 let should_forget_fakes_acc =
5693 should_forget_fakes_acc || should_forget_fakes
5695 (if equal_consistent_kind (snd (Cls.construct class_info)) Inconsistent then
5696 match cid with
5697 | CIstatic ->
5698 let (class_pos, class_name) = cname in
5699 Errors.add_typing_error
5700 Typing_error.(
5701 primary
5702 @@ Primary.New_inconsistent_construct
5703 { pos = p; class_name; class_pos; kind = `static })
5704 | CIexpr _ ->
5705 let (class_pos, class_name) = cname in
5706 Errors.add_typing_error
5707 Typing_error.(
5708 primary
5709 @@ Primary.New_inconsistent_construct
5710 { pos = p; class_name; class_pos; kind = `classname })
5711 | _ -> ());
5712 match cid with
5713 | CIparent ->
5714 let (env, ctor_fty) =
5715 match fst (Cls.construct class_info) with
5716 | Some ({ ce_type = (lazy ty); _ } as ce) ->
5717 let ety_env =
5719 empty_expand_env with
5720 substs =
5721 TUtils.make_locl_subst_for_class_tparams class_info params;
5722 this_ty = obj_ty;
5725 if get_ce_abstract ce then
5726 Errors.add_typing_error
5727 Typing_error.(
5728 primary
5729 @@ Primary.Parent_abstract_call
5731 meth_name = SN.Members.__construct;
5732 pos = p;
5733 decl_pos = get_pos ctor_fty;
5735 let (env, ctor_fty) = Phase.localize ~ety_env env ty in
5736 (env, ctor_fty)
5737 | None -> (env, ctor_fty)
5739 ( (env, tel, typed_unpack_element, should_forget_fakes_acc),
5740 (obj_ty, ctor_fty) )
5741 | CIstatic
5742 | CI _
5743 | CIself ->
5744 ( (env, tel, typed_unpack_element, should_forget_fakes_acc),
5745 (c_ty, ctor_fty) )
5746 | CIexpr _ ->
5747 (* When constructing from a (classname) variable, the variable
5748 * dictates what the constructed object is going to be. This allows
5749 * for generic and dependent types to be correctly carried
5750 * through the 'new $foo()' iff the constructed obj_ty is a
5751 * supertype of the variable-dictated c_ty *)
5752 let env =
5753 Typing_ops.sub_type
5755 Reason.URnone
5757 c_ty
5758 obj_ty
5759 Typing_error.Callback.unify_error
5761 ( (env, tel, typed_unpack_element, should_forget_fakes_acc),
5762 (c_ty, ctor_fty) )
5764 let (had_dynamic, classes) =
5765 List.fold classes ~init:(false, []) ~f:(fun (seen_dynamic, classes) -> function
5766 | `Dynamic -> (true, classes)
5767 | `Class (cname, class_info, c_ty) ->
5768 (seen_dynamic, (cname, class_info, c_ty) :: classes))
5770 let ( (env, tel, typed_unpack_element, should_forget_fakes),
5771 class_types_and_ctor_types ) =
5772 List.fold_map classes ~init:(env, [], None, false) ~f:gather
5774 let class_types_and_ctor_types =
5775 let r = Reason.Rdynamic_construct p in
5776 let dyn = (mk (r, Tdynamic), mk (r, Tdynamic)) in
5777 if had_dynamic then
5778 dyn :: class_types_and_ctor_types
5779 else
5780 class_types_and_ctor_types
5782 let (env, tel, typed_unpack_element, ty, ctor_fty) =
5783 match class_types_and_ctor_types with
5784 | [] ->
5785 let (env, tel, _) =
5786 argument_list_exprs (expr ~allow_awaitable:false) env el
5788 let (env, typed_unpack_element, _) =
5789 match unpacked_element with
5790 | None -> (env, None, MakeType.nothing Reason.Rnone)
5791 | Some unpacked_element ->
5792 let (env, e, ty) =
5793 expr env unpacked_element ~allow_awaitable:(*?*) false
5795 (env, Some e, ty)
5797 let r = Reason.Runknown_class p in
5798 let terr = TUtils.terr env r in
5799 (env, tel, typed_unpack_element, terr, terr)
5800 | [(ty, ctor_fty)] -> (env, tel, typed_unpack_element, ty, ctor_fty)
5801 | l ->
5802 let (tyl, ctyl) = List.unzip l in
5803 let r = Reason.Rwitness p in
5804 (env, tel, typed_unpack_element, mk (r, Tunion tyl), mk (r, Tunion ctyl))
5806 let (env, new_ty) =
5807 let (cid_ty, _, _) = tcid in
5808 let (env, cid_ty) = Env.expand_type env cid_ty in
5809 if is_generic cid_ty then
5810 (env, cid_ty)
5811 else if check_parent then
5812 (env, ty)
5813 else
5814 ExprDepTy.make env ~cid ty
5816 ( env,
5817 tcid,
5818 tal,
5819 tel,
5820 typed_unpack_element,
5821 new_ty,
5822 ctor_fty,
5823 should_forget_fakes )
5825 and attributes_check_def env kind attrs =
5826 let new_object attr_pos env attr_cid params =
5827 let (env, _, _, _, _, _, _, _) =
5828 new_object
5829 ~expected:None
5830 ~check_parent:false
5831 ~check_not_abstract:false
5832 ~is_using_clause:false
5833 attr_pos
5835 (Aast.CI (Positioned.unsafe_to_raw_positioned attr_cid))
5837 (List.map ~f:(fun e -> (Ast_defs.Pnormal, e)) params)
5838 (* list of attr parameter literals *)
5839 None
5840 (* no variadic arguments *)
5844 let env = Typing_attributes.check_def env new_object kind attrs in
5845 List.map_env env attrs ~f:user_attribute
5847 (** Get class infos for a class expression (e.g. `parent`, `self` or
5848 regular classnames) - which might resolve to a union or intersection
5849 of classes - and check they are instantiable.
5851 FIXME: we need to separate our instantiability into two parts. Currently,
5852 all this function is doing is checking if a given type is inhabited --
5853 that is, whether there are runtime values of type Aast. However,
5854 instantiability should be the stricter notion that T has a runtime
5855 constructor; that is, `new T()` should be valid. In particular, interfaces
5856 are inhabited, but not instantiable.
5857 To make this work with classname, we likely need to add something like
5858 concrete_classname<T>, where T cannot be an interface. *)
5859 and instantiable_cid ?(exact = Nonexact) p env cid explicit_targs :
5860 newable_class_info =
5861 let (env, tal, te, classes) =
5862 class_id_for_new ~exact p env cid explicit_targs
5864 List.iter classes ~f:(function
5865 | `Dynamic -> ()
5866 | `Class ((pos, name), class_info, c_ty) ->
5867 let pos = Pos_or_decl.unsafe_to_raw_pos pos in
5868 let kind = Cls.kind class_info in
5870 Ast_defs.is_c_trait kind
5871 || Ast_defs.is_c_enum kind
5872 || Ast_defs.is_c_enum_class kind
5873 then
5874 match cid with
5875 | CIexpr _
5876 | CI _ ->
5877 uninstantiable_error env p cid (Cls.pos class_info) name pos c_ty
5878 | CIstatic
5879 | CIparent
5880 | CIself ->
5882 else if Ast_defs.is_c_abstract kind && Cls.final class_info then
5883 uninstantiable_error env p cid (Cls.pos class_info) name pos c_ty
5884 else
5885 ());
5886 (env, tal, te, classes)
5888 (* Deal with assignment of a value of type ty2 to lvalue e1 *)
5889 and assign p env e1 pos2 ty2 =
5890 assign_with_subtype_err_ p Reason.URassign env e1 pos2 ty2
5892 and assign_ p ur env e1 pos2 ty2 =
5893 let (env, te, ty, _err) = assign_with_subtype_err_ p ur env e1 pos2 ty2 in
5894 (env, te, ty)
5896 and assign_with_subtype_err_ p ur env (e1 : Nast.expr) pos2 ty2 =
5897 match e1 with
5898 | (_, _, Hole (e, _, _, _)) -> assign_with_subtype_err_ p ur env e pos2 ty2
5899 | _ ->
5900 let allow_awaitable = (*?*) false in
5901 let env =
5902 match e1 with
5903 | (_, _, Lvar (_, x)) ->
5904 Env.forget_prefixed_members env x Reason.(Blame (p, BSassignment))
5905 (* If we ever extend fake members from $x->a to more complicated lvalues
5906 such as $x->a->b, we would need to call forget_prefixed_members on
5907 other lvalues as well. *)
5908 | (_, _, Obj_get (_, (_, _, Id (_, property)), _, _)) ->
5909 Env.forget_suffixed_members
5911 property
5912 Reason.(Blame (p, BSassignment))
5913 | _ -> env
5915 (match e1 with
5916 | (_, _, Lvar ((_, x) as id)) ->
5917 let env = set_valid_rvalue p env x ty2 in
5918 let (_, p1, _) = e1 in
5919 let (env, te, ty) = make_result env p1 (Aast.Lvar id) ty2 in
5920 (env, te, ty, None)
5921 | (_, _, Lplaceholder id) ->
5922 let placeholder_ty = MakeType.void (Reason.Rplaceholder p) in
5923 let (_, p1, _) = e1 in
5924 let (env, te, ty) =
5925 make_result env p1 (Aast.Lplaceholder id) placeholder_ty
5927 (env, te, ty, None)
5928 | (_, _, List el) ->
5929 (* Generate fresh types for each lhs list element, then subtype against
5930 rhs type *)
5931 let (env, tyl) =
5932 List.map_env env el ~f:(fun env (_, p, _e) -> Env.fresh_type env p)
5934 let (_, p1, _) = e1 in
5935 let destructure_ty =
5936 MakeType.list_destructure (Reason.Rdestructure p1) tyl
5938 let lty2 = LoclType ty2 in
5939 let assign_accumulate (env, tel, errs) (lvalue : Nast.expr) ty2 =
5940 let (env, te, _, err_opt) = assign p env lvalue pos2 ty2 in
5941 (env, te :: tel, err_opt :: errs)
5943 let type_list_elem env =
5944 let (env, reversed_tel, rev_subtype_errs) =
5945 List.fold2_exn el tyl ~init:(env, [], []) ~f:assign_accumulate
5947 let (_, p1, _) = e1 in
5948 let (env, te, ty) =
5949 make_result env p1 (Aast.List (List.rev reversed_tel)) ty2
5951 (env, te, ty, List.rev rev_subtype_errs)
5954 (* Here we attempt to unify the type of the rhs we assigning with
5955 a number of fresh tyvars corresponding to the arity of the lhs `list`
5957 if we have a failure in subtyping the fresh tyvars in `destructure_ty`,
5958 we have a rhs which cannot be destructured to the variables on the lhs;
5959 e.g. `list($x,$y) = 2` or `list($x,$y) = tuple (1,2,3)`
5961 in the error case, we add a `Hole` with expected type `nothing` since
5962 there is no type we can suggest was expected
5964 in the ok case were the destrucutring succeeded, the fresh vars
5965 now have types so we can subtype each element, accumulate the errors
5966 and pack back into the rhs structure as our expected type *)
5967 Result.fold
5968 ~ok:(fun env ->
5969 let (env, te, ty, subty_errs) = type_list_elem env in
5970 let err_opt =
5971 if List.for_all subty_errs ~f:Option.is_none then
5972 None
5973 else
5974 Some (ty2, pack_errs pos2 ty2 (subty_errs, None))
5976 (env, te, ty, err_opt))
5977 ~error:(fun env ->
5978 let (env, te, ty, _) = type_list_elem env in
5979 let nothing =
5980 MakeType.nothing @@ Reason.Rsolve_fail (Pos_or_decl.of_raw_pos pos2)
5982 (env, te, ty, Some (ty2, nothing)))
5983 @@ Result.map ~f:(fun env -> Env.set_tyvar_variance_i env destructure_ty)
5984 @@ Type.sub_type_i_res
5988 lty2
5989 destructure_ty
5990 Typing_error.Callback.unify_error
5991 | ( _,
5992 pobj,
5993 Obj_get
5994 (obj, (_, pm, Id ((_, member_name) as m)), nullflavor, prop_or_method)
5995 ) ->
5996 let lenv = env.lenv in
5997 let nullsafe =
5998 match nullflavor with
5999 | OG_nullthrows -> None
6000 | OG_nullsafe -> Some (Reason.Rnullsafe_op pobj)
6002 let (env, tobj, obj_ty) =
6003 expr ~accept_using_var:true env obj ~allow_awaitable
6005 let env = might_throw env in
6006 let (_, p1, _) = obj in
6007 let (env, (declared_ty, _tal), lval_err_opt, rval_err_opt) =
6008 TOG.obj_get_with_err
6009 ~obj_pos:p1
6010 ~is_method:false
6011 ~nullsafe
6012 ~inst_meth:false
6013 ~meth_caller:false
6014 ~coerce_from_ty:(Some (p, ur, ty2))
6015 ~explicit_targs:[]
6016 ~class_id:(CIexpr e1)
6017 ~member_id:m
6018 ~on_error:Typing_error.Callback.unify_error
6020 obj_ty
6022 let te1 =
6023 Tast.make_typed_expr
6024 pobj
6025 declared_ty
6026 (Aast.Obj_get
6027 ( hole_on_err ~err_opt:lval_err_opt tobj,
6028 Tast.make_typed_expr pm declared_ty (Aast.Id m),
6029 nullflavor,
6030 prop_or_method ))
6032 let env = { env with lenv } in
6033 begin
6034 match obj with
6035 | (_, _, This)
6036 | (_, _, Lvar _) ->
6037 let (env, local) = Env.FakeMembers.make env obj member_name p in
6038 let (env, refined_ty) =
6039 Inter.intersect env ~r:(Reason.Rwitness p) declared_ty ty2
6041 let env = set_valid_rvalue p env local refined_ty in
6042 (env, te1, ty2, rval_err_opt)
6043 | _ -> (env, te1, ty2, rval_err_opt)
6045 | (_, _, Obj_get _) ->
6046 let lenv = env.lenv in
6047 let no_fakes = LEnv.env_with_empty_fakes env in
6048 let (env, te1, real_type) = lvalue no_fakes e1 in
6049 let (env, exp_real_type) = Env.expand_type env real_type in
6050 let env = { env with lenv } in
6051 let (env, err_opt) =
6052 Result.fold
6053 ~ok:(fun env -> (env, None))
6054 ~error:(fun env -> (env, Some (ty2, exp_real_type)))
6055 @@ Typing_coercion.coerce_type_res
6060 (MakeType.unenforced exp_real_type)
6061 Typing_error.Callback.unify_error
6063 (env, te1, ty2, err_opt)
6064 | (_, _, Class_get (_, CGexpr _, _)) ->
6065 failwith "AST should not have any CGexprs after naming"
6066 | (_, _, Class_get (((_, _, x) as cid), CGstring (pos_member, y), _)) ->
6067 let lenv = env.lenv in
6068 let no_fakes = LEnv.env_with_empty_fakes env in
6069 let (env, te1, _) = lvalue no_fakes e1 in
6070 let env = { env with lenv } in
6071 let (env, ety2) = Env.expand_type env ty2 in
6072 (* This defers the coercion check to class_get, which looks up the appropriate target type *)
6073 let (env, _tal, _, cty) = class_expr env [] cid in
6074 let env = might_throw env in
6075 let (env, (declared_ty, _), rval_err_opt) =
6076 class_get_err
6077 ~is_method:false
6078 ~is_const:false
6079 ~coerce_from_ty:(Some (p, ur, ety2))
6082 (pos_member, y)
6085 let (env, local) = Env.FakeMembers.make_static env x y p in
6086 let (env, refined_ty) =
6087 Inter.intersect env ~r:(Reason.Rwitness p) declared_ty ty2
6089 let env = set_valid_rvalue p env local refined_ty in
6090 (env, te1, ty2, rval_err_opt)
6091 | (_, pos, Array_get (e1, None)) ->
6092 let (env, te1, ty1) = update_array_type pos env e1 `lvalue in
6093 let (_, p1, _) = e1 in
6094 let (env, ty1', arr_err_opt, val_err_opt) =
6095 Typing_array_access.assign_array_append_with_err
6096 ~array_pos:p1
6097 ~expr_pos:p
6103 let (env, te1) =
6104 if is_hack_collection env ty1 then
6105 (env, hole_on_err ~err_opt:arr_err_opt te1)
6106 else
6107 let (env, te1, ty, _) =
6108 assign_with_subtype_err_ p ur env e1 p1 ty1'
6110 (* Update the actual type to that after assignment *)
6111 let arr_err_opt =
6112 Option.map arr_err_opt ~f:(fun (_, ty_expect) -> (ty, ty_expect))
6114 (env, hole_on_err ~err_opt:arr_err_opt te1)
6116 let (env, te, ty) =
6117 make_result env pos (Aast.Array_get (te1, None)) ty2
6119 (env, te, ty, val_err_opt)
6120 | (_, pos, Array_get (e1, Some e)) ->
6121 let (env, te1, ty1) = update_array_type pos env e1 `lvalue in
6122 let (env, te, ty) = expr env e ~allow_awaitable in
6123 let env = might_throw env in
6124 let (_, p1, _) = e1 in
6125 let (env, ty1', arr_err_opt, key_err_opt, val_err_opt) =
6126 Typing_array_access.assign_array_get_with_err
6127 ~array_pos:p1
6128 ~expr_pos:p
6136 let (env, te1) =
6137 if is_hack_collection env ty1 then
6138 (env, hole_on_err ~err_opt:arr_err_opt te1)
6139 else
6140 let (env, te1, ty, _) =
6141 assign_with_subtype_err_ p ur env e1 p1 ty1'
6143 (* Update the actual type to that after assignment *)
6144 let arr_err_opt =
6145 Option.map arr_err_opt ~f:(fun (_, ty_expect) -> (ty, ty_expect))
6147 (env, hole_on_err ~err_opt:arr_err_opt te1)
6149 ( env,
6150 ( ty2,
6151 pos,
6152 Aast.Array_get (te1, Some (hole_on_err ~err_opt:key_err_opt te)) ),
6153 ty2,
6154 val_err_opt )
6155 | _ -> assign_simple p ur env e1 ty2)
6157 and assign_simple pos ur env e1 ty2 =
6158 let (env, te1, ty1) = lvalue env e1 in
6159 let (env, err_opt) =
6160 Result.fold
6161 ~ok:(fun env -> (env, None))
6162 ~error:(fun env -> (env, Some (ty2, ty1)))
6163 @@ Typing_coercion.coerce_type_res
6168 (MakeType.unenforced ty1)
6169 Typing_error.Callback.unify_error
6171 (env, te1, ty2, err_opt)
6173 and array_field env ~allow_awaitable = function
6174 | AFvalue ve ->
6175 let (env, tve, tv) = expr env ve ~allow_awaitable in
6176 (env, (Aast.AFvalue tve, None, tv))
6177 | AFkvalue (ke, ve) ->
6178 let (env, tke, tk) = expr env ke ~allow_awaitable in
6179 let (env, tve, tv) = expr env ve ~allow_awaitable in
6180 (env, (Aast.AFkvalue (tke, tve), Some tk, tv))
6182 and array_value ~(expected : ExpectedTy.t option) env x =
6183 let (env, te, ty) = expr ?expected env x ~allow_awaitable:(*?*) false in
6184 (env, (te, ty))
6186 and arraykey_value
6187 ?(add_hole = false)
6189 class_name
6190 is_set
6191 ~(expected : ExpectedTy.t option)
6193 ((_, pos, _) as x) =
6194 let (env, (te, ty)) = array_value ~expected env x in
6195 let (ty_arraykey, reason) =
6196 if is_set then
6197 ( MakeType.arraykey (Reason.Rset_element pos),
6198 Reason.set_element class_name )
6199 else
6200 (MakeType.arraykey (Reason.Ridx_dict pos), Reason.index_class class_name)
6202 let ty_expected = { et_type = ty_arraykey; et_enforced = Enforced } in
6203 let (env, te) =
6204 if add_hole then
6205 (* If we have an error in coercion here, we will add a `Hole` indicating the
6206 actual and expected type. The `Hole` may then be used in a codemod to
6207 add a call to `UNSAFE_CAST` so we need to consider what type we expect.
6209 If we were to add an expected type of 'arraykey' here it would be
6210 correct but adding an `UNSAFE_CAST<?string,arraykey>($x)` means we
6211 get cascading errors if we have e.g. a return type of keyset<string>.
6213 To try and prevent this, if this is an optional type where the nonnull
6214 part can be coerced to arraykey, we prefer that type as our expected type.
6216 let (ok, ty_actual) =
6217 match deref ty with
6218 | (_, Toption ty_inner) ->
6219 ( (fun env ->
6220 let ty_str = lazy (Typing_print.full_strip_ns env ty_inner) in
6221 let reasons_opt =
6222 Some
6223 (Lazy.map ty_str ~f:(fun ty_str ->
6224 Reason.to_string
6225 "Expected `arraykey`"
6226 (Reason.Ridx_dict pos)
6227 @ [(get_pos ty, Format.sprintf "But got `?%s`" ty_str)]))
6229 (* We actually failed so generate the error we should
6230 have seen *)
6231 Errors.add_typing_error
6232 Typing_error.(
6233 primary
6234 @@ Primary.Unify_error
6236 pos;
6237 msg_opt = Some (Reason.string_of_ureason reason);
6238 reasons_opt;
6240 (env, Some (ty, ty_inner))),
6241 ty_inner )
6242 | _ -> ((fun env -> (env, None)), ty)
6244 let (env, err_opt) =
6245 Result.fold ~ok ~error:(fun env -> (env, Some (ty_actual, ty_arraykey)))
6246 @@ Typing_coercion.coerce_type_res
6247 ~coerce_for_op:true
6249 reason
6251 ty_actual
6252 ty_expected
6253 Typing_error.Callback.unify_error
6255 (env, hole_on_err ~err_opt te)
6256 else
6257 let env =
6258 Typing_coercion.coerce_type
6259 ~coerce_for_op:true
6261 reason
6264 ty_expected
6265 Typing_error.Callback.unify_error
6267 (env, te)
6270 (env, (te, ty))
6272 and check_parent_construct pos env el unpacked_element env_parent =
6273 let check_not_abstract = false in
6274 let (env, env_parent) =
6275 Phase.localize_no_subst env ~ignore_errors:true env_parent
6277 let ( env,
6278 _tcid,
6279 _tal,
6280 tel,
6281 typed_unpack_element,
6282 parent,
6283 fty,
6284 should_forget_fakes ) =
6285 new_object
6286 ~expected:None
6287 ~check_parent:true
6288 ~check_not_abstract
6289 ~is_using_clause:false
6292 CIparent
6295 unpacked_element
6297 (* Not sure why we need to equate these types *)
6298 let env =
6299 Type.sub_type
6301 Reason.URnone
6303 env_parent
6304 parent
6305 Typing_error.Callback.unify_error
6307 let env =
6308 Type.sub_type
6310 Reason.URnone
6312 parent
6313 env_parent
6314 Typing_error.Callback.unify_error
6316 ( env,
6317 tel,
6318 typed_unpack_element,
6319 MakeType.void (Reason.Rwitness pos),
6320 parent,
6321 fty,
6322 should_forget_fakes )
6324 and call_parent_construct pos env el unpacked_element =
6325 match Env.get_parent_ty env with
6326 | Some parent -> check_parent_construct pos env el unpacked_element parent
6327 | None ->
6328 (* continue here *)
6329 let ty = Typing_utils.mk_tany env pos in
6330 let should_invalidate_fake_members = true in
6331 let default = (env, [], None, ty, ty, ty, should_invalidate_fake_members) in
6332 (match Env.get_self_id env with
6333 | Some self ->
6334 (match Env.get_class env self with
6335 | Some trait when Ast_defs.is_c_trait (Cls.kind trait) ->
6336 (match trait_most_concrete_req_class trait env with
6337 | None ->
6338 Errors.add_typing_error
6339 Typing_error.(primary @@ Primary.Parent_in_trait pos);
6340 default
6341 | Some (c, parent_ty) ->
6342 (match Cls.construct c with
6343 | (_, Inconsistent) ->
6344 Errors.add_typing_error
6345 Typing_error.(
6346 primary
6347 @@ Primary.Trait_parent_construct_inconsistent
6348 { pos; decl_pos = Cls.pos c })
6349 | _ -> ());
6350 check_parent_construct pos env el unpacked_element parent_ty)
6351 | Some _self_tc ->
6352 Errors.add_typing_error
6353 Typing_error.(primary @@ Primary.Undefined_parent pos);
6354 default
6355 | None -> assert false)
6356 | None ->
6357 Errors.add_typing_error
6358 Typing_error.(primary @@ Primary.Parent_outside_class pos);
6359 let ty = err_witness env pos in
6360 (env, [], None, ty, ty, ty, should_invalidate_fake_members))
6362 (* Depending on the kind of expression we are dealing with
6363 * The typing of call is different.
6365 and dispatch_call
6366 ~(expected : ExpectedTy.t option)
6367 ~is_using_clause
6368 ~valkind
6369 ?in_await
6372 ((_, fpos, fun_expr) as e : Nast.expr)
6373 explicit_targs
6375 unpacked_element =
6376 let expr = expr ~allow_awaitable:(*?*) false in
6377 let make_call env te tal tel typed_unpack_element ty =
6378 make_result env p (Aast.Call (te, tal, tel, typed_unpack_element)) ty
6380 (match valkind with
6381 | `lvalue
6382 | `lvalue_subexpr ->
6383 Errors.add_typing_error Typing_error.(primary @@ Primary.Call_lvalue p)
6384 | `other -> ());
6385 (* TODO: Avoid Tany annotations in TAST by eliminating `make_call_special` *)
6386 let make_call_special env id tel ty =
6387 make_call
6389 (Tast.make_typed_expr fpos (TUtils.mk_tany env fpos) (Aast.Id id))
6392 None
6395 (* For special functions and pseudofunctions with a definition in an HHI
6396 * file. It is preferred over [make_call_special] because it does not generate
6397 * [TAny] for the function type of the call.
6399 let make_call_special_from_def env id tel ty_ =
6400 let (env, fty, tal) = fun_type_of_id env id explicit_targs el in
6401 let ty =
6402 match get_node fty with
6403 | Tfun ft -> ft.ft_ret.et_type
6404 | _ -> ty_ (Reason.Rwitness p)
6406 make_call env (Tast.make_typed_expr fpos fty (Aast.Id id)) tal tel None ty
6408 let overload_function = overload_function make_call fpos in
6409 (* Require [get_idisposable_value()] function calls to be inside a [using]
6410 statement. *)
6411 let check_disposable_in_return env fty =
6412 if is_return_disposable_fun_type env fty && not is_using_clause then
6413 Errors.add_typing_error
6414 Typing_error.(primary @@ Primary.Invalid_new_disposable p)
6417 let dispatch_id env id =
6418 let (env, fty, tal) = fun_type_of_id env id explicit_targs el in
6419 check_disposable_in_return env fty;
6420 let (env, (tel, typed_unpack_element, ty, should_forget_fakes)) =
6421 call ~expected p env fty el unpacked_element
6423 let result =
6424 make_call
6426 (Tast.make_typed_expr fpos fty (Aast.Id id))
6429 typed_unpack_element
6432 (result, should_forget_fakes)
6434 let dispatch_class_const env ((_, pos, e1_) as e1) m =
6435 let (env, _tal, tcid, ty1) = class_expr env [] e1 in
6436 let this_ty = MakeType.this (Reason.Rwitness fpos) in
6437 (* In static context, you can only call parent::foo() on static methods.
6438 * In instance context, you can call parent:foo() on static
6439 * methods as well as instance methods
6441 let is_static =
6442 (not (Nast.equal_class_id_ e1_ CIparent))
6443 || Env.is_static env
6444 || class_contains_smethod env ty1 m
6446 let (env, (fty, tal)) =
6447 if not is_static then
6448 (* parent::nonStaticFunc() is really weird. It's calling a method
6449 * defined on the parent class, but $this is still the child class.
6451 TOG.obj_get
6452 ~inst_meth:false
6453 ~meth_caller:false
6454 ~is_method:true
6455 ~nullsafe:None
6456 ~obj_pos:pos
6457 ~coerce_from_ty:None
6458 ~explicit_targs:[]
6459 ~class_id:e1_
6460 ~member_id:m
6461 ~on_error:Typing_error.Callback.unify_error
6462 ~parent_ty:ty1
6464 this_ty
6465 else
6466 class_get
6467 ~coerce_from_ty:None
6468 ~is_method:true
6469 ~is_const:false
6470 ~explicit_targs
6476 check_disposable_in_return env fty;
6477 let (env, (tel, typed_unpack_element, ty, should_forget_fakes)) =
6478 call ~expected p env fty el unpacked_element
6480 let result =
6481 make_call
6483 (Tast.make_typed_expr fpos fty (Aast.Class_const (tcid, m)))
6486 typed_unpack_element
6489 (result, should_forget_fakes)
6491 match fun_expr with
6492 (* Special top-level function *)
6493 | Id ((pos, x) as id) when SN.StdlibFunctions.needs_special_dispatch x ->
6494 begin
6495 match x with
6496 (* Special function [echo]. *)
6497 | echo when String.equal echo SN.SpecialFunctions.echo ->
6498 (* TODO(tany): TODO(T92020097):
6499 * Add [function print(arraykey ...$args)[io]: void] to an HHI file and
6500 * remove special casing of [echo] and [print].
6502 let env = Typing_local_ops.enforce_io pos env in
6503 let (env, tel, _) =
6504 argument_list_exprs (expr ~accept_using_var:true) env el
6506 let arraykey_ty = MakeType.arraykey (Reason.Rwitness pos) in
6507 let like_ak_ty =
6508 MakeType.union
6509 (Reason.Rwitness pos)
6510 [MakeType.dynamic (Reason.Rwitness pos); arraykey_ty]
6512 let (env, rev_tel) =
6513 List.fold
6515 ~init:(env, [])
6516 ~f:(fun (env, tel) (pk, ((ty, pos, _) as te)) ->
6517 let (env, err_opt) =
6518 Result.fold
6519 ~ok:(fun env -> (env, None))
6520 ~error:(fun env -> (env, Some (ty, arraykey_ty)))
6521 @@ SubType.sub_type_res
6524 like_ak_ty
6525 (Typing_error.Reasons_callback.invalid_echo_argument_at
6526 pos)
6528 (env, (pk, hole_on_err ~err_opt te) :: tel))
6530 let tel = List.rev rev_tel in
6531 let should_forget_fakes = false in
6532 ( make_call_special env id tel (MakeType.void (Reason.Rwitness pos)),
6533 should_forget_fakes )
6534 (* `unsafe_cast` *)
6535 | unsafe_cast when String.equal unsafe_cast SN.PseudoFunctions.unsafe_cast
6537 let result =
6538 match el with
6539 | [(Ast_defs.Pnormal, original_expr)]
6540 when TypecheckerOptions.ignore_unsafe_cast (Env.get_tcopt env) ->
6541 expr env original_expr
6542 | _ ->
6543 (* first type the `unsafe_cast` as a call, handling arity errors *)
6544 let (env, fty, tal) = fun_type_of_id env id explicit_targs el in
6545 check_disposable_in_return env fty;
6546 let (env, (tel, _, ty, _should_forget_fakes)) =
6547 call ~expected p env fty el unpacked_element
6549 (* construct the `Hole` using default value and type arguments
6550 if necessary *)
6551 let dflt_ty = MakeType.err Reason.none in
6552 let el =
6553 match tel with
6554 | (_, e) :: _ -> e
6555 | [] -> Tast.make_typed_expr fpos dflt_ty Aast.Null
6556 and (ty_from, ty_to) =
6557 match tal with
6558 | (ty_from, _) :: (ty_to, _) :: _ -> (ty_from, ty_to)
6559 | (ty, _) :: _ -> (ty, ty)
6560 | _ -> (dflt_ty, dflt_ty)
6562 let te =
6563 Aast.Hole
6564 (el, ty_from, ty_to, UnsafeCast (List.map ~f:snd explicit_targs))
6566 make_result env p te ty
6568 let should_forget_fakes = false in
6569 (result, should_forget_fakes)
6570 (* Special function `isset` *)
6571 | isset when String.equal isset SN.PseudoFunctions.isset ->
6572 let (env, tel, _) =
6573 argument_list_exprs
6574 (expr ~accept_using_var:true ~check_defined:false)
6578 if Option.is_some unpacked_element then
6579 Errors.add_typing_error
6580 Typing_error.(
6581 primary
6582 @@ Primary.Unpacking_disallowed_builtin_function
6583 { pos = p; fn_name = isset });
6584 let should_forget_fakes = false in
6585 let result = make_call_special_from_def env id tel MakeType.bool in
6586 (result, should_forget_fakes)
6587 (* Special function `unset` *)
6588 | unset when String.equal unset SN.PseudoFunctions.unset ->
6589 let (env, tel, _) = argument_list_exprs expr env el in
6590 if Option.is_some unpacked_element then
6591 Errors.add_typing_error
6592 Typing_error.(
6593 primary
6594 @@ Primary.Unpacking_disallowed_builtin_function
6595 { pos = p; fn_name = unset });
6596 let env = Typing_local_ops.check_unset_target env tel in
6597 let env =
6598 match (el, unpacked_element) with
6599 | ([(Ast_defs.Pnormal, (_, _, Array_get (ea, Some _)))], None) ->
6600 let (env, _te, ty) = expr env ea in
6601 let r = Reason.Rwitness p in
6602 let tmixed = MakeType.mixed r in
6603 let super =
6605 ( r,
6606 Tunion
6608 MakeType.dynamic r;
6609 MakeType.dict r tmixed tmixed;
6610 MakeType.keyset r tmixed;
6611 MakeType.darray r tmixed tmixed;
6614 let reason =
6615 Reason.to_string
6616 ("This is " ^ Typing_print.error ~ignore_dynamic:true env ty)
6617 (get_reason ty)
6619 SubType.sub_type_or_fail env ty super
6620 @@ Some
6621 Typing_error.(
6622 primary @@ Primary.Unset_nonidx_in_strict { pos = p; reason })
6623 | _ ->
6624 (Errors.add_typing_error
6625 @@ Typing_error.(
6626 primary
6627 @@ Primary.Unset_nonidx_in_strict { pos = p; reason = [] }));
6630 let should_forget_fakes = false in
6631 let result =
6632 match el with
6633 | [(_, (_, p, Obj_get (_, _, OG_nullsafe, _)))] ->
6634 (Errors.add_typing_error
6635 @@ Typing_error.(
6636 primary @@ Primary.Nullsafe_property_write_context p));
6637 make_call_special_from_def env id tel (TUtils.terr env)
6638 | _ -> make_call_special_from_def env id tel MakeType.void
6640 (result, should_forget_fakes)
6641 | type_structure
6642 when String.equal type_structure SN.StdlibFunctions.type_structure
6643 && Int.equal (List.length el) 2
6644 && Option.is_none unpacked_element ->
6645 let should_forget_fakes = false in
6646 (match el with
6647 | [e1; e2] ->
6648 (match e2 with
6649 | (_, (_, p, String cst)) ->
6650 (* find the class constant implicitly defined by the typeconst *)
6651 let cid =
6652 match e1 with
6653 | (_, (_, _, Class_const (cid, (_, x))))
6654 | (_, (_, _, Class_get (cid, CGstring (_, x), _)))
6655 when String.equal x SN.Members.mClass ->
6657 | _ ->
6658 let (_, ((_, p1, _) as e1_)) = e1 in
6659 ((), p1, CIexpr e1_)
6661 let result = class_const ~incl_tc:true env p (cid, (p, cst)) in
6662 (result, should_forget_fakes)
6663 | _ ->
6664 Errors.add_typing_error
6665 Typing_error.(primary @@ Primary.Illegal_type_structure pos);
6666 let result = expr_error env (Reason.Rwitness pos) e in
6667 (result, should_forget_fakes))
6668 | _ -> assert false)
6669 | _ -> dispatch_id env id
6671 (* Special Shapes:: function *)
6672 | Class_const (((_, _, CI (_, shapes)) as class_id), ((_, x) as method_id))
6673 when String.equal shapes SN.Shapes.cShapes
6674 || String.equal shapes SN.Shapes.cReadonlyShapes ->
6675 begin
6676 match x with
6677 (* Special function `Shapes::idx` *)
6678 | idx when String.equal idx SN.Shapes.idx ->
6679 overload_function
6682 class_id
6683 method_id
6685 unpacked_element
6686 (fun env fty res el tel ->
6687 match (el, tel) with
6688 | (_, [(_, (shape_ty, shape_pos, _)); (_, field)]) ->
6689 Typing_shapes.idx
6691 shape_ty
6692 field
6693 None
6694 ~expr_pos:p
6695 ~fun_pos:(get_reason fty)
6696 ~shape_pos
6697 | ( [_; _; (_, default)],
6699 (_, (shape_ty, shape_pos, _));
6700 (_, field);
6701 (_, (_, default_pos, _));
6702 ] ) ->
6703 (* We reevaluate the default argument rather than using the one
6704 evaluated during the typechecking wrt to the overloaded
6705 function signature in the HHI file because bidirectional
6706 typechecking introduces TAnys to the system otherwise. *)
6707 let (env, _td, default_ty) = expr env default in
6708 Typing_shapes.idx
6710 shape_ty
6711 field
6712 (Some (default_pos, default_ty))
6713 ~expr_pos:p
6714 ~fun_pos:(get_reason fty)
6715 ~shape_pos
6716 | _ -> (env, res))
6717 (* Special function `Shapes::at` *)
6718 | at when String.equal at SN.Shapes.at ->
6719 overload_function
6722 class_id
6723 method_id
6725 unpacked_element
6726 (fun env _fty res _el tel ->
6727 match tel with
6728 | [(_, (shape_ty, shape_pos, _)); (_, field)] ->
6729 Typing_shapes.at env ~expr_pos:p ~shape_pos shape_ty field
6730 | _ -> (env, res))
6731 (* Special function `Shapes::keyExists` *)
6732 | key_exists when String.equal key_exists SN.Shapes.keyExists ->
6733 overload_function
6736 class_id
6737 method_id
6739 unpacked_element
6740 (fun env fty res _el tel ->
6741 match tel with
6742 | [(_, (shape_ty, shape_pos, _)); (_, field)] ->
6743 (* try accessing the field, to verify existence, but ignore
6744 * the returned type and keep the one coming from function
6745 * return type hint *)
6746 let (env, _) =
6747 Typing_shapes.idx
6749 shape_ty
6750 field
6751 None
6752 ~expr_pos:p
6753 ~fun_pos:(get_reason fty)
6754 ~shape_pos
6756 (env, res)
6757 | _ -> (env, res))
6758 (* Special function `Shapes::removeKey` *)
6759 | remove_key when String.equal remove_key SN.Shapes.removeKey ->
6760 overload_function
6763 class_id
6764 method_id
6766 unpacked_element
6767 (fun env _ res el _tel ->
6768 match el with
6769 | [(Ast_defs.Pinout _, shape); (_, field)] ->
6770 begin
6771 match shape with
6772 | (_, _, Lvar (_, lvar))
6773 | (_, _, Hole ((_, _, Lvar (_, lvar)), _, _, _)) ->
6774 (* We reevaluate the shape instead of using the shape type
6775 evaluated during typechecking against the HHI signature
6776 because this argument is inout and bidirectional
6777 typechecking causes a union with the open shape type
6778 which defeats the purpose of this extra-logical function.
6780 let (env, _te, shape_ty) = expr env shape in
6781 let (env, shape_ty) =
6782 Typing_shapes.remove_key p env shape_ty field
6784 let env = set_valid_rvalue p env lvar shape_ty in
6785 (env, res)
6786 | (_, shape_pos, _) ->
6787 Errors.add_typing_error
6788 Typing_error.(
6789 shape @@ Primary.Shape.Invalid_shape_remove_key shape_pos);
6790 (env, res)
6792 | _ -> (env, res))
6793 (* Special function `Shapes::toArray` *)
6794 | to_array when String.equal to_array SN.Shapes.toArray ->
6795 overload_function
6798 class_id
6799 method_id
6801 unpacked_element
6802 (fun env _ res _el tel ->
6803 match tel with
6804 | [(_, (shape_ty, _, _))] ->
6805 Typing_shapes.to_array env p shape_ty res
6806 | _ -> (env, res))
6807 (* Special function `Shapes::toDict` *)
6808 | to_dict when String.equal to_dict SN.Shapes.toDict ->
6809 overload_function
6812 class_id
6813 method_id
6815 unpacked_element
6816 (fun env _ res _el tel ->
6817 match tel with
6818 | [(_, (shape_ty, _, _))] ->
6819 Typing_shapes.to_dict env p shape_ty res
6820 | _ -> (env, res))
6821 | _ -> dispatch_class_const env class_id method_id
6823 (* Special function `parent::__construct` *)
6824 | Class_const ((_, pos, CIparent), ((_, construct) as id))
6825 when String.equal construct SN.Members.__construct ->
6826 let (env, tel, typed_unpack_element, ty, pty, ctor_fty, should_forget_fakes)
6828 call_parent_construct p env el unpacked_element
6830 let result =
6831 make_call
6833 (Tast.make_typed_expr
6834 fpos
6835 ctor_fty
6836 (Aast.Class_const ((pty, pos, Aast.CIparent), id)))
6837 [] (* tal: no type arguments to constructor *)
6839 typed_unpack_element
6842 (result, should_forget_fakes)
6843 (* Calling parent / class method *)
6844 | Class_const (class_id, m) -> dispatch_class_const env class_id m
6845 (* Readonly Expressions do not affect the type, but need to be threaded through when they're part of a call *)
6846 | ReadonlyExpr r ->
6847 let env = Env.set_readonly env true in
6848 (* Recurse onto the inner call *)
6849 let ((env, expr, ty), s) =
6850 dispatch_call
6851 ~expected
6852 ~is_using_clause
6853 ~valkind
6854 ?in_await
6858 explicit_targs
6860 unpacked_element
6862 (match expr with
6863 | (ty, _, Call (caller, tal, tel, c)) ->
6864 let (caller_ty, caller_pos, _) = caller in
6865 (* Rewrap the caller in the readonly expression after we're done *)
6866 let wrapped_caller =
6867 Tast.make_typed_expr caller_pos caller_ty (Aast.ReadonlyExpr caller)
6869 let result = make_call env wrapped_caller tal tel c ty in
6870 (result, s)
6871 | _ -> ((env, expr, ty), s))
6872 (* Call instance method *)
6873 | Obj_get (e1, (_, pos_id, Id m), nullflavor, Is_method)
6874 when not (TypecheckerOptions.method_call_inference (Env.get_tcopt env)) ->
6875 let (env, te1, ty1) = expr ~accept_using_var:true env e1 in
6876 let nullsafe =
6877 match nullflavor with
6878 | OG_nullthrows -> None
6879 | OG_nullsafe -> Some p
6881 let (_, p1, _) = e1 in
6882 let (env, (tfty, tal), lval_err_opt, _rval_err_opt) =
6883 TOG.obj_get_with_err
6884 ~obj_pos:p1
6885 ~is_method:true
6886 ~inst_meth:false
6887 ~meth_caller:false
6888 ~nullsafe:(Option.map ~f:(fun p -> Reason.Rnullsafe_op p) nullsafe)
6889 ~coerce_from_ty:None
6890 ~explicit_targs
6891 ~class_id:(CIexpr e1)
6892 ~member_id:m
6893 ~on_error:Typing_error.Callback.unify_error
6897 check_disposable_in_return env tfty;
6898 let (env, (tel, typed_unpack_element, ty, should_forget_fakes)) =
6899 call ~nullsafe ~expected p env tfty el unpacked_element
6901 let result =
6902 make_call
6904 (Tast.make_typed_expr
6905 fpos
6906 tfty
6907 (Aast.Obj_get
6908 ( hole_on_err ~err_opt:lval_err_opt te1,
6909 Tast.make_typed_expr pos_id tfty (Aast.Id m),
6910 nullflavor,
6911 Is_method )))
6914 typed_unpack_element
6917 (result, should_forget_fakes)
6918 (* Call instance method using new method call inference *)
6919 | Obj_get (receiver, (_, pos_id, Id meth), nullflavor, Is_method) ->
6920 (*****
6921 Typecheck `Obj_get` by enforcing that:
6922 - `<instance_type>` <: `Thas_member(m, #1)`
6923 where #1 is a fresh type variable.
6924 *****)
6925 let (env, typed_receiver, receiver_ty) =
6926 expr ~accept_using_var:true env receiver
6928 let env = might_throw env in
6929 let nullsafe =
6930 match nullflavor with
6931 | OG_nullthrows -> None
6932 | OG_nullsafe -> Some p
6934 (* Generate a fresh type `method_ty` for the type of the
6935 instance method, i.e. #1 *)
6936 let (env, method_ty) = Env.fresh_type env p in
6937 (* Create `Thas_member` constraint type *)
6938 let (_, receiver_p, _) = receiver in
6939 let reason = Reason.Rwitness receiver_p in
6940 let has_method_ty =
6941 MakeType.has_member
6942 reason
6943 ~name:meth
6944 ~ty:method_ty
6945 ~class_id:(CIexpr receiver)
6946 ~explicit_targs:(Some explicit_targs)
6948 let env = Env.set_tyvar_variance env method_ty in
6949 let (env, has_method_super_ty) =
6950 if Option.is_none nullsafe then
6951 (env, has_method_ty)
6952 else
6953 (* If null-safe, then `receiver_ty` <: `?Thas_member(m, #1)`,
6954 but *unlike* property access typing in `expr_`, we still use `#1` as
6955 our "result" if `receiver_ty` is nullable (as opposed to `?#1`),
6956 deferring null-safety handling to after `call` *)
6957 let r = Reason.Rnullsafe_op p in
6958 let null_ty = MakeType.null r in
6959 Union.union_i env r has_method_ty null_ty
6961 let (_, receiver_pos, _) = receiver in
6962 let env_res =
6963 Type.sub_type_i_res
6964 receiver_pos
6965 Reason.URnone
6967 (LoclType receiver_ty)
6968 has_method_super_ty
6969 Typing_error.Callback.unify_error
6971 let ty_nothing = MakeType.nothing Reason.none in
6972 let (env, err_opt) =
6973 Result.fold
6974 env_res
6975 ~ok:(fun env -> (env, None))
6976 ~error:(fun env -> (env, Some (receiver_ty, ty_nothing)))
6979 (* Perhaps solve for `method_ty`. Opening and closing a scope is too coarse
6980 here - type parameters are localised to fresh type variables over the
6981 course of subtyping above, and we do not want to solve these until later.
6982 Once we typecheck all function calls with a subtyping of function types,
6983 we should not need to solve early at all - transitive closure of
6984 subtyping should give enough information. *)
6985 let env =
6986 match get_var method_ty with
6987 | Some var ->
6988 Typing_solver.solve_to_equal_bound_or_wrt_variance env Reason.Rnone var
6989 | None -> env
6991 let localize_targ env (_, targ) = Phase.localize_targ env targ in
6992 let (env, typed_targs) =
6993 List.map_env env ~f:(localize_targ ~check_well_kinded:true) explicit_targs
6995 check_disposable_in_return env method_ty;
6996 let (env, (typed_params, typed_unpack_element, ret_ty, should_forget_fakes))
6998 call ~nullsafe ~expected ?in_await p env method_ty el unpacked_element
7000 (* If the call is nullsafe AND the receiver is nullable,
7001 make the return type nullable too *)
7002 let (env, ret_ty) =
7003 if Option.is_some nullsafe then
7004 let r = Reason.Rnullsafe_op p in
7005 let null_ty = MakeType.null r in
7006 let (env, null_or_nothing_ty) =
7007 Inter.intersect env ~r null_ty receiver_ty
7009 let (env, ret_option_ty) = Union.union env null_or_nothing_ty ret_ty in
7010 (env, ret_option_ty)
7011 else
7012 (env, ret_ty)
7014 let result =
7015 make_call
7017 (Tast.make_typed_expr
7018 fpos
7019 method_ty
7020 (Aast.Obj_get
7021 ( hole_on_err ~err_opt typed_receiver,
7022 Tast.make_typed_expr pos_id method_ty (Aast.Id meth),
7023 nullflavor,
7024 Is_method )))
7025 typed_targs
7026 typed_params
7027 typed_unpack_element
7028 ret_ty
7030 (result, should_forget_fakes)
7031 (* Function invocation *)
7032 | Fun_id x ->
7033 let (env, fty, tal) = fun_type_of_id env x explicit_targs el in
7034 check_disposable_in_return env fty;
7035 let (env, (tel, typed_unpack_element, ty, should_forget_fakes)) =
7036 call ~expected p env fty el unpacked_element
7038 let result =
7039 make_call
7041 (Tast.make_typed_expr fpos fty (Aast.Fun_id x))
7044 typed_unpack_element
7047 (result, should_forget_fakes)
7048 | Id id -> dispatch_id env id
7049 | _ ->
7050 let (env, te, fty) = expr env e in
7051 let (env, fty) =
7052 Typing_solver.expand_type_and_solve
7053 ~description_of_expected:"a function value"
7055 fpos
7058 check_disposable_in_return env fty;
7059 let (env, (tel, typed_unpack_element, ty, should_forget_fakes)) =
7060 call ~expected p env fty el unpacked_element
7062 let result =
7063 make_call
7066 (* tal: no type arguments to function values, as they are non-generic *)
7069 typed_unpack_element
7072 (result, should_forget_fakes)
7074 and class_get_res
7075 ~is_method
7076 ~is_const
7077 ~coerce_from_ty
7078 ?(explicit_targs = [])
7079 ?(incl_tc = false)
7080 ?(is_function_pointer = false)
7083 (p, mid)
7084 cid =
7085 let (env, this_ty) =
7086 if is_method then
7087 this_for_method env cid cty
7088 else
7089 (env, cty)
7091 class_get_inner
7092 ~is_method
7093 ~is_const
7094 ~this_ty
7095 ~explicit_targs
7096 ~incl_tc
7097 ~coerce_from_ty
7098 ~is_function_pointer
7102 (p, mid)
7104 and class_get_err
7105 ~is_method
7106 ~is_const
7107 ~coerce_from_ty
7108 ?explicit_targs
7109 ?incl_tc
7110 ?is_function_pointer
7113 (p, mid)
7114 cid =
7115 let (env, tys, rval_res_opt) =
7116 class_get_res
7117 ~is_method
7118 ~is_const
7119 ~coerce_from_ty
7120 ?explicit_targs
7121 ?incl_tc
7122 ?is_function_pointer
7125 (p, mid)
7128 let rval_err_opt = Option.bind ~f:Result.error rval_res_opt in
7129 (env, tys, rval_err_opt)
7131 and class_get
7132 ~is_method
7133 ~is_const
7134 ~coerce_from_ty
7135 ?explicit_targs
7136 ?incl_tc
7137 ?is_function_pointer
7140 (p, mid)
7141 cid =
7142 let (env, tys, _) =
7143 class_get_res
7144 ~is_method
7145 ~is_const
7146 ~coerce_from_ty
7147 ?explicit_targs
7148 ?incl_tc
7149 ?is_function_pointer
7152 (p, mid)
7155 (env, tys)
7157 and class_get_inner
7158 ~is_method
7159 ~is_const
7160 ~this_ty
7161 ~coerce_from_ty
7162 ?(explicit_targs = [])
7163 ?(incl_tc = false)
7164 ?(is_function_pointer = false)
7166 ((_, cid_pos, cid_) as cid)
7168 (p, mid) =
7169 let (env, cty) = Env.expand_type env cty in
7170 let dflt_rval_err = Option.map ~f:(fun (_, _, ty) -> Ok ty) coerce_from_ty in
7171 match deref cty with
7172 | (r, Tany _) -> (env, (mk (r, Typing_utils.tany env), []), dflt_rval_err)
7173 | (_, Terr) -> (env, (err_witness env cid_pos, []), dflt_rval_err)
7174 | (_, Tdynamic) -> (env, (cty, []), dflt_rval_err)
7175 | (_, Tunion tyl) ->
7176 let (env, pairs, rval_err_opts) =
7177 List.fold_left
7179 ~init:(env, [], [])
7180 ~f:(fun (env, pairs, rval_err_opts) ty ->
7181 let (env, pair, rval_err_opt) =
7182 class_get_res
7183 ~is_method
7184 ~is_const
7185 ~explicit_targs
7186 ~incl_tc
7187 ~coerce_from_ty
7188 ~is_function_pointer
7191 (p, mid)
7194 (env, pair :: pairs, rval_err_opt :: rval_err_opts))
7197 let rval_err = Option.(map ~f:union_coercion_errs @@ all rval_err_opts) in
7198 let (env, ty) =
7199 Union.union_list env (get_reason cty) (List.map ~f:fst pairs)
7201 (env, (ty, []), rval_err)
7202 | (_, Tintersection tyl) ->
7203 let (env, pairs, rval_err_opts) =
7204 TUtils.run_on_intersection_res env tyl ~f:(fun env ty ->
7205 class_get_inner
7206 ~is_method
7207 ~is_const
7208 ~this_ty
7209 ~explicit_targs
7210 ~incl_tc
7211 ~coerce_from_ty
7212 ~is_function_pointer
7216 (p, mid))
7218 let rval_err =
7219 Option.(map ~f:intersect_coercion_errs @@ all rval_err_opts)
7221 let (env, ty) =
7222 Inter.intersect_list env (get_reason cty) (List.map ~f:fst pairs)
7224 (env, (ty, []), rval_err)
7225 | (_, Tnewtype (_, _, ty))
7226 | (_, Tdependent (_, ty)) ->
7227 class_get_inner
7228 ~is_method
7229 ~is_const
7230 ~this_ty
7231 ~explicit_targs
7232 ~incl_tc
7233 ~coerce_from_ty
7234 ~is_function_pointer
7238 (p, mid)
7239 | (r, Tgeneric _) ->
7240 let (env, tyl) =
7241 TUtils.get_concrete_supertypes ~abstract_enum:true env cty
7243 if List.is_empty tyl then begin
7244 Errors.add_typing_error
7245 Typing_error.(
7246 primary
7247 @@ Primary.Non_class_member
7249 elt =
7250 (if is_method then
7251 `meth
7252 else
7253 `prop);
7254 member_name = mid;
7255 pos = p;
7256 ty_name = lazy (Typing_print.error env cty);
7257 decl_pos = get_pos cty;
7260 (env, (err_witness env p, []), dflt_rval_err)
7261 end else
7262 let (env, ty) = Typing_intersection.intersect_list env r tyl in
7263 class_get_inner
7264 ~is_method
7265 ~is_const
7266 ~this_ty
7267 ~explicit_targs
7268 ~incl_tc
7269 ~coerce_from_ty
7270 ~is_function_pointer
7274 (p, mid)
7275 | (_, Tclass ((_, c), _, paraml)) ->
7276 let class_ = Env.get_class env c in
7277 (match class_ with
7278 | None -> (env, (Typing_utils.mk_tany env p, []), dflt_rval_err)
7279 | Some class_ ->
7280 (* TODO akenn: Should we move this to the class_get original call? *)
7281 let (env, this_ty) = ExprDepTy.make env ~cid:cid_ this_ty in
7282 (* We need to instantiate generic parameters in the method signature *)
7283 let ety_env =
7285 empty_expand_env with
7286 this_ty;
7287 substs = TUtils.make_locl_subst_for_class_tparams class_ paraml;
7290 let get_smember_from_constraints env class_info =
7291 let upper_bounds =
7292 Cls.upper_bounds_on_this_from_constraints class_info
7294 let (env, upper_bounds) =
7295 List.map_env env upper_bounds ~f:(fun env up ->
7296 Phase.localize ~ety_env env up)
7298 let (env, inter_ty) =
7299 Inter.intersect_list env (Reason.Rwitness p) upper_bounds
7301 class_get_inner
7302 ~is_method
7303 ~is_const
7304 ~this_ty
7305 ~explicit_targs
7306 ~incl_tc
7307 ~coerce_from_ty
7308 ~is_function_pointer
7311 inter_ty
7312 (p, mid)
7314 let try_get_smember_from_constraints env class_info =
7315 Errors.try_with_error
7316 (fun () -> get_smember_from_constraints env class_info)
7317 (fun () ->
7318 Errors.add_typing_error
7319 @@ TOG.smember_not_found
7321 ~is_const
7322 ~is_method
7323 ~is_function_pointer
7324 class_info
7326 Typing_error.Callback.unify_error;
7327 (env, (TUtils.terr env Reason.Rnone, []), dflt_rval_err))
7329 if is_const then (
7330 let const =
7331 if incl_tc then
7332 Env.get_const env class_ mid
7333 else
7334 match Env.get_typeconst env class_ mid with
7335 | Some _ ->
7336 Errors.add_typing_error
7337 Typing_error.(
7338 primary @@ Primary.Illegal_typeconst_direct_access p);
7339 None
7340 | None -> Env.get_const env class_ mid
7342 match const with
7343 | None when Cls.has_upper_bounds_on_this_from_constraints class_ ->
7344 try_get_smember_from_constraints env class_
7345 | None ->
7346 Errors.add_typing_error
7347 @@ TOG.smember_not_found
7349 ~is_const
7350 ~is_method
7351 ~is_function_pointer
7352 class_
7354 Typing_error.Callback.unify_error;
7355 (env, (TUtils.terr env Reason.Rnone, []), dflt_rval_err)
7356 | Some { cc_type; cc_abstract; cc_pos; _ } ->
7357 let (env, cc_locl_type) = Phase.localize ~ety_env env cc_type in
7358 (match cc_abstract with
7359 | CCAbstract _ ->
7360 (match cid_ with
7361 | CIstatic
7362 | CIexpr _ ->
7364 | _ ->
7365 let cc_name = Cls.name class_ ^ "::" ^ mid in
7366 let err =
7367 Typing_error.(
7368 primary
7369 @@ Primary.Abstract_const_usage
7370 { pos = p; decl_pos = cc_pos; name = cc_name })
7372 Errors.add_typing_error err)
7373 | CCConcrete -> ());
7374 (env, (cc_locl_type, []), dflt_rval_err)
7375 ) else
7376 let static_member_opt =
7377 Env.get_static_member is_method env class_ mid
7379 (match static_member_opt with
7380 | None when Cls.has_upper_bounds_on_this_from_constraints class_ ->
7381 try_get_smember_from_constraints env class_
7382 | None ->
7383 Errors.add_typing_error
7384 @@ TOG.smember_not_found
7386 ~is_const
7387 ~is_method
7388 ~is_function_pointer
7389 class_
7391 Typing_error.Callback.unify_error;
7392 (env, (TUtils.terr env Reason.Rnone, []), dflt_rval_err)
7393 | Some
7395 ce_visibility = vis;
7396 ce_type = (lazy member_decl_ty);
7397 ce_deprecated;
7399 } as ce) ->
7400 let def_pos = get_pos member_decl_ty in
7401 Option.iter
7402 ~f:Errors.add_typing_error
7403 (TVis.check_class_access
7404 ~is_method
7405 ~use_pos:p
7406 ~def_pos
7408 (vis, get_ce_lsb ce)
7409 cid_
7410 class_);
7411 Option.iter
7412 ~f:Errors.add_typing_error
7413 (TVis.check_deprecated ~use_pos:p ~def_pos ce_deprecated);
7414 check_class_get env p def_pos c mid ce cid is_function_pointer;
7415 let (env, member_ty, et_enforced, tal) =
7416 match deref member_decl_ty with
7417 (* We special case Tfun here to allow passing in explicit tparams to localize_ft. *)
7418 | (r, Tfun ft) when is_method ->
7419 let (env, explicit_targs) =
7420 Phase.localize_targs
7421 ~check_well_kinded:true
7422 ~is_method:true
7423 ~def_pos
7424 ~use_pos:p
7425 ~use_name:(strip_ns mid)
7427 ft.ft_tparams
7428 (List.map ~f:snd explicit_targs)
7430 let ft =
7431 Typing_enforceability.compute_enforced_and_pessimize_fun_type
7435 let (env, ft) =
7436 Phase.(
7437 localize_ft
7438 ~instantiation:
7439 { use_name = strip_ns mid; use_pos = p; explicit_targs }
7440 ~ety_env
7441 ~def_pos
7445 let fty =
7446 Typing_dynamic.relax_method_type
7448 (get_ce_support_dynamic_type ce)
7452 (env, fty, Unenforced, explicit_targs)
7453 (* unused *)
7454 | _ ->
7455 let { et_type; et_enforced } =
7456 Typing_enforceability.compute_enforced_and_pessimize_ty
7458 member_decl_ty
7460 let (env, member_ty) = Phase.localize ~ety_env env et_type in
7461 (* TODO(T52753871) make function just return possibly_enforced_ty
7462 * after considering intersection case *)
7463 (env, member_ty, et_enforced, [])
7465 let (env, member_ty) =
7466 if Cls.has_upper_bounds_on_this_from_constraints class_ then
7467 let ((env, (member_ty', _), _), succeed) =
7468 Errors.try_
7469 (fun () -> (get_smember_from_constraints env class_, true))
7470 (fun _ ->
7471 (* No eligible functions found in constraints *)
7472 ( (env, (MakeType.mixed Reason.Rnone, []), dflt_rval_err),
7473 false ))
7475 if succeed then
7476 Inter.intersect env ~r:(Reason.Rwitness p) member_ty member_ty'
7477 else
7478 (env, member_ty)
7479 else
7480 (env, member_ty)
7482 let (env, rval_err) =
7483 match coerce_from_ty with
7484 | None -> (env, None)
7485 | Some (p, ur, ty) ->
7486 Result.fold
7487 ~ok:(fun env -> (env, Some (Ok ty)))
7488 ~error:(fun env -> (env, Some (Error (ty, member_ty))))
7489 @@ Typing_coercion.coerce_type_res
7494 { et_type = member_ty; et_enforced }
7495 Typing_error.Callback.unify_error
7497 (env, (member_ty, tal), rval_err)))
7498 | (_, Tunapplied_alias _) ->
7499 Typing_defs.error_Tunapplied_alias_in_illegal_context ()
7500 | ( _,
7501 ( Tvar _ | Tnonnull | Tvec_or_dict _ | Toption _ | Tprim _ | Tfun _
7502 | Ttuple _ | Tshape _ | Taccess _ | Tneg _ ) ) ->
7503 Errors.add_typing_error
7504 Typing_error.(
7505 primary
7506 @@ Primary.Non_class_member
7508 elt =
7509 (if is_method then
7510 `meth
7511 else
7512 `prop);
7513 member_name = mid;
7514 pos = p;
7515 ty_name = lazy (Typing_print.error env cty);
7516 decl_pos = get_pos cty;
7518 (env, (err_witness env p, []), dflt_rval_err)
7520 and class_id_for_new
7521 ~exact p env (cid : Nast.class_id_) (explicit_targs : Nast.targ list) :
7522 newable_class_info =
7523 let (env, tal, te, cid_ty) =
7524 class_expr
7525 ~check_targs_well_kinded:true
7526 ~check_explicit_targs:true
7527 ~exact
7529 explicit_targs
7530 ((), p, cid)
7532 (* Need to deal with union case *)
7533 let rec get_info res tyl =
7534 match tyl with
7535 | [] -> (env, tal, te, res)
7536 | ty :: tyl ->
7537 (match get_node ty with
7538 | Tunion tyl'
7539 | Tintersection tyl' ->
7540 get_info res (tyl' @ tyl)
7541 | _ ->
7542 (* Instantiation on an abstract class (e.g. from classname<T>) is
7543 * via the base type (to check constructor args), but the actual
7544 * type `ty` must be preserved. *)
7545 (match get_node (TUtils.get_base_type env ty) with
7546 | Tdynamic -> get_info (`Dynamic :: res) tyl
7547 | Tclass (sid, _, _) ->
7548 let class_ = Env.get_class env (snd sid) in
7549 (match class_ with
7550 | None -> get_info res tyl
7551 | Some class_info ->
7552 (match (te, cid_ty) with
7553 (* When computing the classes for a new T() where T is a generic,
7554 * the class must be consistent (final, final constructor, or
7555 * <<__ConsistentConstruct>>) for its constructor to be considered *)
7556 | ((_, _, Aast.CI (_, c)), ty) when is_generic_equal_to c ty ->
7557 (* Only have this choosing behavior for new T(), not all generic types
7558 * i.e. new classname<T>, TODO: T41190512 *)
7559 if Cls.valid_newable_class class_info then
7560 get_info (`Class (sid, class_info, ty) :: res) tyl
7561 else
7562 get_info res tyl
7563 | _ -> get_info (`Class (sid, class_info, ty) :: res) tyl))
7564 | _ -> get_info res tyl))
7566 get_info [] [cid_ty]
7568 (* When invoking a method, the class_id is used to determine what class we
7569 * lookup the method in, but the type of 'this' will be the late bound type.
7570 * For example:
7572 * class C {
7573 * public static function get(): this { return new static(); }
7575 * public static function alias(): this { return self::get(); }
7578 * In C::alias, when we invoke self::get(), 'self' is resolved to the class
7579 * in the lexical scope (C), so call C::get. However the method is executed in
7580 * the current context, so static inside C::get will be resolved to the late
7581 * bound type (get_called_class() within C::alias).
7583 * This means when determining the type of this, CIparent and CIself should be
7584 * changed to CIstatic. For the other cases of C::get() or $c::get(), we only
7585 * look at the left hand side of the '::' and use the type associated
7586 * with it.
7588 * Thus C::get() will return a type C, while $c::get() will return the same
7589 * type as $c.
7591 and this_for_method env (_, p, cid) default_ty =
7592 match cid with
7593 | CIparent
7594 | CIself
7595 | CIstatic ->
7596 let (env, _tal, _te, ty) = class_expr env [] ((), p, CIstatic) in
7597 ExprDepTy.make env ~cid:CIstatic ty
7598 | _ -> (env, default_ty)
7600 (** Resolve class expressions:
7601 * self CIself lexically enclosing class
7602 * parent CIparent lexically enclosing `extends` class
7603 * static CIstatic late-static-bound class (i.e. runtime receiver)
7604 * <id> CI id literal class name
7605 * <expr> CIexpr expr expression that evaluates to an object or classname
7607 and class_expr
7608 ?(check_targs_well_kinded = false)
7609 ?(exact = Nonexact)
7610 ?(check_explicit_targs = false)
7611 (env : env)
7612 (tal : Nast.targ list)
7613 ((_, p, cid_) : Nast.class_id) :
7614 env * Tast.targ list * Tast.class_id * locl_ty =
7615 let make_result env tal te ty = (env, tal, (ty, p, te), ty) in
7616 match cid_ with
7617 | CIparent ->
7618 (match Env.get_self_id env with
7619 | Some self ->
7620 (match Env.get_class env self with
7621 | Some trait when Ast_defs.is_c_trait (Cls.kind trait) ->
7622 (match trait_most_concrete_req_class trait env with
7623 | None ->
7624 Errors.add_typing_error
7625 Typing_error.(primary @@ Primary.Parent_in_trait p);
7626 make_result env [] Aast.CIparent (err_witness env p)
7627 | Some (_, parent_ty) ->
7628 (* inside a trait, parent is SN.Typehints.this, but with the
7629 * type of the most concrete class that the trait has
7630 * "require extend"-ed *)
7631 let (env, parent_ty) =
7632 Phase.localize_no_subst env ~ignore_errors:true parent_ty
7634 make_result env [] Aast.CIparent parent_ty)
7635 | _ ->
7636 let parent =
7637 match Env.get_parent_ty env with
7638 | None ->
7639 Errors.add_typing_error
7640 Typing_error.(primary @@ Primary.Parent_undefined p);
7641 mk (Reason.none, Typing_defs.make_tany ())
7642 | Some parent -> parent
7644 let (env, parent) =
7645 Phase.localize_no_subst env ~ignore_errors:true parent
7647 (* parent is still technically the same object. *)
7648 make_result env [] Aast.CIparent parent)
7649 | None ->
7650 let parent =
7651 match Env.get_parent_ty env with
7652 | None ->
7653 Errors.add_typing_error
7654 Typing_error.(primary @@ Primary.Parent_undefined p);
7655 mk (Reason.none, Typing_defs.make_tany ())
7656 | Some parent -> parent
7658 let (env, parent) =
7659 Phase.localize_no_subst env ~ignore_errors:true parent
7661 (* parent is still technically the same object. *)
7662 make_result env [] Aast.CIparent parent)
7663 | CIstatic ->
7664 let this =
7665 if Option.is_some (Env.next_cont_opt env) then
7666 MakeType.this (Reason.Rwitness p)
7667 else
7668 MakeType.nothing (Reason.Rwitness p)
7670 make_result env [] Aast.CIstatic this
7671 | CIself ->
7672 let ty =
7673 match Env.get_self_class_type env with
7674 | Some (c, _, tyl) -> mk (Reason.Rwitness p, Tclass (c, exact, tyl))
7675 | None ->
7676 (* Naming phase has already checked and replaced CIself with CI if outside a class *)
7677 Errors.internal_error p "Unexpected CIself";
7678 Typing_utils.mk_tany env p
7680 make_result env [] Aast.CIself ty
7681 | CI ((p, id) as c) ->
7682 begin
7683 match Env.get_pos_and_kind_of_generic env id with
7684 | Some (def_pos, kind) ->
7685 let simple_kind = Typing_kinding_defs.Simple.from_full_kind kind in
7686 let param_nkinds =
7687 Typing_kinding_defs.Simple.get_named_parameter_kinds simple_kind
7689 let (env, tal) =
7690 Phase.localize_targs_with_kinds
7691 ~check_well_kinded:check_targs_well_kinded
7692 ~is_method:true
7693 ~def_pos
7694 ~use_pos:p
7695 ~use_name:(strip_ns (snd c))
7696 ~check_explicit_targs
7698 param_nkinds
7699 (List.map ~f:snd tal)
7701 let r = Reason.Rhint (Pos_or_decl.of_raw_pos p) in
7702 let type_args = List.map tal ~f:fst in
7703 let tgeneric = MakeType.generic ~type_args r id in
7704 make_result env tal (Aast.CI c) tgeneric
7705 | None ->
7706 (* Not a type parameter *)
7707 let class_ = Env.get_class env id in
7708 (match class_ with
7709 | None -> make_result env [] (Aast.CI c) (Typing_utils.mk_tany env p)
7710 | Some class_ ->
7711 Option.iter
7712 ~f:Errors.add_typing_error
7713 (TVis.check_classname_access
7714 ~use_pos:p
7715 ~in_signature:false
7717 class_);
7718 (* Don't add Exact superfluously to class type if it's final *)
7719 let exact =
7720 if Cls.final class_ then
7721 Nonexact
7722 else
7723 exact
7725 let (env, ty, tal) =
7726 List.map ~f:snd tal
7727 |> Phase.localize_targs_and_check_constraints
7728 ~exact
7729 ~check_well_kinded:check_targs_well_kinded
7730 ~def_pos:(Cls.pos class_)
7731 ~use_pos:p
7732 ~check_explicit_targs
7735 (Cls.tparams class_)
7737 make_result env tal (Aast.CI c) ty)
7739 | CIexpr ((_, p, _) as e) ->
7740 let (env, te, ty) = expr env e ~allow_awaitable:(*?*) false in
7741 let fold_errs errs =
7742 let rec aux = function
7743 | (Ok xs, Ok x :: rest) -> aux (Ok (x :: xs), rest)
7744 | (Ok xs, Error (x, y) :: rest) -> aux (Error (x :: xs, y :: xs), rest)
7745 | (Error (xs, ys), Ok x :: rest) -> aux (Error (x :: xs, x :: ys), rest)
7746 | (Error (xs, ys), Error (x, y) :: rest) ->
7747 aux (Error (x :: xs, y :: ys), rest)
7748 | (acc, []) -> acc
7750 aux (Ok [], errs)
7752 let rec resolve_ety env ty =
7753 let (env, ty) =
7754 Typing_solver.expand_type_and_solve
7755 ~description_of_expected:"an object"
7760 let base_ty = TUtils.get_base_type env ty in
7761 match deref base_ty with
7762 | (_, Tnewtype (classname, [the_cls], as_ty))
7763 when String.equal classname SN.Classes.cClassname ->
7764 let (env, ty, err_res) = resolve_ety env the_cls in
7765 let wrap ty = mk (Reason.none, Tnewtype (classname, [ty], as_ty)) in
7766 let err_res =
7767 match err_res with
7768 | Ok ty -> Ok (wrap ty)
7769 | Error (ty_act, ty_exp) -> Error (wrap ty_act, wrap ty_exp)
7771 (env, ty, err_res)
7772 | (_, Tgeneric _)
7773 | (_, Tclass _) ->
7774 (env, ty, Ok ty)
7775 | (r, Tunion tyl) ->
7776 let (env, tyl, errs) = List.map_env_err_res env tyl ~f:resolve_ety in
7777 let ty = MakeType.union r tyl in
7778 let err =
7779 match fold_errs errs with
7780 | Ok _ -> Ok ty
7781 | Error (ty_actuals, ty_expects) ->
7782 let ty_actual = MakeType.union Reason.none ty_actuals
7783 and ty_expect = MakeType.union Reason.none ty_expects in
7784 Error (ty_actual, ty_expect)
7786 (env, ty, err)
7787 | (r, Tintersection tyl) ->
7788 let (env, tyl, errs) =
7789 TUtils.run_on_intersection_res env tyl ~f:resolve_ety
7791 let (env, ty) = Inter.intersect_list env r tyl in
7792 let (env, err) =
7793 match fold_errs errs with
7794 | Ok _ -> (env, Ok ty)
7795 | Error (ty_actuals, ty_expects) ->
7796 let (env, ty_actual) =
7797 Inter.intersect_list env Reason.none ty_actuals
7799 let (env, ty_expect) =
7800 Inter.intersect_list env Reason.none ty_expects
7802 (env, Error (ty_actual, ty_expect))
7804 (env, ty, err)
7805 | (_, Tdynamic) -> (env, base_ty, Ok base_ty)
7806 | (_, Terr) ->
7807 let ty = err_witness env p in
7808 (env, ty, Ok ty)
7809 | (r, Tvar _) ->
7810 Errors.add_typing_error
7811 Typing_error.(
7812 primary
7813 @@ Primary.Unknown_type
7815 expected = "an object";
7816 pos = p;
7817 reason = Reason.to_string "It is unknown" r;
7819 let ty = err_witness env p in
7820 (env, ty, Ok ty)
7821 | (_, Tunapplied_alias _) ->
7822 Typing_defs.error_Tunapplied_alias_in_illegal_context ()
7823 | ( _,
7824 ( Tany _ | Tnonnull | Tvec_or_dict _ | Toption _ | Tprim _ | Tfun _
7825 | Ttuple _ | Tnewtype _ | Tdependent _ | Tshape _ | Taccess _ | Tneg _
7826 ) ) ->
7827 Errors.add_typing_error
7828 Typing_error.(
7829 primary
7830 @@ Primary.Expected_class
7832 suffix =
7833 Some (lazy (", but got " ^ Typing_print.error env base_ty));
7834 pos = p;
7836 let ty_nothing = MakeType.nothing Reason.none in
7837 let ty_expect = MakeType.classname Reason.none [ty_nothing] in
7838 (env, err_witness env p, Error (base_ty, ty_expect))
7840 let (env, result_ty, err_res) = resolve_ety env ty in
7841 let err_opt =
7842 Result.fold
7843 err_res
7844 ~ok:(fun _ -> None)
7845 ~error:(fun (ty_act, ty_expect) -> Some (ty_act, ty_expect))
7847 let te = hole_on_err ~err_opt te in
7848 let x = make_result env [] (Aast.CIexpr te) result_ty in
7851 and call_construct p env class_ params el unpacked_element cid cid_ty =
7852 let cid_ty =
7853 if Nast.equal_class_id_ cid CIparent then
7854 MakeType.this (Reason.Rwitness p)
7855 else
7856 cid_ty
7858 let ety_env =
7860 empty_expand_env with
7861 this_ty = cid_ty;
7862 substs = TUtils.make_locl_subst_for_class_tparams class_ params;
7863 on_error = Typing_error.Reasons_callback.unify_error_at p;
7866 let env =
7867 Phase.check_where_constraints
7868 ~in_class:true
7869 ~use_pos:p
7870 ~definition_pos:(Cls.pos class_)
7871 ~ety_env
7873 (Cls.where_constraints class_)
7875 let cstr = Env.get_construct env class_ in
7876 match fst cstr with
7877 | None ->
7878 if (not (List.is_empty el)) || Option.is_some unpacked_element then
7879 Errors.add_typing_error
7880 Typing_error.(primary @@ Primary.Constructor_no_args p);
7881 let (env, tel, _tyl) =
7882 argument_list_exprs (expr ~allow_awaitable:false) env el
7884 let should_forget_fakes = true in
7885 (env, tel, None, TUtils.terr env Reason.Rnone, should_forget_fakes)
7886 | Some { ce_visibility = vis; ce_type = (lazy m); ce_deprecated; _ } ->
7887 let def_pos = get_pos m in
7888 Option.iter
7889 ~f:Errors.add_typing_error
7890 (TVis.check_obj_access ~is_method:true ~use_pos:p ~def_pos env vis);
7891 Option.iter
7892 ~f:Errors.add_typing_error
7893 (TVis.check_deprecated ~use_pos:p ~def_pos ce_deprecated);
7894 (* Obtain the type of the constructor *)
7895 let (env, m) =
7896 let r = get_reason m |> Typing_reason.localize in
7897 match get_node m with
7898 | Tfun ft ->
7899 let ft =
7900 Typing_enforceability.compute_enforced_and_pessimize_fun_type env ft
7902 (* This creates type variables for non-denotable type parameters on constructors.
7903 * These are notably different from the tparams on the class, which are handled
7904 * at the top of this function. User-written type parameters on constructors
7905 * are still a parse error. This is a no-op if ft.ft_tparams is empty. *)
7906 let (env, implicit_constructor_targs) =
7907 Phase.localize_targs
7908 ~check_well_kinded:true
7909 ~is_method:true
7910 ~def_pos
7911 ~use_pos:p
7912 ~use_name:"constructor"
7914 ft.ft_tparams
7917 let (env, ft) =
7918 Phase.(
7919 localize_ft
7920 ~instantiation:
7922 use_name = "constructor";
7923 use_pos = p;
7924 explicit_targs = implicit_constructor_targs;
7926 ~ety_env
7927 ~def_pos
7931 (env, mk (r, Tfun ft))
7932 | _ ->
7933 Errors.internal_error p "Expected function type for constructor";
7934 let ty = TUtils.terr env r in
7935 (env, ty)
7937 let (env, (tel, typed_unpack_element, _ty, should_forget_fakes)) =
7938 call ~expected:None p env m el unpacked_element
7940 (env, tel, typed_unpack_element, m, should_forget_fakes)
7942 and inout_write_back env { fp_type; _ } (pk, ((_, pos, _) as e)) =
7943 match pk with
7944 | Ast_defs.Pinout _ ->
7945 (* Translate the write-back semantics of inout parameters.
7947 * This matters because we want to:
7948 * (1) make sure we can write to the original argument
7949 * (modifiable lvalue check)
7950 * (2) allow for growing of locals / Tunions (type side effect)
7951 * but otherwise unify the argument type with the parameter hint
7953 let (env, _te, _ty) =
7954 assign_ pos Reason.URparam_inout env e pos fp_type.et_type
7957 | _ -> env
7959 (** Typechecks a call.
7960 * Returns in this order the typed expressions for the arguments, for the
7961 * variadic arguments, the return type, and a boolean indicating whether fake
7962 * members should be forgotten.
7964 and call
7965 ~(expected : ExpectedTy.t option)
7966 ?(nullsafe : Pos.t option = None)
7967 ?in_await
7968 ?(in_supportdyn = false)
7972 (el : (Ast_defs.param_kind * Nast.expr) list)
7973 (unpacked_element : Nast.expr option) :
7975 * ((Ast_defs.param_kind * Tast.expr) list
7976 * Tast.expr option
7977 * locl_ty
7978 * bool) =
7979 let expr = expr ~allow_awaitable:(*?*) false in
7980 let (env, tyl) =
7981 TUtils.get_concrete_supertypes
7982 ~expand_supportdyn:false
7983 ~abstract_enum:true
7987 if List.is_empty tyl then begin
7988 bad_call env pos fty;
7989 let env = call_untyped_unpack env (get_pos fty) unpacked_element in
7990 let should_forget_fakes = true in
7991 (env, ([], None, err_witness env pos, should_forget_fakes))
7992 end else
7993 let (env, fty) =
7994 Typing_intersection.intersect_list env (get_reason fty) tyl
7996 let (env, efty) =
7997 if TypecheckerOptions.method_call_inference (Env.get_tcopt env) then
7998 Env.expand_type env fty
7999 else
8000 Typing_solver.expand_type_and_solve
8001 ~description_of_expected:"a function value"
8006 match deref efty with
8007 | (r, Tdynamic) when TCO.enable_sound_dynamic (Env.get_tcopt env) ->
8008 let ty = MakeType.dynamic (Reason.Rdynamic_call pos) in
8009 let el =
8010 (* Need to check that the type of the unpacked_element can be,
8011 * coerced to dynamic, just like all of the other arguments, in addition
8012 * to the check below in call_untyped_unpack, that it is unpackable.
8013 * We don't need to unpack and check each type because a tuple is
8014 * coercible iff it's constituent types are. *)
8015 Option.value_map
8016 ~f:(fun u -> el @ [(Ast_defs.Pnormal, u)])
8017 ~default:el
8018 unpacked_element
8020 let expected_arg_ty =
8021 ExpectedTy.make
8022 ~coerce:(Some Typing_logic.CoerceToDynamic)
8024 Reason.URparam
8027 let (env, tel) =
8028 List.map_env env el ~f:(fun env (pk, elt) ->
8029 let (env, te, e_ty) = expr ~expected:expected_arg_ty env elt in
8030 let env =
8031 match pk with
8032 | Ast_defs.Pinout _ ->
8033 let (_, pos, _) = elt in
8034 let (env, _te, _ty) =
8035 assign_ pos Reason.URparam_inout env elt pos efty
8038 | Ast_defs.Pnormal -> env
8040 let (env, err_opt) =
8041 Result.fold
8042 ~ok:(fun env -> (env, None))
8043 ~error:(fun env -> (env, Some (e_ty, ty)))
8044 @@ Typing_subtype.sub_type_res
8045 ~coerce:(Some Typing_logic.CoerceToDynamic)
8047 e_ty
8049 (Typing_error.Reasons_callback.unify_error_at pos)
8051 (env, (pk, hole_on_err ~err_opt te)))
8053 let env = call_untyped_unpack env (Reason.to_pos r) unpacked_element in
8054 let should_forget_fakes = true in
8055 (env, (tel, None, ty, should_forget_fakes))
8056 | (r, ((Tprim Tnull | Tdynamic | Terr | Tany _ | Tunion []) as ty))
8057 when match ty with
8058 | Tprim Tnull -> Option.is_some nullsafe
8059 | _ -> true ->
8060 let el =
8061 Option.value_map
8062 ~f:(fun u -> el @ [(Ast_defs.Pnormal, u)])
8063 ~default:el
8064 unpacked_element
8066 let expected_arg_ty =
8067 (* Note: We ought to be using 'mixed' here *)
8068 ExpectedTy.make pos Reason.URparam (Typing_utils.mk_tany env pos)
8070 let (env, tel) =
8071 List.map_env env el ~f:(fun env (pk, elt) ->
8072 let (env, te, ty) = expr ~expected:expected_arg_ty env elt in
8073 let (env, err_opt) =
8074 if TCO.global_inference (Env.get_tcopt env) then
8075 match get_node efty with
8076 | Terr
8077 | Tany _
8078 | Tdynamic ->
8079 Result.fold
8080 ~ok:(fun env -> (env, None))
8081 ~error:(fun env -> (env, Some (ty, efty)))
8082 @@ Typing_coercion.coerce_type_res
8084 Reason.URparam
8087 (MakeType.unenforced efty)
8088 Typing_error.Callback.unify_error
8089 | _ -> (env, None)
8090 else
8091 (env, None)
8093 let env =
8094 match pk with
8095 | Ast_defs.Pinout _ ->
8096 let (_, pos, _) = elt in
8097 let (env, _te, _ty) =
8098 assign_ pos Reason.URparam_inout env elt pos efty
8101 | Ast_defs.Pnormal -> env
8103 (env, (pk, hole_on_err ~err_opt te)))
8105 let env = call_untyped_unpack env (Reason.to_pos r) unpacked_element in
8106 let ty =
8107 match ty with
8108 | Tprim Tnull -> mk (r, Tprim Tnull)
8109 | Tdynamic -> MakeType.dynamic (Reason.Rdynamic_call pos)
8110 | Terr
8111 | Tany _ ->
8112 Typing_utils.mk_tany env pos
8113 | Tunion []
8114 | _ (* _ should not happen! *) ->
8115 mk (r, Tunion [])
8117 let should_forget_fakes = true in
8118 (env, (tel, None, ty, should_forget_fakes))
8119 | (_, Tunion [ty]) ->
8120 call ~expected ~nullsafe ?in_await pos env ty el unpacked_element
8121 | (r, Tunion tyl) ->
8122 let (env, resl) =
8123 List.map_env env tyl ~f:(fun env ty ->
8124 call ~expected ~nullsafe ?in_await pos env ty el unpacked_element)
8126 let should_forget_fakes =
8127 List.exists resl ~f:(fun (_, _, _, forget) -> forget)
8129 let retl = List.map resl ~f:(fun (_, _, x, _) -> x) in
8130 let (env, ty) = Union.union_list env r retl in
8131 (* We shouldn't be picking arbitrarily for the TAST here, as TAST checks
8132 * depend on the types inferred. Here's we're preserving legacy behaviour
8133 * by picking the last one.
8134 * TODO: don't do this, instead use subtyping to push unions
8135 * through function types
8137 let (tel, typed_unpack_element, _, _) = List.hd_exn (List.rev resl) in
8138 (env, (tel, typed_unpack_element, ty, should_forget_fakes))
8139 | (r, Tintersection tyl) ->
8140 let (env, resl) =
8141 TUtils.run_on_intersection env tyl ~f:(fun env ty ->
8142 call ~expected ~nullsafe ?in_await pos env ty el unpacked_element)
8144 let should_forget_fakes =
8145 List.for_all resl ~f:(fun (_, _, _, forget) -> forget)
8147 let retl = List.map resl ~f:(fun (_, _, x, _) -> x) in
8148 let (env, ty) = Inter.intersect_list env r retl in
8149 (* We shouldn't be picking arbitrarily for the TAST here, as TAST checks
8150 * depend on the types inferred. Here we're preserving legacy behaviour
8151 * by picking the last one.
8152 * TODO: don't do this, instead use subtyping to push intersections
8153 * through function types
8155 let (tel, typed_unpack_element, _, _) = List.hd_exn (List.rev resl) in
8156 (env, (tel, typed_unpack_element, ty, should_forget_fakes))
8157 | (r2, Tfun ft) ->
8158 (* Typing of format string functions. It is dependent on the arguments (el)
8159 * so it cannot be done earlier.
8161 let pos_def = Reason.to_pos r2 in
8162 let (env, ft) = Typing_exts.retype_magic_func env ft el in
8163 let (env, var_param) = variadic_param env ft in
8164 (* Force subtype with expected result *)
8165 let env =
8166 check_expected_ty "Call result" env ft.ft_ret.et_type expected
8168 let env = Env.set_tyvar_variance env ft.ft_ret.et_type in
8169 let is_lambda (_, _, e) =
8170 match e with
8171 | Efun _
8172 | Lfun _ ->
8173 true
8174 | _ -> false
8176 let get_next_param_info paraml =
8177 match paraml with
8178 | param :: paraml -> (false, Some param, paraml)
8179 | [] -> (true, var_param, paraml)
8181 let rec compute_enum_name env lty =
8182 match get_node lty with
8183 | Tclass ((_, enum_name), _, _) when Env.is_enum_class env enum_name ->
8184 (env, Some enum_name)
8185 | Tgeneric (name, _) ->
8186 let (env, upper_bounds) =
8187 Typing_utils.collect_enum_class_upper_bounds env name
8189 begin
8190 match upper_bounds with
8191 | None -> (env, None)
8192 | Some upper_bound ->
8193 (* To avoid ambiguity, we only support the case where
8194 * there is a single upper bound that is an EnumClass.
8195 * We might want to relax that later (e.g. with the
8196 * support for intersections).
8198 begin
8199 match get_node upper_bound with
8200 | Tclass ((_, name), _, _) when Env.is_enum_class env name ->
8201 (env, Some name)
8202 | _ -> (env, None)
8205 | Tvar var ->
8206 (* minimal support to only deal with Tvar when:
8207 * - it is the valueOf from BuiltinEnumClass.
8208 * In this case, we know the tvar as a single lowerbound,
8209 * `this` which must be an enum class.
8210 * - it is a generic "TX::T" from a where clause. We try
8211 * to look at an upper bound, if it is an enum class, or fail.
8213 * We could relax this in the future but
8214 * I want to avoid complex constraints for now.
8216 let lower_bounds = Env.get_tyvar_lower_bounds env var in
8217 if ITySet.cardinal lower_bounds <> 1 then
8218 (env, None)
8219 else (
8220 match ITySet.choose lower_bounds with
8221 | ConstraintType _ -> (env, None)
8222 | LoclType lower ->
8223 (match get_node lower with
8224 | Tclass ((_, enum_name), _, _)
8225 when Env.is_enum_class env enum_name ->
8226 (env, Some enum_name)
8227 | Tgeneric _ -> compute_enum_name env lower
8228 | _ -> (env, None))
8230 | _ ->
8231 (* Already reported, see Typing_type_wellformedness *)
8232 (env, None)
8234 let check_arg env param_kind ((_, pos, arg) as e) opt_param ~is_variadic =
8235 match opt_param with
8236 | Some param ->
8237 (* First check if the parameter is a HH\EnumClass\Label. *)
8238 let (env, label_type) =
8239 let ety = param.fp_type.et_type in
8240 let (env, ety) = Env.expand_type env ety in
8241 let is_label =
8242 match get_node (TUtils.strip_dynamic env ety) with
8243 | Tnewtype (name, _, _) ->
8244 String.equal SN.Classes.cEnumClassLabel name
8245 | _ -> false
8247 match arg with
8248 | EnumClassLabel (None, label_name) when is_label ->
8249 (match get_node (TUtils.strip_dynamic env ety) with
8250 | Tnewtype (name, [ty_enum; _ty_interface], _)
8251 when String.equal name SN.Classes.cMemberOf
8252 || String.equal name SN.Classes.cEnumClassLabel ->
8253 let ctor = name in
8254 (match compute_enum_name env ty_enum with
8255 | (env, None) -> (env, EnumClassLabelOps.ClassNotFound)
8256 | (env, Some enum_name) ->
8257 EnumClassLabelOps.expand
8260 ~full:false
8261 ~ctor
8262 enum_name
8263 label_name)
8264 | _ ->
8265 (* Already reported, see Typing_type_wellformedness *)
8266 (env, EnumClassLabelOps.Invalid))
8267 | EnumClassLabel (Some _, _) ->
8268 (* Full info is here, use normal inference *)
8269 (env, EnumClassLabelOps.Skip)
8270 | _ -> (env, EnumClassLabelOps.Skip)
8272 let (env, te, ty) =
8273 match label_type with
8274 | EnumClassLabelOps.Success (te, ty)
8275 | EnumClassLabelOps.LabelNotFound (te, ty) ->
8276 (env, te, ty)
8277 | _ ->
8278 let expected =
8279 ExpectedTy.make_and_allow_coercion_opt
8282 Reason.URparam
8283 param.fp_type
8285 expr
8286 ~accept_using_var:(get_fp_accept_disposable param)
8287 ?expected
8291 let (env, err_opt) =
8292 call_param ~in_supportdyn env param param_kind (e, ty) ~is_variadic
8294 (env, Some (hole_on_err ~err_opt te, ty))
8295 | None ->
8296 let expected =
8297 ExpectedTy.make pos Reason.URparam (Typing_utils.mk_tany env pos)
8299 let (env, te, ty) = expr ~expected env e in
8300 (env, Some (te, ty))
8302 let set_tyvar_variance_from_lambda_param env opt_param =
8303 match opt_param with
8304 | Some param ->
8305 let rec set_params_variance env ty =
8306 let (env, ty) = Env.expand_type env ty in
8307 match get_node ty with
8308 | Tunion [ty] -> set_params_variance env ty
8309 | Toption ty -> set_params_variance env ty
8310 | Tfun { ft_params; ft_ret; _ } ->
8311 let env =
8312 List.fold
8313 ~init:env
8314 ~f:(fun env param ->
8315 Env.set_tyvar_variance env param.fp_type.et_type)
8316 ft_params
8318 Env.set_tyvar_variance env ft_ret.et_type ~flip:true
8319 | _ -> env
8321 set_params_variance env param.fp_type.et_type
8322 | None -> env
8324 (* Given an expected function type ft, check types for the non-unpacked
8325 * arguments. Don't check lambda expressions if check_lambdas=false *)
8326 let rec check_args check_lambdas env el paraml =
8327 match el with
8328 (* We've got an argument *)
8329 | ((pk, e), opt_result) :: el ->
8330 (* Pick up next parameter type info *)
8331 let (is_variadic, opt_param, paraml) = get_next_param_info paraml in
8332 let (env, one_result) =
8333 match (check_lambdas, is_lambda e) with
8334 | (false, false)
8335 | (true, true) ->
8336 check_arg env pk e opt_param ~is_variadic
8337 | (false, true) ->
8338 let env = set_tyvar_variance_from_lambda_param env opt_param in
8339 (env, opt_result)
8340 | (true, false) -> (env, opt_result)
8342 let (env, rl, paraml) = check_args check_lambdas env el paraml in
8343 (env, ((pk, e), one_result) :: rl, paraml)
8344 | [] -> (env, [], paraml)
8346 (* Same as above, but checks the types of the implicit arguments, which are
8347 * read from the context *)
8348 let check_implicit_args env =
8349 let capability =
8350 Typing_coeffects.get_type ft.ft_implicit_params.capability
8352 if not (TypecheckerOptions.call_coeffects (Env.get_tcopt env)) then
8354 else
8355 let env_capability =
8356 Env.get_local_check_defined env (pos, Typing_coeffects.capability_id)
8358 let base_error =
8359 Typing_error.Primary.(
8360 Coeffect
8361 (Coeffect.Call_coeffect
8363 pos;
8364 available_incl_unsafe =
8365 Typing_coeffects.pretty env env_capability;
8366 available_pos = Typing_defs.get_pos env_capability;
8367 required_pos = Typing_defs.get_pos capability;
8368 required = Typing_coeffects.pretty env capability;
8371 Type.sub_type pos Reason.URnone env env_capability capability
8372 @@ Typing_error.Callback.always base_error
8374 let should_forget_fakes =
8375 (* If the function doesn't have write priveleges to properties, fake
8376 members cannot be reassigned, so their refinements stand. *)
8377 let capability =
8378 Typing_coeffects.get_type ft.ft_implicit_params.capability
8380 SubType.is_sub_type
8382 capability
8383 (MakeType.capability Reason.Rnone SN.Capabilities.writeProperty)
8386 (* First check the non-lambda arguments. For generic functions, this
8387 * is likely to resolve type variables to concrete types *)
8388 let rl = List.map el ~f:(fun e -> (e, None)) in
8389 let non_variadic_ft_params =
8390 if get_ft_variadic ft then
8391 List.drop_last_exn ft.ft_params
8392 else
8393 ft.ft_params
8395 let (env, rl, _) = check_args false env rl non_variadic_ft_params in
8396 (* Now check the lambda arguments, hopefully with type variables resolved *)
8397 let (env, rl, paraml) = check_args true env rl non_variadic_ft_params in
8398 (* We expect to see results for all arguments after this second pass *)
8399 let get_param ((pk, _), opt) =
8400 match opt with
8401 | Some (e, ty) -> ((pk, e), ty)
8402 | None -> failwith "missing parameter in check_args"
8404 let (tel, _) =
8405 let l = List.map rl ~f:get_param in
8406 List.unzip l
8408 let env = check_implicit_args env in
8409 let (env, typed_unpack_element, arity, did_unpack) =
8410 match unpacked_element with
8411 | None -> (env, None, List.length el, false)
8412 | Some e ->
8413 (* Now that we're considering an splat (Some e) we need to construct a type that
8414 * represents the remainder of the function's parameters. `paraml` represents those
8415 * remaining parameters, and the variadic parameter is stored in `var_param`. For example, given
8417 * function f(int $i, string $j, float $k = 3.14, mixed ...$m): void {}
8418 * function g((string, float, bool) $t): void {
8419 * f(3, ...$t);
8422 * the constraint type we want is splat([#1], [opt#2], #3).
8424 let (consumed, required_params, optional_params) =
8425 split_remaining_params_required_optional ft paraml
8427 let (_, p1, _) = e in
8428 let (env, (d_required, d_optional, d_variadic)) =
8429 generate_splat_type_vars
8432 required_params
8433 optional_params
8434 var_param
8436 let destructure_ty =
8437 ConstraintType
8438 (mk_constraint_type
8439 ( Reason.Runpack_param (p1, pos_def, consumed),
8440 Tdestructure
8442 d_required;
8443 d_optional;
8444 d_variadic;
8445 d_kind = SplatUnpack;
8446 } ))
8448 let (env, te, ty) = expr env e in
8449 (* Populate the type variables from the expression in the splat *)
8450 let env_res =
8451 Type.sub_type_i_res
8453 Reason.URparam
8455 (LoclType ty)
8456 destructure_ty
8457 Typing_error.Callback.unify_error
8459 let (env, te) =
8460 match env_res with
8461 | Error env ->
8462 (* Our type cannot be destructured, add a hole with `nothing`
8463 as expected type *)
8464 let ty_expect =
8465 MakeType.nothing
8466 @@ Reason.Rsolve_fail (Pos_or_decl.of_raw_pos pos)
8468 (env, mk_hole te ~ty_have:ty ~ty_expect)
8469 | Ok env ->
8470 (* We have a type that can be destructured so continue and use
8471 the type variables for the remaining parameters *)
8472 let (env, err_opts) =
8473 List.fold2_exn
8474 ~init:(env, [])
8475 d_required
8476 required_params
8477 ~f:(fun (env, errs) elt param ->
8478 let (env, err_opt) =
8479 call_param
8480 ~in_supportdyn
8482 param
8483 Ast_defs.Pnormal
8484 (e, elt)
8485 ~is_variadic:false
8487 (env, err_opt :: errs))
8489 let (env, err_opts) =
8490 List.fold2_exn
8491 ~init:(env, err_opts)
8492 d_optional
8493 optional_params
8494 ~f:(fun (env, errs) elt param ->
8495 let (env, err_opt) =
8496 call_param
8497 ~in_supportdyn
8499 param
8500 Ast_defs.Pnormal
8501 (e, elt)
8502 ~is_variadic:false
8504 (env, err_opt :: errs))
8506 let (env, var_err_opt) =
8507 Option.map2 d_variadic var_param ~f:(fun v vp ->
8508 call_param
8509 ~in_supportdyn
8512 Ast_defs.Pnormal
8513 (e, v)
8514 ~is_variadic:true)
8515 |> Option.value ~default:(env, None)
8517 let subtyping_errs = (List.rev err_opts, var_err_opt) in
8518 let te =
8519 match (List.filter_map ~f:Fn.id err_opts, var_err_opt) with
8520 | ([], None) -> te
8521 | _ ->
8522 let (_, pos, _) = te in
8523 hole_on_err
8525 ~err_opt:(Some (ty, pack_errs pos ty subtyping_errs))
8527 (env, te)
8530 ( env,
8531 Some te,
8532 List.length el + List.length d_required,
8533 Option.is_some d_variadic )
8535 (* If we unpacked an array, we don't check arity exactly. Since each
8536 * unpacked array consumes 1 or many parameters, it is nonsensical to say
8537 * that not enough args were passed in (so we don't do the min check).
8539 let () = check_arity ~did_unpack pos pos_def ft arity in
8540 (* Variadic params cannot be inout so we can stop early *)
8541 let env = wfold_left2 inout_write_back env non_variadic_ft_params el in
8542 let ret =
8543 if in_supportdyn then
8544 MakeType.locl_like r2 ft.ft_ret.et_type
8545 else
8546 ft.ft_ret.et_type
8548 (env, (tel, typed_unpack_element, ret, should_forget_fakes))
8549 | (r, Tvar _)
8550 when TypecheckerOptions.method_call_inference (Env.get_tcopt env) ->
8552 Typecheck calls with unresolved function type by constructing a
8553 suitable function type from the arguments and invoking subtyping.
8555 let (env, typed_el, type_of_el) =
8556 argument_list_exprs (expr ~accept_using_var:true) env el
8558 let (env, typed_unpacked_element, type_of_unpacked_element) =
8559 match unpacked_element with
8560 | Some unpacked ->
8561 let (env, typed_unpacked, type_of_unpacked) =
8562 expr ~accept_using_var:true env unpacked
8564 (env, Some typed_unpacked, Some type_of_unpacked)
8565 | None -> (env, None, None)
8567 let mk_function_supertype env pos (type_of_el, type_of_unpacked_element) =
8568 let mk_fun_param ty =
8569 let flags =
8570 (* Keep supertype as permissive as possible: *)
8571 make_fp_flags
8572 ~mode:FPnormal (* TODO: deal with `inout` parameters *)
8573 ~accept_disposable:false (* TODO: deal with disposables *)
8574 ~has_default:false
8575 ~ifc_external:false
8576 ~ifc_can_call:false
8577 ~readonly:false
8580 fp_pos = Pos_or_decl.of_raw_pos pos;
8581 fp_name = None;
8582 fp_type = MakeType.enforced ty;
8583 fp_flags = flags;
8586 let ft_arity =
8587 match type_of_unpacked_element with
8588 | Some type_of_unpacked ->
8589 let fun_param = mk_fun_param type_of_unpacked in
8590 [fun_param]
8591 | None -> []
8593 (* TODO: ensure `ft_params`/`ft_where_constraints` don't affect subtyping *)
8594 let ft_tparams = [] in
8595 let ft_where_constraints = [] in
8596 let ft_params = List.map ~f:mk_fun_param type_of_el in
8597 let ft_implicit_params =
8599 capability =
8600 CapDefaults (Pos_or_decl.of_raw_pos pos)
8601 (* TODO(coeffects) should this be a different type? *);
8604 let (env, return_ty) = Env.fresh_type env pos in
8605 let return_ty =
8606 match in_await with
8607 | None -> return_ty
8608 | Some r -> MakeType.awaitable r return_ty
8610 let ft_ret = MakeType.enforced return_ty in
8611 let ft_flags =
8612 (* Keep supertype as permissive as possible: *)
8613 make_ft_flags
8614 Ast_defs.FSync (* `FSync` fun can still return `Awaitable<_>` *)
8615 ~return_disposable:false (* TODO: deal with disposable return *)
8616 ~returns_readonly:false
8617 ~readonly_this:false
8618 ~support_dynamic_type:false
8619 ~is_memoized:false
8620 ~variadic:(not (List.is_empty ft_arity))
8622 let ft_ifc_decl = Typing_defs_core.default_ifc_fun_decl in
8623 let fun_locl_type =
8625 ft_tparams;
8626 ft_where_constraints;
8627 ft_params = ft_params @ ft_arity;
8628 ft_implicit_params;
8629 ft_ret;
8630 ft_flags;
8631 ft_ifc_decl;
8634 let fun_type = mk (r, Tfun fun_locl_type) in
8635 let env = Env.set_tyvar_variance env fun_type in
8636 (env, fun_type, return_ty)
8638 let (env, fun_type, return_ty) =
8639 mk_function_supertype env pos (type_of_el, type_of_unpacked_element)
8641 let env =
8642 Type.sub_type
8644 Reason.URnone
8646 efty
8647 fun_type
8648 Typing_error.Callback.unify_error
8650 let should_forget_fakes = true in
8651 (env, (typed_el, typed_unpacked_element, return_ty, should_forget_fakes))
8652 | (_, Tnewtype (name, [ty], _))
8653 when String.equal name SN.Classes.cSupportDyn ->
8654 Errors.try_
8655 (fun () ->
8656 call ~expected ~nullsafe ?in_await pos env ty el unpacked_element)
8657 (fun _ ->
8658 call_supportdyn
8659 ~expected
8660 ~nullsafe
8661 ?in_await
8666 unpacked_element)
8667 | _ ->
8668 bad_call env pos efty;
8669 let env = call_untyped_unpack env (get_pos efty) unpacked_element in
8670 let should_forget_fakes = true in
8671 (env, ([], None, err_witness env pos, should_forget_fakes))
8673 and call_supportdyn ~expected ~nullsafe ?in_await pos env ty el unpacked_element
8675 let (env, ty) = Env.expand_type env ty in
8676 match deref ty with
8677 | (_, Tfun _) ->
8678 call
8679 ~expected
8680 ~nullsafe
8681 ?in_await
8682 ~in_supportdyn:true
8687 unpacked_element
8688 | (r, _) ->
8689 call
8690 ~expected
8691 ~nullsafe
8692 ?in_await
8695 (MakeType.dynamic r)
8697 unpacked_element
8699 and call_untyped_unpack env f_pos unpacked_element =
8700 match unpacked_element with
8701 (* In the event that we don't have a known function call type, we can still
8702 * verify that any unpacked arguments (`...$args`) are something that can
8703 * be actually unpacked. *)
8704 | None -> env
8705 | Some e ->
8706 let (env, _, ety) = expr env e ~allow_awaitable:(*?*) false in
8707 let (_, p, _) = e in
8708 let (env, ty) = Env.fresh_type env p in
8709 let destructure_ty =
8710 MakeType.simple_variadic_splat (Reason.Runpack_param (p, f_pos, 0)) ty
8712 Type.sub_type_i
8714 Reason.URnone
8716 (LoclType ety)
8717 destructure_ty
8718 Typing_error.Callback.unify_error
8721 * Build an environment for the true or false branch of
8722 * conditional statements.
8724 and condition ?lhs_of_null_coalesce env tparamet ((ty, p, e) as te : Tast.expr)
8726 let condition = condition ?lhs_of_null_coalesce in
8727 match e with
8728 | Aast.Hole (e, _, _, _) -> condition env tparamet e
8729 | Aast.True when not tparamet ->
8730 (LEnv.drop_cont env C.Next, Local_id.Set.empty)
8731 | Aast.False when tparamet -> (LEnv.drop_cont env C.Next, Local_id.Set.empty)
8732 | Aast.Call ((_, _, Aast.Id (_, func)), _, [(_, te)], None)
8733 when String.equal SN.StdlibFunctions.is_null func ->
8734 condition_nullity ~nonnull:(not tparamet) env te
8735 | Aast.Binop ((Ast_defs.Eqeq | Ast_defs.Eqeqeq), (_, _, Aast.Null), e)
8736 | Aast.Binop ((Ast_defs.Eqeq | Ast_defs.Eqeqeq), e, (_, _, Aast.Null)) ->
8737 condition_nullity ~nonnull:(not tparamet) env e
8738 | Aast.Lvar _
8739 | Aast.Obj_get _
8740 | Aast.Class_get _
8741 | Aast.Binop (Ast_defs.Eq None, _, _) ->
8742 let (env, ety) = Env.expand_type env ty in
8743 (match get_node ety with
8744 | Tprim Tbool -> (env, Local_id.Set.empty)
8745 | _ -> condition_nullity ~nonnull:tparamet env te)
8746 | Aast.Binop (((Ast_defs.Diff | Ast_defs.Diff2) as op), e1, e2) ->
8747 let op =
8748 if Ast_defs.(equal_bop op Diff) then
8749 Ast_defs.Eqeq
8750 else
8751 Ast_defs.Eqeqeq
8753 condition env (not tparamet) (ty, p, Aast.Binop (op, e1, e2))
8754 (* Conjunction of conditions. Matches the two following forms:
8755 if (cond1 && cond2)
8756 if (!(cond1 || cond2))
8758 | Aast.Binop (((Ast_defs.Ampamp | Ast_defs.Barbar) as bop), e1, e2)
8759 when Bool.equal tparamet Ast_defs.(equal_bop bop Ampamp) ->
8760 let (env, lset1) = condition env tparamet e1 in
8761 (* This is necessary in case there is an assignment in e2
8762 * We essentially redo what has been undone in the
8763 * `Binop (Ampamp|Barbar)` case of `expr` *)
8764 let (env, _, _) =
8765 expr env (Tast.to_nast_expr e2) ~allow_awaitable:(*?*) false
8767 let (env, lset2) = condition env tparamet e2 in
8768 (env, Local_id.Set.union lset1 lset2)
8769 (* Disjunction of conditions. Matches the two following forms:
8770 if (cond1 || cond2)
8771 if (!(cond1 && cond2))
8773 | Aast.Binop (((Ast_defs.Ampamp | Ast_defs.Barbar) as bop), e1, e2)
8774 when Bool.equal tparamet Ast_defs.(equal_bop bop Barbar) ->
8775 let (env, lset1, lset2) =
8776 branch
8778 (fun env ->
8779 (* Either cond1 is true and we don't know anything about cond2... *)
8780 condition env tparamet e1)
8781 (fun env ->
8782 (* ... Or cond1 is false and therefore cond2 must be true *)
8783 let (env, _lset) = condition env (not tparamet) e1 in
8784 (* Similarly to the conjunction case, there might be an assignment in
8785 cond2 which we must account for. Again we redo what has been undone in
8786 the `Binop (Ampamp|Barbar)` case of `expr` *)
8787 let (env, _, _) =
8788 expr env (Tast.to_nast_expr e2) ~allow_awaitable:(*?*) false
8790 condition env tparamet e2)
8792 (env, Local_id.Set.union lset1 lset2)
8793 | Aast.Call ((_, p, Aast.Id (_, f)), _, [(_, lv)], None)
8794 when tparamet && String.equal f SN.StdlibFunctions.is_dict_or_darray ->
8795 safely_refine_is_array env HackDictOrDArray p f lv
8796 | Aast.Call ((_, p, Aast.Id (_, f)), _, [(_, lv)], None)
8797 when tparamet && String.equal f SN.StdlibFunctions.is_vec_or_varray ->
8798 safely_refine_is_array env HackVecOrVArray p f lv
8799 | Aast.Call ((_, p, Aast.Id (_, f)), _, [(_, lv)], None)
8800 when String.equal f SN.StdlibFunctions.is_any_array ->
8801 refine_for_is
8802 ~hint_first:true
8804 tparamet
8806 (Reason.Rpredicated (p, f))
8807 ( p,
8808 Happly
8809 ( (p, "\\HH\\AnyArray"),
8810 [(p, Happly ((p, "_"), [])); (p, Happly ((p, "_"), []))] ) )
8811 | Aast.Call ((_, p, Aast.Id (_, f)), _, [(_, lv)], None)
8812 when tparamet && String.equal f SN.StdlibFunctions.is_php_array ->
8813 safely_refine_is_array env PHPArray p f lv
8814 | Aast.Call
8815 ( ( _,
8817 Aast.Class_const ((_, _, Aast.CI (_, class_name)), (_, method_name))
8820 [(_, shape); (_, field)],
8821 None )
8822 when tparamet
8823 && String.equal class_name SN.Shapes.cShapes
8824 && String.equal method_name SN.Shapes.keyExists ->
8825 key_exists env p shape field
8826 | Aast.Unop (Ast_defs.Unot, e) -> condition env (not tparamet) e
8827 | Aast.Is (ivar, h) ->
8828 refine_for_is ~hint_first:false env tparamet ivar (Reason.Ris (fst h)) h
8829 | _ -> (env, Local_id.Set.empty)
8831 and string2 env idl =
8832 let (env, tel) =
8833 List.fold_left idl ~init:(env, []) ~f:(fun (env, tel) x ->
8834 let (env, te, ty) = expr env x ~allow_awaitable:(*?*) false in
8835 let (_, p, _) = x in
8837 TypecheckerOptions.enable_strict_string_concat_interp
8838 (Env.get_tcopt env)
8839 then
8840 let r = Reason.Rinterp_operand p in
8841 let (env, formatter_tyvar) = Env.fresh_type_invariant env p in
8842 let stringlike =
8843 MakeType.union
8846 MakeType.arraykey r;
8847 MakeType.dynamic r;
8848 MakeType.hh_formatstring r formatter_tyvar;
8851 let (env, err_opt) =
8852 Result.fold
8853 ~ok:(fun env -> (env, None))
8854 ~error:(fun env -> (env, Some (ty, stringlike)))
8855 @@ Typing_ops.sub_type_res
8857 Reason.URstr_interp
8860 stringlike
8861 Typing_error.Callback.strict_str_interp_type_mismatch
8863 (env, hole_on_err ~err_opt te :: tel)
8864 else
8865 let env = Typing_substring.sub_string p env ty in
8866 (env, te :: tel))
8868 (env, List.rev tel)
8870 and user_attribute env ua =
8871 let (env, typed_ua_params) =
8872 List.map_env env ua.ua_params ~f:(fun env e ->
8873 let (env, te, _) = expr env e ~allow_awaitable:(*?*) false in
8874 (env, te))
8876 (env, { Aast.ua_name = ua.ua_name; Aast.ua_params = typed_ua_params })
8878 and file_attributes env file_attrs =
8879 (* Disable checking of error positions, as file attributes have spans that
8880 * aren't subspans of the class or function into which they are copied *)
8881 Errors.run_with_span Pos.none @@ fun () ->
8882 List.map_env env file_attrs ~f:(fun env fa ->
8883 let (env, user_attributes) =
8884 attributes_check_def env SN.AttributeKinds.file fa.fa_user_attributes
8886 let env = set_tcopt_unstable_features env fa in
8887 ( env,
8889 Aast.fa_user_attributes = user_attributes;
8890 Aast.fa_namespace = fa.fa_namespace;
8891 } ))
8893 and type_param env t =
8894 let (env, user_attributes) =
8895 attributes_check_def env SN.AttributeKinds.typeparam t.tp_user_attributes
8897 let (env, tp_parameters) = List.map_env env t.tp_parameters ~f:type_param in
8898 ( env,
8900 Aast.tp_variance = t.tp_variance;
8901 Aast.tp_name = t.tp_name;
8902 Aast.tp_parameters;
8903 Aast.tp_constraints = t.tp_constraints;
8904 Aast.tp_reified = reify_kind t.tp_reified;
8905 Aast.tp_user_attributes = user_attributes;
8908 (* Calls the method of a class, but allows the f callback to override the
8909 * return value type *)
8910 and overload_function
8911 make_call fpos p env class_id method_id el unpacked_element f =
8912 let (env, _tal, tcid, ty) = class_expr env [] class_id in
8913 let (env, (fty, tal)) =
8914 class_get
8915 ~is_method:true
8916 ~is_const:false
8917 ~coerce_from_ty:None
8920 method_id
8921 class_id
8923 let (env, (tel, typed_unpack_element, res, should_forget_fakes)) =
8924 call ~expected:None p env fty el unpacked_element
8926 let (env, ty) = f env fty res el tel in
8927 let (env, fty) = Env.expand_type env fty in
8928 let fty =
8929 map_ty fty ~f:(function
8930 | Tfun ft -> Tfun { ft with ft_ret = MakeType.unenforced ty }
8931 | ty -> ty)
8933 let te = Tast.make_typed_expr fpos fty (Aast.Class_const (tcid, method_id)) in
8934 (make_call env te tal tel typed_unpack_element ty, should_forget_fakes)
8936 and update_array_type ?lhs_of_null_coalesce p env e1 valkind =
8937 match valkind with
8938 | `lvalue
8939 | `lvalue_subexpr ->
8940 let (env, te1, ty1) =
8941 raw_expr
8942 ~valkind:`lvalue_subexpr
8943 ~check_defined:true
8946 ~allow_awaitable:(*?*) false
8948 begin
8949 match e1 with
8950 | (_, _, Lvar (_, x)) ->
8951 (* type_mapper has updated the type in ty1 typevars, but we
8952 need to update the local variable type too *)
8953 let env = set_local env (p, x) ty1 in
8954 (env, te1, ty1)
8955 | _ -> (env, te1, ty1)
8957 | _ -> raw_expr ?lhs_of_null_coalesce env e1 ~allow_awaitable:(*?*) false
8959 (* External API *)
8960 let expr ?expected env e =
8961 Typing_env.with_origin2 env Decl_counters.Body (fun env ->
8962 expr ?expected env e ~allow_awaitable:(*?*) false)
8964 let expr_with_pure_coeffects ?expected env e =
8965 Typing_env.with_origin2 env Decl_counters.Body (fun env ->
8966 expr_with_pure_coeffects ?expected env e ~allow_awaitable:(*?*) false)
8968 let stmt env st =
8969 Typing_env.with_origin env Decl_counters.Body (fun env -> stmt env st)