2 * Copyright (c) 2015, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
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
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
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
=
57 * [ `Class
of pos_id
* Cls.t
* locl_ty
| `Dynamic
] list
59 (*****************************************************************************)
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 _
=
71 "Last typecheck pos: %s"
72 (Pos.string (Pos.to_absolute
!debug_last_pos))
74 (*****************************************************************************)
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
84 | Aast.Typing
-> ty_have
90 | (ty
, pos
, Aast.Callconv
(param_kind
, expr
)) ->
91 (* push the hole inside the `Callconv` constructor *)
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'
)
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 =
116 (_
, _
, Hole
((_
, _
, Binop
(op
, _
, te2
)), ty_have
, ty_expect
, source
))
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
121 | (topt
, p
, Aast.Binop
(_
, te1
, (_
, _
, Aast.Binop
(op
, _
, te2
)))) ->
122 let te = Aast.Binop
(Ast_defs.Eq
(Some op
), te1
, te2
) in
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
=
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
=
148 ~ok
:(fun tys
-> Ok
(MakeType.intersection
Reason.Rnone tys
))
149 ~error
:(fun (acts
, exps
) ->
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
=
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
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
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
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 *)
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
)))
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
=
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
->
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
223 Typing_coeffects.register_capabilities
env cap_ty unsafe_cap_ty
227 (* Set all the types in an expression to the given type. *)
228 let with_type ty
env (e
: Nast.expr) : Tast.expr =
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
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
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
268 | FileInfo.Mpartial
->
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
->
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
)
284 (* Is this type KeyedTraversable<kty,vty>
285 * or KeyedContainer<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
->
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 *)
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)
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
)
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
) ->
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
335 get_ft_return_disposable ft
337 (Typing_disposable.is_disposable_type
env ft
.ft_ret
.et_type
)
340 (* Turn an environment into a local_id_map suitable to be embedded
341 * into an AssertEnv statement
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
)
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
356 Local_id.Map.filter
(fun lid _
-> Local_id.Set.mem lid lset
) map
358 if Local_id.Map.is_empty
map then
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
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
375 let stmt = (pos
, stmt) in
378 | `Start
-> [mk_assert env_map
; stmt]
379 | `End
-> [stmt; mk_assert env_map
]
384 let set_tcopt_unstable_features env { fa_user_attributes
; _
} =
386 Naming_attributes.find
387 SN.UserAttributes.uaEnableUnstableFeatures
391 | Some
{ ua_name
= _
; ua_params
} ->
392 let ( = ) = String.equal
in
393 List.fold ua_params ~
init:env ~f
:(fun env (_
, _
, feature
) ->
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
->
404 TypecheckerOptions.set_tco_enable_expression_trees t
true)
408 (** Do a subtype check of inferred type against expected type *)
409 let check_expected_ty_res
412 (inferred_ty
: locl_ty
)
413 (expected
: ExpectedTy.t
option) : (env, env) result
=
416 | Some
ExpectedTy.{ pos
= p
; reason
= ur
; ty } ->
418 log_with_level
env "typing" ~level
:1 (fun () ->
420 (Pos_or_decl.of_raw_pos p
)
425 "Typing.check_expected_ty %s enforced=%s"
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
);
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
)) ->
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
454 if not
(Pos.equal
Pos.none local_pos
) then
456 else if not
(Pos.equal
Pos.none ret_pos
) then
461 let param_ty = mk
(Reason.Rinout_param
(get_pos
ty), get_node
ty) in
464 Reason.URassign_inout
468 Errors.inout_return_type_mismatch
471 let fun_implicit_return env pos ret
= function
472 | Ast_defs.FGenerator
473 | Ast_defs.FAsyncGenerator
->
476 (* A function without a terminal block has an implicit return; the
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
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
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
502 (* Require a new construct with disposable *)
503 let rec enforce_return_disposable _env e
=
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
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
528 let might_throw env = save_and_merge_next_in_catch env
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
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
) =
549 let tk = MakeType.mixed Reason.Rnone
in
550 (env, MakeType.traversable
(Reason.Rforeach pe
) tv
, tk, tv
)
552 let (env, tk) = Env.fresh_type
env pe
in
553 (env, MakeType.keyed_traversable
(Reason.Rforeach pe
) tk tv
, tk, tv
)
555 let tk = MakeType.mixed Reason.Rnone
in
556 (env, MakeType.async_iterator
(Reason.Rasyncforeach pe
) tv
, tk, tv
)
558 let (env, tk) = Env.fresh_type
env pe
in
560 MakeType.async_keyed_iterator
(Reason.Rasyncforeach pe
) tk tv
,
564 let rec distribute_union env ty =
565 let (env, ty) = Env.expand_type
env ty in
566 match get_node
ty with
569 List.fold tyl ~
init:(env, []) ~f
:(fun (env, errs
) ty ->
570 let (env, err
) = distribute_union env ty in
573 (env, union_coercion_errs errs
)
575 if SubType.is_sub_type_for_union
env ty (MakeType.dynamic
Reason.Rnone
)
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
581 let ur = Reason.URforeach
in
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
591 let (env, err_res
) = distribute_union env ty1
in
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
603 let typing_env_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 *)
612 (* Look up things in shared memory occasionally to have a chance to be
614 match Env.get_class
env "FOR_TEST_ONLY" with
615 | None
-> Unix.sleep
1
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
630 Errors.escaping_disposable
pos
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
=
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
648 let ft = set_ft_is_function_pointer
ft true in
649 mk
(get_reason
ty, Tfun
ft)
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
)) =
666 ~on_error
:Errors.unify_error
670 let ureason = Reason.URxhp
(snd sid
, snd namepstr
) in
673 ~ok
:(fun env -> (env, None
))
674 ~error
:(fun env -> (env, Some
(valty
, declty
)))
675 @@ Typing_coercion.coerce_type_res
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
689 let hint_pos = fst hty
in
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
695 Typing_coercion.coerce_type
700 (MakeType.unenforced hty
)
705 let stash_conts_for_closure env p is_anon captured f
=
707 if is_anon
&& TypecheckerOptions.any_coeffects
(Env.get_tcopt
env) then
709 (Pos.none
, local_capability_id
) :: (Pos.none
, capability_id
) :: captured)
714 if Env.is_local_defined
env this
then
715 (Pos.none
, this
) :: captured
720 Option.map (Env.next_cont_opt
env) ~f
:(fun next_cont
->
723 Env.get_locals
env captured
725 next_cont
.Typing_per_cont_env.local_types
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 ->
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
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
) ->
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
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
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
784 let expand_expected_and_get_node env (expected
: ExpectedTy.t
option) =
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
=
798 let ty_str = "This would be " ^
Typing_print.error
env c_ty
in
799 Some
(reason_pos
, ty_str)
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
811 { et_type
= throwable_ty; et_enforced
= Unenforced
}
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
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
=
851 | CIself
when get_ce_abstract ce
->
853 match Env.get_self_id
env with
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 *)
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
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
872 (* Ban self::some_abstract_method() in a class. This will
874 Errors.self_abstract_call mid p def_pos
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
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
895 let (env, _
, ty) = unbound_name env x
((), Pos.none
, Aast.Null
) in
902 fe_support_dynamic_type
;
907 (match get_node fe_type
with
910 Typing_special_fun.transform_special_fun_ty
ft x
(List.length el
)
912 let ety_env = empty_expand_env
in
915 ~check_well_kinded
:true
919 ~use_name
:(strip_ns
(snd x
))
922 (List.map ~f
:snd tal
)
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
933 { use_name
= strip_ns
(snd x
); use_pos; explicit_targs
= tal
}
940 Typing_dynamic.relax_method_type
942 fe_support_dynamic_type
946 TVis.check_deprecated ~
use_pos ~
def_pos fe_deprecated
;
947 let curr_module = Env.get_module
env in
952 && not
(Option.equal
String.equal fe_module
curr_module) ->
953 Errors.module_mismatch
(fst x
) fe_pos
curr_module m
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
971 Option.is_some
@@ Env.get_static_member
true env class_ mid
)
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 =
985 (Cls.all_ancestor_reqs trait
)
989 let (_r
, (_p
, name
), _paraml
) = TUtils.unwrap_class_type
ty in
992 | Some
(c
, _ty
) -> Cls.has_ancestor c name
998 let class_ = Env.get_class
env name
in
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)
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
1016 let exp_max = List.length
ft.ft_params
in
1023 if arity > exp_max then
1024 Errors.typing_too_many_args
exp_max arity pos pos_def
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
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 {
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.
1067 ~f
:(fun fp
-> not
(Typing_defs.get_fp_has_default fp
))
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
)
1090 let (env, ty) = Env.fresh_type
env p
in
1093 (env, (d_required
, d_optional
, d_variadic
))
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
1105 | Hole
((_
, _
, Lvar _
), _
, _
, _
)
1107 ExprDepTy.make
env ~cid
:(CIexpr e
) arg_ty
1108 | _
-> (env, arg_ty
)
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
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
=
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
))
1131 ( (((_
, _
, This
) | (_
, _
, Lvar _
)) as obj
),
1132 (_
, _
, Id
(_
, member_name
)),
1135 let (env, local
) = Env.FakeMembers.make
env obj member_name p
in
1136 (env, Some
(p
, local
))
1138 | (_
, _
, Dollardollar x
) ->
1140 | (_
, _
, Hole
(e
, _
, _
, _
)) -> make_a_local_of env e
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
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 *)
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 =
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 *)
1176 ( (_
, _
, Aast.Class_const
((_
, _
, Aast.CI
(_
, shapes
)), (_
, idx
))),
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
=
1185 Typing_shapes.shapes_idx_not_null
env shape_ty
field
1189 refine_lvalue_type env shape ~
refine
1190 | (_
, _
, Hole
(te, _
, _
, _
)) -> condition_nullity ~nonnull
env te
1194 Typing_solver.non_null
env (Pos_or_decl.of_raw_pos p
) ty
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
1208 then class_info is the class info of MyClass and hint_tyl corresponds
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
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
=
1220 tp_name
= (_
, tparam_name
);
1221 tp_reified
= reified
;
1228 Attributes.mem
SN.UserAttributes.uaEnforceable tp_user_attributes
1231 Attributes.mem
SN.UserAttributes.uaNewable tp_user_attributes
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))
1243 let (env, new_name
) =
1244 Env.add_fresh_generic_parameter
1246 (Pos_or_decl.of_raw_pos p
)
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
1269 (tparams_with_new_names
: (decl_tparam
* string) option list
)
1271 (* Type of variable in block will be class name
1272 * with fresh type parameters *)
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 *)
1280 empty_expand_env
with
1281 substs
= Subst.make_locl
tparams tyl_fresh
;
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
))
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
->
1317 | Toption
ty -> might_be_supertype ty
1318 | Tunion tyl
-> List.for_all tyl ~f
:might_be_supertype
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
1329 (Errors.unify_error_at p
)
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
)
1351 List.map2_exn
tyl_fresh tparams_with_new_names ~f
:(fun orig_ty tparam_opt
->
1352 match tparam_opt
with
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
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
1376 ( (((_
, _
, This
) | (_
, _
, Lvar _
)) as obj
),
1377 (_
, _
, Id
(_
, member_name
)),
1380 let (env, local
) = Env.FakeMembers.make
env obj member_name p
in
1382 | (_
, _
, Dollardollar
(p
, x
))
1383 | (_
, _
, Lvar
(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
)) ->
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
1409 tparams_with_new_names
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) ->
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
)
1439 (* TODO(T69551141) handle type arguments for Tgeneric *)
1440 let tarrkey = MakeType.generic
r tarrkey_name
in
1442 SubType.add_constraint
1444 Ast_defs.Constraint_as
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
)
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.
1464 let tk = MakeType.arraykey Reason.(Rvarray_or_darray_key
(to_pos
r)) in
1466 MakeType.varray_or_darray
r tk tv
1468 (* This is the refined type of e inside the branch *)
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
->
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
1496 List.fold_left supertypes ~
init:env ~f
:(fun env ty ->
1497 SubType.add_constraint
1499 Ast_defs.Constraint_as
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
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
1530 ( (fun_pos
, p
, (Lfun
(fun_
, idl
) | Efun
(fun_
, idl
))),
1534 (* Express tree literals containing splices use an anonymous
1535 function that returns the makeTree call.
1538 $0splice1 = "whatever";
1539 return MyVisitor::makeTree(...);
1542 let map_stmt env s
=
1544 | (pos, Return
(Some
expr)) ->
1545 let (env, expr) = rewrite_expr_tree_maketree env expr f
in
1546 (env, (pos, Return
(Some
expr)))
1550 let (env, body_ast
) = List.map_env
env fun_
.f_body
.fb_ast ~f
:map_stmt in
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
))
1557 (* The desugarer might give us a simple call to makeTree, so we
1558 can process it immediately. *)
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 =
1587 | Call
(e, _
, el
, unpacked_element
) ->
1588 (env, Call
(e, [((), hint_virtual
)], el
, unpacked_element
))
1592 rewrite_expr_tree_maketree env expr rewrite_expr
1594 module EnumClassLabelOps
= struct
1596 | Success
of Tast.expr * locl_ty
1598 | LabelNotFound
of Tast.expr * locl_ty
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
1616 (match Env.get_const
env cls label_name
with
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
1624 match deref
dty with
1625 | (r, Tapply
((p
, _
), args
)) -> mk
(r, Tapply
((p
, ctor
), args
))
1628 let (env, lty
) = Phase.localize_no_subst
env ~ignore_errors
:true dty in
1632 Some
(pos, enum_name
)
1636 let te = (hi, pos, EnumClassLabel
(qualifier, label_name
)) in
1637 (env, Success
(te, lty
))
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
)
1660 ~f
:(Decl_hint.hint env.decl_env
)
1661 (hint_of_type_hint param
.param_type_hint
)
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
1670 ExpectedTy.make_and_allow_coercion_opt
1676 let (env, (te, ty2
)) =
1677 let pure = MakeType.mixed (Reason.Rwitness param
.param_pos
) in
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;
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 *)
1699 Union.union
env ty1 ty2
1700 (* Otherwise we have an explicit type, and the default expression type
1701 * must be a subtype *)
1704 Typing_coercion.coerce_type
1710 Errors.parameter_default_value_wrong_type
1716 let (env, user_attributes
) =
1717 List.map_env
env param
.param_user_attributes ~f
:user_attribute
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
1738 if has_accept_disposable_attribute param
then
1739 Env.set_using_var
env id
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
1756 Errors.internal_error
1758 ("Type inference for this function has been disabled by the "
1759 ^
SN.UserAttributes.uaDisableTypecheckerInternal
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
; _
} =
1770 let has_implicit_return = LEnv.has_next
env in
1771 let named_body_is_unsafe = Nast.named_body_is_unsafe named_body
in
1773 if (not
has_implicit_return) || abstract
|| named_body_is_unsafe then
1776 fun_implicit_return env pos ret
.et_type f_kind
1779 Typing_env.set_fun_tast_info
1781 { Tast.has_implicit_return; Tast.named_body_is_unsafe }
1783 debug_last_pos := Pos.none
;
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. *)
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 *)
1796 | (_
, Aast.Block
stl'
) -> List.rev
stl'
@ 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 =
1809 SN.Members.__disposeAsync
1811 SN.Members.__dispose
1813 let (_
, obj_pos
, _
) = e in
1814 let (env, (tfty
, _tal
)) =
1821 ~coerce_from_ty
:None
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
) =
1845 (* Simple assignment to local of form `$lvar = e` *)
1846 | Binop
(Ast_defs.Eq None
, (_
, lvar_pos
, Lvar lvar
), e) ->
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
1857 ( Tast.make_typed_expr
1862 Tast.make_typed_expr lvar_pos
ty (Aast.Lvar lvar
),
1865 (* Arbitrary expression. This will be assigned to a temporary *)
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
=
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;
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:
1901 let infer_loop env f
=
1902 let in_loop_outer = env.in_loop
in
1904 if in_loop_outer then
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
1924 let env = { env with in_loop
= in_loop_outer } in
1931 let env = Env.open_tyvars
env pos in
1932 (fun (env, tb
) -> (Typing_solver.close_tyvars_and_solve
env, tb
))
1938 LEnv.move_and_merge_next_in_cont
env C.Fallthrough
1942 (env, Aast.Fallthrough
)
1943 | Noop
-> (env, Aast.Noop
)
1944 | AssertEnv _
-> (env, Aast.Noop
)
1946 let env = LEnv.move_and_merge_next_in_cont
env C.Exit
in
1947 (env, Aast.Yield_break
)
1949 let (env, te, _
) = expr env e in
1951 if TFTerm.typed_expression_exits
te then
1952 LEnv.move_and_merge_next_in_cont
env C.Exit
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
) =
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
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
1978 (* TODO TAST: annotate with joined types *)
1979 (env, Aast.If
(te, tb1
, tb2
))
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
; _
} =
1986 let expected_return =
1987 Typing_return.strip_awaitable
(Env.get_fn_kind
env) env expected_return
1990 match Env.get_fn_kind
env with
1991 | Ast_defs.FGenerator
1992 | Ast_defs.FAsyncGenerator
->
1995 Typing_return.implicit_return
1998 ~
expected:expected_return.et_type
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.
2011 return_dynamically_callable
= _
;
2016 Typing_return.strip_awaitable
(Env.get_fn_kind
env) env return_type
2019 if return_explicit
then
2021 (ExpectedTy.make_and_allow_coercion
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) =
2036 ~ok
:(fun env -> (env, None
))
2037 ~error
:(fun env -> (env, Some
(rty, return_type.et_type
)))
2038 @@ Typing_coercion.coerce_type_res
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)))
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
2061 infer_loop env (fun 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
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
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
2079 (env, Aast.Do
(tb
, te))
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
2085 infer_loop env (fun 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
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
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 *)
2115 assert_env_stmt ~
pos ~at
:`End
Aast.Refinement
refinement_map while_st
2120 us_has_await
= has_await
;
2121 us_exprs
= (loc
, using_clause
);
2122 us_block
= using_block
;
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
2136 us_has_await
= has_await
;
2137 us_exprs
= (loc
, typed_using_clause
);
2138 us_block
= typed_using_block
;
2141 | For
(e1
, e2
, e3
, b
) ->
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
2152 let (env, te1
, _
) = exprs env e1
in
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
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
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
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
2185 assert_env_stmt ~
pos ~at
:`End
Aast.Refinement
refinement_map 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'.
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
2199 LEnv.update_next_from_conts
env [C.Continue
; C.Break
; C.Next
]
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 ->
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
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
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
2240 Async.overload_extract_from_awaitable
env ~p
:pos2 ty2
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
))
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)
2260 let env = LEnv.move_and_merge_next_in_cont
env C.Continue
in
2261 (env, Aast.Continue
)
2263 let env = LEnv.move_and_merge_next_in_cont
env C.Break
in
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
=
2279 let env = LEnv.update_next_from_conts
env [C.Next
; C.Finally
] in
2282 let parent_locals = LEnv.get_all_locals
env in
2283 (* First typecheck the finally block against all continuations merged
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
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
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
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
2327 LEnv.restore_and_merge_conts_from
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
2345 Errors.default_fallthrough switch_pos
2347 Errors.case_fallthrough switch_pos case_pos
2351 (* below, we try to find out if the switch is exhaustive *)
2353 List.exists cl ~f
:(function
2358 (* If it hasn't got a default clause then we need to solve type variables
2359 * in order to check for an enum *)
2361 Env.expand_type
env ty
2363 Typing_solver.expand_type_and_solve
2365 ~description_of_expected
:"a value"
2369 (* leverage that enums are checked for exhaustivity *)
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
2386 let rec case_list env = function
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
)
2404 and catch
catchctx env (sid
, exn_lvar
, b
) =
2405 let env = LEnv.replace_cont
env C.Next
catchctx 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
=
2419 let (env, te, _
, _
) = assign p
env ev p ty2
in
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))
2435 (* TODO Probably impossible, should check that *)
2439 ?
(expected : ExpectedTy.t
option)
2440 ?
(accept_using_var
= false)
2441 ?
(is_using_clause
= false)
2442 ?
(in_readonly_expr
= false)
2444 ?
(check_defined
= true)
2453 | Some
ExpectedTy.{ reason = r; ty = { et_type
= ty; _
}; _
} ->
2455 log_with_level
env "typing" ~level
:1 (fun () ->
2457 (Pos_or_decl.of_raw_pos p
)
2461 ( "Typing.expr " ^
Typing_reason.string_of_ureason
r,
2462 [Log_type
("expected_ty", ty)] );
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
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
2502 ?
(check_defined
= true)
2507 let (_
, p
, _
) = e in
2508 debug_last_pos := p
;
2514 ?lhs_of_null_coalesce
2523 let valkind = `lvalue
in
2524 expr_ ~
valkind ~check_defined
:false env e ~allow_awaitable
:(*?*) false
2526 and lvalues
env el
=
2528 | [] -> (env, [], [])
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
) =
2548 Typing_solver.non_null
env (Pos_or_decl.of_raw_pos p
) tyc
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
2567 ?
(accept_using_var
= false)
2568 ?
(expected : ExpectedTy.t
option)
2570 ?
(check_defined
= true)
2575 | [] -> (env, [], [])
2587 let (env, tel
, tyl
) =
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
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
2617 ~
(valkind : [> `lvalue
| `lvalue_subexpr
| `other
])
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
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
) =
2642 let (env, supertype
) = Env.fresh_type_reason
env use_pos r in
2647 SubType.sub_type
env supertype
ty (fun ?code _
-> ignore code
)
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
))
2656 let subtype_value env ty =
2657 check_expected_ty_res
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 ->
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))
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
)
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
)
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
2704 ~f
:(fun te err_opt -> hole_on_err te ~
err_opt)
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 *)
2713 if String.equal
name SN.Typehints.varray
then
2715 else if String.equal
name SN.Typehints.darray
then
2716 SN.Collections.cDict
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
2726 (empty_expand_env_with_on_error
2727 (Env.invalid_type_hint_assert_primary_pos_in_current_decl
env))
2729 substs
= TUtils.make_locl_subst_for_class_tparams
class_ tys
;
2732 Phase.check_tparams_constraints
2736 (Cls.tparams class_)
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
2746 ~report_to_user
:false);
2747 (* Continue typechecking without performing the check on a best effort
2751 Typing_type_wellformedness.expr env outer
;
2755 failwith
"AST should not contain these nodes"
2756 | Hole
(e, _
, _
, _
) ->
2761 ?lhs_of_null_coalesce
2769 let ty = Typing_utils.mk_tany
env p
in
2770 make_result env p
Aast.Omitted
ty
2772 | ValCollection
(_
, th
, el
) ->
2773 let (get_expected_kind
, name, subtype_val
, make_expr
, make_ty
) =
2775 | ValCollection
(kind
, _
, _
) ->
2776 let class_name = Nast.vc_kind_to_name kind
in
2782 arraykey_value p
class_name true
2791 (fun th elements
-> Aast.ValCollection
(kind
, th
, elements
)),
2793 MakeType.class_type
(Reason.Rwitness p
) class_name [value_ty
] )
2798 (fun th elements
-> Aast.ValCollection
(Vec
, th
, elements
)),
2799 (fun value_ty
-> MakeType.varray
(Reason.Rwitness p
) value_ty
) )
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
) =
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)
2813 match expand_expected_and_get_node env expected with
2814 | (env, Some
(pos, ur, ety
, _
)) ->
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
2827 ~
reason:Reason.URvector
2828 (Reason.Rtype_variable_generics
(p
, "T", strip_ns
name))
2833 make_result env p
(make_expr th tel
) (make_ty elem_ty
)
2835 | KeyValCollection
(_
, th
, l
) ->
2836 let (get_expected_kind
, name, make_expr
, make_ty
) =
2838 | KeyValCollection
(kind
, _
, _
) ->
2839 let class_name = Nast.kvc_kind_to_name kind
in
2840 ( get_kvc_inst p kind
,
2842 (fun th pairs
-> Aast.KeyValCollection
(kind
, th
, pairs
)),
2843 (fun k v
-> MakeType.class_type
(Reason.Rwitness p
) class_name [k
; v
])
2846 let name = "darray" in
2847 ( get_kvc_inst p Dict
,
2849 (fun th pairs
-> Aast.KeyValCollection
(Dict
, th
, pairs
)),
2850 (fun k v
-> MakeType.darray
(Reason.Rwitness p
) k v
) )
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
) =
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))
2864 (* no explicit typehint, fallback to supplied expect *)
2866 match expand_expected_and_get_node env expected with
2867 | (env, Some
(pos, reason, ety
, _
)) ->
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
2882 compute_exprs_and_supertype
2885 ~
reason:(Reason.URkey
name)
2886 ~bound
:(MakeType.arraykey r)
2890 (arraykey_value p
name false)
2893 compute_exprs_and_supertype
2896 ~
reason:Reason.URvalue
2897 (Reason.Rtype_variable_generics
(p
, "Tv", strip_ns
name))
2902 let pairs = List.zip_exn tkl tvl
in
2903 make_result env p
(make_expr th
pairs) (make_ty k v
)
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
)) =
2917 ~coerce_from_ty
:None
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
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
))
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
2947 | Null
-> make_result env p
Aast.Null
(MakeType.null
(Reason.Rwitness p
))
2949 make_result env p
(Aast.String s
) (MakeType.string (Reason.Rwitness p
))
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
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
2970 (Aast.PrefixedString
(n
, te))
2971 (Typing_regex.type_pattern
e)
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
2988 Errors.re_prefixed_non_string pe
"Strings with embedded expressions";
2989 expr_error env (Reason.Rregex pe
) e
2991 Errors.re_prefixed_non_string pe
"Non-strings";
2992 expr_error env (Reason.Rregex pe
) e)
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
)
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
)) =
3023 ~coerce_from_ty
:None
3025 ~class_id
:(CIexpr instance
)
3027 ~on_error
:Errors.unify_error
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:
3039 let class_ = Env.get_class
env class_name in
3041 | None
-> unbound_name env pos_cname outer
3043 (* Create a class type for the given object instantiated with unresolved
3044 * types for its type parameters.
3047 if Ast_defs.is_c_trait
(Cls.kind
class_) then
3048 Errors.meth_caller_trait
pos class_name
3051 List.map_env
env (Cls.tparams class_) ~f
:(fun env _
->
3052 Env.fresh_type
env p
)
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
)
3061 (Reason.Rwitness_from_decl
(Pos_or_decl.of_raw_pos p
))
3062 (Positioned.of_raw_positioned pos_cname
)
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
)) =
3079 ~coerce_from_ty
:None
3081 ~class_id
:(CI
(pos, class_name))
3082 ~member_id
:meth_name
3083 ~on_error
:Errors.unify_error
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)
3097 on_error
= Env.unify_error_assert_primary_pos_in_current_decl
env;
3101 Phase.check_tparams_constraints
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
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
;
3124 (Aast.Method_caller
(pos_cname
, meth_name
))
3125 (mk
(reason, Tfun
caller))
3127 (* This can happen if the method lives in PHP *)
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
)) =
3139 ~incl_tc
:false (* What is this? *)
3140 ~coerce_from_ty
:None
(* What is this? *)
3141 ~explicit_targs
:targs
3142 ~is_function_pointer
:true
3148 let env = Env.set_tyvar_variance
env fpty
in
3149 let fpty = set_function_pointer fpty in
3153 (Aast.FunctionPointer
(FP_class_const
(ce
, meth), tal
))
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
) =
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)
3172 let classname = Option.value classname ~default
:"" in
3175 (* The class given as a static string was not found. *)
3176 unbound_name env (pc
, classname) outer
3178 let smethod = Env.get_static_member
true env class_ (snd
meth) in
3181 (* The static method wasn't found. *)
3182 TOG.smember_not_found
3186 ~is_function_pointer
:false
3190 expr_error env Reason.Rnone outer
3191 | Some
({ ce_type
= (lazy ty); ce_pos
= (lazy ce_pos
); _
} as ce
) ->
3193 if get_ce_abstract ce
then
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
3203 match get_node cid_ty
with
3204 | Tclass
(_
, _
, tyargs) -> tyargs
3209 empty_expand_env
with
3210 substs
= TUtils.make_locl_subst_for_class_tparams
class_ tyargs;
3214 let r = get_reason
ty |> Typing_reason.localize
in
3215 (match get_node
ty with
3218 Typing_enforceability.compute_enforced_and_pessimize_fun_type
env ft
3220 let def_pos = ce_pos
in
3222 Phase.localize_targs
3223 ~check_well_kinded
:true
3227 ~use_name
:(strip_ns
(snd
meth))
3238 use_name
= strip_ns
(snd
meth);
3240 explicit_targs
= tal
;
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
3253 make_result env p
(Aast.Smethod_id
(te, meth)) ty
3255 Errors.private_class_meth ~
def_pos ~
use_pos;
3256 expr_error env r outer
3258 Errors.protected_class_meth ~
def_pos ~
use_pos;
3259 expr_error env r outer
)
3261 Errors.internal_error p
"We have a method which isn't callable";
3262 expr_error env r outer
)))
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;
3277 if check_defined
then
3278 Env.get_local_check_defined
env id
3282 make_result env p
(Aast.Lvar
id) ty
3284 let (env, expected) = expand_expected_and_get_node env expected in
3285 let (env, tel
, tyl
) =
3287 | Some
(pos, ur, _
, Ttuple expected_tyl
) ->
3288 exprs_expected
(pos, ur, expected_tyl
) env el
3291 let ty = MakeType.tuple
(Reason.Rwitness p
) tyl
in
3292 make_result env p
(Aast.Tuple tel
) ty
3294 let (env, tel
, tyl
) =
3297 | `lvalue_subexpr
->
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
) =
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
))
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
) =
3332 ~
reason:Reason.URpair_value
3334 (Reason.Rtype_variable_generics
(p1
, "T1", "Pair"))
3338 let (env, ty2
, err_opt2
) =
3341 ~
reason:Reason.URpair_value
3343 (Reason.Rtype_variable_generics
(p2
, "T2", "Pair"))
3347 let ty = MakeType.pair
(Reason.Rwitness p
) ty1 ty2
in
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
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
3375 ?lhs_of_null_coalesce
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
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
3401 | [(_
, _
, String key_str
); (_
, _
, Int level_str
)] ->
3402 Env.set_log_level
env key_str
(int_of_string level_str
)
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
3412 let ty = MakeType.void
(Reason.Rwitness p
) in
3417 ( Tast.make_typed_expr pos_id
(TUtils.mk_tany
env pos_id
) (Aast.Id
id),
3422 | Call
(e, explicit_targs
, el
, unpacked_element
) ->
3423 let env = might_throw env in
3424 let ((env, te, ty), should_forget_fakes
) =
3437 if should_forget_fakes
then
3438 Env.forget_members
env Reason.(Blame
(p
, BScall
))
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
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
3473 (Aast.Binop
(Ast_defs.QuestionQuestion
, te1
, te2
))
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
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
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
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
3502 | Some
(_, _, te) -> make_result env p
te ty
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
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
3528 (* TODO: This could be less conservative: we only need to account for
3529 * the possibility of exception if the operator is `/` or `/=`.
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
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 * --------------------------------------
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
3557 if Env.is_local_defined
env dd_var then
3558 Some
(Env.get_local_pos
env dd_var)
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
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
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
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
) ->
3581 match Env.get_typedef
env (snd sid
) with
3582 | Some
{ td_tparams
= tparaml
; _ } ->
3583 (* Typedef type parameters cannot have constraints *)
3588 fun { tp_name
= (p
, x
); _ } ->
3589 (* TODO(T69551141) handle type arguments for Tgeneric *)
3590 MakeType.generic
(Reason.Rwitness_from_decl p
) x
3594 let p_ = Pos_or_decl.of_raw_pos p
in
3597 ( Reason.Rwitness_from_decl
p_,
3598 Tapply
(Positioned.of_raw_positioned sid
, params) )
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
)
3610 (empty_expand_env_with_on_error
3611 (Env.invalid_type_hint_assert_primary_pos_in_current_decl
env))
3613 substs
= Subst.make_locl tparaml
tparams;
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
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
)) =
3640 ~coerce_from_ty
:None
3647 Env.FakeMembers.check_static_invalid
env cid_
(snd mid
) ty
3650 Errors.try_if_no_errors
3651 (fun () -> Typing_local_ops.enforce_static_property_access ppos
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
3658 Typing_local_ops.enforce_mutable_static_variable
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
) ->
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
3699 ~class_id
:(CIexpr e1
)
3700 ~explicit_targs
:None
3702 let lty1 = LoclType ty1
in
3703 let (env, result_ty
) =
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
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
3737 let (env, result_ty
) =
3738 Env.FakeMembers.check_instance_invalid
env e1
(snd m
) result_ty
3745 Tast.make_typed_expr pm result_ty
(Aast.Id m
),
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
3754 if TUtils.is_dynamic
env ty1
then
3755 MakeType.dynamic
(Reason.Rwitness p
)
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
3764 let (env, (taf
, opt_key
, value)) = array_field ~allow_awaitable
env af
in
3765 let Typing_env_return_info.{ return_type = expected_return; _ } =
3769 match get_node
expected_return.et_type
with
3770 | Tclass
(_, _, _ :: _ :: send :: _) -> send
3772 Errors.internal_error p
"Return type is not a generator";
3773 Typing_utils.terr
env (Reason.Ryield_send p
)
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 *)
3783 match (af
, opt_key
) with
3784 | (AFvalue
(_, p
, _), None
) ->
3786 let (env, ty) = Env.fresh_type
env p
in
3787 (env, MakeType.nullable_locl
(Reason.Ryield_asyncnull p
) ty)
3789 (env, MakeType.int (Reason.Rwitness p
))
3790 | (_, Some x
) -> (env, x
)
3791 | (_, _) -> assert false
3795 MakeType.async_generator
(Reason.Ryield_asyncgen p
) key
value send
3797 MakeType.generator
(Reason.Ryield_gen p
) key
value send
3799 let Typing_env_return_info.{ return_type = expected_return; _ } =
3803 Typing_coercion.coerce_type
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
3817 (MakeType.nullable_locl
(Reason.Ryield_send p
) send)
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) =
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
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
3840 typed_unpack_element
,
3843 should_forget_fakes
) =
3848 ~check_not_abstract
:true
3857 if should_forget_fakes
then
3858 Env.forget_members
env Reason.(Blame
(p
, BScall
))
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
3870 if rd
.rdt_abstract
then Errors.new_abstract_record
(pos, id);
3872 let field_name (_, pos, expr_
) =
3874 | Aast.String
name -> Some
(pos, name)
3876 (* TODO T44306013: Ensure that other values for field names are banned. *)
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)
3884 (* Check for missing required fields. *)
3885 let fields_present_names =
3886 List.map ~f
:snd
fields_present |> SSet.of_list
3889 (fun field_name info
->
3890 let ((field_pos
, _), req
) = info
in
3892 | Typing_defs.ValueRequired
3893 when not
(SSet.mem
field_name fields_present_names) ->
3894 Errors.missing_record_field_name
3898 ~field_decl_pos
:field_pos
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
3909 ~decl_pos
:(fst rd
.rdt_name
))
3910 | None
-> Errors.type_not_record
id pos);
3912 expr_error env (Reason.Rwitness p
) outer
3914 let (env, te, ty2
) = expr ?in_await
env e in
3915 let env = might_throw env in
3918 TypecheckerOptions.experimental_feature_enabled
3920 TypecheckerOptions.experimental_forbid_nullable_cast
3921 && not
(TUtils.is_mixed
env ty2
)
3923 SubType.sub_type_or_fail
3926 (MakeType.nonnull
(get_reason ty2
))
3928 Errors.nullable_cast p
(Typing_print.error
env ty2
) (get_pos ty2
))
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
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
3957 if enable_sound_dynamic && is_dyn then
3959 ~coerce
:(Some
Typing_logic.CoerceToDynamic
)
3963 (Errors.unify_error_at p
)
3967 let (env, hint_ty) =
3968 if is_dyn && not
enable_sound_dynamic then
3970 if is_instance_var e then
3971 let (env, ivar
) = get_instance_var env e in
3972 set_local env ivar
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
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
4000 (* Check attributes on the lambda *)
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. *)
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"
4016 Typing_enforceability.compute_enforced_and_pessimize_fun_type
4020 (* When creating a closure, the 'this' type will mean the late bound type
4021 * of the current enclosing class
4024 empty_expand_env_with_on_error
4025 (Env.invalid_type_hint_assert_primary_pos_in_current_decl
env)
4027 let (env, declared_ft) =
4031 { use_name
= "lambda"; use_pos = p
; explicit_targs
= [] }
4033 ~
def_pos:declared_pos
4037 List.iter idl ~f
:(check_escaping_var env);
4039 (* Ensure lambda arity is not ellipsis in strict mode *)
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
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
4056 ( Reason.Rwitness p
,
4061 (if is_explicit_ret then
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 *)
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
)
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
) ->
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
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
}
4103 resolved_ft_param :: rest
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. *)
4110 (* This means the expected_ft params list can have more parameters
4111 * than declared parameters in the lambda. For variadics, this is OK.
4115 let replace_non_declared_arity variadic declared_arity expected_arity
=
4117 | FVvariadicArg
{ param_type_hint
= (_, Some
_); _ } -> declared_arity
4118 | FVvariadicArg
_ ->
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
4131 replace_non_declared_arity
4133 declared_ft.ft_arity
4134 expected_ft.ft_arity
;
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 *)
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
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
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
4170 FL.Lambda.explicit_params
);
4171 check_body_under_known_params env declared_ft
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
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
=
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 }
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
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
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
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
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
4248 let (env, t
) = Env.fresh_type
env pos in
4252 et_type
= mk
(get_reason et
.et_type
, Tclass
(id, e, [t
]));
4256 let freshen_untyped_param env ft_param
=
4257 let (env, fp_type
) =
4260 (Pos_or_decl.unsafe_to_raw_pos ft_param
.fp_pos
)
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
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
4285 | Xml
(sid
, attrl
, el
) ->
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 *)
4293 List.find_map classes ~f
:(function
4295 | `Class
(_, class_info, _) -> Some
class_info)
4297 let (env, te, obj
) =
4298 (* New statements derived from Xml literals are of the following form:
4301 * darray<string,mixed> $attributes,
4302 * varray<mixed> $children,
4307 let new_exp = Typing_xhp.rewrite_xml_into_new p sid attrl el
in
4308 expr ?
expected env new_exp
4319 (_, _, (Varray
(_, children
) | ValCollection
(Vec
, _, children
)));
4325 (* Typing_xhp.rewrite_xml_into_new generates an AST node for a `varray[]` literal, which is interpreted as a vec[] *)
4328 (* We end up in this case when the cosntructed new expression does
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
4341 let (env, fdm_with_expected
) =
4342 match expand_expected_and_get_node env expected with
4343 | (env, Some
(pos, ur, _, Tshape
(_, expected_fdm
))) ->
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
))))
4354 | _ -> (env, List.map ~f
:(fun (k
, v
) -> (k
, (v
, None
))) fdm
)
4356 (* allow_inter adds a type-variable *)
4359 ~f
:(fun env (key
, (e, expected)) ->
4360 let (env, te, ty) = expr ?
expected env e in
4361 (env, (key
, (te, ty))))
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
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. *)
4387 (Aast.Shape
(List.map ~f
:(fun (k
, (te, _)) -> (k
, te)) tfdm
))
4388 (mk
(Reason.Rwitness p
, Tshape
(Closed_shape
, fdm)))
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
;
4396 (Aast.EnumClassLabel
(None
, s))
4397 (mk
(Reason.Rwitness p
, Terr
))
4398 | EnumClassLabel
((Some
(pos, cname
) as e), name) ->
4400 EnumClassLabelOps.expand
4404 ~ctor
:SN.Classes.cEnumClassLabel
4412 (Aast.EnumClassLabel
(e, name))
4413 (mk
(Reason.Rwitness p
, Terr
))
4416 | EnumClassLabelOps.Success
((_, _, texpr
), lty
) ->
4417 make_result env p texpr lty
4418 | EnumClassLabelOps.ClassNotFound
->
4419 (* Error registered in nast_check/unbound_name_check *)
4421 | EnumClassLabelOps.LabelNotFound
_ ->
4422 (* Error registered in EnumClassLabelOps.expand *)
4424 | EnumClassLabelOps.Invalid
4425 | EnumClassLabelOps.Skip
->
4426 Errors.enum_class_label_as_expr p
;
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
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
4439 let (env, (const_ty
, _tal
)) =
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
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
) =
4463 | Some
class_info -> Typing_xhp.get_spread_attributes
env p
class_info valty
4465 let (env, has_err
) =
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))
4473 (* If we have a subtyping error for any attribute, the best we can do here
4474 is give an expected type of dynamic *)
4477 Some
(valty
, MakeType.nothing Reason.Rnone
)
4481 (* Build the typed attribute node *)
4482 let typed_attr = Aast.Xhp_spread
(hole_on_err ~
err_opt te) in
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
4498 { xs_name
= id; xs_type
= decl_ty
; xs_expr
= hole_on_err ~
err_opt te }
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) =
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
=
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
4532 | param
:: paraml
->
4534 (match hint_of_type_hint param
.param_type_hint
with
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
4542 Typing_coercion.coerce_type
4547 (MakeType.unenforced h
)
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
])
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
4573 (* if the hint is missing, use the type we expect *)
4574 (env, variadic_ty
, get_pos variadic_ty
)
4576 let pos = fst
hint in
4578 Phase.localize_hint_no_subst
env ~ignore_errors
:false hint
4581 Typing_coercion.coerce_type
4586 (MakeType.unenforced h
)
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
4597 and closure_bind_opt_param
env param
: env =
4598 match param
.param_expr
with
4600 let ty = Typing_utils.mk_tany
env param
.param_pos
in
4601 let (env, _) = bind_param env (ty, param
) in
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 *)
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. *)
4631 if check_escapes
then
4632 Typing_escape.refresh_env_and_type
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
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
)
4658 let (env, cap_ty
, unsafe_cap_ty
) =
4659 type_capability env f
.f_ctxs f
.f_unsafe_ctxs
(fst f
.f_name
)
4662 Typing_coeffects.register_capabilities
env cap_ty unsafe_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
) =
4704 ~f
:(closure_bind_param
params)
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
4714 Unify.unify_param_modes
4720 match f
.f_variadic
with
4723 TUtils.default_fun_param
4724 ~
pos:(Pos_or_decl.of_raw_pos
pos)
4725 (mk
(Reason.Rvar_param
pos, Typing_defs.make_tany
()))
4730 let rec iter l1 l2
=
4731 match (l1
, l2
, var_param) with
4733 | ([], _, None
) -> ()
4734 | ([], x2
:: rl2
, Some def1
) ->
4735 param_modes ~is_variadic
:true def1 x2
;
4737 | (x1
:: rl1
, x2
:: 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
4746 Option.map ~f
:(Decl_hint.hint env.decl_env
) (hint_of_type_hint f
.f_ret
)
4749 match snd f
.f_ret
with
4750 | Some
(ret_pos, _) -> ret_pos
4751 | None
-> lambda_pos
4756 (* Do we have a contextual return type? *)
4759 | None
-> Typing_return.make_fresh_return_type
env ret_pos
4760 | Some
ret_ty -> (env, ret_ty)
4763 (* If a 'this' type appears it needs to be compatible with the
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
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
4779 (Typing_return.make_info
4784 ~is_explicit
:(Option.is_some
ret_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
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
4799 if (not
has_implicit_return) || Nast.named_body_is_unsafe nb then
4802 fun_implicit_return env lambda_pos hret f
.f_fun_kind
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
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
4837 Tast.make_typed_expr
4841 Aast.Efun
(tfun_, idl
)
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
4864 let (env, t_splices
) = block
env et_splices
in
4866 (* Type check the virtualized expression, which will look
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
4898 (Aast.ExpressionTree
4901 et_splices
= t_splices
;
4902 et_virtualized_expr
= t_virtualized_expr
;
4903 et_runtime_expr
= t_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 (*****************************************************************************)
4922 ~
(expected : ExpectedTy.t
option)
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>);
4938 let (env, tal
, tcid
, classes
) =
4939 instantiable_cid ~exact
:Exact p
env cid explicit_targs
4941 let allow_abstract_bound_generic =
4943 | (ty, _, Aast.CI
(_, tn
)) -> is_generic_equal_to tn
ty
4947 (env, _tel
, _typed_unpack_element
, should_forget_fakes_acc
)
4948 (cname
, class_info, c_ty
) =
4951 && Cls.abstract
class_info
4952 && (not
(requires_consistent_construct cid))
4953 && not
allow_abstract_bound_generic
4955 uninstantiable_error
4959 (Cls.pos class_info)
4960 (Cls.name class_info)
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
) ->
4970 List.map_env
env (Cls.tparams class_info) ~f
:(fun env tparam ->
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;
4982 match class_type_opt
with
4983 | Some
(_, Exact
, _) -> (env, Tclass
(cname
, Exact
, params), params)
4984 | _ -> (env, Tclass
(cname
, Nonexact
, params), params)
4989 && (not is_using_clause
)
4990 && Cls.is_disposable
class_info
4992 Errors.invalid_new_disposable p
;
4993 let r_witness = Reason.Rwitness p
in
4994 let obj_ty = mk
(r_witness, obj_ty_
) in
4999 mk
(r_witness, get_node
c_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
5007 else if check_parent
then
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
5025 | CIstatic
-> Errors.new_inconsistent_construct p cname `static
5026 | CIexpr
_ -> Errors.new_inconsistent_construct p cname `
classname
5030 let (env, ctor_fty
) =
5031 match fst
(Cls.construct
class_info) with
5032 | Some
({ ce_type
= (lazy ty); _ } as ce
) ->
5035 empty_expand_env
with
5037 TUtils.make_locl_subst_for_class_tparams
class_info params;
5041 if get_ce_abstract ce
then
5042 Errors.parent_abstract_call
5043 SN.Members.__construct
5046 let (env, ctor_fty
) = Phase.localize ~
ety_env env ty in
5048 | None
-> (env, ctor_fty
)
5050 ( (env, tel
, typed_unpack_element
, should_forget_fakes_acc),
5051 (obj_ty, ctor_fty
) )
5055 ( (env, tel
, typed_unpack_element
, should_forget_fakes_acc),
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 *)
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),
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
5083 dyn :: class_types_and_ctor_types
5085 class_types_and_ctor_types
5087 let (env, tel
, typed_unpack_element
, ty, ctor_fty
) =
5088 match class_types_and_ctor_types with
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
->
5096 expr env unpacked_element ~allow_awaitable
:(*?*) false
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
)
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
))
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
5113 else if check_parent
then
5116 ExprDepTy.make
env ~
cid ty
5122 typed_unpack_element
,
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
5131 Typing_lenv.stash_and_do
env (Env.all_continuations
env) (fun 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
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)
5167 uninstantiable_error env p
cid (Cls.pos class_info) name pos c_ty
5173 Ast_defs.is_c_abstract
(Cls.kind
class_info) && Cls.final
class_info
5175 uninstantiable_error env p
cid (Cls.pos class_info) name pos c_ty
5178 (env, tal
, te, classes
)
5180 and check_shape_keys_validity
:
5181 env -> pos -> Ast_defs.shape_field_name list
-> env =
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. *)
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
5203 (MakeType.arraykey r)
5205 Errors.invalid_shape_field_type
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
5217 Errors.invalid_shape_field_literal
key_pos witness_pos
;
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
5232 (Typing_solver.is_sub_type
env ty1 ty2
5233 && Typing_solver.is_sub_type
env ty2 ty1
)
5235 Errors.shape_field_type_mismatch
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
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
5262 and assign_with_subtype_err_ p
ur env (e1
: Nast.expr) pos2 ty2
=
5264 | (_, _, Hole
(e, _, _, _)) -> assign_with_subtype_err_ p
ur env e pos2 ty2
5266 let allow_awaitable = (*?*) false in
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
5278 Reason.(Blame
(p
, BSassignment
))
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
5287 | (_, _, Lplaceholder
id) ->
5288 let placeholder_ty = MakeType.void
(Reason.Rplaceholder p
) in
5289 let (_, p1
, _) = e1
in
5291 make_result env p1
(Aast.Lplaceholder
id) placeholder_ty
5294 | (_, _, List el
) ->
5295 (* Generate fresh types for each lhs list element, then subtype against
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
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 *)
5335 let (env, te, ty, subty_errs
) = type_list_elem env in
5337 if List.for_all subty_errs ~f
:Option.is_none
then
5340 Some
(ty2
, pack_errs pos2 ty2
(subty_errs
, None
))
5342 (env, te, ty, err_opt))
5344 let (env, te, ty, _) = type_list_elem env in
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
5353 Obj_get
(obj
, (_, pm
, Id
((_, member_name
) as m
)), nullflavor
, in_parens
)
5355 let lenv = env.lenv in
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
5373 ~coerce_from_ty
:(Some
(p
, ur, ty2
))
5375 ~class_id
:(CIexpr e1
)
5377 ~on_error
:Errors.unify_error
5382 Tast.make_typed_expr
5387 Tast.make_typed_expr pm declared_ty
(Aast.Id m
),
5391 let env = { env with lenv } in
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) =
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
)
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) =
5438 ~coerce_from_ty
:(Some
(p
, ur, ety2
))
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
5463 if is_hack_collection env ty1
then
5466 let (env, te1, _, _) = assign_with_subtype_err_ p
ur env e1 p1 ty1'
in
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
5490 if is_hack_collection env ty1
then
5493 let (env, te1, _, _) = assign_with_subtype_err_ p
ur env e1 p1 ty1'
in
5499 Aast.Array_get
(te1, Some
(hole_on_err ~
err_opt:key_err_opt
te)) ),
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) =
5508 ~ok
:(fun env -> (env, None
))
5509 ~
error:(fun env -> (env, Some
(ty2
, ty1
)))
5510 @@ Typing_coercion.coerce_type_res
5515 (MakeType.unenforced ty1
)
5518 (env, te1, ty2
, err_opt)
5520 and array_field
env ~
allow_awaitable = function
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
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) =
5539 ( MakeType.arraykey (Reason.Rset_element
pos),
5540 Reason.set_element
class_name )
5542 (MakeType.arraykey (Reason.Ridx_dict
pos), Reason.index_class
class_name)
5544 let (env, err_opt) =
5546 ~ok
:(fun env -> (env, None
))
5547 ~
error:(fun env -> (env, Some
(ty, ty_arraykey
)))
5548 @@ Typing_coercion.coerce_type_res
5553 { et_type
= ty_arraykey
; et_enforced
= Enforced
}
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
5567 typed_unpack_element
,
5570 should_forget_fakes
) =
5575 ~is_using_clause
:false
5583 (* Not sure why we need to equate these types *)
5585 Type.sub_type
pos Reason.URnone
env env_parent parent
Errors.unify_error
5588 Type.sub_type
pos Reason.URnone
env parent env_parent
Errors.unify_error
5592 typed_unpack_element
,
5593 MakeType.void
(Reason.Rwitness
pos),
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
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
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
5612 Errors.parent_in_trait
pos;
5614 | Some
(_, parent_ty
) ->
5615 check_parent_construct
pos env el unpacked_element parent_ty
)
5617 if not
(Cls.members_fully_known self_tc
) then
5619 (* Don't know the hierarchy, assume it's correct *)
5621 Errors.undefined_parent
pos;
5623 | None
-> assert false)
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.
5633 ~
(expected : ExpectedTy.t
option)
5638 ((_, fpos
, fun_expr
) as e : Nast.expr)
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 =
5651 (Tast.make_typed_expr fpos
(TUtils.mk_tany
env fpos
) (Aast.Id
id))
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
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]
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
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
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.
5718 ~coerce_from_ty
:None
5722 ~on_error
:Errors.unify_error
5728 ~coerce_from_ty
:None
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
5744 (Tast.make_typed_expr fpos
fty (Aast.Class_const
(tcid
, m
)))
5747 typed_unpack_element
5750 (result, should_forget_fakes
)
5753 (* Special top-level function *)
5754 | Id
((pos, x
) as id) when SN.StdlibFunctions.needs_special_dispatch x
->
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
5767 List.fold tel ~
init:env ~f
:(fun env (ty, pos, _) ->
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 )
5778 | unsafe_cast
when String.equal unsafe_cast
SN.PseudoFunctions.unsafe_cast
5782 Int.(List.length el
= 1)
5783 && TypecheckerOptions.ignore_unsafe_cast
(Env.get_tcopt
env)
5785 let original_expr = List.hd_exn el
in
5786 expr env original_expr
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
5797 let dflt_ty = MakeType.err
Reason.none
in
5801 ~
default:(Tast.make_typed_expr fpos
dflt_ty Aast.Null
)
5802 and (ty_from
, ty_to
) =
5804 | (ty_from
, _) :: (ty_to
, _) :: _ -> (ty_from
, ty_to
)
5805 | (ty, _) :: _ -> (ty, ty)
5806 | _ -> (dflt_ty, dflt_ty)
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
->
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
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
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 () ->
5866 ^
Typing_print.error ~ignore_dynamic
:true env ty)
5869 checked_unset_error p
[];
5872 let should_forget_fakes = false in
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` *)
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 =
5901 if List.length
el > 1 then
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
) ->
5916 List.map_env
env tyl ~f
:get_array_filter_return_type
5918 Typing_union.union_list
env r tyl
5919 | (r, Tintersection 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)
5927 let (env, tk) = Env.fresh_type
env p
in
5928 let (env, tv) = Env.fresh_type
env p
in
5931 let keyed_container_type =
5932 MakeType.keyed_container
Reason.Rnone
tk tv
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))
5946 let container_type = MakeType.container
Reason.Rnone
tv in
5947 let (_, p
, _) = x in
5953 (Errors.unify_error_at p
)
5955 let (env, tv) = get_value_type env tv in
5959 (explain_array_filter (MakeType.arraykey r))
5961 (fun _ -> (env, res
)))
5963 let (env, rty) = get_array_filter_return_type env ty in
5965 map_ty
fty ~f
:(function
5966 | Tfun
ft -> Tfun
{ ft with ft_ret
= MakeType.unenforced
rty }
5969 let should_forget_fakes = false in
5973 (Tast.make_typed_expr fpos
fty (Aast.Id
id))
5976 typed_unpack_element
5979 (result, should_forget_fakes)
5980 (* Special function `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
5989 | (_, p
, String cst
) ->
5990 (* find the class constant implicitly defined by the typeconst *)
5993 | (_, _, Class_const
(cid, (_, x)))
5994 | (_, _, Class_get
(cid, CGstring
(_, x), _))
5995 when String.equal
x SN.Members.mClass
->
5998 let (_, p1
, _) = e1
in
6001 let result = class_const ~incl_tc
:true env p
(cid, (p
, cst
)) in
6002 (result, should_forget_fakes)
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` *)
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
6034 | (r, Tvarray
_) -> (env, (fun env tr
-> (env, MakeType.varray
r tr
)))
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)
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)
6055 List.map_env
env builders ~f
:(fun env f
-> f
env tr
)
6057 Typing_intersection.intersect_list
env r tyl
)
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
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
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
6086 (Errors.unify_error_at
pos)
6089 (fun env tr
-> (env, MakeType.darray
r (MakeType.arraykey r) tr
))
6094 (fun () -> try_vector env)
6097 (fun () -> try_keyed_container env)
6100 (fun () -> try_container env)
6102 (env, (fun env _ -> (env, Typing_utils.mk_tany
env p
))))))
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
6113 match get_varray_inst funty
.ft_ret
.et_type
with
6114 | None
-> (env, fty)
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 }))
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
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
->
6143 (* Special function `Shapes::idx` *)
6144 | idx
when String.equal idx
SN.Shapes.idx
->
6152 (fun env fty res
el ->
6155 let (env, _ts
, shape_ty
) = expr env shape
in
6156 let (_, shape_pos
, _) = shape
in
6163 ~fun_pos
:(get_reason
fty)
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
6174 (Some
(default_pos
, default_ty
))
6176 ~fun_pos
:(get_reason
fty)
6179 (* Special function `Shapes::at` *)
6180 | at
when String.equal at
SN.Shapes.at
->
6188 (fun env _fty res
el ->
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
6195 (* Special function `Shapes::keyExists` *)
6196 | key_exists when String.equal
key_exists SN.Shapes.keyExists
->
6204 (fun env fty res
el ->
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
6219 ~fun_pos
:(get_reason
fty)
6224 (* Special function `Shapes::removeKey` *)
6225 | remove_key
when String.equal remove_key
SN.Shapes.removeKey
->
6233 (fun env _ res
el ->
6238 | (_, _, Lvar
(_, lvar
))
6239 | (_, _, Callconv
(Ast_defs.Pinout
, (_, _, Lvar
(_, lvar
))))
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
6252 let (_, shape_pos
, _) = shape
in
6253 Errors.invalid_shape_remove_key shape_pos
;
6257 (* Special function `Shapes::toArray` *)
6258 | to_array
when String.equal to_array
SN.Shapes.toArray
->
6266 (fun env _ res
el ->
6269 let (env, _te
, shape_ty
) = expr env shape
in
6270 Typing_shapes.to_array
env p shape_ty res
6272 (* Special function `Shapes::toDict` *)
6273 | to_dict
when String.equal to_dict
SN.Shapes.toDict
->
6281 (fun env _ res
el ->
6284 let (env, _te
, shape_ty
) = expr env shape
in
6285 Typing_shapes.to_dict
env p shape_ty 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
6299 (Tast.make_typed_expr
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
6316 match nullflavor
with
6317 | OG_nullthrows
-> None
6318 | OG_nullsafe
-> Some p
6320 let (_, p1
, _) = e1
in
6321 let (env, (tfty
, tal
)) =
6327 ~
nullsafe:(Option.map ~f
:(fun p
-> Reason.Rnullsafe_op p
) nullsafe)
6328 ~coerce_from_ty
:None
6330 ~class_id
:(CIexpr e1
)
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
6343 (Tast.make_typed_expr
6348 Tast.make_typed_expr pos_id tfty
(Aast.Id m
),
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) ->
6360 Typecheck `Obj_get` by enforcing that:
6361 - `<instance_type>` <: `Thas_member(m, #1)`
6362 where #1 is a fresh type variable.
6364 let (env, typed_receiver
, receiver_ty
) =
6365 expr ~accept_using_var
:true env receiver
6367 let env = might_throw env in
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
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)
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
6406 (LoclType receiver_ty
)
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. *)
6417 match get_var method_ty
with
6419 Typing_solver.solve_to_equal_bound_or_wrt_variance
env Reason.Rnone var
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 *)
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
)
6448 (Tast.make_typed_expr
6453 Tast.make_typed_expr pos_id method_ty
(Aast.Id
meth),
6458 typed_unpack_element
6461 (result, should_forget_fakes)
6462 (* Function invocation *)
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
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
6481 let (env, te, fty) = expr env e in
6483 Typing_solver.expand_type_and_solve
6484 ~description_of_expected
:"a function value"
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
6497 (* tal: no type arguments to function values, as they are non-generic *)
6500 typed_unpack_element
6503 (result, should_forget_fakes)
6509 ?
(explicit_targs
= [])
6511 ?
(is_function_pointer
= false)
6516 let (env, this_ty) =
6518 this_for_method
env cid cty
6529 ~is_function_pointer
6541 ?is_function_pointer
6546 let (env, tys
, err_res_opt
) =
6553 ?is_function_pointer
6560 match err_res_opt
with
6564 | Some
(Error
(ty_actual
, ty_expect
)) -> Some
(ty_actual
, ty_expect
)
6574 ?is_function_pointer
6586 ?is_function_pointer
6599 ?
(explicit_targs
= [])
6601 ?
(is_function_pointer
= false)
6603 ((_, cid_pos
, cid_
) as cid)
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
) =
6622 ~is_function_pointer
6628 (env, pair
:: pairs, err
:: errs
))
6630 let err_res_opt = Option.(map ~f
:union_coercion_errs @@ all err_res_opts
) in
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 ->
6645 ~is_function_pointer
6652 Option.(map ~f
:intersect_coercion_errs @@ all err_res_opts
)
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)) ->
6667 ~is_function_pointer
6672 | (r, Tgeneric
_) ->
6674 TUtils.get_concrete_supertypes ~abstract_enum
:true env cty
6676 if List.is_empty tyl
then begin
6677 Errors.non_class_member
6681 (Typing_print.error env cty
)
6683 (env, (err_witness env p
, []), dflt_err)
6685 let (env, ty) = Typing_intersection.intersect_list
env r tyl
in
6693 ~is_function_pointer
6698 | (_, Tclass
((_, c), _, paraml
)) ->
6699 let class_ = Env.get_class
env c in
6701 | None
-> (env, (Typing_utils.mk_tany
env p
, []), dflt_err)
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 *)
6708 empty_expand_env
with
6710 substs
= TUtils.make_locl_subst_for_class_tparams
class_ paraml
;
6713 let get_smember_from_constraints env class_info =
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
6731 ~is_function_pointer
6737 let try_get_smember_from_constraints env class_info =
6738 Errors.try_with_error
6739 (fun () -> get_smember_from_constraints env class_info)
6741 TOG.smember_not_found
6745 ~is_function_pointer
6749 (env, (TUtils.terr
env Reason.Rnone
, []), dflt_err))
6754 Env.get_const
env class_ mid
6756 match Env.get_typeconst
env class_ mid
with
6758 Errors.illegal_typeconst_direct_access p
;
6760 | None
-> Env.get_const
env class_ mid
6763 | None
when Cls.has_upper_bounds_on_this_from_constraints
class_ ->
6764 try_get_smember_from_constraints env class_
6766 TOG.smember_not_found
6770 ~is_function_pointer
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
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)
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_
6796 TOG.smember_not_found
6800 ~is_function_pointer
6804 (env, (TUtils.terr
env Reason.Rnone
, []), dflt_err)
6807 ce_visibility = vis
;
6808 ce_type
= (lazy member_decl_ty
);
6812 let def_pos = get_pos member_decl_ty
in
6813 TVis.check_class_access
6817 (vis
, get_ce_lsb ce
)
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
6832 ~use_name
:(strip_ns mid
)
6835 (List.map ~f
:snd explicit_targs
)
6838 Typing_enforceability.compute_enforced_and_pessimize_fun_type
6846 { use_name
= strip_ns mid
; use_pos = p
; explicit_targs
}
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
)
6863 let { et_type
; et_enforced
} =
6864 Typing_enforceability.compute_enforced_and_pessimize_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
) =
6877 (fun () -> (get_smember_from_constraints env class_, true))
6879 (* No eligible functions found in constraints *)
6880 ((env, (MakeType.mixed Reason.Rnone
, []), dflt_err), false))
6883 Inter.intersect
env ~
r:(Reason.Rwitness p
) member_ty member_ty'
6889 let (env, err_res_opt) =
6890 match coerce_from_ty
with
6891 | None
-> (env, None
)
6892 | Some
(p
, ur, ty) ->
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
}
6904 (env, (member_ty
, tal
), err_res_opt)))
6905 | (_, Tunapplied_alias
_) ->
6906 Typing_defs.error_Tunapplied_alias_in_illegal_context
()
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
6915 (Typing_print.error env 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
) =
6924 ~check_targs_well_kinded
:true
6925 ~check_explicit_targs
:true
6931 (* Need to deal with union case *)
6932 let rec get_info res tyl
=
6934 | [] -> (env, tal
, te, res
)
6936 (match get_node
ty with
6938 | Tintersection tyl'
->
6939 get_info res
(tyl'
@ tyl
)
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
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
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.
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
6987 * Thus C::get() will return a type C, while $c::get() will return the same
6990 and this_for_method
env (_, p
, cid) default_ty
=
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
7007 ?
(check_targs_well_kinded
= false)
7009 ?
(check_explicit_targs
= false)
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
7017 (match Env.get_self_id
env with
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
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
)
7035 match Env.get_parent_ty
env with
7037 Errors.parent_undefined p
;
7038 mk
(Reason.none
, Typing_defs.make_tany
())
7039 | Some
parent -> 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)
7048 match Env.get_parent_ty
env with
7050 Errors.parent_undefined p
;
7051 mk
(Reason.none
, Typing_defs.make_tany
())
7052 | Some
parent -> 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)
7061 if Option.is_some
(Env.next_cont_opt
env) then
7062 MakeType.this (Reason.Rwitness p
)
7064 MakeType.nothing (Reason.Rwitness p
)
7066 make_result env [] Aast.CIstatic
this
7069 match Env.get_self_class_type
env with
7070 | Some
(c, _, tyl
) -> mk
(Reason.Rwitness p
, Tclass
(c, exact
, tyl
))
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) ->
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
7083 Typing_kinding_defs.Simple.get_named_parameter_kinds
simple_kind
7086 Phase.localize_targs_with_kinds
7087 ~check_well_kinded
:check_targs_well_kinded
7091 ~use_name
:(strip_ns
(snd
c))
7092 ~check_explicit_targs
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
7102 (* Not a type parameter *)
7103 let class_ = Env.get_class
env id in
7105 | None
-> make_result env [] (Aast.CI
c) (Typing_utils.mk_tany
env p
)
7107 TVis.check_classname_access ~
use_pos:p ~in_signature
:false env class_;
7108 let (env, ty, tal
) =
7110 |> Phase.localize_targs_and_check_constraints
7112 ~check_well_kinded
:check_targs_well_kinded
7113 ~
def_pos:(Cls.pos class_)
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 =
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
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
)
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
()
7156 ( Tany
_ | Tnonnull
| Tvarray
_ | Tdarray
_ | Tvarray_or_darray
_
7157 | Tvec_or_dict
_ | Toption
_ | Tprim
_ | Tfun
_ | Ttuple
_
7158 | Tnewtype
_ | Tdependent
_ | Tobject
| Tshape
_ | Taccess
_ | Tneg
_
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
=
7170 if Nast.equal_class_id_
cid CIparent
then
7171 MakeType.this (Reason.Rwitness p
)
7177 empty_expand_env
with
7179 substs
= TUtils.make_locl_subst_for_class_tparams
class_ params;
7180 on_error
= Errors.unify_error_at p
;
7184 Phase.check_where_constraints
7187 ~definition_pos
:(Cls.pos class_)
7190 (Cls.where_constraints
class_)
7192 let cstr = Env.get_construct
env class_ in
7193 let mode = Env.get_mode
env in
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_
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 *)
7211 let r = get_reason m
|> Typing_reason.localize
in
7212 match get_node m
with
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
7227 ~use_name
:"constructor"
7237 use_name
= "constructor";
7239 explicit_targs
= implicit_constructor_targs
;
7246 (env, mk
(r, Tfun
ft))
7248 Errors.internal_error p
"Expected function type for constructor";
7249 let ty = TUtils.terr
env r in
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) =
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
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.
7281 ~
(expected : ExpectedTy.t
option)
7282 ?
(nullsafe : Pos.t
option = None
)
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))
7300 Typing_intersection.intersect_list
env (get_reason
fty) tyl
7303 if TypecheckerOptions.method_call_inference
(Env.get_tcopt
env) then
7304 Env.expand_type
env fty
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
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
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
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
7337 let (env, err_opt) =
7339 ~ok
:(fun env -> (env, None
))
7340 ~
error:(fun env -> (env, Some
(e_ty
, ty)))
7341 @@ Typing_coercion.coerce_type_res
7347 Typing_defs_core.et_type
= ty;
7348 Typing_defs_core.et_enforced
= Unenforced
;
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))
7359 | Tprim Tnull
-> Option.is_some
nullsafe
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)
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
7378 ~ok
:(fun env -> (env, None
))
7379 ~
error:(fun env -> (env, Some
(ty, efty
)))
7380 @@ Typing_coercion.coerce_type_res
7385 (MakeType.unenforced efty
)
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
7401 (env, hole_on_err ~
err_opt te))
7403 let env = call_untyped_unpack
env (Reason.to_pos
r) unpacked_element
in
7406 | Tprim Tnull
-> mk
(r, Tprim Tnull
)
7407 | Tdynamic
-> MakeType.dynamic
(Reason.Rdynamic_call
pos)
7410 Typing_utils.mk_tany
env pos
7412 | _ (* _ should not happen! *) ->
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
) ->
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
) ->
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))
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 *)
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) =
7474 let get_next_param_info paraml
=
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
->
7483 | Tgeneric
(name, _) ->
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
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
7509 match ITySet.choose
lower_bounds with
7510 | ConstraintType
_ -> None
7512 (match get_node lower
with
7513 | Tclass
((_, enum_name), _, _)
7514 when Env.is_enum_class
env enum_name ->
7519 (* Already reported, see Typing_type_wellformedness *)
7522 let check_arg env ((_, pos, arg
) as e) opt_param ~is_variadic
=
7523 match opt_param
with
7525 (* First check if __ViaLabel is used or if the parameter is
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
7533 match get_node
ety with
7534 | Tnewtype
(name, _, _) ->
7535 String.equal
SN.Classes.cEnumClassLabel
name
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
->
7545 (match compute_enum_name env ty_enum
with
7546 | None
-> (env, EnumClassLabelOps.ClassNotFound
)
7548 EnumClassLabelOps.expand
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
)
7570 match label_type
with
7571 | EnumClassLabelOps.Success
(te, ty)
7572 | EnumClassLabelOps.LabelNotFound
(te, ty) ->
7576 ExpectedTy.make_and_allow_coercion_opt
7583 ~accept_using_var
:(get_fp_accept_disposable
param)
7588 let (env, err_opt) = call_param env param (e, ty) ~is_variadic
in
7589 (env, Some
(hole_on_err ~
err_opt te, ty))
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
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; _ } ->
7609 ~f
:(fun env param ->
7610 Env.set_tyvar_variance
env param.fp_type
.et_type
)
7613 Env.set_tyvar_variance
env ft_ret.et_type ~flip
:true
7616 set_params_variance env param.fp_type
.et_type
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
=
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
7631 check_arg env e opt_param ~is_variadic
7633 let env = set_tyvar_variance_from_lambda_param env opt_param
in
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 =
7645 Typing_coeffects.get_type
ft.ft_implicit_params
.capability
7647 if not
(TypecheckerOptions.call_coeffects
(Env.get_tcopt
env)) then
7650 let env_capability =
7651 Env.get_local_check_defined
env (pos, Typing_coeffects.capability_id
)
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. *)
7672 Typing_coeffects.get_type
ft.ft_implicit_params
.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 *)
7690 | None
-> failwith
"missing parameter in check_args"
7693 let l = List.map rl ~f
:(fun (_, opt
) -> get_param opt
) in
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)
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 {
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
7724 let destructure_ty =
7727 ( Reason.Runpack_param
(p1
, pos_def, consumed),
7733 d_kind
= SplatUnpack
;
7736 let (env, te, ty) = expr env e in
7737 (* Populate the type variables from the expression in the splat *)
7750 (* Our type cannot be destructured, add a hole with `nothing`
7754 @@ Reason.Rsolve_fail
(Pos_or_decl.of_raw_pos
pos)
7756 (env, mk_hole te ~ty_have
:ty ~
ty_expect)
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
) =
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
) =
7773 ~
init:(env, err_opts
)
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
7789 match (List.filter_map ~f
:Fn.id err_opts
, var_err_opt
) with
7792 let (_, pos, _) = te in
7795 ~
err_opt:(Some
(ty, pack_errs pos ty subtyping_errs))
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))
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
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 =
7832 (* Keep supertype as permissive as possible: *)
7834 ~
mode:FPnormal
(* TODO: deal with `inout` parameters *)
7835 ~accept_disposable
:false (* TODO: deal with disposables *)
7843 fp_pos
= Pos_or_decl.of_raw_pos
pos;
7845 fp_type
= MakeType.enforced ty;
7850 match type_of_unpacked_element
with
7851 | Some type_of_unpacked
->
7852 let fun_param = mk_fun_param type_of_unpacked
in
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 =
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
7871 | Some
r -> MakeType.awaitable
r return_ty
7873 let ft_ret = MakeType.enforced return_ty in
7875 (* Keep supertype as permissive as possible: *)
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
7887 ft_where_constraints;
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
)
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))
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. *)
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
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
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
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
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) ->
7967 if Ast_defs.(equal_bop
op Diff
) then
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 *)
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
7986 (env, Local_id.Set.empty
)
7987 (* Conjunction of conditions. Matches the two following forms:
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` *)
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:
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
) =
8012 (* Either cond1 is true and we don't know anything about cond2... *)
8013 condition env tparamet e1
)
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` *)
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
8041 Aast.Class_const
((_, _, Aast.CI
(_, class_name)), (_, method_name
))
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
))
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
8078 refine_type env hint_ty
8081 | _ -> (env, Local_id.Set.empty
)
8083 and string2
env idl
=
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
8092 let r = Reason.Rinterp_operand p
in
8093 let (env, formatter_tyvar
) = Env.fresh_type_invariant
env p
in
8098 MakeType.arraykey r;
8100 MakeType.new_type
r SN.Classes.cHHFormatString
[formatter_tyvar
];
8103 let (env, err_opt) =
8105 ~ok
:(fun env -> (env, None
))
8106 ~
error:(fun env -> (env, Some
(ty, stringlike)))
8107 @@ Typing_ops.sub_type_res
8113 Errors.strict_str_interp_type_mismatch
8115 (env, hole_on_err ~
err_opt te :: tel
)
8117 let env = Typing_substring.sub_string p
env ty in
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
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
8143 Aast.fa_user_attributes
= user_attributes
;
8144 Aast.fa_namespace
= fa
.fa_namespace
;
8147 and type_param
env t
=
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
8157 Aast.tp_variance
= t
.tp_variance
;
8158 Aast.tp_name
= t
.tp_name
;
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
)) =
8175 ~coerce_from_ty
:None
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
8187 map_ty
fty ~f
:(function
8188 | Tfun
ft -> Tfun
{ ft with ft_ret = MakeType.unenforced
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 =
8197 | `lvalue_subexpr
->
8198 let (env, te1, ty1
) =
8200 ~
valkind:`lvalue_subexpr
8204 ~
allow_awaitable:(*?*) false
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
8213 | _ -> (env, te1, ty1
)
8215 | _ -> raw_expr ?lhs_of_null_coalesce
env e1 ~
allow_awaitable:(*?*) false
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)
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
8234 (Naming_attributes_params.get_module_attribute typedef
.t_user_attributes
)
8237 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
8239 ~ignore_errors
:false
8243 Typing_type_wellformedness.typedef
env typedef
;
8244 Typing_variance.typedef
env typedef
;
8247 t_name
= (t_pos
, t_name
);
8249 t_constraint
= tcstr
;
8251 t_user_attributes
= _;
8262 Phase.localize_hint_no_subst
8264 ~ignore_errors
:false
8265 ~report_cycle
:(t_pos
, t_name
)
8272 Phase.localize_hint_no_subst
env ~ignore_errors
:false tcstr
8276 Reason.URnewtype_cstr
8280 Errors.newtype_alias_must_satisfy_constraint
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
)
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
;