renaming Ast_defs `class_kind` into `classish_kind`
[hiphop-php.git] / hphp / hack / src / typing / typing.ml
blob6fc268b86c3ce1ffef9c1faea6b469b0a5810498
1 (*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
8 *)
10 (* This module implements the typing.
12 * Given an Nast.program, it infers the type of all the local
13 * variables, and checks that all the types are correct (aka
14 * consistent) *)
15 open Hh_prelude
16 open Common
17 open Aast
18 open Tast
19 open Typing_defs
20 open Typing_env_types
21 open Utils
22 open Typing_helpers
23 module TFTerm = Typing_func_terminality
24 module TUtils = Typing_utils
25 module Reason = Typing_reason
26 module Type = Typing_ops
27 module Env = Typing_env
28 module Inf = Typing_inference_env
29 module LEnv = Typing_lenv
30 module Async = Typing_async
31 module SubType = Typing_subtype
32 module Union = Typing_union
33 module Inter = Typing_intersection
34 module SN = Naming_special_names
35 module TVis = Typing_visibility
36 module Phase = Typing_phase
37 module TOG = Typing_object_get
38 module Subst = Decl_subst
39 module ExprDepTy = Typing_dependent_type.ExprDepTy
40 module TCO = TypecheckerOptions
41 module EnvFromDef = Typing_env_from_def
42 module C = Typing_continuations
43 module CMap = C.Map
44 module Try = Typing_try
45 module FL = FeatureLogging
46 module MakeType = Typing_make_type
47 module Cls = Decl_provider.Class
48 module Partial = Partial_provider
49 module Fake = Typing_fake_members
50 module ExpectedTy = Typing_helpers.ExpectedTy
51 module ITySet = Internal_type_set
53 type newable_class_info =
54 env
55 * Tast.targ list
56 * Tast.class_id
57 * [ `Class of pos_id * Cls.t * locl_ty | `Dynamic ] list
59 (*****************************************************************************)
60 (* Debugging *)
61 (*****************************************************************************)
63 (* A guess as to the last position we were typechecking, for use in debugging,
64 * such as figuring out what a runaway hh_server thread is doing. Updated
65 * only best-effort -- it's an approximation to point debugging in the right
66 * direction, nothing more. *)
67 let debug_last_pos = ref Pos.none
69 let debug_print_last_pos _ =
70 Hh_logger.info
71 "Last typecheck pos: %s"
72 (Pos.string (Pos.to_absolute !debug_last_pos))
74 (*****************************************************************************)
75 (* Helpers *)
76 (*****************************************************************************)
78 let mk_hole ?(source = Aast.Typing) expr ~ty_have ~ty_expect =
79 (* if the hole is generated from typing, we leave the type unchanged,
80 if it is a call to `[unsafe|enforced]_cast`, we give it the expected type
82 let ty_hole =
83 match source with
84 | Aast.Typing -> ty_have
85 | UnsafeCast _
86 | EnforcedCast _ ->
87 ty_expect
89 match expr with
90 | (ty, pos, Aast.Callconv (param_kind, expr)) ->
91 (* push the hole inside the `Callconv` constructor *)
92 let expr' =
93 make_typed_expr pos ty_hole @@ Aast.Hole (expr, ty_have, ty_expect, source)
95 make_typed_expr pos ty @@ Aast.Callconv (param_kind, expr')
96 | (_, pos, _) ->
97 make_typed_expr pos ty_hole @@ Aast.Hole (expr, ty_have, ty_expect, source)
99 let hole_on_err (te : Tast.expr) ~err_opt =
100 Option.value_map err_opt ~default:te ~f:(fun (ty_have, ty_expect) ->
101 mk_hole te ~ty_have ~ty_expect)
103 (* When typing compound assignments we generate a 'fake' expression which
104 desugars it to the operation on the rhs of the assignment. If there
105 was a subtyping error, we end up with the Hole on the fake rhs
106 rather than the original rhs. This function rewrites the
107 desugared expression with the Hole in the correct place *)
108 let resugar_binop expr =
109 match expr with
110 | ( topt,
112 Aast.(
113 Binop
114 ( _,
115 te1,
116 (_, _, Hole ((_, _, Binop (op, _, te2)), ty_have, ty_expect, source))
117 )) ) ->
118 let hte2 = mk_hole te2 ~ty_have ~ty_expect ~source in
119 let te = Aast.Binop (Ast_defs.Eq (Some op), te1, hte2) in
120 Some (topt, p, te)
121 | (topt, p, Aast.Binop (_, te1, (_, _, Aast.Binop (op, _, te2)))) ->
122 let te = Aast.Binop (Ast_defs.Eq (Some op), te1, te2) in
123 Some (topt, p, te)
124 | _ -> None
126 (* When recording subtyping or coercion errors for union and intersection types
127 we need to look at the error for each element and then reconstruct any
128 errors into a union or intersection. If there were no errors for any
129 element, the result if also `Ok`; if there was an error for at least
130 on element we have `Error` with list of actual and expected types *)
131 let fold_coercion_errs errs =
132 List.fold_left errs ~init:(Ok []) ~f:(fun acc err ->
133 match (acc, err) with
134 | (Ok xs, Ok x) -> Ok (x :: xs)
135 | (Ok xs, Error (x, y)) -> Error (x :: xs, y :: xs)
136 | (Error (xs, ys), Ok x) -> Error (x :: xs, x :: ys)
137 | (Error (xs, ys), Error (x, y)) -> Error (x :: xs, y :: ys))
139 let union_coercion_errs errs =
140 Result.fold
141 ~ok:(fun tys -> Ok (MakeType.union Reason.Rnone tys))
142 ~error:(fun (acts, exps) ->
143 Error (MakeType.union Reason.Rnone acts, MakeType.union Reason.Rnone exps))
144 @@ fold_coercion_errs errs
146 let intersect_coercion_errs errs =
147 Result.fold
148 ~ok:(fun tys -> Ok (MakeType.intersection Reason.Rnone tys))
149 ~error:(fun (acts, exps) ->
150 Error
151 ( MakeType.intersection Reason.Rnone acts,
152 MakeType.intersection Reason.Rnone exps ))
153 @@ fold_coercion_errs errs
155 (** Given the type of an argument that has been unpacked and typed against
156 positional and variadic function parameter types, apply the subtyping /
157 coercion errors back to the original packed type. *)
158 let pack_errs pos ty subtyping_errs =
159 let nothing =
160 MakeType.nothing @@ Reason.Rsolve_fail (Pos_or_decl.of_raw_pos pos)
162 let rec aux ~k = function
163 (* Case 1: we have a type error at this positional parameter so
164 replace the type parameter which caused it with the expected type *)
165 | ((Some (_, ty) :: rest, var_opt), _ :: tys)
166 (* Case 2: there was no type error here so retain the original type
167 parameter *)
168 | ((None :: rest, var_opt), ty :: tys) ->
169 (* recurse for any remaining positional parameters and add the
170 corrected (case 1) or original (case 2) type to the front of the
171 list of type parameters in the continuation *)
172 aux ((rest, var_opt), tys) ~k:(fun tys -> k (ty :: tys))
173 (* Case 3: we have a type error at the variadic parameter so replace
174 the type parameter which cased it with the expected type *)
175 | ((_, (Some (_, ty) as var_opt)), _ :: tys) ->
176 (* recurse with the variadic parameter error and add the
177 corrected type to the front of the list of type parameters in the
178 continuation *)
179 aux (([], var_opt), tys) ~k:(fun tys -> k (ty :: tys))
180 (* Case 4: we have a variadic parameter but no error - we're done so
181 pass the remaining unchanged type parameters into the contination
182 to rebuild corrected type params in the right order *)
183 | ((_, None), tys) -> k tys
184 (* Case 5: no more type parameters - again we're done so pass empty
185 list to continuation and rebuild corrected type params in the right
186 order *)
187 | (_, []) -> k []
189 (* The only types that _can_ be upacked are tuples and pairs; match on the
190 type to get the type parameters, pass them to our recursive function
191 aux to subsitute the expected type where we have a type error
192 then reconstruct the type in the continuation *)
193 match deref ty with
194 | (r, Ttuple tys) ->
195 aux (subtyping_errs, tys) ~k:(fun tys -> mk (r, Ttuple tys))
196 | (r, Tclass (pos_id, exact, tys)) ->
197 aux (subtyping_errs, tys) ~k:(fun tys ->
198 mk (r, Tclass (pos_id, exact, tys)))
199 | _ -> nothing
201 let err_witness env p = TUtils.terr env (Reason.Rwitness p)
203 let triple_to_pair (env, te, ty) = (env, (te, ty))
205 let with_special_coeffects env cap_ty unsafe_cap_ty f =
206 let init =
207 Option.map (Env.next_cont_opt env) ~f:(fun next_cont ->
208 let initial_locals = next_cont.Typing_per_cont_env.local_types in
209 let tpenv = Env.get_tpenv env in
210 (initial_locals, tpenv))
212 Typing_lenv.stash_and_do env (Env.all_continuations env) (fun env ->
213 let env =
214 match init with
215 | None -> env
216 | Some (initial_locals, tpenv) ->
217 let env = Env.reinitialize_locals env in
218 let env = Env.set_locals env initial_locals in
219 let env = Env.env_with_tpenv env tpenv in
222 let (env, _ty) =
223 Typing_coeffects.register_capabilities env cap_ty unsafe_cap_ty
225 f env)
227 (* Set all the types in an expression to the given type. *)
228 let with_type ty env (e : Nast.expr) : Tast.expr =
229 let visitor =
230 object (self)
231 inherit [_] Aast.map
233 method! on_expr env ((), p, expr_) = (ty, p, self#on_expr_ env expr_)
235 method on_'ex _ () = ty
237 method on_'fb _ _ = ()
239 method on_'en _ _ = env
242 visitor#on_expr () e
244 let invalid_expr_ env p : Tast.expr_ =
245 let expr = ((), p, Naming.invalid_expr_ p) in
246 let ty = TUtils.terr env Reason.Rnone in
247 let (_, _, expr_) = with_type ty Tast.dummy_saved_env expr in
248 expr_
250 let expr_error env (r : Reason.t) (e : Nast.expr) =
251 let ty = TUtils.terr env r in
252 (env, with_type ty Tast.dummy_saved_env e, ty)
254 let expr_any env p e =
255 let ty = Typing_utils.mk_tany env p in
256 (env, with_type ty Tast.dummy_saved_env e, ty)
258 let unbound_name env (pos, name) e =
259 let strictish = Partial.should_check_error (Env.get_mode env) 4107 in
260 match Env.get_mode env with
261 | FileInfo.Mstrict ->
262 Errors.unbound_name_typing pos name;
263 expr_error env (Reason.Rwitness pos) e
264 | FileInfo.Mpartial when strictish ->
265 Errors.unbound_name_typing pos name;
266 expr_error env (Reason.Rwitness pos) e
267 | FileInfo.Mhhi
268 | FileInfo.Mpartial ->
269 expr_any env pos e
271 (* Is this type Traversable<vty> or Container<vty> for some vty? *)
272 let get_value_collection_inst ty =
273 match get_node ty with
274 | Tclass ((_, c), _, [vty])
275 when String.equal c SN.Collections.cTraversable
276 || String.equal c SN.Collections.cContainer ->
277 Some vty
278 (* If we're expecting a mixed or a nonnull then we can just assume
279 * that the element type is mixed *)
280 | Tnonnull -> Some (MakeType.mixed Reason.Rnone)
281 | Tany _ -> Some ty
282 | _ -> None
284 (* Is this type KeyedTraversable<kty,vty>
285 * or KeyedContainer<kty,vty>
286 * for some kty, vty?
288 let get_key_value_collection_inst p ty =
289 match get_node ty with
290 | Tclass ((_, c), _, [kty; vty])
291 when String.equal c SN.Collections.cKeyedTraversable
292 || String.equal c SN.Collections.cKeyedContainer ->
293 Some (kty, vty)
294 (* If we're expecting a mixed or a nonnull then we can just assume
295 * that the key type is arraykey and the value type is mixed *)
296 | Tnonnull ->
297 let arraykey = MakeType.arraykey (Reason.Rkey_value_collection_key p) in
298 let mixed = MakeType.mixed Reason.Rnone in
299 Some (arraykey, mixed)
300 | Tany _ -> Some (ty, ty)
301 | _ -> None
303 (* Is this type varray<vty> or a supertype for some vty? *)
304 let get_varray_inst ty =
305 match get_node ty with
306 (* It's varray<vty> *)
307 | Tvarray vty -> Some vty
308 | _ -> get_value_collection_inst ty
310 (* Is this type one of the value collection types with element type vty? *)
311 let get_vc_inst vc_kind ty =
312 match get_node ty with
313 | Tclass ((_, c), _, [vty]) when String.equal c (Nast.vc_kind_to_name vc_kind)
315 Some vty
316 | _ -> get_value_collection_inst ty
318 (* Is this type one of the three key-value collection types
319 * e.g. dict<kty,vty> or a supertype for some kty and vty? *)
320 let get_kvc_inst p kvc_kind ty =
321 match get_node ty with
322 | Tclass ((_, c), _, [kty; vty])
323 when String.equal c (Nast.kvc_kind_to_name kvc_kind) ->
324 Some (kty, vty)
325 | _ -> get_key_value_collection_inst p ty
327 (* Is this type darray<kty, vty> or a supertype for some kty and vty? *)
328 (* Check whether this is a function type that (a) either returns a disposable
329 * or (b) has the <<__ReturnDisposable>> attribute
331 let is_return_disposable_fun_type env ty =
332 let (_env, ty) = Env.expand_type env ty in
333 match get_node ty with
334 | Tfun ft ->
335 get_ft_return_disposable ft
336 || Option.is_some
337 (Typing_disposable.is_disposable_type env ft.ft_ret.et_type)
338 | _ -> false
340 (* Turn an environment into a local_id_map suitable to be embedded
341 * into an AssertEnv statement
343 let annot_map env =
344 match Env.next_cont_opt env with
345 | Some { Typing_per_cont_env.local_types; _ } ->
346 Some (Local_id.Map.map (fun (ty, pos, _expr_id) -> (pos, ty)) local_types)
347 | None -> None
349 (* Similar to annot_map above, but filters the map to only contain
350 * information about locals in lset
352 let refinement_annot_map env lset =
353 match annot_map env with
354 | Some map ->
355 let map =
356 Local_id.Map.filter (fun lid _ -> Local_id.Set.mem lid lset) map
358 if Local_id.Map.is_empty map then
359 None
360 else
361 Some map
362 | None -> None
364 let assert_env_blk ~pos ~at annotation_kind env_map_opt blk =
365 let mk_assert map = (pos, Aast.AssertEnv (annotation_kind, map)) in
366 let annot_blk = Option.to_list (Option.map ~f:mk_assert env_map_opt) in
367 match at with
368 | `Start -> annot_blk @ blk
369 | `End -> blk @ annot_blk
371 let assert_env_stmt ~pos ~at annotation_kind env_map_opt stmt =
372 let mk_assert map = (pos, Aast.AssertEnv (annotation_kind, map)) in
373 match env_map_opt with
374 | Some env_map ->
375 let stmt = (pos, stmt) in
376 let blk =
377 match at with
378 | `Start -> [mk_assert env_map; stmt]
379 | `End -> [stmt; mk_assert env_map]
381 Aast.Block blk
382 | None -> stmt
384 let set_tcopt_unstable_features env { fa_user_attributes; _ } =
385 match
386 Naming_attributes.find
387 SN.UserAttributes.uaEnableUnstableFeatures
388 fa_user_attributes
389 with
390 | None -> env
391 | Some { ua_name = _; ua_params } ->
392 let ( = ) = String.equal in
393 List.fold ua_params ~init:env ~f:(fun env (_, _, feature) ->
394 match feature with
395 | Aast.String s when s = SN.UnstableFeatures.ifc ->
396 Env.map_tcopt ~f:TypecheckerOptions.enable_ifc env
397 | Aast.String s when s = SN.UnstableFeatures.readonly ->
398 Env.map_tcopt ~f:(fun t -> TypecheckerOptions.set_readonly t true) env
399 | Aast.String s when s = SN.UnstableFeatures.modules ->
400 Env.map_tcopt ~f:(fun t -> TypecheckerOptions.set_modules t true) env
401 | Aast.String s when s = SN.UnstableFeatures.expression_trees ->
402 Env.map_tcopt
403 ~f:(fun t ->
404 TypecheckerOptions.set_tco_enable_expression_trees t true)
406 | _ -> env)
408 (** Do a subtype check of inferred type against expected type *)
409 let check_expected_ty_res
410 (message : string)
411 (env : env)
412 (inferred_ty : locl_ty)
413 (expected : ExpectedTy.t option) : (env, env) result =
414 match expected with
415 | None -> Ok env
416 | Some ExpectedTy.{ pos = p; reason = ur; ty } ->
417 Typing_log.(
418 log_with_level env "typing" ~level:1 (fun () ->
419 log_types
420 (Pos_or_decl.of_raw_pos p)
423 Log_head
424 ( Printf.sprintf
425 "Typing.check_expected_ty %s enforced=%s"
426 message
427 (match ty.et_enforced with
428 | Unenforced -> "unenforced"
429 | Enforced -> "enforced"
430 | PartiallyEnforced (_, (_, cn)) ->
431 "partially enforced " ^ cn),
433 Log_type ("inferred_ty", inferred_ty);
434 Log_type ("expected_ty", ty.et_type);
435 ] );
436 ]));
437 Typing_coercion.coerce_type_res p ur env inferred_ty ty Errors.unify_error
439 let check_expected_ty message env inferred_ty expected =
440 Result.fold ~ok:Fn.id ~error:Fn.id
441 @@ check_expected_ty_res message env inferred_ty expected
443 let check_inout_return ret_pos env =
444 let params = Local_id.Map.elements (Env.get_params env) in
445 List.fold params ~init:env ~f:(fun env (id, (ty, param_pos, mode)) ->
446 match mode with
447 | FPinout ->
448 (* Whenever the function exits normally, we require that each local
449 * corresponding to an inout parameter be compatible with the original
450 * type for the parameter (under subtyping rules). *)
451 let (local_ty, local_pos) = Env.get_local_pos env id in
452 let (env, ety) = Env.expand_type env local_ty in
453 let pos =
454 if not (Pos.equal Pos.none local_pos) then
455 local_pos
456 else if not (Pos.equal Pos.none ret_pos) then
457 ret_pos
458 else
459 param_pos
461 let param_ty = mk (Reason.Rinout_param (get_pos ty), get_node ty) in
462 Type.sub_type
464 Reason.URassign_inout
467 param_ty
468 Errors.inout_return_type_mismatch
469 | _ -> env)
471 let fun_implicit_return env pos ret = function
472 | Ast_defs.FGenerator
473 | Ast_defs.FAsyncGenerator ->
475 | Ast_defs.FSync ->
476 (* A function without a terminal block has an implicit return; the
477 * "void" type *)
478 let env = check_inout_return Pos.none env in
479 let r = Reason.Rno_return pos in
480 let rty = MakeType.void r in
481 Typing_return.implicit_return env pos ~expected:ret ~actual:rty
482 | Ast_defs.FAsync ->
483 (* An async function without a terminal block has an implicit return;
484 * the Awaitable<void> type *)
485 let r = Reason.Rno_return_async pos in
486 let rty = MakeType.awaitable r (MakeType.void r) in
487 Typing_return.implicit_return env pos ~expected:ret ~actual:rty
489 (* Set a local; must not be already assigned if it is a using variable *)
490 let set_local ?(is_using_clause = false) env (pos, x) ty =
491 if Env.is_using_var env x then
492 if is_using_clause then
493 Errors.duplicate_using_var pos
494 else
495 Errors.illegal_disposable pos "assigned";
496 let env = Env.set_local env x ty pos in
497 if is_using_clause then
498 Env.set_using_var env x
499 else
502 (* Require a new construct with disposable *)
503 let rec enforce_return_disposable _env e =
504 match e with
505 | (_, _, New _) -> ()
506 | (_, _, Call _) -> ()
507 | (_, _, Await (_, _, Call _)) -> ()
508 | (_, _, Hole (e, _, _, _)) -> enforce_return_disposable _env e
509 | (_, p, _) -> Errors.invalid_return_disposable p
511 (* Wrappers around the function with the same name in Typing_lenv, which only
512 * performs the move/save and merge operation if we are in a try block or in a
513 * function with return type 'noreturn'.
514 * This enables significant perf improvement, because this is called at every
515 * function of method call, when most calls are outside of a try block. *)
516 let move_and_merge_next_in_catch env =
517 if env.in_try || TFTerm.is_noreturn env then
518 LEnv.move_and_merge_next_in_cont env C.Catch
519 else
520 LEnv.drop_cont env C.Next
522 let save_and_merge_next_in_catch env =
523 if env.in_try || TFTerm.is_noreturn env then
524 LEnv.save_and_merge_next_in_cont env C.Catch
525 else
528 let might_throw env = save_and_merge_next_in_catch env
530 let branch :
531 type res. env -> (env -> env * res) -> (env -> env * res) -> env * res * res
533 fun env branch1 branch2 ->
534 let parent_lenv = env.lenv in
535 let (env, tbr1) = branch1 env in
536 let lenv1 = env.lenv in
537 let env = { env with lenv = parent_lenv } in
538 let (env, tbr2) = branch2 env in
539 let lenv2 = env.lenv in
540 let env = LEnv.union_lenvs env parent_lenv lenv1 lenv2 in
541 (env, tbr1, tbr2)
543 let as_expr env ty1 pe e =
544 let env = Env.open_tyvars env pe in
545 let (env, tv) = Env.fresh_type env pe in
546 let (env, expected_ty, tk, tv) =
547 match e with
548 | As_v _ ->
549 let tk = MakeType.mixed Reason.Rnone in
550 (env, MakeType.traversable (Reason.Rforeach pe) tv, tk, tv)
551 | As_kv _ ->
552 let (env, tk) = Env.fresh_type env pe in
553 (env, MakeType.keyed_traversable (Reason.Rforeach pe) tk tv, tk, tv)
554 | Await_as_v _ ->
555 let tk = MakeType.mixed Reason.Rnone in
556 (env, MakeType.async_iterator (Reason.Rasyncforeach pe) tv, tk, tv)
557 | Await_as_kv _ ->
558 let (env, tk) = Env.fresh_type env pe in
559 ( env,
560 MakeType.async_keyed_iterator (Reason.Rasyncforeach pe) tk tv,
562 tv )
564 let rec distribute_union env ty =
565 let (env, ty) = Env.expand_type env ty in
566 match get_node ty with
567 | Tunion tyl ->
568 let (env, errs) =
569 List.fold tyl ~init:(env, []) ~f:(fun (env, errs) ty ->
570 let (env, err) = distribute_union env ty in
571 (env, err :: errs))
573 (env, union_coercion_errs errs)
574 | _ ->
575 if SubType.is_sub_type_for_union env ty (MakeType.dynamic Reason.Rnone)
576 then
577 let env = SubType.sub_type env ty tk (Errors.unify_error_at pe) in
578 let env = SubType.sub_type env ty tv (Errors.unify_error_at pe) in
579 (env, Ok ty)
580 else
581 let ur = Reason.URforeach in
582 let (env, err) =
583 Result.fold
584 ~ok:(fun env -> (env, Ok ty))
585 ~error:(fun env -> (env, Error (ty, expected_ty)))
586 @@ Type.sub_type_res pe ur env ty expected_ty Errors.unify_error
588 (env, err)
591 let (env, err_res) = distribute_union env ty1 in
592 let err_opt =
593 match err_res with
594 | Ok _ -> None
595 | Error (act, exp) -> Some (act, exp)
597 let env = Env.set_tyvar_variance env expected_ty in
598 (Typing_solver.close_tyvars_and_solve env, tk, tv, err_opt)
600 (* These functions invoke special printing functions for Typing_env. They do not
601 * appear in user code, but we still check top level function calls against their
602 * names. *)
603 let typing_env_pseudofunctions =
604 SN.PseudoFunctions.(
605 String.Hash_set.of_list
606 ~growth_allowed:false
607 [hh_show; hh_show_env; hh_log_level; hh_force_solve; hh_loop_forever])
609 let loop_forever env =
610 (* forever = up to 10 minutes, to avoid accidentally stuck processes *)
611 for i = 1 to 600 do
612 (* Look up things in shared memory occasionally to have a chance to be
613 * interrupted *)
614 match Env.get_class env "FOR_TEST_ONLY" with
615 | None -> Unix.sleep 1
616 | _ -> assert false
617 done;
618 Utils.assert_false_log_backtrace
619 (Some "hh_loop_forever was looping for more than 10 minutes")
621 let is_parameter env x = Local_id.Map.mem x (Env.get_params env)
623 let check_escaping_var env (pos, x) =
624 if Env.is_using_var env x then
625 if Local_id.equal x this then
626 Errors.escaping_this pos
627 else if is_parameter env x then
628 Errors.escaping_disposable_parameter pos
629 else
630 Errors.escaping_disposable pos
631 else
634 let make_result env p te ty =
635 (* Set the variance of any type variables that were generated according
636 * to how they appear in the expression type *)
637 let env = Env.set_tyvar_variance env ty in
638 (env, Tast.make_typed_expr p ty te, ty)
640 let localize_targ env ta =
641 let pos = fst ta in
642 let (env, targ) = Phase.localize_targ ~check_well_kinded:true env ta in
643 (env, targ, ExpectedTy.make pos Reason.URhint (fst targ))
645 let set_function_pointer ty =
646 match get_node ty with
647 | Tfun ft ->
648 let ft = set_ft_is_function_pointer ft true in
649 mk (get_reason ty, Tfun ft)
650 | _ -> ty
652 let xhp_attribute_decl_ty env sid obj attr =
653 let (namepstr, valpty) = attr in
654 let (valp, valty) = valpty in
655 let (env, (declty, _tal)) =
656 TOG.obj_get
657 ~obj_pos:(fst sid)
658 ~is_method:false
659 ~inst_meth:false
660 ~meth_caller:false
661 ~nullsafe:None
662 ~coerce_from_ty:None
663 ~explicit_targs:[]
664 ~class_id:(CI sid)
665 ~member_id:namepstr
666 ~on_error:Errors.unify_error
670 let ureason = Reason.URxhp (snd sid, snd namepstr) in
671 let (env, err_opt) =
672 Result.fold
673 ~ok:(fun env -> (env, None))
674 ~error:(fun env -> (env, Some (valty, declty)))
675 @@ Typing_coercion.coerce_type_res
676 valp
677 ureason
679 valty
680 (MakeType.unenforced declty)
681 Errors.xhp_attribute_does_not_match_hint
683 (env, declty, err_opt)
685 let closure_check_param env param =
686 match hint_of_type_hint param.param_type_hint with
687 | None -> env
688 | Some hty ->
689 let hint_pos = fst hty in
690 let (env, hty) =
691 Phase.localize_hint_no_subst env ~ignore_errors:false hty
693 let paramty = Env.get_local env (Local_id.make_unscoped param.param_name) in
694 let env =
695 Typing_coercion.coerce_type
696 hint_pos
697 Reason.URhint
699 paramty
700 (MakeType.unenforced hty)
701 Errors.unify_error
705 let stash_conts_for_closure env p is_anon captured f =
706 let captured =
707 if is_anon && TypecheckerOptions.any_coeffects (Env.get_tcopt env) then
708 Typing_coeffects.(
709 (Pos.none, local_capability_id) :: (Pos.none, capability_id) :: captured)
710 else
711 captured
713 let captured =
714 if Env.is_local_defined env this then
715 (Pos.none, this) :: captured
716 else
717 captured
719 let init =
720 Option.map (Env.next_cont_opt env) ~f:(fun next_cont ->
721 let initial_locals =
722 if is_anon then
723 Env.get_locals env captured
724 else
725 next_cont.Typing_per_cont_env.local_types
727 let initial_fakes =
728 Fake.forget (Env.get_fake_members env) Reason.(Blame (p, BSlambda))
730 let tpenv = Env.get_tpenv env in
731 (initial_locals, initial_fakes, tpenv))
733 Typing_lenv.stash_and_do env (Env.all_continuations env) (fun env ->
734 let env =
735 match init with
736 | None -> env
737 | Some (initial_locals, initial_fakes, tpenv) ->
738 let env = Env.reinitialize_locals env in
739 let env = Env.set_locals env initial_locals in
740 let env = Env.set_fake_members env initial_fakes in
741 let env = Env.env_with_tpenv env tpenv in
744 f env)
746 let type_capability env ctxs unsafe_ctxs default_pos =
747 (* No need to repeat the following check (saves time) for unsafe_ctx
748 because it's synthetic and well-kinded by construction *)
749 Option.iter ctxs ~f:(fun (_pos, hl) ->
750 List.iter
753 (Typing_kinding.Simple.check_well_kinded_hint ~in_signature:false env));
755 let cc = Decl_hint.aast_contexts_to_decl_capability in
756 let (decl_pos, cap) = cc env.decl_env ctxs default_pos in
757 let (env, cap_ty) =
758 match cap with
759 | CapTy ty -> Phase.localize_no_subst env ~ignore_errors:false ty
760 | CapDefaults p -> (env, MakeType.default_capability p)
762 if TypecheckerOptions.strict_contexts (Env.get_tcopt env) then
763 Typing_coeffects.validate_capability env decl_pos cap_ty;
764 let (env, unsafe_cap_ty) =
765 match snd @@ cc env.decl_env unsafe_ctxs default_pos with
766 | CapTy ty -> Phase.localize_no_subst env ~ignore_errors:false ty
767 | CapDefaults p -> (env, MakeType.default_capability_unsafe p)
769 (env, cap_ty, unsafe_cap_ty)
771 let requires_consistent_construct = function
772 | CIstatic -> true
773 | CIexpr _ -> true
774 | CIparent -> false
775 | CIself -> false
776 | CI _ -> false
778 (* Caller will be looking for a particular form of expected type
779 * e.g. a function type (when checking lambdas) or tuple type (when checking
780 * tuples). First expand the expected type and elide single union; also
781 * strip nullables, so ?t becomes t, as context will always accept a t if a ?t
782 * is expected.
784 let expand_expected_and_get_node env (expected : ExpectedTy.t option) =
785 match expected with
786 | None -> (env, None)
787 | Some ExpectedTy.{ pos = p; reason = ur; ty = { et_type = ty; _ }; _ } ->
788 let (env, ty) = Env.expand_type env ty in
789 (match get_node ty with
790 | Tunion [ty] -> (env, Some (p, ur, ty, get_node ty))
791 | Toption ty -> (env, Some (p, ur, ty, get_node ty))
792 | _ -> (env, Some (p, ur, ty, get_node ty)))
794 let uninstantiable_error env reason_pos cid c_tc_pos c_name c_usage_pos c_ty =
795 let reason =
796 match cid with
797 | CIexpr _ ->
798 let ty_str = "This would be " ^ Typing_print.error env c_ty in
799 Some (reason_pos, ty_str)
800 | _ -> None
802 Errors.uninstantiable_class c_usage_pos c_tc_pos c_name reason
804 let coerce_to_throwable pos env exn_ty =
805 let throwable_ty = MakeType.throwable (Reason.Rthrow pos) in
806 Typing_coercion.coerce_type
808 Reason.URthrow
810 exn_ty
811 { et_type = throwable_ty; et_enforced = Unenforced }
812 Errors.unify_error
814 let shape_field_pos = function
815 | Ast_defs.SFlit_int (p, _)
816 | Ast_defs.SFlit_str (p, _) ->
818 | Ast_defs.SFclass_const ((cls_pos, _), (mem_pos, _)) ->
819 Pos.btw cls_pos mem_pos
821 let set_valid_rvalue p env x ty =
822 let env = set_local env (p, x) ty in
823 (* We are assigning a new value to the local variable, so we need to
824 * generate a new expression id
826 Env.set_local_expr_id env x (Ident.tmp ())
828 (* Produce an error if assignment is used in the scope of the |> operator, i.e.
829 * if $$ is in scope *)
830 let error_if_assign_in_pipe p env =
831 let dd_var = Local_id.make_unscoped SN.SpecialIdents.dollardollar in
832 let dd_defined = Env.is_local_defined env dd_var in
833 if dd_defined then
834 Errors.unimplemented_feature p "Assignment within pipe expressions"
836 let is_hack_collection env ty =
837 (* TODO(like types) This fails if a collection is used as a parameter under
838 * pessimization, because ~Vector<int> </: ConstCollection<mixed>. This is the
839 * test we use to see whether to update the expression id for expressions
840 * $vector[0] = $x and $vector[] = $x. If this is false, the receiver is assumed
841 * to be a Hack array which are COW. This approximation breaks down in the presence
842 * of dynamic. It is unclear whether we should change an expression id if the
843 * receiver is dynamic. *)
844 Typing_solver.is_sub_type
847 (MakeType.const_collection Reason.Rnone (MakeType.mixed Reason.Rnone))
849 let check_class_get env p def_pos cid mid ce e function_pointer =
850 match e with
851 | CIself when get_ce_abstract ce ->
852 begin
853 match Env.get_self_id env with
854 | Some self ->
855 (* at runtime, self:: in a trait is a call to whatever
856 * self:: is in the context of the non-trait "use"-ing
857 * the trait's code *)
858 begin
859 match Env.get_class env self with
860 | Some cls when Ast_defs.is_c_trait (Cls.kind cls) ->
861 (* Ban self::some_abstract_method() in a trait, if the
862 * method is also defined in a trait.
864 * Abstract methods from interfaces are fine: we'll check
865 * in the child class that we actually have an
866 * implementation. *)
867 (match Decl_provider.get_class (Env.get_ctx env) ce.ce_origin with
868 | Some meth_cls when Ast_defs.is_c_trait (Cls.kind meth_cls) ->
869 Errors.self_abstract_call mid p def_pos
870 | _ -> ())
871 | _ ->
872 (* Ban self::some_abstract_method() in a class. This will
873 * always error. *)
874 Errors.self_abstract_call mid p def_pos
876 | None -> ()
878 | CIparent when get_ce_abstract ce ->
879 Errors.parent_abstract_call mid p def_pos
880 | CI _ when get_ce_abstract ce && function_pointer ->
881 Errors.abstract_function_pointer cid mid p def_pos
882 | CI _ when get_ce_abstract ce ->
883 Errors.classname_abstract_call cid mid p def_pos
884 | CI (_, classname) when get_ce_synthesized ce ->
885 Errors.static_synthetic_method classname mid p def_pos
886 | _ -> ()
888 (** Given an identifier for a function, find its function type in the
889 * environment and localise it with the input type parameters. If the function
890 * cannot be found, return [Terr].
892 let fun_type_of_id env x tal el =
893 match Env.get_fun env (snd x) with
894 | None ->
895 let (env, _, ty) = unbound_name env x ((), Pos.none, Aast.Null) in
896 (env, ty, [])
897 | Some
899 fe_type;
900 fe_pos;
901 fe_deprecated;
902 fe_support_dynamic_type;
903 fe_internal;
904 fe_module;
906 } ->
907 (match get_node fe_type with
908 | Tfun ft ->
909 let ft =
910 Typing_special_fun.transform_special_fun_ty ft x (List.length el)
912 let ety_env = empty_expand_env in
913 let (env, tal) =
914 Phase.localize_targs
915 ~check_well_kinded:true
916 ~is_method:true
917 ~def_pos:fe_pos
918 ~use_pos:(fst x)
919 ~use_name:(strip_ns (snd x))
921 ft.ft_tparams
922 (List.map ~f:snd tal)
924 let ft =
925 Typing_enforceability.compute_enforced_and_pessimize_fun_type env ft
927 let use_pos = fst x in
928 let def_pos = fe_pos in
929 let (env, ft) =
930 Phase.(
931 localize_ft
932 ~instantiation:
933 { use_name = strip_ns (snd x); use_pos; explicit_targs = tal }
934 ~def_pos
935 ~ety_env
939 let fty =
940 Typing_dynamic.relax_method_type
942 fe_support_dynamic_type
943 (get_reason fe_type)
946 TVis.check_deprecated ~use_pos ~def_pos fe_deprecated;
947 let curr_module = Env.get_module env in
948 begin
949 match fe_module with
950 | Some m
951 when fe_internal
952 && not (Option.equal String.equal fe_module curr_module) ->
953 Errors.module_mismatch (fst x) fe_pos curr_module m
954 | _ -> ()
955 end;
956 (env, fty, tal)
957 | _ -> failwith "Expected function type")
960 * Checks if a class (given by cty) contains a given static method.
962 * We could refactor this + class_get
964 let class_contains_smethod env cty (_pos, mid) =
965 let lookup_member ty =
966 match get_class_type ty with
967 | Some ((_, c), _, _) ->
968 (match Env.get_class env c with
969 | None -> false
970 | Some class_ ->
971 Option.is_some @@ Env.get_static_member true env class_ mid)
972 | None -> false
974 let (_env, tyl) =
975 TUtils.get_concrete_supertypes ~abstract_enum:true env cty
977 List.exists tyl ~f:lookup_member
979 (* To be a valid trait declaration, all of its 'require extends' must
980 * match; since there's no multiple inheritance, it follows that all of
981 * the 'require extends' must belong to the same inheritance hierarchy
982 * and one of them should be the child of all the others *)
983 let trait_most_concrete_req_class trait env =
984 List.fold
985 (Cls.all_ancestor_reqs trait)
987 begin
988 fun acc (_p, ty) ->
989 let (_r, (_p, name), _paraml) = TUtils.unwrap_class_type ty in
990 let keep =
991 match acc with
992 | Some (c, _ty) -> Cls.has_ancestor c name
993 | None -> false
995 if keep then
997 else
998 let class_ = Env.get_class env name in
999 match class_ with
1000 | None -> acc
1001 | Some c when Ast_defs.is_c_interface (Cls.kind c) -> acc
1002 | Some c when Ast_defs.is_c_trait (Cls.kind c) ->
1003 (* this is an error case for which Typing_type_wellformedness spits out
1004 * an error, but does *not* currently remove the offending
1005 * 'require extends' or 'require implements' *)
1007 | Some c -> Some (c, ty)
1009 ~init:None
1011 let check_arity ?(did_unpack = false) pos pos_def ft (arity : int) =
1012 let exp_min = Typing_defs.arity_min ft in
1013 if arity < exp_min then Errors.typing_too_few_args exp_min arity pos pos_def;
1014 match ft.ft_arity with
1015 | Fstandard ->
1016 let exp_max = List.length ft.ft_params in
1017 let arity =
1018 if did_unpack then
1019 arity + 1
1020 else
1021 arity
1023 if arity > exp_max then
1024 Errors.typing_too_many_args exp_max arity pos pos_def
1025 | Fvariadic _ -> ()
1027 let check_lambda_arity lambda_pos def_pos lambda_ft expected_ft =
1028 match (lambda_ft.ft_arity, expected_ft.ft_arity) with
1029 | (Fstandard, Fstandard) ->
1030 let expected_min = Typing_defs.arity_min expected_ft in
1031 let lambda_min = Typing_defs.arity_min lambda_ft in
1032 if lambda_min < expected_min then
1033 Errors.typing_too_few_args expected_min lambda_min lambda_pos def_pos;
1034 if lambda_min > expected_min then
1035 Errors.typing_too_many_args expected_min lambda_min lambda_pos def_pos
1036 | (_, _) -> ()
1038 (* The variadic capture argument is an array listing the passed
1039 * variable arguments for the purposes of the function body; callsites
1040 * should not unify with it *)
1041 let variadic_param env ft =
1042 match ft.ft_arity with
1043 | Fvariadic param -> (env, Some param)
1044 | Fstandard -> (env, None)
1046 let param_modes ?(is_variadic = false) ({ fp_pos; _ } as fp) (_, pos, e) =
1047 match (get_fp_mode fp, e) with
1048 | (FPnormal, Callconv _) ->
1049 Errors.inout_annotation_unexpected pos fp_pos is_variadic
1050 | (FPnormal, _) -> ()
1051 | (FPinout, Callconv (Ast_defs.Pinout, _)) -> ()
1052 | (FPinout, _) -> Errors.inout_annotation_missing pos fp_pos
1054 let split_remaining_params_required_optional ft remaining_params =
1055 (* Same example as above
1057 * function f(int $i, string $j, float $k = 3.14, mixed ...$m): void {}
1058 * function g((string, float, bool) $t): void {
1059 * f(3, ...$t);
1062 * `remaining_params` will contain [string, float] and there has been 1 parameter consumed. The min_arity
1063 * of this function is 2, so there is 1 required parameter remaining and 1 optional parameter.
1065 let min_arity =
1066 List.count
1067 ~f:(fun fp -> not (Typing_defs.get_fp_has_default fp))
1068 ft.ft_params
1070 let original_params = ft.ft_params in
1071 let consumed = List.length original_params - List.length remaining_params in
1072 let required_remaining = Int.max (min_arity - consumed) 0 in
1073 let (required_params, optional_params) =
1074 List.split_n remaining_params required_remaining
1076 (consumed, required_params, optional_params)
1078 let generate_splat_type_vars
1079 env p required_params optional_params variadic_param =
1080 let (env, d_required) =
1081 List.map_env env required_params ~f:(fun env _ -> Env.fresh_type env p)
1083 let (env, d_optional) =
1084 List.map_env env optional_params ~f:(fun env _ -> Env.fresh_type env p)
1086 let (env, d_variadic) =
1087 match variadic_param with
1088 | None -> (env, None)
1089 | Some _ ->
1090 let (env, ty) = Env.fresh_type env p in
1091 (env, Some ty)
1093 (env, (d_required, d_optional, d_variadic))
1095 let call_param
1096 env param (((_, pos, expr_) as e : Nast.expr), arg_ty) ~is_variadic :
1097 env * (locl_ty * locl_ty) option =
1098 param_modes ~is_variadic param e;
1099 (* When checking params, the type 'x' may be expression dependent. Since
1100 * we store the expression id in the local env for Lvar, we want to apply
1101 * it in this case.
1103 let (env, dep_ty) =
1104 match expr_ with
1105 | Hole ((_, _, Lvar _), _, _, _)
1106 | Lvar _ ->
1107 ExprDepTy.make env ~cid:(CIexpr e) arg_ty
1108 | _ -> (env, arg_ty)
1110 Result.fold
1111 ~ok:(fun env -> (env, None))
1112 ~error:(fun env -> (env, Some (dep_ty, param.fp_type.et_type)))
1113 @@ Typing_coercion.coerce_type_res
1115 Reason.URparam
1117 dep_ty
1118 param.fp_type
1119 Errors.unify_error
1121 let bad_call env p ty = Errors.bad_call p (Typing_print.error env ty)
1123 let rec make_a_local_of env e =
1124 match e with
1125 | (_, p, Class_get ((_, _, cname), CGstring (_, member_name), _)) ->
1126 let (env, local) = Env.FakeMembers.make_static env cname member_name p in
1127 (env, Some (p, local))
1128 | ( _,
1130 Obj_get
1131 ( (((_, _, This) | (_, _, Lvar _)) as obj),
1132 (_, _, Id (_, member_name)),
1134 _ ) ) ->
1135 let (env, local) = Env.FakeMembers.make env obj member_name p in
1136 (env, Some (p, local))
1137 | (_, _, Lvar x)
1138 | (_, _, Dollardollar x) ->
1139 (env, Some x)
1140 | (_, _, Hole (e, _, _, _)) -> make_a_local_of env e
1141 | _ -> (env, None)
1143 (* This function captures the common bits of logic behind refinement
1144 * of the type of a local variable or a class member variable as a
1145 * result of a dynamic check (e.g., nullity check, simple type check
1146 * using functions like is_int, is_string, is_array etc.). The
1147 * argument refine is a function that takes the type of the variable
1148 * and returns a refined type (making necessary changes to the
1149 * environment, which is threaded through).
1151 * All refinement functions return, in addition to the updated
1152 * environment, a (conservative) set of all the locals that got
1153 * refined. This set is used to construct AssertEnv statmements in
1154 * the typed AST.
1156 let refine_lvalue_type env ((ty, _, _) as te) ~refine =
1157 let (env, ty) = refine env ty in
1158 let e = Tast.to_nast_expr te in
1159 let (env, localopt) = make_a_local_of env e in
1160 (* TODO TAST: generate an assignment to the fake local in the TAST *)
1161 match localopt with
1162 | Some lid -> (set_local env lid ty, Local_id.Set.singleton (snd lid))
1163 | None -> (env, Local_id.Set.empty)
1165 let rec condition_nullity ~nonnull (env : env) te =
1166 match te with
1167 (* assignment: both the rhs and lhs of the '=' must be made null/non-null *)
1168 | (_, _, Aast.Binop (Ast_defs.Eq None, var, te)) ->
1169 let (env, lset1) = condition_nullity ~nonnull env te in
1170 let (env, lset2) = condition_nullity ~nonnull env var in
1171 (env, Local_id.Set.union lset1 lset2)
1172 (* case where `Shapes::idx(...)` must be made null/non-null *)
1173 | ( _,
1175 Aast.Call
1176 ( (_, _, Aast.Class_const ((_, _, Aast.CI (_, shapes)), (_, idx))),
1178 [shape; field],
1179 _ ) )
1180 when String.equal shapes SN.Shapes.cShapes && String.equal idx SN.Shapes.idx
1182 let field = Tast.to_nast_expr field in
1183 let refine env shape_ty =
1184 if nonnull then
1185 Typing_shapes.shapes_idx_not_null env shape_ty field
1186 else
1187 (env, shape_ty)
1189 refine_lvalue_type env shape ~refine
1190 | (_, _, Hole (te, _, _, _)) -> condition_nullity ~nonnull env te
1191 | (_, p, _) ->
1192 let refine env ty =
1193 if nonnull then
1194 Typing_solver.non_null env (Pos_or_decl.of_raw_pos p) ty
1195 else
1196 let r = Reason.Rwitness_from_decl (get_pos ty) in
1197 Inter.intersect env ~r ty (MakeType.null r)
1199 refine_lvalue_type env te ~refine
1201 let rec condition_isset env = function
1202 | (_, _, Aast.Array_get (x, _)) -> condition_isset env x
1203 | (_, _, Aast.Hole (x, _, _, _)) -> condition_isset env x
1204 | v -> condition_nullity ~nonnull:true env v
1206 (** If we are dealing with a refinement like
1207 $x is MyClass<A, B>
1208 then class_info is the class info of MyClass and hint_tyl corresponds
1209 to A, B. *)
1210 let generate_fresh_tparams env class_info p reason hint_tyl =
1211 let tparams_len = List.length (Cls.tparams class_info) in
1212 let hint_tyl = List.take hint_tyl tparams_len in
1213 let pad_len = tparams_len - List.length hint_tyl in
1214 let hint_tyl =
1215 List.map hint_tyl ~f:(fun x -> Some x)
1216 @ List.init pad_len ~f:(fun _ -> None)
1218 let replace_wildcard env hint_ty tp =
1219 let {
1220 tp_name = (_, tparam_name);
1221 tp_reified = reified;
1222 tp_user_attributes;
1227 let enforceable =
1228 Attributes.mem SN.UserAttributes.uaEnforceable tp_user_attributes
1230 let newable =
1231 Attributes.mem SN.UserAttributes.uaNewable tp_user_attributes
1233 match hint_ty with
1234 | Some ty ->
1235 begin
1236 match get_node ty with
1237 | Tgeneric (name, _targs) when Env.is_fresh_generic_parameter name ->
1238 (* TODO(T69551141) handle type arguments above and below *)
1239 (env, (Some (tp, name), MakeType.generic reason name))
1240 | _ -> (env, (None, ty))
1242 | None ->
1243 let (env, new_name) =
1244 Env.add_fresh_generic_parameter
1246 (Pos_or_decl.of_raw_pos p)
1247 tparam_name
1248 ~reified
1249 ~enforceable
1250 ~newable
1252 (* TODO(T69551141) handle type arguments for Tgeneric *)
1253 (env, (Some (tp, new_name), MakeType.generic reason new_name))
1255 let (env, tparams_and_tyl) =
1256 List.map2_env env hint_tyl (Cls.tparams class_info) ~f:replace_wildcard
1258 let (tparams_with_new_names, tyl_fresh) = List.unzip tparams_and_tyl in
1259 (env, tparams_with_new_names, tyl_fresh)
1261 let safely_refine_class_type
1264 class_name
1265 class_info
1266 ivar_ty
1267 obj_ty
1268 reason
1269 (tparams_with_new_names : (decl_tparam * string) option list)
1270 tyl_fresh =
1271 (* Type of variable in block will be class name
1272 * with fresh type parameters *)
1273 let obj_ty =
1274 mk (get_reason obj_ty, Tclass (class_name, Nonexact, tyl_fresh))
1276 let tparams = Cls.tparams class_info in
1277 (* Add in constraints as assumptions on those type parameters *)
1278 let ety_env =
1280 empty_expand_env with
1281 substs = Subst.make_locl tparams tyl_fresh;
1282 this_ty = obj_ty;
1285 let add_bounds env (t, ty_fresh) =
1286 List.fold_left t.tp_constraints ~init:env ~f:(fun env (ck, ty) ->
1287 (* Substitute fresh type parameters for
1288 * original formals in constraint *)
1289 let (env, ty) = Phase.localize ~ety_env env ty in
1290 SubType.add_constraint env ck ty_fresh ty (Errors.unify_error_at p))
1292 let env =
1293 List.fold_left (List.zip_exn tparams tyl_fresh) ~f:add_bounds ~init:env
1295 (* Finally, if we have a class-test on something with static classish type,
1296 * then we can chase the hierarchy and decompose the types to deduce
1297 * further assumptions on type parameters. For example, we might have
1298 * class B<Tb> { ... }
1299 * class C extends B<int>
1300 * and have obj_ty = C and x_ty = B<T> for a generic parameter Aast.
1301 * Then SubType.add_constraint will deduce that T=int and add int as
1302 * both lower and upper bound on T in env.lenv.tpenv
1304 * We only wish to do this if the types are in a possible subtype relationship.
1306 let (env, supertypes) =
1307 TUtils.get_concrete_supertypes ~abstract_enum:true env ivar_ty
1309 let rec might_be_supertype ty =
1310 let (_env, ty) = Env.expand_type env ty in
1311 match get_node ty with
1312 | Tclass ((_, name), _, _)
1313 when String.equal name (Cls.name class_info)
1314 || Cls.has_ancestor class_info name ->
1315 true
1316 | Tdynamic -> true
1317 | Toption ty -> might_be_supertype ty
1318 | Tunion tyl -> List.for_all tyl ~f:might_be_supertype
1319 | _ -> false
1321 let env =
1322 List.fold_left supertypes ~init:env ~f:(fun env ty ->
1323 if might_be_supertype ty then
1324 SubType.add_constraint
1326 Ast_defs.Constraint_as
1327 obj_ty
1329 (Errors.unify_error_at p)
1330 else
1331 env)
1333 (* It's often the case that the fresh name isn't necessary. For
1334 * example, if C<T> extends B<T>, and we have $x:B<t> for some type t
1335 * then $x is C should refine to $x:C<t>.
1336 * We take a simple approach:
1337 * For a fresh type parameter T#1, if
1338 * - There is an eqality constraint T#1 = t,
1339 * - T#1 is covariant, and T#1 has upper bound t (or mixed if absent)
1340 * - T#1 is contravariant, and T#1 has lower bound t (or nothing if absent)
1341 * then replace T#1 with t.
1342 * This is done in Type_parameter_env_ops.simplify_tpenv
1344 let (env, tparam_substs) =
1345 Type_parameter_env_ops.simplify_tpenv
1347 (List.zip_exn tparams_with_new_names tyl_fresh)
1348 reason
1350 let tyl_fresh =
1351 List.map2_exn tyl_fresh tparams_with_new_names ~f:(fun orig_ty tparam_opt ->
1352 match tparam_opt with
1353 | None -> orig_ty
1354 | Some (_tp, name) -> SMap.find name tparam_substs)
1356 let obj_ty_simplified =
1357 mk (get_reason obj_ty, Tclass (class_name, Nonexact, tyl_fresh))
1359 (env, obj_ty_simplified)
1361 let rec is_instance_var = function
1362 | (_, _, Hole (e, _, _, _)) -> is_instance_var e
1363 | (_, _, (Lvar _ | This | Dollardollar _)) -> true
1364 | (_, _, Obj_get ((_, _, This), (_, _, Id _), _, _)) -> true
1365 | (_, _, Obj_get ((_, _, Lvar _), (_, _, Id _), _, _)) -> true
1366 | (_, _, Class_get (_, _, _)) -> true
1367 | _ -> false
1369 let rec get_instance_var env = function
1370 | (_, p, Class_get ((_, _, cname), CGstring (_, member_name), _)) ->
1371 let (env, local) = Env.FakeMembers.make_static env cname member_name p in
1372 (env, (p, local))
1373 | ( _,
1375 Obj_get
1376 ( (((_, _, This) | (_, _, Lvar _)) as obj),
1377 (_, _, Id (_, member_name)),
1379 _ ) ) ->
1380 let (env, local) = Env.FakeMembers.make env obj member_name p in
1381 (env, (p, local))
1382 | (_, _, Dollardollar (p, x))
1383 | (_, _, Lvar (p, x)) ->
1384 (env, (p, x))
1385 | (_, p, This) -> (env, (p, this))
1386 | (_, _, Hole (e, _, _, _)) -> get_instance_var env e
1387 | _ -> failwith "Should only be called when is_instance_var is true"
1389 (** Transform a hint like `A<_>` to a localized type like `A<T#1>` for refinement of
1390 an instance variable. ivar_ty is the previous type of that instance variable. *)
1391 let rec class_for_refinement env p reason ivar_pos ivar_ty hint_ty =
1392 let (env, hint_ty) = Env.expand_type env hint_ty in
1393 match (get_node ivar_ty, get_node hint_ty) with
1394 | (_, Tclass (((_, cid) as _c), _, tyl)) ->
1395 begin
1396 match Env.get_class env cid with
1397 | Some class_info ->
1398 let (env, tparams_with_new_names, tyl_fresh) =
1399 generate_fresh_tparams env class_info p reason tyl
1401 safely_refine_class_type
1405 class_info
1406 ivar_ty
1407 hint_ty
1408 reason
1409 tparams_with_new_names
1410 tyl_fresh
1411 | None -> (env, mk (Reason.Rwitness ivar_pos, Tobject))
1413 | (Ttuple ivar_tyl, Ttuple hint_tyl)
1414 when Int.equal (List.length ivar_tyl) (List.length hint_tyl) ->
1415 let (env, tyl) =
1416 List.map2_env env ivar_tyl hint_tyl ~f:(fun env ivar_ty hint_ty ->
1417 class_for_refinement env p reason ivar_pos ivar_ty hint_ty)
1419 (env, MakeType.tuple reason tyl)
1420 | _ -> (env, hint_ty)
1422 (* Refine type for is_array, is_vec, is_keyset and is_dict tests
1423 * `pred_name` is the function name itself (e.g. 'is_vec')
1424 * `p` is position of the function name in the source
1425 * `arg_expr` is the argument to the function
1427 and safely_refine_is_array env ty p pred_name arg_expr =
1428 refine_lvalue_type env arg_expr ~refine:(fun env arg_ty ->
1429 let r = Reason.Rpredicated (p, pred_name) in
1430 let (env, tarrkey_name) =
1431 Env.add_fresh_generic_parameter
1433 (Pos_or_decl.of_raw_pos p)
1434 "Tk"
1435 ~reified:Erased
1436 ~enforceable:false
1437 ~newable:false
1439 (* TODO(T69551141) handle type arguments for Tgeneric *)
1440 let tarrkey = MakeType.generic r tarrkey_name in
1441 let env =
1442 SubType.add_constraint
1444 Ast_defs.Constraint_as
1445 tarrkey
1446 (MakeType.arraykey r)
1447 (Errors.unify_error_at p)
1449 let (env, tfresh_name) =
1450 Env.add_fresh_generic_parameter
1452 (Pos_or_decl.of_raw_pos p)
1454 ~reified:Erased
1455 ~enforceable:false
1456 ~newable:false
1458 (* TODO(T69551141) handle type arguments for Tgeneric *)
1459 let tfresh = MakeType.generic r tfresh_name in
1460 (* If we're refining the type for `is_array` we have a slightly more
1461 * involved process. Let's separate out that logic so we can re-use it.
1463 let array_ty =
1464 let tk = MakeType.arraykey Reason.(Rvarray_or_darray_key (to_pos r)) in
1465 let tv = tfresh in
1466 MakeType.varray_or_darray r tk tv
1468 (* This is the refined type of e inside the branch *)
1469 let hint_ty =
1470 match ty with
1471 | `HackDict -> MakeType.dict r tarrkey tfresh
1472 | `HackVec -> MakeType.vec r tfresh
1473 | `HackKeyset -> MakeType.keyset r tarrkey
1474 | `PHPArray -> array_ty
1475 | `AnyArray -> MakeType.any_array r tarrkey tfresh
1476 | `HackDictOrDArray ->
1477 MakeType.union
1479 [MakeType.dict r tarrkey tfresh; MakeType.darray r tarrkey tfresh]
1480 | `HackVecOrVArray ->
1481 MakeType.union r [MakeType.vec r tfresh; MakeType.varray r tfresh]
1483 let (_, arg_pos, _) = arg_expr in
1484 let (env, hint_ty) =
1485 class_for_refinement env p r arg_pos arg_ty hint_ty
1487 (* Add constraints on generic parameters that must
1488 * hold for refined_ty <:arg_ty. For example, if arg_ty is Traversable<T>
1489 * and refined_ty is keyset<T#1> then we know T#1 <: T.
1490 * See analogous code in safely_refine_class_type.
1492 let (env, supertypes) =
1493 TUtils.get_concrete_supertypes ~abstract_enum:true env arg_ty
1495 let env =
1496 List.fold_left supertypes ~init:env ~f:(fun env ty ->
1497 SubType.add_constraint
1499 Ast_defs.Constraint_as
1500 hint_ty
1502 (Errors.unify_error_at p))
1504 Inter.intersect ~r env hint_ty arg_ty)
1506 let key_exists env pos shape field =
1507 let field = Tast.to_nast_expr field in
1508 refine_lvalue_type env shape ~refine:(fun env shape_ty ->
1509 match TUtils.shape_field_name env field with
1510 | None -> (env, shape_ty)
1511 | Some field_name ->
1512 let field_name = TShapeField.of_ast Pos_or_decl.of_raw_pos field_name in
1513 Typing_shapes.refine_shape field_name pos env shape_ty)
1515 (** Add a fresh type parameter to [env] with a name starting [prefix]
1516 and a subtype constraint on [ty]. *)
1517 let synthesize_type_param env p prefix ty =
1518 let (env, name) = Env.fresh_param_name env prefix in
1519 let env = Env.add_upper_bound_global env name ty in
1521 let hint = (p, Aast.Habstr (name, [])) in
1522 (hint, env)
1524 (** Transform calls to MyVisitor::makeTree with [f]. *)
1525 let rec rewrite_expr_tree_maketree env expr f =
1526 let (pos, p, expr_) = expr in
1527 let (env, expr_) =
1528 match expr_ with
1529 | Call
1530 ( (fun_pos, p, (Lfun (fun_, idl) | Efun (fun_, idl))),
1531 targs,
1532 args,
1533 variadic ) ->
1534 (* Express tree literals containing splices use an anonymous
1535 function that returns the makeTree call.
1537 (function() {
1538 $0splice1 = "whatever";
1539 return MyVisitor::makeTree(...);
1540 })()
1542 let map_stmt env s =
1543 match s with
1544 | (pos, Return (Some expr)) ->
1545 let (env, expr) = rewrite_expr_tree_maketree env expr f in
1546 (env, (pos, Return (Some expr)))
1547 | _ -> (env, s)
1550 let (env, body_ast) = List.map_env env fun_.f_body.fb_ast ~f:map_stmt in
1551 let fun_ =
1552 { fun_ with f_body = { fun_.f_body with fb_ast = body_ast } }
1555 (env, Call ((fun_pos, p, Lfun (fun_, idl)), targs, args, variadic))
1556 | Call _ ->
1557 (* The desugarer might give us a simple call to makeTree, so we
1558 can process it immediately. *)
1559 f env expr_
1560 | _ -> (env, expr_)
1562 (env, (pos, p, expr_))
1564 (** Given [expr], a runtime expression for an expression tree, add a
1565 type parameter to the makeTree call.
1567 This enables expression tree visitors to use phantom type
1568 parameters. The visitor can be defined with __Explicit.
1570 public static function makeTree<<<__Explicit>> TInfer>(...) { ... }
1572 Userland calls to this method must provide an explicit type.
1574 MyVisitor::makeTree<MyVisitorInt>(...);
1576 For expression tree literals, we run type inference and provide a
1577 synthesized type parameter to the desugared runtime expression.
1579 MyVisitor`1`; // we infer MyVisitorInt
1580 MyVisitor::makeTree<_>(...) where _ as MyVisitorInt // we add this constrained type parameter
1583 let maketree_with_type_param env p expr expected_ty =
1584 let (hint_virtual, env) = synthesize_type_param env p "TInfer" expected_ty in
1585 let rewrite_expr env expr =
1586 match expr with
1587 | Call (e, _, el, unpacked_element) ->
1588 (env, Call (e, [((), hint_virtual)], el, unpacked_element))
1589 | e -> (env, e)
1592 rewrite_expr_tree_maketree env expr rewrite_expr
1594 module EnumClassLabelOps = struct
1595 type result =
1596 | Success of Tast.expr * locl_ty
1597 | ClassNotFound
1598 | LabelNotFound of Tast.expr * locl_ty
1599 | Invalid
1600 | Skip
1602 (** Given an [enum_name] and an [label], tries to see if
1603 [enum_name] has a constant named [label].
1604 In such case, creates the expected typed expression.
1606 If [label] is not there, it will register and error.
1608 [ctor] is either `MemberOf` or `Label`
1609 [full] describe if the original expression was a full
1610 label, as in E#A, or a short version, as in #A
1612 let expand pos env ~full ~ctor enum_name label_name =
1613 let cls = Env.get_class env enum_name in
1614 match cls with
1615 | Some cls ->
1616 (match Env.get_const env cls label_name with
1617 | Some const_def ->
1618 let dty = const_def.cc_type in
1619 (* the enum constant has type MemberOf<X, Y>. If we are
1620 * processing a Label argument, we just switch MemberOf for
1621 * Label.
1623 let dty =
1624 match deref dty with
1625 | (r, Tapply ((p, _), args)) -> mk (r, Tapply ((p, ctor), args))
1626 | _ -> dty
1628 let (env, lty) = Phase.localize_no_subst env ~ignore_errors:true dty in
1629 let hi = lty in
1630 let qualifier =
1631 if full then
1632 Some (pos, enum_name)
1633 else
1634 None
1636 let te = (hi, pos, EnumClassLabel (qualifier, label_name)) in
1637 (env, Success (te, lty))
1638 | None ->
1639 Errors.enum_class_label_unknown pos label_name enum_name;
1640 let r = Reason.Rwitness pos in
1641 let ty = Typing_utils.terr env r in
1642 let te = (ty, pos, EnumClassLabel (None, label_name)) in
1643 (env, LabelNotFound (te, ty)))
1644 | None -> (env, ClassNotFound)
1647 (* Given a localized parameter type and parameter information, infer
1648 * a type for the parameter default expression (if present) and check that
1649 * it is a subtype of the parameter type (if present). If no parameter type
1650 * is specified, then union with Tany. (So it's as though we did a conditional
1651 * assignment of the default expression to the parameter).
1652 * Set the type of the parameter in the locals environment *)
1653 let rec bind_param env ?(immutable = false) (ty1, param) =
1654 let (env, param_te, ty1) =
1655 match param.param_expr with
1656 | None -> (env, None, ty1)
1657 | Some e ->
1658 let decl_hint =
1659 Option.map
1660 ~f:(Decl_hint.hint env.decl_env)
1661 (hint_of_type_hint param.param_type_hint)
1663 let enforced =
1664 match decl_hint with
1665 | None -> Unenforced
1666 | Some ty -> Typing_enforceability.get_enforcement env ty
1668 let ty1_enforced = { et_type = ty1; et_enforced = enforced } in
1669 let expected =
1670 ExpectedTy.make_and_allow_coercion_opt
1672 param.param_pos
1673 Reason.URparam
1674 ty1_enforced
1676 let (env, (te, ty2)) =
1677 let pure = MakeType.mixed (Reason.Rwitness param.param_pos) in
1678 let (env, cap) =
1679 MakeType.apply
1680 (Reason.Rwitness_from_decl (Pos_or_decl.of_raw_pos param.param_pos))
1681 (* Accessing statics for default arguments is allowed *)
1682 ( Pos_or_decl.of_raw_pos param.param_pos,
1683 SN.Capabilities.accessGlobals )
1685 |> Phase.localize_no_subst env ~ignore_errors:false
1687 with_special_coeffects env cap pure @@ fun env ->
1688 expr ?expected env e ~allow_awaitable:(*?*) false |> triple_to_pair
1690 Typing_sequencing.sequence_check_expr e;
1691 let (env, ty1) =
1693 Option.is_none (hint_of_type_hint param.param_type_hint)
1694 && (not @@ TCO.global_inference (Env.get_tcopt env))
1695 (* ty1 will be Tany iff we have no type hint and we are not in
1696 * 'infer missing mode'. When it ty1 is Tany we just union it with
1697 * the type of the default expression *)
1698 then
1699 Union.union env ty1 ty2
1700 (* Otherwise we have an explicit type, and the default expression type
1701 * must be a subtype *)
1702 else
1703 let env =
1704 Typing_coercion.coerce_type
1705 param.param_pos
1706 Reason.URhint
1709 ty1_enforced
1710 Errors.parameter_default_value_wrong_type
1712 (env, ty1)
1714 (env, Some te, ty1)
1716 let (env, user_attributes) =
1717 List.map_env env param.param_user_attributes ~f:user_attribute
1719 let tparam =
1721 Aast.param_annotation = Tast.make_expr_annotation param.param_pos ty1;
1722 Aast.param_type_hint = (ty1, hint_of_type_hint param.param_type_hint);
1723 Aast.param_is_variadic = param.param_is_variadic;
1724 Aast.param_pos = param.param_pos;
1725 Aast.param_name = param.param_name;
1726 Aast.param_expr = param_te;
1727 Aast.param_callconv = param.param_callconv;
1728 Aast.param_readonly = param.param_readonly;
1729 Aast.param_user_attributes = user_attributes;
1730 Aast.param_visibility = param.param_visibility;
1733 let mode = get_param_mode param.param_callconv in
1734 let id = Local_id.make_unscoped param.param_name in
1735 let env = Env.set_local ~immutable env id ty1 param.param_pos in
1736 let env = Env.set_param env id (ty1, param.param_pos, mode) in
1737 let env =
1738 if has_accept_disposable_attribute param then
1739 Env.set_using_var env id
1740 else
1743 (env, tparam)
1745 (*****************************************************************************)
1746 (* function used to type closures, functions and methods *)
1747 (*****************************************************************************)
1748 and fun_ ?(abstract = false) ?(disable = false) env return pos named_body f_kind
1750 Env.with_env env (fun env ->
1751 debug_last_pos := pos;
1752 let env = Env.set_return env return in
1753 let (env, tb) =
1754 if disable then
1755 let () =
1756 Errors.internal_error
1758 ("Type inference for this function has been disabled by the "
1759 ^ SN.UserAttributes.uaDisableTypecheckerInternal
1760 ^ " attribute")
1762 block env []
1763 else
1764 block env named_body.fb_ast
1766 Typing_sequencing.sequence_check_block named_body.fb_ast;
1767 let { Typing_env_return_info.return_type = ret; _ } =
1768 Env.get_return env
1770 let has_implicit_return = LEnv.has_next env in
1771 let named_body_is_unsafe = Nast.named_body_is_unsafe named_body in
1772 let env =
1773 if (not has_implicit_return) || abstract || named_body_is_unsafe then
1775 else
1776 fun_implicit_return env pos ret.et_type f_kind
1778 let env =
1779 Typing_env.set_fun_tast_info
1781 { Tast.has_implicit_return; Tast.named_body_is_unsafe }
1783 debug_last_pos := Pos.none;
1784 (env, tb))
1786 and block env stl =
1787 Typing_env.with_origin env Decl_counters.Body @@ fun env ->
1788 (* To insert an `AssertEnv`, `stmt` might return a `Block`. We eliminate it here
1789 to keep ASTs `Block`-free. *)
1790 let (env, stl) =
1791 List.fold ~init:(env, []) stl ~f:(fun (env, stl) st ->
1792 let (env, st) = stmt env st in
1793 (* Accumulate statements in reverse order *)
1794 let stl =
1795 match st with
1796 | (_, Aast.Block stl') -> List.rev stl' @ stl
1797 | _ -> st :: stl
1799 (env, stl))
1801 (env, List.rev stl)
1803 (* Ensure that `ty` is a subtype of IDisposable (for `using`) or
1804 * IAsyncDisposable (for `await using`)
1806 and has_dispose_method env has_await p e ty =
1807 let meth =
1808 if has_await then
1809 SN.Members.__disposeAsync
1810 else
1811 SN.Members.__dispose
1813 let (_, obj_pos, _) = e in
1814 let (env, (tfty, _tal)) =
1815 TOG.obj_get
1816 ~obj_pos
1817 ~is_method:true
1818 ~inst_meth:false
1819 ~meth_caller:false
1820 ~nullsafe:None
1821 ~coerce_from_ty:None
1822 ~explicit_targs:[]
1823 ~class_id:(CIexpr e)
1824 ~member_id:(p, meth)
1825 ~on_error:(Errors.using_error p has_await)
1829 let (env, (_tel, _typed_unpack_element, _ty, _should_forget_fakes)) =
1830 call ~expected:None p env tfty [] None
1834 (* Check an individual component in the expression `e` in the
1835 * `using (e) { ... }` statement.
1836 * This consists of either
1837 * a simple assignment `$x = e`, in which `$x` is the using variable, or
1838 * an arbitrary expression `e`, in which case a temporary is the using
1839 * variable, inaccessible in the source.
1840 * Return the typed expression and its type, and any variables that must
1841 * be designated as "using variables" for avoiding escapes.
1843 and check_using_expr has_await env ((_, pos, content) as using_clause) =
1844 match content with
1845 (* Simple assignment to local of form `$lvar = e` *)
1846 | Binop (Ast_defs.Eq None, (_, lvar_pos, Lvar lvar), e) ->
1847 let (env, te, ty) =
1848 expr ~is_using_clause:true env e ~allow_awaitable:(*?*) false
1850 let env = has_dispose_method env has_await pos e ty in
1851 let env = set_local ~is_using_clause:true env lvar ty in
1852 (* We are assigning a new value to the local variable, so we need to
1853 * generate a new expression id
1855 let env = Env.set_local_expr_id env (snd lvar) (Ident.tmp ()) in
1856 ( env,
1857 ( Tast.make_typed_expr
1860 (Aast.Binop
1861 ( Ast_defs.Eq None,
1862 Tast.make_typed_expr lvar_pos ty (Aast.Lvar lvar),
1863 te )),
1864 [snd lvar] ) )
1865 (* Arbitrary expression. This will be assigned to a temporary *)
1866 | _ ->
1867 let (env, typed_using_clause, ty) =
1868 expr ~is_using_clause:true env using_clause ~allow_awaitable:(*?*) false
1870 let env = has_dispose_method env has_await pos using_clause ty in
1871 (env, (typed_using_clause, []))
1873 (* Check the using clause e in
1874 * `using (e) { ... }` statement (`has_await = false`) or
1875 * `await using (e) { ... }` statement (`has_await = true`).
1876 * `using_clauses` is a list of expressions.
1877 * Return the typed expression, and any variables that must
1878 * be designated as "using variables" for avoiding escapes.
1880 and check_using_clause env has_await using_clauses =
1881 let (env, pairs) =
1882 List.map_env env using_clauses ~f:(check_using_expr has_await)
1884 let (typed_using_clauses, vars) = List.unzip pairs in
1885 (env, typed_using_clauses, List.concat vars)
1887 and stmt env (pos, st) =
1888 let (env, st) = stmt_ env pos st in
1889 Typing_debug.log_env_if_too_big pos env;
1890 (env, (pos, st))
1892 and stmt_ env pos st =
1893 let expr ?(allow_awaitable = (*?*) false) = expr ~allow_awaitable in
1894 let exprs = exprs ~allow_awaitable:(*?*) false in
1895 (* Type check a loop. f env = (env, result) checks the body of the loop.
1896 * We iterate over the loop until the "next" continuation environment is
1897 * stable. alias_depth is supposed to be an upper bound on this; but in
1898 * certain cases this fails (e.g. a generic type grows unboundedly). TODO:
1899 * fix this.
1901 let infer_loop env f =
1902 let in_loop_outer = env.in_loop in
1903 let alias_depth =
1904 if in_loop_outer then
1906 else
1907 Typing_alias.get_depth (pos, st)
1909 let env = { env with in_loop = true } in
1910 let rec loop env n =
1911 (* Remember the old environment *)
1912 let old_next_entry = Env.next_cont_opt env in
1913 let (env, result) = f env in
1914 let new_next_entry = Env.next_cont_opt env in
1915 (* Finish if we reach the bound, or if the environments match *)
1917 Int.equal n alias_depth
1918 || Typing_per_cont_ops.is_sub_opt_entry
1919 Typing_subtype.is_sub_type
1921 new_next_entry
1922 old_next_entry
1923 then
1924 let env = { env with in_loop = in_loop_outer } in
1925 (env, result)
1926 else
1927 loop env (n + 1)
1929 loop env 1
1931 let env = Env.open_tyvars env pos in
1932 (fun (env, tb) -> (Typing_solver.close_tyvars_and_solve env, tb))
1934 match st with
1935 | Fallthrough ->
1936 let env =
1937 if env.in_case then
1938 LEnv.move_and_merge_next_in_cont env C.Fallthrough
1939 else
1942 (env, Aast.Fallthrough)
1943 | Noop -> (env, Aast.Noop)
1944 | AssertEnv _ -> (env, Aast.Noop)
1945 | Yield_break ->
1946 let env = LEnv.move_and_merge_next_in_cont env C.Exit in
1947 (env, Aast.Yield_break)
1948 | Expr e ->
1949 let (env, te, _) = expr env e in
1950 let env =
1951 if TFTerm.typed_expression_exits te then
1952 LEnv.move_and_merge_next_in_cont env C.Exit
1953 else
1956 (env, Aast.Expr te)
1957 | If (e, b1, b2) ->
1958 let assert_refinement_env =
1959 assert_env_blk ~pos ~at:`Start Aast.Refinement
1961 let (env, te, _) = expr env e in
1962 let (env, tb1, tb2) =
1963 branch
1965 (fun env ->
1966 let (env, lset) = condition env true te in
1967 let refinement_map = refinement_annot_map env lset in
1968 let (env, b1) = block env b1 in
1969 let b1 = assert_refinement_env refinement_map b1 in
1970 (env, b1))
1971 (fun env ->
1972 let (env, lset) = condition env false te in
1973 let refinement_map = refinement_annot_map env lset in
1974 let (env, b2) = block env b2 in
1975 let b2 = assert_refinement_env refinement_map b2 in
1976 (env, b2))
1978 (* TODO TAST: annotate with joined types *)
1979 (env, Aast.If (te, tb1, tb2))
1980 | Return None ->
1981 let env = check_inout_return pos env in
1982 let rty = MakeType.void (Reason.Rwitness pos) in
1983 let { Typing_env_return_info.return_type = expected_return; _ } =
1984 Env.get_return env
1986 let expected_return =
1987 Typing_return.strip_awaitable (Env.get_fn_kind env) env expected_return
1989 let env =
1990 match Env.get_fn_kind env with
1991 | Ast_defs.FGenerator
1992 | Ast_defs.FAsyncGenerator ->
1994 | _ ->
1995 Typing_return.implicit_return
1998 ~expected:expected_return.et_type
1999 ~actual:rty
2001 let env = LEnv.move_and_merge_next_in_cont env C.Exit in
2002 (env, Aast.Return None)
2003 | Return (Some e) ->
2004 let env = check_inout_return pos env in
2005 let (_, expr_pos, _) = e in
2006 let Typing_env_return_info.
2008 return_type;
2009 return_disposable;
2010 return_explicit;
2011 return_dynamically_callable = _;
2013 Env.get_return env
2015 let return_type =
2016 Typing_return.strip_awaitable (Env.get_fn_kind env) env return_type
2018 let expected =
2019 if return_explicit then
2020 Some
2021 (ExpectedTy.make_and_allow_coercion
2022 expr_pos
2023 Reason.URreturn
2024 return_type)
2025 else
2026 None
2028 if return_disposable then enforce_return_disposable env e;
2029 let (env, te, rty) =
2030 expr ~is_using_clause:return_disposable ?expected env e
2032 (* This is a unify_error rather than a return_type_mismatch because the return
2033 * statement is the problem, not the return type itself. *)
2034 let (env, err_opt) =
2035 Result.fold
2036 ~ok:(fun env -> (env, None))
2037 ~error:(fun env -> (env, Some (rty, return_type.et_type)))
2038 @@ Typing_coercion.coerce_type_res
2039 expr_pos
2040 Reason.URreturn
2043 return_type
2044 Errors.unify_error
2046 let env = LEnv.move_and_merge_next_in_cont env C.Exit in
2047 (env, Aast.Return (Some (hole_on_err ~err_opt te)))
2048 | Do (b, e) ->
2049 (* NOTE: leaks scope as currently implemented; this matches
2050 the behavior in naming (cf. `do_stmt` in naming/naming.ml).
2052 let (env, (tb, te)) =
2053 LEnv.stash_and_do env [C.Continue; C.Break; C.Do] (fun env ->
2054 let env = LEnv.save_and_merge_next_in_cont env C.Do in
2055 let (env, _) = block env b in
2056 (* saving the locals in continue here even if there is no continue
2057 * statement because they must be merged at the end of the loop, in
2058 * case there is no iteration *)
2059 let env = LEnv.save_and_merge_next_in_cont env C.Continue in
2060 let (env, tb) =
2061 infer_loop env (fun env ->
2062 let env =
2063 LEnv.update_next_from_conts env [C.Continue; C.Next]
2065 (* The following is necessary in case there is an assignment in the
2066 * expression *)
2067 let (env, te, _) = expr env e in
2068 let (env, _lset) = condition env true te in
2069 let env = LEnv.update_next_from_conts env [C.Do; C.Next] in
2070 let (env, tb) = block env b in
2071 (env, tb))
2073 let env = LEnv.update_next_from_conts env [C.Continue; C.Next] in
2074 let (env, te, _) = expr env e in
2075 let (env, _lset) = condition env false te in
2076 let env = LEnv.update_next_from_conts env [C.Break; C.Next] in
2077 (env, (tb, te)))
2079 (env, Aast.Do (tb, te))
2080 | While (e, b) ->
2081 let (env, (te, tb, refinement_map)) =
2082 LEnv.stash_and_do env [C.Continue; C.Break] (fun env ->
2083 let env = LEnv.save_and_merge_next_in_cont env C.Continue in
2084 let (env, tb) =
2085 infer_loop env (fun env ->
2086 let env =
2087 LEnv.update_next_from_conts env [C.Continue; C.Next]
2089 let join_map = annot_map env in
2090 (* The following is necessary in case there is an assignment in the
2091 * expression *)
2092 let (env, te, _) = expr env e in
2093 let (env, lset) = condition env true te in
2094 let refinement_map = refinement_annot_map env lset in
2095 (* TODO TAST: avoid repeated generation of block *)
2096 let (env, tb) = block env b in
2098 (* Annotate loop body with join and refined environments *)
2099 let assert_env_blk = assert_env_blk ~pos ~at:`Start in
2100 let tb = assert_env_blk Aast.Refinement refinement_map tb in
2101 let tb = assert_env_blk Aast.Join join_map tb in
2103 (env, tb))
2105 let env = LEnv.update_next_from_conts env [C.Continue; C.Next] in
2106 let (env, te, _) = expr env e in
2107 let (env, lset) = condition env false te in
2108 let refinement_map_at_exit = refinement_annot_map env lset in
2109 let env = LEnv.update_next_from_conts env [C.Break; C.Next] in
2110 (env, (te, tb, refinement_map_at_exit)))
2112 let while_st = Aast.While (te, tb) in
2113 (* Export the refined environment after the exit condition holds *)
2114 let while_st =
2115 assert_env_stmt ~pos ~at:`End Aast.Refinement refinement_map while_st
2117 (env, while_st)
2118 | Using
2120 us_has_await = has_await;
2121 us_exprs = (loc, using_clause);
2122 us_block = using_block;
2123 us_is_block_scoped;
2124 } ->
2125 let (env, typed_using_clause, using_vars) =
2126 check_using_clause env has_await using_clause
2128 let (env, typed_using_block) = block env using_block in
2129 (* Remove any using variables from the environment, as they should not
2130 * be in scope outside the block *)
2131 let env = List.fold_left using_vars ~init:env ~f:Env.unset_local in
2132 ( env,
2133 Aast.Using
2134 Aast.
2136 us_has_await = has_await;
2137 us_exprs = (loc, typed_using_clause);
2138 us_block = typed_using_block;
2139 us_is_block_scoped;
2141 | For (e1, e2, e3, b) ->
2142 let e2 =
2143 match e2 with
2144 | Some e2 -> e2
2145 | None -> ((), Pos.none, True)
2147 let (env, (te1, te2, te3, tb, refinement_map)) =
2148 LEnv.stash_and_do env [C.Continue; C.Break] (fun env ->
2149 (* For loops leak their initalizer, but nothing that's defined in the
2150 body
2152 let (env, te1, _) = exprs env e1 in
2153 (* initializer *)
2154 let env = LEnv.save_and_merge_next_in_cont env C.Continue in
2155 let (env, (tb, te3)) =
2156 infer_loop env (fun env ->
2157 (* The following is necessary in case there is an assignment in the
2158 * expression *)
2159 let (env, te2, _) = expr env e2 in
2160 let (env, lset) = condition env true te2 in
2161 let refinement_map = refinement_annot_map env lset in
2162 let (env, tb) = block env b in
2163 let env =
2164 LEnv.update_next_from_conts env [C.Continue; C.Next]
2166 let join_map = annot_map env in
2167 let (env, te3, _) = exprs env e3 in
2169 (* Export the join and refinement environments *)
2170 let assert_env_blk = assert_env_blk ~pos ~at:`Start in
2171 let tb = assert_env_blk Aast.Refinement refinement_map tb in
2172 let tb = assert_env_blk Aast.Join join_map tb in
2174 (env, (tb, te3)))
2176 let env = LEnv.update_next_from_conts env [C.Continue; C.Next] in
2177 let (env, te2, _) = expr env e2 in
2178 let (env, lset) = condition env false te2 in
2179 let refinement_map_at_exit = refinement_annot_map env lset in
2180 let env = LEnv.update_next_from_conts env [C.Break; C.Next] in
2181 (env, (te1, te2, te3, tb, refinement_map_at_exit)))
2183 let for_st = Aast.For (te1, Some te2, te3, tb) in
2184 let for_st =
2185 assert_env_stmt ~pos ~at:`End Aast.Refinement refinement_map for_st
2187 (env, for_st)
2188 | Switch (((_, pos, _) as e), cl) ->
2189 let (env, te, ty) = expr env e in
2190 (* NB: A 'continue' inside a 'switch' block is equivalent to a 'break'.
2191 * See the note in
2192 * http://php.net/manual/en/control-structures.continue.php *)
2193 let (env, (te, tcl)) =
2194 LEnv.stash_and_do env [C.Continue; C.Break] (fun env ->
2195 let parent_locals = LEnv.get_all_locals env in
2196 let case_list env = case_list parent_locals ty env pos cl in
2197 let (env, tcl) = Env.in_case env case_list in
2198 let env =
2199 LEnv.update_next_from_conts env [C.Continue; C.Break; C.Next]
2201 (env, (te, tcl)))
2203 (env, Aast.Switch (te, tcl))
2204 | Foreach (e1, e2, b) ->
2205 (* It's safe to do foreach over a disposable, as no leaking is possible *)
2206 let (env, te1, ty1) = expr ~accept_using_var:true env e1 in
2207 let (env, (te1, te2, tb)) =
2208 LEnv.stash_and_do env [C.Continue; C.Break] (fun env ->
2209 let env = LEnv.save_and_merge_next_in_cont env C.Continue in
2210 let (_, p1, _) = e1 in
2211 let (env, tk, tv, err_opt) = as_expr env ty1 p1 e2 in
2212 let (env, (te2, tb)) =
2213 infer_loop env (fun env ->
2214 let env =
2215 LEnv.update_next_from_conts env [C.Continue; C.Next]
2217 let join_map = annot_map env in
2218 let (env, te2) = bind_as_expr env p1 tk tv e2 in
2219 let (env, tb) = block env b in
2220 (* Export the join environment *)
2221 let tb = assert_env_blk ~pos ~at:`Start Aast.Join join_map tb in
2222 (env, (te2, tb)))
2224 let env =
2225 LEnv.update_next_from_conts env [C.Continue; C.Break; C.Next]
2227 (env, (hole_on_err ~err_opt te1, te2, tb)))
2229 (env, Aast.Foreach (te1, te2, tb))
2230 | Try (tb, cl, fb) ->
2231 let (env, ttb, tcl, tfb) = try_catch env tb cl fb in
2232 (env, Aast.Try (ttb, tcl, tfb))
2233 | Awaitall (el, b) ->
2234 let env = might_throw env in
2235 let (env, el) =
2236 List.fold_left el ~init:(env, []) ~f:(fun (env, tel) (e1, e2) ->
2237 let (env, te2, ty2) = expr env e2 ~allow_awaitable:true in
2238 let (_, pos2, _) = e2 in
2239 let (env, ty2) =
2240 Async.overload_extract_from_awaitable env ~p:pos2 ty2
2242 match e1 with
2243 | Some e1 ->
2244 let pos = fst e1 in
2245 let (env, _, _, err_opt) =
2246 assign pos env ((), pos, Lvar e1) pos2 ty2
2248 (env, (Some e1, hole_on_err ~err_opt te2) :: tel)
2249 | None -> (env, (None, te2) :: tel))
2251 let (env, b) = block env b in
2252 (env, Aast.Awaitall (el, b))
2253 | Throw e ->
2254 let (_, p, _) = e in
2255 let (env, te, ty) = expr env e in
2256 let env = coerce_to_throwable p env ty in
2257 let env = move_and_merge_next_in_catch env in
2258 (env, Aast.Throw te)
2259 | Continue ->
2260 let env = LEnv.move_and_merge_next_in_cont env C.Continue in
2261 (env, Aast.Continue)
2262 | Break ->
2263 let env = LEnv.move_and_merge_next_in_cont env C.Break in
2264 (env, Aast.Break)
2265 | Block _
2266 | Markup _ ->
2267 failwith
2268 "Unexpected nodes in AST. These nodes should have been removed in naming."
2270 and finally_cont fb env ctx =
2271 (* The only locals in scope are the ones from the current continuation *)
2272 let env = Env.env_with_locals env @@ CMap.singleton C.Next ctx in
2273 let (env, _tfb) = block env fb in
2274 (env, LEnv.get_all_locals env)
2276 and finally env fb =
2277 match fb with
2278 | [] ->
2279 let env = LEnv.update_next_from_conts env [C.Next; C.Finally] in
2280 (env, [])
2281 | _ ->
2282 let parent_locals = LEnv.get_all_locals env in
2283 (* First typecheck the finally block against all continuations merged
2284 * together.
2285 * During this phase, record errors found in the finally block, but discard
2286 * the resulting environment. *)
2287 let all_conts = Env.all_continuations env in
2288 let env = LEnv.update_next_from_conts env all_conts in
2289 let (env, tfb) = block env fb in
2290 let env = LEnv.restore_conts_from env parent_locals all_conts in
2291 (* Second, typecheck the finally block once against each continuation. This
2292 * helps be more clever about what each continuation will be after the
2293 * finally block.
2294 * We don't want to record errors during this phase, because certain types
2295 * of errors will fire wrongly. For example, if $x is nullable in some
2296 * continuations but not in others, then we must use `?->` on $x, but an
2297 * error will fire when typechecking the finally block againts continuations
2298 * where $x is non-null. *)
2299 let finally_cont env _key = finally_cont fb env in
2300 let (env, locals_map) =
2301 Errors.ignore_ (fun () -> CMap.map_env finally_cont env parent_locals)
2303 let union env _key = LEnv.union_contextopts env in
2304 let (env, locals) = Try.finally_merge union env locals_map all_conts in
2305 (Env.env_with_locals env locals, tfb)
2307 and try_catch env tb cl fb =
2308 let parent_locals = LEnv.get_all_locals env in
2309 let env =
2310 LEnv.drop_conts env [C.Break; C.Continue; C.Exit; C.Catch; C.Finally]
2312 let (env, (ttb, tcb)) =
2313 Env.in_try env (fun env ->
2314 let (env, ttb) = block env tb in
2315 let env = LEnv.move_and_merge_next_in_cont env C.Finally in
2316 let catchctx = LEnv.get_cont_option env C.Catch in
2317 let (env, lenvtcblist) = List.map_env env ~f:(catch catchctx) cl in
2318 let (lenvl, tcb) = List.unzip lenvtcblist in
2319 let env = LEnv.union_lenv_list env env.lenv lenvl in
2320 let env = LEnv.move_and_merge_next_in_cont env C.Finally in
2321 (env, (ttb, tcb)))
2323 let (env, tfb) = finally env fb in
2324 let env = LEnv.update_next_from_conts env [C.Finally] in
2325 let env = LEnv.drop_cont env C.Finally in
2326 let env =
2327 LEnv.restore_and_merge_conts_from
2329 parent_locals
2330 [C.Break; C.Continue; C.Exit; C.Catch; C.Finally]
2332 (env, ttb, tcb, tfb)
2334 and case_list parent_locals ty env switch_pos cl =
2335 let initialize_next_cont env =
2336 let env = LEnv.restore_conts_from env parent_locals [C.Next] in
2337 let env = LEnv.update_next_from_conts env [C.Next; C.Fallthrough] in
2338 LEnv.drop_cont env C.Fallthrough
2340 let check_fallthrough env switch_pos case_pos block rest_of_list ~is_default =
2341 if (not (List.is_empty block)) && not (List.is_empty rest_of_list) then
2342 match LEnv.get_cont_option env C.Next with
2343 | Some _ ->
2344 if is_default then
2345 Errors.default_fallthrough switch_pos
2346 else
2347 Errors.case_fallthrough switch_pos case_pos
2348 | None -> ()
2350 let env =
2351 (* below, we try to find out if the switch is exhaustive *)
2352 let has_default =
2353 List.exists cl ~f:(function
2354 | Default _ -> true
2355 | _ -> false)
2357 let (env, ty) =
2358 (* If it hasn't got a default clause then we need to solve type variables
2359 * in order to check for an enum *)
2360 if has_default then
2361 Env.expand_type env ty
2362 else
2363 Typing_solver.expand_type_and_solve
2365 ~description_of_expected:"a value"
2366 switch_pos
2369 (* leverage that enums are checked for exhaustivity *)
2370 let is_enum =
2371 let top_type =
2372 MakeType.class_type
2373 Reason.Rnone
2374 SN.Classes.cHH_BuiltinEnum
2375 [MakeType.mixed Reason.Rnone]
2377 Typing_subtype.is_sub_type_for_coercion env ty top_type
2379 (* register that the runtime may throw in case we cannot prove
2380 that the switch is exhaustive *)
2381 if has_default || is_enum then
2383 else
2384 might_throw env
2386 let rec case_list env = function
2387 | [] -> (env, [])
2388 | Default (pos, b) :: rl ->
2389 let env = initialize_next_cont env in
2390 let (env, tb) = block env b in
2391 check_fallthrough env switch_pos pos b rl ~is_default:true;
2392 let (env, tcl) = case_list env rl in
2393 (env, Aast.Default (pos, tb) :: tcl)
2394 | Case (((_, pos, _) as e), b) :: rl ->
2395 let env = initialize_next_cont env in
2396 let (env, te, _) = expr env e ~allow_awaitable:(*?*) false in
2397 let (env, tb) = block env b in
2398 check_fallthrough env switch_pos pos b rl ~is_default:false;
2399 let (env, tcl) = case_list env rl in
2400 (env, Aast.Case (te, tb) :: tcl)
2402 case_list env cl
2404 and catch catchctx env (sid, exn_lvar, b) =
2405 let env = LEnv.replace_cont env C.Next catchctx in
2406 let cid = CI sid in
2407 let ety_p = fst sid in
2408 let (env, _, _, _) = instantiable_cid ety_p env cid [] in
2409 let (env, _tal, _te, ety) = class_expr env [] ((), ety_p, cid) in
2410 let env = coerce_to_throwable ety_p env ety in
2411 let (p, x) = exn_lvar in
2412 let env = set_valid_rvalue p env x ety in
2413 let (env, tb) = block env b in
2414 (env, (env.lenv, (sid, exn_lvar, tb)))
2416 and bind_as_expr env p ty1 ty2 aexpr =
2417 match aexpr with
2418 | As_v ev ->
2419 let (env, te, _, _) = assign p env ev p ty2 in
2420 (env, Aast.As_v te)
2421 | Await_as_v (p, ev) ->
2422 let (env, te, _, _) = assign p env ev p ty2 in
2423 (env, Aast.Await_as_v (p, te))
2424 | As_kv ((_, p, Lvar ((_, k) as id)), ev) ->
2425 let env = set_valid_rvalue p env k ty1 in
2426 let (env, te, _, _) = assign p env ev p ty2 in
2427 let tk = Tast.make_typed_expr p ty1 (Aast.Lvar id) in
2428 (env, Aast.As_kv (tk, te))
2429 | Await_as_kv (p, (_, p1, Lvar ((_, k) as id)), ev) ->
2430 let env = set_valid_rvalue p env k ty1 in
2431 let (env, te, _, _) = assign p env ev p ty2 in
2432 let tk = Tast.make_typed_expr p1 ty1 (Aast.Lvar id) in
2433 (env, Aast.Await_as_kv (p, tk, te))
2434 | _ ->
2435 (* TODO Probably impossible, should check that *)
2436 assert false
2438 and expr
2439 ?(expected : ExpectedTy.t option)
2440 ?(accept_using_var = false)
2441 ?(is_using_clause = false)
2442 ?(in_readonly_expr = false)
2443 ?(valkind = `other)
2444 ?(check_defined = true)
2445 ?in_await
2446 ~allow_awaitable
2448 ((_, p, _) as e) =
2450 begin
2451 match expected with
2452 | None -> ()
2453 | Some ExpectedTy.{ reason = r; ty = { et_type = ty; _ }; _ } ->
2454 Typing_log.(
2455 log_with_level env "typing" ~level:1 (fun () ->
2456 log_types
2457 (Pos_or_decl.of_raw_pos p)
2460 Log_head
2461 ( "Typing.expr " ^ Typing_reason.string_of_ureason r,
2462 [Log_type ("expected_ty", ty)] );
2464 end;
2465 raw_expr
2466 ~accept_using_var
2467 ~is_using_clause
2468 ~in_readonly_expr
2469 ~valkind
2470 ~check_defined
2471 ?in_await
2472 ?expected
2473 ~allow_awaitable
2476 with
2477 | Inf.InconsistentTypeVarState _ as e ->
2478 (* we don't want to catch unwanted exceptions here, eg Timeouts *)
2479 let typechecking_is_deferring = Deferred_decl.is_deferring () in
2480 Errors.exception_occurred ~typechecking_is_deferring p (Exception.wrap e);
2481 make_result env p (invalid_expr_ env p) @@ err_witness env p
2483 (* Some (legacy) special functions are allowed in initializers,
2484 therefore treat them as pure and insert the matching capabilities. *)
2485 and expr_with_pure_coeffects
2486 ?(expected : ExpectedTy.t option) ~allow_awaitable env e =
2487 let (_, p, _) = e in
2488 let pure = MakeType.mixed (Reason.Rwitness p) in
2489 let (env, (te, ty)) =
2490 with_special_coeffects env pure pure @@ fun env ->
2491 expr env e ?expected ~allow_awaitable |> triple_to_pair
2493 (env, te, ty)
2495 and raw_expr
2496 ?(accept_using_var = false)
2497 ?(is_using_clause = false)
2498 ?(in_readonly_expr = false)
2499 ?(expected : ExpectedTy.t option)
2500 ?lhs_of_null_coalesce
2501 ?(valkind = `other)
2502 ?(check_defined = true)
2503 ?in_await
2504 ~allow_awaitable
2507 let (_, p, _) = e in
2508 debug_last_pos := p;
2509 expr_
2510 ~accept_using_var
2511 ~is_using_clause
2512 ~in_readonly_expr
2513 ?expected
2514 ?lhs_of_null_coalesce
2515 ?in_await
2516 ~allow_awaitable
2517 ~valkind
2518 ~check_defined
2522 and lvalue env e =
2523 let valkind = `lvalue in
2524 expr_ ~valkind ~check_defined:false env e ~allow_awaitable:(*?*) false
2526 and lvalues env el =
2527 match el with
2528 | [] -> (env, [], [])
2529 | e :: el ->
2530 let (env, te, ty) = lvalue env e in
2531 let (env, tel, tyl) = lvalues env el in
2532 (env, te :: tel, ty :: tyl)
2534 (* $x ?? 0 is handled similarly to $x ?: 0, except that the latter will also
2535 * look for sketchy null checks in the condition. *)
2536 (* TODO TAST: type refinement should be made explicit in the typed AST *)
2537 and eif env ~(expected : ExpectedTy.t option) ?in_await p c e1 e2 =
2538 let condition = condition ~lhs_of_null_coalesce:false in
2539 let (env, tc, tyc) =
2540 raw_expr ~lhs_of_null_coalesce:false env c ~allow_awaitable:false
2542 let parent_lenv = env.lenv in
2543 let (env, _lset) = condition env true tc in
2544 let (env, te1, ty1) =
2545 match e1 with
2546 | None ->
2547 let (env, ty) =
2548 Typing_solver.non_null env (Pos_or_decl.of_raw_pos p) tyc
2550 (env, None, ty)
2551 | Some e1 ->
2552 let (env, te1, ty1) =
2553 expr ?expected ?in_await env e1 ~allow_awaitable:true
2555 (env, Some te1, ty1)
2557 let lenv1 = env.lenv in
2558 let env = { env with lenv = parent_lenv } in
2559 let (env, _lset) = condition env false tc in
2560 let (env, te2, ty2) = expr ?expected ?in_await env e2 ~allow_awaitable:true in
2561 let lenv2 = env.lenv in
2562 let env = LEnv.union_lenvs env parent_lenv lenv1 lenv2 in
2563 let (env, ty) = Union.union ~approx_cancel_neg:true env ty1 ty2 in
2564 make_result env p (Aast.Eif (tc, te1, te2)) ty
2566 and exprs
2567 ?(accept_using_var = false)
2568 ?(expected : ExpectedTy.t option)
2569 ?(valkind = `other)
2570 ?(check_defined = true)
2571 ~allow_awaitable
2573 el =
2574 match el with
2575 | [] -> (env, [], [])
2576 | e :: el ->
2577 let (env, te, ty) =
2578 expr
2579 ~accept_using_var
2580 ?expected
2581 ~valkind
2582 ~check_defined
2585 ~allow_awaitable
2587 let (env, tel, tyl) =
2588 exprs
2589 ~accept_using_var
2590 ?expected
2591 ~valkind
2592 ~check_defined
2595 ~allow_awaitable
2597 (env, te :: tel, ty :: tyl)
2599 and exprs_expected (pos, ur, expected_tyl) env el =
2600 match (el, expected_tyl) with
2601 | ([], _) -> (env, [], [])
2602 | (e :: el, expected_ty :: expected_tyl) ->
2603 let expected = ExpectedTy.make pos ur expected_ty in
2604 let (env, te, ty) = expr ~expected env e ~allow_awaitable:(*?*) false in
2605 let (env, tel, tyl) = exprs_expected (pos, ur, expected_tyl) env el in
2606 (env, te :: tel, ty :: tyl)
2607 | (el, []) -> exprs env el ~allow_awaitable:(*?*) false
2609 and expr_
2610 ?(expected : ExpectedTy.t option)
2611 ?(accept_using_var = false)
2612 ?(is_using_clause = false)
2613 ?(in_readonly_expr = false)
2614 ?lhs_of_null_coalesce
2615 ?in_await
2616 ~allow_awaitable
2617 ~(valkind : [> `lvalue | `lvalue_subexpr | `other ])
2618 ~check_defined
2620 ((_, p, e) as outer) =
2621 let env = Env.open_tyvars env p in
2622 (fun (env, te, ty) ->
2623 let env = Typing_solver.close_tyvars_and_solve env in
2624 (env, te, ty))
2626 let expr ?(allow_awaitable = allow_awaitable) =
2627 expr ~check_defined ~allow_awaitable
2629 let exprs = exprs ~check_defined ~allow_awaitable in
2630 let raw_expr ?(allow_awaitable = allow_awaitable) =
2631 raw_expr ~check_defined ~allow_awaitable
2634 * Given a list of types, computes their supertype. If any of the types are
2635 * unknown (e.g., comes from PHP), the supertype will be Typing_utils.tany env.
2637 let compute_supertype
2638 ~(expected : ExpectedTy.t option) ~reason ~use_pos ?bound r env tys =
2639 let (env, supertype) =
2640 match expected with
2641 | None ->
2642 let (env, supertype) = Env.fresh_type_reason env use_pos r in
2643 let env =
2644 match bound with
2645 | None -> env
2646 | Some ty ->
2647 SubType.sub_type env supertype ty (fun ?code _ -> ignore code)
2649 (env, supertype)
2650 | Some ExpectedTy.{ ty = { et_type = ty; _ }; _ } -> (env, ty)
2652 match get_node supertype with
2653 (* No need to check individual subtypes if expected type is mixed or any! *)
2654 | Tany _ -> (env, supertype, List.map tys ~f:(fun _ -> None))
2655 | _ ->
2656 let subtype_value env ty =
2657 check_expected_ty_res
2658 "Collection"
2661 (Some (ExpectedTy.make use_pos reason supertype))
2663 let (env, rev_ty_err_opts) =
2664 List.fold_left tys ~init:(env, []) ~f:(fun (env, errs) ty ->
2665 Result.fold
2666 ~ok:(fun env -> (env, None :: errs))
2667 ~error:(fun env -> (env, Some (ty, supertype) :: errs))
2668 @@ subtype_value env ty)
2672 List.exists tys ~f:(fun ty ->
2673 equal_locl_ty_ (get_node ty) (Typing_utils.tany env))
2674 then
2675 (* If one of the values comes from PHP land, we have to be conservative
2676 * and consider that we don't know what the type of the values are. *)
2677 (env, Typing_utils.mk_tany env p, List.rev rev_ty_err_opts)
2678 else
2679 (env, supertype, List.rev rev_ty_err_opts)
2682 * Given a 'a list and a method to extract an expr and its ty from a 'a, this
2683 * function extracts a list of exprs from the list, and computes the supertype
2684 * of all of the expressions' tys.
2686 let compute_exprs_and_supertype
2687 ~(expected : ExpectedTy.t option)
2688 ?(reason = Reason.URarray_value)
2689 ?bound
2690 ~use_pos
2694 extract_expr_and_ty =
2695 let (env, exprs_and_tys) =
2696 List.map_env env l ~f:(extract_expr_and_ty ~expected)
2698 let (exprs, tys) = List.unzip exprs_and_tys in
2699 let (env, supertype, err_opts) =
2700 compute_supertype ~expected ~reason ~use_pos ?bound r env tys
2702 ( env,
2703 List.map2_exn
2704 ~f:(fun te err_opt -> hole_on_err te ~err_opt)
2705 exprs
2706 err_opts,
2707 supertype )
2709 let check_collection_tparams env name tys =
2710 (* varrays and darrays are not classes but they share the same
2711 constraints with vec and dict respectively *)
2712 let name =
2713 if String.equal name SN.Typehints.varray then
2714 SN.Collections.cVec
2715 else if String.equal name SN.Typehints.darray then
2716 SN.Collections.cDict
2717 else
2718 name
2720 (* Class retrieval always succeeds because we're fetching a
2721 collection decl from an HHI file. *)
2722 match Env.get_class env name with
2723 | Some class_ ->
2724 let ety_env =
2726 (empty_expand_env_with_on_error
2727 (Env.invalid_type_hint_assert_primary_pos_in_current_decl env))
2728 with
2729 substs = TUtils.make_locl_subst_for_class_tparams class_ tys;
2732 Phase.check_tparams_constraints
2733 ~use_pos:p
2734 ~ety_env
2736 (Cls.tparams class_)
2737 | None ->
2738 let typechecking_is_deferring = Deferred_decl.is_deferring () in
2739 (if not typechecking_is_deferring then
2740 let desc = "Missing collection decl during type parameter check" in
2741 Telemetry.(create () |> string_ ~key:"class name" ~value:name)
2742 |> Errors.invariant_violation
2744 ~typechecking_is_deferring
2745 ~desc
2746 ~report_to_user:false);
2747 (* Continue typechecking without performing the check on a best effort
2748 basis. *)
2751 Typing_type_wellformedness.expr env outer;
2752 match e with
2753 | Import _
2754 | Collection _ ->
2755 failwith "AST should not contain these nodes"
2756 | Hole (e, _, _, _) ->
2757 expr_
2758 ?expected
2759 ~accept_using_var
2760 ~is_using_clause
2761 ?lhs_of_null_coalesce
2762 ?in_await
2763 ~allow_awaitable
2764 ~valkind
2765 ~check_defined
2768 | Omitted ->
2769 let ty = Typing_utils.mk_tany env p in
2770 make_result env p Aast.Omitted ty
2771 | Varray (th, el)
2772 | ValCollection (_, th, el) ->
2773 let (get_expected_kind, name, subtype_val, make_expr, make_ty) =
2774 match e with
2775 | ValCollection (kind, _, _) ->
2776 let class_name = Nast.vc_kind_to_name kind in
2777 let subtype_val =
2778 match kind with
2779 | Set
2780 | ImmSet
2781 | Keyset ->
2782 arraykey_value p class_name true
2783 | Vector
2784 | ImmVector
2785 | Vec ->
2786 array_value
2788 ( get_vc_inst kind,
2789 class_name,
2790 subtype_val,
2791 (fun th elements -> Aast.ValCollection (kind, th, elements)),
2792 fun value_ty ->
2793 MakeType.class_type (Reason.Rwitness p) class_name [value_ty] )
2794 | Varray _ ->
2795 ( get_vc_inst Vec,
2796 "varray",
2797 array_value,
2798 (fun th elements -> Aast.ValCollection (Vec, th, elements)),
2799 (fun value_ty -> MakeType.varray (Reason.Rwitness p) value_ty) )
2800 | _ ->
2801 (* The parent match makes this case impossible *)
2802 failwith "impossible match case"
2804 (* Use expected type to determine expected element type *)
2805 let (env, elem_expected, th) =
2806 match th with
2807 | Some (_, tv) ->
2808 let (env, tv, tv_expected) = localize_targ env tv in
2809 let env = check_collection_tparams env name [fst tv] in
2810 (env, Some tv_expected, Some tv)
2811 | _ ->
2812 begin
2813 match expand_expected_and_get_node env expected with
2814 | (env, Some (pos, ur, ety, _)) ->
2815 begin
2816 match get_expected_kind ety with
2817 | Some vty -> (env, Some (ExpectedTy.make pos ur vty), None)
2818 | None -> (env, None, None)
2820 | _ -> (env, None, None)
2823 let (env, tel, elem_ty) =
2824 compute_exprs_and_supertype
2825 ~expected:elem_expected
2826 ~use_pos:p
2827 ~reason:Reason.URvector
2828 (Reason.Rtype_variable_generics (p, "T", strip_ns name))
2831 subtype_val
2833 make_result env p (make_expr th tel) (make_ty elem_ty)
2834 | Darray (th, l)
2835 | KeyValCollection (_, th, l) ->
2836 let (get_expected_kind, name, make_expr, make_ty) =
2837 match e with
2838 | KeyValCollection (kind, _, _) ->
2839 let class_name = Nast.kvc_kind_to_name kind in
2840 ( get_kvc_inst p kind,
2841 class_name,
2842 (fun th pairs -> Aast.KeyValCollection (kind, th, pairs)),
2843 (fun k v -> MakeType.class_type (Reason.Rwitness p) class_name [k; v])
2845 | Darray _ ->
2846 let name = "darray" in
2847 ( get_kvc_inst p Dict,
2848 name,
2849 (fun th pairs -> Aast.KeyValCollection (Dict, th, pairs)),
2850 (fun k v -> MakeType.darray (Reason.Rwitness p) k v) )
2851 | _ ->
2852 (* The parent match makes this case impossible *)
2853 failwith "impossible match case"
2855 (* Use expected type to determine expected key and value types *)
2856 let (env, kexpected, vexpected, th) =
2857 match th with
2858 | Some ((_, tk), (_, tv)) ->
2859 let (env, tk, tk_expected) = localize_targ env tk in
2860 let (env, tv, tv_expected) = localize_targ env tv in
2861 let env = check_collection_tparams env name [fst tk; fst tv] in
2862 (env, Some tk_expected, Some tv_expected, Some (tk, tv))
2863 | _ ->
2864 (* no explicit typehint, fallback to supplied expect *)
2865 begin
2866 match expand_expected_and_get_node env expected with
2867 | (env, Some (pos, reason, ety, _)) ->
2868 begin
2869 match get_expected_kind ety with
2870 | Some (kty, vty) ->
2871 let k_expected = ExpectedTy.make pos reason kty in
2872 let v_expected = ExpectedTy.make pos reason vty in
2873 (env, Some k_expected, Some v_expected, None)
2874 | None -> (env, None, None, None)
2876 | _ -> (env, None, None, None)
2879 let (kl, vl) = List.unzip l in
2880 let r = Reason.Rtype_variable_generics (p, "Tk", strip_ns name) in
2881 let (env, tkl, k) =
2882 compute_exprs_and_supertype
2883 ~expected:kexpected
2884 ~use_pos:p
2885 ~reason:(Reason.URkey name)
2886 ~bound:(MakeType.arraykey r)
2890 (arraykey_value p name false)
2892 let (env, tvl, v) =
2893 compute_exprs_and_supertype
2894 ~expected:vexpected
2895 ~use_pos:p
2896 ~reason:Reason.URvalue
2897 (Reason.Rtype_variable_generics (p, "Tv", strip_ns name))
2900 array_value
2902 let pairs = List.zip_exn tkl tvl in
2903 make_result env p (make_expr th pairs) (make_ty k v)
2904 | Clone e ->
2905 let (env, te, ty) = expr env e in
2906 (* Clone only works on objects; anything else fatals at runtime.
2907 * Constructing a call `e`->__clone() checks that `e` is an object and
2908 * checks coeffects on __clone *)
2909 let (_, pe, _) = e in
2910 let (env, (tfty, _tal)) =
2911 TOG.obj_get
2912 ~obj_pos:pe
2913 ~is_method:true
2914 ~inst_meth:false
2915 ~meth_caller:false
2916 ~nullsafe:None
2917 ~coerce_from_ty:None
2918 ~explicit_targs:[]
2919 ~class_id:(CIexpr e)
2920 ~member_id:(p, SN.Members.__clone)
2921 ~on_error:Errors.unify_error
2925 let (env, (_tel, _typed_unpack_element, _ty, _should_forget_fakes)) =
2926 call ~expected:None p env tfty [] None
2928 make_result env p (Aast.Clone te) ty
2929 | This ->
2930 if Option.is_none (Env.get_self_ty env) then Errors.this_var_outside_class p;
2931 if not accept_using_var then check_escaping_var env (p, this);
2932 let ty = Env.get_local env this in
2933 let r = Reason.Rwitness p in
2934 let ty = mk (r, get_node ty) in
2935 make_result env p Aast.This ty
2936 | True -> make_result env p Aast.True (MakeType.bool (Reason.Rwitness p))
2937 | False -> make_result env p Aast.False (MakeType.bool (Reason.Rwitness p))
2938 (* TODO TAST: consider checking that the integer is in range. Right now
2939 * it's possible for HHVM to fail on well-typed Hack code
2941 | Int s -> make_result env p (Aast.Int s) (MakeType.int (Reason.Rwitness p))
2942 | Float s ->
2943 make_result env p (Aast.Float s) (MakeType.float (Reason.Rwitness p))
2944 (* TODO TAST: consider introducing a "null" type, and defining ?t to
2945 * be null | t
2947 | Null -> make_result env p Aast.Null (MakeType.null (Reason.Rwitness p))
2948 | String s ->
2949 make_result env p (Aast.String s) (MakeType.string (Reason.Rwitness p))
2950 | String2 idl ->
2951 let (env, tel) = string2 env idl in
2952 make_result env p (Aast.String2 tel) (MakeType.string (Reason.Rwitness p))
2953 | PrefixedString (n, e) ->
2954 if String.( <> ) n "re" then (
2955 Errors.experimental_feature
2957 "String prefixes other than `re` are not yet supported.";
2958 expr_error env Reason.Rnone outer
2959 ) else
2960 let (env, te, ty) = expr env e in
2961 let (_, pe, expr_) = e in
2962 let env = Typing_substring.sub_string pe env ty in
2963 (match expr_ with
2964 | String _ ->
2965 begin
2967 make_result
2970 (Aast.PrefixedString (n, te))
2971 (Typing_regex.type_pattern e)
2972 with
2973 | Pcre.Error (Pcre.BadPattern (s, i)) ->
2974 let s = s ^ " [" ^ string_of_int i ^ "]" in
2975 Errors.bad_regex_pattern pe s;
2976 expr_error env (Reason.Rregex pe) e
2977 | Typing_regex.Empty_regex_pattern ->
2978 Errors.bad_regex_pattern pe "This pattern is empty";
2979 expr_error env (Reason.Rregex pe) e
2980 | Typing_regex.Missing_delimiter ->
2981 Errors.bad_regex_pattern pe "Missing delimiter(s)";
2982 expr_error env (Reason.Rregex pe) e
2983 | Typing_regex.Invalid_global_option ->
2984 Errors.bad_regex_pattern pe "Invalid global option(s)";
2985 expr_error env (Reason.Rregex pe) e
2987 | String2 _ ->
2988 Errors.re_prefixed_non_string pe "Strings with embedded expressions";
2989 expr_error env (Reason.Rregex pe) e
2990 | _ ->
2991 Errors.re_prefixed_non_string pe "Non-strings";
2992 expr_error env (Reason.Rregex pe) e)
2993 | Fun_id x ->
2994 let (env, fty, _tal) = fun_type_of_id env x [] [] in
2995 make_result env p (Aast.Fun_id x) fty
2996 | Id ((cst_pos, cst_name) as id) ->
2997 (match Env.get_gconst env cst_name with
2998 | None when Partial.should_check_error (Env.get_mode env) 4106 ->
2999 Errors.unbound_global cst_pos;
3000 let ty = err_witness env cst_pos in
3001 make_result env cst_pos (Aast.Id id) ty
3002 | None -> make_result env p (Aast.Id id) (Typing_utils.mk_tany env cst_pos)
3003 | Some const ->
3004 let (env, ty) =
3005 Phase.localize_no_subst env ~ignore_errors:true const.cd_type
3007 make_result env p (Aast.Id id) ty)
3008 | Method_id (instance, meth) ->
3009 (* Method_id is used when creating a "method pointer" using the magic
3010 * inst_meth function.
3012 * Typing this is pretty simple, we just need to check that instance->meth
3013 * is public+not static and then return its type.
3015 let (env, te, ty1) = expr env instance in
3016 let (env, (result, _tal)) =
3017 TOG.obj_get
3018 ~inst_meth:true
3019 ~meth_caller:false
3020 ~obj_pos:p
3021 ~is_method:true
3022 ~nullsafe:None
3023 ~coerce_from_ty:None
3024 ~explicit_targs:[]
3025 ~class_id:(CIexpr instance)
3026 ~member_id:meth
3027 ~on_error:Errors.unify_error
3031 let (env, result) =
3032 Env.FakeMembers.check_instance_invalid env instance (snd meth) result
3034 make_result env p (Aast.Method_id (te, meth)) result
3035 | Method_caller (((pos, class_name) as pos_cname), meth_name) ->
3036 (* meth_caller('X', 'foo') desugars to:
3037 * $x ==> $x->foo()
3039 let class_ = Env.get_class env class_name in
3040 (match class_ with
3041 | None -> unbound_name env pos_cname outer
3042 | Some class_ ->
3043 (* Create a class type for the given object instantiated with unresolved
3044 * types for its type parameters.
3046 let () =
3047 if Ast_defs.is_c_trait (Cls.kind class_) then
3048 Errors.meth_caller_trait pos class_name
3050 let (env, tvarl) =
3051 List.map_env env (Cls.tparams class_) ~f:(fun env _ ->
3052 Env.fresh_type env p)
3054 let params =
3055 List.map (Cls.tparams class_) ~f:(fun { tp_name = (p, n); _ } ->
3056 (* TODO(T69551141) handle type arguments for Tgeneric *)
3057 MakeType.generic (Reason.Rwitness_from_decl p) n)
3059 let obj_type =
3060 MakeType.apply
3061 (Reason.Rwitness_from_decl (Pos_or_decl.of_raw_pos p))
3062 (Positioned.of_raw_positioned pos_cname)
3063 params
3065 let ety_env =
3067 (empty_expand_env_with_on_error (Errors.invalid_type_hint pos)) with
3068 substs = TUtils.make_locl_subst_for_class_tparams class_ tvarl;
3071 let (env, local_obj_ty) = Phase.localize ~ety_env env obj_type in
3072 let (env, (fty, _tal)) =
3073 TOG.obj_get
3074 ~obj_pos:pos
3075 ~is_method:true
3076 ~nullsafe:None
3077 ~inst_meth:false
3078 ~meth_caller:true
3079 ~coerce_from_ty:None
3080 ~explicit_targs:[]
3081 ~class_id:(CI (pos, class_name))
3082 ~member_id:meth_name
3083 ~on_error:Errors.unify_error
3085 local_obj_ty
3087 let (env, fty) = Env.expand_type env fty in
3088 (match deref fty with
3089 | (reason, Tfun ftype) ->
3090 (* We are creating a fake closure:
3091 * function(Class $x, arg_types_of(Class::meth_name))
3092 : return_type_of(Class::meth_name)
3094 let ety_env =
3096 ety_env with
3097 on_error = Env.unify_error_assert_primary_pos_in_current_decl env;
3100 let env =
3101 Phase.check_tparams_constraints
3102 ~use_pos:p
3103 ~ety_env
3105 (Cls.tparams class_)
3107 let local_obj_fp = TUtils.default_fun_param local_obj_ty in
3108 let fty = { ftype with ft_params = local_obj_fp :: ftype.ft_params } in
3109 let caller =
3111 ft_arity = fty.ft_arity;
3112 ft_tparams = fty.ft_tparams;
3113 ft_where_constraints = fty.ft_where_constraints;
3114 ft_params = fty.ft_params;
3115 ft_implicit_params = fty.ft_implicit_params;
3116 ft_ret = fty.ft_ret;
3117 ft_flags = fty.ft_flags;
3118 ft_ifc_decl = fty.ft_ifc_decl;
3121 make_result
3124 (Aast.Method_caller (pos_cname, meth_name))
3125 (mk (reason, Tfun caller))
3126 | _ ->
3127 (* This can happen if the method lives in PHP *)
3128 make_result
3131 (Aast.Method_caller (pos_cname, meth_name))
3132 (Typing_utils.mk_tany env pos)))
3133 | FunctionPointer (FP_class_const (cid, meth), targs) ->
3134 let (env, _, ce, cty) = class_expr env [] cid in
3135 let (env, (fpty, tal)) =
3136 class_get
3137 ~is_method:true
3138 ~is_const:false
3139 ~incl_tc:false (* What is this? *)
3140 ~coerce_from_ty:None (* What is this? *)
3141 ~explicit_targs:targs
3142 ~is_function_pointer:true
3145 meth
3148 let env = Env.set_tyvar_variance env fpty in
3149 let fpty = set_function_pointer fpty in
3150 make_result
3153 (Aast.FunctionPointer (FP_class_const (ce, meth), tal))
3154 fpty
3155 | Smethod_id (((_, pc, cid_) as cid), meth) ->
3156 (* Smethod_id is used when creating a "method pointer" using the magic
3157 * class_meth function.
3159 * Typing this is pretty simple, we just need to check that c::meth is
3160 * public+static and then return its type.
3162 let (class_, classname) =
3163 match cid_ with
3164 | CIself
3165 | CIstatic ->
3166 (Env.get_self_class env, Env.get_self_id env)
3167 | CI (_, const) when String.equal const SN.PseudoConsts.g__CLASS__ ->
3168 (Env.get_self_class env, Env.get_self_id env)
3169 | CI (_, id) -> (Env.get_class env id, Some id)
3170 | _ -> (None, None)
3172 let classname = Option.value classname ~default:"" in
3173 (match class_ with
3174 | None ->
3175 (* The class given as a static string was not found. *)
3176 unbound_name env (pc, classname) outer
3177 | Some class_ ->
3178 let smethod = Env.get_static_member true env class_ (snd meth) in
3179 (match smethod with
3180 | None ->
3181 (* The static method wasn't found. *)
3182 TOG.smember_not_found
3183 (fst meth)
3184 ~is_const:false
3185 ~is_method:true
3186 ~is_function_pointer:false
3187 class_
3188 (snd meth)
3189 Errors.unify_error;
3190 expr_error env Reason.Rnone outer
3191 | Some ({ ce_type = (lazy ty); ce_pos = (lazy ce_pos); _ } as ce) ->
3192 let () =
3193 if get_ce_abstract ce then
3194 match cid_ with
3195 | CIstatic -> ()
3196 | _ -> Errors.class_meth_abstract_call classname (snd meth) p ce_pos
3198 let ce_visibility = ce.ce_visibility in
3199 let ce_deprecated = ce.ce_deprecated in
3200 let (env, _tal, te, cid_ty) = class_expr ~exact:Exact env [] cid in
3201 let (env, cid_ty) = Env.expand_type env cid_ty in
3202 let tyargs =
3203 match get_node cid_ty with
3204 | Tclass (_, _, tyargs) -> tyargs
3205 | _ -> []
3207 let ety_env =
3209 empty_expand_env with
3210 substs = TUtils.make_locl_subst_for_class_tparams class_ tyargs;
3211 this_ty = cid_ty;
3214 let r = get_reason ty |> Typing_reason.localize in
3215 (match get_node ty with
3216 | Tfun ft ->
3217 let ft =
3218 Typing_enforceability.compute_enforced_and_pessimize_fun_type env ft
3220 let def_pos = ce_pos in
3221 let (env, tal) =
3222 Phase.localize_targs
3223 ~check_well_kinded:true
3224 ~is_method:true
3225 ~def_pos:ce_pos
3226 ~use_pos:p
3227 ~use_name:(strip_ns (snd meth))
3229 ft.ft_tparams
3232 let (env, ft) =
3233 Phase.(
3234 localize_ft
3235 ~instantiation:
3236 Phase.
3238 use_name = strip_ns (snd meth);
3239 use_pos = p;
3240 explicit_targs = tal;
3242 ~ety_env
3243 ~def_pos:ce_pos
3247 let ty = mk (r, Tfun ft) in
3248 let use_pos = fst meth in
3249 TVis.check_deprecated ~use_pos ~def_pos ce_deprecated;
3250 (match ce_visibility with
3251 | Vpublic
3252 | Vinternal _ ->
3253 make_result env p (Aast.Smethod_id (te, meth)) ty
3254 | Vprivate _ ->
3255 Errors.private_class_meth ~def_pos ~use_pos;
3256 expr_error env r outer
3257 | Vprotected _ ->
3258 Errors.protected_class_meth ~def_pos ~use_pos;
3259 expr_error env r outer)
3260 | _ ->
3261 Errors.internal_error p "We have a method which isn't callable";
3262 expr_error env r outer)))
3263 | Lplaceholder p ->
3264 let r = Reason.Rplaceholder p in
3265 let ty = MakeType.void r in
3266 make_result env p (Aast.Lplaceholder p) ty
3267 | Dollardollar _ when phys_equal valkind `lvalue ->
3268 Errors.dollardollar_lvalue p;
3269 expr_error env (Reason.Rwitness p) outer
3270 | Dollardollar id ->
3271 let ty = Env.get_local_check_defined env id in
3272 let env = might_throw env in
3273 make_result env p (Aast.Dollardollar id) ty
3274 | Lvar ((_, x) as id) ->
3275 if not accept_using_var then check_escaping_var env id;
3276 let ty =
3277 if check_defined then
3278 Env.get_local_check_defined env id
3279 else
3280 Env.get_local env x
3282 make_result env p (Aast.Lvar id) ty
3283 | Tuple el ->
3284 let (env, expected) = expand_expected_and_get_node env expected in
3285 let (env, tel, tyl) =
3286 match expected with
3287 | Some (pos, ur, _, Ttuple expected_tyl) ->
3288 exprs_expected (pos, ur, expected_tyl) env el
3289 | _ -> exprs env el
3291 let ty = MakeType.tuple (Reason.Rwitness p) tyl in
3292 make_result env p (Aast.Tuple tel) ty
3293 | List el ->
3294 let (env, tel, tyl) =
3295 match valkind with
3296 | `lvalue
3297 | `lvalue_subexpr ->
3298 lvalues env el
3299 | `other ->
3300 let (env, expected) = expand_expected_and_get_node env expected in
3301 (match expected with
3302 | Some (pos, ur, _, Ttuple expected_tyl) ->
3303 exprs_expected (pos, ur, expected_tyl) env el
3304 | _ -> exprs env el)
3306 let ty = MakeType.tuple (Reason.Rwitness p) tyl in
3307 make_result env p (Aast.List tel) ty
3308 | Pair (th, e1, e2) ->
3309 let (env, expected1, expected2, th) =
3310 match th with
3311 | Some ((_, t1), (_, t2)) ->
3312 let (env, t1, t1_expected) = localize_targ env t1 in
3313 let (env, t2, t2_expected) = localize_targ env t2 in
3314 (env, Some t1_expected, Some t2_expected, Some (t1, t2))
3315 | None ->
3316 (* Use expected type to determine expected element types *)
3317 (match expand_expected_and_get_node env expected with
3318 | (env, Some (pos, reason, _ty, Tclass ((_, k), _, [ty1; ty2])))
3319 when String.equal k SN.Collections.cPair ->
3320 let ty1_expected = ExpectedTy.make pos reason ty1 in
3321 let ty2_expected = ExpectedTy.make pos reason ty2 in
3322 (env, Some ty1_expected, Some ty2_expected, None)
3323 | _ -> (env, None, None, None))
3325 let (env, te1, ty1) = expr ?expected:expected1 env e1 in
3326 let (env, te2, ty2) = expr ?expected:expected2 env e2 in
3327 let (_, p1, _) = e1 in
3328 let (_, p2, _) = e2 in
3329 let (env, ty1, err_opt1) =
3330 compute_supertype
3331 ~expected:expected1
3332 ~reason:Reason.URpair_value
3333 ~use_pos:p1
3334 (Reason.Rtype_variable_generics (p1, "T1", "Pair"))
3336 [ty1]
3338 let (env, ty2, err_opt2) =
3339 compute_supertype
3340 ~expected:expected2
3341 ~reason:Reason.URpair_value
3342 ~use_pos:p2
3343 (Reason.Rtype_variable_generics (p2, "T2", "Pair"))
3345 [ty2]
3347 let ty = MakeType.pair (Reason.Rwitness p) ty1 ty2 in
3348 make_result
3351 (Aast.Pair
3352 ( th,
3353 hole_on_err te1 ~err_opt:(Option.join @@ List.hd err_opt1),
3354 hole_on_err te2 ~err_opt:(Option.join @@ List.hd err_opt2) ))
3356 | Array_get (e, None) ->
3357 let (env, te, _) = update_array_type p env e valkind in
3358 let env = might_throw env in
3359 (* NAST check reports an error if [] is used for reading in an
3360 lvalue context. *)
3361 let ty = err_witness env p in
3362 make_result env p (Aast.Array_get (te, None)) ty
3363 | Array_get (e1, Some e2) ->
3364 let (env, te1, ty1) =
3365 update_array_type ?lhs_of_null_coalesce p env e1 valkind
3367 let (env, te2, ty2) = expr env e2 in
3368 let env = might_throw env in
3369 let is_lvalue = phys_equal valkind `lvalue in
3370 let (_, p1, _) = e1 in
3371 let (env, ty, key_err_opt, arr_err_opt) =
3372 Typing_array_access.array_get
3373 ~array_pos:p1
3374 ~expr_pos:p
3375 ?lhs_of_null_coalesce
3376 is_lvalue
3382 make_result
3385 (Aast.Array_get
3386 ( hole_on_err ~err_opt:arr_err_opt te1,
3387 Some (hole_on_err ~err_opt:key_err_opt te2) ))
3389 | Call ((_, pos_id, Id ((_, s) as id)), [], el, None)
3390 when Hash_set.mem typing_env_pseudofunctions s ->
3391 let (env, tel, tys) = exprs ~accept_using_var:true env el in
3392 let env =
3393 if String.equal s SN.PseudoFunctions.hh_show then (
3394 List.iter tys ~f:(Typing_log.hh_show p env);
3396 ) else if String.equal s SN.PseudoFunctions.hh_show_env then (
3397 Typing_log.hh_show_env p env;
3399 ) else if String.equal s SN.PseudoFunctions.hh_log_level then
3400 match el with
3401 | [(_, _, String key_str); (_, _, Int level_str)] ->
3402 Env.set_log_level env key_str (int_of_string level_str)
3403 | _ -> env
3404 else if String.equal s SN.PseudoFunctions.hh_force_solve then
3405 Typing_solver.solve_all_unsolved_tyvars env
3406 else if String.equal s SN.PseudoFunctions.hh_loop_forever then
3407 let _ = loop_forever env in
3409 else
3412 let ty = MakeType.void (Reason.Rwitness p) in
3413 make_result
3416 (Aast.Call
3417 ( Tast.make_typed_expr pos_id (TUtils.mk_tany env pos_id) (Aast.Id id),
3419 tel,
3420 None ))
3422 | Call (e, explicit_targs, el, unpacked_element) ->
3423 let env = might_throw env in
3424 let ((env, te, ty), should_forget_fakes) =
3425 dispatch_call
3426 ~is_using_clause
3427 ~expected
3428 ?in_await
3432 explicit_targs
3434 unpacked_element
3436 let env =
3437 if should_forget_fakes then
3438 Env.forget_members env Reason.(Blame (p, BScall))
3439 else
3442 (env, te, ty)
3443 | FunctionPointer (FP_id fid, targs) ->
3444 let (env, fty, targs) = fun_type_of_id env fid targs [] in
3445 let e = Aast.FunctionPointer (FP_id fid, targs) in
3446 let fty = set_function_pointer fty in
3447 make_result env p e fty
3448 | Binop (Ast_defs.QuestionQuestion, e1, e2) ->
3449 let (_, e1_pos, _) = e1 in
3450 let (_, e2_pos, _) = e2 in
3451 let (env, te1, ty1) =
3452 raw_expr ~lhs_of_null_coalesce:true env e1 ~allow_awaitable:true
3454 let (env, te2, ty2) = expr ?expected env e2 ~allow_awaitable:true in
3455 let (env, ty1') = Env.fresh_type env e1_pos in
3456 let env =
3457 SubType.sub_type
3460 (MakeType.nullable_locl Reason.Rnone ty1')
3461 (Errors.unify_error_at e1_pos)
3463 (* Essentially mimic a call to
3464 * function coalesce<Tr, Ta as Tr, Tb as Tr>(?Ta, Tb): Tr
3465 * That way we let the constraint solver take care of the union logic.
3467 let (env, ty_result) = Env.fresh_type env e2_pos in
3468 let env = SubType.sub_type env ty1' ty_result (Errors.unify_error_at p) in
3469 let env = SubType.sub_type env ty2 ty_result (Errors.unify_error_at p) in
3470 make_result
3473 (Aast.Binop (Ast_defs.QuestionQuestion, te1, te2))
3474 ty_result
3475 | Binop (Ast_defs.Eq op_opt, e1, e2) ->
3476 let make_result env p te ty =
3477 let (env, te, ty) = make_result env p te ty in
3478 let env = Typing_local_ops.check_assignment env te in
3479 (env, te, ty)
3481 (match op_opt with
3482 (* For example, e1 += e2. This is typed and translated as if
3483 * written e1 = e1 + e2.
3484 * TODO TAST: is this right? e1 will get evaluated more than once
3486 | Some op ->
3487 let (_, _, expr_) = e1 in
3488 (match (op, expr_) with
3489 | (Ast_defs.QuestionQuestion, Class_get _) ->
3490 Errors.experimental_feature
3492 "null coalesce assignment operator with static properties";
3493 expr_error env Reason.Rnone outer
3494 | _ ->
3495 let e_fake =
3496 ((), p, Binop (Ast_defs.Eq None, e1, ((), p, Binop (op, e1, e2))))
3498 let (env, te_fake, ty) = raw_expr env e_fake in
3499 let te_opt = resugar_binop te_fake in
3500 begin
3501 match te_opt with
3502 | Some (_, _, te) -> make_result env p te ty
3503 | _ -> assert false
3504 end)
3505 | None ->
3506 let (env, te2, ty2) = raw_expr env e2 in
3507 let (_, pos2, _) = te2 in
3508 let (env, te1, ty, err_opt) = assign p env e1 pos2 ty2 in
3509 let te = Aast.Binop (Ast_defs.Eq None, te1, hole_on_err ~err_opt te2) in
3510 make_result env p te ty)
3511 | Binop (((Ast_defs.Ampamp | Ast_defs.Barbar) as bop), e1, e2) ->
3512 let c = Ast_defs.(equal_bop bop Ampamp) in
3513 let (env, te1, _) = expr env e1 in
3514 let lenv = env.lenv in
3515 let (env, _lset) = condition env c te1 in
3516 let (env, te2, _) = expr env e2 in
3517 let env = { env with lenv } in
3518 make_result
3521 (Aast.Binop (bop, te1, te2))
3522 (MakeType.bool (Reason.Rlogic_ret p))
3523 | Binop (bop, e1, e2) ->
3524 let (env, te1, ty1) = raw_expr env e1 in
3525 let (env, te2, ty2) = raw_expr env e2 in
3526 let env =
3527 match bop with
3528 (* TODO: This could be less conservative: we only need to account for
3529 * the possibility of exception if the operator is `/` or `/=`.
3531 | Ast_defs.Eqeqeq
3532 | Ast_defs.Diff2 ->
3534 | _ -> might_throw env
3536 let (_, p1, _) = e1 in
3537 let (_, p2, _) = e2 in
3538 let (env, te3, ty) =
3539 Typing_arithmetic.binop p env bop p1 te1 ty1 p2 te2 ty2
3541 (env, te3, ty)
3542 | Pipe (e0, e1, e2) ->
3543 (* If it weren't for local variable assignment or refinement the pipe
3544 * expression e1 |> e2 could be typed using this rule (E is environment with
3545 * types for locals):
3547 * E |- e1 : ty1 E[$$:ty1] |- e2 : ty2
3548 * --------------------------------------
3549 * E |- e1|>e2 : ty2
3551 * The possibility of e2 changing the types of locals in E means that E
3552 * can evolve, and so we need to restore $$ to its original state.
3554 let (env, te1, ty1) = expr env e1 in
3555 let dd_var = Local_id.make_unscoped SN.SpecialIdents.dollardollar in
3556 let dd_old_ty =
3557 if Env.is_local_defined env dd_var then
3558 Some (Env.get_local_pos env dd_var)
3559 else
3560 None
3562 let env = Env.set_local env dd_var ty1 Pos.none in
3563 let (env, te2, ty2) = expr env e2 ~allow_awaitable:true in
3564 let env =
3565 match dd_old_ty with
3566 | None -> Env.unset_local env dd_var
3567 | Some (ty, pos) -> Env.set_local env dd_var ty pos
3569 let (env, te, ty) = make_result env p (Aast.Pipe (e0, te1, te2)) ty2 in
3570 (env, te, ty)
3571 | Unop (uop, e) ->
3572 let (env, te, ty) = raw_expr env e in
3573 let env = might_throw env in
3574 let (env, tuop, ty) = Typing_arithmetic.unop p env uop te ty in
3575 let env = Typing_local_ops.check_assignment env te in
3576 (env, tuop, ty)
3577 | Eif (c, e1, e2) -> eif env ~expected ?in_await p c e1 e2
3578 | Class_const ((_, p, CI sid), pstr)
3579 when String.equal (snd pstr) "class" && Env.is_typedef env (snd sid) ->
3580 begin
3581 match Env.get_typedef env (snd sid) with
3582 | Some { td_tparams = tparaml; _ } ->
3583 (* Typedef type parameters cannot have constraints *)
3584 let params =
3585 List.map
3587 begin
3588 fun { tp_name = (p, x); _ } ->
3589 (* TODO(T69551141) handle type arguments for Tgeneric *)
3590 MakeType.generic (Reason.Rwitness_from_decl p) x
3592 tparaml
3594 let p_ = Pos_or_decl.of_raw_pos p in
3595 let tdef =
3597 ( Reason.Rwitness_from_decl p_,
3598 Tapply (Positioned.of_raw_positioned sid, params) )
3600 let typename =
3602 ( Reason.Rwitness_from_decl p_,
3603 Tapply ((p_, SN.Classes.cTypename), [tdef]) )
3605 let (env, tparams) =
3606 List.map_env env tparaml ~f:(fun env _tp -> Env.fresh_type env p)
3608 let ety_env =
3610 (empty_expand_env_with_on_error
3611 (Env.invalid_type_hint_assert_primary_pos_in_current_decl env))
3612 with
3613 substs = Subst.make_locl tparaml tparams;
3616 let env =
3617 Phase.check_tparams_constraints ~use_pos:p ~ety_env env tparaml
3619 let (env, ty) = Phase.localize ~ety_env env typename in
3620 make_result env p (Class_const ((ty, p, CI sid), pstr)) ty
3621 | None ->
3622 (* Should not expect None as we've checked whether the sid is a typedef *)
3623 expr_error env (Reason.Rwitness p) outer
3625 | Class_const (cid, mid) -> class_const env p (cid, mid)
3626 | Class_get (((_, _, cid_) as cid), CGstring mid, in_parens)
3627 when Env.FakeMembers.is_valid_static env cid_ (snd mid) ->
3628 let (env, local) = Env.FakeMembers.make_static env cid_ (snd mid) p in
3629 let local = ((), p, Lvar (p, local)) in
3630 let (env, _, ty) = expr env local in
3631 let (env, _tal, te, _) = class_expr env [] cid in
3632 make_result env p (Aast.Class_get (te, Aast.CGstring mid, in_parens)) ty
3633 | Class_get (((_, _, cid_) as cid), CGstring ((ppos, _) as mid), in_parens) ->
3634 let (env, _tal, te, cty) = class_expr env [] cid in
3635 let env = might_throw env in
3636 let (env, (ty, _tal)) =
3637 class_get
3638 ~is_method:false
3639 ~is_const:false
3640 ~coerce_from_ty:None
3646 let (env, ty) =
3647 Env.FakeMembers.check_static_invalid env cid_ (snd mid) ty
3649 let env =
3650 Errors.try_if_no_errors
3651 (fun () -> Typing_local_ops.enforce_static_property_access ppos env)
3652 (fun env ->
3653 let is_lvalue = phys_equal valkind `lvalue in
3654 (* If it's an lvalue we throw an error in a separate check in check_assign *)
3655 if in_readonly_expr || is_lvalue then
3657 else
3658 Typing_local_ops.enforce_mutable_static_variable
3659 ppos
3661 (* This msg only appears if we have access to ReadStaticVariables,
3662 since otherwise we would have errored in the first function *)
3663 ~msg:"Please enclose the static in a readonly expression")
3665 make_result env p (Aast.Class_get (te, Aast.CGstring mid, in_parens)) ty
3666 (* Fake member property access. For example:
3667 * if ($x->f !== null) { ...$x->f... }
3669 | Class_get (_, CGexpr _, _) ->
3670 failwith "AST should not have any CGexprs after naming"
3671 | Obj_get (e, (_, pid, Id (py, y)), nf, in_parens)
3672 when Env.FakeMembers.is_valid env e y ->
3673 let env = might_throw env in
3674 let (env, local) = Env.FakeMembers.make env e y p in
3675 let local = ((), p, Lvar (p, local)) in
3676 let (env, _, ty) = expr env local in
3677 let (env, t_lhs, _) = expr ~accept_using_var:true env e in
3678 let t_rhs = Tast.make_typed_expr pid ty (Aast.Id (py, y)) in
3679 make_result env p (Aast.Obj_get (t_lhs, t_rhs, nf, in_parens)) ty
3680 (* Statically-known instance property access e.g. $x->f *)
3681 | Obj_get (e1, (_, pm, Id m), nullflavor, in_parens) ->
3682 let nullsafe =
3683 match nullflavor with
3684 | OG_nullthrows -> None
3685 | OG_nullsafe -> Some p
3687 let (env, te1, ty1) = expr ~accept_using_var:true env e1 in
3688 let env = might_throw env in
3689 (* We typecheck Obj_get by checking whether it is a subtype of
3690 Thas_member(m, #1) where #1 is a fresh type variable. *)
3691 let (env, mem_ty) = Env.fresh_type env p in
3692 let (_, p1, _) = e1 in
3693 let r = Reason.Rwitness p1 in
3694 let has_member_ty =
3695 MakeType.has_member
3697 ~name:m
3698 ~ty:mem_ty
3699 ~class_id:(CIexpr e1)
3700 ~explicit_targs:None
3702 let lty1 = LoclType ty1 in
3703 let (env, result_ty) =
3704 match nullsafe with
3705 | None ->
3706 let env =
3707 Type.sub_type_i
3709 Reason.URnone
3711 lty1
3712 has_member_ty
3713 Errors.unify_error
3715 (env, mem_ty)
3716 | Some _ ->
3717 (* In that case ty1 is a subtype of ?Thas_member(m, #1)
3718 and the result is ?#1 if ty1 is nullable. *)
3719 let r = Reason.Rnullsafe_op p in
3720 let null_ty = MakeType.null r in
3721 let (env, null_has_mem_ty) =
3722 Union.union_i env r has_member_ty null_ty
3724 let env =
3725 Type.sub_type_i
3727 Reason.URnone
3729 lty1
3730 null_has_mem_ty
3731 Errors.unify_error
3733 let (env, null_or_nothing_ty) = Inter.intersect env ~r null_ty ty1 in
3734 let (env, result_ty) = Union.union env null_or_nothing_ty mem_ty in
3735 (env, result_ty)
3737 let (env, result_ty) =
3738 Env.FakeMembers.check_instance_invalid env e1 (snd m) result_ty
3740 make_result
3743 (Aast.Obj_get
3744 ( te1,
3745 Tast.make_typed_expr pm result_ty (Aast.Id m),
3746 nullflavor,
3747 in_parens ))
3748 result_ty
3749 (* Dynamic instance property access e.g. $x->$f *)
3750 | Obj_get (e1, e2, nullflavor, in_parens) ->
3751 let (env, te1, ty1) = expr ~accept_using_var:true env e1 in
3752 let (env, te2, _) = expr env e2 in
3753 let ty =
3754 if TUtils.is_dynamic env ty1 then
3755 MakeType.dynamic (Reason.Rwitness p)
3756 else
3757 Typing_utils.mk_tany env p
3759 let (_, pos, te2) = te2 in
3760 let env = might_throw env in
3761 let te2 = Tast.make_typed_expr pos ty te2 in
3762 make_result env p (Aast.Obj_get (te1, te2, nullflavor, in_parens)) ty
3763 | Yield af ->
3764 let (env, (taf, opt_key, value)) = array_field ~allow_awaitable env af in
3765 let Typing_env_return_info.{ return_type = expected_return; _ } =
3766 Env.get_return env
3768 let send =
3769 match get_node expected_return.et_type with
3770 | Tclass (_, _, _ :: _ :: send :: _) -> send
3771 | _ ->
3772 Errors.internal_error p "Return type is not a generator";
3773 Typing_utils.terr env (Reason.Ryield_send p)
3775 let is_async =
3776 match Env.get_fn_kind env with
3777 | Ast_defs.FGenerator -> false
3778 (* This could also catch sync/async non-generators, but an error would
3779 * have already been generated elsewhere *)
3780 | _ -> true
3782 let (env, key) =
3783 match (af, opt_key) with
3784 | (AFvalue (_, p, _), None) ->
3785 if is_async then
3786 let (env, ty) = Env.fresh_type env p in
3787 (env, MakeType.nullable_locl (Reason.Ryield_asyncnull p) ty)
3788 else
3789 (env, MakeType.int (Reason.Rwitness p))
3790 | (_, Some x) -> (env, x)
3791 | (_, _) -> assert false
3793 let rty =
3794 if is_async then
3795 MakeType.async_generator (Reason.Ryield_asyncgen p) key value send
3796 else
3797 MakeType.generator (Reason.Ryield_gen p) key value send
3799 let Typing_env_return_info.{ return_type = expected_return; _ } =
3800 Env.get_return env
3802 let env =
3803 Typing_coercion.coerce_type
3805 Reason.URyield
3808 expected_return
3809 Errors.unify_error
3811 let env = Env.forget_members env Reason.(Blame (p, BScall)) in
3812 let env = LEnv.save_and_merge_next_in_cont env C.Exit in
3813 make_result
3816 (Aast.Yield taf)
3817 (MakeType.nullable_locl (Reason.Ryield_send p) send)
3818 | Await e ->
3819 let env = might_throw env in
3820 (* Await is permitted in a using clause e.g. using (await make_handle()) *)
3821 let (env, te, rty) =
3822 expr
3823 ~is_using_clause
3824 ~in_await:(Reason.Rwitness p)
3827 ~allow_awaitable:true
3829 let (env, ty) = Async.overload_extract_from_awaitable env ~p rty in
3830 make_result env p (Aast.Await te) ty
3831 | ReadonlyExpr e ->
3832 let (env, te, rty) = expr ~is_using_clause ~in_readonly_expr:true env e in
3833 make_result env p (Aast.ReadonlyExpr te) rty
3834 | New ((_, pos, c), explicit_targs, el, unpacked_element, ()) ->
3835 let env = might_throw env in
3836 let ( env,
3838 tal,
3839 tel,
3840 typed_unpack_element,
3842 ctor_fty,
3843 should_forget_fakes ) =
3844 new_object
3845 ~expected
3846 ~is_using_clause
3847 ~check_parent:false
3848 ~check_not_abstract:true
3852 explicit_targs
3854 unpacked_element
3856 let env =
3857 if should_forget_fakes then
3858 Env.forget_members env Reason.(Blame (p, BScall))
3859 else
3862 make_result
3865 (Aast.New (tc, tal, tel, typed_unpack_element, ctor_fty))
3867 | Record ((pos, id), field_values) ->
3868 (match Decl_provider.get_record_def (Env.get_ctx env) id with
3869 | Some rd ->
3870 if rd.rdt_abstract then Errors.new_abstract_record (pos, id);
3872 let field_name (_, pos, expr_) =
3873 match expr_ with
3874 | Aast.String name -> Some (pos, name)
3875 | _ ->
3876 (* TODO T44306013: Ensure that other values for field names are banned. *)
3877 None
3879 let fields_declared = Typing_helpers.all_record_fields env rd in
3880 let fields_present =
3881 List.map field_values ~f:(fun (name, _value) -> field_name name)
3882 |> List.filter_opt
3884 (* Check for missing required fields. *)
3885 let fields_present_names =
3886 List.map ~f:snd fields_present |> SSet.of_list
3888 SMap.iter
3889 (fun field_name info ->
3890 let ((field_pos, _), req) = info in
3891 match req with
3892 | Typing_defs.ValueRequired
3893 when not (SSet.mem field_name fields_present_names) ->
3894 Errors.missing_record_field_name
3895 ~field_name
3896 ~new_pos:pos
3897 ~record_name:id
3898 ~field_decl_pos:field_pos
3899 | _ -> ())
3900 fields_declared;
3902 (* Check for unknown fields.*)
3903 List.iter fields_present ~f:(fun (pos, field_name) ->
3904 if not (SMap.mem field_name fields_declared) then
3905 Errors.unexpected_record_field_name
3906 ~field_name
3907 ~field_pos:pos
3908 ~record_name:id
3909 ~decl_pos:(fst rd.rdt_name))
3910 | None -> Errors.type_not_record id pos);
3912 expr_error env (Reason.Rwitness p) outer
3913 | Cast (hint, e) ->
3914 let (env, te, ty2) = expr ?in_await env e in
3915 let env = might_throw env in
3916 let env =
3918 TypecheckerOptions.experimental_feature_enabled
3919 (Env.get_tcopt env)
3920 TypecheckerOptions.experimental_forbid_nullable_cast
3921 && not (TUtils.is_mixed env ty2)
3922 then
3923 SubType.sub_type_or_fail
3926 (MakeType.nonnull (get_reason ty2))
3927 (fun () ->
3928 Errors.nullable_cast p (Typing_print.error env ty2) (get_pos ty2))
3929 else
3932 let (env, ty) =
3933 Phase.localize_hint_no_subst env ~ignore_errors:false hint
3935 make_result env p (Aast.Cast (hint, te)) ty
3936 | ExpressionTree et -> expression_tree env p et
3937 | Is (e, hint) ->
3938 let (env, te, _) = expr env e in
3939 make_result env p (Aast.Is (te, hint)) (MakeType.bool (Reason.Rwitness p))
3940 | As (e, hint, is_nullable) ->
3941 let refine_type env lpos lty rty =
3942 let reason = Reason.Ras lpos in
3943 let (env, rty) = Env.expand_type env rty in
3944 let (env, rty) = class_for_refinement env p reason lpos lty rty in
3945 Inter.intersect env ~r:reason lty rty
3947 let (env, te, expr_ty) = expr env e in
3948 let env = might_throw env in
3949 let (env, hint_ty) =
3950 Phase.localize_hint_no_subst env ~ignore_errors:false hint
3952 let enable_sound_dynamic =
3953 TypecheckerOptions.enable_sound_dynamic env.genv.tcopt
3955 let is_dyn = Typing_utils.is_dynamic env hint_ty in
3956 let env =
3957 if enable_sound_dynamic && is_dyn then
3958 SubType.sub_type
3959 ~coerce:(Some Typing_logic.CoerceToDynamic)
3961 expr_ty
3962 hint_ty
3963 (Errors.unify_error_at p)
3964 else
3967 let (env, hint_ty) =
3968 if is_dyn && not enable_sound_dynamic then
3969 let env =
3970 if is_instance_var e then
3971 let (env, ivar) = get_instance_var env e in
3972 set_local env ivar hint_ty
3973 else
3976 (env, hint_ty)
3977 else if is_nullable && not is_dyn then
3978 let (_, e_p, _) = e in
3979 let (env, hint_ty) = refine_type env e_p expr_ty hint_ty in
3980 (env, MakeType.nullable_locl (Reason.Rwitness p) hint_ty)
3981 else if is_instance_var e then
3982 let (env, _, ivar_ty) = raw_expr env e in
3983 let (env, ((ivar_pos, _) as ivar)) = get_instance_var env e in
3984 let (env, hint_ty) = refine_type env ivar_pos ivar_ty hint_ty in
3985 let env = set_local env ivar hint_ty in
3986 (env, hint_ty)
3987 else
3988 let (_, e_p, _) = e in
3989 refine_type env e_p expr_ty hint_ty
3991 make_result env p (Aast.As (te, hint, is_nullable)) hint_ty
3992 | Efun (f, idl)
3993 | Lfun (f, idl) ->
3994 let is_anon =
3995 match e with
3996 | Efun _ -> true
3997 | Lfun _ -> false
3998 | _ -> assert false
4000 (* Check attributes on the lambda *)
4001 let env =
4002 attributes_check_def env SN.AttributeKinds.lambda f.f_user_attributes
4004 (* This is the function type as declared on the lambda itself.
4005 * If type hints are absent then use Tany instead. *)
4006 let declared_fe =
4007 Decl_nast.fun_decl_in_env env.decl_env ~is_lambda:true f
4009 let { fe_type; fe_pos; _ } = declared_fe in
4010 let (declared_pos, declared_ft) =
4011 match get_node fe_type with
4012 | Tfun ft -> (fe_pos, ft)
4013 | _ -> failwith "Not a function"
4015 let declared_ft =
4016 Typing_enforceability.compute_enforced_and_pessimize_fun_type
4018 declared_ft
4020 (* When creating a closure, the 'this' type will mean the late bound type
4021 * of the current enclosing class
4023 let ety_env =
4024 empty_expand_env_with_on_error
4025 (Env.invalid_type_hint_assert_primary_pos_in_current_decl env)
4027 let (env, declared_ft) =
4028 Phase.(
4029 localize_ft
4030 ~instantiation:
4031 { use_name = "lambda"; use_pos = p; explicit_targs = [] }
4032 ~ety_env
4033 ~def_pos:declared_pos
4035 declared_ft)
4037 List.iter idl ~f:(check_escaping_var env);
4039 (* Ensure lambda arity is not ellipsis in strict mode *)
4040 begin
4041 match declared_ft.ft_arity with
4042 | Fvariadic { fp_name = None; _ }
4043 when Partial.should_check_error (Env.get_mode env) 4223 ->
4044 Errors.ellipsis_strict_mode ~require:`Param_name p
4045 | _ -> ()
4046 end;
4048 (* Is the return type declared? *)
4049 let is_explicit_ret = Option.is_some (hint_of_type_hint f.f_ret) in
4050 let check_body_under_known_params env ?ret_ty ft : env * _ * locl_ty =
4051 let (env, (tefun, ty, ft)) =
4052 closure_make ?ret_ty env p f ft idl is_anon
4054 let inferred_ty =
4056 ( Reason.Rwitness p,
4057 Tfun
4059 ft with
4060 ft_ret =
4061 (if is_explicit_ret then
4062 declared_ft.ft_ret
4063 else
4064 MakeType.unenforced ty);
4067 (env, tefun, inferred_ty)
4069 let (env, eexpected) = expand_expected_and_get_node env expected in
4070 (* TODO: move this into the expand_expected_and_get_node function and prune its callsites
4071 * Strip like type from function type hint *)
4072 let eexpected =
4073 match eexpected with
4074 | Some (pos, ur, _, Tunion [ty1; ty2]) when is_dynamic ty1 && is_fun ty2
4076 Some (pos, ur, ty2, get_node ty2)
4077 | _ -> eexpected
4079 begin
4080 match eexpected with
4081 | Some (_pos, _ur, ty, Tfun expected_ft) ->
4082 (* First check that arities match up *)
4083 check_lambda_arity p (get_pos ty) declared_ft expected_ft;
4084 (* Use declared types for parameters in preference to those determined
4085 * by the context (expected parameters): they might be more general. *)
4086 let rec replace_non_declared_types declared_ft_params expected_ft_params
4088 match (declared_ft_params, expected_ft_params) with
4089 | ( declared_ft_param :: declared_ft_params,
4090 expected_ft_param :: expected_ft_params ) ->
4091 let rest =
4092 replace_non_declared_types declared_ft_params expected_ft_params
4094 (* If the type parameter did not have a type hint, it is Tany and
4095 we use the expected type instead. Otherwise, declared type takes
4096 precedence. *)
4097 let resolved_ft_param =
4098 if TUtils.is_any env declared_ft_param.fp_type.et_type then
4099 { declared_ft_param with fp_type = expected_ft_param.fp_type }
4100 else
4101 declared_ft_param
4103 resolved_ft_param :: rest
4104 | (_, []) ->
4105 (* Morally, this case should match on ([],[]) because we already
4106 check arity mismatch between declared and expected types. We
4107 handle it more generally here to be graceful. *)
4108 declared_ft_params
4109 | ([], _) ->
4110 (* This means the expected_ft params list can have more parameters
4111 * than declared parameters in the lambda. For variadics, this is OK.
4113 expected_ft_params
4115 let replace_non_declared_arity variadic declared_arity expected_arity =
4116 match variadic with
4117 | FVvariadicArg { param_type_hint = (_, Some _); _ } -> declared_arity
4118 | FVvariadicArg _ ->
4119 begin
4120 match (declared_arity, expected_arity) with
4121 | (Fvariadic declared, Fvariadic expected) ->
4122 Fvariadic { declared with fp_type = expected.fp_type }
4123 | (_, _) -> declared_arity
4125 | _ -> declared_arity
4127 let expected_ft =
4129 expected_ft with
4130 ft_arity =
4131 replace_non_declared_arity
4132 f.f_variadic
4133 declared_ft.ft_arity
4134 expected_ft.ft_arity;
4135 ft_params =
4136 replace_non_declared_types
4137 declared_ft.ft_params
4138 expected_ft.ft_params;
4139 ft_implicit_params = declared_ft.ft_implicit_params;
4142 (* Don't bother passing in `void` if there is no explicit return *)
4143 let ret_ty =
4144 match get_node expected_ft.ft_ret.et_type with
4145 | Tprim Tvoid when not is_explicit_ret -> None
4146 | _ -> Some expected_ft.ft_ret.et_type
4148 Typing_log.increment_feature_count env FL.Lambda.contextual_params;
4149 check_body_under_known_params env ?ret_ty expected_ft
4150 | _ ->
4151 let explicit_variadic_param_or_non_variadic =
4152 match f.f_variadic with
4153 | FVvariadicArg { param_type_hint; _ } ->
4154 Option.is_some (hint_of_type_hint param_type_hint)
4155 | FVellipsis _ -> false
4156 | _ -> true
4158 (* If all parameters are annotated with explicit types, then type-check
4159 * the body under those assumptions and pick up the result type *)
4160 let all_explicit_params =
4161 List.for_all f.f_params ~f:(fun param ->
4162 Option.is_some (hint_of_type_hint param.param_type_hint))
4164 if all_explicit_params && explicit_variadic_param_or_non_variadic then (
4165 Typing_log.increment_feature_count
4167 (if List.is_empty f.f_params then
4168 FL.Lambda.no_params
4169 else
4170 FL.Lambda.explicit_params);
4171 check_body_under_known_params env declared_ft
4172 ) else (
4173 match expected with
4174 | Some ExpectedTy.{ ty = { et_type; _ }; _ } when is_any et_type ->
4175 (* If the expected type is Tany env then we're passing a lambda to
4176 * an untyped function and we just assume every parameter has type
4177 * Tany.
4178 * Note: we should be using 'nothing' to type the arguments. *)
4179 Typing_log.increment_feature_count env FL.Lambda.untyped_context;
4180 check_body_under_known_params env declared_ft
4181 | Some ExpectedTy.{ ty = { et_type; _ }; _ }
4182 when TUtils.is_mixed env et_type || TUtils.is_dynamic env et_type ->
4183 (* If the expected type of a lambda is mixed or dynamic, we
4184 * decompose the expected type into a function type where the
4185 * undeclared parameters and the return type are set to the expected
4186 * type of lambda, i.e., mixed or dynamic.
4188 * For an expected mixed type, one could argue that the lambda
4189 * doesn't even need to be checked as it can't be called (there is
4190 * no downcast to function type). Thus, we should be using nothing
4191 * to type the arguments. But generally users are very confused by
4192 * the use of nothing and would expect the lambda body to be
4193 * checked as though it could be called.
4195 let replace_non_declared_type declared_ft_param =
4196 let is_undeclared =
4197 TUtils.is_any env declared_ft_param.fp_type.et_type
4199 if is_undeclared then
4200 let enforced_ty = { et_enforced = Unenforced; et_type } in
4201 { declared_ft_param with fp_type = enforced_ty }
4202 else
4203 declared_ft_param
4205 let expected_ft =
4206 let ft_params =
4207 List.map ~f:replace_non_declared_type declared_ft.ft_params
4209 { declared_ft with ft_params }
4211 let ret_ty = et_type in
4212 check_body_under_known_params env ~ret_ty expected_ft
4213 | Some _ ->
4214 (* If the expected type is something concrete but not a function
4215 * then we should reject in strict mode. Check body anyway.
4216 * Note: we should be using 'nothing' to type the arguments. *)
4217 if Partial.should_check_error (Env.get_mode env) 4224 then
4218 Errors.untyped_lambda_strict_mode p;
4219 Typing_log.increment_feature_count
4221 FL.Lambda.non_function_typed_context;
4222 check_body_under_known_params env declared_ft
4223 | None ->
4224 (* If we're in partial mode then type-check definition anyway,
4225 * so treating parameters without type hints as "untyped"
4227 if not (Env.is_strict env) then (
4228 Typing_log.increment_feature_count
4230 FL.Lambda.non_strict_unknown_params;
4231 check_body_under_known_params env declared_ft
4232 ) else (
4233 Typing_log.increment_feature_count
4235 FL.Lambda.fresh_tyvar_params;
4237 (* Replace uses of Tany that originated from "untyped" parameters or return type
4238 * with fresh type variables *)
4239 let freshen_ftype env ft =
4240 let freshen_ty env pos et =
4241 match get_node et.et_type with
4242 | Tany _ ->
4243 let (env, ty) = Env.fresh_type env pos in
4244 (env, { et with et_type = ty })
4245 | Tclass (id, e, [ty])
4246 when String.equal (snd id) SN.Classes.cAwaitable
4247 && is_any ty ->
4248 let (env, t) = Env.fresh_type env pos in
4249 ( env,
4251 et with
4252 et_type = mk (get_reason et.et_type, Tclass (id, e, [t]));
4254 | _ -> (env, et)
4256 let freshen_untyped_param env ft_param =
4257 let (env, fp_type) =
4258 freshen_ty
4260 (Pos_or_decl.unsafe_to_raw_pos ft_param.fp_pos)
4261 ft_param.fp_type
4263 (env, { ft_param with fp_type })
4265 let (env, ft_params) =
4266 List.map_env env ft.ft_params ~f:freshen_untyped_param
4268 let (env, ft_ret) = freshen_ty env f.f_span ft.ft_ret in
4269 (env, { ft with ft_params; ft_ret })
4271 let (env, declared_ft) = freshen_ftype env declared_ft in
4272 let env =
4273 Env.set_tyvar_variance env (mk (Reason.Rnone, Tfun declared_ft))
4275 (* TODO(jjwu): the declared_ft here is set to public,
4276 but is actually inferred from the surrounding context
4277 (don't think this matters in practice, since we check lambdas separately) *)
4278 check_body_under_known_params
4280 ~ret_ty:declared_ft.ft_ret.et_type
4281 declared_ft
4285 | Xml (sid, attrl, el) ->
4286 let cid = CI sid in
4287 let (env, _tal, _te, classes) =
4288 class_id_for_new ~exact:Nonexact p env cid []
4290 (* OK to ignore rest of list; class_info only used for errors, and
4291 * cid = CI sid cannot produce a union of classes anyhow *)
4292 let class_info =
4293 List.find_map classes ~f:(function
4294 | `Dynamic -> None
4295 | `Class (_, class_info, _) -> Some class_info)
4297 let (env, te, obj) =
4298 (* New statements derived from Xml literals are of the following form:
4300 * __construct(
4301 * darray<string,mixed> $attributes,
4302 * varray<mixed> $children,
4303 * string $file,
4304 * int $line
4305 * );
4307 let new_exp = Typing_xhp.rewrite_xml_into_new p sid attrl el in
4308 expr ?expected env new_exp
4310 let tchildren =
4311 match te with
4312 | ( _,
4315 ( _,
4319 (_, _, (Varray (_, children) | ValCollection (Vec, _, children)));
4324 _ ) ) ->
4325 (* Typing_xhp.rewrite_xml_into_new generates an AST node for a `varray[]` literal, which is interpreted as a vec[] *)
4326 children
4327 | _ ->
4328 (* We end up in this case when the cosntructed new expression does
4329 not typecheck. *)
4332 let (env, typed_attrs) = xhp_attribute_exprs env class_info attrl sid obj in
4333 let txml = Aast.Xml (sid, typed_attrs, tchildren) in
4334 (match class_info with
4335 | None -> make_result env p txml (mk (Reason.Runknown_class p, Tobject))
4336 | Some _ -> make_result env p txml obj)
4337 | Callconv (kind, e) ->
4338 let (env, te, ty) = expr env e in
4339 make_result env p (Aast.Callconv (kind, te)) ty
4340 | Shape fdm ->
4341 let (env, fdm_with_expected) =
4342 match expand_expected_and_get_node env expected with
4343 | (env, Some (pos, ur, _, Tshape (_, expected_fdm))) ->
4344 let fdme =
4345 List.map
4346 ~f:(fun (k, v) ->
4347 let tk = TShapeField.of_ast Pos_or_decl.of_raw_pos k in
4348 match TShapeMap.find_opt tk expected_fdm with
4349 | None -> (k, (v, None))
4350 | Some sft -> (k, (v, Some (ExpectedTy.make pos ur sft.sft_ty))))
4353 (env, fdme)
4354 | _ -> (env, List.map ~f:(fun (k, v) -> (k, (v, None))) fdm)
4356 (* allow_inter adds a type-variable *)
4357 let (env, tfdm) =
4358 List.map_env
4359 ~f:(fun env (key, (e, expected)) ->
4360 let (env, te, ty) = expr ?expected env e in
4361 (env, (key, (te, ty))))
4363 fdm_with_expected
4365 let (env, fdm) =
4366 let convert_expr_and_type_to_shape_field_type env (key, (_, ty)) =
4367 (* An expression evaluation always corresponds to a shape_field_type
4368 with sft_optional = false. *)
4369 (env, (key, { sft_optional = false; sft_ty = ty }))
4371 List.map_env ~f:convert_expr_and_type_to_shape_field_type env tfdm
4373 let fdm =
4374 List.fold_left
4375 ~f:(fun acc (k, v) ->
4376 let tk = TShapeField.of_ast Pos_or_decl.of_raw_pos k in
4377 TShapeMap.add tk v acc)
4378 ~init:TShapeMap.empty
4381 let env = check_shape_keys_validity env p (List.map tfdm ~f:fst) in
4382 (* Fields are fully known, because this shape is constructed
4383 * using shape keyword and we know exactly what fields are set. *)
4384 make_result
4387 (Aast.Shape (List.map ~f:(fun (k, (te, _)) -> (k, te)) tfdm))
4388 (mk (Reason.Rwitness p, Tshape (Closed_shape, fdm)))
4389 | ET_Splice e ->
4390 Typing_env.with_in_expr_tree env false (fun env -> et_splice env p e)
4391 | EnumClassLabel (None, s) ->
4392 Errors.enum_class_label_as_expr p;
4393 make_result
4396 (Aast.EnumClassLabel (None, s))
4397 (mk (Reason.Rwitness p, Terr))
4398 | EnumClassLabel ((Some (pos, cname) as e), name) ->
4399 let (env, res) =
4400 EnumClassLabelOps.expand
4403 ~full:true
4404 ~ctor:SN.Classes.cEnumClassLabel
4405 cname
4406 name
4408 let error () =
4409 make_result
4412 (Aast.EnumClassLabel (e, name))
4413 (mk (Reason.Rwitness p, Terr))
4415 (match res with
4416 | EnumClassLabelOps.Success ((_, _, texpr), lty) ->
4417 make_result env p texpr lty
4418 | EnumClassLabelOps.ClassNotFound ->
4419 (* Error registered in nast_check/unbound_name_check *)
4420 error ()
4421 | EnumClassLabelOps.LabelNotFound _ ->
4422 (* Error registered in EnumClassLabelOps.expand *)
4423 error ()
4424 | EnumClassLabelOps.Invalid
4425 | EnumClassLabelOps.Skip ->
4426 Errors.enum_class_label_as_expr p;
4427 error ())
4429 (* let ty = err_witness env cst_pos in *)
4430 and class_const ?(incl_tc = false) env p (cid, mid) =
4431 let (env, _tal, ce, cty) = class_expr env [] cid in
4432 let env =
4433 match get_node cty with
4434 | Tclass ((_, n), _, _)
4435 when Env.is_enum_class env n && String.(SN.Members.mClass <> snd mid) ->
4436 Typing_local_ops.enforce_enum_class_variant p env
4437 | _ -> env
4439 let (env, (const_ty, _tal)) =
4440 class_get
4441 ~is_method:false
4442 ~is_const:true
4443 ~incl_tc
4444 ~coerce_from_ty:None
4450 make_result env p (Aast.Class_const (ce, mid)) const_ty
4453 * Process a spread operator by computing the intersection of XHP attributes
4454 * between the spread expression and the XHP constructor onto which we're
4455 * spreading.
4457 and xhp_spread_attribute env c_onto valexpr sid obj =
4458 let (_, p, _) = valexpr in
4459 let (env, te, valty) = expr env valexpr ~allow_awaitable:(*?*) false in
4460 let (env, attr_ptys) =
4461 match c_onto with
4462 | None -> (env, [])
4463 | Some class_info -> Typing_xhp.get_spread_attributes env p class_info valty
4465 let (env, has_err) =
4466 List.fold_left
4467 attr_ptys
4468 ~f:(fun (env, has_err) attr ->
4469 let (env, _, err_opt) = xhp_attribute_decl_ty env sid obj attr in
4470 (env, has_err || Option.is_some err_opt))
4471 ~init:(env, false)
4473 (* If we have a subtyping error for any attribute, the best we can do here
4474 is give an expected type of dynamic *)
4475 let err_opt =
4476 if has_err then
4477 Some (valty, MakeType.nothing Reason.Rnone)
4478 else
4479 None
4481 (* Build the typed attribute node *)
4482 let typed_attr = Aast.Xhp_spread (hole_on_err ~err_opt te) in
4483 (env, typed_attr)
4486 * Simple XHP attributes (attr={expr} form) are simply interpreted as a member
4487 * variable prefixed with a colon.
4489 and xhp_simple_attribute env id valexpr sid obj =
4490 let (_, p, _) = valexpr in
4491 let (env, te, valty) = expr env valexpr ~allow_awaitable:(*?*) false in
4492 (* This converts the attribute name to a member name. *)
4493 let name = ":" ^ snd id in
4494 let attr_pty = ((fst id, name), (p, valty)) in
4495 let (env, decl_ty, err_opt) = xhp_attribute_decl_ty env sid obj attr_pty in
4496 let typed_attr =
4497 Aast.Xhp_simple
4498 { xs_name = id; xs_type = decl_ty; xs_expr = hole_on_err ~err_opt te }
4500 (env, typed_attr)
4503 * Typecheck the attribute expressions - this just checks that the expressions are
4504 * valid, not that they match the declared type for the attribute and,
4505 * in case of spreads, makes sure they are XHP.
4507 and xhp_attribute_exprs env cls_decl attrl sid obj =
4508 let handle_attr (env, typed_attrl) attr =
4509 let (env, typed_attr) =
4510 match attr with
4511 | Xhp_simple { xs_name = id; xs_expr = valexpr; _ } ->
4512 xhp_simple_attribute env id valexpr sid obj
4513 | Xhp_spread valexpr -> xhp_spread_attribute env cls_decl valexpr sid obj
4515 (env, typed_attr :: typed_attrl)
4517 let (env, typed_attrl) =
4518 List.fold_left ~f:handle_attr ~init:(env, []) attrl
4520 (env, List.rev typed_attrl)
4522 (*****************************************************************************)
4523 (* Anonymous functions & lambdas. *)
4524 (*****************************************************************************)
4525 and closure_bind_param params (env, t_params) ty : env * Tast.fun_param list =
4526 match !params with
4527 | [] ->
4528 (* This code cannot be executed normally, because the arity is wrong
4529 * and it will error later. Bind as many parameters as we can and carry
4530 * on. *)
4531 (env, t_params)
4532 | param :: paraml ->
4533 params := paraml;
4534 (match hint_of_type_hint param.param_type_hint with
4535 | Some h ->
4536 let (pos, _) = h in
4537 (* When creating a closure, the 'this' type will mean the
4538 * late bound type of the current enclosing class
4540 let (env, h) = Phase.localize_hint_no_subst env ~ignore_errors:false h in
4541 let env =
4542 Typing_coercion.coerce_type
4544 Reason.URparam
4547 (MakeType.unenforced h)
4548 Errors.unify_error
4550 (* Closures are allowed to have explicit type-hints. When
4551 * that is the case we should check that the argument passed
4552 * is compatible with the type-hint.
4553 * The body of the function should be type-checked with the
4554 * hint and not the type of the argument passed.
4555 * Otherwise it leads to strange results where
4556 * foo(?string $x = null) is called with a string and fails to
4557 * type-check. If $x is a string instead of ?string, null is not
4558 * subtype of string ...
4560 let (env, t_param) = bind_param env (h, param) in
4561 (env, t_params @ [t_param])
4562 | None ->
4563 let ty =
4564 mk (Reason.Rlambda_param (param.param_pos, get_reason ty), get_node ty)
4566 let (env, t_param) = bind_param env (ty, param) in
4567 (env, t_params @ [t_param]))
4569 and closure_bind_variadic env vparam variadic_ty =
4570 let (env, ty, pos) =
4571 match hint_of_type_hint vparam.param_type_hint with
4572 | None ->
4573 (* if the hint is missing, use the type we expect *)
4574 (env, variadic_ty, get_pos variadic_ty)
4575 | Some hint ->
4576 let pos = fst hint in
4577 let (env, h) =
4578 Phase.localize_hint_no_subst env ~ignore_errors:false hint
4580 let env =
4581 Typing_coercion.coerce_type
4583 Reason.URparam
4585 variadic_ty
4586 (MakeType.unenforced h)
4587 Errors.unify_error
4589 (env, h, Pos_or_decl.of_raw_pos vparam.param_pos)
4591 let r = Reason.Rvar_param_from_decl pos in
4592 let arr_values = mk (r, get_node ty) in
4593 let ty = MakeType.varray r arr_values in
4594 let (env, t_variadic) = bind_param env (ty, vparam) in
4595 (env, t_variadic)
4597 and closure_bind_opt_param env param : env =
4598 match param.param_expr with
4599 | None ->
4600 let ty = Typing_utils.mk_tany env param.param_pos in
4601 let (env, _) = bind_param env (ty, param) in
4603 | Some default ->
4604 let (env, _te, ty) = expr env default ~allow_awaitable:(*?*) false in
4605 Typing_sequencing.sequence_check_expr default;
4606 let (env, _) = bind_param env (ty, param) in
4609 (* Make a type-checking function for an anonymous function or lambda. *)
4610 (* Here ret_ty should include Awaitable wrapper *)
4611 (* TODO: ?el is never set; so we need to fix variadic use of lambda *)
4612 and closure_make
4613 ?el ?ret_ty ?(check_escapes = true) env lambda_pos f ft idl is_anon =
4614 let type_closure f =
4615 (* Wrap the function f so that it can freely clobber function-specific
4616 parts of the environment; the clobbered parts are restored before
4617 returning the result. Additionally, we also prevent type parameters
4618 created in the closure from unsoundly leaking into the environment
4619 of the enclosing function. *)
4620 let snap = Typing_escape.snapshot_env env in
4621 let (env, (escaping, (te, hret, ft))) =
4622 Env.closure env (fun env ->
4623 stash_conts_for_closure env lambda_pos is_anon idl (fun env ->
4624 let (env, res) = f env in
4625 let escaping = Typing_escape.escaping_from_snapshot snap env in
4626 (env, (escaping, res))))
4628 (* After the body of the function is checked, erase all the type parameters
4629 created from the env and the return type. *)
4630 let (env, hret) =
4631 if check_escapes then
4632 Typing_escape.refresh_env_and_type
4633 ~remove:escaping
4634 ~pos:lambda_pos
4636 hret
4637 else
4638 (env, hret)
4640 (env, (te, hret, ft))
4642 type_closure @@ fun env ->
4643 let nb = f.f_body in
4644 (* Extract capabilities from AAST and add them to the environment *)
4645 let (env, capability) =
4646 match (f.f_ctxs, f.f_unsafe_ctxs) with
4647 | (None, None) ->
4648 (* if the closure has no explicit coeffect annotations,
4649 do _not_ insert (unsafe) capabilities into the environment;
4650 instead, rely on the fact that a capability from an enclosing
4651 scope can simply be captured, which has the same semantics
4652 as redeclaring and shadowing with another same-typed capability.
4653 This avoid unnecessary overhead in the most common case, i.e.,
4654 when a closure does not need a different (usually smaller)
4655 set of capabilities. *)
4656 (env, Env.get_local env Typing_coeffects.local_capability_id)
4657 | (_, _) ->
4658 let (env, cap_ty, unsafe_cap_ty) =
4659 type_capability env f.f_ctxs f.f_unsafe_ctxs (fst f.f_name)
4661 let (env, _) =
4662 Typing_coeffects.register_capabilities env cap_ty unsafe_cap_ty
4664 (env, cap_ty)
4666 let ft = { ft with ft_implicit_params = { capability = CapTy capability } } in
4667 let env = Env.clear_params env in
4668 let make_variadic_arg env varg tyl =
4669 let remaining_types =
4670 (* It's possible the variadic arg will capture the variadic
4671 * parameter of the supplied arity (if arity is Fvariadic)
4672 * and additional supplied params.
4674 * For example in cases such as:
4675 * lambda1 = (int $a, string...$c) ==> {};
4676 * lambda1(1, "hello", ...$y); (where $y is a variadic string)
4677 * lambda1(1, "hello", "world");
4678 * then ...$c will contain "hello" and everything in $y in the first
4679 * example, and "hello" and "world" in the second example.
4681 * To account for a mismatch in arity, we take the remaining supplied
4682 * parameters and return a list of all their types. We'll use this
4683 * to create a union type when creating the typed variadic arg.
4685 let remaining_params = List.drop ft.ft_params (List.length f.f_params) in
4686 List.map ~f:(fun param -> param.fp_type.et_type) remaining_params
4688 let r = Reason.Rvar_param varg.param_pos in
4689 let union = Tunion (tyl @ remaining_types) in
4690 let (env, t_param) = closure_bind_variadic env varg (mk (r, union)) in
4691 (env, Aast.FVvariadicArg t_param)
4693 let (env, t_variadic) =
4694 match (f.f_variadic, ft.ft_arity) with
4695 | (FVvariadicArg arg, Fvariadic variadic) ->
4696 make_variadic_arg env arg [variadic.fp_type.et_type]
4697 | (FVvariadicArg arg, Fstandard) -> make_variadic_arg env arg []
4698 | (FVellipsis pos, _) -> (env, Aast.FVellipsis pos)
4699 | (_, _) -> (env, Aast.FVnonVariadic)
4701 let params = ref f.f_params in
4702 let (env, t_params) =
4703 List.fold_left
4704 ~f:(closure_bind_param params)
4705 ~init:(env, [])
4706 (List.map ft.ft_params ~f:(fun x -> x.fp_type.et_type))
4708 let env = List.fold_left ~f:closure_bind_opt_param ~init:env !params in
4709 let env = List.fold_left ~f:closure_check_param ~init:env f.f_params in
4710 let env =
4711 match el with
4712 | None ->
4713 (*iter2_shortest
4714 Unify.unify_param_modes
4715 ft.ft_params
4716 supplied_params; *)
4718 | Some x ->
4719 let var_param =
4720 match f.f_variadic with
4721 | FVellipsis pos ->
4722 let param =
4723 TUtils.default_fun_param
4724 ~pos:(Pos_or_decl.of_raw_pos pos)
4725 (mk (Reason.Rvar_param pos, Typing_defs.make_tany ()))
4727 Some param
4728 | _ -> None
4730 let rec iter l1 l2 =
4731 match (l1, l2, var_param) with
4732 | (_, [], _) -> ()
4733 | ([], _, None) -> ()
4734 | ([], x2 :: rl2, Some def1) ->
4735 param_modes ~is_variadic:true def1 x2;
4736 iter [] rl2
4737 | (x1 :: rl1, x2 :: rl2, _) ->
4738 param_modes x1 x2;
4739 iter rl1 rl2
4741 iter ft.ft_params x;
4742 wfold_left2 inout_write_back env ft.ft_params x
4744 let env = Env.set_fn_kind env f.f_fun_kind in
4745 let decl_ty =
4746 Option.map ~f:(Decl_hint.hint env.decl_env) (hint_of_type_hint f.f_ret)
4748 let ret_pos =
4749 match snd f.f_ret with
4750 | Some (ret_pos, _) -> ret_pos
4751 | None -> lambda_pos
4753 let (env, hret) =
4754 match decl_ty with
4755 | None ->
4756 (* Do we have a contextual return type? *)
4757 begin
4758 match ret_ty with
4759 | None -> Typing_return.make_fresh_return_type env ret_pos
4760 | Some ret_ty -> (env, ret_ty)
4762 | Some ret ->
4763 (* If a 'this' type appears it needs to be compatible with the
4764 * late static type
4766 let ety_env =
4767 empty_expand_env_with_on_error
4768 (Env.invalid_type_hint_assert_primary_pos_in_current_decl env)
4770 Typing_return.make_return_type (Phase.localize ~ety_env) env ret
4772 let (env, hret) =
4773 Typing_return.force_return_kind ~is_toplevel:false env ret_pos hret
4775 let ft = { ft with ft_ret = { ft.ft_ret with et_type = hret } } in
4776 let env =
4777 Env.set_return
4779 (Typing_return.make_info
4780 ret_pos
4781 f.f_fun_kind
4784 ~is_explicit:(Option.is_some ret_ty)
4785 hret
4786 decl_ty)
4788 let local_tpenv = Env.get_tpenv env in
4789 (* Outer pipe variables aren't available in closures. Note that
4790 * locals are restored by Env.closure after processing the closure
4792 let env =
4793 Env.unset_local env (Local_id.make_unscoped SN.SpecialIdents.dollardollar)
4795 let (env, tb) = block env nb.fb_ast in
4796 let has_implicit_return = LEnv.has_next env in
4797 let named_body_is_unsafe = Nast.named_body_is_unsafe nb in
4798 let env =
4799 if (not has_implicit_return) || Nast.named_body_is_unsafe nb then
4801 else
4802 fun_implicit_return env lambda_pos hret f.f_fun_kind
4804 let env =
4805 Typing_env.set_fun_tast_info
4807 { Tast.has_implicit_return; Tast.named_body_is_unsafe }
4809 let (env, tparams) = List.map_env env f.f_tparams ~f:type_param in
4810 let (env, user_attributes) =
4811 List.map_env env f.f_user_attributes ~f:user_attribute
4813 let tfun_ =
4815 Aast.f_annotation = Env.save local_tpenv env;
4816 Aast.f_readonly_this = f.f_readonly_this;
4817 Aast.f_span = f.f_span;
4818 Aast.f_ret = (hret, hint_of_type_hint f.f_ret);
4819 Aast.f_readonly_ret = f.f_readonly_ret;
4820 Aast.f_name = f.f_name;
4821 Aast.f_tparams = tparams;
4822 Aast.f_where_constraints = f.f_where_constraints;
4823 Aast.f_fun_kind = f.f_fun_kind;
4824 Aast.f_user_attributes = user_attributes;
4825 Aast.f_body = { Aast.fb_ast = tb; fb_annotation = () };
4826 Aast.f_ctxs = f.f_ctxs;
4827 Aast.f_unsafe_ctxs = f.f_unsafe_ctxs;
4828 Aast.f_params = t_params;
4829 Aast.f_variadic = t_variadic;
4830 (* TODO TAST: Variadic efuns *)
4831 Aast.f_external = f.f_external;
4832 Aast.f_doc_comment = f.f_doc_comment;
4835 let ty = mk (Reason.Rwitness lambda_pos, Tfun ft) in
4836 let te =
4837 Tast.make_typed_expr
4838 lambda_pos
4840 (if is_anon then
4841 Aast.Efun (tfun_, idl)
4842 else
4843 Aast.Lfun (tfun_, idl))
4845 let env = Env.set_tyvar_variance env ty in
4846 (env, (te, hret, ft))
4848 (*****************************************************************************)
4849 (* End of anonymous functions & lambdas. *)
4850 (*****************************************************************************)
4852 (*****************************************************************************)
4853 (* Expression trees *)
4854 (*****************************************************************************)
4855 and expression_tree env p et =
4856 let { et_hint; et_splices; et_virtualized_expr; et_runtime_expr } = et in
4858 (* Given the expression tree literal:
4860 MyVisitor`1 + ${ foo() }`
4862 First, type check the expressions that are spliced in, so foo() in
4863 this example. *)
4864 let (env, t_splices) = block env et_splices in
4866 (* Type check the virtualized expression, which will look
4867 roughly like this:
4869 function() {
4870 $0splice0 = foo();
4871 return MyVisitor::intType()->__plus($0splice0);
4874 let (env, t_virtualized_expr, ty_virtual) =
4875 Typing_env.with_in_expr_tree env true (fun env ->
4876 expr env et_virtualized_expr ~allow_awaitable:false)
4879 (* Given the runtime expression:
4881 MyVisitor::makeTree(...)
4883 add the inferred type as a type parameter:
4885 MyVisitor::makeTree<MyVisitorInt>(...)
4887 and then typecheck. *)
4888 let (env, runtime_expr) =
4889 maketree_with_type_param env p et_runtime_expr ty_virtual
4891 let (env, t_runtime_expr, ty_runtime_expr) =
4892 expr env runtime_expr ~allow_awaitable:false
4895 make_result
4898 (Aast.ExpressionTree
4900 et_hint;
4901 et_splices = t_splices;
4902 et_virtualized_expr = t_virtualized_expr;
4903 et_runtime_expr = t_runtime_expr;
4905 ty_runtime_expr
4907 and et_splice env p e =
4908 let (env, te, ty) = expr env e ~allow_awaitable:(*?*) false in
4909 let (env, ty_visitor) = Env.fresh_type env p in
4910 let (env, ty_res) = Env.fresh_type env p in
4911 let (env, ty_infer) = Env.fresh_type env p in
4912 let spliceable_type =
4913 MakeType.spliceable (Reason.Rsplice p) ty_visitor ty_res ty_infer
4915 let env = SubType.sub_type env ty spliceable_type (Errors.unify_error_at p) in
4916 make_result env p (Aast.ET_Splice te) ty_infer
4918 (*****************************************************************************)
4919 (* End expression trees *)
4920 (*****************************************************************************)
4921 and new_object
4922 ~(expected : ExpectedTy.t option)
4923 ~check_parent
4924 ~check_not_abstract
4925 ~is_using_clause
4929 explicit_targs
4931 unpacked_element =
4932 (* Obtain class info from the cid expression. We get multiple
4933 * results with a CIexpr that has a union type, e.g. in
4935 $classname = (mycond()? classname<A>: classname<B>);
4936 new $classname();
4938 let (env, tal, tcid, classes) =
4939 instantiable_cid ~exact:Exact p env cid explicit_targs
4941 let allow_abstract_bound_generic =
4942 match tcid with
4943 | (ty, _, Aast.CI (_, tn)) -> is_generic_equal_to tn ty
4944 | _ -> false
4946 let gather
4947 (env, _tel, _typed_unpack_element, should_forget_fakes_acc)
4948 (cname, class_info, c_ty) =
4950 check_not_abstract
4951 && Cls.abstract class_info
4952 && (not (requires_consistent_construct cid))
4953 && not allow_abstract_bound_generic
4954 then
4955 uninstantiable_error
4959 (Cls.pos class_info)
4960 (Cls.name class_info)
4962 c_ty;
4963 let (env, obj_ty_, params) =
4964 let (env, c_ty) = Env.expand_type env c_ty in
4965 match (cid, tal, get_class_type c_ty) with
4966 (* Explicit type arguments *)
4967 | (CI _, _ :: _, Some (_, _, tyl)) -> (env, get_node c_ty, tyl)
4968 | (_, _, class_type_opt) ->
4969 let (env, params) =
4970 List.map_env env (Cls.tparams class_info) ~f:(fun env tparam ->
4971 let (env, tvar) =
4972 Env.fresh_type_reason
4975 (Reason.Rtype_variable_generics
4976 (p, snd tparam.tp_name, strip_ns (snd cname)))
4978 Typing_log.log_new_tvar_for_new_object env p tvar cname tparam;
4979 (env, tvar))
4981 begin
4982 match class_type_opt with
4983 | Some (_, Exact, _) -> (env, Tclass (cname, Exact, params), params)
4984 | _ -> (env, Tclass (cname, Nonexact, params), params)
4988 (not check_parent)
4989 && (not is_using_clause)
4990 && Cls.is_disposable class_info
4991 then
4992 Errors.invalid_new_disposable p;
4993 let r_witness = Reason.Rwitness p in
4994 let obj_ty = mk (r_witness, obj_ty_) in
4995 let c_ty =
4996 match cid with
4997 | CIstatic
4998 | CIexpr _ ->
4999 mk (r_witness, get_node c_ty)
5000 | _ -> obj_ty
5002 let (env, new_ty) =
5003 let (cid_ty, _, _) = tcid in
5004 let (env, cid_ty) = Env.expand_type env cid_ty in
5005 if is_generic cid_ty then
5006 (env, cid_ty)
5007 else if check_parent then
5008 (env, c_ty)
5009 else
5010 ExprDepTy.make env ~cid c_ty
5012 (* Set variance according to type of `new` expression now. Lambda arguments
5013 * to the constructor might depend on it, and `call_construct` only uses
5014 * `ctor_fty` to set the variance which has void return type *)
5015 let env = Env.set_tyvar_variance env new_ty in
5016 let (env, tel, typed_unpack_element, ctor_fty, should_forget_fakes) =
5017 let env = check_expected_ty "New" env new_ty expected in
5018 call_construct p env class_info params el unpacked_element cid new_ty
5020 let should_forget_fakes_acc =
5021 should_forget_fakes_acc || should_forget_fakes
5023 (if equal_consistent_kind (snd (Cls.construct class_info)) Inconsistent then
5024 match cid with
5025 | CIstatic -> Errors.new_inconsistent_construct p cname `static
5026 | CIexpr _ -> Errors.new_inconsistent_construct p cname `classname
5027 | _ -> ());
5028 match cid with
5029 | CIparent ->
5030 let (env, ctor_fty) =
5031 match fst (Cls.construct class_info) with
5032 | Some ({ ce_type = (lazy ty); _ } as ce) ->
5033 let ety_env =
5035 empty_expand_env with
5036 substs =
5037 TUtils.make_locl_subst_for_class_tparams class_info params;
5038 this_ty = obj_ty;
5041 if get_ce_abstract ce then
5042 Errors.parent_abstract_call
5043 SN.Members.__construct
5045 (get_pos ctor_fty);
5046 let (env, ctor_fty) = Phase.localize ~ety_env env ty in
5047 (env, ctor_fty)
5048 | None -> (env, ctor_fty)
5050 ( (env, tel, typed_unpack_element, should_forget_fakes_acc),
5051 (obj_ty, ctor_fty) )
5052 | CIstatic
5053 | CI _
5054 | CIself ->
5055 ( (env, tel, typed_unpack_element, should_forget_fakes_acc),
5056 (c_ty, ctor_fty) )
5057 | CIexpr _ ->
5058 (* When constructing from a (classname) variable, the variable
5059 * dictates what the constructed object is going to be. This allows
5060 * for generic and dependent types to be correctly carried
5061 * through the 'new $foo()' iff the constructed obj_ty is a
5062 * supertype of the variable-dictated c_ty *)
5063 let env =
5064 Typing_ops.sub_type p Reason.URnone env c_ty obj_ty Errors.unify_error
5066 ( (env, tel, typed_unpack_element, should_forget_fakes_acc),
5067 (c_ty, ctor_fty) )
5069 let (had_dynamic, classes) =
5070 List.fold classes ~init:(false, []) ~f:(fun (seen_dynamic, classes) -> function
5071 | `Dynamic -> (true, classes)
5072 | `Class (cname, class_info, c_ty) ->
5073 (seen_dynamic, (cname, class_info, c_ty) :: classes))
5075 let ( (env, tel, typed_unpack_element, should_forget_fakes),
5076 class_types_and_ctor_types ) =
5077 List.fold_map classes ~init:(env, [], None, false) ~f:gather
5079 let class_types_and_ctor_types =
5080 let r = Reason.Rdynamic_construct p in
5081 let dyn = (mk (r, Tdynamic), mk (r, Tdynamic)) in
5082 if had_dynamic then
5083 dyn :: class_types_and_ctor_types
5084 else
5085 class_types_and_ctor_types
5087 let (env, tel, typed_unpack_element, ty, ctor_fty) =
5088 match class_types_and_ctor_types with
5089 | [] ->
5090 let (env, tel, _) = exprs env el ~allow_awaitable:(*?*) false in
5091 let (env, typed_unpack_element, _) =
5092 match unpacked_element with
5093 | None -> (env, None, MakeType.nothing Reason.Rnone)
5094 | Some unpacked_element ->
5095 let (env, e, ty) =
5096 expr env unpacked_element ~allow_awaitable:(*?*) false
5098 (env, Some e, ty)
5100 let r = Reason.Runknown_class p in
5101 (env, tel, typed_unpack_element, mk (r, Tobject), TUtils.terr env r)
5102 | [(ty, ctor_fty)] -> (env, tel, typed_unpack_element, ty, ctor_fty)
5103 | l ->
5104 let (tyl, ctyl) = List.unzip l in
5105 let r = Reason.Rwitness p in
5106 (env, tel, typed_unpack_element, mk (r, Tunion tyl), mk (r, Tunion ctyl))
5108 let (env, new_ty) =
5109 let (cid_ty, _, _) = tcid in
5110 let (env, cid_ty) = Env.expand_type env cid_ty in
5111 if is_generic cid_ty then
5112 (env, cid_ty)
5113 else if check_parent then
5114 (env, ty)
5115 else
5116 ExprDepTy.make env ~cid ty
5118 ( env,
5119 tcid,
5120 tal,
5121 tel,
5122 typed_unpack_element,
5123 new_ty,
5124 ctor_fty,
5125 should_forget_fakes )
5127 and attributes_check_def env kind attrs =
5128 (* TODO(coeffects) change to mixed after changing those constructors to pure *)
5129 let defaults = MakeType.default_capability Pos_or_decl.none in
5130 let (env, _) =
5131 Typing_lenv.stash_and_do env (Env.all_continuations env) (fun env ->
5132 let env =
5133 fst @@ Typing_coeffects.register_capabilities env defaults defaults
5135 (Typing_attributes.check_def env new_object kind attrs, ()))
5139 (** Get class infos for a class expression (e.g. `parent`, `self` or
5140 regular classnames) - which might resolve to a union or intersection
5141 of classes - and check they are instantiable.
5143 FIXME: we need to separate our instantiability into two parts. Currently,
5144 all this function is doing is checking if a given type is inhabited --
5145 that is, whether there are runtime values of type Aast. However,
5146 instantiability should be the stricter notion that T has a runtime
5147 constructor; that is, `new T()` should be valid. In particular, interfaces
5148 are inhabited, but not instantiable.
5149 To make this work with classname, we likely need to add something like
5150 concrete_classname<T>, where T cannot be an interface. *)
5151 and instantiable_cid ?(exact = Nonexact) p env cid explicit_targs :
5152 newable_class_info =
5153 let (env, tal, te, classes) =
5154 class_id_for_new ~exact p env cid explicit_targs
5156 List.iter classes ~f:(function
5157 | `Dynamic -> ()
5158 | `Class ((pos, name), class_info, c_ty) ->
5159 let pos = Pos_or_decl.unsafe_to_raw_pos pos in
5161 Ast_defs.is_c_trait (Cls.kind class_info)
5162 || Ast_defs.is_c_enum (Cls.kind class_info)
5163 then
5164 match cid with
5165 | CIexpr _
5166 | CI _ ->
5167 uninstantiable_error env p cid (Cls.pos class_info) name pos c_ty
5168 | CIstatic
5169 | CIparent
5170 | CIself ->
5172 else if
5173 Ast_defs.is_c_abstract (Cls.kind class_info) && Cls.final class_info
5174 then
5175 uninstantiable_error env p cid (Cls.pos class_info) name pos c_ty
5176 else
5177 ());
5178 (env, tal, te, classes)
5180 and check_shape_keys_validity :
5181 env -> pos -> Ast_defs.shape_field_name list -> env =
5182 fun env pos keys ->
5183 (* If the key is a class constant, get its class name and type. *)
5184 let get_field_info env key =
5185 let key_pos = shape_field_pos key in
5186 (* Empty strings or literals that start with numbers are not
5187 permitted as shape field names. *)
5188 match key with
5189 | Ast_defs.SFlit_int _ -> (env, key_pos, None)
5190 | Ast_defs.SFlit_str (_, key_name) ->
5191 if Int.equal 0 (String.length key_name) then
5192 Errors.invalid_shape_field_name_empty key_pos;
5193 (env, key_pos, None)
5194 | Ast_defs.SFclass_const (((p, cls) as x), y) ->
5195 let (env, _te, ty) = class_const env pos (((), p, CI x), y) in
5196 let r = Reason.Rwitness key_pos in
5197 let env =
5198 Type.sub_type
5199 key_pos
5200 Reason.URnone
5203 (MakeType.arraykey r)
5204 (fun ?code:_ _ _ ->
5205 Errors.invalid_shape_field_type
5206 key_pos
5207 (get_pos ty)
5208 (Typing_print.error env ty)
5211 (env, key_pos, Some (cls, ty))
5213 let check_field witness_pos witness_info env key =
5214 let (env, key_pos, key_info) = get_field_info env key in
5215 match (witness_info, key_info) with
5216 | (Some _, None) ->
5217 Errors.invalid_shape_field_literal key_pos witness_pos;
5219 | (None, Some _) ->
5220 Errors.invalid_shape_field_const key_pos witness_pos;
5222 | (None, None) -> env
5223 | (Some (cls1, ty1), Some (cls2, ty2)) ->
5224 if String.( <> ) cls1 cls2 then
5225 Errors.shape_field_class_mismatch
5226 key_pos
5227 witness_pos
5228 (strip_ns cls2)
5229 (strip_ns cls1);
5232 (Typing_solver.is_sub_type env ty1 ty2
5233 && Typing_solver.is_sub_type env ty2 ty1)
5234 then
5235 Errors.shape_field_type_mismatch
5236 key_pos
5237 witness_pos
5238 (Typing_print.error env ty2)
5239 (Typing_print.error env ty1);
5242 (* Sort the keys by their positions since the error messages will make
5243 * more sense if we take the one that appears first as canonical and if
5244 * they are processed in source order. *)
5245 let cmp_keys x y = Pos.compare (shape_field_pos x) (shape_field_pos y) in
5246 let keys = List.sort ~compare:cmp_keys keys in
5247 match keys with
5248 | [] -> env
5249 | witness :: rest_keys ->
5250 let (env, pos, info) = get_field_info env witness in
5251 List.fold_left ~f:(check_field pos info) ~init:env rest_keys
5253 (* Deal with assignment of a value of type ty2 to lvalue e1 *)
5254 and assign p env e1 pos2 ty2 =
5255 error_if_assign_in_pipe p env;
5256 assign_with_subtype_err_ p Reason.URassign env e1 pos2 ty2
5258 and assign_ p ur env e1 pos2 ty2 =
5259 let (env, te, ty, _err) = assign_with_subtype_err_ p ur env e1 pos2 ty2 in
5260 (env, te, ty)
5262 and assign_with_subtype_err_ p ur env (e1 : Nast.expr) pos2 ty2 =
5263 match e1 with
5264 | (_, _, Hole (e, _, _, _)) -> assign_with_subtype_err_ p ur env e pos2 ty2
5265 | _ ->
5266 let allow_awaitable = (*?*) false in
5267 let env =
5268 match e1 with
5269 | (_, _, Lvar (_, x)) ->
5270 Env.forget_prefixed_members env x Reason.(Blame (p, BSassignment))
5271 (* If we ever extend fake members from $x->a to more complicated lvalues
5272 such as $x->a->b, we would need to call forget_prefixed_members on
5273 other lvalues as well. *)
5274 | (_, _, Obj_get (_, (_, _, Id (_, property)), _, _)) ->
5275 Env.forget_suffixed_members
5277 property
5278 Reason.(Blame (p, BSassignment))
5279 | _ -> env
5281 (match e1 with
5282 | (_, _, Lvar ((_, x) as id)) ->
5283 let env = set_valid_rvalue p env x ty2 in
5284 let (_, p1, _) = e1 in
5285 let (env, te, ty) = make_result env p1 (Aast.Lvar id) ty2 in
5286 (env, te, ty, None)
5287 | (_, _, Lplaceholder id) ->
5288 let placeholder_ty = MakeType.void (Reason.Rplaceholder p) in
5289 let (_, p1, _) = e1 in
5290 let (env, te, ty) =
5291 make_result env p1 (Aast.Lplaceholder id) placeholder_ty
5293 (env, te, ty, None)
5294 | (_, _, List el) ->
5295 (* Generate fresh types for each lhs list element, then subtype against
5296 rhs type *)
5297 let (env, tyl) =
5298 List.map_env env el ~f:(fun env (_, p, _e) -> Env.fresh_type env p)
5300 let (_, p1, _) = e1 in
5301 let destructure_ty =
5302 MakeType.list_destructure (Reason.Rdestructure p1) tyl
5304 let lty2 = LoclType ty2 in
5305 let assign_accumulate (env, tel, errs) (lvalue : Nast.expr) ty2 =
5306 let (env, te, _, err_opt) = assign p env lvalue pos2 ty2 in
5307 (env, te :: tel, err_opt :: errs)
5309 let type_list_elem env =
5310 let (env, reversed_tel, rev_subtype_errs) =
5311 List.fold2_exn el tyl ~init:(env, [], []) ~f:assign_accumulate
5313 let (_, p1, _) = e1 in
5314 let (env, te, ty) =
5315 make_result env p1 (Aast.List (List.rev reversed_tel)) ty2
5317 (env, te, ty, List.rev rev_subtype_errs)
5320 (* Here we attempt to unify the type of the rhs we assigning with
5321 a number of fresh tyvars corresponding to the arity of the lhs `list`
5323 if we have a failure in subtyping the fresh tyvars in `destructure_ty`,
5324 we have a rhs which cannot be destructured to the variables on the lhs;
5325 e.g. `list($x,$y) = 2` or `list($x,$y) = tuple (1,2,3)`
5327 in the error case, we add a `Hole` with expected type `nothing` since
5328 there is no type we can suggest was expected
5330 in the ok case were the destrucutring succeeded, the fresh vars
5331 now have types so we can subtype each element, accumulate the errors
5332 and pack back into the rhs structure as our expected type *)
5333 Result.fold
5334 ~ok:(fun env ->
5335 let (env, te, ty, subty_errs) = type_list_elem env in
5336 let err_opt =
5337 if List.for_all subty_errs ~f:Option.is_none then
5338 None
5339 else
5340 Some (ty2, pack_errs pos2 ty2 (subty_errs, None))
5342 (env, te, ty, err_opt))
5343 ~error:(fun env ->
5344 let (env, te, ty, _) = type_list_elem env in
5345 let nothing =
5346 MakeType.nothing @@ Reason.Rsolve_fail (Pos_or_decl.of_raw_pos pos2)
5348 (env, te, ty, Some (ty2, nothing)))
5349 @@ Result.map ~f:(fun env -> Env.set_tyvar_variance_i env destructure_ty)
5350 @@ Type.sub_type_i_res p ur env lty2 destructure_ty Errors.unify_error
5351 | ( _,
5352 pobj,
5353 Obj_get (obj, (_, pm, Id ((_, member_name) as m)), nullflavor, in_parens)
5354 ) ->
5355 let lenv = env.lenv in
5356 let nullsafe =
5357 match nullflavor with
5358 | OG_nullthrows -> None
5359 | OG_nullsafe -> Some (Reason.Rnullsafe_op pobj)
5361 let (env, tobj, obj_ty) =
5362 expr ~accept_using_var:true env obj ~allow_awaitable
5364 let env = might_throw env in
5365 let (_, p1, _) = obj in
5366 let (env, (declared_ty, _tal), err_opt) =
5367 TOG.obj_get_with_err
5368 ~obj_pos:p1
5369 ~is_method:false
5370 ~nullsafe
5371 ~inst_meth:false
5372 ~meth_caller:false
5373 ~coerce_from_ty:(Some (p, ur, ty2))
5374 ~explicit_targs:[]
5375 ~class_id:(CIexpr e1)
5376 ~member_id:m
5377 ~on_error:Errors.unify_error
5379 obj_ty
5381 let te1 =
5382 Tast.make_typed_expr
5383 pobj
5384 declared_ty
5385 (Aast.Obj_get
5386 ( tobj,
5387 Tast.make_typed_expr pm declared_ty (Aast.Id m),
5388 nullflavor,
5389 in_parens ))
5391 let env = { env with lenv } in
5392 begin
5393 match obj with
5394 | (_, _, This)
5395 | (_, _, Lvar _) ->
5396 let (env, local) = Env.FakeMembers.make env obj member_name p in
5397 let (env, refined_ty) =
5398 Inter.intersect env ~r:(Reason.Rwitness p) declared_ty ty2
5400 let env = set_valid_rvalue p env local refined_ty in
5401 (env, te1, ty2, err_opt)
5402 | _ -> (env, te1, ty2, err_opt)
5404 | (_, _, Obj_get _) ->
5405 let lenv = env.lenv in
5406 let no_fakes = LEnv.env_with_empty_fakes env in
5407 let (env, te1, real_type) = lvalue no_fakes e1 in
5408 let (env, exp_real_type) = Env.expand_type env real_type in
5409 let env = { env with lenv } in
5410 let (env, err_opt) =
5411 Result.fold
5412 ~ok:(fun env -> (env, None))
5413 ~error:(fun env -> (env, Some (ty2, exp_real_type)))
5414 @@ Typing_coercion.coerce_type_res
5419 (MakeType.unenforced exp_real_type)
5420 Errors.unify_error
5422 (env, te1, ty2, err_opt)
5423 | (_, _, Class_get (_, CGexpr _, _)) ->
5424 failwith "AST should not have any CGexprs after naming"
5425 | (_, _, Class_get (((_, _, x) as cid), CGstring (pos_member, y), _)) ->
5426 let lenv = env.lenv in
5427 let no_fakes = LEnv.env_with_empty_fakes env in
5428 let (env, te1, _) = lvalue no_fakes e1 in
5429 let env = { env with lenv } in
5430 let (env, ety2) = Env.expand_type env ty2 in
5431 (* This defers the coercion check to class_get, which looks up the appropriate target type *)
5432 let (env, _tal, _, cty) = class_expr env [] cid in
5433 let env = might_throw env in
5434 let (env, (declared_ty, _), err_opt) =
5435 class_get_err
5436 ~is_method:false
5437 ~is_const:false
5438 ~coerce_from_ty:(Some (p, ur, ety2))
5441 (pos_member, y)
5444 let (env, local) = Env.FakeMembers.make_static env x y p in
5445 let (env, refined_ty) =
5446 Inter.intersect env ~r:(Reason.Rwitness p) declared_ty ty2
5448 let env = set_valid_rvalue p env local refined_ty in
5449 (env, te1, ty2, err_opt)
5450 | (_, pos, Array_get (e1, None)) ->
5451 let (env, te1, ty1) = update_array_type pos env e1 `lvalue in
5452 let (_, p1, _) = e1 in
5453 let (env, ty1', err_opt) =
5454 Typing_array_access.assign_array_append_with_err
5455 ~array_pos:p1
5456 ~expr_pos:p
5462 let (env, te1) =
5463 if is_hack_collection env ty1 then
5464 (env, te1)
5465 else
5466 let (env, te1, _, _) = assign_with_subtype_err_ p ur env e1 p1 ty1' in
5467 (env, te1)
5469 let (env, te, ty) =
5470 make_result env pos (Aast.Array_get (te1, None)) ty2
5472 (env, te, ty, err_opt)
5473 | (_, pos, Array_get (e1, Some e)) ->
5474 let (env, te1, ty1) = update_array_type pos env e1 `lvalue in
5475 let (env, te, ty) = expr env e ~allow_awaitable in
5476 let env = might_throw env in
5477 let (_, p1, _) = e1 in
5478 let (env, ty1', key_err_opt, err_opt) =
5479 Typing_array_access.assign_array_get_with_err
5480 ~array_pos:p1
5481 ~expr_pos:p
5489 let (env, te1) =
5490 if is_hack_collection env ty1 then
5491 (env, te1)
5492 else
5493 let (env, te1, _, _) = assign_with_subtype_err_ p ur env e1 p1 ty1' in
5494 (env, te1)
5496 ( env,
5497 ( ty2,
5498 pos,
5499 Aast.Array_get (te1, Some (hole_on_err ~err_opt:key_err_opt te)) ),
5500 ty2,
5501 err_opt )
5502 | _ -> assign_simple p ur env e1 ty2)
5504 and assign_simple pos ur env e1 ty2 =
5505 let (env, te1, ty1) = lvalue env e1 in
5506 let (env, err_opt) =
5507 Result.fold
5508 ~ok:(fun env -> (env, None))
5509 ~error:(fun env -> (env, Some (ty2, ty1)))
5510 @@ Typing_coercion.coerce_type_res
5515 (MakeType.unenforced ty1)
5516 Errors.unify_error
5518 (env, te1, ty2, err_opt)
5520 and array_field env ~allow_awaitable = function
5521 | AFvalue ve ->
5522 let (env, tve, tv) = expr env ve ~allow_awaitable in
5523 (env, (Aast.AFvalue tve, None, tv))
5524 | AFkvalue (ke, ve) ->
5525 let (env, tke, tk) = expr env ke ~allow_awaitable in
5526 let (env, tve, tv) = expr env ve ~allow_awaitable in
5527 (env, (Aast.AFkvalue (tke, tve), Some tk, tv))
5529 and array_value ~(expected : ExpectedTy.t option) env x =
5530 let (env, te, ty) = expr ?expected env x ~allow_awaitable:(*?*) false in
5531 (env, (te, ty))
5533 and arraykey_value
5534 p class_name is_set ~(expected : ExpectedTy.t option) env ((_, pos, _) as x)
5536 let (env, (te, ty)) = array_value ~expected env x in
5537 let (ty_arraykey, reason) =
5538 if is_set then
5539 ( MakeType.arraykey (Reason.Rset_element pos),
5540 Reason.set_element class_name )
5541 else
5542 (MakeType.arraykey (Reason.Ridx_dict pos), Reason.index_class class_name)
5544 let (env, err_opt) =
5545 Result.fold
5546 ~ok:(fun env -> (env, None))
5547 ~error:(fun env -> (env, Some (ty, ty_arraykey)))
5548 @@ Typing_coercion.coerce_type_res
5550 reason
5553 { et_type = ty_arraykey; et_enforced = Enforced }
5554 Errors.unify_error
5556 (env, (hole_on_err ~err_opt te, ty))
5558 and check_parent_construct pos env el unpacked_element env_parent =
5559 let check_not_abstract = false in
5560 let (env, env_parent) =
5561 Phase.localize_no_subst env ~ignore_errors:true env_parent
5563 let ( env,
5564 _tcid,
5565 _tal,
5566 tel,
5567 typed_unpack_element,
5568 parent,
5569 fty,
5570 should_forget_fakes ) =
5571 new_object
5572 ~expected:None
5573 ~check_parent:true
5574 ~check_not_abstract
5575 ~is_using_clause:false
5578 CIparent
5581 unpacked_element
5583 (* Not sure why we need to equate these types *)
5584 let env =
5585 Type.sub_type pos Reason.URnone env env_parent parent Errors.unify_error
5587 let env =
5588 Type.sub_type pos Reason.URnone env parent env_parent Errors.unify_error
5590 ( env,
5591 tel,
5592 typed_unpack_element,
5593 MakeType.void (Reason.Rwitness pos),
5594 parent,
5595 fty,
5596 should_forget_fakes )
5598 and call_parent_construct pos env el unpacked_element =
5599 match Env.get_parent_ty env with
5600 | Some parent -> check_parent_construct pos env el unpacked_element parent
5601 | None ->
5602 (* continue here *)
5603 let ty = Typing_utils.mk_tany env pos in
5604 let should_invalidate_fake_members = true in
5605 let default = (env, [], None, ty, ty, ty, should_invalidate_fake_members) in
5606 (match Env.get_self_id env with
5607 | Some self ->
5608 (match Env.get_class env self with
5609 | Some trait when Ast_defs.is_c_trait (Cls.kind trait) ->
5610 (match trait_most_concrete_req_class trait env with
5611 | None ->
5612 Errors.parent_in_trait pos;
5613 default
5614 | Some (_, parent_ty) ->
5615 check_parent_construct pos env el unpacked_element parent_ty)
5616 | Some self_tc ->
5617 if not (Cls.members_fully_known self_tc) then
5619 (* Don't know the hierarchy, assume it's correct *)
5620 else
5621 Errors.undefined_parent pos;
5622 default
5623 | None -> assert false)
5624 | None ->
5625 Errors.parent_outside_class pos;
5626 let ty = err_witness env pos in
5627 (env, [], None, ty, ty, ty, should_invalidate_fake_members))
5629 (* Depending on the kind of expression we are dealing with
5630 * The typing of call is different.
5632 and dispatch_call
5633 ~(expected : ExpectedTy.t option)
5634 ~is_using_clause
5635 ?in_await
5638 ((_, fpos, fun_expr) as e : Nast.expr)
5639 explicit_targs
5641 unpacked_element =
5642 let expr = expr ~allow_awaitable:(*?*) false in
5643 let exprs = exprs ~allow_awaitable:(*?*) false in
5644 let make_call env te tal tel typed_unpack_element ty =
5645 make_result env p (Aast.Call (te, tal, tel, typed_unpack_element)) ty
5647 (* TODO: Avoid Tany annotations in TAST by eliminating `make_call_special` *)
5648 let make_call_special env id tel ty =
5649 make_call
5651 (Tast.make_typed_expr fpos (TUtils.mk_tany env fpos) (Aast.Id id))
5654 None
5657 (* For special functions and pseudofunctions with a definition in an HHI
5658 * file. It is preferred over [make_call_special] because it does not generate
5659 * [TAny] for the function type of the call.
5661 let make_call_special_from_def env id tel ty_ =
5662 let (env, fty, tal) = fun_type_of_id env id explicit_targs el in
5663 let ty =
5664 match get_node fty with
5665 | Tfun ft -> ft.ft_ret.et_type
5666 | _ -> ty_ (Reason.Rwitness p)
5668 make_call env (Tast.make_typed_expr fpos fty (Aast.Id id)) tal tel None ty
5670 let overload_function = overload_function make_call fpos in
5671 (* Require [get_idisposable_value()] function calls to be inside a [using]
5672 statement. *)
5673 let check_disposable_in_return env fty =
5674 if is_return_disposable_fun_type env fty && not is_using_clause then
5675 Errors.invalid_new_disposable p
5678 let dispatch_id env id =
5679 let (env, fty, tal) = fun_type_of_id env id explicit_targs el in
5680 check_disposable_in_return env fty;
5681 let (env, (tel, typed_unpack_element, ty, should_forget_fakes)) =
5682 call ~expected p env fty el unpacked_element
5684 let result =
5685 make_call
5687 (Tast.make_typed_expr fpos fty (Aast.Id id))
5690 typed_unpack_element
5693 (result, should_forget_fakes)
5695 let dispatch_class_const env ((_, pos, e1_) as e1) m =
5696 let (env, _tal, tcid, ty1) = class_expr env [] e1 in
5697 let this_ty = MakeType.this (Reason.Rwitness fpos) in
5698 (* In static context, you can only call parent::foo() on static methods.
5699 * In instance context, you can call parent:foo() on static
5700 * methods as well as instance methods
5702 let is_static =
5703 (not (Nast.equal_class_id_ e1_ CIparent))
5704 || Env.is_static env
5705 || class_contains_smethod env ty1 m
5707 let (env, (fty, tal)) =
5708 if not is_static then
5709 (* parent::nonStaticFunc() is really weird. It's calling a method
5710 * defined on the parent class, but $this is still the child class.
5712 TOG.obj_get
5713 ~inst_meth:false
5714 ~meth_caller:false
5715 ~is_method:true
5716 ~nullsafe:None
5717 ~obj_pos:pos
5718 ~coerce_from_ty:None
5719 ~explicit_targs:[]
5720 ~class_id:e1_
5721 ~member_id:m
5722 ~on_error:Errors.unify_error
5723 ~parent_ty:ty1
5725 this_ty
5726 else
5727 class_get
5728 ~coerce_from_ty:None
5729 ~is_method:true
5730 ~is_const:false
5731 ~explicit_targs
5737 check_disposable_in_return env fty;
5738 let (env, (tel, typed_unpack_element, ty, should_forget_fakes)) =
5739 call ~expected p env fty el unpacked_element
5741 let result =
5742 make_call
5744 (Tast.make_typed_expr fpos fty (Aast.Class_const (tcid, m)))
5747 typed_unpack_element
5750 (result, should_forget_fakes)
5752 match fun_expr with
5753 (* Special top-level function *)
5754 | Id ((pos, x) as id) when SN.StdlibFunctions.needs_special_dispatch x ->
5755 begin
5756 match x with
5757 (* Special function [echo]. *)
5758 | echo when String.equal echo SN.SpecialFunctions.echo ->
5759 (* TODO(tany): TODO(T92020097):
5760 * Add [function print(arraykey ...$args)[io]: void] to an HHI file and
5761 * remove special casing of [echo] and [print].
5763 let env = Typing_local_ops.enforce_io pos env in
5764 let (env, tel, _) = exprs ~accept_using_var:true env el in
5765 let arraykey_ty = MakeType.arraykey (Reason.Rwitness pos) in
5766 let env =
5767 List.fold tel ~init:env ~f:(fun env (ty, pos, _) ->
5768 SubType.sub_type
5771 arraykey_ty
5772 (Errors.invalid_echo_argument_at pos))
5774 let should_forget_fakes = false in
5775 ( make_call_special env id tel (MakeType.void (Reason.Rwitness pos)),
5776 should_forget_fakes )
5777 (* `unsafe_cast` *)
5778 | unsafe_cast when String.equal unsafe_cast SN.PseudoFunctions.unsafe_cast
5780 let result =
5782 Int.(List.length el = 1)
5783 && TypecheckerOptions.ignore_unsafe_cast (Env.get_tcopt env)
5784 then
5785 let original_expr = List.hd_exn el in
5786 expr env original_expr
5787 else (
5788 Errors.unsafe_cast p;
5789 (* first type the `unsafe_cast` as a call, handling arity errors *)
5790 let (env, fty, tal) = fun_type_of_id env id explicit_targs el in
5791 check_disposable_in_return env fty;
5792 let (env, (tel, _, ty, _should_forget_fakes)) =
5793 call ~expected p env fty el unpacked_element
5795 (* construct the `Hole` using default value and type arguments
5796 if necessary *)
5797 let dflt_ty = MakeType.err Reason.none in
5798 let el =
5799 Option.value
5800 (List.hd tel)
5801 ~default:(Tast.make_typed_expr fpos dflt_ty Aast.Null)
5802 and (ty_from, ty_to) =
5803 match tal with
5804 | (ty_from, _) :: (ty_to, _) :: _ -> (ty_from, ty_to)
5805 | (ty, _) :: _ -> (ty, ty)
5806 | _ -> (dflt_ty, dflt_ty)
5808 let te =
5809 Aast.Hole
5810 (el, ty_from, ty_to, UnsafeCast (List.map ~f:snd explicit_targs))
5812 make_result env p te ty
5815 let should_forget_fakes = false in
5816 (result, should_forget_fakes)
5817 (* Special function `isset` *)
5818 | isset when String.equal isset SN.PseudoFunctions.isset ->
5819 let (env, tel, _) =
5820 exprs ~accept_using_var:true ~check_defined:false env el
5822 if Option.is_some unpacked_element then
5823 Errors.unpacking_disallowed_builtin_function p isset;
5824 let should_forget_fakes = false in
5825 let result = make_call_special_from_def env id tel MakeType.bool in
5826 (result, should_forget_fakes)
5827 (* Special function `unset` *)
5828 | unset when String.equal unset SN.PseudoFunctions.unset ->
5829 let (env, tel, _) = exprs env el in
5830 if Option.is_some unpacked_element then
5831 Errors.unpacking_disallowed_builtin_function p unset;
5832 let env = Typing_local_ops.check_unset_target env tel in
5833 let checked_unset_error =
5834 if Partial.should_check_error (Env.get_mode env) 4135 then
5835 Errors.unset_nonidx_in_strict
5836 else
5837 fun _ _ ->
5840 let env =
5841 match (el, unpacked_element) with
5842 | ([(_, _, Array_get ((_, _, Class_const _), Some _))], None)
5843 when Partial.should_check_error (Env.get_mode env) 4011 ->
5844 Errors.const_mutation p Pos_or_decl.none "";
5846 | ([(_, _, Array_get (ea, Some _))], None) ->
5847 let (env, _te, ty) = expr env ea in
5848 let r = Reason.Rwitness p in
5849 let tmixed = MakeType.mixed r in
5850 let super =
5852 ( Reason.Rnone,
5853 Tunion
5855 MakeType.dynamic r;
5856 MakeType.dict r tmixed tmixed;
5857 MakeType.keyset r tmixed;
5858 MakeType.darray r tmixed tmixed;
5861 SubType.sub_type_or_fail env ty super (fun () ->
5862 checked_unset_error
5864 (Reason.to_string
5865 ("This is "
5866 ^ Typing_print.error ~ignore_dynamic:true env ty)
5867 (get_reason ty)))
5868 | _ ->
5869 checked_unset_error p [];
5872 let should_forget_fakes = false in
5873 let result =
5874 match el with
5875 | [(_, p, Obj_get (_, _, OG_nullsafe, _))] ->
5876 Errors.nullsafe_property_write_context p;
5877 make_call_special_from_def env id tel (TUtils.terr env)
5878 | _ -> make_call_special_from_def env id tel MakeType.void
5880 (result, should_forget_fakes)
5881 (* Special function `array_filter` *)
5882 | array_filter
5883 when String.equal array_filter SN.StdlibFunctions.array_filter
5884 && (not (List.is_empty el))
5885 && Option.is_none unpacked_element ->
5886 (* dispatch the call to typecheck the arguments *)
5887 let (env, fty, tal) = fun_type_of_id env id explicit_targs el in
5888 let (env, (tel, typed_unpack_element, res, _should_forget_fakes)) =
5889 call ~expected p env fty el unpacked_element
5891 (* but ignore the result and overwrite it with custom return type *)
5892 (* TODO: eliminate [x] and use the head of [tel] to instead of
5893 typechecking [x] again. *)
5894 let x = List.hd_exn el in
5895 let (env, _tx, ty) = expr env x in
5896 let explain_array_filter ty =
5897 map_reason ty ~f:(fun r -> Reason.Rarray_filter (p, r))
5899 let get_value_type env tv =
5900 let (env, tv) =
5901 if List.length el > 1 then
5902 (env, tv)
5903 else
5904 Typing_solver.non_null env (Pos_or_decl.of_raw_pos p) tv
5906 (env, explain_array_filter tv)
5908 let rec get_array_filter_return_type env ty =
5909 let (env, ety) = Env.expand_type env ty in
5910 match deref ety with
5911 | (r, Tvarray tv) ->
5912 let (env, tv) = get_value_type env tv in
5913 (env, MakeType.varray r tv)
5914 | (r, Tunion tyl) ->
5915 let (env, tyl) =
5916 List.map_env env tyl ~f:get_array_filter_return_type
5918 Typing_union.union_list env r tyl
5919 | (r, Tintersection tyl) ->
5920 let (env, tyl) =
5921 List.map_env env tyl ~f:get_array_filter_return_type
5923 Inter.intersect_list env r tyl
5924 | (r, Tany _) -> (env, mk (r, Typing_utils.tany env))
5925 | (r, Terr) -> (env, TUtils.terr env r)
5926 | (r, _) ->
5927 let (env, tk) = Env.fresh_type env p in
5928 let (env, tv) = Env.fresh_type env p in
5929 Errors.try_
5930 (fun () ->
5931 let keyed_container_type =
5932 MakeType.keyed_container Reason.Rnone tk tv
5934 let env =
5935 SubType.sub_type
5938 keyed_container_type
5939 (Errors.unify_error_at p)
5941 let (env, tv) = get_value_type env tv in
5942 (env, MakeType.darray r (explain_array_filter tk) tv))
5943 (fun _ ->
5944 Errors.try_
5945 (fun () ->
5946 let container_type = MakeType.container Reason.Rnone tv in
5947 let (_, p, _) = x in
5948 let env =
5949 SubType.sub_type
5952 container_type
5953 (Errors.unify_error_at p)
5955 let (env, tv) = get_value_type env tv in
5956 ( env,
5957 MakeType.darray
5959 (explain_array_filter (MakeType.arraykey r))
5960 tv ))
5961 (fun _ -> (env, res)))
5963 let (env, rty) = get_array_filter_return_type env ty in
5964 let fty =
5965 map_ty fty ~f:(function
5966 | Tfun ft -> Tfun { ft with ft_ret = MakeType.unenforced rty }
5967 | ty -> ty)
5969 let should_forget_fakes = false in
5970 let result =
5971 make_call
5973 (Tast.make_typed_expr fpos fty (Aast.Id id))
5976 typed_unpack_element
5979 (result, should_forget_fakes)
5980 (* Special function `type_structure` *)
5981 | type_structure
5982 when String.equal type_structure SN.StdlibFunctions.type_structure
5983 && Int.equal (List.length el) 2
5984 && Option.is_none unpacked_element ->
5985 let should_forget_fakes = false in
5986 (match el with
5987 | [e1; e2] ->
5988 (match e2 with
5989 | (_, p, String cst) ->
5990 (* find the class constant implicitly defined by the typeconst *)
5991 let cid =
5992 match e1 with
5993 | (_, _, Class_const (cid, (_, x)))
5994 | (_, _, Class_get (cid, CGstring (_, x), _))
5995 when String.equal x SN.Members.mClass ->
5997 | _ ->
5998 let (_, p1, _) = e1 in
5999 ((), p1, CIexpr e1)
6001 let result = class_const ~incl_tc:true env p (cid, (p, cst)) in
6002 (result, should_forget_fakes)
6003 | _ ->
6004 Errors.illegal_type_structure pos "second argument is not a string";
6005 let result = expr_error env (Reason.Rwitness pos) e in
6006 (result, should_forget_fakes))
6007 | _ -> assert false)
6008 (* Special function `array_map` *)
6009 | array_map
6010 when String.equal array_map SN.StdlibFunctions.array_map
6011 && (not (List.is_empty el))
6012 && Option.is_none unpacked_element ->
6013 (* This uses the arity to determine a signature for array_map. But there
6014 * is more: for two-argument use of array_map, we specialize the return
6015 * type to the collection that's passed in, below. *)
6016 let (env, fty, tal) = fun_type_of_id env id explicit_targs el in
6017 let (env, fty) = Env.expand_type env fty in
6018 let r_fty = get_reason fty in
6020 Takes a Container type and returns a function that can "pack" a type
6021 into an array of appropriate shape, preserving the key type, i.e.:
6022 array -> f, where f R = array
6023 array<X> -> f, where f R = array<R>
6024 array<X, Y> -> f, where f R = array<X, R>
6025 Vector<X> -> f where f R = array<R>
6026 KeyedContainer<X, Y> -> f, where f R = array<X, R>
6027 Container<X> -> f, where f R = array<arraykey, R>
6028 X -> f, where f R = Y
6030 let rec build_output_container pos env (x : locl_ty) :
6031 env * (env -> locl_ty -> env * locl_ty) =
6032 let (env, x) = Env.expand_type env x in
6033 match deref x with
6034 | (r, Tvarray _) -> (env, (fun env tr -> (env, MakeType.varray r tr)))
6035 | (r, Tany _) ->
6036 (env, (fun env _ -> (env, mk (r, Typing_utils.tany env))))
6037 | (r, Terr) -> (env, (fun env _ -> (env, TUtils.terr env r)))
6038 | (r, Tunion tyl) ->
6039 let (env, builders) =
6040 List.map_env env tyl ~f:(build_output_container pos)
6042 ( env,
6043 fun env tr ->
6044 let (env, tyl) =
6045 List.map_env env builders ~f:(fun env f -> f env tr)
6047 Typing_union.union_list env r tyl )
6048 | (r, Tintersection tyl) ->
6049 let (env, builders) =
6050 List.map_env env tyl ~f:(build_output_container pos)
6052 ( env,
6053 fun env tr ->
6054 let (env, tyl) =
6055 List.map_env env builders ~f:(fun env f -> f env tr)
6057 Typing_intersection.intersect_list env r tyl )
6058 | (r, _) ->
6059 let (env, tk) = Env.fresh_type env p in
6060 let (env, tv) = Env.fresh_type env p in
6061 let try_vector env =
6062 let vector_type = MakeType.const_vector r_fty tv in
6063 let env =
6064 SubType.sub_type env x vector_type (Errors.unify_error_at pos)
6066 (env, (fun env tr -> (env, MakeType.varray r tr)))
6068 let try_keyed_container env =
6069 let keyed_container_type = MakeType.keyed_container r_fty tk tv in
6070 let env =
6071 SubType.sub_type
6074 keyed_container_type
6075 (Errors.unify_error_at pos)
6077 (env, (fun env tr -> (env, MakeType.darray r tk tr)))
6079 let try_container env =
6080 let container_type = MakeType.container r_fty tv in
6081 let env =
6082 SubType.sub_type
6085 container_type
6086 (Errors.unify_error_at pos)
6088 ( env,
6089 (fun env tr -> (env, MakeType.darray r (MakeType.arraykey r) tr))
6092 let (env, tr) =
6093 Errors.try_
6094 (fun () -> try_vector env)
6095 (fun _ ->
6096 Errors.try_
6097 (fun () -> try_keyed_container env)
6098 (fun _ ->
6099 Errors.try_
6100 (fun () -> try_container env)
6101 (fun _ ->
6102 (env, (fun env _ -> (env, Typing_utils.mk_tany env p))))))
6104 (env, tr)
6106 let (env, fty) =
6107 match (deref fty, el) with
6108 | ((_, Tfun funty), [_; x]) ->
6109 let (_, x_pos, _) = x in
6110 let (env, _tx, x) = expr env x in
6111 let (env, output_container) = build_output_container x_pos env x in
6112 begin
6113 match get_varray_inst funty.ft_ret.et_type with
6114 | None -> (env, fty)
6115 | Some elem_ty ->
6116 let (env, elem_ty) = output_container env elem_ty in
6117 let ft_ret = MakeType.unenforced elem_ty in
6118 (env, mk (r_fty, Tfun { funty with ft_ret }))
6120 | _ -> (env, fty)
6122 let (env, (tel, typed_unpack_element, ty, _should_forget_fakes)) =
6123 call ~expected p env fty el None
6125 let should_forget_fakes = false in
6126 let result =
6127 make_call
6129 (Tast.make_typed_expr fpos fty (Aast.Id id))
6132 typed_unpack_element
6135 (result, should_forget_fakes)
6136 | _ -> dispatch_id env id
6138 (* Special Shapes:: function *)
6139 | Class_const (((_, _, CI (_, shapes)) as class_id), ((_, x) as method_id))
6140 when String.equal shapes SN.Shapes.cShapes ->
6141 begin
6142 match x with
6143 (* Special function `Shapes::idx` *)
6144 | idx when String.equal idx SN.Shapes.idx ->
6145 overload_function
6148 class_id
6149 method_id
6151 unpacked_element
6152 (fun env fty res el ->
6153 match el with
6154 | [shape; field] ->
6155 let (env, _ts, shape_ty) = expr env shape in
6156 let (_, shape_pos, _) = shape in
6157 Typing_shapes.idx
6159 shape_ty
6160 field
6161 None
6162 ~expr_pos:p
6163 ~fun_pos:(get_reason fty)
6164 ~shape_pos
6165 | [shape; field; default] ->
6166 let (env, _ts, shape_ty) = expr env shape in
6167 let (env, _td, default_ty) = expr env default in
6168 let (_, shape_pos, _) = shape in
6169 let (_, default_pos, _) = default in
6170 Typing_shapes.idx
6172 shape_ty
6173 field
6174 (Some (default_pos, default_ty))
6175 ~expr_pos:p
6176 ~fun_pos:(get_reason fty)
6177 ~shape_pos
6178 | _ -> (env, res))
6179 (* Special function `Shapes::at` *)
6180 | at when String.equal at SN.Shapes.at ->
6181 overload_function
6184 class_id
6185 method_id
6187 unpacked_element
6188 (fun env _fty res el ->
6189 match el with
6190 | [shape; field] ->
6191 let (env, _te, shape_ty) = expr env shape in
6192 let (_, shape_pos, _) = shape in
6193 Typing_shapes.at env ~expr_pos:p ~shape_pos shape_ty field
6194 | _ -> (env, res))
6195 (* Special function `Shapes::keyExists` *)
6196 | key_exists when String.equal key_exists SN.Shapes.keyExists ->
6197 overload_function
6200 class_id
6201 method_id
6203 unpacked_element
6204 (fun env fty res el ->
6205 match el with
6206 | [shape; field] ->
6207 let (env, _te, shape_ty) = expr env shape in
6208 (* try accessing the field, to verify existence, but ignore
6209 * the returned type and keep the one coming from function
6210 * return type hint *)
6211 let (_, shape_pos, _) = shape in
6212 let (env, _) =
6213 Typing_shapes.idx
6215 shape_ty
6216 field
6217 None
6218 ~expr_pos:p
6219 ~fun_pos:(get_reason fty)
6220 ~shape_pos
6222 (env, res)
6223 | _ -> (env, res))
6224 (* Special function `Shapes::removeKey` *)
6225 | remove_key when String.equal remove_key SN.Shapes.removeKey ->
6226 overload_function
6229 class_id
6230 method_id
6232 unpacked_element
6233 (fun env _ res el ->
6234 match el with
6235 | [shape; field] ->
6236 begin
6237 match shape with
6238 | (_, _, Lvar (_, lvar))
6239 | (_, _, Callconv (Ast_defs.Pinout, (_, _, Lvar (_, lvar))))
6240 | ( _,
6242 Callconv
6243 ( Ast_defs.Pinout,
6244 (_, _, Hole ((_, _, Lvar (_, lvar)), _, _, _)) ) ) ->
6245 let (env, _te, shape_ty) = expr env shape in
6246 let (env, shape_ty) =
6247 Typing_shapes.remove_key p env shape_ty field
6249 let env = set_valid_rvalue p env lvar shape_ty in
6250 (env, res)
6251 | _ ->
6252 let (_, shape_pos, _) = shape in
6253 Errors.invalid_shape_remove_key shape_pos;
6254 (env, res)
6256 | _ -> (env, res))
6257 (* Special function `Shapes::toArray` *)
6258 | to_array when String.equal to_array SN.Shapes.toArray ->
6259 overload_function
6262 class_id
6263 method_id
6265 unpacked_element
6266 (fun env _ res el ->
6267 match el with
6268 | [shape] ->
6269 let (env, _te, shape_ty) = expr env shape in
6270 Typing_shapes.to_array env p shape_ty res
6271 | _ -> (env, res))
6272 (* Special function `Shapes::toDict` *)
6273 | to_dict when String.equal to_dict SN.Shapes.toDict ->
6274 overload_function
6277 class_id
6278 method_id
6280 unpacked_element
6281 (fun env _ res el ->
6282 match el with
6283 | [shape] ->
6284 let (env, _te, shape_ty) = expr env shape in
6285 Typing_shapes.to_dict env p shape_ty res
6286 | _ -> (env, res))
6287 | _ -> dispatch_class_const env class_id method_id
6289 (* Special function `parent::__construct` *)
6290 | Class_const ((_, pos, CIparent), ((_, construct) as id))
6291 when String.equal construct SN.Members.__construct ->
6292 let (env, tel, typed_unpack_element, ty, pty, ctor_fty, should_forget_fakes)
6294 call_parent_construct p env el unpacked_element
6296 let result =
6297 make_call
6299 (Tast.make_typed_expr
6300 fpos
6301 ctor_fty
6302 (Aast.Class_const ((pty, pos, Aast.CIparent), id)))
6303 [] (* tal: no type arguments to constructor *)
6305 typed_unpack_element
6308 (result, should_forget_fakes)
6309 (* Calling parent / class method *)
6310 | Class_const (class_id, m) -> dispatch_class_const env class_id m
6311 (* Call instance method *)
6312 | Obj_get (e1, (_, pos_id, Id m), nullflavor, false)
6313 when not (TypecheckerOptions.method_call_inference (Env.get_tcopt env)) ->
6314 let (env, te1, ty1) = expr ~accept_using_var:true env e1 in
6315 let nullsafe =
6316 match nullflavor with
6317 | OG_nullthrows -> None
6318 | OG_nullsafe -> Some p
6320 let (_, p1, _) = e1 in
6321 let (env, (tfty, tal)) =
6322 TOG.obj_get
6323 ~obj_pos:p1
6324 ~is_method:true
6325 ~inst_meth:false
6326 ~meth_caller:false
6327 ~nullsafe:(Option.map ~f:(fun p -> Reason.Rnullsafe_op p) nullsafe)
6328 ~coerce_from_ty:None
6329 ~explicit_targs
6330 ~class_id:(CIexpr e1)
6331 ~member_id:m
6332 ~on_error:Errors.unify_error
6336 check_disposable_in_return env tfty;
6337 let (env, (tel, typed_unpack_element, ty, should_forget_fakes)) =
6338 call ~nullsafe ~expected p env tfty el unpacked_element
6340 let result =
6341 make_call
6343 (Tast.make_typed_expr
6344 fpos
6345 tfty
6346 (Aast.Obj_get
6347 ( te1,
6348 Tast.make_typed_expr pos_id tfty (Aast.Id m),
6349 nullflavor,
6350 false )))
6353 typed_unpack_element
6356 (result, should_forget_fakes)
6357 (* Call instance method using new method call inference *)
6358 | Obj_get (receiver, (_, pos_id, Id meth), nullflavor, false) ->
6359 (*****
6360 Typecheck `Obj_get` by enforcing that:
6361 - `<instance_type>` <: `Thas_member(m, #1)`
6362 where #1 is a fresh type variable.
6363 *****)
6364 let (env, typed_receiver, receiver_ty) =
6365 expr ~accept_using_var:true env receiver
6367 let env = might_throw env in
6368 let nullsafe =
6369 match nullflavor with
6370 | OG_nullthrows -> None
6371 | OG_nullsafe -> Some p
6373 (* Generate a fresh type `method_ty` for the type of the
6374 instance method, i.e. #1 *)
6375 let (env, method_ty) = Env.fresh_type env p in
6376 (* Create `Thas_member` constraint type *)
6377 let (_, receiver_p, _) = receiver in
6378 let reason = Reason.Rwitness receiver_p in
6379 let has_method_ty =
6380 MakeType.has_member
6381 reason
6382 ~name:meth
6383 ~ty:method_ty
6384 ~class_id:(CIexpr receiver)
6385 ~explicit_targs:(Some explicit_targs)
6387 let env = Env.set_tyvar_variance env method_ty in
6388 let (env, has_method_super_ty) =
6389 if Option.is_none nullsafe then
6390 (env, has_method_ty)
6391 else
6392 (* If null-safe, then `receiver_ty` <: `?Thas_member(m, #1)`,
6393 but *unlike* property access typing in `expr_`, we still use `#1` as
6394 our "result" if `receiver_ty` is nullable (as opposed to `?#1`),
6395 deferring null-safety handling to after `call` *)
6396 let r = Reason.Rnullsafe_op p in
6397 let null_ty = MakeType.null r in
6398 Union.union_i env r has_method_ty null_ty
6400 let (_, receiver_pos, _) = receiver in
6401 let env =
6402 Type.sub_type_i
6403 receiver_pos
6404 Reason.URnone
6406 (LoclType receiver_ty)
6407 has_method_super_ty
6408 Errors.unify_error
6410 (* Perhaps solve for `method_ty`. Opening and closing a scope is too coarse
6411 here - type parameters are localised to fresh type variables over the
6412 course of subtyping above, and we do not want to solve these until later.
6413 Once we typecheck all function calls with a subtyping of function types,
6414 we should not need to solve early at all - transitive closure of
6415 subtyping should give enough information. *)
6416 let env =
6417 match get_var method_ty with
6418 | Some var ->
6419 Typing_solver.solve_to_equal_bound_or_wrt_variance env Reason.Rnone var
6420 | None -> env
6422 let localize_targ env (_, targ) = Phase.localize_targ env targ in
6423 let (env, typed_targs) =
6424 List.map_env env ~f:(localize_targ ~check_well_kinded:true) explicit_targs
6426 check_disposable_in_return env method_ty;
6427 let (env, (typed_params, typed_unpack_element, ret_ty, should_forget_fakes))
6429 call ~nullsafe ~expected ?in_await p env method_ty el unpacked_element
6431 (* If the call is nullsafe AND the receiver is nullable,
6432 make the return type nullable too *)
6433 let (env, ret_ty) =
6434 if Option.is_some nullsafe then
6435 let r = Reason.Rnullsafe_op p in
6436 let null_ty = MakeType.null r in
6437 let (env, null_or_nothing_ty) =
6438 Inter.intersect env ~r null_ty receiver_ty
6440 let (env, ret_option_ty) = Union.union env null_or_nothing_ty ret_ty in
6441 (env, ret_option_ty)
6442 else
6443 (env, ret_ty)
6445 let result =
6446 make_call
6448 (Tast.make_typed_expr
6449 fpos
6450 method_ty
6451 (Aast.Obj_get
6452 ( typed_receiver,
6453 Tast.make_typed_expr pos_id method_ty (Aast.Id meth),
6454 nullflavor,
6455 false )))
6456 typed_targs
6457 typed_params
6458 typed_unpack_element
6459 ret_ty
6461 (result, should_forget_fakes)
6462 (* Function invocation *)
6463 | Fun_id x ->
6464 let (env, fty, tal) = fun_type_of_id env x explicit_targs el in
6465 check_disposable_in_return env fty;
6466 let (env, (tel, typed_unpack_element, ty, should_forget_fakes)) =
6467 call ~expected p env fty el unpacked_element
6469 let result =
6470 make_call
6472 (Tast.make_typed_expr fpos fty (Aast.Fun_id x))
6475 typed_unpack_element
6478 (result, should_forget_fakes)
6479 | Id id -> dispatch_id env id
6480 | _ ->
6481 let (env, te, fty) = expr env e in
6482 let (env, fty) =
6483 Typing_solver.expand_type_and_solve
6484 ~description_of_expected:"a function value"
6486 fpos
6489 check_disposable_in_return env fty;
6490 let (env, (tel, typed_unpack_element, ty, should_forget_fakes)) =
6491 call ~expected p env fty el unpacked_element
6493 let result =
6494 make_call
6497 (* tal: no type arguments to function values, as they are non-generic *)
6500 typed_unpack_element
6503 (result, should_forget_fakes)
6505 and class_get_res
6506 ~is_method
6507 ~is_const
6508 ~coerce_from_ty
6509 ?(explicit_targs = [])
6510 ?(incl_tc = false)
6511 ?(is_function_pointer = false)
6514 (p, mid)
6515 cid =
6516 let (env, this_ty) =
6517 if is_method then
6518 this_for_method env cid cty
6519 else
6520 (env, cty)
6522 class_get_inner
6523 ~is_method
6524 ~is_const
6525 ~this_ty
6526 ~explicit_targs
6527 ~incl_tc
6528 ~coerce_from_ty
6529 ~is_function_pointer
6533 (p, mid)
6535 and class_get_err
6536 ~is_method
6537 ~is_const
6538 ~coerce_from_ty
6539 ?explicit_targs
6540 ?incl_tc
6541 ?is_function_pointer
6544 (p, mid)
6545 cid =
6546 let (env, tys, err_res_opt) =
6547 class_get_res
6548 ~is_method
6549 ~is_const
6550 ~coerce_from_ty
6551 ?explicit_targs
6552 ?incl_tc
6553 ?is_function_pointer
6556 (p, mid)
6559 let err_opt =
6560 match err_res_opt with
6561 | None
6562 | Some (Ok _) ->
6563 None
6564 | Some (Error (ty_actual, ty_expect)) -> Some (ty_actual, ty_expect)
6566 (env, tys, err_opt)
6568 and class_get
6569 ~is_method
6570 ~is_const
6571 ~coerce_from_ty
6572 ?explicit_targs
6573 ?incl_tc
6574 ?is_function_pointer
6577 (p, mid)
6578 cid =
6579 let (env, tys, _) =
6580 class_get_res
6581 ~is_method
6582 ~is_const
6583 ~coerce_from_ty
6584 ?explicit_targs
6585 ?incl_tc
6586 ?is_function_pointer
6589 (p, mid)
6592 (env, tys)
6594 and class_get_inner
6595 ~is_method
6596 ~is_const
6597 ~this_ty
6598 ~coerce_from_ty
6599 ?(explicit_targs = [])
6600 ?(incl_tc = false)
6601 ?(is_function_pointer = false)
6603 ((_, cid_pos, cid_) as cid)
6605 (p, mid) =
6606 let dflt_err = Option.map ~f:(fun (_, _, ty) -> Ok ty) coerce_from_ty in
6607 let (env, cty) = Env.expand_type env cty in
6608 match deref cty with
6609 | (r, Tany _) -> (env, (mk (r, Typing_utils.tany env), []), dflt_err)
6610 | (_, Terr) -> (env, (err_witness env cid_pos, []), dflt_err)
6611 | (_, Tdynamic) -> (env, (cty, []), dflt_err)
6612 | (_, Tunion tyl) ->
6613 let (env, pairs, err_res_opts) =
6614 List.fold_left tyl ~init:(env, [], []) ~f:(fun (env, pairs, errs) ty ->
6615 let (env, pair, err) =
6616 class_get_res
6617 ~is_method
6618 ~is_const
6619 ~explicit_targs
6620 ~incl_tc
6621 ~coerce_from_ty
6622 ~is_function_pointer
6625 (p, mid)
6628 (env, pair :: pairs, err :: errs))
6630 let err_res_opt = Option.(map ~f:union_coercion_errs @@ all err_res_opts) in
6631 let (env, ty) =
6632 Union.union_list env (get_reason cty) (List.map ~f:fst pairs)
6634 (env, (ty, []), err_res_opt)
6635 | (_, Tintersection tyl) ->
6636 let (env, pairs, err_res_opts) =
6637 TUtils.run_on_intersection_res env tyl ~f:(fun env ty ->
6638 class_get_inner
6639 ~is_method
6640 ~is_const
6641 ~this_ty
6642 ~explicit_targs
6643 ~incl_tc
6644 ~coerce_from_ty
6645 ~is_function_pointer
6649 (p, mid))
6651 let err_res_opt =
6652 Option.(map ~f:intersect_coercion_errs @@ all err_res_opts)
6654 let (env, ty) =
6655 Inter.intersect_list env (get_reason cty) (List.map ~f:fst pairs)
6657 (env, (ty, []), err_res_opt)
6658 | (_, Tnewtype (_, _, ty))
6659 | (_, Tdependent (_, ty)) ->
6660 class_get_inner
6661 ~is_method
6662 ~is_const
6663 ~this_ty
6664 ~explicit_targs
6665 ~incl_tc
6666 ~coerce_from_ty
6667 ~is_function_pointer
6671 (p, mid)
6672 | (r, Tgeneric _) ->
6673 let (env, tyl) =
6674 TUtils.get_concrete_supertypes ~abstract_enum:true env cty
6676 if List.is_empty tyl then begin
6677 Errors.non_class_member
6678 ~is_method
6681 (Typing_print.error env cty)
6682 (get_pos cty);
6683 (env, (err_witness env p, []), dflt_err)
6684 end else
6685 let (env, ty) = Typing_intersection.intersect_list env r tyl in
6686 class_get_inner
6687 ~is_method
6688 ~is_const
6689 ~this_ty
6690 ~explicit_targs
6691 ~incl_tc
6692 ~coerce_from_ty
6693 ~is_function_pointer
6697 (p, mid)
6698 | (_, Tclass ((_, c), _, paraml)) ->
6699 let class_ = Env.get_class env c in
6700 (match class_ with
6701 | None -> (env, (Typing_utils.mk_tany env p, []), dflt_err)
6702 | Some class_ ->
6703 (* TODO akenn: Should we move this to the class_get original call? *)
6704 let (env, this_ty) = ExprDepTy.make env ~cid:cid_ this_ty in
6705 (* We need to instantiate generic parameters in the method signature *)
6706 let ety_env =
6708 empty_expand_env with
6709 this_ty;
6710 substs = TUtils.make_locl_subst_for_class_tparams class_ paraml;
6713 let get_smember_from_constraints env class_info =
6714 let upper_bounds =
6715 Cls.upper_bounds_on_this_from_constraints class_info
6717 let (env, upper_bounds) =
6718 List.map_env env upper_bounds ~f:(fun env up ->
6719 Phase.localize ~ety_env env up)
6721 let (env, inter_ty) =
6722 Inter.intersect_list env (Reason.Rwitness p) upper_bounds
6724 class_get_inner
6725 ~is_method
6726 ~is_const
6727 ~this_ty
6728 ~explicit_targs
6729 ~incl_tc
6730 ~coerce_from_ty
6731 ~is_function_pointer
6734 inter_ty
6735 (p, mid)
6737 let try_get_smember_from_constraints env class_info =
6738 Errors.try_with_error
6739 (fun () -> get_smember_from_constraints env class_info)
6740 (fun () ->
6741 TOG.smember_not_found
6743 ~is_const
6744 ~is_method
6745 ~is_function_pointer
6746 class_info
6748 Errors.unify_error;
6749 (env, (TUtils.terr env Reason.Rnone, []), dflt_err))
6751 if is_const then (
6752 let const =
6753 if incl_tc then
6754 Env.get_const env class_ mid
6755 else
6756 match Env.get_typeconst env class_ mid with
6757 | Some _ ->
6758 Errors.illegal_typeconst_direct_access p;
6759 None
6760 | None -> Env.get_const env class_ mid
6762 match const with
6763 | None when Cls.has_upper_bounds_on_this_from_constraints class_ ->
6764 try_get_smember_from_constraints env class_
6765 | None ->
6766 TOG.smember_not_found
6768 ~is_const
6769 ~is_method
6770 ~is_function_pointer
6771 class_
6773 Errors.unify_error;
6774 (env, (TUtils.terr env Reason.Rnone, []), dflt_err)
6775 | Some { cc_type; cc_abstract; cc_pos; _ } ->
6776 let (env, cc_locl_type) = Phase.localize ~ety_env env cc_type in
6777 (match cc_abstract with
6778 | CCAbstract _ ->
6779 (match cid_ with
6780 | CIstatic
6781 | CIexpr _ ->
6783 | _ ->
6784 let cc_name = Cls.name class_ ^ "::" ^ mid in
6785 Errors.abstract_const_usage p cc_pos cc_name)
6786 | CCConcrete -> ());
6787 (env, (cc_locl_type, []), dflt_err)
6788 ) else
6789 let static_member_opt =
6790 Env.get_static_member is_method env class_ mid
6792 (match static_member_opt with
6793 | None when Cls.has_upper_bounds_on_this_from_constraints class_ ->
6794 try_get_smember_from_constraints env class_
6795 | None ->
6796 TOG.smember_not_found
6798 ~is_const
6799 ~is_method
6800 ~is_function_pointer
6801 class_
6803 Errors.unify_error;
6804 (env, (TUtils.terr env Reason.Rnone, []), dflt_err)
6805 | Some
6807 ce_visibility = vis;
6808 ce_type = (lazy member_decl_ty);
6809 ce_deprecated;
6811 } as ce) ->
6812 let def_pos = get_pos member_decl_ty in
6813 TVis.check_class_access
6814 ~use_pos:p
6815 ~def_pos
6817 (vis, get_ce_lsb ce)
6818 cid_
6819 class_;
6820 TVis.check_deprecated ~use_pos:p ~def_pos ce_deprecated;
6821 check_class_get env p def_pos c mid ce cid_ is_function_pointer;
6822 let (env, member_ty, et_enforced, tal) =
6823 match deref member_decl_ty with
6824 (* We special case Tfun here to allow passing in explicit tparams to localize_ft. *)
6825 | (r, Tfun ft) when is_method ->
6826 let (env, explicit_targs) =
6827 Phase.localize_targs
6828 ~check_well_kinded:true
6829 ~is_method:true
6830 ~def_pos
6831 ~use_pos:p
6832 ~use_name:(strip_ns mid)
6834 ft.ft_tparams
6835 (List.map ~f:snd explicit_targs)
6837 let ft =
6838 Typing_enforceability.compute_enforced_and_pessimize_fun_type
6842 let (env, ft) =
6843 Phase.(
6844 localize_ft
6845 ~instantiation:
6846 { use_name = strip_ns mid; use_pos = p; explicit_targs }
6847 ~ety_env
6848 ~def_pos
6852 let fty =
6853 Typing_dynamic.relax_method_type
6855 (Cls.get_support_dynamic_type class_
6856 || get_ce_support_dynamic_type ce)
6860 (env, fty, Unenforced, explicit_targs)
6861 (* unused *)
6862 | _ ->
6863 let { et_type; et_enforced } =
6864 Typing_enforceability.compute_enforced_and_pessimize_ty
6866 member_decl_ty
6868 let (env, member_ty) = Phase.localize ~ety_env env et_type in
6869 (* TODO(T52753871) make function just return possibly_enforced_ty
6870 * after considering intersection case *)
6871 (env, member_ty, et_enforced, [])
6873 let (env, member_ty) =
6874 if Cls.has_upper_bounds_on_this_from_constraints class_ then
6875 let ((env, (member_ty', _), _), succeed) =
6876 Errors.try_
6877 (fun () -> (get_smember_from_constraints env class_, true))
6878 (fun _ ->
6879 (* No eligible functions found in constraints *)
6880 ((env, (MakeType.mixed Reason.Rnone, []), dflt_err), false))
6882 if succeed then
6883 Inter.intersect env ~r:(Reason.Rwitness p) member_ty member_ty'
6884 else
6885 (env, member_ty)
6886 else
6887 (env, member_ty)
6889 let (env, err_res_opt) =
6890 match coerce_from_ty with
6891 | None -> (env, None)
6892 | Some (p, ur, ty) ->
6893 Result.fold
6894 ~ok:(fun env -> (env, Some (Ok ty)))
6895 ~error:(fun env -> (env, Some (Error (ty, member_ty))))
6896 @@ Typing_coercion.coerce_type_res
6901 { et_type = member_ty; et_enforced }
6902 Errors.unify_error
6904 (env, (member_ty, tal), err_res_opt)))
6905 | (_, Tunapplied_alias _) ->
6906 Typing_defs.error_Tunapplied_alias_in_illegal_context ()
6907 | ( _,
6908 ( Tvar _ | Tnonnull | Tvarray _ | Tdarray _ | Tvarray_or_darray _
6909 | Tvec_or_dict _ | Toption _ | Tprim _ | Tfun _ | Ttuple _ | Tobject
6910 | Tshape _ | Taccess _ | Tneg _ ) ) ->
6911 Errors.non_class_member
6912 ~is_method
6915 (Typing_print.error env cty)
6916 (get_pos cty);
6917 (env, (err_witness env p, []), dflt_err)
6919 and class_id_for_new
6920 ~exact p env (cid : Nast.class_id_) (explicit_targs : Nast.targ list) :
6921 newable_class_info =
6922 let (env, tal, te, cid_ty) =
6923 class_expr
6924 ~check_targs_well_kinded:true
6925 ~check_explicit_targs:true
6926 ~exact
6928 explicit_targs
6929 ((), p, cid)
6931 (* Need to deal with union case *)
6932 let rec get_info res tyl =
6933 match tyl with
6934 | [] -> (env, tal, te, res)
6935 | ty :: tyl ->
6936 (match get_node ty with
6937 | Tunion tyl'
6938 | Tintersection tyl' ->
6939 get_info res (tyl' @ tyl)
6940 | _ ->
6941 (* Instantiation on an abstract class (e.g. from classname<T>) is
6942 * via the base type (to check constructor args), but the actual
6943 * type `ty` must be preserved. *)
6944 (match get_node (TUtils.get_base_type env ty) with
6945 | Tdynamic -> get_info (`Dynamic :: res) tyl
6946 | Tclass (sid, _, _) ->
6947 let class_ = Env.get_class env (snd sid) in
6948 (match class_ with
6949 | None -> get_info res tyl
6950 | Some class_info ->
6951 (match (te, cid_ty) with
6952 (* When computing the classes for a new T() where T is a generic,
6953 * the class must be consistent (final, final constructor, or
6954 * <<__ConsistentConstruct>>) for its constructor to be considered *)
6955 | ((_, _, Aast.CI (_, c)), ty) when is_generic_equal_to c ty ->
6956 (* Only have this choosing behavior for new T(), not all generic types
6957 * i.e. new classname<T>, TODO: T41190512 *)
6958 if Tast_utils.valid_newable_class class_info then
6959 get_info (`Class (sid, class_info, ty) :: res) tyl
6960 else
6961 get_info res tyl
6962 | _ -> get_info (`Class (sid, class_info, ty) :: res) tyl))
6963 | _ -> get_info res tyl))
6965 get_info [] [cid_ty]
6967 (* When invoking a method, the class_id is used to determine what class we
6968 * lookup the method in, but the type of 'this' will be the late bound type.
6969 * For example:
6971 * class C {
6972 * public static function get(): this { return new static(); }
6974 * public static function alias(): this { return self::get(); }
6977 * In C::alias, when we invoke self::get(), 'self' is resolved to the class
6978 * in the lexical scope (C), so call C::get. However the method is executed in
6979 * the current context, so static inside C::get will be resolved to the late
6980 * bound type (get_called_class() within C::alias).
6982 * This means when determining the type of this, CIparent and CIself should be
6983 * changed to CIstatic. For the other cases of C::get() or $c::get(), we only
6984 * look at the left hand side of the '::' and use the type associated
6985 * with it.
6987 * Thus C::get() will return a type C, while $c::get() will return the same
6988 * type as $c.
6990 and this_for_method env (_, p, cid) default_ty =
6991 match cid with
6992 | CIparent
6993 | CIself
6994 | CIstatic ->
6995 let (env, _tal, _te, ty) = class_expr env [] ((), p, CIstatic) in
6996 ExprDepTy.make env ~cid:CIstatic ty
6997 | _ -> (env, default_ty)
6999 (** Resolve class expressions:
7000 * self CIself lexically enclosing class
7001 * parent CIparent lexically enclosing `extends` class
7002 * static CIstatic late-static-bound class (i.e. runtime receiver)
7003 * <id> CI id literal class name
7004 * <expr> CIexpr expr expression that evaluates to an object or classname
7006 and class_expr
7007 ?(check_targs_well_kinded = false)
7008 ?(exact = Nonexact)
7009 ?(check_explicit_targs = false)
7010 (env : env)
7011 (tal : Nast.targ list)
7012 ((_, p, cid_) : Nast.class_id) :
7013 env * Tast.targ list * Tast.class_id * locl_ty =
7014 let make_result env tal te ty = (env, tal, (ty, p, te), ty) in
7015 match cid_ with
7016 | CIparent ->
7017 (match Env.get_self_id env with
7018 | Some self ->
7019 (match Env.get_class env self with
7020 | Some trait when Ast_defs.is_c_trait (Cls.kind trait) ->
7021 (match trait_most_concrete_req_class trait env with
7022 | None ->
7023 Errors.parent_in_trait p;
7024 make_result env [] Aast.CIparent (err_witness env p)
7025 | Some (_, parent_ty) ->
7026 (* inside a trait, parent is SN.Typehints.this, but with the
7027 * type of the most concrete class that the trait has
7028 * "require extend"-ed *)
7029 let (env, parent_ty) =
7030 Phase.localize_no_subst env ~ignore_errors:true parent_ty
7032 make_result env [] Aast.CIparent parent_ty)
7033 | _ ->
7034 let parent =
7035 match Env.get_parent_ty env with
7036 | None ->
7037 Errors.parent_undefined p;
7038 mk (Reason.none, Typing_defs.make_tany ())
7039 | Some parent -> parent
7041 let (env, parent) =
7042 Phase.localize_no_subst env ~ignore_errors:true parent
7044 (* parent is still technically the same object. *)
7045 make_result env [] Aast.CIparent parent)
7046 | None ->
7047 let parent =
7048 match Env.get_parent_ty env with
7049 | None ->
7050 Errors.parent_undefined p;
7051 mk (Reason.none, Typing_defs.make_tany ())
7052 | Some parent -> parent
7054 let (env, parent) =
7055 Phase.localize_no_subst env ~ignore_errors:true parent
7057 (* parent is still technically the same object. *)
7058 make_result env [] Aast.CIparent parent)
7059 | CIstatic ->
7060 let this =
7061 if Option.is_some (Env.next_cont_opt env) then
7062 MakeType.this (Reason.Rwitness p)
7063 else
7064 MakeType.nothing (Reason.Rwitness p)
7066 make_result env [] Aast.CIstatic this
7067 | CIself ->
7068 let ty =
7069 match Env.get_self_class_type env with
7070 | Some (c, _, tyl) -> mk (Reason.Rwitness p, Tclass (c, exact, tyl))
7071 | None ->
7072 (* Naming phase has already checked and replaced CIself with CI if outside a class *)
7073 Errors.internal_error p "Unexpected CIself";
7074 Typing_utils.mk_tany env p
7076 make_result env [] Aast.CIself ty
7077 | CI ((p, id) as c) ->
7078 begin
7079 match Env.get_pos_and_kind_of_generic env id with
7080 | Some (def_pos, kind) ->
7081 let simple_kind = Typing_kinding_defs.Simple.from_full_kind kind in
7082 let param_nkinds =
7083 Typing_kinding_defs.Simple.get_named_parameter_kinds simple_kind
7085 let (env, tal) =
7086 Phase.localize_targs_with_kinds
7087 ~check_well_kinded:check_targs_well_kinded
7088 ~is_method:true
7089 ~def_pos
7090 ~use_pos:p
7091 ~use_name:(strip_ns (snd c))
7092 ~check_explicit_targs
7094 param_nkinds
7095 (List.map ~f:snd tal)
7097 let r = Reason.Rhint (Pos_or_decl.of_raw_pos p) in
7098 let type_args = List.map tal ~f:fst in
7099 let tgeneric = MakeType.generic ~type_args r id in
7100 make_result env tal (Aast.CI c) tgeneric
7101 | None ->
7102 (* Not a type parameter *)
7103 let class_ = Env.get_class env id in
7104 (match class_ with
7105 | None -> make_result env [] (Aast.CI c) (Typing_utils.mk_tany env p)
7106 | Some class_ ->
7107 TVis.check_classname_access ~use_pos:p ~in_signature:false env class_;
7108 let (env, ty, tal) =
7109 List.map ~f:snd tal
7110 |> Phase.localize_targs_and_check_constraints
7111 ~exact
7112 ~check_well_kinded:check_targs_well_kinded
7113 ~def_pos:(Cls.pos class_)
7114 ~use_pos:p
7115 ~check_explicit_targs
7118 (Cls.tparams class_)
7120 make_result env tal (Aast.CI c) ty)
7122 | CIexpr ((_, p, _) as e) ->
7123 let (env, te, ty) = expr env e ~allow_awaitable:(*?*) false in
7124 let rec resolve_ety env ty =
7125 let (env, ty) =
7126 Typing_solver.expand_type_and_solve
7127 ~description_of_expected:"an object"
7132 let base_ty = TUtils.get_base_type env ty in
7133 match deref base_ty with
7134 | (_, Tnewtype (classname, [the_cls], _))
7135 when String.equal classname SN.Classes.cClassname ->
7136 resolve_ety env the_cls
7137 | (_, Tgeneric _)
7138 | (_, Tclass _) ->
7139 (env, ty)
7140 | (r, Tunion tyl) ->
7141 let (env, tyl) = List.map_env env tyl ~f:resolve_ety in
7142 (env, MakeType.union r tyl)
7143 | (r, Tintersection tyl) ->
7144 let (env, tyl) = TUtils.run_on_intersection env tyl ~f:resolve_ety in
7145 Inter.intersect_list env r tyl
7146 | (_, Tdynamic) -> (env, base_ty)
7147 | (_, (Tany _ | Tprim Tstring | Tobject)) when not (Env.is_strict env) ->
7148 (env, Typing_utils.mk_tany env p)
7149 | (_, Terr) -> (env, err_witness env p)
7150 | (r, Tvar _) ->
7151 Errors.unknown_type "an object" p (Reason.to_string "It is unknown" r);
7152 (env, err_witness env p)
7153 | (_, Tunapplied_alias _) ->
7154 Typing_defs.error_Tunapplied_alias_in_illegal_context ()
7155 | ( _,
7156 ( Tany _ | Tnonnull | Tvarray _ | Tdarray _ | Tvarray_or_darray _
7157 | Tvec_or_dict _ | Toption _ | Tprim _ | Tfun _ | Ttuple _
7158 | Tnewtype _ | Tdependent _ | Tobject | Tshape _ | Taccess _ | Tneg _
7159 ) ) ->
7160 Errors.expected_class
7161 ~suffix:(", but got " ^ Typing_print.error env base_ty)
7163 (env, err_witness env p)
7165 let (env, result_ty) = resolve_ety env ty in
7166 make_result env [] (Aast.CIexpr te) result_ty
7168 and call_construct p env class_ params el unpacked_element cid cid_ty =
7169 let cid_ty =
7170 if Nast.equal_class_id_ cid CIparent then
7171 MakeType.this (Reason.Rwitness p)
7172 else
7173 cid_ty
7175 let ety_env =
7177 empty_expand_env with
7178 this_ty = cid_ty;
7179 substs = TUtils.make_locl_subst_for_class_tparams class_ params;
7180 on_error = Errors.unify_error_at p;
7183 let env =
7184 Phase.check_where_constraints
7185 ~in_class:true
7186 ~use_pos:p
7187 ~definition_pos:(Cls.pos class_)
7188 ~ety_env
7190 (Cls.where_constraints class_)
7192 let cstr = Env.get_construct env class_ in
7193 let mode = Env.get_mode env in
7194 match fst cstr with
7195 | None ->
7197 ((not (List.is_empty el)) || Option.is_some unpacked_element)
7198 && (FileInfo.is_strict mode || FileInfo.(equal_mode mode Mpartial))
7199 && Cls.members_fully_known class_
7200 then
7201 Errors.constructor_no_args p;
7202 let (env, tel, _tyl) = exprs env el ~allow_awaitable:(*?*) false in
7203 let should_forget_fakes = true in
7204 (env, tel, None, TUtils.terr env Reason.Rnone, should_forget_fakes)
7205 | Some { ce_visibility = vis; ce_type = (lazy m); ce_deprecated; _ } ->
7206 let def_pos = get_pos m in
7207 TVis.check_obj_access ~use_pos:p ~def_pos env vis;
7208 TVis.check_deprecated ~use_pos:p ~def_pos ce_deprecated;
7209 (* Obtain the type of the constructor *)
7210 let (env, m) =
7211 let r = get_reason m |> Typing_reason.localize in
7212 match get_node m with
7213 | Tfun ft ->
7214 let ft =
7215 Typing_enforceability.compute_enforced_and_pessimize_fun_type env ft
7217 (* This creates type variables for non-denotable type parameters on constructors.
7218 * These are notably different from the tparams on the class, which are handled
7219 * at the top of this function. User-written type parameters on constructors
7220 * are still a parse error. This is a no-op if ft.ft_tparams is empty. *)
7221 let (env, implicit_constructor_targs) =
7222 Phase.localize_targs
7223 ~check_well_kinded:true
7224 ~is_method:true
7225 ~def_pos
7226 ~use_pos:p
7227 ~use_name:"constructor"
7229 ft.ft_tparams
7232 let (env, ft) =
7233 Phase.(
7234 localize_ft
7235 ~instantiation:
7237 use_name = "constructor";
7238 use_pos = p;
7239 explicit_targs = implicit_constructor_targs;
7241 ~ety_env
7242 ~def_pos
7246 (env, mk (r, Tfun ft))
7247 | _ ->
7248 Errors.internal_error p "Expected function type for constructor";
7249 let ty = TUtils.terr env r in
7250 (env, ty)
7252 let (env, (tel, typed_unpack_element, _ty, should_forget_fakes)) =
7253 call ~expected:None p env m el unpacked_element
7255 (env, tel, typed_unpack_element, m, should_forget_fakes)
7257 and inout_write_back env { fp_type; _ } (_, _, e) =
7258 match e with
7259 | Callconv (Ast_defs.Pinout, e1) ->
7260 (* Translate the write-back semantics of inout parameters.
7262 * This matters because we want to:
7263 * (1) make sure we can write to the original argument
7264 * (modifiable lvalue check)
7265 * (2) allow for growing of locals / Tunions (type side effect)
7266 * but otherwise unify the argument type with the parameter hint
7268 let (_, pos, _) = e1 in
7269 let (env, _te, _ty) =
7270 assign_ pos Reason.URparam_inout env e1 pos fp_type.et_type
7273 | _ -> env
7275 (** Typechecks a call.
7276 * Returns in this order the typed expressions for the arguments, for the
7277 * variadic arguments, the return type, and a boolean indicating whether fake
7278 * members should be forgotten.
7280 and call
7281 ~(expected : ExpectedTy.t option)
7282 ?(nullsafe : Pos.t option = None)
7283 ?in_await
7287 (el : Nast.expr list)
7288 (unpacked_element : Nast.expr option) :
7289 env * (Tast.expr list * Tast.expr option * locl_ty * bool) =
7290 let expr = expr ~allow_awaitable:(*?*) false in
7291 let exprs = exprs ~allow_awaitable:(*?*) false in
7292 let (env, tyl) = TUtils.get_concrete_supertypes ~abstract_enum:true env fty in
7293 if List.is_empty tyl then begin
7294 bad_call env pos fty;
7295 let env = call_untyped_unpack env (get_pos fty) unpacked_element in
7296 let should_forget_fakes = true in
7297 (env, ([], None, err_witness env pos, should_forget_fakes))
7298 end else
7299 let (env, fty) =
7300 Typing_intersection.intersect_list env (get_reason fty) tyl
7302 let (env, efty) =
7303 if TypecheckerOptions.method_call_inference (Env.get_tcopt env) then
7304 Env.expand_type env fty
7305 else
7306 Typing_solver.expand_type_and_solve
7307 ~description_of_expected:"a function value"
7312 match deref efty with
7313 | (r, Tdynamic) when TCO.enable_sound_dynamic (Env.get_tcopt env) ->
7314 let ty = MakeType.dynamic (Reason.Rdynamic_call pos) in
7315 let el =
7316 (* Need to check that the type of the unpacked_element can be,
7317 * coerced to dynamic, just like all of the other arguments, in addition
7318 * to the check below in call_untyped_unpack, that it is unpackable.
7319 * We don't need to unpack and check each type because a tuple is
7320 * coercible iff it's constituent types are. *)
7321 Option.value_map ~f:(fun u -> el @ [u]) ~default:el unpacked_element
7323 let (env, tel) =
7324 List.map_env env el ~f:(fun env elt ->
7325 (* TODO(sowens): Pass the expected type to expr *)
7326 let (env, te, e_ty) = expr env elt in
7327 let env =
7328 match elt with
7329 | (_, _, Callconv (Ast_defs.Pinout, e1)) ->
7330 let (_, pos, _) = e1 in
7331 let (env, _te, _ty) =
7332 assign_ pos Reason.URparam_inout env e1 pos efty
7335 | _ -> env
7337 let (env, err_opt) =
7338 Result.fold
7339 ~ok:(fun env -> (env, None))
7340 ~error:(fun env -> (env, Some (e_ty, ty)))
7341 @@ Typing_coercion.coerce_type_res
7343 Reason.URnone
7345 e_ty
7347 Typing_defs_core.et_type = ty;
7348 Typing_defs_core.et_enforced = Unenforced;
7350 Errors.unify_error
7352 (env, hole_on_err ~err_opt te))
7354 let env = call_untyped_unpack env (Reason.to_pos r) unpacked_element in
7355 let should_forget_fakes = true in
7356 (env, (tel, None, ty, should_forget_fakes))
7357 | (r, ((Tprim Tnull | Tdynamic | Terr | Tany _ | Tunion []) as ty))
7358 when match ty with
7359 | Tprim Tnull -> Option.is_some nullsafe
7360 | _ -> true ->
7361 let el =
7362 Option.value_map ~f:(fun u -> el @ [u]) ~default:el unpacked_element
7364 let expected_arg_ty =
7365 (* Note: We ought to be using 'mixed' here *)
7366 ExpectedTy.make pos Reason.URparam (Typing_utils.mk_tany env pos)
7368 let (env, tel) =
7369 List.map_env env el ~f:(fun env elt ->
7370 let (env, te, ty) = expr ~expected:expected_arg_ty env elt in
7371 let (env, err_opt) =
7372 if TCO.global_inference (Env.get_tcopt env) then
7373 match get_node efty with
7374 | Terr
7375 | Tany _
7376 | Tdynamic ->
7377 Result.fold
7378 ~ok:(fun env -> (env, None))
7379 ~error:(fun env -> (env, Some (ty, efty)))
7380 @@ Typing_coercion.coerce_type_res
7382 Reason.URparam
7385 (MakeType.unenforced efty)
7386 Errors.unify_error
7387 | _ -> (env, None)
7388 else
7389 (env, None)
7391 let env =
7392 match elt with
7393 | (_, _, Callconv (Ast_defs.Pinout, e1)) ->
7394 let (_, pos, _) = e1 in
7395 let (env, _te, _ty) =
7396 assign_ pos Reason.URparam_inout env e1 pos efty
7399 | _ -> env
7401 (env, hole_on_err ~err_opt te))
7403 let env = call_untyped_unpack env (Reason.to_pos r) unpacked_element in
7404 let ty =
7405 match ty with
7406 | Tprim Tnull -> mk (r, Tprim Tnull)
7407 | Tdynamic -> MakeType.dynamic (Reason.Rdynamic_call pos)
7408 | Terr
7409 | Tany _ ->
7410 Typing_utils.mk_tany env pos
7411 | Tunion []
7412 | _ (* _ should not happen! *) ->
7413 mk (r, Tunion [])
7415 let should_forget_fakes = true in
7416 (env, (tel, None, ty, should_forget_fakes))
7417 | (_, Tunion [ty]) ->
7418 call ~expected ~nullsafe ?in_await pos env ty el unpacked_element
7419 | (r, Tunion tyl) ->
7420 let (env, resl) =
7421 List.map_env env tyl ~f:(fun env ty ->
7422 call ~expected ~nullsafe ?in_await pos env ty el unpacked_element)
7424 let should_forget_fakes =
7425 List.exists resl ~f:(fun (_, _, _, forget) -> forget)
7427 let retl = List.map resl ~f:(fun (_, _, x, _) -> x) in
7428 let (env, ty) = Union.union_list env r retl in
7429 (* We shouldn't be picking arbitrarily for the TAST here, as TAST checks
7430 * depend on the types inferred. Here's we're preserving legacy behaviour
7431 * by picking the last one.
7432 * TODO: don't do this, instead use subtyping to push unions
7433 * through function types
7435 let (tel, typed_unpack_element, _, _) = List.hd_exn (List.rev resl) in
7436 (env, (tel, typed_unpack_element, ty, should_forget_fakes))
7437 | (r, Tintersection tyl) ->
7438 let (env, resl) =
7439 TUtils.run_on_intersection env tyl ~f:(fun env ty ->
7440 call ~expected ~nullsafe ?in_await pos env ty el unpacked_element)
7442 let should_forget_fakes =
7443 List.for_all resl ~f:(fun (_, _, _, forget) -> forget)
7445 let retl = List.map resl ~f:(fun (_, _, x, _) -> x) in
7446 let (env, ty) = Inter.intersect_list env r retl in
7447 (* We shouldn't be picking arbitrarily for the TAST here, as TAST checks
7448 * depend on the types inferred. Here we're preserving legacy behaviour
7449 * by picking the last one.
7450 * TODO: don't do this, instead use subtyping to push intersections
7451 * through function types
7453 let (tel, typed_unpack_element, _, _) = List.hd_exn (List.rev resl) in
7454 (env, (tel, typed_unpack_element, ty, should_forget_fakes))
7455 | (r2, Tfun ft) ->
7456 (* Typing of format string functions. It is dependent on the arguments (el)
7457 * so it cannot be done earlier.
7459 let pos_def = Reason.to_pos r2 in
7460 let (env, ft) = Typing_exts.retype_magic_func env ft el in
7461 let (env, var_param) = variadic_param env ft in
7462 (* Force subtype with expected result *)
7463 let env =
7464 check_expected_ty "Call result" env ft.ft_ret.et_type expected
7466 let env = Env.set_tyvar_variance env ft.ft_ret.et_type in
7467 let is_lambda (_, _, e) =
7468 match e with
7469 | Efun _
7470 | Lfun _ ->
7471 true
7472 | _ -> false
7474 let get_next_param_info paraml =
7475 match paraml with
7476 | param :: paraml -> (false, Some param, paraml)
7477 | [] -> (true, var_param, paraml)
7479 let compute_enum_name env lty =
7480 match get_node lty with
7481 | Tclass ((_, enum_name), _, _) when Env.is_enum_class env enum_name ->
7482 Some enum_name
7483 | Tgeneric (name, _) ->
7484 let upper_bounds =
7485 Typing_utils.collect_enum_class_upper_bounds env name
7487 (* To avoid ambiguity, we only support the case where
7488 * there is a single upper bound that is an EnumClass.
7489 * We might want to relax that later (e.g. with the
7490 * support for intersections.
7491 * See Typing_type_wellformedness.check_via_label_on_param.
7493 if SSet.cardinal upper_bounds = 1 then
7494 let enum_name = SSet.choose upper_bounds in
7495 Some enum_name
7496 else
7497 None
7498 | Tvar var ->
7499 (* minimal support to only deal with Tvar when it is the
7500 * valueOf from BuiltinEnumClass. In this case, we know the
7501 * the tvar as a single lowerbound, `this` which must be
7502 * an enum class. We could relax this in the future but
7503 * I want to avoid complex constraints for now.
7505 let lower_bounds = Env.get_tyvar_lower_bounds env var in
7506 if ITySet.cardinal lower_bounds <> 1 then
7507 None
7508 else (
7509 match ITySet.choose lower_bounds with
7510 | ConstraintType _ -> None
7511 | LoclType lower ->
7512 (match get_node lower with
7513 | Tclass ((_, enum_name), _, _)
7514 when Env.is_enum_class env enum_name ->
7515 Some enum_name
7516 | _ -> None)
7518 | _ ->
7519 (* Already reported, see Typing_type_wellformedness *)
7520 None
7522 let check_arg env ((_, pos, arg) as e) opt_param ~is_variadic =
7523 match opt_param with
7524 | Some param ->
7525 (* First check if __ViaLabel is used or if the parameter is
7526 * a HH\Label.
7528 let (env, label_type) =
7529 let via_label = get_fp_via_label param in
7530 let ety = param.fp_type.et_type in
7531 let (env, ety) = Env.expand_type env ety in
7532 let is_label =
7533 match get_node ety with
7534 | Tnewtype (name, _, _) ->
7535 String.equal SN.Classes.cEnumClassLabel name
7536 | _ -> false
7538 match arg with
7539 | EnumClassLabel (None, label_name) when via_label || is_label ->
7540 (match get_node ety with
7541 | Tnewtype (name, [ty_enum; _ty_interface], _)
7542 when String.equal name SN.Classes.cMemberOf
7543 || String.equal name SN.Classes.cEnumClassLabel ->
7544 let ctor = name in
7545 (match compute_enum_name env ty_enum with
7546 | None -> (env, EnumClassLabelOps.ClassNotFound)
7547 | Some enum_name ->
7548 EnumClassLabelOps.expand
7551 ~full:false
7552 ~ctor
7553 enum_name
7554 label_name)
7555 | _ ->
7556 (* Already reported, see Typing_type_wellformedness *)
7557 (env, EnumClassLabelOps.Invalid))
7558 | EnumClassLabel (Some _, _) ->
7559 (* Full info is here, use normal inference *)
7560 (env, EnumClassLabelOps.Skip)
7561 | Class_const _ when via_label ->
7562 Errors.enum_class_label_invalid_argument pos ~is_proj:true;
7563 (env, EnumClassLabelOps.Invalid)
7564 | _ when via_label ->
7565 Errors.enum_class_label_invalid_argument pos ~is_proj:false;
7566 (env, EnumClassLabelOps.Invalid)
7567 | _ -> (env, EnumClassLabelOps.Skip)
7569 let (env, te, ty) =
7570 match label_type with
7571 | EnumClassLabelOps.Success (te, ty)
7572 | EnumClassLabelOps.LabelNotFound (te, ty) ->
7573 (env, te, ty)
7574 | _ ->
7575 let expected =
7576 ExpectedTy.make_and_allow_coercion_opt
7579 Reason.URparam
7580 param.fp_type
7582 expr
7583 ~accept_using_var:(get_fp_accept_disposable param)
7584 ?expected
7588 let (env, err_opt) = call_param env param (e, ty) ~is_variadic in
7589 (env, Some (hole_on_err ~err_opt te, ty))
7590 | None ->
7591 let expected =
7592 ExpectedTy.make pos Reason.URparam (Typing_utils.mk_tany env pos)
7594 let (env, te, ty) = expr ~expected env e in
7595 (env, Some (te, ty))
7597 let set_tyvar_variance_from_lambda_param env opt_param =
7598 match opt_param with
7599 | Some param ->
7600 let rec set_params_variance env ty =
7601 let (env, ty) = Env.expand_type env ty in
7602 match get_node ty with
7603 | Tunion [ty] -> set_params_variance env ty
7604 | Toption ty -> set_params_variance env ty
7605 | Tfun { ft_params; ft_ret; _ } ->
7606 let env =
7607 List.fold
7608 ~init:env
7609 ~f:(fun env param ->
7610 Env.set_tyvar_variance env param.fp_type.et_type)
7611 ft_params
7613 Env.set_tyvar_variance env ft_ret.et_type ~flip:true
7614 | _ -> env
7616 set_params_variance env param.fp_type.et_type
7617 | None -> env
7619 (* Given an expected function type ft, check types for the non-unpacked
7620 * arguments. Don't check lambda expressions if check_lambdas=false *)
7621 let rec check_args check_lambdas env el paraml =
7622 match el with
7623 (* We've got an argument *)
7624 | (e, opt_result) :: el ->
7625 (* Pick up next parameter type info *)
7626 let (is_variadic, opt_param, paraml) = get_next_param_info paraml in
7627 let (env, one_result) =
7628 match (check_lambdas, is_lambda e) with
7629 | (false, false)
7630 | (true, true) ->
7631 check_arg env e opt_param ~is_variadic
7632 | (false, true) ->
7633 let env = set_tyvar_variance_from_lambda_param env opt_param in
7634 (env, opt_result)
7635 | (true, false) -> (env, opt_result)
7637 let (env, rl, paraml) = check_args check_lambdas env el paraml in
7638 (env, (e, one_result) :: rl, paraml)
7639 | [] -> (env, [], paraml)
7641 (* Same as above, but checks the types of the implicit arguments, which are
7642 * read from the context *)
7643 let check_implicit_args env =
7644 let capability =
7645 Typing_coeffects.get_type ft.ft_implicit_params.capability
7647 if not (TypecheckerOptions.call_coeffects (Env.get_tcopt env)) then
7649 else
7650 let env_capability =
7651 Env.get_local_check_defined env (pos, Typing_coeffects.capability_id)
7653 Type.sub_type
7655 Reason.URnone
7657 env_capability
7658 capability
7659 (fun ?code:_c _ _ ->
7660 Errors.call_coeffect_error
7662 ~available_incl_unsafe:
7663 (Typing_coeffects.pretty env env_capability)
7664 ~available_pos:(Typing_defs.get_pos env_capability)
7665 ~required_pos:(Typing_defs.get_pos capability)
7666 ~required:(Typing_coeffects.pretty env capability))
7668 let should_forget_fakes =
7669 (* If the function doesn't have write priveleges to properties, fake
7670 members cannot be reassigned, so their refinements stand. *)
7671 let capability =
7672 Typing_coeffects.get_type ft.ft_implicit_params.capability
7674 SubType.is_sub_type
7676 capability
7677 (MakeType.write_property_capability Reason.Rnone)
7680 (* First check the non-lambda arguments. For generic functions, this
7681 * is likely to resolve type variables to concrete types *)
7682 let rl = List.map el ~f:(fun e -> (e, None)) in
7683 let (env, rl, _) = check_args false env rl ft.ft_params in
7684 (* Now check the lambda arguments, hopefully with type variables resolved *)
7685 let (env, rl, paraml) = check_args true env rl ft.ft_params in
7686 (* We expect to see results for all arguments after this second pass *)
7687 let get_param opt =
7688 match opt with
7689 | Some x -> x
7690 | None -> failwith "missing parameter in check_args"
7692 let (tel, _) =
7693 let l = List.map rl ~f:(fun (_, opt) -> get_param opt) in
7694 List.unzip l
7696 let env = check_implicit_args env in
7697 let (env, typed_unpack_element, arity, did_unpack) =
7698 match unpacked_element with
7699 | None -> (env, None, List.length el, false)
7700 | Some e ->
7701 (* Now that we're considering an splat (Some e) we need to construct a type that
7702 * represents the remainder of the function's parameters. `paraml` represents those
7703 * remaining parameters, and the variadic parameter is stored in `var_param`. For example, given
7705 * function f(int $i, string $j, float $k = 3.14, mixed ...$m): void {}
7706 * function g((string, float, bool) $t): void {
7707 * f(3, ...$t);
7710 * the constraint type we want is splat([#1], [opt#2], #3).
7712 let (consumed, required_params, optional_params) =
7713 split_remaining_params_required_optional ft paraml
7715 let (_, p1, _) = e in
7716 let (env, (d_required, d_optional, d_variadic)) =
7717 generate_splat_type_vars
7720 required_params
7721 optional_params
7722 var_param
7724 let destructure_ty =
7725 ConstraintType
7726 (mk_constraint_type
7727 ( Reason.Runpack_param (p1, pos_def, consumed),
7728 Tdestructure
7730 d_required;
7731 d_optional;
7732 d_variadic;
7733 d_kind = SplatUnpack;
7734 } ))
7736 let (env, te, ty) = expr env e in
7737 (* Populate the type variables from the expression in the splat *)
7738 let env_res =
7739 Type.sub_type_i_res
7741 Reason.URparam
7743 (LoclType ty)
7744 destructure_ty
7745 Errors.unify_error
7747 let (env, te) =
7748 match env_res with
7749 | Error env ->
7750 (* Our type cannot be destructured, add a hole with `nothing`
7751 as expected type *)
7752 let ty_expect =
7753 MakeType.nothing
7754 @@ Reason.Rsolve_fail (Pos_or_decl.of_raw_pos pos)
7756 (env, mk_hole te ~ty_have:ty ~ty_expect)
7757 | Ok env ->
7758 (* We have a type that can be destructured so continue and use
7759 the type variables for the remaining parameters *)
7760 let (env, err_opts) =
7761 List.fold2_exn
7762 ~init:(env, [])
7763 d_required
7764 required_params
7765 ~f:(fun (env, errs) elt param ->
7766 let (env, err_opt) =
7767 call_param env param (e, elt) ~is_variadic:false
7769 (env, err_opt :: errs))
7771 let (env, err_opts) =
7772 List.fold2_exn
7773 ~init:(env, err_opts)
7774 d_optional
7775 optional_params
7776 ~f:(fun (env, errs) elt param ->
7777 let (env, err_opt) =
7778 call_param env param (e, elt) ~is_variadic:false
7780 (env, err_opt :: errs))
7782 let (env, var_err_opt) =
7783 Option.map2 d_variadic var_param ~f:(fun v vp ->
7784 call_param env vp (e, v) ~is_variadic:true)
7785 |> Option.value ~default:(env, None)
7787 let subtyping_errs = (List.rev err_opts, var_err_opt) in
7788 let te =
7789 match (List.filter_map ~f:Fn.id err_opts, var_err_opt) with
7790 | ([], None) -> te
7791 | _ ->
7792 let (_, pos, _) = te in
7793 hole_on_err
7795 ~err_opt:(Some (ty, pack_errs pos ty subtyping_errs))
7797 (env, te)
7800 ( env,
7801 Some te,
7802 List.length el + List.length d_required,
7803 Option.is_some d_variadic )
7805 (* If we unpacked an array, we don't check arity exactly. Since each
7806 * unpacked array consumes 1 or many parameters, it is nonsensical to say
7807 * that not enough args were passed in (so we don't do the min check).
7809 let () = check_arity ~did_unpack pos pos_def ft arity in
7810 (* Variadic params cannot be inout so we can stop early *)
7811 let env = wfold_left2 inout_write_back env ft.ft_params el in
7812 (env, (tel, typed_unpack_element, ft.ft_ret.et_type, should_forget_fakes))
7813 | (r, Tvar _)
7814 when TypecheckerOptions.method_call_inference (Env.get_tcopt env) ->
7816 Typecheck calls with unresolved function type by constructing a
7817 suitable function type from the arguments and invoking subtyping.
7819 let (env, typed_el, type_of_el) = exprs ~accept_using_var:true env el in
7820 let (env, typed_unpacked_element, type_of_unpacked_element) =
7821 match unpacked_element with
7822 | Some unpacked ->
7823 let (env, typed_unpacked, type_of_unpacked) =
7824 expr ~accept_using_var:true env unpacked
7826 (env, Some typed_unpacked, Some type_of_unpacked)
7827 | None -> (env, None, None)
7829 let mk_function_supertype env pos (type_of_el, type_of_unpacked_element) =
7830 let mk_fun_param ty =
7831 let flags =
7832 (* Keep supertype as permissive as possible: *)
7833 make_fp_flags
7834 ~mode:FPnormal (* TODO: deal with `inout` parameters *)
7835 ~accept_disposable:false (* TODO: deal with disposables *)
7836 ~has_default:false
7837 ~ifc_external:false
7838 ~ifc_can_call:false
7839 ~via_label:false
7840 ~readonly:false
7843 fp_pos = Pos_or_decl.of_raw_pos pos;
7844 fp_name = None;
7845 fp_type = MakeType.enforced ty;
7846 fp_flags = flags;
7849 let ft_arity =
7850 match type_of_unpacked_element with
7851 | Some type_of_unpacked ->
7852 let fun_param = mk_fun_param type_of_unpacked in
7853 Fvariadic fun_param
7854 | None -> Fstandard
7856 (* TODO: ensure `ft_params`/`ft_where_constraints` don't affect subtyping *)
7857 let ft_tparams = [] in
7858 let ft_where_constraints = [] in
7859 let ft_params = List.map ~f:mk_fun_param type_of_el in
7860 let ft_implicit_params =
7862 capability =
7863 CapDefaults (Pos_or_decl.of_raw_pos pos)
7864 (* TODO(coeffects) should this be a different type? *);
7867 let (env, return_ty) = Env.fresh_type env pos in
7868 let return_ty =
7869 match in_await with
7870 | None -> return_ty
7871 | Some r -> MakeType.awaitable r return_ty
7873 let ft_ret = MakeType.enforced return_ty in
7874 let ft_flags =
7875 (* Keep supertype as permissive as possible: *)
7876 make_ft_flags
7877 Ast_defs.FSync (* `FSync` fun can still return `Awaitable<_>` *)
7878 ~return_disposable:false (* TODO: deal with disposable return *)
7879 ~returns_readonly:false
7880 ~readonly_this:false
7882 let ft_ifc_decl = Typing_defs_core.default_ifc_fun_decl in
7883 let fun_locl_type =
7885 ft_arity;
7886 ft_tparams;
7887 ft_where_constraints;
7888 ft_params;
7889 ft_implicit_params;
7890 ft_ret;
7891 ft_flags;
7892 ft_ifc_decl;
7895 let fun_type = mk (r, Tfun fun_locl_type) in
7896 let env = Env.set_tyvar_variance env fun_type in
7897 (env, fun_type, return_ty)
7899 let (env, fun_type, return_ty) =
7900 mk_function_supertype env pos (type_of_el, type_of_unpacked_element)
7902 let env =
7903 Type.sub_type pos Reason.URnone env efty fun_type Errors.unify_error
7905 let should_forget_fakes = true in
7906 (env, (typed_el, typed_unpacked_element, return_ty, should_forget_fakes))
7907 | _ ->
7908 bad_call env pos efty;
7909 let env = call_untyped_unpack env (get_pos efty) unpacked_element in
7910 let should_forget_fakes = true in
7911 (env, ([], None, err_witness env pos, should_forget_fakes))
7913 and call_untyped_unpack env f_pos unpacked_element =
7914 match unpacked_element with
7915 (* In the event that we don't have a known function call type, we can still
7916 * verify that any unpacked arguments (`...$args`) are something that can
7917 * be actually unpacked. *)
7918 | None -> env
7919 | Some e ->
7920 let (env, _, ety) = expr env e ~allow_awaitable:(*?*) false in
7921 let (_, p, _) = e in
7922 let (env, ty) = Env.fresh_type env p in
7923 let destructure_ty =
7924 MakeType.simple_variadic_splat (Reason.Runpack_param (p, f_pos, 0)) ty
7926 Type.sub_type_i
7928 Reason.URnone
7930 (LoclType ety)
7931 destructure_ty
7932 Errors.unify_error
7935 * Build an environment for the true or false branch of
7936 * conditional statements.
7938 and condition ?lhs_of_null_coalesce env tparamet ((ty, p, e) as te : Tast.expr)
7940 let condition = condition ?lhs_of_null_coalesce in
7941 match e with
7942 | Aast.Hole (e, _, _, _) -> condition env tparamet e
7943 | Aast.True when not tparamet ->
7944 (LEnv.drop_cont env C.Next, Local_id.Set.empty)
7945 | Aast.False when tparamet -> (LEnv.drop_cont env C.Next, Local_id.Set.empty)
7946 | Aast.Call ((_, _, Aast.Id (_, func)), _, [param], None)
7947 when String.equal SN.PseudoFunctions.isset func
7948 && tparamet
7949 && not (Env.is_strict env) ->
7950 condition_isset env param
7951 | Aast.Call ((_, _, Aast.Id (_, func)), _, [te], None)
7952 when String.equal SN.StdlibFunctions.is_null func ->
7953 condition_nullity ~nonnull:(not tparamet) env te
7954 | Aast.Binop ((Ast_defs.Eqeq | Ast_defs.Eqeqeq), (_, _, Aast.Null), e)
7955 | Aast.Binop ((Ast_defs.Eqeq | Ast_defs.Eqeqeq), e, (_, _, Aast.Null)) ->
7956 condition_nullity ~nonnull:(not tparamet) env e
7957 | Aast.Lvar _
7958 | Aast.Obj_get _
7959 | Aast.Class_get _
7960 | Aast.Binop (Ast_defs.Eq None, _, _) ->
7961 let (env, ety) = Env.expand_type env ty in
7962 (match get_node ety with
7963 | Tprim Tbool -> (env, Local_id.Set.empty)
7964 | _ -> condition_nullity ~nonnull:tparamet env te)
7965 | Aast.Binop (((Ast_defs.Diff | Ast_defs.Diff2) as op), e1, e2) ->
7966 let op =
7967 if Ast_defs.(equal_bop op Diff) then
7968 Ast_defs.Eqeq
7969 else
7970 Ast_defs.Eqeqeq
7972 condition env (not tparamet) (ty, p, Aast.Binop (op, e1, e2))
7973 | Aast.Id (p, s) when String.equal s SN.Rx.is_enabled ->
7974 (* when Rx\IS_ENABLED is false - switch env to non-reactive *)
7975 let env =
7976 if not tparamet then
7977 if TypecheckerOptions.any_coeffects (Env.get_tcopt env) then
7978 let env = Typing_local_ops.enforce_rx_is_enabled p env in
7979 let defaults = MakeType.default_capability Pos_or_decl.none in
7980 fst @@ Typing_coeffects.register_capabilities env defaults defaults
7981 else
7983 else
7986 (env, Local_id.Set.empty)
7987 (* Conjunction of conditions. Matches the two following forms:
7988 if (cond1 && cond2)
7989 if (!(cond1 || cond2))
7991 | Aast.Binop (((Ast_defs.Ampamp | Ast_defs.Barbar) as bop), e1, e2)
7992 when Bool.equal tparamet Ast_defs.(equal_bop bop Ampamp) ->
7993 let (env, lset1) = condition env tparamet e1 in
7994 (* This is necessary in case there is an assignment in e2
7995 * We essentially redo what has been undone in the
7996 * `Binop (Ampamp|Barbar)` case of `expr` *)
7997 let (env, _, _) =
7998 expr env (Tast.to_nast_expr e2) ~allow_awaitable:(*?*) false
8000 let (env, lset2) = condition env tparamet e2 in
8001 (env, Local_id.Set.union lset1 lset2)
8002 (* Disjunction of conditions. Matches the two following forms:
8003 if (cond1 || cond2)
8004 if (!(cond1 && cond2))
8006 | Aast.Binop (((Ast_defs.Ampamp | Ast_defs.Barbar) as bop), e1, e2)
8007 when Bool.equal tparamet Ast_defs.(equal_bop bop Barbar) ->
8008 let (env, lset1, lset2) =
8009 branch
8011 (fun env ->
8012 (* Either cond1 is true and we don't know anything about cond2... *)
8013 condition env tparamet e1)
8014 (fun env ->
8015 (* ... Or cond1 is false and therefore cond2 must be true *)
8016 let (env, _lset) = condition env (not tparamet) e1 in
8017 (* Similarly to the conjunction case, there might be an assignment in
8018 cond2 which we must account for. Again we redo what has been undone in
8019 the `Binop (Ampamp|Barbar)` case of `expr` *)
8020 let (env, _, _) =
8021 expr env (Tast.to_nast_expr e2) ~allow_awaitable:(*?*) false
8023 condition env tparamet e2)
8025 (env, Local_id.Set.union lset1 lset2)
8026 | Aast.Call ((_, p, Aast.Id (_, f)), _, [lv], None)
8027 when tparamet && String.equal f SN.StdlibFunctions.is_dict_or_darray ->
8028 safely_refine_is_array env `HackDictOrDArray p f lv
8029 | Aast.Call ((_, p, Aast.Id (_, f)), _, [lv], None)
8030 when tparamet && String.equal f SN.StdlibFunctions.is_vec_or_varray ->
8031 safely_refine_is_array env `HackVecOrVArray p f lv
8032 | Aast.Call ((_, p, Aast.Id (_, f)), _, [lv], None)
8033 when tparamet && String.equal f SN.StdlibFunctions.is_any_array ->
8034 safely_refine_is_array env `AnyArray p f lv
8035 | Aast.Call ((_, p, Aast.Id (_, f)), _, [lv], None)
8036 when tparamet && String.equal f SN.StdlibFunctions.is_php_array ->
8037 safely_refine_is_array env `PHPArray p f lv
8038 | Aast.Call
8039 ( ( _,
8041 Aast.Class_const ((_, _, Aast.CI (_, class_name)), (_, method_name))
8044 [shape; field],
8045 None )
8046 when tparamet
8047 && String.equal class_name SN.Shapes.cShapes
8048 && String.equal method_name SN.Shapes.keyExists ->
8049 key_exists env p shape field
8050 | Aast.Unop (Ast_defs.Unot, e) -> condition env (not tparamet) e
8051 | Aast.Is (ivar, h) ->
8052 let reason = Reason.Ris (fst h) in
8053 let refine_type env hint_ty =
8054 let (ivar_ty, ivar_pos, _) = ivar in
8055 let (env, ivar) = get_instance_var env (Tast.to_nast_expr ivar) in
8056 let (env, hint_ty) =
8057 class_for_refinement env p reason ivar_pos ivar_ty hint_ty
8059 let (env, refined_ty) = Inter.intersect env ~r:reason ivar_ty hint_ty in
8060 (set_local env ivar refined_ty, Local_id.Set.singleton (snd ivar))
8062 let (env, lset) =
8063 match snd h with
8064 | Aast.Hnonnull -> condition_nullity ~nonnull:tparamet env ivar
8065 | Aast.Hprim Tnull -> condition_nullity ~nonnull:(not tparamet) env ivar
8066 | _ -> (env, Local_id.Set.empty)
8068 if is_instance_var (Tast.to_nast_expr ivar) then
8069 let (env, hint_ty) =
8070 Phase.localize_hint_no_subst env ~ignore_errors:false h
8072 let (env, hint_ty) =
8073 if not tparamet then
8074 Inter.negate_type env reason hint_ty ~approx:TUtils.ApproxUp
8075 else
8076 (env, hint_ty)
8078 refine_type env hint_ty
8079 else
8080 (env, lset)
8081 | _ -> (env, Local_id.Set.empty)
8083 and string2 env idl =
8084 let (env, tel) =
8085 List.fold_left idl ~init:(env, []) ~f:(fun (env, tel) x ->
8086 let (env, te, ty) = expr env x ~allow_awaitable:(*?*) false in
8087 let (_, p, _) = x in
8089 TypecheckerOptions.enable_strict_string_concat_interp
8090 (Env.get_tcopt env)
8091 then
8092 let r = Reason.Rinterp_operand p in
8093 let (env, formatter_tyvar) = Env.fresh_type_invariant env p in
8094 let stringlike =
8095 MakeType.union
8098 MakeType.arraykey r;
8099 MakeType.dynamic r;
8100 MakeType.new_type r SN.Classes.cHHFormatString [formatter_tyvar];
8103 let (env, err_opt) =
8104 Result.fold
8105 ~ok:(fun env -> (env, None))
8106 ~error:(fun env -> (env, Some (ty, stringlike)))
8107 @@ Typing_ops.sub_type_res
8109 Reason.URstr_interp
8112 stringlike
8113 Errors.strict_str_interp_type_mismatch
8115 (env, hole_on_err ~err_opt te :: tel)
8116 else
8117 let env = Typing_substring.sub_string p env ty in
8118 (env, te :: tel))
8120 (env, List.rev tel)
8122 and user_attribute env ua =
8123 let (env, typed_ua_params) =
8124 List.map_env env ua.ua_params ~f:(fun env e ->
8125 let (env, te, _) = expr env e ~allow_awaitable:(*?*) false in
8126 (env, te))
8128 (env, { Aast.ua_name = ua.ua_name; Aast.ua_params = typed_ua_params })
8130 and file_attributes env file_attrs =
8131 (* Disable checking of error positions, as file attributes have spans that
8132 * aren't subspans of the class or function into which they are copied *)
8133 Errors.run_with_span Pos.none @@ fun () ->
8134 let uas = List.concat_map ~f:(fun fa -> fa.fa_user_attributes) file_attrs in
8135 let env = attributes_check_def env SN.AttributeKinds.file uas in
8136 List.map_env env file_attrs ~f:(fun env fa ->
8137 let (env, user_attributes) =
8138 List.map_env env fa.fa_user_attributes ~f:user_attribute
8140 let env = set_tcopt_unstable_features env fa in
8141 ( env,
8143 Aast.fa_user_attributes = user_attributes;
8144 Aast.fa_namespace = fa.fa_namespace;
8145 } ))
8147 and type_param env t =
8148 let env =
8149 attributes_check_def env SN.AttributeKinds.typeparam t.tp_user_attributes
8151 let (env, user_attributes) =
8152 List.map_env env t.tp_user_attributes ~f:user_attribute
8154 let (env, tp_parameters) = List.map_env env t.tp_parameters ~f:type_param in
8155 ( env,
8157 Aast.tp_variance = t.tp_variance;
8158 Aast.tp_name = t.tp_name;
8159 Aast.tp_parameters;
8160 Aast.tp_constraints = t.tp_constraints;
8161 Aast.tp_reified = reify_kind t.tp_reified;
8162 Aast.tp_user_attributes = user_attributes;
8165 (* Calls the method of a class, but allows the f callback to override the
8166 * return value type *)
8167 and overload_function
8168 make_call fpos p env class_id method_id el unpacked_element f =
8169 let (env, _tal, tcid, ty) = class_expr env [] class_id in
8170 let (env, _tel, _) = exprs env el ~allow_awaitable:(*?*) false in
8171 let (env, (fty, tal)) =
8172 class_get
8173 ~is_method:true
8174 ~is_const:false
8175 ~coerce_from_ty:None
8178 method_id
8179 class_id
8181 let (env, (tel, typed_unpack_element, res, should_forget_fakes)) =
8182 call ~expected:None p env fty el unpacked_element
8184 let (env, ty) = f env fty res el in
8185 let (env, fty) = Env.expand_type env fty in
8186 let fty =
8187 map_ty fty ~f:(function
8188 | Tfun ft -> Tfun { ft with ft_ret = MakeType.unenforced ty }
8189 | ty -> ty)
8191 let te = Tast.make_typed_expr fpos fty (Aast.Class_const (tcid, method_id)) in
8192 (make_call env te tal tel typed_unpack_element ty, should_forget_fakes)
8194 and update_array_type ?lhs_of_null_coalesce p env e1 valkind =
8195 match valkind with
8196 | `lvalue
8197 | `lvalue_subexpr ->
8198 let (env, te1, ty1) =
8199 raw_expr
8200 ~valkind:`lvalue_subexpr
8201 ~check_defined:true
8204 ~allow_awaitable:(*?*) false
8206 begin
8207 match e1 with
8208 | (_, _, Lvar (_, x)) ->
8209 (* type_mapper has updated the type in ty1 typevars, but we
8210 need to update the local variable type too *)
8211 let env = set_local env (p, x) ty1 in
8212 (env, te1, ty1)
8213 | _ -> (env, te1, ty1)
8215 | _ -> raw_expr ?lhs_of_null_coalesce env e1 ~allow_awaitable:(*?*) false
8217 (* External API *)
8218 let expr ?expected env e =
8219 Typing_env.with_origin2 env Decl_counters.Body (fun env ->
8220 expr ?expected env e ~allow_awaitable:(*?*) false)
8222 let expr_with_pure_coeffects ?expected env e =
8223 Typing_env.with_origin2 env Decl_counters.Body (fun env ->
8224 expr_with_pure_coeffects ?expected env e ~allow_awaitable:(*?*) false)
8226 let stmt env st =
8227 Typing_env.with_origin env Decl_counters.Body (fun env -> stmt env st)
8229 let typedef_def ctx typedef =
8230 let env = EnvFromDef.typedef_env ~origin:Decl_counters.TopLevel ctx typedef in
8231 let env =
8232 Env.set_module
8234 (Naming_attributes_params.get_module_attribute typedef.t_user_attributes)
8236 let env =
8237 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
8239 ~ignore_errors:false
8240 typedef.t_tparams
8243 Typing_type_wellformedness.typedef env typedef;
8244 Typing_variance.typedef env typedef;
8245 let {
8246 t_annotation = ();
8247 t_name = (t_pos, t_name);
8248 t_tparams = _;
8249 t_constraint = tcstr;
8250 t_kind = hint;
8251 t_user_attributes = _;
8252 t_vis = _;
8253 t_mode = _;
8254 t_namespace = _;
8255 t_span = _;
8256 t_emit_id = _;
8257 t_is_ctx = _;
8259 typedef
8261 let (env, ty) =
8262 Phase.localize_hint_no_subst
8264 ~ignore_errors:false
8265 ~report_cycle:(t_pos, t_name)
8266 hint
8268 let env =
8269 match tcstr with
8270 | Some tcstr ->
8271 let (env, cstr) =
8272 Phase.localize_hint_no_subst env ~ignore_errors:false tcstr
8274 Typing_ops.sub_type
8275 t_pos
8276 Reason.URnewtype_cstr
8279 cstr
8280 Errors.newtype_alias_must_satisfy_constraint
8281 | _ -> env
8283 let env =
8284 match hint with
8285 | (pos, Hshape { nsi_allows_unknown_fields = _; nsi_field_map }) ->
8286 let get_name sfi = sfi.sfi_name in
8287 check_shape_keys_validity env pos (List.map ~f:get_name nsi_field_map)
8288 | _ -> env
8290 let env =
8291 attributes_check_def
8293 SN.AttributeKinds.typealias
8294 typedef.t_user_attributes
8296 let (env, tparams) = List.map_env env typedef.t_tparams ~f:type_param in
8297 let (env, user_attributes) =
8298 List.map_env env typedef.t_user_attributes ~f:user_attribute
8301 Aast.t_annotation = Env.save (Env.get_tpenv env) env;
8302 Aast.t_name = typedef.t_name;
8303 Aast.t_mode = typedef.t_mode;
8304 Aast.t_vis = typedef.t_vis;
8305 Aast.t_user_attributes = user_attributes;
8306 Aast.t_constraint = typedef.t_constraint;
8307 Aast.t_kind = typedef.t_kind;
8308 Aast.t_tparams = tparams;
8309 Aast.t_namespace = typedef.t_namespace;
8310 Aast.t_span = typedef.t_span;
8311 Aast.t_emit_id = typedef.t_emit_id;
8312 Aast.t_is_ctx = typedef.t_is_ctx;