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 C
= Typing_continuations
43 module Try
= Typing_try
44 module FL
= FeatureLogging
45 module MakeType
= Typing_make_type
46 module Cls
= Decl_provider.Class
47 module Fake
= Typing_fake_members
48 module ExpectedTy
= Typing_helpers.ExpectedTy
49 module ITySet
= Internal_type_set
51 type newable_class_info
=
55 * [ `Class
of pos_id
* Cls.t
* locl_ty
| `Dynamic
] list
57 (*****************************************************************************)
59 (*****************************************************************************)
61 (* A guess as to the last position we were typechecking, for use in debugging,
62 * such as figuring out what a runaway hh_server thread is doing. Updated
63 * only best-effort -- it's an approximation to point debugging in the right
64 * direction, nothing more. *)
65 let debug_last_pos = ref Pos.none
67 let debug_print_last_pos _
=
69 "Last typecheck pos: %s"
70 (Pos.string (Pos.to_absolute
!debug_last_pos))
72 (*****************************************************************************)
74 (*****************************************************************************)
76 let mk_hole ?
(source
= Aast.Typing
) ((_
, pos
, _
) as expr
) ~ty_have ~ty_expect
=
77 if equal_locl_ty ty_have ty_expect
then
80 (* if the hole is generated from typing, we leave the type unchanged,
81 if it is a call to `[unsafe|enforced]_cast`, we give it the expected type
85 | Aast.Typing
-> ty_have
90 make_typed_expr pos
ty_hole @@ Aast.Hole
(expr
, ty_have
, ty_expect
, source
)
92 let hole_on_err (te
: Tast.expr
) ~err_opt
=
93 Option.value_map err_opt ~default
:te ~f
:(fun (ty_have
, ty_expect
) ->
94 mk_hole te ~ty_have ~ty_expect
)
96 (* When typing compound assignments we generate a 'fake' expression which
97 desugars it to the operation on the rhs of the assignment. If there
98 was a subtyping error, we end up with the Hole on the fake rhs
99 rather than the original rhs. This function rewrites the
100 desugared expression with the Hole in the correct place *)
101 let resugar_binop expr
=
109 (_
, _
, Hole
((_
, _
, Binop
(op
, _
, te2
)), ty_have
, ty_expect
, source
))
111 let hte2 = mk_hole te2 ~ty_have ~ty_expect ~source
in
112 let te = Aast.Binop
(Ast_defs.Eq
(Some op
), te1
, hte2) in
114 | (topt
, p
, Aast.Binop
(_
, te1
, (_
, _
, Aast.Binop
(op
, _
, te2
)))) ->
115 let te = Aast.Binop
(Ast_defs.Eq
(Some op
), te1
, te2
) in
119 (* When recording subtyping or coercion errors for union and intersection types
120 we need to look at the error for each element and then reconstruct any
121 errors into a union or intersection. If there were no errors for any
122 element, the result if also `Ok`; if there was an error for at least
123 on element we have `Error` with list of actual and expected types *)
124 let fold_coercion_errs errs
=
125 List.fold_left errs ~init
:(Ok
[]) ~f
:(fun acc err
->
126 match (acc
, err
) with
127 | (Ok xs
, Ok x
) -> Ok
(x
:: xs
)
128 | (Ok xs
, Error
(x
, y
)) -> Error
(x
:: xs
, y
:: xs
)
129 | (Error
(xs
, ys
), Ok x
) -> Error
(x
:: xs
, x
:: ys
)
130 | (Error
(xs
, ys
), Error
(x
, y
)) -> Error
(x
:: xs
, y
:: ys
))
132 let union_coercion_errs errs
=
134 ~ok
:(fun tys
-> Ok
(MakeType.union
Reason.Rnone tys
))
135 ~error
:(fun (acts
, exps
) ->
136 Error
(MakeType.union
Reason.Rnone acts
, MakeType.union
Reason.Rnone exps
))
137 @@ fold_coercion_errs errs
139 let intersect_coercion_errs errs
=
141 ~ok
:(fun tys
-> Ok
(MakeType.intersection
Reason.Rnone tys
))
142 ~error
:(fun (acts
, exps
) ->
144 ( MakeType.intersection
Reason.Rnone acts
,
145 MakeType.intersection
Reason.Rnone exps
))
146 @@ fold_coercion_errs errs
148 (** Given the type of an argument that has been unpacked and typed against
149 positional and variadic function parameter types, apply the subtyping /
150 coercion errors back to the original packed type. *)
151 let pack_errs pos ty subtyping_errs
=
153 MakeType.nothing @@ Reason.Rsolve_fail
(Pos_or_decl.of_raw_pos pos
)
155 let rec aux ~k
= function
156 (* Case 1: we have a type error at this positional parameter so
157 replace the type parameter which caused it with the expected type *)
158 | ((Some
(_
, ty
) :: rest
, var_opt
), _
:: tys
)
159 (* Case 2: there was no type error here so retain the original type
161 | ((None
:: rest
, var_opt
), ty
:: tys
) ->
162 (* recurse for any remaining positional parameters and add the
163 corrected (case 1) or original (case 2) type to the front of the
164 list of type parameters in the continuation *)
165 aux ((rest
, var_opt
), tys
) ~k
:(fun tys
-> k
(ty
:: tys
))
166 (* Case 3: we have a type error at the variadic parameter so replace
167 the type parameter which cased it with the expected type *)
168 | ((_
, (Some
(_
, ty
) as var_opt
)), _
:: tys
) ->
169 (* recurse with the variadic parameter error and add the
170 corrected type to the front of the list of type parameters in the
172 aux (([], var_opt
), tys
) ~k
:(fun tys
-> k
(ty
:: tys
))
173 (* Case 4: we have a variadic parameter but no error - we're done so
174 pass the remaining unchanged type parameters into the contination
175 to rebuild corrected type params in the right order *)
176 | ((_
, None
), tys
) -> k tys
177 (* Case 5: no more type parameters - again we're done so pass empty
178 list to continuation and rebuild corrected type params in the right
182 (* The only types that _can_ be upacked are tuples and pairs; match on the
183 type to get the type parameters, pass them to our recursive function
184 aux to subsitute the expected type where we have a type error
185 then reconstruct the type in the continuation *)
188 aux (subtyping_errs
, tys
) ~k
:(fun tys
-> mk
(r
, Ttuple tys
))
189 | (r
, Tclass
(pos_id
, exact
, tys
)) ->
190 aux (subtyping_errs
, tys
) ~k
:(fun tys
->
191 mk
(r
, Tclass
(pos_id
, exact
, tys
)))
194 let err_witness env p
= TUtils.terr env
(Reason.Rwitness p
)
196 let triple_to_pair (env
, te, ty
) = (env
, (te, ty
))
198 let with_special_coeffects env cap_ty unsafe_cap_ty f
=
200 Option.map
(Env.next_cont_opt env
) ~f
:(fun next_cont
->
201 let initial_locals = next_cont
.Typing_per_cont_env.local_types
in
202 let tpenv = Env.get_tpenv env
in
203 (initial_locals, tpenv))
205 Typing_lenv.stash_and_do env
(Env.all_continuations env
) (fun env
->
209 | Some
(initial_locals, tpenv) ->
210 let env = Env.reinitialize_locals
env in
211 let env = Env.set_locals
env initial_locals in
212 let env = Env.env_with_tpenv
env tpenv in
216 Typing_coeffects.register_capabilities
env cap_ty unsafe_cap_ty
220 (* Set all the types in an expression to the given type. *)
221 let with_type ty
env (e
: Nast.expr
) : Tast.expr
=
226 method! on_expr
env ((), p
, expr_
) = (ty
, p
, self#on_expr_
env expr_
)
228 method on_'ex _
() = ty
230 method on_'en _ _
= env
235 let invalid_expr_ env p
: Tast.expr_
=
236 let expr = ((), p
, Naming.invalid_expr_ p
) in
237 let ty = TUtils.terr
env Reason.Rnone
in
238 let (_
, _
, expr_
) = with_type ty Tast.dummy_saved_env
expr in
241 let expr_error env (r
: Reason.t
) (e
: Nast.expr) =
242 let ty = TUtils.terr
env r
in
243 (env, with_type ty Tast.dummy_saved_env e
, ty)
245 let expr_any env p e
=
246 let ty = Typing_utils.mk_tany
env p
in
247 (env, with_type ty Tast.dummy_saved_env e
, ty)
249 let unbound_name env (pos
, name
) e
=
250 match Env.get_mode
env with
251 | FileInfo.Mstrict
->
252 Errors.add_typing_error
253 Typing_error.(primary
@@ Primary.Unbound_name
{ pos
; name
});
254 expr_error env (Reason.Rwitness pos
) e
255 | FileInfo.Mhhi
-> expr_any env pos e
257 (* Is this type Traversable<vty> or Container<vty> for some vty? *)
258 let get_value_collection_inst env ty =
259 match get_node
ty with
260 | Tclass
((_
, c
), _
, [vty
])
261 when String.equal c
SN.Collections.cTraversable
262 || String.equal c
SN.Collections.cContainer
->
264 (* If we're expecting a mixed or a nonnull then we can just assume
265 * that the element type is mixed *)
266 | Tnonnull
-> Some
(MakeType.mixed
(get_reason
ty))
268 | Tdynamic
when env.in_support_dynamic_type_method_check
->
269 Some
ty (* interpret dynamic as Traversable<dynamic> *)
272 (* Is this type KeyedTraversable<kty,vty>
273 * or KeyedContainer<kty,vty>
276 let get_key_value_collection_inst env p
ty =
277 match get_node
ty with
278 | Tclass
((_
, c
), _
, [kty
; vty
])
279 when String.equal c
SN.Collections.cKeyedTraversable
280 || String.equal c
SN.Collections.cKeyedContainer
->
282 (* If we're expecting a mixed or a nonnull then we can just assume
283 * that the key type is arraykey and the value type is mixed *)
285 let arraykey = MakeType.arraykey (Reason.Rkey_value_collection_key p
) in
286 let mixed = MakeType.mixed (Reason.Rwitness p
) in
287 Some
(arraykey, mixed)
288 | Tany _
-> Some
(ty, ty)
289 | Tdynamic
when env.in_support_dynamic_type_method_check
->
290 (* interpret dynamic as KeyedTraversable<arraykey, dynamic> *)
291 let arraykey = MakeType.arraykey (Reason.Rkey_value_collection_key p
) in
295 (* Is this type varray<vty> or a supertype for some vty? *)
296 let vc_kind_to_supers kind
=
298 | Vector
-> [SN.Collections.cVector
; SN.Collections.cMutableVector
]
299 | ImmVector
-> [SN.Collections.cImmVector
; SN.Collections.cConstVector
]
300 | Vec
-> [SN.Collections.cVec
]
301 | Set
-> [SN.Collections.cSet
; SN.Collections.cMutableSet
]
302 | ImmSet
-> [SN.Collections.cImmSet
; SN.Collections.cConstSet
]
303 | Keyset
-> [SN.Collections.cKeyset
]
305 let kvc_kind_to_supers kind
=
307 | Map
-> [SN.Collections.cMap
; SN.Collections.cMutableMap
]
308 | ImmMap
-> [SN.Collections.cImmMap
; SN.Collections.cConstMap
]
309 | Dict
-> [SN.Collections.cDict
]
311 (* Is this type one of the value collection types with element type vty? *)
312 let get_vc_inst env vc_kind
ty =
313 let classnames = vc_kind_to_supers vc_kind
in
314 match get_node
ty with
315 | Tclass
((_
, c
), _
, [vty
]) when List.exists
classnames ~f
:(String.equal c
) ->
317 | _
-> get_value_collection_inst env ty
319 (* Is this type one of the three key-value collection types
320 * e.g. dict<kty,vty> or a supertype for some kty and vty? *)
321 let get_kvc_inst env p kvc_kind
ty =
322 let classnames = kvc_kind_to_supers kvc_kind
in
323 match get_node
ty with
324 | Tclass
((_
, c
), _
, [kty
; vty
])
325 when List.exists
classnames ~f
:(String.equal c
) ->
327 | _
-> get_key_value_collection_inst env p
ty
329 (* Check whether this is a function type that (a) either returns a disposable
330 * or (b) has the <<__ReturnDisposable>> attribute
332 let is_return_disposable_fun_type env ty =
333 let (_env
, ty) = Env.expand_type
env ty in
334 match get_node
ty with
336 get_ft_return_disposable ft
338 (Typing_disposable.is_disposable_type
env ft
.ft_ret
.et_type
)
341 (* Turn an environment into a local_id_map suitable to be embedded
342 * into an AssertEnv statement
345 match Env.next_cont_opt
env with
346 | Some
{ Typing_per_cont_env.local_types
; _
} ->
347 Some
(Local_id.Map.map
(fun (ty, pos
, _expr_id
) -> (pos
, ty)) local_types
)
350 (* Similar to annot_map above, but filters the map to only contain
351 * information about locals in lset
353 let refinement_annot_map env lset
=
354 match annot_map env with
357 Local_id.Map.filter
(fun lid _
-> Local_id.Set.mem lid lset
) map
359 if Local_id.Map.is_empty
map then
365 let assert_env_blk ~pos ~at annotation_kind env_map_opt blk
=
366 let mk_assert map = (pos
, Aast.AssertEnv
(annotation_kind
, map)) in
367 let annot_blk = Option.to_list
(Option.map ~f
:mk_assert env_map_opt
) in
369 | `Start
-> annot_blk @ blk
370 | `End
-> blk
@ annot_blk
372 let assert_env_stmt ~pos ~at annotation_kind env_map_opt stmt
=
373 let mk_assert map = (pos
, Aast.AssertEnv
(annotation_kind
, map)) in
374 match env_map_opt
with
376 let stmt = (pos
, stmt) in
379 | `Start
-> [mk_assert env_map
; stmt]
380 | `End
-> [stmt; mk_assert env_map
]
385 let set_tcopt_unstable_features env { fa_user_attributes
; _
} =
387 Naming_attributes.find
388 SN.UserAttributes.uaEnableUnstableFeatures
392 | Some
{ ua_name
= _
; ua_params
} ->
393 let ( = ) = String.equal
in
394 List.fold ua_params ~
init:env ~f
:(fun env (_
, _
, feature
) ->
396 | Aast.String s
when s
= SN.UnstableFeatures.ifc
->
397 Env.map_tcopt ~f
:TypecheckerOptions.enable_ifc
env
398 | Aast.String s
when s
= SN.UnstableFeatures.modules
->
399 Env.map_tcopt ~f
:(fun t
-> TypecheckerOptions.set_modules t
true) env
400 | Aast.String s
when s
= SN.UnstableFeatures.expression_trees
->
403 TypecheckerOptions.set_tco_enable_expression_trees t
true)
407 (** Do a subtype check of inferred type against expected type.
408 * The optional coerce_for_op parameter controls whether any arguments of type
409 * dynamic can be coerced to enforceable types because they are arguments to a
412 let check_expected_ty_res
413 ~
(coerce_for_op
: bool)
416 (inferred_ty
: locl_ty
)
417 (expected
: ExpectedTy.t
option) : (env, env) result
=
420 | Some
ExpectedTy.{ pos
= p
; reason
= ur
; ty; coerce
} ->
422 log_with_level
env "typing" ~level
:1 (fun () ->
424 (Pos_or_decl.of_raw_pos p
)
429 "Typing.check_expected_ty %s enforced=%s"
431 (match ty.et_enforced
with
432 | Unenforced
-> "unenforced"
433 | Enforced
-> "enforced"),
435 Log_type
("inferred_ty", inferred_ty
);
436 Log_type
("expected_ty", ty.et_type
);
439 Typing_coercion.coerce_type_res
447 Typing_error.Callback.unify_error
449 let check_expected_ty message
env inferred_ty expected
=
450 Result.fold ~ok
:Fn.id ~error
:Fn.id
451 @@ check_expected_ty_res ~coerce_for_op
:false message
env inferred_ty expected
453 (* Set a local; must not be already assigned if it is a using variable *)
454 let set_local ?
(is_using_clause
= false) env (pos
, x
) ty =
455 if Env.is_using_var
env x
then
456 Errors.add_typing_error
459 (if is_using_clause
then
460 Primary.Duplicate_using_var pos
462 Primary.Illegal_disposable
{ pos
; verb
= `assigned
}));
463 let env = Env.set_local env x
ty pos
in
464 if is_using_clause
then
465 Env.set_using_var
env x
469 (* Require a new construct with disposable *)
470 let rec enforce_return_disposable _env e
=
472 | (_
, _
, New _
) -> ()
473 | (_
, _
, Call _
) -> ()
474 | (_
, _
, Await
(_
, _
, Call _
)) -> ()
475 | (_
, _
, Hole
(e
, _
, _
, _
)) -> enforce_return_disposable _env e
477 Errors.add_typing_error
478 Typing_error.(primary
@@ Primary.Invalid_return_disposable p
)
480 (* Wrappers around the function with the same name in Typing_lenv, which only
481 * performs the move/save and merge operation if we are in a try block or in a
482 * function with return type 'noreturn'.
483 * This enables significant perf improvement, because this is called at every
484 * function of method call, when most calls are outside of a try block. *)
485 let move_and_merge_next_in_catch env =
486 if env.in_try
|| TFTerm.is_noreturn
env then
487 LEnv.move_and_merge_next_in_cont
env C.Catch
489 LEnv.drop_cont
env C.Next
491 let save_and_merge_next_in_catch env =
492 if env.in_try
|| TFTerm.is_noreturn
env then
493 LEnv.save_and_merge_next_in_cont
env C.Catch
497 let might_throw env = save_and_merge_next_in_catch env
500 type res
. env -> (env -> env * res
) -> (env -> env * res
) -> env * res
* res
502 fun env branch1 branch2
->
503 let parent_lenv = env.lenv
in
504 let (env, tbr1
) = branch1
env in
505 let lenv1 = env.lenv
in
506 let env = { env with lenv
= parent_lenv } in
507 let (env, tbr2
) = branch2
env in
508 let lenv2 = env.lenv
in
509 let env = LEnv.union_lenvs
env parent_lenv lenv1 lenv2 in
512 let as_expr env ty1 pe e
=
513 let env = Env.open_tyvars
env pe
in
514 let (env, tv
) = Env.fresh_type
env pe
in
515 let (env, expected_ty
, tk
, tv
) =
518 let tk = MakeType.mixed Reason.Rnone
in
519 (env, MakeType.traversable
(Reason.Rforeach pe
) tv
, tk, tv
)
521 let (env, tk) = Env.fresh_type
env pe
in
522 (env, MakeType.keyed_traversable
(Reason.Rforeach pe
) tk tv
, tk, tv
)
524 let tk = MakeType.mixed Reason.Rnone
in
525 (env, MakeType.async_iterator
(Reason.Rasyncforeach pe
) tv
, tk, tv
)
527 let (env, tk) = Env.fresh_type
env pe
in
529 MakeType.async_keyed_iterator
(Reason.Rasyncforeach pe
) tk tv
,
533 let rec distribute_union env ty =
534 let (env, ty) = Env.expand_type
env ty in
535 match get_node
ty with
538 List.fold tyl ~
init:(env, []) ~f
:(fun (env, errs
) ty ->
539 let (env, err
) = distribute_union env ty in
542 (env, union_coercion_errs errs
)
544 if SubType.is_sub_type_for_union
env ty (MakeType.dynamic
Reason.Rnone
)
551 (Typing_error.Reasons_callback.unify_error_at pe
)
558 (Typing_error.Reasons_callback.unify_error_at pe
)
562 let ur = Reason.URforeach
in
565 ~ok
:(fun env -> (env, Ok
ty))
566 ~error
:(fun env -> (env, Error
(ty, expected_ty
)))
573 Typing_error.Callback.unify_error
578 let (env, err_res
) = distribute_union env ty1
in
582 | Error
(act
, exp
) -> Some
(act
, exp
)
584 let env = Env.set_tyvar_variance
env expected_ty
in
585 (Typing_solver.close_tyvars_and_solve
env, tk, tv
, err_opt)
587 (* These functions invoke special printing functions for Typing_env. They do not
588 * appear in user code, but we still check top level function calls against their
590 let typing_env_pseudofunctions =
592 String.Hash_set.of_list
593 ~growth_allowed
:false
597 hh_expect_equivalent
;
604 let do_hh_expect ~equivalent
env use_pos explicit_targs p tys
=
605 match explicit_targs
with
607 let (env, (expected_ty
, _
)) =
608 Phase.localize_targ ~check_well_kinded
:true env (snd targ
)
610 let right_expected_ty =
611 if TypecheckerOptions.pessimise_builtins
(Env.get_tcopt
env) then
613 (Reason.Renforceable
(get_pos expected_ty
))
626 Reasons_callback.of_primary_error
627 @@ Primary.Hh_expect
{ pos
= p
; equivalent
})
637 Reasons_callback.of_primary_error
638 @@ Primary.Hh_expect
{ pos
= p
; equivalent
})
644 (Errors.add_typing_error
647 @@ Primary.Expected_tparam
648 { pos
= use_pos
; decl_pos
= Pos_or_decl.none
; n
= 1 }));
651 let loop_forever env =
652 (* forever = up to 10 minutes, to avoid accidentally stuck processes *)
654 (* Look up things in shared memory occasionally to have a chance to be
656 match Env.get_class
env "FOR_TEST_ONLY" with
657 | None
-> Unix.sleep
1
660 Utils.assert_false_log_backtrace
661 (Some
"hh_loop_forever was looping for more than 10 minutes")
663 let is_parameter env x
= Local_id.Map.mem x
(Env.get_params
env)
665 let check_escaping_var env (pos
, x
) =
667 if Env.is_using_var
env x
then
668 let open Typing_error.Primary
in
670 (if Local_id.equal x this
then
672 else if is_parameter env x
then
673 Escaping_disposable_param pos
675 Escaping_disposable pos
)
679 Option.iter
err_opt ~f
:(fun err
->
680 Errors.add_typing_error
@@ Typing_error.primary err
)
682 let make_result env p
te ty =
683 (* Set the variance of any type variables that were generated according
684 * to how they appear in the expression type *)
685 let env = Env.set_tyvar_variance
env ty in
686 (env, Tast.make_typed_expr p
ty te, ty)
688 let localize_targ env ta
=
690 let (env, targ
) = Phase.localize_targ ~check_well_kinded
:true env ta
in
691 (env, targ
, ExpectedTy.make
pos Reason.URhint
(fst targ
))
693 let set_function_pointer ty =
694 match get_node
ty with
696 let ft = set_ft_is_function_pointer
ft true in
697 mk
(get_reason
ty, Tfun
ft)
700 let set_readonly_this ty =
701 match get_node
ty with
703 let ft = set_ft_readonly_this
ft true in
704 mk
(get_reason
ty, Tfun
ft)
707 let xhp_attribute_decl_ty env sid obj attr
=
708 let (namepstr
, valpty
) = attr
in
709 let (valp
, valty
) = valpty
in
710 let (env, (declty
, _tal
)) =
721 ~on_error
:Typing_error.Callback.unify_error
725 let ureason = Reason.URxhp
(snd sid
, snd namepstr
) in
728 ~ok
:(fun env -> (env, None
))
729 ~error
:(fun env -> (env, Some
(valty
, declty
)))
730 @@ Typing_coercion.coerce_type_res
735 (MakeType.unenforced declty
)
736 Typing_error.Callback.xhp_attribute_does_not_match_hint
738 (env, declty
, err_opt)
740 let closure_check_param env param
=
741 match hint_of_type_hint param
.param_type_hint
with
744 let hint_pos = fst hty
in
746 Phase.localize_hint_no_subst
env ~ignore_errors
:false hty
748 let paramty = Env.get_local
env (Local_id.make_unscoped param
.param_name
) in
750 Typing_coercion.coerce_type
755 (MakeType.unenforced hty
)
756 Typing_error.Callback.unify_error
760 let stash_conts_for_closure env p is_anon captured f
=
762 if is_anon
&& TypecheckerOptions.any_coeffects
(Env.get_tcopt
env) then
764 (Pos.none
, local_capability_id
) :: (Pos.none
, capability_id
) :: captured)
769 if Env.is_local_defined
env this
&& not
(Env.is_in_expr_tree
env) then
770 (Pos.none
, this
) :: captured
775 Option.map (Env.next_cont_opt
env) ~f
:(fun next_cont
->
778 Env.get_locals
env captured
780 next_cont
.Typing_per_cont_env.local_types
783 Fake.forget
(Env.get_fake_members
env) Reason.(Blame
(p
, BSlambda
))
785 let tpenv = Env.get_tpenv
env in
786 (initial_locals, initial_fakes, tpenv))
788 Typing_lenv.stash_and_do
env (Env.all_continuations
env) (fun env ->
792 | Some
(initial_locals, initial_fakes, tpenv) ->
793 let env = Env.reinitialize_locals
env in
794 let env = Env.set_locals
env initial_locals in
795 let env = Env.set_fake_members
env initial_fakes in
796 let env = Env.env_with_tpenv
env tpenv in
801 let requires_consistent_construct = function
808 (* Caller will be looking for a particular form of expected type
809 * e.g. a function type (when checking lambdas) or tuple type (when checking
810 * tuples). First expand the expected type and elide single union; also
811 * strip nullables, so ?t becomes t, as context will always accept a t if a ?t
814 * If allow_supportdyn is true, then decompose supportdyn<t> and return true to
815 * indicate that the type supports dynamic.
817 * Note: we currently do not generally expand ?t into (null | t), so ~?t is (dynamic | Toption t).
819 let expand_expected_and_get_node
820 ?
(allow_supportdyn
= false) env (expected
: ExpectedTy.t
option) =
821 let rec unbox env ty =
822 match TUtils.try_strip_dynamic
env ty with
823 | Some stripped_ty
->
824 if TypecheckerOptions.enable_sound_dynamic
env.genv
.tcopt
then
825 let (env, opt_ty
) = Typing_dynamic.try_push_like
env stripped_ty
in
827 | None
-> unbox env stripped_ty
829 let dyn = MakeType.dynamic
Reason.Rnone
in
831 SubType.is_sub_type_for_union
832 ~coerce
:(Some
Typing_logic.CoerceToDynamic
)
839 unbox env stripped_ty
841 unbox env stripped_ty
844 match get_node
ty with
845 | Tunion
[ty] -> unbox env ty
846 | Toption
ty -> unbox env ty
847 | Tnewtype
(name
, [ty], _
) when String.equal name
SN.Classes.cSupportDyn
849 let (env, ty, _
) = unbox env ty in
851 | _
-> (env, ty, false)
855 | None
-> (env, None
)
856 | Some
ExpectedTy.{ pos = p
; reason
= ur; ty = { et_type
= ty; _
}; _
} ->
857 let (env, ty) = Env.expand_type
env ty in
858 let (env, uty
, supportdyn
) = unbox env ty in
859 if supportdyn
&& not allow_supportdyn
then
862 (env, Some
(p
, ur, supportdyn
, uty
, get_node uty
))
864 let uninstantiable_error env reason_pos cid c_tc_pos c_name c_usage_pos c_ty
=
867 | CIexpr _
-> Some
(reason_pos
, lazy (Typing_print.error
env c_ty
))
873 @@ Primary.Uninstantiable_class
881 Errors.add_typing_error
err
883 let coerce_to_throwable pos env exn_ty
=
884 let throwable_ty = MakeType.throwable
(Reason.Rthrow
pos) in
885 Typing_coercion.coerce_type
891 { et_type
= throwable_ty; et_enforced
= Enforced
}
892 Typing_error.Callback.unify_error
894 let set_valid_rvalue p
env x
ty =
895 let env = set_local env (p
, x
) ty in
896 (* We are assigning a new value to the local variable, so we need to
897 * generate a new expression id
899 Env.set_local_expr_id
env x
(Ident.tmp
())
901 let is_hack_collection env ty =
902 (* TODO(like types) This fails if a collection is used as a parameter under
903 * pessimization, because ~Vector<int> </: ConstCollection<mixed>. This is the
904 * test we use to see whether to update the expression id for expressions
905 * $vector[0] = $x and $vector[] = $x. If this is false, the receiver is assumed
906 * to be a Hack array which are COW. This approximation breaks down in the presence
907 * of dynamic. It is unclear whether we should change an expression id if the
908 * receiver is dynamic. *)
909 Typing_solver.is_sub_type
912 (MakeType.const_collection
Reason.Rnone
(MakeType.mixed Reason.Rnone
))
914 let check_class_get env p def_pos cid mid ce
(_
, _cid_pos
, e
) function_pointer
=
916 | CIself
when get_ce_abstract ce
->
918 match Env.get_self_id
env with
920 (* at runtime, self:: in a trait is a call to whatever
921 * self:: is in the context of the non-trait "use"-ing
922 * the trait's code *)
924 match Env.get_class
env self
with
925 | Some cls
when Ast_defs.is_c_trait
(Cls.kind cls
) ->
926 (* Ban self::some_abstract_method() in a trait, if the
927 * method is also defined in a trait.
929 * Abstract methods from interfaces are fine: we'll check
930 * in the child class that we actually have an
932 (match Decl_provider.get_class
(Env.get_ctx
env) ce
.ce_origin
with
933 | Some meth_cls
when Ast_defs.is_c_trait
(Cls.kind meth_cls
) ->
934 Errors.add_typing_error
937 @@ Primary.Self_abstract_call
946 (* Ban self::some_abstract_method() in a class. This will
948 Errors.add_typing_error
951 @@ Primary.Self_abstract_call
961 | CIparent
when get_ce_abstract ce
->
962 Errors.add_typing_error
965 @@ Primary.Parent_abstract_call
966 { meth_name
= mid
; pos = p
; decl_pos
= def_pos
})
967 | CI _
when get_ce_abstract ce
&& function_pointer
->
968 Errors.add_typing_error
971 @@ Primary.Abstract_function_pointer
972 { class_name
= cid
; meth_name
= mid
; pos = p
; decl_pos
= def_pos
})
973 | CI _
when get_ce_abstract ce
->
974 Errors.add_typing_error
977 @@ Primary.Classname_abstract_call
978 { class_name
= cid
; meth_name
= mid
; pos = p
; decl_pos
= def_pos
})
979 | CI
(_
, class_name
) when get_ce_synthesized ce
->
980 Errors.add_typing_error
983 @@ Primary.Static_synthetic_method
984 { class_name
; meth_name
= mid
; pos = p
; decl_pos
= def_pos
})
987 (** Given an identifier for a function, find its function type in the
988 * environment and localise it with the input type parameters. If the function
989 * cannot be found, return [Terr].
991 let fun_type_of_id env x tal el
=
992 match Env.get_fun
env (snd x
) with
994 let (env, _
, ty) = unbound_name env x
((), Pos.none
, Aast.Null
) in
1001 fe_support_dynamic_type
;
1006 (match get_node fe_type
with
1010 TypecheckerOptions.pessimise_builtins
(Env.get_tcopt
env)
1012 Typing_special_fun.transform_special_fun_ty
1018 let ety_env = empty_expand_env
in
1020 Phase.localize_targs
1021 ~check_well_kinded
:true
1025 ~use_name
:(strip_ns
(snd x
))
1028 (List.map ~f
:snd tal
)
1031 Typing_enforceability.compute_enforced_and_pessimize_fun_type
env ft
1033 let use_pos = fst x
in
1034 let def_pos = fe_pos
in
1039 { use_name
= strip_ns
(snd x
); use_pos; explicit_targs
= tal
}
1046 Typing_dynamic.relax_method_type
1048 fe_support_dynamic_type
1049 (get_reason fe_type
)
1053 ~f
:Errors.add_typing_error
1054 (TVis.check_deprecated ~
use_pos ~
def_pos fe_deprecated
);
1056 let open Typing_error.Primary.Modules
in
1059 Typing_modules.can_access
1060 ~current
:(Env.get_module
env)
1061 ~target
:(Option.map fe_module ~f
:snd
)
1064 | `Disjoint
(current
, target
) ->
1070 current_module_opt
= Some current
;
1071 target_module
= target
;
1073 | `Outside target
->
1079 current_module_opt
= None
;
1080 target_module
= target
;
1085 Option.iter
err_opt ~f
:(fun err ->
1086 Errors.add_typing_error
@@ Typing_error.modules
err);
1088 | _
-> failwith
"Expected function type")
1091 * Checks if a class (given by cty) contains a given static method.
1093 * We could refactor this + class_get
1095 let class_contains_smethod env cty
(_pos
, mid
) =
1096 let lookup_member ty =
1097 match get_class_type
ty with
1098 | Some
((_
, c
), _
, _
) ->
1099 (match Env.get_class
env c
with
1102 Option.is_some
@@ Env.get_static_member
true env class_ mid
)
1106 TUtils.get_concrete_supertypes ~abstract_enum
:true env cty
1108 List.exists tyl ~f
:lookup_member
1110 (* To be a valid trait declaration, all of its 'require extends' must
1111 * match; since there's no multiple inheritance, it follows that all of
1112 * the 'require extends' must belong to the same inheritance hierarchy
1113 * and one of them should be the child of all the others *)
1114 let trait_most_concrete_req_class trait
env =
1116 (Cls.all_ancestor_reqs trait
)
1120 let (_r
, (_p
, name
), _paraml
) = TUtils.unwrap_class_type
ty in
1123 | Some
(c
, _ty
) -> Cls.has_ancestor c name
1129 let class_ = Env.get_class
env name
in
1132 | Some c
when Ast_defs.is_c_interface
(Cls.kind c
) -> acc
1133 | Some c
when Ast_defs.is_c_trait
(Cls.kind c
) ->
1134 (* this is an error case for which Typing_type_wellformedness spits out
1135 * an error, but does *not* currently remove the offending
1136 * 'require extends' or 'require implements' *)
1138 | Some c
-> Some
(c
, ty)
1142 let check_arity ?
(did_unpack
= false) pos pos_def
ft (arity
: int) =
1143 let exp_min = Typing_defs.arity_min
ft in
1144 if arity
< exp_min then
1145 Errors.add_typing_error
1148 @@ Primary.Typing_too_few_args
1149 { expected
= exp_min; actual
= arity
; pos; decl_pos
= pos_def
});
1150 if get_ft_variadic
ft then
1154 let exp_max = List.length
ft.ft_params
in
1161 if arity > exp_max then
1162 Errors.add_typing_error
1165 @@ Primary.Typing_too_many_args
1166 { expected
= exp_max; actual
= arity; pos; decl_pos
= pos_def
})
1168 let check_lambda_arity lambda_pos
def_pos lambda_ft expected_ft
=
1169 match (get_ft_variadic lambda_ft
, get_ft_variadic expected_ft
) with
1171 let expected = Typing_defs.arity_min expected_ft
in
1172 let actual = Typing_defs.arity_min lambda_ft
in
1174 if actual < expected then
1176 (Typing_error.Primary.Typing_too_few_args
1177 { expected; actual; pos = lambda_pos
; decl_pos
= def_pos })
1178 (* Errors.typing_too_few_args expected_min lambda_min lambda_pos def_pos; *)
1179 else if actual > expected then
1181 (Typing_error.Primary.Typing_too_many_args
1182 { expected; actual; pos = lambda_pos
; decl_pos
= def_pos })
1183 (* Errors.typing_too_many_args expected_minlambda_min lambda_pos def_pos *)
1189 ~f
:Fn.(compose
Errors.add_typing_error
Typing_error.primary
)
1192 (* The variadic capture argument is an array listing the passed
1193 * variable arguments for the purposes of the function body; callsites
1194 * should not unify with it *)
1195 let variadic_param env ft =
1196 if get_ft_variadic
ft then
1197 (env, List.last
ft.ft_params
)
1202 ?
(is_variadic
= false) ({ fp_pos
; _
} as fp
) (_
, pos, _
) param_kind
=
1204 let open Typing_error.Primary
in
1205 match (get_fp_mode fp
, param_kind
) with
1206 | (FPnormal
, Ast_defs.Pnormal
) -> None
1207 | (FPinout
, Ast_defs.Pinout _
) -> None
1208 | (FPnormal
, Ast_defs.Pinout p
) ->
1210 (Inout_annotation_unexpected
1212 pos = Pos.merge p
pos;
1214 param_is_variadic
= is_variadic
;
1217 | (FPinout
, Ast_defs.Pnormal
) ->
1218 Some
(Inout_annotation_missing
{ pos; decl_pos
= fp_pos
})
1221 Option.iter
err_opt ~f
:(fun err ->
1222 Errors.add_typing_error
@@ Typing_error.primary
err)
1224 let split_remaining_params_required_optional ft remaining_params
=
1225 (* Same example as above
1227 * function f(int $i, string $j, float $k = 3.14, mixed ...$m): void {}
1228 * function g((string, float, bool) $t): void {
1232 * `remaining_params` will contain [string, float] and there has been 1 parameter consumed. The min_arity
1233 * of this function is 2, so there is 1 required parameter remaining and 1 optional parameter.
1235 let original_params =
1236 if get_ft_variadic
ft then
1237 List.drop_last_exn
ft.ft_params
1243 ~f
:(fun fp
-> not
(Typing_defs.get_fp_has_default fp
))
1246 let consumed = List.length
original_params - List.length remaining_params
in
1247 let required_remaining = Int.max
(min_arity - consumed) 0 in
1248 let (required_params
, optional_params
) =
1249 List.split_n remaining_params
required_remaining
1251 (consumed, required_params
, optional_params
)
1253 let generate_splat_type_vars
1254 env p required_params optional_params
variadic_param =
1255 let (env, d_required
) =
1256 List.map_env
env required_params ~f
:(fun env _
-> Env.fresh_type
env p
)
1258 let (env, d_optional
) =
1259 List.map_env
env optional_params ~f
:(fun env _
-> Env.fresh_type
env p
)
1261 let (env, d_variadic
) =
1262 match variadic_param with
1263 | None
-> (env, None
)
1265 let (env, ty) = Env.fresh_type
env p
in
1268 (env, (d_required
, d_optional
, d_variadic
))
1270 let strip_dynamic env ty =
1271 let (env, ty) = Env.expand_type
env ty in
1272 match get_node
ty with
1273 | Tdynamic
-> Typing_make_type.nothing (get_reason
ty)
1274 | _
-> Typing_utils.strip_dynamic env ty
1281 (((_
, pos, expr_
) as e
: Nast.expr), arg_ty
)
1282 ~is_variadic
: env * (locl_ty
* locl_ty
) option =
1283 param_modes ~is_variadic param e param_kind
;
1284 (* When checking params, the type 'x' may be expression dependent. Since
1285 * we store the expression id in the local env for Lvar, we want to apply
1290 | Hole
((_
, _
, Lvar _
), _
, _
, _
)
1292 ExprDepTy.make
env ~cid
:(CIexpr e
) arg_ty
1293 | _
-> (env, arg_ty
)
1296 match param_kind
with
1297 | Ast_defs.Pnormal
-> pos
1298 | Ast_defs.Pinout pk_pos
-> Pos.merge pk_pos
pos
1301 if in_supportdyn
then
1302 let dyn_ty = MakeType.dynamic
(get_reason dep_ty
) in
1304 (* If in_supportdyn is set, then the function type is supportdyn<t1 ... tn -> t>
1305 and we are trying to call it as though it were dynamic. Hence all of the
1306 arguments must be subtypes of dynamic, regardless of whether they have
1307 a like to be stripped. *)
1308 Typing_subtype.sub_type
1310 ~coerce
:(Some
Typing_logic.CoerceToDynamic
)
1313 (Typing_error.Reasons_callback.unify_error_at
pos)
1315 (env, strip_dynamic env dep_ty
)
1320 if env.in_support_dynamic_type_method_check
then
1321 Typing_log.log_pessimise_param
env param
.fp_pos param
.fp_name
1324 ~ok
:(fun env -> (env, None
))
1325 ~error
:(fun env -> (env, Some
(dep_ty
, param
.fp_type
.et_type
)))
1326 @@ Typing_coercion.coerce_type_res
1332 Typing_error.Callback.(
1333 (with_side_effect ~
eff unify_error
[@alert
"-deprecated"]))
1335 let bad_call env p
ty =
1336 Errors.add_typing_error
1340 { pos = p
; ty_name
= lazy (Typing_print.error
env ty) })
1342 let rec make_a_local_of ~include_this
env e
=
1344 | (_
, p
, Class_get
((_
, _
, cname
), CGstring
(_
, member_name
), _
)) ->
1345 let (env, local
) = Env.FakeMembers.make_static
env cname member_name p
in
1346 (env, Some
(p
, local
))
1350 ( (((_
, _
, This
) | (_
, _
, Lvar _
)) as obj
),
1351 (_
, _
, Id
(_
, member_name
)),
1354 let (env, local
) = Env.FakeMembers.make
env obj member_name p
in
1355 (env, Some
(p
, local
))
1357 | (_
, _
, Dollardollar x
) ->
1359 | (_
, p
, This
) when include_this
-> (env, Some
(p
, this
))
1360 | (_
, _
, Hole
(e
, _
, _
, _
)) -> make_a_local_of ~include_this
env e
1363 (* This function captures the common bits of logic behind refinement
1364 * of the type of a local variable or a class member variable as a
1365 * result of a dynamic check (e.g., nullity check, simple type check
1366 * using functions like is_int, is_string, is_array etc.). The
1367 * argument refine is a function that takes the type of the variable
1368 * and returns a refined type (making necessary changes to the
1369 * environment, which is threaded through).
1371 * All refinement functions return, in addition to the updated
1372 * environment, a (conservative) set of all the locals that got
1373 * refined. This set is used to construct AssertEnv statmements in
1376 let refine_lvalue_type env ((ty, _
, _
) as te) ~refine
=
1377 let (env, ty) = refine
env ty in
1378 let e = Tast.to_nast_expr
te in
1379 let (env, localopt
) = make_a_local_of ~include_this
:false env e in
1380 (* TODO TAST: generate an assignment to the fake local in the TAST *)
1382 | Some lid
-> (set_local env lid
ty, Local_id.Set.singleton
(snd lid
))
1383 | None
-> (env, Local_id.Set.empty
)
1385 let rec condition_nullity ~nonnull
(env : env) te =
1387 (* assignment: both the rhs and lhs of the '=' must be made null/non-null *)
1388 | (_
, _
, Aast.Binop
(Ast_defs.Eq None
, var
, te)) ->
1389 let (env, lset1
) = condition_nullity ~nonnull
env te in
1390 let (env, lset2
) = condition_nullity ~nonnull
env var
in
1391 (env, Local_id.Set.union lset1 lset2
)
1392 (* case where `Shapes::idx(...)` must be made null/non-null *)
1396 ( (_
, _
, Aast.Class_const
((_
, _
, Aast.CI
(_
, shapes
)), (_
, idx
))),
1398 [(Ast_defs.Pnormal
, shape
); (Ast_defs.Pnormal
, field
)],
1400 when String.equal shapes
SN.Shapes.cShapes
&& String.equal idx
SN.Shapes.idx
1402 let field = Tast.to_nast_expr
field in
1403 let refine env shape_ty
=
1405 Typing_shapes.shapes_idx_not_null
env shape_ty
field
1409 refine_lvalue_type env shape ~
refine
1410 | (_
, _
, Hole
(te, _
, _
, _
)) -> condition_nullity ~nonnull
env te
1414 Typing_solver.non_null
env (Pos_or_decl.of_raw_pos p
) ty
1416 let r = Reason.Rwitness_from_decl
(get_pos
ty) in
1417 Inter.intersect
env ~
r ty (MakeType.null
r)
1419 refine_lvalue_type env te ~
refine
1421 (** If we are dealing with a refinement like
1423 then class_info is the class info of MyClass and hint_tyl corresponds
1425 let generate_fresh_tparams env class_info p reason hint_tyl
=
1426 let tparams_len = List.length
(Cls.tparams class_info
) in
1427 let hint_tyl = List.take
hint_tyl tparams_len in
1428 let pad_len = tparams_len - List.length
hint_tyl in
1430 List.map hint_tyl ~f
:(fun x
-> Some x
)
1431 @ List.init pad_len ~f
:(fun _
-> None
)
1433 let replace_wildcard env hint_ty tp
=
1435 tp_name
= (_
, tparam_name
);
1436 tp_reified
= reified
;
1443 Attributes.mem
SN.UserAttributes.uaEnforceable tp_user_attributes
1446 Attributes.mem
SN.UserAttributes.uaNewable tp_user_attributes
1451 match get_node
ty with
1452 | Tgeneric
(name
, _targs
) when Env.is_fresh_generic_parameter name
->
1453 (* TODO(T69551141) handle type arguments above and below *)
1454 (env, (Some
(tp
, name
), MakeType.generic reason name
))
1455 | _
-> (env, (None
, ty))
1458 let (env, new_name
) =
1459 Env.add_fresh_generic_parameter
1461 (Pos_or_decl.of_raw_pos p
)
1467 (* TODO(T69551141) handle type arguments for Tgeneric *)
1468 (env, (Some
(tp
, new_name
), MakeType.generic reason new_name
))
1470 let (env, tparams_and_tyl
) =
1471 List.map2_env
env hint_tyl (Cls.tparams class_info
) ~f
:replace_wildcard
1473 let (tparams_with_new_names
, tyl_fresh
) = List.unzip tparams_and_tyl
in
1474 (env, tparams_with_new_names
, tyl_fresh
)
1476 let safely_refine_class_type
1484 (tparams_with_new_names
: (decl_tparam
* string) option list
)
1486 (* Type of variable in block will be class name
1487 * with fresh type parameters *)
1489 mk
(get_reason
obj_ty, Tclass
(class_name
, Nonexact
, tyl_fresh
))
1491 let tparams = Cls.tparams class_info
in
1492 (* Add in constraints as assumptions on those type parameters *)
1495 empty_expand_env
with
1496 substs
= Subst.make_locl
tparams tyl_fresh
;
1500 let add_bounds env (t
, ty_fresh
) =
1501 List.fold_left t
.tp_constraints ~
init:env ~f
:(fun env (ck
, ty) ->
1502 (* Substitute fresh type parameters for
1503 * original formals in constraint *)
1504 let (env, ty) = Phase.localize ~
ety_env env ty in
1505 SubType.add_constraint
1510 (Typing_error.Reasons_callback.unify_error_at p
))
1513 List.fold_left
(List.zip_exn
tparams tyl_fresh
) ~f
:add_bounds ~
init:env
1515 (* Finally, if we have a class-test on something with static classish type,
1516 * then we can chase the hierarchy and decompose the types to deduce
1517 * further assumptions on type parameters. For example, we might have
1518 * class B<Tb> { ... }
1519 * class C extends B<int>
1520 * and have obj_ty = C and x_ty = B<T> for a generic parameter Aast.
1521 * Then SubType.add_constraint will deduce that T=int and add int as
1522 * both lower and upper bound on T in env.lenv.tpenv
1524 * We only wish to do this if the types are in a possible subtype relationship.
1526 let (env, supertypes
) =
1527 TUtils.get_concrete_supertypes ~abstract_enum
:true env ivar_ty
1529 let rec might_be_supertype ty =
1530 let (_env
, ty) = Env.expand_type
env ty in
1531 match get_node
ty with
1532 | Tclass
((_
, name
), _
, _
)
1533 when String.equal name
(Cls.name class_info
)
1534 || Cls.has_ancestor class_info name
1535 || Cls.requires_ancestor class_info name
->
1538 | Toption
ty -> might_be_supertype ty
1539 | Tunion tyl
-> List.for_all tyl ~f
:might_be_supertype
1543 List.fold_left supertypes ~
init:env ~f
:(fun env ty ->
1544 if might_be_supertype ty then
1545 SubType.add_constraint
1547 Ast_defs.Constraint_as
1550 (Typing_error.Reasons_callback.unify_error_at p
)
1554 (* It's often the case that the fresh name isn't necessary. For
1555 * example, if C<T> extends B<T>, and we have $x:B<t> for some type t
1556 * then $x is C should refine to $x:C<t>.
1557 * We take a simple approach:
1558 * For a fresh type parameter T#1, if
1559 * - There is an eqality constraint T#1 = t,
1560 * - T#1 is covariant, and T#1 has upper bound t (or mixed if absent)
1561 * - T#1 is contravariant, and T#1 has lower bound t (or nothing if absent)
1562 * then replace T#1 with t.
1563 * This is done in Type_parameter_env_ops.simplify_tpenv
1565 let (env, tparam_substs
) =
1566 Type_parameter_env_ops.simplify_tpenv
1568 (List.zip_exn tparams_with_new_names tyl_fresh
)
1572 List.map2_exn
tyl_fresh tparams_with_new_names ~f
:(fun orig_ty tparam_opt
->
1573 match tparam_opt
with
1575 | Some
(_tp
, name
) -> SMap.find name tparam_substs
)
1577 let obj_ty_simplified =
1578 mk
(get_reason
obj_ty, Tclass
(class_name
, Nonexact
, tyl_fresh))
1580 (env, obj_ty_simplified)
1582 (** Transform a hint like `A<_>` to a localized type like `A<T#1>` for refinement of
1583 an instance variable. ivar_ty is the previous type of that instance variable. Return
1584 the intersection of the hint and variable. *)
1585 let rec class_for_refinement env p reason ivar_pos ivar_ty hint_ty
=
1586 let (env, hint_ty
) = Env.expand_type
env hint_ty
in
1587 match (get_node ivar_ty
, get_node hint_ty
) with
1588 | (_
, Tclass
(((_
, cid
) as _c
), _
, tyl
)) ->
1590 match Env.get_class
env cid
with
1591 | Some class_info
->
1592 let (env, tparams_with_new_names
, tyl_fresh) =
1593 generate_fresh_tparams env class_info p reason tyl
1595 safely_refine_class_type
1603 tparams_with_new_names
1605 | None
-> (env, TUtils.terr
env (Reason.Rwitness ivar_pos
))
1607 | (Ttuple ivar_tyl
, Ttuple
hint_tyl)
1608 when Int.equal
(List.length ivar_tyl
) (List.length
hint_tyl) ->
1610 List.map2_env
env ivar_tyl
hint_tyl ~f
:(fun env ivar_ty hint_ty
->
1611 class_for_refinement env p reason ivar_pos ivar_ty hint_ty
)
1613 (env, MakeType.tuple reason tyl
)
1614 | _
-> (env, hint_ty
)
1616 let refine_and_simplify_intersection
1617 ~hint_first
env p reason ivar_pos ivar_ty hint_ty
=
1618 match get_node ivar_ty
with
1620 when Typing_defs.is_dynamic ty1
|| Typing_defs.is_dynamic ty2
->
1621 (* Distribute the intersection over the union *)
1622 let (env, hint_ty1
) =
1623 class_for_refinement env p reason ivar_pos ty1 hint_ty
1625 let (env, hint_ty2
) =
1626 class_for_refinement env p reason ivar_pos ty2 hint_ty
1628 let (env, ty1
) = Inter.intersect
env ~
r:reason ty1 hint_ty1
in
1629 let (env, ty2
) = Inter.intersect
env ~
r:reason ty2 hint_ty2
in
1630 Typing_union.union
env ty1 ty2
1632 let (env, hint_ty
) =
1633 class_for_refinement env p reason ivar_pos ivar_ty hint_ty
1635 (* Sometimes the type checker is sensitive to the ordering of intersections *)
1637 Inter.intersect
env ~
r:reason hint_ty ivar_ty
1639 Inter.intersect
env ~
r:reason ivar_ty hint_ty
1641 let refine_for_is ~hint_first
env tparamet ivar reason hint
=
1644 | Aast.Hnonnull
-> condition_nullity ~nonnull
:tparamet
env ivar
1645 | Aast.Hprim Tnull
-> condition_nullity ~nonnull
:(not tparamet
) env ivar
1646 | _
-> (env, Local_id.Set.empty
)
1649 make_a_local_of ~include_this
:true env (Tast.to_nast_expr ivar
)
1653 let (env, hint_ty
) =
1654 Phase.localize_hint_no_subst
env ~ignore_errors
:false hint
1656 let (env, hint_ty
) =
1657 if not tparamet
then
1658 Inter.negate_type
env reason hint_ty ~approx
:TUtils.ApproxUp
1662 let (env, refined_ty
) =
1663 refine_and_simplify_intersection
1672 (set_local env locl_ivar refined_ty
, Local_id.Set.singleton
(snd locl_ivar
))
1673 | None
-> (env, lset
)
1675 type legacy_arrays
=
1680 (* Refine type for is_array, is_vec, is_keyset and is_dict tests
1681 * `pred_name` is the function name itself (e.g. 'is_vec')
1682 * `p` is position of the function name in the source
1683 * `arg_expr` is the argument to the function
1685 let safely_refine_is_array env ty p pred_name arg_expr
=
1686 refine_lvalue_type env arg_expr ~
refine:(fun env arg_ty
->
1687 let r = Reason.Rpredicated
(p
, pred_name
) in
1688 let (env, tarrkey_name
) =
1689 Env.add_fresh_generic_parameter
1691 (Pos_or_decl.of_raw_pos p
)
1697 (* TODO(T69551141) handle type arguments for Tgeneric *)
1698 let tarrkey = MakeType.generic
r tarrkey_name
in
1700 SubType.add_constraint
1702 Ast_defs.Constraint_as
1704 (MakeType.arraykey r)
1705 (Typing_error.Reasons_callback.unify_error_at p
)
1707 let (env, tfresh_name
) =
1708 Env.add_fresh_generic_parameter
1710 (Pos_or_decl.of_raw_pos p
)
1716 (* TODO(T69551141) handle type arguments for Tgeneric *)
1717 let tfresh = MakeType.generic
r tfresh_name
in
1718 (* If we're refining the type for `is_array` we have a slightly more
1719 * involved process. Let's separate out that logic so we can re-use it.
1722 let tk = MakeType.arraykey Reason.(Rvarray_or_darray_key
(to_pos
r)) in
1724 MakeType.varray_or_darray
r tk tv
1726 (* This is the refined type of e inside the branch *)
1729 | PHPArray
-> array_ty
1730 | HackDictOrDArray
->
1733 [MakeType.dict
r tarrkey tfresh; MakeType.darray
r tarrkey tfresh]
1734 | HackVecOrVArray
->
1735 MakeType.union
r [MakeType.vec
r tfresh; MakeType.varray
r tfresh]
1737 let (_
, arg_pos
, _
) = arg_expr
in
1738 let (env, refined_ty
) =
1739 class_for_refinement env p
r arg_pos arg_ty
hint_ty
1741 (* Add constraints on generic parameters that must
1742 * hold for refined_ty <:arg_ty. For example, if arg_ty is Traversable<T>
1743 * and refined_ty is keyset<T#1> then we know T#1 <: T.
1744 * See analogous code in safely_refine_class_type.
1746 let (env, supertypes
) =
1747 TUtils.get_concrete_supertypes ~abstract_enum
:true env arg_ty
1750 List.fold_left supertypes ~
init:env ~f
:(fun env ty ->
1751 SubType.add_constraint
1753 Ast_defs.Constraint_as
1756 (Typing_error.Reasons_callback.unify_error_at p
))
1758 Inter.intersect ~
r env refined_ty arg_ty
)
1760 let key_exists env pos shape
field =
1761 let field = Tast.to_nast_expr
field in
1762 refine_lvalue_type env shape ~
refine:(fun env shape_ty
->
1763 match TUtils.shape_field_name
env field with
1764 | None
-> (env, shape_ty
)
1765 | Some field_name
->
1766 let field_name = TShapeField.of_ast
Pos_or_decl.of_raw_pos
field_name in
1767 Typing_shapes.refine_shape
field_name pos env shape_ty
)
1769 (** Add a fresh type parameter to [env] with a name starting [prefix]
1770 and a constraint on [ty]. *)
1771 let synthesize_type_param env p prefix
ty =
1772 let (env, name
) = Env.fresh_param_name
env prefix
in
1773 let env = Env.add_upper_bound_global
env name
ty in
1774 let env = Env.add_lower_bound_global
env name
ty in
1776 let hint = (p
, Aast.Habstr
(name
, [])) in
1779 (** Transform calls to MyVisitor::makeTree with [f]. *)
1780 let rec rewrite_expr_tree_maketree env expr f
=
1781 let (pos, p
, expr_
) = expr in
1785 ( (fun_pos
, p
, (Lfun
(fun_
, idl
) | Efun
(fun_
, idl
))),
1789 (* Express tree literals containing splices use an anonymous
1790 function that returns the makeTree call.
1793 $0splice1 = "whatever";
1794 return MyVisitor::makeTree(...);
1797 let map_stmt env s
=
1799 | (pos, Return
(Some
expr)) ->
1800 let (env, expr) = rewrite_expr_tree_maketree env expr f
in
1801 (env, (pos, Return
(Some
expr)))
1805 let (env, body_ast
) = List.map_env
env fun_
.f_body
.fb_ast ~f
:map_stmt in
1806 let fun_ = { fun_ with f_body
= { fb_ast
= body_ast
} } in
1808 (env, Call
((fun_pos
, p
, Lfun
(fun_, idl
)), targs
, args
, variadic
))
1810 (* The desugarer might give us a simple call to makeTree, so we
1811 can process it immediately. *)
1815 (env, (pos, p
, expr_
))
1817 (** Given [expr], a runtime expression for an expression tree, add a
1818 type parameter to the makeTree call.
1820 This enables expression tree visitors to use phantom type
1821 parameters. The visitor can be defined with __Explicit.
1823 public static function makeTree<<<__Explicit>> TInfer>(...) { ... }
1825 Userland calls to this method must provide an explicit type.
1827 MyVisitor::makeTree<MyVisitorInt>(...);
1829 For expression tree literals, we run type inference and provide a
1830 synthesized type parameter to the desugared runtime expression.
1832 MyVisitor`1`; // we infer MyVisitorInt
1833 // we add this constrained type parameter:
1834 MyVisitor::makeTree<TInfer#1>(...) where TInfer#1 = MyVisitorInt
1837 let maketree_with_type_param env p
expr expected_ty
=
1838 let (hint_virtual
, env) = synthesize_type_param env p
"TInfer" expected_ty
in
1839 let rewrite_expr env expr =
1841 | Call
(e, _
, el
, unpacked_element
) ->
1842 (env, Call
(e, [((), hint_virtual
)], el
, unpacked_element
))
1846 rewrite_expr_tree_maketree env expr rewrite_expr
1848 module EnumClassLabelOps
= struct
1850 | Success
of Tast.expr * locl_ty
1852 | LabelNotFound
of Tast.expr * locl_ty
1856 (** Given an [enum_name] and an [label], tries to see if
1857 [enum_name] has a constant named [label].
1858 In such case, creates the expected typed expression.
1860 If [label] is not there, it will register and error.
1862 [ctor] is either `MemberOf` or `Label`
1863 [full] describe if the original expression was a full
1864 label, as in E#A, or a short version, as in #A
1866 let expand pos env ~full ~ctor enum_name label_name
=
1867 let cls = Env.get_class
env enum_name
in
1870 (match Env.get_const
env cls label_name
with
1872 let dty = const_def
.cc_type
in
1873 (* the enum constant has type MemberOf<X, Y>. If we are
1874 * processing a Label argument, we just switch MemberOf for
1878 match deref
dty with
1879 | (r, Tapply
((p
, _
), args
)) -> mk
(r, Tapply
((p
, ctor
), args
))
1882 let (env, lty
) = Phase.localize_no_subst
env ~ignore_errors
:true dty in
1886 Some
(pos, enum_name
)
1890 let te = (hi, pos, EnumClassLabel
(qualifier, label_name
)) in
1891 (env, Success
(te, lty
))
1893 Errors.add_typing_error
1896 @@ Primary.Enum.Enum_class_label_unknown
1897 { pos; label_name
; class_name
= enum_name
});
1898 let r = Reason.Rwitness
pos in
1899 let ty = Typing_utils.terr
env r in
1900 let te = (ty, pos, EnumClassLabel
(None
, label_name
)) in
1901 (env, LabelNotFound
(te, ty)))
1902 | None
-> (env, ClassNotFound
)
1905 let is_lvalue = function
1909 (* Given a localized parameter type and parameter information, infer
1910 * a type for the parameter default expression (if present) and check that
1911 * it is a subtype of the parameter type (if present). If no parameter type
1912 * is specified, then union with Tany. (So it's as though we did a conditional
1913 * assignment of the default expression to the parameter).
1914 * Set the type of the parameter in the locals environment *)
1916 env ?
(immutable
= false) ?
(can_read_globals
= false) (ty1
, param
) =
1917 let (env, param_te
, ty1
) =
1918 match param
.param_expr
with
1919 | None
-> (env, None
, ty1
)
1923 ~f
:(Decl_hint.hint env.decl_env
)
1924 (hint_of_type_hint param
.param_type_hint
)
1927 match decl_hint with
1928 | None
-> Unenforced
1929 | Some
ty -> Typing_enforceability.get_enforcement
env ty
1931 let ty1_enforced = { et_type
= ty1
; et_enforced
= enforced } in
1933 ExpectedTy.make_and_allow_coercion_opt
1939 let (env, (te, ty2
)) =
1940 let reason = Reason.Rwitness param
.param_pos
in
1941 let pure = MakeType.mixed reason in
1943 if can_read_globals
then
1944 MakeType.capability
reason SN.Capabilities.accessGlobals
1948 with_special_coeffects env cap pure @@ fun env ->
1949 expr ?
expected env e ~allow_awaitable
:(*?*) false |> triple_to_pair
1951 Typing_sequencing.sequence_check_expr
e;
1954 Option.is_none
(hint_of_type_hint param
.param_type_hint
)
1955 && (not
@@ TCO.global_inference
(Env.get_tcopt
env))
1956 (* ty1 will be Tany iff we have no type hint and we are not in
1957 * 'infer missing mode'. When it ty1 is Tany we just union it with
1958 * the type of the default expression *)
1960 Union.union
env ty1 ty2
1961 (* Otherwise we have an explicit type, and the default expression type
1962 * must be a subtype *)
1965 Typing_coercion.coerce_type
1971 Typing_error.Callback.parameter_default_value_wrong_type
1977 let (env, user_attributes
) =
1978 attributes_check_def
1980 SN.AttributeKinds.parameter
1981 param
.param_user_attributes
1985 Aast.param_annotation
= Tast.make_expr_annotation param
.param_pos ty1
;
1986 Aast.param_type_hint
= (ty1
, hint_of_type_hint param
.param_type_hint
);
1987 Aast.param_is_variadic
= param
.param_is_variadic
;
1988 Aast.param_pos
= param
.param_pos
;
1989 Aast.param_name
= param
.param_name
;
1990 Aast.param_expr
= param_te
;
1991 Aast.param_callconv
= param
.param_callconv
;
1992 Aast.param_readonly
= param
.param_readonly
;
1993 Aast.param_user_attributes
= user_attributes
;
1994 Aast.param_visibility
= param
.param_visibility
;
1997 let mode = get_param_mode param
.param_callconv
in
1998 let id = Local_id.make_unscoped param
.param_name
in
2000 let env = Env.set_local ~immutable
env id ty1 param
.param_pos
in
2001 let env = Env.set_param
env id (ty1
, param
.param_pos
, mode) in
2003 if has_accept_disposable_attribute param
then
2004 Env.set_using_var
env id
2010 (*****************************************************************************)
2011 (* function used to type closures, functions and methods *)
2012 (*****************************************************************************)
2013 and fun_ ?
(abstract
= false) ?
(disable
= false) env return
pos named_body f_kind
2015 Env.with_env
env (fun env ->
2016 debug_last_pos := pos;
2017 let env = Env.set_return
env return
in
2021 Errors.internal_error
2023 ("Type inference for this function has been disabled by the "
2024 ^
SN.UserAttributes.uaDisableTypecheckerInternal
2029 block
env named_body
.fb_ast
2031 Typing_sequencing.sequence_check_block named_body
.fb_ast
;
2032 let { Typing_env_return_info.return_type
= ret
; _
} =
2035 let has_implicit_return = LEnv.has_next
env in
2036 let has_readonly = Env.get_readonly
env in
2038 if (not
has_implicit_return) || abstract
|| Env.is_hhi
env then
2041 Typing_return.fun_implicit_return
env pos ret
.et_type f_kind
2044 Typing_env.set_fun_tast_info
2046 Tast.{ has_implicit_return; has_readonly }
2048 debug_last_pos := Pos.none
;
2052 Typing_env.with_origin
env Decl_counters.Body
@@ fun env ->
2053 (* To insert an `AssertEnv`, `stmt` might return a `Block`. We eliminate it here
2054 to keep ASTs `Block`-free. *)
2056 List.fold ~
init:(env, []) stl ~f
:(fun (env, stl
) st
->
2057 let (env, st
) = stmt env st
in
2058 (* Accumulate statements in reverse order *)
2061 | (_
, Aast.Block
stl'
) -> List.rev
stl'
@ stl
2068 (* Ensure that `ty` is a subtype of IDisposable (for `using`) or
2069 * IAsyncDisposable (for `await using`)
2071 and has_dispose_method
env has_await p
e ty =
2074 SN.Members.__disposeAsync
2076 SN.Members.__dispose
2078 let (_
, obj_pos
, _
) = e in
2079 let (env, (tfty
, _tal
)) =
2086 ~coerce_from_ty
:None
2088 ~class_id
:(CIexpr
e)
2089 ~member_id
:(p
, meth)
2090 ~on_error
:(Typing_error.Callback.using_error p ~has_await
)
2094 let (env, (_tel
, _typed_unpack_element
, _ty
, _should_forget_fakes
)) =
2095 call ~
expected:None p
env tfty
[] None
2099 (* Check an individual component in the expression `e` in the
2100 * `using (e) { ... }` statement.
2101 * This consists of either
2102 * a simple assignment `$x = e`, in which `$x` is the using variable, or
2103 * an arbitrary expression `e`, in which case a temporary is the using
2104 * variable, inaccessible in the source.
2105 * Return the typed expression and its type, and any variables that must
2106 * be designated as "using variables" for avoiding escapes.
2108 and check_using_expr has_await
env ((_
, pos, content
) as using_clause
) =
2110 (* Simple assignment to local of form `$lvar = e` *)
2111 | Binop
(Ast_defs.Eq None
, (_
, lvar_pos
, Lvar lvar
), e) ->
2113 expr ~is_using_clause
:true env e ~allow_awaitable
:(*?*) false
2115 let env = has_dispose_method
env has_await
pos e ty in
2116 let env = set_local ~is_using_clause
:true env lvar
ty in
2117 (* We are assigning a new value to the local variable, so we need to
2118 * generate a new expression id
2120 let env = Env.set_local_expr_id
env (snd lvar
) (Ident.tmp
()) in
2122 ( Tast.make_typed_expr
2127 Tast.make_typed_expr lvar_pos
ty (Aast.Lvar lvar
),
2130 (* Arbitrary expression. This will be assigned to a temporary *)
2132 let (env, typed_using_clause
, ty) =
2133 expr ~is_using_clause
:true env using_clause ~allow_awaitable
:(*?*) false
2135 let env = has_dispose_method
env has_await
pos using_clause
ty in
2136 (env, (typed_using_clause
, []))
2138 (* Check the using clause e in
2139 * `using (e) { ... }` statement (`has_await = false`) or
2140 * `await using (e) { ... }` statement (`has_await = true`).
2141 * `using_clauses` is a list of expressions.
2142 * Return the typed expression, and any variables that must
2143 * be designated as "using variables" for avoiding escapes.
2145 and check_using_clause
env has_await using_clauses
=
2147 List.map_env
env using_clauses ~f
:(check_using_expr has_await
)
2149 let (typed_using_clauses
, vars
) = List.unzip pairs
in
2150 (env, typed_using_clauses
, List.concat vars
)
2152 and stmt env (pos, st
) =
2153 let (env, st
) = stmt_
env pos st
in
2154 Typing_debug.log_env_if_too_big
pos env;
2157 and stmt_
env pos st
=
2158 let expr ?
(allow_awaitable
= (*?*) false) = expr ~allow_awaitable
in
2159 let exprs = exprs ~allow_awaitable
:(*?*) false in
2160 (* Type check a loop. f env = (env, result) checks the body of the loop.
2161 * We iterate over the loop until the "next" continuation environment is
2162 * stable. alias_depth is supposed to be an upper bound on this; but in
2163 * certain cases this fails (e.g. a generic type grows unboundedly). TODO:
2166 let infer_loop env f
=
2167 let in_loop_outer = env.in_loop
in
2169 if in_loop_outer then
2172 Typing_alias.get_depth
(pos, st
)
2174 let env = { env with in_loop
= true } in
2175 let rec loop env n
=
2176 (* Remember the old environment *)
2177 let old_next_entry = Env.next_cont_opt
env in
2178 let (env, result
) = f
env in
2179 let new_next_entry = Env.next_cont_opt
env in
2180 (* Finish if we reach the bound, or if the environments match *)
2182 Int.equal n
alias_depth
2183 || Typing_per_cont_ops.is_sub_opt_entry
2184 Typing_subtype.is_sub_type
2189 let env = { env with in_loop
= in_loop_outer } in
2196 let env = Env.open_tyvars
env pos in
2197 (fun (env, tb
) -> (Typing_solver.close_tyvars_and_solve
env, tb
))
2201 let env = LEnv.move_and_merge_next_in_cont
env C.Fallthrough
in
2202 (env, Aast.Fallthrough
)
2203 | Noop
-> (env, Aast.Noop
)
2204 | AssertEnv _
-> (env, Aast.Noop
)
2206 let env = LEnv.move_and_merge_next_in_cont
env C.Exit
in
2207 (env, Aast.Yield_break
)
2209 let (env, te, _
) = expr env e in
2211 if TFTerm.typed_expression_exits
te then
2212 LEnv.move_and_merge_next_in_cont
env C.Exit
2218 let assert_refinement_env =
2219 assert_env_blk ~
pos ~at
:`Start
Aast.Refinement
2221 let (env, te, _
) = expr env e in
2222 let (env, tb1
, tb2
) =
2226 let (env, lset
) = condition
env true te in
2227 let refinement_map = refinement_annot_map env lset
in
2228 let (env, b1
) = block
env b1
in
2229 let b1 = assert_refinement_env refinement_map b1 in
2232 let (env, lset
) = condition
env false te in
2233 let refinement_map = refinement_annot_map env lset
in
2234 let (env, b2
) = block
env b2
in
2235 let b2 = assert_refinement_env refinement_map b2 in
2238 (* TODO TAST: annotate with joined types *)
2239 (env, Aast.If
(te, tb1
, tb2
))
2241 let env = Typing_return.check_inout_return
pos env in
2242 let rty = MakeType.void
(Reason.Rwitness
pos) in
2243 let { Typing_env_return_info.return_type
= expected_return
; _
} =
2246 let expected_return =
2247 Typing_return.strip_awaitable
(Env.get_fn_kind
env) env expected_return
2250 match Env.get_fn_kind
env with
2251 | Ast_defs.FGenerator
2252 | Ast_defs.FAsyncGenerator
->
2255 Typing_return.implicit_return
2258 ~
expected:expected_return.et_type
2261 let env = LEnv.move_and_merge_next_in_cont
env C.Exit
in
2262 (env, Aast.Return None
)
2263 | Return
(Some
e) ->
2264 let env = Typing_return.check_inout_return
pos env in
2265 let (_
, expr_pos
, _
) = e in
2266 let Typing_env_return_info.
2271 return_dynamically_callable
= _
;
2276 Typing_return.strip_awaitable
(Env.get_fn_kind
env) env return_type
2279 if return_explicit
then
2281 (ExpectedTy.make_and_allow_coercion
2288 if return_disposable
then enforce_return_disposable env e;
2289 let (env, te, rty) =
2290 expr ~is_using_clause
:return_disposable ?
expected env e
2292 (* This is a unify_error rather than a return_type_mismatch because the return
2293 * statement is the problem, not the return type itself. *)
2294 let (env, err_opt) =
2296 ~ok
:(fun env -> (env, None
))
2297 ~error
:(fun env -> (env, Some
(rty, return_type.et_type
)))
2298 @@ Typing_coercion.coerce_type_res
2304 Typing_error.Callback.unify_error
2306 let env = LEnv.move_and_merge_next_in_cont
env C.Exit
in
2307 (env, Aast.Return
(Some
(hole_on_err ~
err_opt te)))
2309 (* NOTE: leaks scope as currently implemented; this matches
2310 the behavior in naming (cf. `do_stmt` in naming/naming.ml).
2312 let (env, (tb
, te)) =
2313 LEnv.stash_and_do
env [C.Continue
; C.Break
; C.Do
] (fun env ->
2314 let env = LEnv.save_and_merge_next_in_cont
env C.Do
in
2315 let (env, _
) = block
env b
in
2316 (* saving the locals in continue here even if there is no continue
2317 * statement because they must be merged at the end of the loop, in
2318 * case there is no iteration *)
2319 let env = LEnv.save_and_merge_next_in_cont
env C.Continue
in
2321 infer_loop env (fun env ->
2323 LEnv.update_next_from_conts
env [C.Continue
; C.Next
]
2325 (* The following is necessary in case there is an assignment in the
2327 let (env, te, _
) = expr env e in
2328 let (env, _lset
) = condition
env true te in
2329 let env = LEnv.update_next_from_conts
env [C.Do
; C.Next
] in
2330 let (env, tb
) = block
env b
in
2333 let env = LEnv.update_next_from_conts
env [C.Continue
; C.Next
] in
2334 let (env, te, _
) = expr env e in
2335 let (env, _lset
) = condition
env false te in
2336 let env = LEnv.update_next_from_conts
env [C.Break
; C.Next
] in
2339 (env, Aast.Do
(tb
, te))
2341 let (env, (te, tb
, refinement_map)) =
2342 LEnv.stash_and_do
env [C.Continue
; C.Break
] (fun env ->
2343 let env = LEnv.save_and_merge_next_in_cont
env C.Continue
in
2345 infer_loop env (fun env ->
2347 LEnv.update_next_from_conts
env [C.Continue
; C.Next
]
2349 let join_map = annot_map env in
2350 (* The following is necessary in case there is an assignment in the
2352 let (env, te, _
) = expr env e in
2353 let (env, lset
) = condition
env true te in
2354 let refinement_map = refinement_annot_map env lset
in
2355 (* TODO TAST: avoid repeated generation of block *)
2356 let (env, tb
) = block
env b
in
2358 (* Annotate loop body with join and refined environments *)
2359 let assert_env_blk = assert_env_blk ~
pos ~at
:`Start
in
2360 let tb = assert_env_blk Aast.Refinement
refinement_map tb in
2361 let tb = assert_env_blk Aast.Join
join_map tb in
2365 let env = LEnv.update_next_from_conts
env [C.Continue
; C.Next
] in
2366 let (env, te, _
) = expr env e in
2367 let (env, lset
) = condition
env false te in
2368 let refinement_map_at_exit = refinement_annot_map env lset
in
2369 let env = LEnv.update_next_from_conts
env [C.Break
; C.Next
] in
2370 (env, (te, tb, refinement_map_at_exit)))
2372 let while_st = Aast.While
(te, tb) in
2373 (* Export the refined environment after the exit condition holds *)
2375 assert_env_stmt ~
pos ~at
:`End
Aast.Refinement
refinement_map while_st
2380 us_has_await
= has_await
;
2381 us_exprs
= (loc
, using_clause
);
2382 us_block
= using_block
;
2385 let (env, typed_using_clause
, using_vars
) =
2386 check_using_clause
env has_await using_clause
2388 let (env, typed_using_block
) = block
env using_block
in
2389 (* Remove any using variables from the environment, as they should not
2390 * be in scope outside the block *)
2391 let env = List.fold_left using_vars ~
init:env ~f
:Env.unset_local
in
2396 us_has_await
= has_await
;
2397 us_exprs
= (loc
, typed_using_clause
);
2398 us_block
= typed_using_block
;
2401 | For
(e1
, e2
, e3
, b
) ->
2405 | None
-> ((), Pos.none
, True
)
2407 let (env, (te1
, te2
, te3
, tb, refinement_map)) =
2408 LEnv.stash_and_do
env [C.Continue
; C.Break
] (fun env ->
2409 (* For loops leak their initalizer, but nothing that's defined in the
2412 let (env, te1
, _
) = exprs env e1
in
2414 let env = LEnv.save_and_merge_next_in_cont
env C.Continue
in
2415 let (env, (tb, te3
)) =
2416 infer_loop env (fun env ->
2417 (* The following is necessary in case there is an assignment in the
2419 let (env, te2
, _
) = expr env e2 in
2420 let (env, lset
) = condition
env true te2
in
2421 let refinement_map = refinement_annot_map env lset
in
2422 let (env, tb) = block
env b
in
2424 LEnv.update_next_from_conts
env [C.Continue
; C.Next
]
2426 let join_map = annot_map env in
2427 let (env, te3
, _
) = exprs env e3
in
2429 (* Export the join and refinement environments *)
2430 let assert_env_blk = assert_env_blk ~
pos ~at
:`Start
in
2431 let tb = assert_env_blk Aast.Refinement
refinement_map tb in
2432 let tb = assert_env_blk Aast.Join
join_map tb in
2436 let env = LEnv.update_next_from_conts
env [C.Continue
; C.Next
] in
2437 let (env, te2
, _
) = expr env e2 in
2438 let (env, lset
) = condition
env false te2
in
2439 let refinement_map_at_exit = refinement_annot_map env lset
in
2440 let env = LEnv.update_next_from_conts
env [C.Break
; C.Next
] in
2441 (env, (te1
, te2
, te3
, tb, refinement_map_at_exit)))
2443 let for_st = Aast.For
(te1
, Some te2
, te3
, tb) in
2445 assert_env_stmt ~
pos ~at
:`End
Aast.Refinement
refinement_map for_st
2448 | Switch
(((_
, pos, _
) as e), cl
, dfl
) ->
2449 let (env, te, ty) = expr env e in
2450 (* NB: A 'continue' inside a 'switch' block is equivalent to a 'break'.
2452 * http://php.net/manual/en/control-structures.continue.php *)
2453 let (env, (te, tcl
, tdfl
)) =
2454 LEnv.stash_and_do
env [C.Continue
; C.Break
] (fun env ->
2455 let parent_locals = LEnv.get_all_locals
env in
2456 let (env, tcl
, tdfl
) = case_list
parent_locals ty env pos cl dfl
in
2458 LEnv.update_next_from_conts
env [C.Continue
; C.Break
; C.Next
]
2460 (env, (te, tcl
, tdfl
)))
2462 (env, Aast.Switch
(te, tcl
, tdfl
))
2463 | Foreach
(e1
, e2, b
) ->
2464 (* It's safe to do foreach over a disposable, as no leaking is possible *)
2465 let (env, te1
, ty1
) = expr ~accept_using_var
:true env e1
in
2466 let (env, (te1
, te2
, tb)) =
2467 LEnv.stash_and_do
env [C.Continue
; C.Break
] (fun env ->
2468 let env = LEnv.save_and_merge_next_in_cont
env C.Continue
in
2469 let (_
, p1
, _
) = e1
in
2470 let (env, tk, tv, err_opt) = as_expr env ty1 p1
e2 in
2471 let (env, (te2
, tb)) =
2472 infer_loop env (fun env ->
2474 LEnv.update_next_from_conts
env [C.Continue
; C.Next
]
2476 let join_map = annot_map env in
2477 let (env, te2
) = bind_as_expr
env p1
tk tv e2 in
2478 let (env, tb) = block
env b
in
2479 (* Export the join environment *)
2480 let tb = assert_env_blk ~
pos ~at
:`Start
Aast.Join
join_map tb in
2484 LEnv.update_next_from_conts
env [C.Continue
; C.Break
; C.Next
]
2486 (env, (hole_on_err ~
err_opt te1
, te2
, tb)))
2488 (env, Aast.Foreach
(te1
, te2
, tb))
2489 | Try
(tb, cl
, fb
) ->
2490 let (env, ttb
, tcl
, tfb
) = try_catch
env tb cl fb
in
2491 (env, Aast.Try
(ttb
, tcl
, tfb
))
2492 | Awaitall
(el
, b
) ->
2493 let env = might_throw env in
2495 List.fold_left el ~
init:(env, []) ~f
:(fun (env, tel
) (e1
, e2) ->
2496 let (env, te2
, ty2
) = expr env e2 ~allow_awaitable
:true in
2497 let (_
, pos2
, _
) = e2 in
2499 Async.overload_extract_from_awaitable
env ~p
:pos2 ty2
2504 let (env, _
, _
, err_opt) =
2505 assign
pos env ((), pos, Lvar e1
) pos2 ty2
2507 (env, (Some e1
, hole_on_err ~
err_opt te2
) :: tel
)
2508 | None
-> (env, (None
, te2
) :: tel
))
2510 let (env, b
) = block
env b
in
2511 (env, Aast.Awaitall
(el
, b
))
2513 let (_
, p
, _
) = e in
2514 let (env, te, ty) = expr env e in
2515 let env = coerce_to_throwable p
env ty in
2516 let env = move_and_merge_next_in_catch env in
2517 (env, Aast.Throw
te)
2519 let env = LEnv.move_and_merge_next_in_cont
env C.Continue
in
2520 (env, Aast.Continue
)
2522 let env = LEnv.move_and_merge_next_in_cont
env C.Break
in
2527 "Unexpected nodes in AST. These nodes should have been removed in naming."
2529 and finally_cont fb
env ctx
=
2530 (* The only locals in scope are the ones from the current continuation *)
2531 let env = Env.env_with_locals
env @@ CMap.singleton
C.Next ctx
in
2532 let (env, _tfb
) = block
env fb
in
2533 (env, LEnv.get_all_locals
env)
2535 and finally
env fb
=
2538 let env = LEnv.update_next_from_conts
env [C.Next
; C.Finally
] in
2541 let parent_locals = LEnv.get_all_locals
env in
2542 (* First typecheck the finally block against all continuations merged
2544 * During this phase, record errors found in the finally block, but discard
2545 * the resulting environment. *)
2546 let all_conts = Env.all_continuations
env in
2547 let env = LEnv.update_next_from_conts
env all_conts in
2548 let (env, tfb
) = block
env fb
in
2549 let env = LEnv.restore_conts_from
env parent_locals all_conts in
2550 (* Second, typecheck the finally block once against each continuation. This
2551 * helps be more clever about what each continuation will be after the
2553 * We don't want to record errors during this phase, because certain types
2554 * of errors will fire wrongly. For example, if $x is nullable in some
2555 * continuations but not in others, then we must use `?->` on $x, but an
2556 * error will fire when typechecking the finally block againts continuations
2557 * where $x is non-null. *)
2558 let finally_cont env _key
= finally_cont fb
env in
2559 let (env, locals_map
) =
2560 Errors.ignore_
(fun () -> CMap.map_env
finally_cont env parent_locals)
2562 let union env _key
= LEnv.union_contextopts
env in
2563 let (env, locals
) = Try.finally_merge
union env locals_map
all_conts in
2564 (Env.env_with_locals
env locals
, tfb
)
2566 and try_catch
env tb cl fb
=
2567 let parent_locals = LEnv.get_all_locals
env in
2569 LEnv.drop_conts
env [C.Break
; C.Continue
; C.Exit
; C.Catch
; C.Finally
]
2571 let (env, (ttb
, tcb
)) =
2572 Env.in_try
env (fun env ->
2573 let (env, ttb
) = block
env tb in
2574 let env = LEnv.move_and_merge_next_in_cont
env C.Finally
in
2575 let catchctx = LEnv.get_cont_option
env C.Catch
in
2576 let (env, lenvtcblist
) = List.map_env
env ~f
:(catch
catchctx) cl
in
2577 let (lenvl
, tcb
) = List.unzip lenvtcblist
in
2578 let env = LEnv.union_lenv_list
env env.lenv lenvl
in
2579 let env = LEnv.move_and_merge_next_in_cont
env C.Finally
in
2582 let (env, tfb
) = finally
env fb
in
2583 let env = LEnv.update_next_from_conts
env [C.Finally
] in
2584 let env = LEnv.drop_cont
env C.Finally
in
2586 LEnv.restore_and_merge_conts_from
2589 [C.Break
; C.Continue
; C.Exit
; C.Catch
; C.Finally
]
2591 (env, ttb
, tcb
, tfb
)
2593 and case_list
parent_locals ty env switch_pos cl dfl
=
2594 let initialize_next_cont env =
2595 let env = LEnv.restore_conts_from
env parent_locals [C.Next
] in
2596 let env = LEnv.update_next_from_conts
env [C.Next
; C.Fallthrough
] in
2597 LEnv.drop_cont
env C.Fallthrough
2599 let check_fallthrough env switch_pos case_pos block ~last ~is_default
=
2600 if (not
(List.is_empty block
)) && not last
then
2601 match LEnv.get_cont_option
env C.Next
with
2603 Errors.add_nast_check_error
2606 Nast_check_error.Default_fallthrough switch_pos
2608 Nast_check_error.Case_fallthrough
{ switch_pos
; case_pos
}
2612 (* below, we try to find out if the switch is exhaustive *)
2613 let has_default = Option.is_some dfl
in
2615 (* If it hasn't got a default clause then we need to solve type variables
2616 * in order to check for an enum *)
2618 Env.expand_type
env ty
2620 Typing_solver.expand_type_and_solve
2622 ~description_of_expected
:"a value"
2626 (* leverage that enums are checked for exhaustivity *)
2631 SN.Classes.cHH_BuiltinEnum
2632 [MakeType.mixed Reason.Rnone
]
2634 Typing_subtype.is_sub_type_for_coercion
env ty top_type
2636 (* register that the runtime may throw in case we cannot prove
2637 that the switch is exhaustive *)
2638 if has_default || is_enum then
2644 let rec case_list env = function
2646 | (((_
, pos, _
) as e), b
) :: rl
->
2647 let env = initialize_next_cont env in
2648 let (env, te, _
) = expr env e ~allow_awaitable
:(*?*) false in
2649 let (env, tb) = block
env b
in
2650 let last = List.is_empty rl
&& Option.is_none dfl
in
2651 check_fallthrough env switch_pos
pos b ~
last ~is_default
:false;
2652 let (env, tcl
) = case_list env rl
in
2653 (env, (te, tb) :: tcl
)
2659 | None
-> (env, None
)
2661 let env = initialize_next_cont env in
2662 let (env, tb) = block
env b
in
2663 check_fallthrough env switch_pos
pos b ~
last:true ~is_default
:true;
2664 (env, Some
(pos, tb))
2668 and catch
catchctx env (sid
, exn_lvar
, b
) =
2669 let env = LEnv.replace_cont
env C.Next
catchctx in
2671 let ety_p = fst sid
in
2672 let (env, _
, _
, _
) = instantiable_cid
ety_p env cid [] in
2673 let (env, _tal
, _te
, ety
) = class_expr
env [] ((), ety_p, cid) in
2674 let env = coerce_to_throwable ety_p env ety
in
2675 let (p
, x
) = exn_lvar
in
2676 let env = set_valid_rvalue p
env x ety
in
2677 let (env, tb) = block
env b
in
2678 (env, (env.lenv
, (sid
, exn_lvar
, tb)))
2680 and bind_as_expr
env p ty1 ty2 aexpr
=
2683 let (env, te, _
, _
) = assign p
env ev p ty2
in
2685 | Await_as_v
(p
, ev
) ->
2686 let (env, te, _
, _
) = assign p
env ev p ty2
in
2687 (env, Aast.Await_as_v
(p
, te))
2688 | As_kv
((_
, p
, Lvar
((_
, k
) as id)), ev
) ->
2689 let env = set_valid_rvalue p
env k ty1
in
2690 let (env, te, _
, _
) = assign p
env ev p ty2
in
2691 let tk = Tast.make_typed_expr p ty1
(Aast.Lvar
id) in
2692 (env, Aast.As_kv
(tk, te))
2693 | Await_as_kv
(p
, (_
, p1
, Lvar
((_
, k
) as id)), ev
) ->
2694 let env = set_valid_rvalue p
env k ty1
in
2695 let (env, te, _
, _
) = assign p
env ev p ty2
in
2696 let tk = Tast.make_typed_expr p1 ty1
(Aast.Lvar
id) in
2697 (env, Aast.Await_as_kv
(p
, tk, te))
2699 (* TODO Probably impossible, should check that *)
2703 ?
(expected : ExpectedTy.t
option)
2704 ?
(accept_using_var
= false)
2705 ?
(is_using_clause
= false)
2706 ?
(in_readonly_expr
= false)
2708 ?
(check_defined
= true)
2717 | Some
ExpectedTy.{ reason = r; ty = { et_type
= ty; _
}; _
} ->
2719 log_with_level
env "typing" ~level
:1 (fun () ->
2721 (Pos_or_decl.of_raw_pos p
)
2725 ( "Typing.expr " ^
Typing_reason.string_of_ureason
r,
2726 [Log_type
("expected_ty", ty)] );
2741 | Inf.InconsistentTypeVarState _
as e ->
2742 (* we don't want to catch unwanted exceptions here, eg Timeouts *)
2743 Errors.add_typing_error
2746 @@ Primary.Exception_occurred
{ pos = p
; exn
= Exception.wrap
e });
2747 make_result env p
(invalid_expr_ env p
) @@ err_witness env p
2749 (* Some (legacy) special functions are allowed in initializers,
2750 therefore treat them as pure and insert the matching capabilities. *)
2751 and expr_with_pure_coeffects
2752 ?
(expected : ExpectedTy.t
option) ~allow_awaitable
env e =
2753 let (_
, p
, _
) = e in
2754 let pure = MakeType.mixed (Reason.Rwitness p
) in
2755 let (env, (te, ty)) =
2756 with_special_coeffects env pure pure @@ fun env ->
2757 expr env e ?
expected ~allow_awaitable
|> triple_to_pair
2762 ?
(accept_using_var
= false)
2763 ?
(is_using_clause
= false)
2764 ?
(in_readonly_expr
= false)
2765 ?
(expected : ExpectedTy.t
option)
2766 ?lhs_of_null_coalesce
2768 ?
(check_defined
= true)
2773 let (_
, p
, _
) = e in
2774 debug_last_pos := p
;
2780 ?lhs_of_null_coalesce
2789 let valkind = `lvalue
in
2790 expr_ ~
valkind ~check_defined
:false env e ~allow_awaitable
:(*?*) false
2792 and lvalues
env el
=
2794 | [] -> (env, [], [])
2796 let (env, te, ty) = lvalue
env e in
2797 let (env, tel
, tyl
) = lvalues
env el
in
2798 (env, te :: tel
, ty :: tyl
)
2800 (* $x ?? 0 is handled similarly to $x ?: 0, except that the latter will also
2801 * look for sketchy null checks in the condition. *)
2802 (* TODO TAST: type refinement should be made explicit in the typed AST *)
2803 and eif
env ~
(expected : ExpectedTy.t
option) ?in_await p c e1
e2 =
2804 let condition = condition ~lhs_of_null_coalesce
:false in
2805 let (env, tc
, tyc
) =
2806 raw_expr ~lhs_of_null_coalesce
:false env c ~allow_awaitable
:false
2808 let parent_lenv = env.lenv
in
2809 let (env, _lset
) = condition env true tc
in
2810 let (env, te1
, ty1
) =
2814 Typing_solver.non_null
env (Pos_or_decl.of_raw_pos p
) tyc
2818 let (env, te1
, ty1
) =
2819 expr ?
expected ?in_await
env e1 ~allow_awaitable
:true
2821 (env, Some te1
, ty1
)
2823 let lenv1 = env.lenv
in
2824 let env = { env with lenv
= parent_lenv } in
2825 let (env, _lset
) = condition env false tc
in
2826 let (env, te2
, ty2
) = expr ?
expected ?in_await
env e2 ~allow_awaitable
:true in
2827 let lenv2 = env.lenv
in
2828 let env = LEnv.union_lenvs
env parent_lenv lenv1 lenv2 in
2829 let (env, ty) = Union.union ~approx_cancel_neg
:true env ty1 ty2
in
2830 make_result env p
(Aast.Eif
(tc
, te1
, te2
)) ty
2833 ?
(accept_using_var
= false)
2834 ?
(expected : ExpectedTy.t
option)
2836 ?
(check_defined
= true)
2841 | [] -> (env, [], [])
2853 let (env, tel
, tyl
) =
2863 (env, te :: tel
, ty :: tyl
)
2865 and argument_list_exprs expr_cb
env el
=
2867 | [] -> (env, [], [])
2869 let (env, te, ty) = expr_cb
env e in
2870 let (env, tel
, tyl
) = argument_list_exprs expr_cb
env el
in
2871 (env, (pk
, te) :: tel
, ty :: tyl
)
2873 and exprs_expected
(pos, ur, expected_tyl
) env el
=
2874 match (el
, expected_tyl
) with
2875 | ([], _
) -> (env, [], [])
2876 | (e :: el
, expected_ty
:: expected_tyl
) ->
2877 let expected = ExpectedTy.make
pos ur expected_ty
in
2878 let (env, te, ty) = expr ~
expected env e ~allow_awaitable
:(*?*) false in
2879 let (env, tel
, tyl
) = exprs_expected
(pos, ur, expected_tyl
) env el
in
2880 (env, te :: tel
, ty :: tyl
)
2881 | (el
, []) -> exprs env el ~allow_awaitable
:(*?*) false
2884 ?
(expected : ExpectedTy.t
option)
2885 ?
(accept_using_var
= false)
2886 ?
(is_using_clause
= false)
2887 ?
(in_readonly_expr
= false)
2888 ?lhs_of_null_coalesce
2891 ~
(valkind : [> `lvalue
| `lvalue_subexpr
| `other
])
2894 ((_
, p
, e) as outer
) =
2895 let env = Env.open_tyvars
env p
in
2896 (fun (env, te, ty) ->
2897 let env = Typing_solver.close_tyvars_and_solve
env in
2900 let expr ?
(allow_awaitable
= allow_awaitable
) =
2901 expr ~check_defined ~allow_awaitable
2903 let exprs = exprs ~check_defined ~allow_awaitable
in
2904 let raw_expr ?
(allow_awaitable
= allow_awaitable
) =
2905 raw_expr ~check_defined ~allow_awaitable
2908 * Given a list of types, computes their supertype. If any of the types are
2909 * unknown (e.g., comes from PHP), the supertype will be Typing_utils.tany env.
2910 * The optional coerce_for_op parameter controls whether any arguments of type
2911 * dynamic can be coerced to enforceable types because they are arguments to a
2912 * built-in operator.
2914 let compute_supertype
2915 ~
(expected : ExpectedTy.t
option)
2919 ?
(coerce_for_op
= false)
2920 ?
(can_pessimise
= false)
2924 let (env, supertype
) =
2927 let (env, supertype
) = Env.fresh_type_reason
env use_pos r in
2931 @@ Primary.Internal_error
2932 { pos = use_pos; msg
= "Subtype of fresh type variable" })
2938 (* There can't be an error because the type is fresh *)
2939 SubType.sub_type
env supertype
ty
2940 @@ Typing_error.Reasons_callback.always
error
2943 | Some
ExpectedTy.{ ty = { et_type
= ty; _
}; _
} -> (env, ty)
2945 match get_node supertype
with
2946 (* No need to check individual subtypes if expected type is mixed or any! *)
2947 | Tany _
-> (env, supertype
, List.map tys ~f
:(fun _
-> None
))
2949 let (env, expected_supertype
) =
2950 if coerce_for_op
then
2953 (ExpectedTy.make_and_allow_coercion
2956 { et_type
= supertype
; et_enforced
= Enforced
}) )
2958 let (env, pess_supertype
) =
2959 if can_pessimise
then
2960 Typing_array_access.maybe_pessimise_type
env supertype
2964 (env, Some
(ExpectedTy.make
use_pos reason pess_supertype
))
2966 let dyn_t = MakeType.dynamic
(Reason.Rwitness
use_pos) in
2967 let subtype_value env ty =
2969 if coerce_for_op
&& Typing_utils.is_sub_type_for_union
env dyn_t ty
2971 (* if we're coercing for a primop, and we're going to use the coercion
2972 (because the type of the arg is a supertype of dynamic), then we want
2973 to force the expected_supertype to the bound.
2978 Typing_union.union env ty (mk
(get_reason
ty, get_node bound_ty
))
2982 check_expected_ty_res
2989 let (env, rev_ty_err_opts
) =
2990 List.fold_left tys ~
init:(env, []) ~f
:(fun (env, errs
) ty ->
2992 ~ok
:(fun env -> (env, None
:: errs
))
2993 ~
error:(fun env -> (env, Some
(ty, supertype
) :: errs
))
2994 @@ subtype_value env ty)
2998 List.exists tys ~f
:(fun ty ->
2999 equal_locl_ty_
(get_node
ty) (Typing_utils.tany
env))
3001 (* If one of the values comes from PHP land, we have to be conservative
3002 * and consider that we don't know what the type of the values are. *)
3003 (env, Typing_utils.mk_tany
env p
, List.rev rev_ty_err_opts
)
3005 (env, supertype
, List.rev rev_ty_err_opts
)
3008 * Given a 'a list and a method to extract an expr and its ty from a 'a, this
3009 * function extracts a list of exprs from the list, and computes the supertype
3010 * of all of the expressions' tys.
3012 let compute_exprs_and_supertype
3013 ~
(expected : ExpectedTy.t
option)
3014 ?
(reason = Reason.URarray_value
)
3015 ?
(can_pessimise
= false)
3022 extract_expr_and_ty
=
3023 let (env, pess_expected
) =
3024 if can_pessimise
then
3026 | None
-> (env, None
)
3029 Typing_array_access.maybe_pessimise_type
3031 ety
.ExpectedTy.ty.et_type
3033 (env, Some
ExpectedTy.(make ety
.pos ety
.reason ty))
3037 let (env, exprs_and_tys
) =
3038 List.map_env
env l ~f
:(extract_expr_and_ty ~
expected:pess_expected
)
3040 let (exprs, tys
) = List.unzip exprs_and_tys
in
3041 let (env, supertype
, err_opts
) =
3055 ~f
:(fun te err_opt -> hole_on_err te ~
err_opt)
3060 let check_collection_tparams env name tys
=
3061 (* varrays and darrays are not classes but they share the same
3062 constraints with vec and dict respectively *)
3064 if String.equal
name SN.Typehints.varray
then
3066 else if String.equal
name SN.Typehints.darray
then
3067 SN.Collections.cDict
3071 (* Class retrieval always succeeds because we're fetching a
3072 collection decl from an HHI file. *)
3073 match Env.get_class
env name with
3077 (empty_expand_env_with_on_error
3078 (Env.invalid_type_hint_assert_primary_pos_in_current_decl
env))
3080 substs
= TUtils.make_locl_subst_for_class_tparams
class_ tys
;
3083 Phase.check_tparams_constraints
3087 (Cls.tparams class_)
3089 let desc = "Missing collection decl during type parameter check"
3091 Telemetry.(create
() |> string_ ~key
:"class name" ~
value:name)
3096 @@ Primary.Invariant_violation
3097 { pos = p
; desc; telemetry
; report_to_user
= false })
3099 Errors.add_typing_error
err;
3100 (* Continue typechecking without performing the check on a best effort
3104 List.iter ~f
:Errors.add_typing_error
3105 @@ Typing_type_wellformedness.expr env outer
;
3109 failwith
"AST should not contain these nodes"
3110 | Hole
(e, _
, _
, _
) ->
3115 ?lhs_of_null_coalesce
3123 let ty = Typing_utils.mk_tany
env p
in
3124 make_result env p
Aast.Omitted
ty
3126 | ValCollection
(_
, th
, el
) ->
3127 let (get_expected_kind
, name, subtype_val
, coerce_for_op
, make_expr
, make_ty
)
3130 | ValCollection
(kind
, _
, _
) ->
3131 let class_name = Nast.vc_kind_to_name kind
in
3132 let (subtype_val
, coerce_for_op
) =
3137 (arraykey_value ~add_hole
:true p
class_name true, true)
3141 (array_value
, false)
3143 ( get_vc_inst env kind
,
3147 (fun th elements
-> Aast.ValCollection
(kind
, th
, elements
)),
3149 MakeType.class_type
(Reason.Rwitness p
) class_name [value_ty
] )
3151 ( get_vc_inst env Vec
,
3155 (fun th elements
-> Aast.ValCollection
(Vec
, th
, elements
)),
3156 (fun value_ty
-> MakeType.varray
(Reason.Rwitness p
) value_ty
) )
3158 (* The parent match makes this case impossible *)
3159 failwith
"impossible match case"
3161 (* Use expected type to determine expected element type *)
3162 let (env, elem_expected
, th
) =
3165 let (env, tv, tv_expected
) = localize_targ env tv in
3166 let env = check_collection_tparams env name [fst
tv] in
3167 (env, Some tv_expected
, Some
tv)
3170 match expand_expected_and_get_node env expected with
3171 | (env, Some
(pos, ur, _
, ety
, _
)) ->
3173 match get_expected_kind ety
with
3174 | Some vty
-> (env, Some
(ExpectedTy.make
pos ur vty
), None
)
3175 | None
-> (env, None
, None
)
3177 | _
-> (env, None
, None
)
3181 (* TODO We ought to apply the bound even when not in sound dynamic mode,
3182 to avoid getting Set<dynamic> etc which are unsafe "nothing" factories. *)
3183 if coerce_for_op
&& TypecheckerOptions.enable_sound_dynamic
env.genv
.tcopt
3187 (Reason.Rtype_variable_generics
(p
, "Tk", strip_ns
name)))
3191 let (env, tel
, elem_ty
) =
3192 compute_exprs_and_supertype
3193 ~
expected:elem_expected
3195 ~
reason:Reason.URvector
3199 (Reason.Rtype_variable_generics
(p
, "T", strip_ns
name))
3204 make_result env p
(make_expr th tel
) (make_ty elem_ty
)
3206 | KeyValCollection
(_
, th
, l
) ->
3207 let (get_expected_kind
, name, make_expr
, make_ty
) =
3209 | KeyValCollection
(kind
, _
, _
) ->
3210 let class_name = Nast.kvc_kind_to_name kind
in
3211 ( get_kvc_inst env p kind
,
3213 (fun th pairs
-> Aast.KeyValCollection
(kind
, th
, pairs
)),
3214 (fun k v
-> MakeType.class_type
(Reason.Rwitness p
) class_name [k
; v
])
3217 let name = "darray" in
3218 ( get_kvc_inst env p Dict
,
3220 (fun th pairs
-> Aast.KeyValCollection
(Dict
, th
, pairs
)),
3221 (fun k v
-> MakeType.darray
(Reason.Rwitness p
) k v
) )
3223 (* The parent match makes this case impossible *)
3224 failwith
"impossible match case"
3226 (* Use expected type to determine expected key and value types *)
3227 let (env, kexpected
, vexpected
, th
) =
3229 | Some
((_
, tk), (_
, tv)) ->
3230 let (env, tk, tk_expected
) = localize_targ env tk in
3231 let (env, tv, tv_expected
) = localize_targ env tv in
3232 let env = check_collection_tparams env name [fst
tk; fst
tv] in
3233 (env, Some tk_expected
, Some tv_expected
, Some
(tk, tv))
3235 (* no explicit typehint, fallback to supplied expect *)
3237 match expand_expected_and_get_node env expected with
3238 | (env, Some
(pos, reason, _
, ety
, _
)) ->
3240 match get_expected_kind ety
with
3241 | Some
(kty
, vty
) ->
3242 let k_expected = ExpectedTy.make
pos reason kty
in
3243 let v_expected = ExpectedTy.make
pos reason vty
in
3244 (env, Some
k_expected, Some
v_expected, None
)
3245 | None
-> (env, None
, None
, None
)
3247 | _
-> (env, None
, None
, None
)
3250 let (kl
, vl
) = List.unzip l
in
3251 let r = Reason.Rtype_variable_generics
(p
, "Tk", strip_ns
name) in
3253 compute_exprs_and_supertype
3256 ~
reason:(Reason.URkey
name)
3257 ~
bound:(Some
(MakeType.arraykey r))
3262 (arraykey_value p
name false)
3265 compute_exprs_and_supertype
3268 ~
reason:(Reason.URvalue
name)
3270 ~coerce_for_op
:false
3272 (Reason.Rtype_variable_generics
(p
, "Tv", strip_ns
name))
3277 let pairs = List.zip_exn tkl tvl
in
3278 make_result env p
(make_expr th
pairs) (make_ty k v
)
3280 let (env, te, ty) = expr env e in
3281 (* Clone only works on objects; anything else fatals at runtime.
3282 * Constructing a call `e`->__clone() checks that `e` is an object and
3283 * checks coeffects on __clone *)
3284 let (_
, pe
, _
) = e in
3285 let (env, (tfty
, _tal
)) =
3292 ~coerce_from_ty
:None
3294 ~class_id
:(CIexpr
e)
3295 ~member_id
:(p
, SN.Members.__clone
)
3296 ~on_error
:Typing_error.Callback.unify_error
3300 let (env, (_tel
, _typed_unpack_element
, _ty
, _should_forget_fakes
)) =
3301 call ~
expected:None p
env tfty
[] None
3303 make_result env p
(Aast.Clone
te) ty
3305 if Option.is_none
(Env.get_self_ty
env) then
3306 Errors.add_typing_error
3307 Typing_error.(primary
@@ Primary.This_var_outside_class p
);
3308 if Env.is_in_expr_tree
env then
3309 Errors.add_typing_error
3310 Typing_error.(expr_tree
@@ Primary.Expr_tree.This_var_in_expr_tree p
);
3311 if not accept_using_var
then check_escaping_var env (p
, this
);
3312 let ty = Env.get_local
env this
in
3313 let r = Reason.Rwitness p
in
3314 let ty = mk
(r, get_node
ty) in
3315 make_result env p
Aast.This
ty
3316 | True
-> make_result env p
Aast.True
(MakeType.bool (Reason.Rwitness p
))
3317 | False
-> make_result env p
Aast.False
(MakeType.bool (Reason.Rwitness p
))
3318 (* TODO TAST: consider checking that the integer is in range. Right now
3319 * it's possible for HHVM to fail on well-typed Hack code
3321 | Int s
-> make_result env p
(Aast.Int s
) (MakeType.int (Reason.Rwitness p
))
3323 make_result env p
(Aast.Float s
) (MakeType.float (Reason.Rwitness p
))
3324 (* TODO TAST: consider introducing a "null" type, and defining ?t to
3327 | Null
-> make_result env p
Aast.Null
(MakeType.null
(Reason.Rwitness p
))
3329 make_result env p
(Aast.String s
) (MakeType.string (Reason.Rwitness p
))
3331 let (env, tel
) = string2
env idl
in
3332 make_result env p
(Aast.String2 tel
) (MakeType.string (Reason.Rwitness p
))
3333 | PrefixedString
(n
, e) ->
3334 if String.( <> ) n
"re" then (
3335 Errors.experimental_feature
3337 "String prefixes other than `re` are not yet supported.";
3338 expr_error env Reason.Rnone outer
3340 let (env, te, ty) = expr env e in
3341 let (_
, pe
, expr_
) = e in
3342 let env = Typing_substring.sub_string pe
env ty in
3350 (Aast.PrefixedString
(n
, te))
3351 (Typing_regex.type_pattern
e)
3353 | Pcre.Error
(Pcre.BadPattern
(s
, i
)) ->
3354 let reason = `bad_patt
(s ^
" [" ^ string_of_int i ^
"]") in
3355 Errors.add_typing_error
3357 primary
@@ Primary.Bad_regex_pattern
{ pos = pe
; reason });
3358 expr_error env (Reason.Rregex pe
) e
3359 | Typing_regex.Empty_regex_pattern
->
3360 Errors.add_typing_error
3363 @@ Primary.Bad_regex_pattern
{ pos = pe
; reason = `empty_patt
});
3364 expr_error env (Reason.Rregex pe
) e
3365 | Typing_regex.Missing_delimiter
->
3366 Errors.add_typing_error
3369 @@ Primary.Bad_regex_pattern
3370 { pos = pe
; reason = `missing_delim
});
3371 expr_error env (Reason.Rregex pe
) e
3372 | Typing_regex.Invalid_global_option
->
3373 Errors.add_typing_error
3376 @@ Primary.Bad_regex_pattern
3377 { pos = pe
; reason = `invalid_option
});
3378 expr_error env (Reason.Rregex pe
) e
3381 Errors.add_typing_error
3384 @@ Primary.Re_prefixed_non_string
3385 { pos = pe
; reason = `embedded_expr
});
3386 expr_error env (Reason.Rregex pe
) e
3388 Errors.add_typing_error
3391 @@ Primary.Re_prefixed_non_string
{ pos = pe
; reason = `non_string
});
3392 expr_error env (Reason.Rregex pe
) e)
3394 let (env, fty, _tal
) = fun_type_of_id env x
[] [] in
3395 make_result env p
(Aast.Fun_id x
) fty
3396 | Id
((cst_pos
, cst_name
) as id) ->
3397 (match Env.get_gconst
env cst_name
with
3399 Errors.add_typing_error
3400 Typing_error.(primary
@@ Primary.Unbound_global cst_pos
);
3401 let ty = err_witness env cst_pos
in
3402 make_result env cst_pos
(Aast.Id
id) ty
3405 Phase.localize_no_subst
env ~ignore_errors
:true const
.cd_type
3407 make_result env p
(Aast.Id
id) ty)
3408 | Method_id
(instance
, meth) ->
3409 (* Method_id is used when creating a "method pointer" using the magic
3410 * inst_meth function.
3412 * Typing this is pretty simple, we just need to check that instance->meth
3413 * is public+not static and then return its type.
3415 let (env, te, ty1
) = expr env instance
in
3416 let (env, (result
, _tal
)) =
3423 ~coerce_from_ty
:None
3425 ~class_id
:(CIexpr instance
)
3427 ~on_error
:Typing_error.Callback.unify_error
3432 Env.FakeMembers.check_instance_invalid
env instance
(snd
meth) result
3434 make_result env p
(Aast.Method_id
(te, meth)) result
3435 | Method_caller
(((pos, class_name) as pos_cname
), meth_name
) ->
3436 (* meth_caller('X', 'foo') desugars to:
3439 let class_ = Env.get_class
env class_name in
3441 | None
-> unbound_name env pos_cname outer
3443 (* Create a class type for the given object instantiated with unresolved
3444 * types for its type parameters.
3447 if Ast_defs.is_c_trait
(Cls.kind
class_) then
3448 Errors.add_typing_error
3451 @@ Primary.Meth_caller_trait
{ pos; trait_name
= class_name })
3454 List.map_env
env (Cls.tparams class_) ~f
:(fun env _
->
3455 Env.fresh_type
env p
)
3458 List.map (Cls.tparams class_) ~f
:(fun { tp_name
= (p
, n
); _
} ->
3459 (* TODO(T69551141) handle type arguments for Tgeneric *)
3460 MakeType.generic
(Reason.Rwitness_from_decl p
) n
)
3464 (Reason.Rwitness_from_decl
(Pos_or_decl.of_raw_pos p
))
3465 (Positioned.of_raw_positioned pos_cname
)
3470 (empty_expand_env_with_on_error
3471 (Typing_error.Reasons_callback.invalid_type_hint
pos))
3473 substs
= TUtils.make_locl_subst_for_class_tparams
class_ tvarl
;
3476 let (env, local_obj_ty
) = Phase.localize ~
ety_env env obj_type in
3477 let (env, (fty, _tal
)) =
3484 ~coerce_from_ty
:None
3486 ~class_id
:(CI
(pos, class_name))
3487 ~member_id
:meth_name
3488 ~on_error
:Typing_error.Callback.unify_error
3492 let (env, fty) = Env.expand_type
env fty in
3493 (match deref
fty with
3494 | (reason, Tfun ftype
) ->
3495 (* We are creating a fake closure:
3496 * function(Class $x, arg_types_of(Class::meth_name))
3497 : return_type_of(Class::meth_name)
3502 on_error
= Env.unify_error_assert_primary_pos_in_current_decl
env;
3506 Phase.check_tparams_constraints
3510 (Cls.tparams class_)
3512 let local_obj_fp = TUtils.default_fun_param local_obj_ty
in
3513 let fty = { ftype
with ft_params
= local_obj_fp :: ftype
.ft_params
} in
3516 ft_tparams
= fty.ft_tparams
;
3517 ft_where_constraints
= fty.ft_where_constraints
;
3518 ft_params
= fty.ft_params
;
3519 ft_implicit_params
= fty.ft_implicit_params
;
3520 ft_ret
= fty.ft_ret
;
3521 ft_flags
= fty.ft_flags
;
3522 ft_ifc_decl
= fty.ft_ifc_decl
;
3528 (Aast.Method_caller
(pos_cname
, meth_name
))
3529 (mk
(reason, Tfun
caller))
3531 (* This can happen if the method lives in PHP *)
3535 (Aast.Method_caller
(pos_cname
, meth_name
))
3536 (Typing_utils.mk_tany
env pos)))
3537 | FunctionPointer
(FP_class_const
(cid, meth), targs
) ->
3538 let (env, _
, ce
, cty
) = class_expr
env [] cid in
3539 let (env, (fpty
, tal
)) =
3543 ~incl_tc
:false (* What is this? *)
3544 ~coerce_from_ty
:None
(* What is this? *)
3545 ~explicit_targs
:targs
3546 ~is_function_pointer
:true
3552 let env = Env.set_tyvar_variance
env fpty
in
3553 let fpty = set_function_pointer fpty in
3554 (* All function pointers are readonly_this since they are either toplevel or static *)
3555 let fpty = set_readonly_this fpty in
3559 (Aast.FunctionPointer
(FP_class_const
(ce
, meth), tal
))
3561 | Smethod_id
(((_
, pc
, cid_
) as cid), meth) ->
3562 (* Smethod_id is used when creating a "method pointer" using the magic
3563 * class_meth function.
3565 * Typing this is pretty simple, we just need to check that c::meth is
3566 * public+static and then return its type.
3568 let (class_, classname
) =
3572 (Env.get_self_class
env, Env.get_self_id
env)
3573 | CI
(_
, const
) when String.equal const
SN.PseudoConsts.g__CLASS__
->
3574 (Env.get_self_class
env, Env.get_self_id
env)
3575 | CI
(_
, id) -> (Env.get_class
env id, Some
id)
3578 let classname = Option.value classname ~default
:"" in
3581 (* The class given as a static string was not found. *)
3582 unbound_name env (pc
, classname) outer
3584 let smethod = Env.get_static_member
true env class_ (snd
meth) in
3587 (* The static method wasn't found. *)
3588 Errors.add_typing_error
3589 @@ TOG.smember_not_found
3593 ~is_function_pointer
:false
3596 Typing_error.Callback.unify_error
;
3597 expr_error env Reason.Rnone outer
3598 | Some
({ ce_type
= (lazy ty); ce_pos
= (lazy ce_pos
); _
} as ce
) ->
3600 if get_ce_abstract ce
then
3604 Errors.add_typing_error
3607 @@ Primary.Class_meth_abstract_call
3609 class_name = classname;
3610 meth_name
= snd
meth;
3615 let ce_visibility = ce
.ce_visibility in
3616 let ce_deprecated = ce
.ce_deprecated in
3617 let (env, _tal
, te, cid_ty
) = class_expr ~exact
:Exact
env [] cid in
3618 let (env, cid_ty
) = Env.expand_type
env cid_ty
in
3620 match get_node cid_ty
with
3621 | Tclass
(_
, _
, tyargs) -> tyargs
3626 empty_expand_env
with
3627 substs
= TUtils.make_locl_subst_for_class_tparams
class_ tyargs;
3631 let r = get_reason
ty |> Typing_reason.localize
in
3632 (match get_node
ty with
3635 Typing_enforceability.compute_enforced_and_pessimize_fun_type
env ft
3637 let def_pos = ce_pos
in
3639 Phase.localize_targs
3640 ~check_well_kinded
:true
3644 ~use_name
:(strip_ns
(snd
meth))
3655 use_name
= strip_ns
(snd
meth);
3657 explicit_targs
= tal
;
3664 let ty = mk
(r, Tfun
ft) in
3665 let use_pos = fst
meth in
3667 ~f
:Errors.add_typing_error
3668 (TVis.check_deprecated ~
use_pos ~
def_pos ce_deprecated);
3669 (match ce_visibility with
3672 make_result env p
(Aast.Smethod_id
(te, meth)) ty
3674 Errors.add_typing_error
3677 @@ Primary.Private_class_meth
3678 { decl_pos
= def_pos; pos = use_pos });
3679 expr_error env r outer
3681 Errors.add_typing_error
3684 @@ Primary.Protected_class_meth
3685 { decl_pos
= def_pos; pos = use_pos });
3686 expr_error env r outer
)
3688 Errors.internal_error p
"We have a method which isn't callable";
3689 expr_error env r outer
)))
3691 let r = Reason.Rplaceholder p
in
3692 let ty = MakeType.void
r in
3693 make_result env p
(Aast.Lplaceholder p
) ty
3694 | Dollardollar _
when is_lvalue valkind ->
3695 Errors.add_typing_error
3697 wellformedness
@@ Primary.Wellformedness.Dollardollar_lvalue p
);
3698 expr_error env (Reason.Rwitness p
) outer
3699 | Dollardollar
id ->
3700 let ty = Env.get_local_check_defined
env id in
3701 let env = might_throw env in
3702 make_result env p
(Aast.Dollardollar
id) ty
3703 | Lvar
((_
, x
) as id) ->
3704 if not accept_using_var
then check_escaping_var env id;
3706 if check_defined
then
3707 Env.get_local_check_defined
env id
3711 make_result env p
(Aast.Lvar
id) ty
3713 let (env, expected) = expand_expected_and_get_node env expected in
3714 let (env, tel
, tyl
) =
3716 | Some
(pos, ur, _
, _
, Ttuple expected_tyl
) ->
3717 let (env, pess_expected_tyl
) =
3718 if TypecheckerOptions.pessimise_builtins
(Env.get_tcopt
env) then
3719 List.map_env
env expected_tyl ~f
:Typing_array_access.pessimise_type
3723 exprs_expected
(pos, ur, pess_expected_tyl
) env el
3726 let (env, pess_tyl
) =
3727 if TypecheckerOptions.pessimise_builtins
(Env.get_tcopt
env) then
3728 List.map_env
env tyl ~f
:(Typing_array_access.pessimised_tup_assign p
)
3732 let ty = MakeType.tuple
(Reason.Rwitness p
) pess_tyl
in
3733 make_result env p
(Aast.Tuple tel
) ty
3735 let (env, tel
, tyl
) =
3738 | `lvalue_subexpr
->
3741 let (env, expected) = expand_expected_and_get_node env expected in
3742 (match expected with
3743 | Some
(pos, ur, _
, _
, Ttuple expected_tyl
) ->
3744 exprs_expected
(pos, ur, expected_tyl
) env el
3745 | _
-> exprs env el
)
3747 let ty = MakeType.tuple
(Reason.Rwitness p
) tyl
in
3748 make_result env p
(Aast.List tel
) ty
3749 | Pair
(th
, e1
, e2) ->
3750 let (env, expected1
, expected2
, th
) =
3752 | Some
((_
, t1
), (_
, t2
)) ->
3753 let (env, t1
, t1_expected
) = localize_targ env t1
in
3754 let (env, t2
, t2_expected
) = localize_targ env t2
in
3755 (env, Some t1_expected
, Some t2_expected
, Some
(t1
, t2
))
3757 (* Use expected type to determine expected element types *)
3758 (match expand_expected_and_get_node env expected with
3759 | (env, Some
(pos, reason, _
, _ty
, Tclass
((_
, k
), _
, [ty1
; ty2
])))
3760 when String.equal k
SN.Collections.cPair
->
3761 let ty1_expected = ExpectedTy.make
pos reason ty1
in
3762 let ty2_expected = ExpectedTy.make
pos reason ty2
in
3763 (env, Some
ty1_expected, Some
ty2_expected, None
)
3764 | _
-> (env, None
, None
, None
))
3766 let (env, te1
, ty1
) = expr ?
expected:expected1
env e1
in
3767 let (env, te2
, ty2
) = expr ?
expected:expected2
env e2 in
3768 let (_
, p1
, _
) = e1
in
3769 let (_
, p2
, _
) = e2 in
3770 let (env, ty1
, err_opt1
) =
3773 ~
reason:Reason.URpair_value
3775 (Reason.Rtype_variable_generics
(p1
, "T1", "Pair"))
3779 let (env, ty2
, err_opt2
) =
3782 ~
reason:Reason.URpair_value
3784 (Reason.Rtype_variable_generics
(p2
, "T2", "Pair"))
3788 let ty = MakeType.pair
(Reason.Rwitness p
) ty1 ty2
in
3794 hole_on_err te1 ~
err_opt:(Option.join
@@ List.hd err_opt1
),
3795 hole_on_err te2 ~
err_opt:(Option.join
@@ List.hd err_opt2
) ))
3797 | Array_get
(e, None
) ->
3798 let (env, te, _
) = update_array_type p
env e valkind in
3799 let env = might_throw env in
3800 (* NAST check reports an error if [] is used for reading in an
3802 let ty = err_witness env p
in
3803 make_result env p
(Aast.Array_get
(te, None
)) ty
3804 | Array_get
(e1
, Some
e2) ->
3805 let (env, te1
, ty1
) =
3806 update_array_type ?lhs_of_null_coalesce p
env e1
valkind
3808 let (env, te2
, ty2
) = expr env e2 in
3809 let env = might_throw env in
3810 let is_lvalue = is_lvalue valkind in
3811 let (_
, p1
, _
) = e1
in
3812 let (env, ty, arr_err_opt
, key_err_opt
) =
3813 Typing_array_access.array_get
3816 ?lhs_of_null_coalesce
3827 ( hole_on_err ~
err_opt:arr_err_opt te1
,
3828 Some
(hole_on_err ~
err_opt:key_err_opt te2
) ))
3830 | Call
((_
, pos_id
, Id
((_
, s
) as id)), explicit_targs
, el
, None
)
3831 when Hash_set.mem
typing_env_pseudofunctions s
->
3832 let (env, tel
, tys
) =
3833 argument_list_exprs
(expr ~accept_using_var
:true) env el
3836 if String.equal s
SN.PseudoFunctions.hh_expect
then
3837 do_hh_expect ~equivalent
:false env pos_id explicit_targs p tys
3838 else if String.equal s
SN.PseudoFunctions.hh_expect_equivalent
then
3839 do_hh_expect ~equivalent
:true env pos_id explicit_targs p tys
3840 else if not
(List.is_empty explicit_targs
) then (
3841 Errors.add_typing_error
3844 @@ Primary.Expected_tparam
3845 { decl_pos
= Pos_or_decl.none
; pos = pos_id
; n
= 0 });
3847 ) else if String.equal s
SN.PseudoFunctions.hh_show
then (
3848 List.iter tys ~f
:(Typing_log.hh_show p
env);
3850 ) else if String.equal s
SN.PseudoFunctions.hh_show_env
then (
3851 Typing_log.hh_show_env p
env;
3853 ) else if String.equal s
SN.PseudoFunctions.hh_log_level
then
3856 (Ast_defs.Pnormal
, (_
, _
, String key_str
));
3857 (Ast_defs.Pnormal
, (_
, _
, Int level_str
));
3859 Env.set_log_level
env key_str
(int_of_string level_str
)
3861 else if String.equal s
SN.PseudoFunctions.hh_force_solve
then
3862 Typing_solver.solve_all_unsolved_tyvars
env
3863 else if String.equal s
SN.PseudoFunctions.hh_loop_forever
then
3864 let _ = loop_forever env in
3869 let ty = MakeType.void
(Reason.Rwitness p
) in
3874 ( Tast.make_typed_expr pos_id
(TUtils.mk_tany
env pos_id
) (Aast.Id
id),
3879 | Call
(e, explicit_targs
, el
, unpacked_element
) ->
3880 let env = might_throw env in
3881 let ((env, te, ty), should_forget_fakes
) =
3895 if should_forget_fakes
then
3896 Env.forget_members
env Reason.(Blame
(p
, BScall
))
3901 | FunctionPointer
(FP_id fid
, targs
) ->
3902 let (env, fty, targs
) = fun_type_of_id env fid targs
[] in
3903 let e = Aast.FunctionPointer
(FP_id fid
, targs
) in
3904 let fty = set_function_pointer fty in
3905 (* All function pointers are readonly_this since they are always a toplevel function or static method *)
3906 let fty = set_readonly_this fty in
3907 make_result env p
e fty
3908 | Binop
(Ast_defs.QuestionQuestion
, e1
, e2) ->
3909 let (_, e1_pos
, _) = e1
in
3910 let (_, e2_pos
, _) = e2 in
3911 let (env, te1
, ty1
) =
3912 raw_expr ~lhs_of_null_coalesce
:true env e1 ~allow_awaitable
:true
3914 let (env, te2
, ty2
) = expr ?
expected env e2 ~allow_awaitable
:true in
3915 let (env, ty1'
) = Env.fresh_type
env e1_pos
in
3920 (MakeType.nullable_locl
Reason.Rnone ty1'
)
3921 (Typing_error.Reasons_callback.unify_error_at e1_pos
)
3923 (* Essentially mimic a call to
3924 * function coalesce<Tr, Ta as Tr, Tb as Tr>(?Ta, Tb): Tr
3925 * That way we let the constraint solver take care of the union logic.
3927 let (env, ty_result
) = Env.fresh_type
env e2_pos
in
3933 (Typing_error.Reasons_callback.unify_error_at p
)
3940 (Typing_error.Reasons_callback.unify_error_at p
)
3945 (Aast.Binop
(Ast_defs.QuestionQuestion
, te1
, te2
))
3947 | Binop
(Ast_defs.Eq op_opt
, e1
, e2) ->
3948 let make_result env p
te ty =
3949 let (env, te, ty) = make_result env p
te ty in
3950 let env = Typing_local_ops.check_assignment
env te in
3954 (* For example, e1 += e2. This is typed and translated as if
3955 * written e1 = e1 + e2.
3956 * TODO TAST: is this right? e1 will get evaluated more than once
3959 let (_, _, expr_
) = e1
in
3960 (match (op
, expr_
) with
3961 | (Ast_defs.QuestionQuestion
, Class_get
_) ->
3962 Errors.experimental_feature
3964 "null coalesce assignment operator with static properties";
3965 expr_error env Reason.Rnone outer
3968 ((), p
, Binop
(Ast_defs.Eq None
, e1
, ((), p
, Binop
(op
, e1
, e2))))
3970 let (env, te_fake
, ty) = raw_expr env e_fake in
3971 let te_opt = resugar_binop te_fake
in
3974 | Some
(_, _, te) -> make_result env p
te ty
3978 let (env, te2
, ty2
) = raw_expr env e2 in
3979 let (_, pos2
, _) = te2
in
3980 let (env, te1
, ty, err_opt) = assign p
env e1 pos2 ty2
in
3981 let te = Aast.Binop
(Ast_defs.Eq None
, te1
, hole_on_err ~
err_opt te2
) in
3982 make_result env p
te ty)
3983 | Binop
(((Ast_defs.Ampamp
| Ast_defs.Barbar
) as bop
), e1
, e2) ->
3984 let c = Ast_defs.(equal_bop bop Ampamp
) in
3985 let (env, te1
, _) = expr env e1
in
3986 let lenv = env.lenv in
3987 let (env, _lset
) = condition env c te1
in
3988 let (env, te2
, _) = expr env e2 in
3989 let env = { env with lenv } in
3993 (Aast.Binop
(bop
, te1
, te2
))
3994 (MakeType.bool (Reason.Rlogic_ret p
))
3995 | Binop
(bop
, e1
, e2) ->
3996 let (env, te1
, ty1
) = raw_expr env e1
in
3997 let (env, te2
, ty2
) = raw_expr env e2 in
4000 (* TODO: This could be less conservative: we only need to account for
4001 * the possibility of exception if the operator is `/` or `/=`.
4006 | _ -> might_throw env
4008 let (_, p1
, _) = e1
in
4009 let (_, p2
, _) = e2 in
4010 let (env, te3
, ty) =
4011 Typing_arithmetic.binop p
env bop p1 te1 ty1 p2 te2 ty2
4014 | Pipe
(e0
, e1
, e2) ->
4015 (* If it weren't for local variable assignment or refinement the pipe
4016 * expression e1 |> e2 could be typed using this rule (E is environment with
4017 * types for locals):
4019 * E |- e1 : ty1 E[$$:ty1] |- e2 : ty2
4020 * --------------------------------------
4023 * The possibility of e2 changing the types of locals in E means that E
4024 * can evolve, and so we need to restore $$ to its original state.
4026 let (env, te1
, ty1
) = expr env e1
in
4027 let dd_var = Local_id.make_unscoped
SN.SpecialIdents.dollardollar
in
4029 if Env.is_local_defined
env dd_var then
4030 Some
(Env.get_local_pos
env dd_var)
4034 let env = Env.set_local env dd_var ty1
Pos.none
in
4035 let (env, te2
, ty2
) = expr env e2 ~allow_awaitable
:true in
4037 match dd_old_ty with
4038 | None
-> Env.unset_local
env dd_var
4039 | Some
(ty, pos) -> Env.set_local env dd_var ty pos
4041 let (env, te, ty) = make_result env p
(Aast.Pipe
(e0
, te1
, te2
)) ty2
in
4044 let (env, te, ty) = raw_expr env e in
4045 let env = might_throw env in
4046 let (env, tuop
, ty) = Typing_arithmetic.unop p
env uop
te ty in
4047 let env = Typing_local_ops.check_assignment
env te in
4049 | Eif
(c, e1
, e2) -> eif
env ~
expected ?in_await p
c e1
e2
4050 | Class_const
((_, p
, CI sid
), pstr
)
4051 when String.equal
(snd pstr
) "class" && Env.is_typedef
env (snd sid
) ->
4053 match Env.get_typedef
env (snd sid
) with
4054 | Some
{ td_tparams
= tparaml
; _ } ->
4055 (* Typedef type parameters cannot have constraints *)
4060 fun { tp_name
= (p
, x
); _ } ->
4061 (* TODO(T69551141) handle type arguments for Tgeneric *)
4062 MakeType.generic
(Reason.Rwitness_from_decl p
) x
4066 let p_ = Pos_or_decl.of_raw_pos p
in
4069 ( Reason.Rwitness_from_decl
p_,
4070 Tapply
(Positioned.of_raw_positioned sid
, params) )
4074 ( Reason.Rwitness_from_decl
p_,
4075 Tapply
((p_, SN.Classes.cTypename
), [tdef]) )
4077 let (env, tparams) =
4078 List.map_env
env tparaml ~f
:(fun env _tp
-> Env.fresh_type
env p
)
4082 (empty_expand_env_with_on_error
4083 (Env.invalid_type_hint_assert_primary_pos_in_current_decl
env))
4085 substs
= Subst.make_locl tparaml
tparams;
4089 Phase.check_tparams_constraints ~
use_pos:p ~
ety_env env tparaml
4091 let (env, ty) = Phase.localize ~
ety_env env typename in
4092 make_result env p
(Class_const
((ty, p
, CI sid
), pstr
)) ty
4094 (* Should not expect None as we've checked whether the sid is a typedef *)
4095 expr_error env (Reason.Rwitness p
) outer
4097 | Class_const
(cid, mid
) -> class_const
env p
(cid, mid
)
4098 | Class_get
(((_, _, cid_
) as cid), CGstring mid
, prop_or_method
)
4099 when Env.FakeMembers.is_valid_static
env cid_
(snd mid
) ->
4100 let (env, local
) = Env.FakeMembers.make_static
env cid_
(snd mid
) p
in
4101 let local = ((), p
, Lvar
(p
, local)) in
4102 let (env, _, ty) = expr env local in
4103 let (env, _tal
, te, _) = class_expr
env [] cid in
4107 (Aast.Class_get
(te, Aast.CGstring mid
, prop_or_method
))
4110 (((_, _, cid_
) as cid), CGstring
((ppos
, _) as mid
), prop_or_method
) ->
4111 let (env, _tal
, te, cty
) = class_expr
env [] cid in
4112 let env = might_throw env in
4113 let (env, (ty, _tal
)) =
4117 ~coerce_from_ty
:None
4124 Env.FakeMembers.check_static_invalid
env cid_
(snd mid
) ty
4127 Errors.try_if_no_errors
4128 (fun () -> Typing_local_ops.enforce_static_property_access ppos
env)
4130 let is_lvalue = is_lvalue valkind in
4131 (* If it's an lvalue we throw an error in a separate check in check_assign *)
4132 if in_readonly_expr
|| is_lvalue then
4135 Typing_local_ops.enforce_mutable_static_variable
4138 (* This msg only appears if we have access to ReadStaticVariables,
4139 since otherwise we would have errored in the first function *)
4140 ~msg
:"Please enclose the static in a readonly expression")
4145 (Aast.Class_get
(te, Aast.CGstring mid
, prop_or_method
))
4147 (* Fake member property access. For example:
4148 * if ($x->f !== null) { ...$x->f... }
4150 | Class_get
(_, CGexpr
_, _) ->
4151 failwith
"AST should not have any CGexprs after naming"
4152 | Obj_get
(e, (_, pid
, Id
(py
, y
)), nf
, is_prop
)
4153 when Env.FakeMembers.is_valid
env e y
->
4154 let env = might_throw env in
4155 let (env, local) = Env.FakeMembers.make
env e y p
in
4156 let local = ((), p
, Lvar
(p
, local)) in
4157 let (env, _, ty) = expr env local in
4158 let (env, t_lhs
, _) = expr ~accept_using_var
:true env e in
4159 let t_rhs = Tast.make_typed_expr pid
ty (Aast.Id
(py
, y
)) in
4160 make_result env p
(Aast.Obj_get
(t_lhs
, t_rhs, nf
, is_prop
)) ty
4161 (* Statically-known instance property access e.g. $x->f *)
4162 | Obj_get
(e1
, (_, pm
, Id m
), nullflavor
, prop_or_method
) ->
4164 match nullflavor
with
4165 | OG_nullthrows
-> None
4166 | OG_nullsafe
-> Some p
4168 let (env, te1
, ty1
) = expr ~accept_using_var
:true env e1
in
4169 let env = might_throw env in
4170 (* We typecheck Obj_get by checking whether it is a subtype of
4171 Thas_member(m, #1) where #1 is a fresh type variable. *)
4172 let (env, mem_ty
) = Env.fresh_type
env p
in
4173 let (_, p1
, _) = e1
in
4174 let r = Reason.Rwitness p1
in
4180 ~class_id
:(CIexpr e1
)
4181 ~explicit_targs
:None
4183 let lty1 = LoclType ty1
in
4184 let (env, result_ty
, err_opt) =
4194 Typing_error.Callback.unify_error
4196 let (env, err_opt) =
4199 ~ok
:(fun env -> (env, None
))
4200 ~
error:(fun env -> (env, Some
(ty1
, MakeType.nothing Reason.none
)))
4202 (env, mem_ty
, err_opt)
4204 (* In that case ty1 is a subtype of ?Thas_member(m, #1)
4205 and the result is ?#1 if ty1 is nullable. *)
4206 let r = Reason.Rnullsafe_op p
in
4207 let null_ty = MakeType.null
r in
4208 let (env, null_has_mem_ty
) =
4209 Union.union_i
env r has_member_ty null_ty
4218 Typing_error.Callback.unify_error
4220 let (env, err_opt) =
4223 ~ok
:(fun env -> (env, None
))
4224 ~
error:(fun env -> (env, Some
(ty1
, MakeType.nothing Reason.none
)))
4226 let (env, null_or_nothing_ty
) = Inter.intersect
env ~
r null_ty ty1
in
4227 let (env, result_ty
) = Union.union env null_or_nothing_ty mem_ty
in
4228 (env, result_ty
, err_opt)
4230 let (env, result_ty
) =
4231 Env.FakeMembers.check_instance_invalid
env e1
(snd m
) result_ty
4237 ( hole_on_err ~
err_opt te1
,
4238 Tast.make_typed_expr pm result_ty
(Aast.Id m
),
4242 (* Dynamic instance property access e.g. $x->$f *)
4243 | Obj_get
(e1
, e2, nullflavor
, prop_or_method
) ->
4244 let (env, te1
, ty1
) = expr ~accept_using_var
:true env e1
in
4245 let (env, te2
, _) = expr env e2 in
4247 if TUtils.is_dynamic
env ty1
then
4248 MakeType.dynamic
(Reason.Rwitness p
)
4250 Typing_utils.mk_tany
env p
4252 let (_, pos, te2
) = te2
in
4253 let env = might_throw env in
4254 let te2 = Tast.make_typed_expr
pos ty te2 in
4255 make_result env p
(Aast.Obj_get
(te1
, te2, nullflavor
, prop_or_method
)) ty
4257 let (env, (taf
, opt_key
, value)) = array_field ~allow_awaitable
env af
in
4258 let Typing_env_return_info.{ return_type = expected_return; _ } =
4262 match get_node
expected_return.et_type
with
4263 | Tclass
(_, _, _ :: _ :: send :: _) -> send
4264 | Tdynamic
when env.in_support_dynamic_type_method_check
->
4265 expected_return.et_type
4267 Errors.internal_error p
"Return type is not a generator";
4268 Typing_utils.terr
env (Reason.Ryield_send p
)
4271 match Env.get_fn_kind
env with
4272 | Ast_defs.FGenerator
-> false
4273 (* This could also catch sync/async non-generators, but an error would
4274 * have already been generated elsewhere *)
4278 match (af
, opt_key
) with
4279 | (AFvalue
(_, p
, _), None
) ->
4281 let (env, ty) = Env.fresh_type
env p
in
4282 (env, MakeType.nullable_locl
(Reason.Ryield_asyncnull p
) ty)
4284 (env, MakeType.int (Reason.Rwitness p
))
4285 | (_, Some x
) -> (env, x
)
4286 | (_, _) -> assert false
4290 MakeType.async_generator
(Reason.Ryield_asyncgen p
) key
value send
4292 MakeType.generator
(Reason.Ryield_gen p
) key
value send
4294 let Typing_env_return_info.{ return_type = expected_return; _ } =
4298 Typing_coercion.coerce_type
4304 Typing_error.Callback.unify_error
4306 let env = Env.forget_members
env Reason.(Blame
(p
, BScall
)) in
4307 let env = LEnv.save_and_merge_next_in_cont
env C.Exit
in
4312 (MakeType.nullable_locl
(Reason.Ryield_send p
) send)
4316 | (_, p
, Aast.Call
((_, _, Aast.Id
(_, func
)), _, _, _))
4317 when String.equal func
SN.PseudoFunctions.unsafe_cast
->
4318 Errors.add_typing_error
4319 Typing_error.(primary
@@ Primary.Unsafe_cast_await p
)
4322 let env = might_throw env in
4323 (* Await is permitted in a using clause e.g. using (await make_handle()) *)
4324 let (env, te, rty) =
4327 ~in_await
:(Reason.Rwitness p
)
4330 ~allow_awaitable
:true
4332 let (env, ty) = Async.overload_extract_from_awaitable
env ~p
rty in
4333 make_result env p
(Aast.Await
te) ty
4335 let env = Env.set_readonly
env true in
4336 let (env, te, rty) = expr ~is_using_clause ~in_readonly_expr
:true env e in
4337 make_result env p
(Aast.ReadonlyExpr
te) rty
4338 | New
((_, pos, c), explicit_targs
, el
, unpacked_element
, ()) ->
4339 let env = might_throw env in
4344 typed_unpack_element
,
4347 should_forget_fakes
) =
4352 ~check_not_abstract
:true
4357 (List.map ~f
:(fun e -> (Ast_defs.Pnormal
, e)) el
)
4361 if should_forget_fakes
then
4362 Env.forget_members
env Reason.(Blame
(p
, BScall
))
4369 (Aast.New
(tc
, tal
, List.map ~f
:snd tel
, typed_unpack_element
, ctor_fty
))
4372 let (env, te, ty2
) = expr ?in_await
env e in
4373 let env = might_throw env in
4376 TypecheckerOptions.experimental_feature_enabled
4378 TypecheckerOptions.experimental_forbid_nullable_cast
4379 && not
(TUtils.is_mixed
env ty2
)
4381 SubType.sub_type_or_fail
env ty2
(MakeType.nonnull
(get_reason ty2
))
4385 @@ Primary.Nullable_cast
4388 ty_name
= lazy (Typing_print.error env ty2
);
4389 ty_pos
= get_pos ty2
;
4395 Phase.localize_hint_no_subst
env ~ignore_errors
:false hint
4397 make_result env p
(Aast.Cast
(hint, te)) ty
4398 | ExpressionTree et
-> expression_tree
env p et
4400 let (env, te, _) = expr env e in
4401 make_result env p
(Aast.Is
(te, hint)) (MakeType.bool (Reason.Rwitness p
))
4402 | As
(e, hint, is_nullable
) ->
4403 let refine_type env lpos lty
rty =
4404 let reason = Reason.Ras lpos
in
4405 let (env, rty) = Env.expand_type
env rty in
4406 refine_and_simplify_intersection
4415 let (env, te, expr_ty
) = expr env e in
4416 let env = might_throw env in
4417 let (env, hint_ty) =
4418 Phase.localize_hint_no_subst
env ~ignore_errors
:false hint
4420 let enable_sound_dynamic =
4421 TypecheckerOptions.enable_sound_dynamic env.genv
.tcopt
4423 let (env, hint_ty) =
4424 if Typing_defs.is_dynamic
hint_ty then
4426 if enable_sound_dynamic then
4428 ~coerce
:(Some
Typing_logic.CoerceToDynamic
)
4432 (Typing_error.Reasons_callback.unify_error_at p
)
4436 let (env, locl
) = make_a_local_of ~include_this
:true env e in
4439 | Some ivar
-> set_local env ivar
hint_ty
4443 else if is_nullable
then
4444 let (_, e_p
, _) = e in
4445 let (env, hint_ty) = refine_type env e_p expr_ty
hint_ty in
4446 (env, MakeType.nullable_locl
(Reason.Rwitness p
) hint_ty)
4448 let (env, locl
) = make_a_local_of ~include_this
:true env e in
4450 | Some
((ivar_pos
, _) as ivar
) ->
4451 let (env, hint_ty) = refine_type env ivar_pos expr_ty
hint_ty in
4452 let env = set_local env ivar
hint_ty in
4455 let (_, e_p
, _) = e in
4456 refine_type env e_p expr_ty
hint_ty
4458 make_result env p
(Aast.As
(te, hint, is_nullable
)) hint_ty
4459 | Upcast
(e, hint) ->
4460 let (env, te, expr_ty
) = expr env e in
4461 let (env, hint_ty) =
4462 Phase.localize_hint_no_subst
env ~ignore_errors
:false hint
4466 ~coerce
:(Some
Typing_logic.CoerceToDynamic
)
4470 (Typing_error.Reasons_callback.unify_error_at p
)
4472 make_result env p
(Aast.Upcast
(te, hint)) hint_ty
4473 | Efun
(f
, idl
) -> lambda ~is_anon
:true ?
expected p
env f idl
4474 | Lfun
(f
, idl
) -> lambda ~is_anon
:false ?
expected p
env f idl
4475 | Xml
(sid
, attrl
, el
) ->
4477 let (env, _tal
, _te
, classes
) =
4478 class_id_for_new ~exact
:Nonexact p
env cid []
4480 (* OK to ignore rest of list; class_info only used for errors, and
4481 * cid = CI sid cannot produce a union of classes anyhow *)
4483 List.find_map classes ~f
:(function
4485 | `Class
(_, class_info, _) -> Some
class_info)
4487 let (env, te, obj
) =
4488 (* New statements derived from Xml literals are of the following form:
4491 * darray<string,mixed> $attributes,
4492 * varray<mixed> $children,
4497 let new_exp = Typing_xhp.rewrite_xml_into_new p sid attrl el
in
4498 expr ?
expected env new_exp
4509 (_, _, (Varray
(_, children
) | ValCollection
(Vec
, _, children
)));
4515 (* Typing_xhp.rewrite_xml_into_new generates an AST node for a `varray[]` literal, which is interpreted as a vec[] *)
4518 (* We end up in this case when the cosntructed new expression does
4522 let (env, typed_attrs
) = xhp_attribute_exprs
env class_info attrl sid obj
in
4523 let txml = Aast.Xml
(sid
, typed_attrs
, tchildren) in
4524 (match class_info with
4525 | None
-> make_result env p
txml (TUtils.terr
env (Reason.Runknown_class p
))
4526 | Some
_ -> make_result env p
txml obj
)
4528 let expr_helper ?
expected env (k
, e) =
4529 let (env, et
, ty) = expr ?
expected env e in
4530 if TypecheckerOptions.pessimise_builtins
(Env.get_tcopt
env) then
4531 let (env, ty) = Typing_array_access.pessimised_tup_assign p
env ty in
4537 match expand_expected_and_get_node env expected with
4538 | (env, Some
(pos, ur, _, _, Tshape
(_, expected_fdm
))) ->
4541 ~f
:(fun env ((k
, _) as ke
) ->
4542 let tk = TShapeField.of_ast
Pos_or_decl.of_raw_pos k
in
4543 match TShapeMap.find_opt
tk expected_fdm
with
4544 | None
-> expr_helper env ke
4547 Typing_array_access.maybe_pessimise_type
env sft
.sft_ty
4549 expr_helper ~
expected:(ExpectedTy.make
pos ur ty) env ke
)
4551 | _ -> List.map_env
env ~f
:expr_helper fdm
4555 ~f
:(fun acc
(k
, _, ty) ->
4556 let tk = TShapeField.of_ast
Pos_or_decl.of_raw_pos k
in
4557 TShapeMap.add
tk { sft_optional
= false; sft_ty
= ty } acc
)
4558 ~
init:TShapeMap.empty
4562 Typing_shapes.check_shape_keys_validity
env (List.map tfdm ~f
:fst3
)
4564 (* Fields are fully known, because this shape is constructed
4565 * using shape keyword and we know exactly what fields are set. *)
4569 (Aast.Shape
(List.map ~f
:(fun (k
, te, _) -> (k
, te)) tfdm
))
4570 (mk
(Reason.Rwitness p
, Tshape
(Closed_shape
, fdm)))
4572 Typing_env.with_in_expr_tree
env false (fun env -> et_splice
env p
e)
4573 | EnumClassLabel
(None
, s
) ->
4574 let (env, expect_label
, lty_opt
) =
4577 let (env, lty
) = Env.expand_type
env ety
.ExpectedTy.ty.et_type
in
4579 match get_node
(TUtils.strip_dynamic env lty
) with
4580 | Tnewtype
(name, _, _) ->
4581 String.equal
SN.Classes.cEnumClassLabel
name
4584 (env, expect_label, Some lty
)
4585 | None
-> (env, false, None
)
4588 if expect_label then
4589 Errors.add_typing_error
4590 Typing_error.(enum
@@ Primary.Enum.Enum_class_label_as_expr p
)
4592 let expected_ty_msg_opt =
4593 Option.map lty_opt ~f
:(fun lty
->
4594 let ty_str = lazy (Typing_print.error env lty
) in
4595 let r = get_reason lty
in
4596 Lazy.map ty_str ~f
:(fun ty_str ->
4597 Reason.to_string
(Format.sprintf
"Expected %s" ty_str) r))
4599 Errors.add_typing_error
4602 @@ Primary.Enum.Enum_class_label_member_mismatch
4603 { pos = p
; label
= s
; expected_ty_msg_opt })
4608 (Aast.EnumClassLabel
(None
, s
))
4609 (mk
(Reason.Rwitness p
, Terr
))
4610 | EnumClassLabel
((Some
(pos, cname
) as e), name) ->
4612 EnumClassLabelOps.expand
4616 ~ctor
:SN.Classes.cEnumClassLabel
4624 (Aast.EnumClassLabel
(e, name))
4625 (mk
(Reason.Rwitness p
, Terr
))
4628 | EnumClassLabelOps.Success
((_, _, texpr
), lty
) ->
4629 make_result env p texpr lty
4630 | EnumClassLabelOps.ClassNotFound
->
4631 (* Error registered in nast_check/unbound_name_check *)
4633 | EnumClassLabelOps.LabelNotFound
_ ->
4634 (* Error registered in EnumClassLabelOps.expand *)
4636 | EnumClassLabelOps.Invalid
4637 | EnumClassLabelOps.Skip
->
4638 Errors.add_typing_error
4639 Typing_error.(enum
@@ Primary.Enum.Enum_class_label_as_expr p
);
4642 and class_const ?
(incl_tc
= false) env p
(cid, mid
) =
4643 let (env, _tal
, ce
, cty
) = class_expr
env [] cid in
4645 match get_node cty
with
4646 | Tclass
((_, n
), _, _)
4647 when Env.is_enum_class
env n
&& String.(SN.Members.mClass
<> snd mid
) ->
4648 Typing_local_ops.enforce_enum_class_variant p
env
4651 let (env, (const_ty
, _tal
)) =
4656 ~coerce_from_ty
:None
4662 make_result env p
(Aast.Class_const
(ce
, mid
)) const_ty
4664 and function_dynamically_callable
env f params_decl_ty ret_locl_ty
=
4665 let env = { env with in_support_dynamic_type_method_check
= true } in
4666 (* If any of the parameters doesn't have an explicit hint, then we have
4667 * to treat this is non-enforceable and therefore not dynamically callable
4668 * based purely on the signature *)
4669 let interface_check =
4670 List.for_all f
.f_params ~f
:(fun param
->
4671 Option.is_some
(snd param
.param_type_hint
))
4672 && Typing_dynamic.sound_dynamic_interface_check
4677 let function_body_check () =
4678 (* Here the body of the function is typechecked again to ensure it is safe
4679 * to call it from a dynamic context (eg. under dyn..dyn->dyn assumptions).
4680 * The code below must be kept in sync with with the fun_def checks.
4682 let make_dynamic pos =
4683 Typing_make_type.dynamic
(Reason.Rsupport_dynamic_type
pos)
4685 let dynamic_return_ty = make_dynamic (get_pos ret_locl_ty
) in
4686 let dynamic_return_info =
4687 Typing_env_return_info.
4689 return_type = MakeType.unenforced
dynamic_return_ty;
4690 return_disposable
= false;
4691 return_explicit
= true;
4692 return_dynamically_callable
= true;
4695 let (env, param_tys
) =
4696 List.zip_exn f
.f_params params_decl_ty
4697 |> List.map_env
env ~f
:(fun env (param
, hint) ->
4699 make_dynamic @@ Pos_or_decl.of_raw_pos param
.param_pos
4703 | Some
ty when Typing_enforceability.is_enforceable
env ty ->
4704 Typing_make_type.intersection
4705 (Reason.Rsupport_dynamic_type
Pos_or_decl.none
)
4709 Typing_param.make_param_local_ty
env (Some
ty) param
)
4711 let params_need_immutable = Typing_coeffects.get_ctx_vars f
.f_ctxs
in
4713 (* In this pass, bind_param_and_check receives a pair where the lhs is
4714 * either Tdynamic or TInstersection of the original type and TDynamic,
4715 * but the fun_param is still referencing the source hint. We amend
4716 * the source hint to keep in in sync before calling bind_param
4717 * so the right enforcement is computed.
4719 let bind_param_and_check env lty_and_param
=
4720 let (ty, param
) = lty_and_param
in
4721 let name = param
.param_name
in
4722 let (hi, hopt
) = param
.param_type_hint
in
4724 Option.map hopt ~f
:(fun (p
, h
) ->
4725 if Typing_utils.is_tintersection
env ty then
4726 (p
, Hintersection
[(p
, h
); (p
, Hdynamic
)])
4730 let param_type_hint = (hi, hopt) in
4731 let param = (ty, { param with param_type_hint }) in
4733 List.exists ~f
:(String.equal
name) params_need_immutable
4735 let (env, fun_param
) = bind_param ~
immutable env param in
4740 (List.zip_exn param_tys f
.f_params
)
4741 ~f
:bind_param_and_check
4744 let pos = fst f
.f_name
in
4745 let env = set_tyvars_variance_in_callable
env dynamic_return_ty param_tys
in
4747 Naming_attributes.mem
4748 SN.UserAttributes.uaDisableTypecheckerInternal
4754 let (_ : env * Tast.stmt list
) =
4755 fun_ ~
disable env dynamic_return_info pos f
.f_body f
.f_fun_kind
4759 Errors.function_is_not_dynamically_callable
pos (snd f
.f_name
) error)
4761 if not
interface_check then function_body_check ()
4763 and lambda ~is_anon ?
expected p
env f idl
=
4764 (* This is the function type as declared on the lambda itself.
4765 * If type hints are absent then use Tany instead. *)
4766 let declared_fe = Decl_nast.lambda_decl_in_env
env.decl_env f
in
4767 let { fe_type
; fe_pos
; _ } = declared_fe in
4768 let (declared_pos
, declared_ft
) =
4769 match get_node fe_type
with
4770 | Tfun
ft -> (fe_pos
, ft)
4771 | _ -> failwith
"Not a function"
4773 let declared_decl_ft =
4774 Typing_enforceability.compute_enforced_and_pessimize_fun_type
4778 (* When creating a closure, the 'this' type will mean the late bound type
4779 * of the current enclosing class
4782 empty_expand_env_with_on_error
4783 (Env.invalid_type_hint_assert_primary_pos_in_current_decl
env)
4785 let (env, declared_ft
) =
4788 ~instantiation
:{ use_name
= "lambda"; use_pos = p
; explicit_targs
= [] }
4790 ~
def_pos:declared_pos
4795 (* Check that none of the explicit capture variables are from a using clause *)
4796 List.iter idl ~f
:(check_escaping_var env);
4798 (* Ensure that variadic parameter has a name *)
4799 (if get_ft_variadic declared_ft
then
4800 match List.last declared_ft
.ft_params
with
4801 | Some
{ fp_name
= None
; _ } ->
4802 Errors.add_typing_error
4805 @@ Primary.Ellipsis_strict_mode
{ require
= `Param_name
; pos = p
})
4808 (* Is the return type declared? *)
4809 let is_explicit_ret = Option.is_some
(hint_of_type_hint f
.f_ret
) in
4810 let check_body_under_known_params ~supportdyn
env ?ret_ty
ft :
4812 let (env, (tefun
, ty, ft)) =
4813 closure_make ~supportdyn ?ret_ty
env p
declared_decl_ft f
ft idl is_anon
4817 ( Reason.Rwitness p
,
4822 (if is_explicit_ret then
4825 MakeType.unenforced
ty);
4828 (env, tefun
, inferred_ty)
4830 let (env, eexpected
) =
4831 expand_expected_and_get_node ~allow_supportdyn
:true env expected
4833 match eexpected
with
4834 | Some
(_pos
, _ur
, _, tdyn
, Tdynamic
)
4835 when env.in_support_dynamic_type_method_check
->
4836 let make_dynamic { et_type
; et_enforced
} =
4838 match (get_node
et_type, et_enforced
) with
4839 | (Tany
_, _) (* lambda param without type hint *)
4840 | (_, Unenforced
) ->
4843 MakeType.intersection
4844 (Reason.Rsupport_dynamic_type
(get_pos tdyn
))
4847 { et_type; et_enforced
}
4850 List.map declared_ft
.ft_params ~f
:(function param ->
4851 { param with fp_type
= make_dynamic param.fp_type
})
4853 check_body_under_known_params
4857 { declared_ft
with ft_params }
4858 | Some
(_pos
, _ur
, supportdyn
, ty, Tfun expected_ft
) ->
4859 (* First check that arities match up *)
4860 check_lambda_arity p
(get_pos
ty) declared_ft expected_ft
;
4861 (* Use declared types for parameters in preference to those determined
4862 * by the context (expected parameters): they might be more general. *)
4863 let rec replace_non_declared_types declared_ft_params expected_ft_params
=
4864 match (declared_ft_params
, expected_ft_params
) with
4865 | ( declared_ft_param
:: declared_ft_params
,
4866 expected_ft_param
:: expected_ft_params
) ->
4868 replace_non_declared_types declared_ft_params expected_ft_params
4870 (* If the type parameter did not have a type hint, it is Tany and
4871 we use the expected type instead. Otherwise, declared type takes
4873 let resolved_ft_param =
4874 if TUtils.is_any
env declared_ft_param
.fp_type
.et_type then
4875 { declared_ft_param
with fp_type
= expected_ft_param
.fp_type
}
4879 resolved_ft_param :: rest
4881 (* Morally, this case should match on ([],[]) because we already
4882 check arity mismatch between declared and expected types. We
4883 handle it more generally here to be graceful. *)
4886 if (not
(get_ft_variadic declared_ft
)) && get_ft_variadic expected_ft
4890 (* This means the expected_ft params list can have more parameters
4891 * than declared parameters in the lambda. For variadics, this is OK.
4899 replace_non_declared_types declared_ft
.ft_params expected_ft.ft_params;
4900 ft_implicit_params
= declared_ft
.ft_implicit_params
;
4901 ft_flags
= declared_ft
.ft_flags
;
4904 (* Don't bother passing in `void` if there is no explicit return *)
4906 match get_node
expected_ft.ft_ret
.et_type with
4907 | Tprim Tvoid
when not
is_explicit_ret -> None
4908 | _ -> Some
expected_ft.ft_ret
.et_type
4910 Typing_log.increment_feature_count
env FL.Lambda.contextual_params
;
4911 check_body_under_known_params ~supportdyn
env ?
ret_ty expected_ft
4913 (* If all parameters are annotated with explicit types, then type-check
4914 * the body under those assumptions and pick up the result type *)
4915 let all_explicit_params =
4916 List.for_all f
.f_params ~f
:(fun param ->
4917 Option.is_some
(hint_of_type_hint
param.param_type_hint))
4919 if all_explicit_params then (
4920 Typing_log.increment_feature_count
4922 (if List.is_empty f
.f_params
then
4925 FL.Lambda.explicit_params
);
4926 check_body_under_known_params ~supportdyn
:false env declared_ft
4929 | Some
ExpectedTy.{ ty = { et_type; _ }; _ } when is_any
et_type ->
4930 (* If the expected type is Tany env then we're passing a lambda to
4931 * an untyped function and we just assume every parameter has type
4933 * Note: we should be using 'nothing' to type the arguments. *)
4934 Typing_log.increment_feature_count
env FL.Lambda.untyped_context
;
4935 check_body_under_known_params ~supportdyn
:false env declared_ft
4936 | Some
ExpectedTy.{ ty = { et_type; _ }; _ }
4937 when TUtils.is_mixed
env et_type || is_dynamic
et_type ->
4938 (* If the expected type of a lambda is mixed or dynamic, we
4939 * decompose the expected type into a function type where the
4940 * undeclared parameters and the return type are set to the expected
4941 * type of lambda, i.e., mixed or dynamic.
4943 * For an expected mixed type, one could argue that the lambda
4944 * doesn't even need to be checked as it can't be called (there is
4945 * no downcast to function type). Thus, we should be using nothing
4946 * to type the arguments. But generally users are very confused by
4947 * the use of nothing and would expect the lambda body to be
4948 * checked as though it could be called.
4950 let replace_non_declared_type declared_ft_param
=
4952 TUtils.is_any
env declared_ft_param
.fp_type
.et_type
4954 if is_undeclared then
4955 let enforced_ty = { et_enforced
= Unenforced
; et_type } in
4956 { declared_ft_param
with fp_type
= enforced_ty }
4962 List.map ~f
:replace_non_declared_type declared_ft
.ft_params
4964 { declared_ft
with ft_params }
4966 let ret_ty = et_type in
4967 check_body_under_known_params ~supportdyn
:false env ~
ret_ty expected_ft
4969 (* If the expected type is something concrete but not a function
4970 * then we should reject in strict mode. Check body anyway.
4971 * Note: we should be using 'nothing' to type the arguments. *)
4972 Errors.add_typing_error
4973 Typing_error.(primary
@@ Primary.Untyped_lambda_strict_mode p
);
4974 Typing_log.increment_feature_count
4976 FL.Lambda.non_function_typed_context
;
4977 check_body_under_known_params ~supportdyn
:false env declared_ft
4979 Typing_log.increment_feature_count
env FL.Lambda.fresh_tyvar_params
;
4981 (* Replace uses of Tany that originated from "untyped" parameters or return type
4982 * with fresh type variables *)
4983 let freshen_ftype env ft =
4984 let freshen_ty env pos et
=
4985 match get_node et
.et_type with
4987 let (env, ty) = Env.fresh_type
env pos in
4988 (env, { et
with et_type = ty })
4989 | Tclass
(id, e, [ty])
4990 when String.equal
(snd
id) SN.Classes.cAwaitable
&& is_any
ty ->
4991 let (env, t
) = Env.fresh_type
env pos in
4995 et_type = mk
(get_reason et
.et_type, Tclass
(id, e, [t
]));
4999 let freshen_untyped_param env ft_param
=
5000 let (env, fp_type
) =
5003 (Pos_or_decl.unsafe_to_raw_pos ft_param
.fp_pos
)
5006 (env, { ft_param
with fp_type
})
5008 let (env, ft_params) =
5009 List.map_env
env ft.ft_params ~f
:freshen_untyped_param
5011 let (env, ft_ret
) = freshen_ty env f
.f_span
ft.ft_ret
in
5012 (env, { ft with ft_params; ft_ret
})
5014 let (env, declared_ft
) = freshen_ftype env declared_ft
in
5016 Env.set_tyvar_variance
env (mk
(Reason.Rnone
, Tfun declared_ft
))
5018 (* TODO(jjwu): the declared_ft here is set to public,
5019 but is actually inferred from the surrounding context
5020 (don't think this matters in practice, since we check lambdas separately) *)
5021 check_body_under_known_params
5024 ~
ret_ty:declared_ft
.ft_ret
.et_type
5029 * Process a spread operator by computing the intersection of XHP attributes
5030 * between the spread expression and the XHP constructor onto which we're
5033 and xhp_spread_attribute
env c_onto valexpr sid obj
=
5034 let (_, p
, _) = valexpr
in
5035 let (env, te, valty
) = expr env valexpr ~allow_awaitable
:(*?*) false in
5036 let (env, attr_ptys
) =
5039 | Some
class_info -> Typing_xhp.get_spread_attributes
env p
class_info valty
5041 let (env, has_err
) =
5044 ~f
:(fun (env, has_err
) attr
->
5045 let (env, _, err_opt) = xhp_attribute_decl_ty env sid obj attr
in
5046 (env, has_err
|| Option.is_some
err_opt))
5049 (* If we have a subtyping error for any attribute, the best we can do here
5050 is give an expected type of dynamic *)
5053 Some
(valty
, MakeType.nothing Reason.Rnone
)
5057 (* Build the typed attribute node *)
5058 let typed_attr = Aast.Xhp_spread
(hole_on_err ~
err_opt te) in
5062 * Simple XHP attributes (attr={expr} form) are simply interpreted as a member
5063 * variable prefixed with a colon.
5065 and xhp_simple_attribute
env id valexpr sid obj
=
5066 let (_, p
, _) = valexpr
in
5067 let (env, te, valty
) = expr env valexpr ~allow_awaitable
:(*?*) false in
5068 (* This converts the attribute name to a member name. *)
5069 let name = ":" ^ snd
id in
5070 let attr_pty = ((fst
id, name), (p
, valty
)) in
5071 let (env, decl_ty
, err_opt) = xhp_attribute_decl_ty env sid obj
attr_pty in
5074 { xs_name
= id; xs_type
= decl_ty
; xs_expr
= hole_on_err ~
err_opt te }
5079 * Typecheck the attribute expressions - this just checks that the expressions are
5080 * valid, not that they match the declared type for the attribute and,
5081 * in case of spreads, makes sure they are XHP.
5083 and xhp_attribute_exprs
env cls_decl attrl sid obj
=
5084 let handle_attr (env, typed_attrl
) attr
=
5085 let (env, typed_attr) =
5087 | Xhp_simple
{ xs_name
= id; xs_expr
= valexpr
; _ } ->
5088 xhp_simple_attribute
env id valexpr sid obj
5089 | Xhp_spread valexpr
-> xhp_spread_attribute
env cls_decl valexpr sid obj
5091 (env, typed_attr :: typed_attrl
)
5093 let (env, typed_attrl
) =
5094 List.fold_left ~f
:handle_attr ~
init:(env, []) attrl
5096 (env, List.rev typed_attrl
)
5098 (*****************************************************************************)
5099 (* Anonymous functions & lambdas. *)
5100 (*****************************************************************************)
5101 and closure_bind_param
params (env, t_params
) ty : env * Tast.fun_param list
=
5104 (* This code cannot be executed normally, because the arity is wrong
5105 * and it will error later. Bind as many parameters as we can and carry
5108 | param :: paraml
->
5110 (match hint_of_type_hint
param.param_type_hint with
5113 (* When creating a closure, the 'this' type will mean the
5114 * late bound type of the current enclosing class
5116 let (env, h
) = Phase.localize_hint_no_subst
env ~ignore_errors
:false h
in
5118 Typing_coercion.coerce_type
5123 (MakeType.unenforced h
)
5124 Typing_error.Callback.unify_error
5126 (* Closures are allowed to have explicit type-hints. When
5127 * that is the case we should check that the argument passed
5128 * is compatible with the type-hint.
5129 * The body of the function should be type-checked with the
5130 * hint and not the type of the argument passed.
5131 * Otherwise it leads to strange results where
5132 * foo(?string $x = null) is called with a string and fails to
5133 * type-check. If $x is a string instead of ?string, null is not
5134 * subtype of string ...
5136 let (env, t_param
) = bind_param env (h
, param) in
5137 (env, t_params
@ [t_param
])
5140 mk
(Reason.Rlambda_param
(param.param_pos
, get_reason
ty), get_node
ty)
5142 let (env, t_param
) = bind_param env (ty, param) in
5143 (env, t_params
@ [t_param
]))
5145 and closure_bind_variadic
env vparam variadic_ty
=
5146 let (env, ty, pos) =
5147 match hint_of_type_hint vparam
.param_type_hint with
5149 (* if the hint is missing, use the type we expect *)
5150 (env, variadic_ty
, get_pos variadic_ty
)
5152 let pos = fst
hint in
5154 Phase.localize_hint_no_subst
env ~ignore_errors
:false hint
5157 Typing_coercion.coerce_type
5162 (MakeType.unenforced h
)
5163 Typing_error.Callback.unify_error
5165 (env, h
, Pos_or_decl.of_raw_pos vparam
.param_pos
)
5167 let r = Reason.Rvar_param_from_decl
pos in
5168 let arr_values = mk
(r, get_node
ty) in
5169 let ty = MakeType.varray
r arr_values in
5170 let (env, t_variadic
) = bind_param env (ty, vparam
) in
5173 and closure_bind_opt_param
env param : env =
5174 match param.param_expr
with
5176 let ty = Typing_utils.mk_tany
env param.param_pos
in
5177 let (env, _) = bind_param env (ty, param) in
5180 let (env, _te
, ty) = expr env default ~allow_awaitable
:(*?*) false in
5181 Typing_sequencing.sequence_check_expr default
;
5182 let (env, _) = bind_param env (ty, param) in
5185 (* Make a type-checking function for an anonymous function or lambda. *)
5186 (* Here ret_ty should include Awaitable wrapper *)
5187 (* TODO: ?el is never set; so we need to fix variadic use of lambda *)
5191 ?
(check_escapes
= true)
5200 let type_closure f
=
5201 (* Wrap the function f so that it can freely clobber function-specific
5202 parts of the environment; the clobbered parts are restored before
5203 returning the result. Additionally, we also prevent type parameters
5204 created in the closure from unsoundly leaking into the environment
5205 of the enclosing function. *)
5206 let snap = Typing_escape.snapshot_env
env in
5207 let (env, (escaping
, (te, hret
, ft))) =
5208 Env.closure
env (fun env ->
5209 stash_conts_for_closure env lambda_pos is_anon idl
(fun env ->
5210 let (env, res) = f
env in
5211 let escaping = Typing_escape.escaping_from_snapshot
snap env in
5212 (env, (escaping, res))))
5214 (* After the body of the function is checked, erase all the type parameters
5215 created from the env and the return type. *)
5217 if check_escapes
then
5218 Typing_escape.refresh_env_and_type
5226 (env, (te, hret
, ft))
5228 type_closure @@ fun env ->
5229 let nb = f
.f_body
in
5230 (* Extract capabilities from AAST and add them to the environment *)
5231 let (env, capability
) =
5232 match (f
.f_ctxs
, f
.f_unsafe_ctxs
) with
5234 (* if the closure has no explicit coeffect annotations,
5235 do _not_ insert (unsafe) capabilities into the environment;
5236 instead, rely on the fact that a capability from an enclosing
5237 scope can simply be captured, which has the same semantics
5238 as redeclaring and shadowing with another same-typed capability.
5239 This avoid unnecessary overhead in the most common case, i.e.,
5240 when a closure does not need a different (usually smaller)
5241 set of capabilities. *)
5242 (env, Env.get_local
env Typing_coeffects.local_capability_id
)
5244 let (env, cap_ty
, unsafe_cap_ty
) =
5245 Typing_coeffects.type_capability
5252 Typing_coeffects.register_capabilities
env cap_ty unsafe_cap_ty
5256 let ft = { ft with ft_implicit_params
= { capability
= CapTy capability
} } in
5257 let env = Env.clear_params
env in
5258 let non_variadic_ft_params =
5259 if get_ft_variadic
ft then
5260 List.drop_last_exn
ft.ft_params
5264 let make_variadic_arg env varg tyl
=
5265 let remaining_types =
5266 (* It's possible the variadic arg will capture the variadic
5267 * parameter of the supplied arity (if arity is Fvariadic)
5268 * and additional supplied params.
5270 * For example in cases such as:
5271 * lambda1 = (int $a, string...$c) ==> {};
5272 * lambda1(1, "hello", ...$y); (where $y is a variadic string)
5273 * lambda1(1, "hello", "world");
5274 * then ...$c will contain "hello" and everything in $y in the first
5275 * example, and "hello" and "world" in the second example.
5277 * To account for a mismatch in arity, we take the remaining supplied
5278 * parameters and return a list of all their types. We'll use this
5279 * to create a union type when creating the typed variadic arg.
5281 let remaining_params =
5282 List.drop
non_variadic_ft_params (List.length f
.f_params
- 1)
5284 List.map ~f
:(fun param -> param.fp_type
.et_type) remaining_params
5286 let r = Reason.Rvar_param varg
.param_pos
in
5287 let union = Tunion
(tyl
@ remaining_types) in
5288 let (env, t_param
) = closure_bind_variadic
env varg
(mk
(r, union)) in
5291 let (env, t_variadic_params
) =
5293 ( List.find f
.f_params ~f
:(fun p
-> p
.param_is_variadic
),
5294 get_ft_variadic
ft )
5296 | (Some arg
, true) ->
5297 make_variadic_arg env arg
[(List.last_exn
ft.ft_params).fp_type
.et_type]
5298 | (Some arg
, false) -> make_variadic_arg env arg
[]
5299 | (_, _) -> (env, [])
5301 let non_variadic_params =
5302 List.filter f
.f_params ~f
:(fun p
-> not p
.param_is_variadic
)
5304 let params = ref non_variadic_params in
5305 let (env, t_params
) =
5307 ~f
:(closure_bind_param
params)
5309 (List.map non_variadic_ft_params ~f
:(fun x
-> x
.fp_type
.et_type))
5311 (* Check attributes on the lambda *)
5312 let (env, user_attributes
) =
5313 attributes_check_def
env SN.AttributeKinds.lambda f
.f_user_attributes
5315 (* Regard a lambda as supporting dynamic if
5316 * it has the attribute <<__SupportDynamicType>>;
5317 * or its enclosing method, function or class has the attribute <<__SupportDynamicType>>;
5318 * or it must support dynamic because of the expected type
5320 let support_dynamic_type =
5321 Naming_attributes.mem
SN.UserAttributes.uaSupportDynamicType user_attributes
5322 || Env.get_support_dynamic_type
env
5325 let env = List.fold_left ~f
:closure_bind_opt_param ~
init:env !params in
5327 List.fold_left ~f
:closure_check_param ~
init:env non_variadic_params
5333 let rec iter l1 l2
=
5337 | (x1
:: rl1
, (pkx_2
, x2
) :: rl2
) ->
5338 param_modes x1 x2 pkx_2
;
5341 iter non_variadic_ft_params x
;
5342 wfold_left2 inout_write_back
env non_variadic_ft_params x
5344 let env = Env.set_fn_kind
env f
.f_fun_kind
in
5346 Option.map ~f
:(Decl_hint.hint env.decl_env
) (hint_of_type_hint f
.f_ret
)
5349 match snd f
.f_ret
with
5350 | Some
(ret_pos, _) -> ret_pos
5351 | None
-> lambda_pos
5356 (* Do we have a contextual return type? *)
5359 | None
-> Typing_return.make_fresh_return_type
env ret_pos
5360 | Some
ret_ty -> (env, ret_ty)
5363 (* If a 'this' type appears it needs to be compatible with the
5367 empty_expand_env_with_on_error
5368 (Env.invalid_type_hint_assert_primary_pos_in_current_decl
env)
5370 Typing_return.make_return_type
(Phase.localize ~
ety_env) env ret
5373 Typing_return.force_return_kind ~is_toplevel
:false env ret_pos hret
5378 ft_ret
= { ft.ft_ret
with et_type = hret
};
5380 Typing_defs_flags.set_bit
5381 Typing_defs_flags.ft_flags_support_dynamic_type
5382 support_dynamic_type
5389 (Typing_return.make_info
5394 ~is_explicit
:(Option.is_some
ret_ty)
5398 let local_tpenv = Env.get_tpenv
env in
5399 (* Outer pipe variables aren't available in closures. Note that
5400 * locals are restored by Env.closure after processing the closure
5403 Env.unset_local
env (Local_id.make_unscoped
SN.SpecialIdents.dollardollar
)
5405 let sound_dynamic_check_saved_env = env in
5406 let (env, tb) = block
env nb.fb_ast
in
5407 let has_implicit_return = LEnv.has_next
env in
5409 if not
has_implicit_return then
5412 Typing_return.fun_implicit_return
env lambda_pos hret f
.f_fun_kind
5414 let has_readonly = Env.get_readonly
env in
5416 Typing_env.set_fun_tast_info
env Tast.{ has_implicit_return; has_readonly }
5418 let (env, tparams) = List.map_env
env f
.f_tparams ~f
:type_param
in
5419 let params_decl_ty =
5420 List.map decl_ft
.ft_params ~f
:(fun { fp_type
= { et_type; _ }; _ } ->
5421 match get_node
et_type with
5423 | _ -> Some
et_type)
5426 TypecheckerOptions.enable_sound_dynamic
5427 (Provider_context.get_tcopt
(Env.get_ctx
env))
5428 && support_dynamic_type
5430 function_dynamically_callable
5431 sound_dynamic_check_saved_env
5437 Aast.f_annotation
= Env.save
local_tpenv env;
5438 Aast.f_readonly_this
= f
.f_readonly_this
;
5439 Aast.f_span
= f
.f_span
;
5440 Aast.f_ret
= (hret
, hint_of_type_hint f
.f_ret
);
5441 Aast.f_readonly_ret
= f
.f_readonly_ret
;
5442 Aast.f_name
= f
.f_name
;
5443 Aast.f_tparams
= tparams;
5444 Aast.f_where_constraints
= f
.f_where_constraints
;
5445 Aast.f_fun_kind
= f
.f_fun_kind
;
5446 Aast.f_user_attributes
= user_attributes
;
5447 Aast.f_body
= { Aast.fb_ast
= tb };
5448 Aast.f_ctxs
= f
.f_ctxs
;
5449 Aast.f_unsafe_ctxs
= f
.f_unsafe_ctxs
;
5450 Aast.f_params
= t_params
@ t_variadic_params
;
5451 Aast.f_external
= f
.f_external
;
5452 Aast.f_doc_comment
= f
.f_doc_comment
;
5455 let ty = mk
(Reason.Rwitness lambda_pos
, Tfun
ft) in
5457 Tast.make_typed_expr
5461 Aast.Efun
(tfun_, idl
)
5463 Aast.Lfun
(tfun_, idl
))
5465 let env = Env.set_tyvar_variance
env ty in
5466 (env, (te, hret
, ft))
5468 (*****************************************************************************)
5469 (* End of anonymous functions & lambdas. *)
5470 (*****************************************************************************)
5472 (*****************************************************************************)
5473 (* Expression trees *)
5474 (*****************************************************************************)
5475 and expression_tree
env p et
=
5479 et_function_pointers
;
5480 et_virtualized_expr
;
5482 et_dollardollar_pos
;
5487 (* Slight hack to deal with |> $$ support *)
5489 match et_dollardollar_pos
with
5491 let dollardollar_var =
5492 Local_id.make_unscoped
SN.ExpressionTrees.dollardollarTmpVar
5494 let dd_var = Local_id.make_unscoped
SN.SpecialIdents.dollardollar
in
5495 let dd_defined = Env.is_local_defined
env dd_var in
5496 if not
dd_defined then
5498 Errors.add_naming_error
5499 @@ Naming_error.Undefined
5502 var_name
= SN.SpecialIdents.dollardollar
;
5503 did_you_mean
= None
;
5506 let nothing_ty = MakeType.nothing Reason.Rnone
in
5507 Env.set_local env dollardollar_var nothing_ty Pos.none
5509 let (dd_ty
, dd_pos
) = Env.get_local_pos
env dd_var in
5510 Env.set_local env dollardollar_var dd_ty dd_pos
5514 (* Given the expression tree literal:
5516 MyVisitor`1 + ${ foo() }`
5518 First, type check the expressions that are spliced in, so foo() in
5520 let (env, t_splices
) = block
env et_splices
in
5522 (* Next, typecheck the function pointer assignments *)
5523 let (env, _, t_function_pointers
) =
5524 Typing_env.with_in_expr_tree
env true (fun env ->
5525 let (env, t_function_pointers
) = block
env et_function_pointers
in
5526 (env, (), t_function_pointers
))
5529 (* Type check the virtualized expression, which will look
5534 return MyVisitor::intType()->__plus($0splice0);
5537 let (env, t_virtualized_expr
, ty_virtual
) =
5538 Typing_env.with_in_expr_tree
env true (fun env ->
5539 expr env et_virtualized_expr ~allow_awaitable
:false)
5542 (* Given the runtime expression:
5544 MyVisitor::makeTree(...)
5546 add the inferred type as a type parameter:
5548 MyVisitor::makeTree<MyVisitorInt>(...)
5550 and then typecheck. *)
5551 let (env, runtime_expr
) =
5552 maketree_with_type_param env p et_runtime_expr ty_virtual
5554 let (env, t_runtime_expr
, ty_runtime_expr
) =
5555 expr env runtime_expr ~allow_awaitable
:false
5561 (Aast.ExpressionTree
5564 et_splices
= t_splices
;
5565 et_function_pointers
= t_function_pointers
;
5566 et_virtualized_expr
= t_virtualized_expr
;
5567 et_runtime_expr
= t_runtime_expr
;
5568 et_dollardollar_pos
;
5572 and et_splice
env p
e =
5573 let (env, te, ty) = expr env e ~allow_awaitable
:(*?*) false in
5574 let (env, ty_visitor
) = Env.fresh_type
env p
in
5575 let (env, ty_res
) = Env.fresh_type
env p
in
5576 let (env, ty_infer
) = Env.fresh_type
env p
in
5577 let spliceable_type =
5578 MakeType.spliceable
(Reason.Rsplice p
) ty_visitor ty_res ty_infer
5585 (Typing_error.Reasons_callback.unify_error_at p
)
5587 make_result env p
(Aast.ET_Splice
te) ty_infer
5589 (*****************************************************************************)
5590 (* End expression trees *)
5591 (*****************************************************************************)
5593 ~
(expected : ExpectedTy.t
option)
5603 (* Obtain class info from the cid expression. We get multiple
5604 * results with a CIexpr that has a union type, e.g. in
5606 $classname = (mycond()? classname<A>: classname<B>);
5609 let (env, tal
, tcid
, classes
) =
5610 instantiable_cid ~exact
:Exact p
env cid explicit_targs
5612 let allow_abstract_bound_generic =
5614 | (ty, _, Aast.CI
(_, tn
)) -> is_generic_equal_to tn
ty
5618 (env, _tel
, _typed_unpack_element
, should_forget_fakes_acc
)
5619 (cname
, class_info, c_ty
) =
5622 && Cls.abstract
class_info
5623 && (not
(requires_consistent_construct cid))
5624 && not
allow_abstract_bound_generic
5626 uninstantiable_error
5630 (Cls.pos class_info)
5631 (Cls.name class_info)
5634 let (env, obj_ty_
, params) =
5635 let (env, c_ty
) = Env.expand_type
env c_ty
in
5636 match (cid, tal
, get_class_type c_ty
) with
5637 (* Explicit type arguments *)
5638 | (CI
_, _ :: _, Some
(_, _, tyl
)) -> (env, get_node c_ty
, tyl
)
5639 | (_, _, class_type_opt
) ->
5641 List.map_env
env (Cls.tparams class_info) ~f
:(fun env tparam ->
5643 Env.fresh_type_reason
5646 (Reason.Rtype_variable_generics
5647 (p
, snd
tparam.tp_name
, strip_ns
(snd cname
)))
5649 Typing_log.log_new_tvar_for_new_object
env p tvar cname
tparam;
5653 match class_type_opt
with
5654 | Some
(_, Exact
, _) -> (env, Tclass
(cname
, Exact
, params), params)
5655 | _ -> (env, Tclass
(cname
, Nonexact
, params), params)
5660 && (not is_using_clause
)
5661 && Typing_disposable.is_disposable_class
env class_info
5663 Errors.add_typing_error
5664 Typing_error.(primary
@@ Primary.Invalid_new_disposable p
);
5665 let r_witness = Reason.Rwitness p
in
5666 let obj_ty = mk
(r_witness, obj_ty_
) in
5671 mk
(r_witness, get_node
c_ty)
5675 let (cid_ty
, _, _) = tcid
in
5676 let (env, cid_ty
) = Env.expand_type
env cid_ty
in
5677 if is_generic cid_ty
then
5679 else if check_parent
then
5682 ExprDepTy.make
env ~
cid c_ty
5684 (* Set variance according to type of `new` expression now. Lambda arguments
5685 * to the constructor might depend on it, and `call_construct` only uses
5686 * `ctor_fty` to set the variance which has void return type *)
5687 let env = Env.set_tyvar_variance
env new_ty
in
5688 let (env, tel
, typed_unpack_element
, ctor_fty
, should_forget_fakes
) =
5689 let env = check_expected_ty "New" env new_ty
expected in
5690 call_construct p
env class_info params el unpacked_element
cid new_ty
5692 let should_forget_fakes_acc =
5693 should_forget_fakes_acc || should_forget_fakes
5695 (if equal_consistent_kind
(snd
(Cls.construct
class_info)) Inconsistent
then
5698 let (class_pos
, class_name) = cname
in
5699 Errors.add_typing_error
5702 @@ Primary.New_inconsistent_construct
5703 { pos = p
; class_name; class_pos
; kind
= `static
})
5705 let (class_pos
, class_name) = cname
in
5706 Errors.add_typing_error
5709 @@ Primary.New_inconsistent_construct
5710 { pos = p
; class_name; class_pos
; kind
= `
classname })
5714 let (env, ctor_fty
) =
5715 match fst
(Cls.construct
class_info) with
5716 | Some
({ ce_type
= (lazy ty); _ } as ce
) ->
5719 empty_expand_env
with
5721 TUtils.make_locl_subst_for_class_tparams
class_info params;
5725 if get_ce_abstract ce
then
5726 Errors.add_typing_error
5729 @@ Primary.Parent_abstract_call
5731 meth_name
= SN.Members.__construct
;
5733 decl_pos
= get_pos ctor_fty
;
5735 let (env, ctor_fty
) = Phase.localize ~
ety_env env ty in
5737 | None
-> (env, ctor_fty
)
5739 ( (env, tel
, typed_unpack_element
, should_forget_fakes_acc),
5740 (obj_ty, ctor_fty
) )
5744 ( (env, tel
, typed_unpack_element
, should_forget_fakes_acc),
5747 (* When constructing from a (classname) variable, the variable
5748 * dictates what the constructed object is going to be. This allows
5749 * for generic and dependent types to be correctly carried
5750 * through the 'new $foo()' iff the constructed obj_ty is a
5751 * supertype of the variable-dictated c_ty *)
5759 Typing_error.Callback.unify_error
5761 ( (env, tel
, typed_unpack_element
, should_forget_fakes_acc),
5764 let (had_dynamic
, classes
) =
5765 List.fold classes ~
init:(false, []) ~f
:(fun (seen_dynamic
, classes
) -> function
5766 | `Dynamic
-> (true, classes
)
5767 | `Class
(cname
, class_info, c_ty) ->
5768 (seen_dynamic
, (cname
, class_info, c_ty) :: classes
))
5770 let ( (env, tel
, typed_unpack_element
, should_forget_fakes
),
5771 class_types_and_ctor_types
) =
5772 List.fold_map classes ~
init:(env, [], None
, false) ~f
:gather
5774 let class_types_and_ctor_types =
5775 let r = Reason.Rdynamic_construct p
in
5776 let dyn = (mk
(r, Tdynamic
), mk
(r, Tdynamic
)) in
5778 dyn :: class_types_and_ctor_types
5780 class_types_and_ctor_types
5782 let (env, tel
, typed_unpack_element
, ty, ctor_fty
) =
5783 match class_types_and_ctor_types with
5786 argument_list_exprs
(expr ~allow_awaitable
:false) env el
5788 let (env, typed_unpack_element
, _) =
5789 match unpacked_element
with
5790 | None
-> (env, None
, MakeType.nothing Reason.Rnone
)
5791 | Some unpacked_element
->
5793 expr env unpacked_element ~allow_awaitable
:(*?*) false
5797 let r = Reason.Runknown_class p
in
5798 let terr = TUtils.terr env r in
5799 (env, tel
, typed_unpack_element
, terr, terr)
5800 | [(ty, ctor_fty
)] -> (env, tel
, typed_unpack_element
, ty, ctor_fty
)
5802 let (tyl
, ctyl
) = List.unzip l
in
5803 let r = Reason.Rwitness p
in
5804 (env, tel
, typed_unpack_element
, mk
(r, Tunion tyl
), mk
(r, Tunion ctyl
))
5807 let (cid_ty
, _, _) = tcid
in
5808 let (env, cid_ty
) = Env.expand_type
env cid_ty
in
5809 if is_generic cid_ty
then
5811 else if check_parent
then
5814 ExprDepTy.make
env ~
cid ty
5820 typed_unpack_element
,
5823 should_forget_fakes
)
5825 and attributes_check_def
env kind attrs
=
5826 let new_object attr_pos
env attr_cid
params =
5827 let (env, _, _, _, _, _, _, _) =
5831 ~check_not_abstract
:false
5832 ~is_using_clause
:false
5835 (Aast.CI
(Positioned.unsafe_to_raw_positioned attr_cid
))
5837 (List.map ~f
:(fun e -> (Ast_defs.Pnormal
, e)) params)
5838 (* list of attr parameter literals *)
5840 (* no variadic arguments *)
5844 let env = Typing_attributes.check_def
env new_object kind attrs
in
5845 List.map_env
env attrs ~f
:user_attribute
5847 (** Get class infos for a class expression (e.g. `parent`, `self` or
5848 regular classnames) - which might resolve to a union or intersection
5849 of classes - and check they are instantiable.
5851 FIXME: we need to separate our instantiability into two parts. Currently,
5852 all this function is doing is checking if a given type is inhabited --
5853 that is, whether there are runtime values of type Aast. However,
5854 instantiability should be the stricter notion that T has a runtime
5855 constructor; that is, `new T()` should be valid. In particular, interfaces
5856 are inhabited, but not instantiable.
5857 To make this work with classname, we likely need to add something like
5858 concrete_classname<T>, where T cannot be an interface. *)
5859 and instantiable_cid ?
(exact
= Nonexact
) p
env cid explicit_targs
:
5860 newable_class_info
=
5861 let (env, tal
, te, classes
) =
5862 class_id_for_new ~exact p
env cid explicit_targs
5864 List.iter classes ~f
:(function
5866 | `Class
((pos, name), class_info, c_ty) ->
5867 let pos = Pos_or_decl.unsafe_to_raw_pos
pos in
5868 let kind = Cls.kind class_info in
5870 Ast_defs.is_c_trait
kind
5871 || Ast_defs.is_c_enum
kind
5872 || Ast_defs.is_c_enum_class
kind
5877 uninstantiable_error env p
cid (Cls.pos class_info) name pos c_ty
5882 else if Ast_defs.is_c_abstract
kind && Cls.final
class_info then
5883 uninstantiable_error env p
cid (Cls.pos class_info) name pos c_ty
5886 (env, tal
, te, classes
)
5888 (* Deal with assignment of a value of type ty2 to lvalue e1 *)
5889 and assign p
env e1 pos2 ty2
=
5890 assign_with_subtype_err_ p
Reason.URassign
env e1 pos2 ty2
5892 and assign_ p
ur env e1 pos2 ty2
=
5893 let (env, te, ty, _err
) = assign_with_subtype_err_ p
ur env e1 pos2 ty2
in
5896 and assign_with_subtype_err_ p
ur env (e1
: Nast.expr) pos2 ty2
=
5898 | (_, _, Hole
(e, _, _, _)) -> assign_with_subtype_err_ p
ur env e pos2 ty2
5900 let allow_awaitable = (*?*) false in
5903 | (_, _, Lvar
(_, x
)) ->
5904 Env.forget_prefixed_members
env x
Reason.(Blame
(p
, BSassignment
))
5905 (* If we ever extend fake members from $x->a to more complicated lvalues
5906 such as $x->a->b, we would need to call forget_prefixed_members on
5907 other lvalues as well. *)
5908 | (_, _, Obj_get
(_, (_, _, Id
(_, property
)), _, _)) ->
5909 Env.forget_suffixed_members
5912 Reason.(Blame
(p
, BSassignment
))
5916 | (_, _, Lvar
((_, x
) as id)) ->
5917 let env = set_valid_rvalue p
env x ty2
in
5918 let (_, p1
, _) = e1
in
5919 let (env, te, ty) = make_result env p1
(Aast.Lvar
id) ty2
in
5921 | (_, _, Lplaceholder
id) ->
5922 let placeholder_ty = MakeType.void
(Reason.Rplaceholder p
) in
5923 let (_, p1
, _) = e1
in
5925 make_result env p1
(Aast.Lplaceholder
id) placeholder_ty
5928 | (_, _, List el
) ->
5929 (* Generate fresh types for each lhs list element, then subtype against
5932 List.map_env
env el ~f
:(fun env (_, p
, _e
) -> Env.fresh_type
env p
)
5934 let (_, p1
, _) = e1
in
5935 let destructure_ty =
5936 MakeType.list_destructure
(Reason.Rdestructure p1
) tyl
5938 let lty2 = LoclType ty2
in
5939 let assign_accumulate (env, tel
, errs
) (lvalue
: Nast.expr) ty2
=
5940 let (env, te, _, err_opt) = assign p
env lvalue pos2 ty2
in
5941 (env, te :: tel
, err_opt :: errs
)
5943 let type_list_elem env =
5944 let (env, reversed_tel
, rev_subtype_errs
) =
5945 List.fold2_exn el tyl ~
init:(env, [], []) ~f
:assign_accumulate
5947 let (_, p1
, _) = e1
in
5949 make_result env p1
(Aast.List
(List.rev reversed_tel
)) ty2
5951 (env, te, ty, List.rev rev_subtype_errs
)
5954 (* Here we attempt to unify the type of the rhs we assigning with
5955 a number of fresh tyvars corresponding to the arity of the lhs `list`
5957 if we have a failure in subtyping the fresh tyvars in `destructure_ty`,
5958 we have a rhs which cannot be destructured to the variables on the lhs;
5959 e.g. `list($x,$y) = 2` or `list($x,$y) = tuple (1,2,3)`
5961 in the error case, we add a `Hole` with expected type `nothing` since
5962 there is no type we can suggest was expected
5964 in the ok case were the destrucutring succeeded, the fresh vars
5965 now have types so we can subtype each element, accumulate the errors
5966 and pack back into the rhs structure as our expected type *)
5969 let (env, te, ty, subty_errs
) = type_list_elem env in
5971 if List.for_all subty_errs ~f
:Option.is_none
then
5974 Some
(ty2
, pack_errs pos2 ty2
(subty_errs
, None
))
5976 (env, te, ty, err_opt))
5978 let (env, te, ty, _) = type_list_elem env in
5980 MakeType.nothing @@ Reason.Rsolve_fail
(Pos_or_decl.of_raw_pos pos2
)
5982 (env, te, ty, Some
(ty2
, nothing)))
5983 @@ Result.map ~f
:(fun env -> Env.set_tyvar_variance_i
env destructure_ty)
5984 @@ Type.sub_type_i_res
5990 Typing_error.Callback.unify_error
5994 (obj
, (_, pm
, Id
((_, member_name
) as m
)), nullflavor
, prop_or_method
)
5996 let lenv = env.lenv in
5998 match nullflavor
with
5999 | OG_nullthrows
-> None
6000 | OG_nullsafe
-> Some
(Reason.Rnullsafe_op pobj
)
6002 let (env, tobj
, obj_ty) =
6003 expr ~accept_using_var
:true env obj ~
allow_awaitable
6005 let env = might_throw env in
6006 let (_, p1
, _) = obj
in
6007 let (env, (declared_ty
, _tal
), lval_err_opt
, rval_err_opt
) =
6008 TOG.obj_get_with_err
6014 ~coerce_from_ty
:(Some
(p
, ur, ty2
))
6016 ~class_id
:(CIexpr e1
)
6018 ~on_error
:Typing_error.Callback.unify_error
6023 Tast.make_typed_expr
6027 ( hole_on_err ~
err_opt:lval_err_opt tobj
,
6028 Tast.make_typed_expr pm declared_ty
(Aast.Id m
),
6032 let env = { env with lenv } in
6037 let (env, local) = Env.FakeMembers.make
env obj member_name p
in
6038 let (env, refined_ty
) =
6039 Inter.intersect
env ~
r:(Reason.Rwitness p
) declared_ty ty2
6041 let env = set_valid_rvalue p
env local refined_ty
in
6042 (env, te1, ty2
, rval_err_opt
)
6043 | _ -> (env, te1, ty2
, rval_err_opt
)
6045 | (_, _, Obj_get
_) ->
6046 let lenv = env.lenv in
6047 let no_fakes = LEnv.env_with_empty_fakes
env in
6048 let (env, te1, real_type
) = lvalue
no_fakes e1
in
6049 let (env, exp_real_type
) = Env.expand_type
env real_type
in
6050 let env = { env with lenv } in
6051 let (env, err_opt) =
6053 ~ok
:(fun env -> (env, None
))
6054 ~
error:(fun env -> (env, Some
(ty2
, exp_real_type
)))
6055 @@ Typing_coercion.coerce_type_res
6060 (MakeType.unenforced exp_real_type
)
6061 Typing_error.Callback.unify_error
6063 (env, te1, ty2
, err_opt)
6064 | (_, _, Class_get
(_, CGexpr
_, _)) ->
6065 failwith
"AST should not have any CGexprs after naming"
6066 | (_, _, Class_get
(((_, _, x
) as cid), CGstring
(pos_member
, y
), _)) ->
6067 let lenv = env.lenv in
6068 let no_fakes = LEnv.env_with_empty_fakes
env in
6069 let (env, te1, _) = lvalue
no_fakes e1
in
6070 let env = { env with lenv } in
6071 let (env, ety2
) = Env.expand_type
env ty2
in
6072 (* This defers the coercion check to class_get, which looks up the appropriate target type *)
6073 let (env, _tal
, _, cty
) = class_expr
env [] cid in
6074 let env = might_throw env in
6075 let (env, (declared_ty
, _), rval_err_opt
) =
6079 ~coerce_from_ty
:(Some
(p
, ur, ety2
))
6085 let (env, local) = Env.FakeMembers.make_static
env x y p
in
6086 let (env, refined_ty
) =
6087 Inter.intersect
env ~
r:(Reason.Rwitness p
) declared_ty ty2
6089 let env = set_valid_rvalue p
env local refined_ty
in
6090 (env, te1, ty2
, rval_err_opt
)
6091 | (_, pos, Array_get
(e1
, None
)) ->
6092 let (env, te1, ty1
) = update_array_type
pos env e1 `lvalue
in
6093 let (_, p1
, _) = e1
in
6094 let (env, ty1'
, arr_err_opt
, val_err_opt
) =
6095 Typing_array_access.assign_array_append_with_err
6104 if is_hack_collection env ty1
then
6105 (env, hole_on_err ~
err_opt:arr_err_opt
te1)
6107 let (env, te1, ty, _) =
6108 assign_with_subtype_err_ p
ur env e1 p1 ty1'
6110 (* Update the actual type to that after assignment *)
6112 Option.map arr_err_opt ~f
:(fun (_, ty_expect
) -> (ty, ty_expect
))
6114 (env, hole_on_err ~
err_opt:arr_err_opt te1)
6117 make_result env pos (Aast.Array_get
(te1, None
)) ty2
6119 (env, te, ty, val_err_opt
)
6120 | (_, pos, Array_get
(e1
, Some
e)) ->
6121 let (env, te1, ty1
) = update_array_type
pos env e1 `lvalue
in
6122 let (env, te, ty) = expr env e ~
allow_awaitable in
6123 let env = might_throw env in
6124 let (_, p1
, _) = e1
in
6125 let (env, ty1'
, arr_err_opt, key_err_opt
, val_err_opt
) =
6126 Typing_array_access.assign_array_get_with_err
6137 if is_hack_collection env ty1
then
6138 (env, hole_on_err ~
err_opt:arr_err_opt te1)
6140 let (env, te1, ty, _) =
6141 assign_with_subtype_err_ p
ur env e1 p1 ty1'
6143 (* Update the actual type to that after assignment *)
6145 Option.map arr_err_opt ~f
:(fun (_, ty_expect
) -> (ty, ty_expect
))
6147 (env, hole_on_err ~
err_opt:arr_err_opt te1)
6152 Aast.Array_get
(te1, Some
(hole_on_err ~
err_opt:key_err_opt
te)) ),
6155 | _ -> assign_simple p
ur env e1 ty2
)
6157 and assign_simple
pos ur env e1 ty2
=
6158 let (env, te1, ty1
) = lvalue
env e1
in
6159 let (env, err_opt) =
6161 ~ok
:(fun env -> (env, None
))
6162 ~
error:(fun env -> (env, Some
(ty2
, ty1
)))
6163 @@ Typing_coercion.coerce_type_res
6168 (MakeType.unenforced ty1
)
6169 Typing_error.Callback.unify_error
6171 (env, te1, ty2
, err_opt)
6173 and array_field
env ~
allow_awaitable = function
6175 let (env, tve
, tv) = expr env ve ~
allow_awaitable in
6176 (env, (Aast.AFvalue tve
, None
, tv))
6177 | AFkvalue
(ke
, ve
) ->
6178 let (env, tke
, tk) = expr env ke ~
allow_awaitable in
6179 let (env, tve
, tv) = expr env ve ~
allow_awaitable in
6180 (env, (Aast.AFkvalue
(tke
, tve
), Some
tk, tv))
6182 and array_value ~
(expected : ExpectedTy.t
option) env x
=
6183 let (env, te, ty) = expr ?
expected env x ~
allow_awaitable:(*?*) false in
6191 ~
(expected : ExpectedTy.t
option)
6193 ((_, pos, _) as x
) =
6194 let (env, (te, ty)) = array_value ~
expected env x
in
6195 let (ty_arraykey
, reason) =
6197 ( MakeType.arraykey (Reason.Rset_element
pos),
6198 Reason.set_element
class_name )
6200 (MakeType.arraykey (Reason.Ridx_dict
pos), Reason.index_class
class_name)
6202 let ty_expected = { et_type = ty_arraykey
; et_enforced
= Enforced
} in
6205 (* If we have an error in coercion here, we will add a `Hole` indicating the
6206 actual and expected type. The `Hole` may then be used in a codemod to
6207 add a call to `UNSAFE_CAST` so we need to consider what type we expect.
6209 If we were to add an expected type of 'arraykey' here it would be
6210 correct but adding an `UNSAFE_CAST<?string,arraykey>($x)` means we
6211 get cascading errors if we have e.g. a return type of keyset<string>.
6213 To try and prevent this, if this is an optional type where the nonnull
6214 part can be coerced to arraykey, we prefer that type as our expected type.
6216 let (ok
, ty_actual
) =
6218 | (_, Toption ty_inner
) ->
6220 let ty_str = lazy (Typing_print.full_strip_ns
env ty_inner
) in
6223 (Lazy.map ty_str ~f
:(fun ty_str ->
6225 "Expected `arraykey`"
6226 (Reason.Ridx_dict
pos)
6227 @ [(get_pos
ty, Format.sprintf
"But got `?%s`" ty_str)]))
6229 (* We actually failed so generate the error we should
6231 Errors.add_typing_error
6234 @@ Primary.Unify_error
6237 msg_opt
= Some
(Reason.string_of_ureason
reason);
6240 (env, Some
(ty, ty_inner
))),
6242 | _ -> ((fun env -> (env, None
)), ty)
6244 let (env, err_opt) =
6245 Result.fold ~ok ~
error:(fun env -> (env, Some
(ty_actual
, ty_arraykey
)))
6246 @@ Typing_coercion.coerce_type_res
6253 Typing_error.Callback.unify_error
6255 (env, hole_on_err ~
err_opt te)
6258 Typing_coercion.coerce_type
6265 Typing_error.Callback.unify_error
6272 and check_parent_construct
pos env el unpacked_element env_parent
=
6273 let check_not_abstract = false in
6274 let (env, env_parent
) =
6275 Phase.localize_no_subst
env ~ignore_errors
:true env_parent
6281 typed_unpack_element
,
6284 should_forget_fakes
) =
6289 ~is_using_clause
:false
6297 (* Not sure why we need to equate these types *)
6305 Typing_error.Callback.unify_error
6314 Typing_error.Callback.unify_error
6318 typed_unpack_element
,
6319 MakeType.void
(Reason.Rwitness
pos),
6322 should_forget_fakes
)
6324 and call_parent_construct
pos env el unpacked_element
=
6325 match Env.get_parent_ty
env with
6326 | Some parent
-> check_parent_construct
pos env el unpacked_element parent
6329 let ty = Typing_utils.mk_tany
env pos in
6330 let should_invalidate_fake_members = true in
6331 let default = (env, [], None
, ty, ty, ty, should_invalidate_fake_members) in
6332 (match Env.get_self_id
env with
6334 (match Env.get_class
env self
with
6335 | Some trait
when Ast_defs.is_c_trait
(Cls.kind trait
) ->
6336 (match trait_most_concrete_req_class trait
env with
6338 Errors.add_typing_error
6339 Typing_error.(primary
@@ Primary.Parent_in_trait
pos);
6341 | Some
(c, parent_ty
) ->
6342 (match Cls.construct
c with
6343 | (_, Inconsistent
) ->
6344 Errors.add_typing_error
6347 @@ Primary.Trait_parent_construct_inconsistent
6348 { pos; decl_pos
= Cls.pos c })
6350 check_parent_construct
pos env el unpacked_element parent_ty
)
6352 Errors.add_typing_error
6353 Typing_error.(primary
@@ Primary.Undefined_parent
pos);
6355 | None
-> assert false)
6357 Errors.add_typing_error
6358 Typing_error.(primary
@@ Primary.Parent_outside_class
pos);
6359 let ty = err_witness env pos in
6360 (env, [], None
, ty, ty, ty, should_invalidate_fake_members))
6362 (* Depending on the kind of expression we are dealing with
6363 * The typing of call is different.
6366 ~
(expected : ExpectedTy.t
option)
6372 ((_, fpos
, fun_expr
) as e : Nast.expr)
6376 let expr = expr ~
allow_awaitable:(*?*) false in
6377 let make_call env te tal tel typed_unpack_element
ty =
6378 make_result env p
(Aast.Call
(te, tal
, tel
, typed_unpack_element
)) ty
6382 | `lvalue_subexpr
->
6383 Errors.add_typing_error
Typing_error.(primary
@@ Primary.Call_lvalue p
)
6385 (* TODO: Avoid Tany annotations in TAST by eliminating `make_call_special` *)
6386 let make_call_special env id tel
ty =
6389 (Tast.make_typed_expr fpos
(TUtils.mk_tany
env fpos
) (Aast.Id
id))
6395 (* For special functions and pseudofunctions with a definition in an HHI
6396 * file. It is preferred over [make_call_special] because it does not generate
6397 * [TAny] for the function type of the call.
6399 let make_call_special_from_def env id tel ty_
=
6400 let (env, fty, tal
) = fun_type_of_id env id explicit_targs el
in
6402 match get_node
fty with
6403 | Tfun
ft -> ft.ft_ret
.et_type
6404 | _ -> ty_
(Reason.Rwitness p
)
6406 make_call env (Tast.make_typed_expr fpos
fty (Aast.Id
id)) tal tel None
ty
6408 let overload_function = overload_function make_call fpos
in
6409 (* Require [get_idisposable_value()] function calls to be inside a [using]
6411 let check_disposable_in_return env fty =
6412 if is_return_disposable_fun_type env fty && not is_using_clause
then
6413 Errors.add_typing_error
6414 Typing_error.(primary
@@ Primary.Invalid_new_disposable p
)
6417 let dispatch_id env id =
6418 let (env, fty, tal
) = fun_type_of_id env id explicit_targs el
in
6419 check_disposable_in_return env fty;
6420 let (env, (tel
, typed_unpack_element
, ty, should_forget_fakes
)) =
6421 call ~
expected p
env fty el unpacked_element
6426 (Tast.make_typed_expr fpos
fty (Aast.Id
id))
6429 typed_unpack_element
6432 (result, should_forget_fakes
)
6434 let dispatch_class_const env ((_, pos, e1_
) as e1
) m
=
6435 let (env, _tal
, tcid
, ty1
) = class_expr
env [] e1
in
6436 let this_ty = MakeType.this
(Reason.Rwitness fpos
) in
6437 (* In static context, you can only call parent::foo() on static methods.
6438 * In instance context, you can call parent:foo() on static
6439 * methods as well as instance methods
6442 (not
(Nast.equal_class_id_ e1_ CIparent
))
6443 || Env.is_static env
6444 || class_contains_smethod env ty1 m
6446 let (env, (fty, tal
)) =
6447 if not
is_static then
6448 (* parent::nonStaticFunc() is really weird. It's calling a method
6449 * defined on the parent class, but $this is still the child class.
6457 ~coerce_from_ty
:None
6461 ~on_error
:Typing_error.Callback.unify_error
6467 ~coerce_from_ty
:None
6476 check_disposable_in_return env fty;
6477 let (env, (tel
, typed_unpack_element
, ty, should_forget_fakes
)) =
6478 call ~
expected p
env fty el unpacked_element
6483 (Tast.make_typed_expr fpos
fty (Aast.Class_const
(tcid
, m
)))
6486 typed_unpack_element
6489 (result, should_forget_fakes
)
6492 (* Special top-level function *)
6493 | Id
((pos, x
) as id) when SN.StdlibFunctions.needs_special_dispatch x
->
6496 (* Special function [echo]. *)
6497 | echo
when String.equal echo
SN.SpecialFunctions.echo
->
6498 (* TODO(tany): TODO(T92020097):
6499 * Add [function print(arraykey ...$args)[io]: void] to an HHI file and
6500 * remove special casing of [echo] and [print].
6502 let env = Typing_local_ops.enforce_io
pos env in
6504 argument_list_exprs
(expr ~accept_using_var
:true) env el
6506 let arraykey_ty = MakeType.arraykey (Reason.Rwitness
pos) in
6509 (Reason.Rwitness
pos)
6510 [MakeType.dynamic
(Reason.Rwitness
pos); arraykey_ty]
6512 let (env, rev_tel
) =
6516 ~f
:(fun (env, tel
) (pk
, ((ty, pos, _) as te)) ->
6517 let (env, err_opt) =
6519 ~ok
:(fun env -> (env, None
))
6520 ~
error:(fun env -> (env, Some
(ty, arraykey_ty)))
6521 @@ SubType.sub_type_res
6525 (Typing_error.Reasons_callback.invalid_echo_argument_at
6528 (env, (pk
, hole_on_err ~
err_opt te) :: tel
))
6530 let tel = List.rev rev_tel
in
6531 let should_forget_fakes = false in
6532 ( make_call_special env id tel (MakeType.void
(Reason.Rwitness
pos)),
6533 should_forget_fakes )
6535 | unsafe_cast
when String.equal unsafe_cast
SN.PseudoFunctions.unsafe_cast
6539 | [(Ast_defs.Pnormal
, original_expr
)]
6540 when TypecheckerOptions.ignore_unsafe_cast
(Env.get_tcopt
env) ->
6541 expr env original_expr
6543 (* first type the `unsafe_cast` as a call, handling arity errors *)
6544 let (env, fty, tal
) = fun_type_of_id env id explicit_targs el
in
6545 check_disposable_in_return env fty;
6546 let (env, (tel, _, ty, _should_forget_fakes
)) =
6547 call ~
expected p
env fty el unpacked_element
6549 (* construct the `Hole` using default value and type arguments
6551 let dflt_ty = MakeType.err Reason.none
in
6555 | [] -> Tast.make_typed_expr fpos
dflt_ty Aast.Null
6556 and (ty_from
, ty_to
) =
6558 | (ty_from
, _) :: (ty_to
, _) :: _ -> (ty_from
, ty_to
)
6559 | (ty, _) :: _ -> (ty, ty)
6560 | _ -> (dflt_ty, dflt_ty)
6564 (el, ty_from
, ty_to
, UnsafeCast
(List.map ~f
:snd explicit_targs
))
6566 make_result env p
te ty
6568 let should_forget_fakes = false in
6569 (result, should_forget_fakes)
6570 (* Special function `isset` *)
6571 | isset
when String.equal isset
SN.PseudoFunctions.isset
->
6574 (expr ~accept_using_var
:true ~check_defined
:false)
6578 if Option.is_some unpacked_element
then
6579 Errors.add_typing_error
6582 @@ Primary.Unpacking_disallowed_builtin_function
6583 { pos = p
; fn_name
= isset
});
6584 let should_forget_fakes = false in
6585 let result = make_call_special_from_def env id tel MakeType.bool in
6586 (result, should_forget_fakes)
6587 (* Special function `unset` *)
6588 | unset
when String.equal unset
SN.PseudoFunctions.unset
->
6589 let (env, tel, _) = argument_list_exprs
expr env el in
6590 if Option.is_some unpacked_element
then
6591 Errors.add_typing_error
6594 @@ Primary.Unpacking_disallowed_builtin_function
6595 { pos = p
; fn_name
= unset
});
6596 let env = Typing_local_ops.check_unset_target
env tel in
6598 match (el, unpacked_element
) with
6599 | ([(Ast_defs.Pnormal
, (_, _, Array_get
(ea
, Some
_)))], None
) ->
6600 let (env, _te
, ty) = expr env ea
in
6601 let r = Reason.Rwitness p
in
6602 let tmixed = MakeType.mixed r in
6609 MakeType.dict
r tmixed tmixed;
6610 MakeType.keyset
r tmixed;
6611 MakeType.darray
r tmixed tmixed;
6616 ("This is " ^
Typing_print.error ~ignore_dynamic
:true env ty)
6619 SubType.sub_type_or_fail
env ty super
6622 primary
@@ Primary.Unset_nonidx_in_strict
{ pos = p
; reason })
6624 (Errors.add_typing_error
6627 @@ Primary.Unset_nonidx_in_strict
{ pos = p
; reason = [] }));
6630 let should_forget_fakes = false in
6633 | [(_, (_, p
, Obj_get
(_, _, OG_nullsafe
, _)))] ->
6634 (Errors.add_typing_error
6636 primary
@@ Primary.Nullsafe_property_write_context p
));
6637 make_call_special_from_def env id tel (TUtils.terr env)
6638 | _ -> make_call_special_from_def env id tel MakeType.void
6640 (result, should_forget_fakes)
6642 when String.equal type_structure
SN.StdlibFunctions.type_structure
6643 && Int.equal
(List.length
el) 2
6644 && Option.is_none unpacked_element
->
6645 let should_forget_fakes = false in
6649 | (_, (_, p
, String cst
)) ->
6650 (* find the class constant implicitly defined by the typeconst *)
6653 | (_, (_, _, Class_const
(cid, (_, x
))))
6654 | (_, (_, _, Class_get
(cid, CGstring
(_, x
), _)))
6655 when String.equal x
SN.Members.mClass
->
6658 let (_, ((_, p1
, _) as e1_
)) = e1
in
6659 ((), p1
, CIexpr e1_
)
6661 let result = class_const ~incl_tc
:true env p
(cid, (p
, cst
)) in
6662 (result, should_forget_fakes)
6664 Errors.add_typing_error
6665 Typing_error.(primary
@@ Primary.Illegal_type_structure
pos);
6666 let result = expr_error env (Reason.Rwitness
pos) e in
6667 (result, should_forget_fakes))
6668 | _ -> assert false)
6669 | _ -> dispatch_id env id
6671 (* Special Shapes:: function *)
6672 | Class_const
(((_, _, CI
(_, shapes
)) as class_id
), ((_, x
) as method_id
))
6673 when String.equal shapes
SN.Shapes.cShapes
6674 || String.equal shapes
SN.Shapes.cReadonlyShapes
->
6677 (* Special function `Shapes::idx` *)
6678 | idx
when String.equal idx
SN.Shapes.idx
->
6686 (fun env fty res el tel ->
6687 match (el, tel) with
6688 | (_, [(_, (shape_ty
, shape_pos
, _)); (_, field)]) ->
6695 ~fun_pos
:(get_reason
fty)
6697 | ( [_; _; (_, default)],
6699 (_, (shape_ty
, shape_pos
, _));
6701 (_, (_, default_pos
, _));
6703 (* We reevaluate the default argument rather than using the one
6704 evaluated during the typechecking wrt to the overloaded
6705 function signature in the HHI file because bidirectional
6706 typechecking introduces TAnys to the system otherwise. *)
6707 let (env, _td
, default_ty
) = expr env default in
6712 (Some
(default_pos
, default_ty
))
6714 ~fun_pos
:(get_reason
fty)
6717 (* Special function `Shapes::at` *)
6718 | at
when String.equal at
SN.Shapes.at
->
6726 (fun env _fty
res _el
tel ->
6728 | [(_, (shape_ty
, shape_pos
, _)); (_, field)] ->
6729 Typing_shapes.at
env ~expr_pos
:p ~shape_pos shape_ty
field
6731 (* Special function `Shapes::keyExists` *)
6732 | key_exists when String.equal
key_exists SN.Shapes.keyExists
->
6740 (fun env fty res _el
tel ->
6742 | [(_, (shape_ty
, shape_pos
, _)); (_, field)] ->
6743 (* try accessing the field, to verify existence, but ignore
6744 * the returned type and keep the one coming from function
6745 * return type hint *)
6753 ~fun_pos
:(get_reason
fty)
6758 (* Special function `Shapes::removeKey` *)
6759 | remove_key
when String.equal remove_key
SN.Shapes.removeKey
->
6767 (fun env _ res el _tel
->
6769 | [(Ast_defs.Pinout
_, shape
); (_, field)] ->
6772 | (_, _, Lvar
(_, lvar
))
6773 | (_, _, Hole
((_, _, Lvar
(_, lvar
)), _, _, _)) ->
6774 (* We reevaluate the shape instead of using the shape type
6775 evaluated during typechecking against the HHI signature
6776 because this argument is inout and bidirectional
6777 typechecking causes a union with the open shape type
6778 which defeats the purpose of this extra-logical function.
6780 let (env, _te
, shape_ty
) = expr env shape
in
6781 let (env, shape_ty
) =
6782 Typing_shapes.remove_key p
env shape_ty
field
6784 let env = set_valid_rvalue p
env lvar shape_ty
in
6786 | (_, shape_pos
, _) ->
6787 Errors.add_typing_error
6789 shape
@@ Primary.Shape.Invalid_shape_remove_key shape_pos
);
6793 (* Special function `Shapes::toArray` *)
6794 | to_array
when String.equal to_array
SN.Shapes.toArray
->
6802 (fun env _ res _el
tel ->
6804 | [(_, (shape_ty
, _, _))] ->
6805 Typing_shapes.to_array
env p shape_ty
res
6807 (* Special function `Shapes::toDict` *)
6808 | to_dict
when String.equal to_dict
SN.Shapes.toDict
->
6816 (fun env _ res _el
tel ->
6818 | [(_, (shape_ty
, _, _))] ->
6819 Typing_shapes.to_dict
env p shape_ty
res
6821 | _ -> dispatch_class_const env class_id method_id
6823 (* Special function `parent::__construct` *)
6824 | Class_const
((_, pos, CIparent
), ((_, construct
) as id))
6825 when String.equal construct
SN.Members.__construct
->
6826 let (env, tel, typed_unpack_element
, ty, pty
, ctor_fty
, should_forget_fakes)
6828 call_parent_construct p
env el unpacked_element
6833 (Tast.make_typed_expr
6836 (Aast.Class_const
((pty
, pos, Aast.CIparent
), id)))
6837 [] (* tal: no type arguments to constructor *)
6839 typed_unpack_element
6842 (result, should_forget_fakes)
6843 (* Calling parent / class method *)
6844 | Class_const
(class_id
, m
) -> dispatch_class_const env class_id m
6845 (* Readonly Expressions do not affect the type, but need to be threaded through when they're part of a call *)
6847 let env = Env.set_readonly
env true in
6848 (* Recurse onto the inner call *)
6849 let ((env, expr, ty), s
) =
6863 | (ty, _, Call
(caller, tal
, tel, c)) ->
6864 let (caller_ty
, caller_pos
, _) = caller in
6865 (* Rewrap the caller in the readonly expression after we're done *)
6866 let wrapped_caller =
6867 Tast.make_typed_expr caller_pos caller_ty
(Aast.ReadonlyExpr
caller)
6869 let result = make_call env wrapped_caller tal
tel c ty in
6871 | _ -> ((env, expr, ty), s
))
6872 (* Call instance method *)
6873 | Obj_get
(e1
, (_, pos_id
, Id m
), nullflavor
, Is_method
)
6874 when not
(TypecheckerOptions.method_call_inference
(Env.get_tcopt
env)) ->
6875 let (env, te1, ty1
) = expr ~accept_using_var
:true env e1
in
6877 match nullflavor
with
6878 | OG_nullthrows
-> None
6879 | OG_nullsafe
-> Some p
6881 let (_, p1
, _) = e1
in
6882 let (env, (tfty
, tal
), lval_err_opt
, _rval_err_opt
) =
6883 TOG.obj_get_with_err
6888 ~
nullsafe:(Option.map ~f
:(fun p
-> Reason.Rnullsafe_op p
) nullsafe)
6889 ~coerce_from_ty
:None
6891 ~class_id
:(CIexpr e1
)
6893 ~on_error
:Typing_error.Callback.unify_error
6897 check_disposable_in_return env tfty
;
6898 let (env, (tel, typed_unpack_element
, ty, should_forget_fakes)) =
6899 call ~
nullsafe ~
expected p
env tfty
el unpacked_element
6904 (Tast.make_typed_expr
6908 ( hole_on_err ~
err_opt:lval_err_opt
te1,
6909 Tast.make_typed_expr pos_id tfty
(Aast.Id m
),
6914 typed_unpack_element
6917 (result, should_forget_fakes)
6918 (* Call instance method using new method call inference *)
6919 | Obj_get
(receiver
, (_, pos_id
, Id
meth), nullflavor
, Is_method
) ->
6921 Typecheck `Obj_get` by enforcing that:
6922 - `<instance_type>` <: `Thas_member(m, #1)`
6923 where #1 is a fresh type variable.
6925 let (env, typed_receiver
, receiver_ty
) =
6926 expr ~accept_using_var
:true env receiver
6928 let env = might_throw env in
6930 match nullflavor
with
6931 | OG_nullthrows
-> None
6932 | OG_nullsafe
-> Some p
6934 (* Generate a fresh type `method_ty` for the type of the
6935 instance method, i.e. #1 *)
6936 let (env, method_ty
) = Env.fresh_type
env p
in
6937 (* Create `Thas_member` constraint type *)
6938 let (_, receiver_p
, _) = receiver
in
6939 let reason = Reason.Rwitness receiver_p
in
6945 ~class_id
:(CIexpr receiver
)
6946 ~explicit_targs
:(Some explicit_targs
)
6948 let env = Env.set_tyvar_variance
env method_ty
in
6949 let (env, has_method_super_ty
) =
6950 if Option.is_none
nullsafe then
6951 (env, has_method_ty)
6953 (* If null-safe, then `receiver_ty` <: `?Thas_member(m, #1)`,
6954 but *unlike* property access typing in `expr_`, we still use `#1` as
6955 our "result" if `receiver_ty` is nullable (as opposed to `?#1`),
6956 deferring null-safety handling to after `call` *)
6957 let r = Reason.Rnullsafe_op p
in
6958 let null_ty = MakeType.null
r in
6959 Union.union_i
env r has_method_ty null_ty
6961 let (_, receiver_pos
, _) = receiver
in
6967 (LoclType receiver_ty
)
6969 Typing_error.Callback.unify_error
6971 let ty_nothing = MakeType.nothing Reason.none
in
6972 let (env, err_opt) =
6975 ~ok
:(fun env -> (env, None
))
6976 ~
error:(fun env -> (env, Some
(receiver_ty
, ty_nothing)))
6979 (* Perhaps solve for `method_ty`. Opening and closing a scope is too coarse
6980 here - type parameters are localised to fresh type variables over the
6981 course of subtyping above, and we do not want to solve these until later.
6982 Once we typecheck all function calls with a subtyping of function types,
6983 we should not need to solve early at all - transitive closure of
6984 subtyping should give enough information. *)
6986 match get_var method_ty
with
6988 Typing_solver.solve_to_equal_bound_or_wrt_variance
env Reason.Rnone var
6991 let localize_targ env (_, targ
) = Phase.localize_targ env targ
in
6992 let (env, typed_targs
) =
6993 List.map_env
env ~f
:(localize_targ ~check_well_kinded
:true) explicit_targs
6995 check_disposable_in_return env method_ty
;
6996 let (env, (typed_params
, typed_unpack_element
, ret_ty, should_forget_fakes))
6998 call ~
nullsafe ~
expected ?in_await p
env method_ty
el unpacked_element
7000 (* If the call is nullsafe AND the receiver is nullable,
7001 make the return type nullable too *)
7003 if Option.is_some
nullsafe then
7004 let r = Reason.Rnullsafe_op p
in
7005 let null_ty = MakeType.null
r in
7006 let (env, null_or_nothing_ty
) =
7007 Inter.intersect
env ~
r null_ty receiver_ty
7009 let (env, ret_option_ty
) = Union.union env null_or_nothing_ty
ret_ty in
7010 (env, ret_option_ty
)
7017 (Tast.make_typed_expr
7021 ( hole_on_err ~
err_opt typed_receiver
,
7022 Tast.make_typed_expr pos_id method_ty
(Aast.Id
meth),
7027 typed_unpack_element
7030 (result, should_forget_fakes)
7031 (* Function invocation *)
7033 let (env, fty, tal
) = fun_type_of_id env x explicit_targs
el in
7034 check_disposable_in_return env fty;
7035 let (env, (tel, typed_unpack_element
, ty, should_forget_fakes)) =
7036 call ~
expected p
env fty el unpacked_element
7041 (Tast.make_typed_expr fpos
fty (Aast.Fun_id x
))
7044 typed_unpack_element
7047 (result, should_forget_fakes)
7048 | Id
id -> dispatch_id env id
7050 let (env, te, fty) = expr env e in
7052 Typing_solver.expand_type_and_solve
7053 ~description_of_expected
:"a function value"
7058 check_disposable_in_return env fty;
7059 let (env, (tel, typed_unpack_element
, ty, should_forget_fakes)) =
7060 call ~
expected p
env fty el unpacked_element
7066 (* tal: no type arguments to function values, as they are non-generic *)
7069 typed_unpack_element
7072 (result, should_forget_fakes)
7078 ?
(explicit_targs
= [])
7080 ?
(is_function_pointer
= false)
7085 let (env, this_ty) =
7087 this_for_method
env cid cty
7098 ~is_function_pointer
7110 ?is_function_pointer
7115 let (env, tys
, rval_res_opt
) =
7122 ?is_function_pointer
7128 let rval_err_opt = Option.bind ~f
:Result.error rval_res_opt
in
7129 (env, tys
, rval_err_opt)
7137 ?is_function_pointer
7149 ?is_function_pointer
7162 ?
(explicit_targs
= [])
7164 ?
(is_function_pointer
= false)
7166 ((_, cid_pos
, cid_
) as cid)
7169 let (env, cty
) = Env.expand_type
env cty
in
7170 let dflt_rval_err = Option.map ~f
:(fun (_, _, ty) -> Ok
ty) coerce_from_ty
in
7171 match deref cty
with
7172 | (r, Tany
_) -> (env, (mk
(r, Typing_utils.tany
env), []), dflt_rval_err)
7173 | (_, Terr
) -> (env, (err_witness env cid_pos
, []), dflt_rval_err)
7174 | (_, Tdynamic
) -> (env, (cty
, []), dflt_rval_err)
7175 | (_, Tunion tyl
) ->
7176 let (env, pairs, rval_err_opts
) =
7180 ~f
:(fun (env, pairs, rval_err_opts
) ty ->
7181 let (env, pair
, rval_err_opt) =
7188 ~is_function_pointer
7194 (env, pair
:: pairs, rval_err_opt :: rval_err_opts
))
7197 let rval_err = Option.(map ~f
:union_coercion_errs @@ all rval_err_opts
) in
7199 Union.union_list
env (get_reason cty
) (List.map ~f
:fst
pairs)
7201 (env, (ty, []), rval_err)
7202 | (_, Tintersection tyl
) ->
7203 let (env, pairs, rval_err_opts
) =
7204 TUtils.run_on_intersection_res
env tyl ~f
:(fun env ty ->
7212 ~is_function_pointer
7219 Option.(map ~f
:intersect_coercion_errs @@ all rval_err_opts
)
7222 Inter.intersect_list
env (get_reason cty
) (List.map ~f
:fst
pairs)
7224 (env, (ty, []), rval_err)
7225 | (_, Tnewtype
(_, _, ty))
7226 | (_, Tdependent
(_, ty)) ->
7234 ~is_function_pointer
7239 | (r, Tgeneric
_) ->
7241 TUtils.get_concrete_supertypes ~abstract_enum
:true env cty
7243 if List.is_empty tyl
then begin
7244 Errors.add_typing_error
7247 @@ Primary.Non_class_member
7256 ty_name
= lazy (Typing_print.error env cty
);
7257 decl_pos
= get_pos cty
;
7260 (env, (err_witness env p
, []), dflt_rval_err)
7262 let (env, ty) = Typing_intersection.intersect_list
env r tyl
in
7270 ~is_function_pointer
7275 | (_, Tclass
((_, c), _, paraml
)) ->
7276 let class_ = Env.get_class
env c in
7278 | None
-> (env, (Typing_utils.mk_tany
env p
, []), dflt_rval_err)
7280 (* TODO akenn: Should we move this to the class_get original call? *)
7281 let (env, this_ty) = ExprDepTy.make
env ~
cid:cid_
this_ty in
7282 (* We need to instantiate generic parameters in the method signature *)
7285 empty_expand_env
with
7287 substs
= TUtils.make_locl_subst_for_class_tparams
class_ paraml
;
7290 let get_smember_from_constraints env class_info =
7292 Cls.upper_bounds_on_this_from_constraints
class_info
7294 let (env, upper_bounds) =
7295 List.map_env
env upper_bounds ~f
:(fun env up
->
7296 Phase.localize ~
ety_env env up
)
7298 let (env, inter_ty
) =
7299 Inter.intersect_list
env (Reason.Rwitness p
) upper_bounds
7308 ~is_function_pointer
7314 let try_get_smember_from_constraints env class_info =
7315 Errors.try_with_error
7316 (fun () -> get_smember_from_constraints env class_info)
7318 Errors.add_typing_error
7319 @@ TOG.smember_not_found
7323 ~is_function_pointer
7326 Typing_error.Callback.unify_error
;
7327 (env, (TUtils.terr env Reason.Rnone
, []), dflt_rval_err))
7332 Env.get_const
env class_ mid
7334 match Env.get_typeconst
env class_ mid
with
7336 Errors.add_typing_error
7338 primary
@@ Primary.Illegal_typeconst_direct_access p
);
7340 | None
-> Env.get_const
env class_ mid
7343 | None
when Cls.has_upper_bounds_on_this_from_constraints
class_ ->
7344 try_get_smember_from_constraints env class_
7346 Errors.add_typing_error
7347 @@ TOG.smember_not_found
7351 ~is_function_pointer
7354 Typing_error.Callback.unify_error
;
7355 (env, (TUtils.terr env Reason.Rnone
, []), dflt_rval_err)
7356 | Some
{ cc_type
; cc_abstract
; cc_pos
; _ } ->
7357 let (env, cc_locl_type
) = Phase.localize ~
ety_env env cc_type
in
7358 (match cc_abstract
with
7365 let cc_name = Cls.name class_ ^
"::" ^ mid
in
7369 @@ Primary.Abstract_const_usage
7370 { pos = p
; decl_pos
= cc_pos
; name = cc_name })
7372 Errors.add_typing_error
err)
7373 | CCConcrete
-> ());
7374 (env, (cc_locl_type
, []), dflt_rval_err)
7376 let static_member_opt =
7377 Env.get_static_member is_method
env class_ mid
7379 (match static_member_opt with
7380 | None
when Cls.has_upper_bounds_on_this_from_constraints
class_ ->
7381 try_get_smember_from_constraints env class_
7383 Errors.add_typing_error
7384 @@ TOG.smember_not_found
7388 ~is_function_pointer
7391 Typing_error.Callback.unify_error
;
7392 (env, (TUtils.terr env Reason.Rnone
, []), dflt_rval_err)
7395 ce_visibility = vis
;
7396 ce_type
= (lazy member_decl_ty
);
7400 let def_pos = get_pos member_decl_ty
in
7402 ~f
:Errors.add_typing_error
7403 (TVis.check_class_access
7408 (vis
, get_ce_lsb ce
)
7412 ~f
:Errors.add_typing_error
7413 (TVis.check_deprecated ~
use_pos:p ~
def_pos ce_deprecated);
7414 check_class_get env p
def_pos c mid ce
cid is_function_pointer
;
7415 let (env, member_ty
, et_enforced
, tal
) =
7416 match deref member_decl_ty
with
7417 (* We special case Tfun here to allow passing in explicit tparams to localize_ft. *)
7418 | (r, Tfun
ft) when is_method
->
7419 let (env, explicit_targs
) =
7420 Phase.localize_targs
7421 ~check_well_kinded
:true
7425 ~use_name
:(strip_ns mid
)
7428 (List.map ~f
:snd explicit_targs
)
7431 Typing_enforceability.compute_enforced_and_pessimize_fun_type
7439 { use_name
= strip_ns mid
; use_pos = p
; explicit_targs
}
7446 Typing_dynamic.relax_method_type
7448 (get_ce_support_dynamic_type ce
)
7452 (env, fty, Unenforced
, explicit_targs
)
7455 let { et_type; et_enforced
} =
7456 Typing_enforceability.compute_enforced_and_pessimize_ty
7460 let (env, member_ty
) = Phase.localize ~
ety_env env et_type in
7461 (* TODO(T52753871) make function just return possibly_enforced_ty
7462 * after considering intersection case *)
7463 (env, member_ty
, et_enforced
, [])
7465 let (env, member_ty
) =
7466 if Cls.has_upper_bounds_on_this_from_constraints
class_ then
7467 let ((env, (member_ty'
, _), _), succeed
) =
7469 (fun () -> (get_smember_from_constraints env class_, true))
7471 (* No eligible functions found in constraints *)
7472 ( (env, (MakeType.mixed Reason.Rnone
, []), dflt_rval_err),
7476 Inter.intersect
env ~
r:(Reason.Rwitness p
) member_ty member_ty'
7482 let (env, rval_err) =
7483 match coerce_from_ty
with
7484 | None
-> (env, None
)
7485 | Some
(p
, ur, ty) ->
7487 ~ok
:(fun env -> (env, Some
(Ok
ty)))
7488 ~
error:(fun env -> (env, Some
(Error
(ty, member_ty
))))
7489 @@ Typing_coercion.coerce_type_res
7494 { et_type = member_ty
; et_enforced
}
7495 Typing_error.Callback.unify_error
7497 (env, (member_ty
, tal
), rval_err)))
7498 | (_, Tunapplied_alias
_) ->
7499 Typing_defs.error_Tunapplied_alias_in_illegal_context
()
7501 ( Tvar
_ | Tnonnull
| Tvec_or_dict
_ | Toption
_ | Tprim
_ | Tfun
_
7502 | Ttuple
_ | Tshape
_ | Taccess
_ | Tneg
_ ) ) ->
7503 Errors.add_typing_error
7506 @@ Primary.Non_class_member
7515 ty_name
= lazy (Typing_print.error env cty
);
7516 decl_pos
= get_pos cty
;
7518 (env, (err_witness env p
, []), dflt_rval_err)
7520 and class_id_for_new
7521 ~exact p
env (cid : Nast.class_id_
) (explicit_targs
: Nast.targ list
) :
7522 newable_class_info
=
7523 let (env, tal
, te, cid_ty
) =
7525 ~check_targs_well_kinded
:true
7526 ~check_explicit_targs
:true
7532 (* Need to deal with union case *)
7533 let rec get_info res tyl
=
7535 | [] -> (env, tal
, te, res)
7537 (match get_node
ty with
7539 | Tintersection tyl'
->
7540 get_info res (tyl'
@ tyl
)
7542 (* Instantiation on an abstract class (e.g. from classname<T>) is
7543 * via the base type (to check constructor args), but the actual
7544 * type `ty` must be preserved. *)
7545 (match get_node
(TUtils.get_base_type
env ty) with
7546 | Tdynamic
-> get_info (`Dynamic
:: res) tyl
7547 | Tclass
(sid
, _, _) ->
7548 let class_ = Env.get_class
env (snd sid
) in
7550 | None
-> get_info res tyl
7551 | Some
class_info ->
7552 (match (te, cid_ty
) with
7553 (* When computing the classes for a new T() where T is a generic,
7554 * the class must be consistent (final, final constructor, or
7555 * <<__ConsistentConstruct>>) for its constructor to be considered *)
7556 | ((_, _, Aast.CI
(_, c)), ty) when is_generic_equal_to
c ty ->
7557 (* Only have this choosing behavior for new T(), not all generic types
7558 * i.e. new classname<T>, TODO: T41190512 *)
7559 if Cls.valid_newable_class
class_info then
7560 get_info (`Class
(sid
, class_info, ty) :: res) tyl
7563 | _ -> get_info (`Class
(sid
, class_info, ty) :: res) tyl
))
7564 | _ -> get_info res tyl
))
7566 get_info [] [cid_ty
]
7568 (* When invoking a method, the class_id is used to determine what class we
7569 * lookup the method in, but the type of 'this' will be the late bound type.
7573 * public static function get(): this { return new static(); }
7575 * public static function alias(): this { return self::get(); }
7578 * In C::alias, when we invoke self::get(), 'self' is resolved to the class
7579 * in the lexical scope (C), so call C::get. However the method is executed in
7580 * the current context, so static inside C::get will be resolved to the late
7581 * bound type (get_called_class() within C::alias).
7583 * This means when determining the type of this, CIparent and CIself should be
7584 * changed to CIstatic. For the other cases of C::get() or $c::get(), we only
7585 * look at the left hand side of the '::' and use the type associated
7588 * Thus C::get() will return a type C, while $c::get() will return the same
7591 and this_for_method
env (_, p
, cid) default_ty
=
7596 let (env, _tal
, _te
, ty) = class_expr
env [] ((), p
, CIstatic
) in
7597 ExprDepTy.make
env ~
cid:CIstatic
ty
7598 | _ -> (env, default_ty
)
7600 (** Resolve class expressions:
7601 * self CIself lexically enclosing class
7602 * parent CIparent lexically enclosing `extends` class
7603 * static CIstatic late-static-bound class (i.e. runtime receiver)
7604 * <id> CI id literal class name
7605 * <expr> CIexpr expr expression that evaluates to an object or classname
7608 ?
(check_targs_well_kinded
= false)
7610 ?
(check_explicit_targs
= false)
7612 (tal
: Nast.targ list
)
7613 ((_, p
, cid_
) : Nast.class_id
) :
7614 env * Tast.targ list
* Tast.class_id
* locl_ty
=
7615 let make_result env tal
te ty = (env, tal
, (ty, p
, te), ty) in
7618 (match Env.get_self_id
env with
7620 (match Env.get_class
env self
with
7621 | Some trait
when Ast_defs.is_c_trait
(Cls.kind trait
) ->
7622 (match trait_most_concrete_req_class trait
env with
7624 Errors.add_typing_error
7625 Typing_error.(primary
@@ Primary.Parent_in_trait p
);
7626 make_result env [] Aast.CIparent
(err_witness env p
)
7627 | Some
(_, parent_ty
) ->
7628 (* inside a trait, parent is SN.Typehints.this, but with the
7629 * type of the most concrete class that the trait has
7630 * "require extend"-ed *)
7631 let (env, parent_ty
) =
7632 Phase.localize_no_subst
env ~ignore_errors
:true parent_ty
7634 make_result env [] Aast.CIparent parent_ty
)
7637 match Env.get_parent_ty
env with
7639 Errors.add_typing_error
7640 Typing_error.(primary
@@ Primary.Parent_undefined p
);
7641 mk
(Reason.none
, Typing_defs.make_tany
())
7642 | Some
parent -> parent
7645 Phase.localize_no_subst
env ~ignore_errors
:true parent
7647 (* parent is still technically the same object. *)
7648 make_result env [] Aast.CIparent
parent)
7651 match Env.get_parent_ty
env with
7653 Errors.add_typing_error
7654 Typing_error.(primary
@@ Primary.Parent_undefined p
);
7655 mk
(Reason.none
, Typing_defs.make_tany
())
7656 | Some
parent -> parent
7659 Phase.localize_no_subst
env ~ignore_errors
:true parent
7661 (* parent is still technically the same object. *)
7662 make_result env [] Aast.CIparent
parent)
7665 if Option.is_some
(Env.next_cont_opt
env) then
7666 MakeType.this (Reason.Rwitness p
)
7668 MakeType.nothing (Reason.Rwitness p
)
7670 make_result env [] Aast.CIstatic
this
7673 match Env.get_self_class_type
env with
7674 | Some
(c, _, tyl
) -> mk
(Reason.Rwitness p
, Tclass
(c, exact
, tyl
))
7676 (* Naming phase has already checked and replaced CIself with CI if outside a class *)
7677 Errors.internal_error p
"Unexpected CIself";
7678 Typing_utils.mk_tany
env p
7680 make_result env [] Aast.CIself
ty
7681 | CI
((p
, id) as c) ->
7683 match Env.get_pos_and_kind_of_generic
env id with
7684 | Some
(def_pos, kind) ->
7685 let simple_kind = Typing_kinding_defs.Simple.from_full_kind
kind in
7687 Typing_kinding_defs.Simple.get_named_parameter_kinds
simple_kind
7690 Phase.localize_targs_with_kinds
7691 ~check_well_kinded
:check_targs_well_kinded
7695 ~use_name
:(strip_ns
(snd
c))
7696 ~check_explicit_targs
7699 (List.map ~f
:snd tal
)
7701 let r = Reason.Rhint
(Pos_or_decl.of_raw_pos p
) in
7702 let type_args = List.map tal ~f
:fst
in
7703 let tgeneric = MakeType.generic ~
type_args r id in
7704 make_result env tal
(Aast.CI
c) tgeneric
7706 (* Not a type parameter *)
7707 let class_ = Env.get_class
env id in
7709 | None
-> make_result env [] (Aast.CI
c) (Typing_utils.mk_tany
env p
)
7712 ~f
:Errors.add_typing_error
7713 (TVis.check_classname_access
7718 (* Don't add Exact superfluously to class type if it's final *)
7720 if Cls.final
class_ then
7725 let (env, ty, tal
) =
7727 |> Phase.localize_targs_and_check_constraints
7729 ~check_well_kinded
:check_targs_well_kinded
7730 ~
def_pos:(Cls.pos class_)
7732 ~check_explicit_targs
7735 (Cls.tparams class_)
7737 make_result env tal
(Aast.CI
c) ty)
7739 | CIexpr
((_, p
, _) as e) ->
7740 let (env, te, ty) = expr env e ~
allow_awaitable:(*?*) false in
7741 let fold_errs errs
=
7742 let rec aux = function
7743 | (Ok xs
, Ok x
:: rest) -> aux (Ok
(x
:: xs
), rest)
7744 | (Ok xs
, Error
(x
, y
) :: rest) -> aux (Error
(x
:: xs
, y
:: xs
), rest)
7745 | (Error
(xs
, ys
), Ok x
:: rest) -> aux (Error
(x
:: xs
, x
:: ys
), rest)
7746 | (Error
(xs
, ys
), Error
(x
, y
) :: rest) ->
7747 aux (Error
(x
:: xs
, y
:: ys
), rest)
7752 let rec resolve_ety env ty =
7754 Typing_solver.expand_type_and_solve
7755 ~description_of_expected
:"an object"
7760 let base_ty = TUtils.get_base_type
env ty in
7761 match deref
base_ty with
7762 | (_, Tnewtype
(classname, [the_cls
], as_ty
))
7763 when String.equal
classname SN.Classes.cClassname
->
7764 let (env, ty, err_res
) = resolve_ety env the_cls
in
7765 let wrap ty = mk
(Reason.none
, Tnewtype
(classname, [ty], as_ty
)) in
7768 | Ok
ty -> Ok
(wrap ty)
7769 | Error
(ty_act
, ty_exp
) -> Error
(wrap ty_act
, wrap ty_exp
)
7775 | (r, Tunion tyl
) ->
7776 let (env, tyl
, errs
) = List.map_env_err_res
env tyl ~f
:resolve_ety in
7777 let ty = MakeType.union r tyl
in
7779 match fold_errs errs
with
7781 | Error
(ty_actuals
, ty_expects
) ->
7782 let ty_actual = MakeType.union Reason.none ty_actuals
7783 and ty_expect
= MakeType.union Reason.none ty_expects
in
7784 Error
(ty_actual, ty_expect
)
7787 | (r, Tintersection tyl
) ->
7788 let (env, tyl
, errs
) =
7789 TUtils.run_on_intersection_res
env tyl ~f
:resolve_ety
7791 let (env, ty) = Inter.intersect_list
env r tyl
in
7793 match fold_errs errs
with
7794 | Ok
_ -> (env, Ok
ty)
7795 | Error
(ty_actuals
, ty_expects
) ->
7796 let (env, ty_actual) =
7797 Inter.intersect_list
env Reason.none ty_actuals
7799 let (env, ty_expect
) =
7800 Inter.intersect_list
env Reason.none ty_expects
7802 (env, Error
(ty_actual, ty_expect
))
7805 | (_, Tdynamic
) -> (env, base_ty, Ok
base_ty)
7807 let ty = err_witness env p
in
7810 Errors.add_typing_error
7813 @@ Primary.Unknown_type
7815 expected = "an object";
7817 reason = Reason.to_string
"It is unknown" r;
7819 let ty = err_witness env p
in
7821 | (_, Tunapplied_alias
_) ->
7822 Typing_defs.error_Tunapplied_alias_in_illegal_context
()
7824 ( Tany
_ | Tnonnull
| Tvec_or_dict
_ | Toption
_ | Tprim
_ | Tfun
_
7825 | Ttuple
_ | Tnewtype
_ | Tdependent
_ | Tshape
_ | Taccess
_ | Tneg
_
7827 Errors.add_typing_error
7830 @@ Primary.Expected_class
7833 Some
(lazy (", but got " ^
Typing_print.error env base_ty));
7836 let ty_nothing = MakeType.nothing Reason.none
in
7837 let ty_expect = MakeType.classname Reason.none
[ty_nothing] in
7838 (env, err_witness env p
, Error
(base_ty, ty_expect))
7840 let (env, result_ty
, err_res) = resolve_ety env ty in
7845 ~
error:(fun (ty_act
, ty_expect) -> Some
(ty_act
, ty_expect))
7847 let te = hole_on_err ~
err_opt te in
7848 let x = make_result env [] (Aast.CIexpr
te) result_ty
in
7851 and call_construct p
env class_ params el unpacked_element
cid cid_ty
=
7853 if Nast.equal_class_id_
cid CIparent
then
7854 MakeType.this (Reason.Rwitness p
)
7860 empty_expand_env
with
7862 substs
= TUtils.make_locl_subst_for_class_tparams
class_ params;
7863 on_error
= Typing_error.Reasons_callback.unify_error_at p
;
7867 Phase.check_where_constraints
7870 ~definition_pos
:(Cls.pos class_)
7873 (Cls.where_constraints
class_)
7875 let cstr = Env.get_construct
env class_ in
7878 if (not
(List.is_empty
el)) || Option.is_some unpacked_element
then
7879 Errors.add_typing_error
7880 Typing_error.(primary
@@ Primary.Constructor_no_args p
);
7881 let (env, tel, _tyl
) =
7882 argument_list_exprs
(expr ~
allow_awaitable:false) env el
7884 let should_forget_fakes = true in
7885 (env, tel, None
, TUtils.terr env Reason.Rnone
, should_forget_fakes)
7886 | Some
{ ce_visibility = vis
; ce_type
= (lazy m
); ce_deprecated; _ } ->
7887 let def_pos = get_pos m
in
7889 ~f
:Errors.add_typing_error
7890 (TVis.check_obj_access ~is_method
:true ~
use_pos:p ~
def_pos env vis
);
7892 ~f
:Errors.add_typing_error
7893 (TVis.check_deprecated ~
use_pos:p ~
def_pos ce_deprecated);
7894 (* Obtain the type of the constructor *)
7896 let r = get_reason m
|> Typing_reason.localize
in
7897 match get_node m
with
7900 Typing_enforceability.compute_enforced_and_pessimize_fun_type
env ft
7902 (* This creates type variables for non-denotable type parameters on constructors.
7903 * These are notably different from the tparams on the class, which are handled
7904 * at the top of this function. User-written type parameters on constructors
7905 * are still a parse error. This is a no-op if ft.ft_tparams is empty. *)
7906 let (env, implicit_constructor_targs
) =
7907 Phase.localize_targs
7908 ~check_well_kinded
:true
7912 ~use_name
:"constructor"
7922 use_name
= "constructor";
7924 explicit_targs
= implicit_constructor_targs
;
7931 (env, mk
(r, Tfun
ft))
7933 Errors.internal_error p
"Expected function type for constructor";
7934 let ty = TUtils.terr env r in
7937 let (env, (tel, typed_unpack_element
, _ty
, should_forget_fakes)) =
7938 call ~
expected:None p
env m
el unpacked_element
7940 (env, tel, typed_unpack_element
, m
, should_forget_fakes)
7942 and inout_write_back
env { fp_type
; _ } (pk
, ((_, pos, _) as e)) =
7944 | Ast_defs.Pinout
_ ->
7945 (* Translate the write-back semantics of inout parameters.
7947 * This matters because we want to:
7948 * (1) make sure we can write to the original argument
7949 * (modifiable lvalue check)
7950 * (2) allow for growing of locals / Tunions (type side effect)
7951 * but otherwise unify the argument type with the parameter hint
7953 let (env, _te
, _ty
) =
7954 assign_
pos Reason.URparam_inout
env e pos fp_type
.et_type
7959 (** Typechecks a call.
7960 * Returns in this order the typed expressions for the arguments, for the
7961 * variadic arguments, the return type, and a boolean indicating whether fake
7962 * members should be forgotten.
7965 ~
(expected : ExpectedTy.t
option)
7966 ?
(nullsafe : Pos.t
option = None
)
7968 ?
(in_supportdyn
= false)
7972 (el : (Ast_defs.param_kind
* Nast.expr) list
)
7973 (unpacked_element
: Nast.expr option) :
7975 * ((Ast_defs.param_kind
* Tast.expr) list
7979 let expr = expr ~
allow_awaitable:(*?*) false in
7981 TUtils.get_concrete_supertypes
7982 ~expand_supportdyn
:false
7987 if List.is_empty tyl
then begin
7988 bad_call env pos fty;
7989 let env = call_untyped_unpack
env (get_pos
fty) unpacked_element
in
7990 let should_forget_fakes = true in
7991 (env, ([], None
, err_witness env pos, should_forget_fakes))
7994 Typing_intersection.intersect_list
env (get_reason
fty) tyl
7997 if TypecheckerOptions.method_call_inference
(Env.get_tcopt
env) then
7998 Env.expand_type
env fty
8000 Typing_solver.expand_type_and_solve
8001 ~description_of_expected
:"a function value"
8006 match deref efty
with
8007 | (r, Tdynamic
) when TCO.enable_sound_dynamic (Env.get_tcopt
env) ->
8008 let ty = MakeType.dynamic
(Reason.Rdynamic_call
pos) in
8010 (* Need to check that the type of the unpacked_element can be,
8011 * coerced to dynamic, just like all of the other arguments, in addition
8012 * to the check below in call_untyped_unpack, that it is unpackable.
8013 * We don't need to unpack and check each type because a tuple is
8014 * coercible iff it's constituent types are. *)
8016 ~f
:(fun u
-> el @ [(Ast_defs.Pnormal
, u
)])
8020 let expected_arg_ty =
8022 ~coerce
:(Some
Typing_logic.CoerceToDynamic
)
8028 List.map_env
env el ~f
:(fun env (pk
, elt
) ->
8029 let (env, te, e_ty
) = expr ~
expected:expected_arg_ty env elt
in
8032 | Ast_defs.Pinout
_ ->
8033 let (_, pos, _) = elt
in
8034 let (env, _te
, _ty
) =
8035 assign_
pos Reason.URparam_inout
env elt
pos efty
8038 | Ast_defs.Pnormal
-> env
8040 let (env, err_opt) =
8042 ~ok
:(fun env -> (env, None
))
8043 ~
error:(fun env -> (env, Some
(e_ty
, ty)))
8044 @@ Typing_subtype.sub_type_res
8045 ~coerce
:(Some
Typing_logic.CoerceToDynamic
)
8049 (Typing_error.Reasons_callback.unify_error_at
pos)
8051 (env, (pk
, hole_on_err ~
err_opt te)))
8053 let env = call_untyped_unpack
env (Reason.to_pos
r) unpacked_element
in
8054 let should_forget_fakes = true in
8055 (env, (tel, None
, ty, should_forget_fakes))
8056 | (r, ((Tprim Tnull
| Tdynamic
| Terr
| Tany
_ | Tunion
[]) as ty))
8058 | Tprim Tnull
-> Option.is_some
nullsafe
8062 ~f
:(fun u
-> el @ [(Ast_defs.Pnormal
, u
)])
8066 let expected_arg_ty =
8067 (* Note: We ought to be using 'mixed' here *)
8068 ExpectedTy.make
pos Reason.URparam
(Typing_utils.mk_tany
env pos)
8071 List.map_env
env el ~f
:(fun env (pk
, elt
) ->
8072 let (env, te, ty) = expr ~
expected:expected_arg_ty env elt
in
8073 let (env, err_opt) =
8074 if TCO.global_inference
(Env.get_tcopt
env) then
8075 match get_node efty
with
8080 ~ok
:(fun env -> (env, None
))
8081 ~
error:(fun env -> (env, Some
(ty, efty
)))
8082 @@ Typing_coercion.coerce_type_res
8087 (MakeType.unenforced efty
)
8088 Typing_error.Callback.unify_error
8095 | Ast_defs.Pinout
_ ->
8096 let (_, pos, _) = elt
in
8097 let (env, _te
, _ty
) =
8098 assign_
pos Reason.URparam_inout
env elt
pos efty
8101 | Ast_defs.Pnormal
-> env
8103 (env, (pk
, hole_on_err ~
err_opt te)))
8105 let env = call_untyped_unpack
env (Reason.to_pos
r) unpacked_element
in
8108 | Tprim Tnull
-> mk
(r, Tprim Tnull
)
8109 | Tdynamic
-> MakeType.dynamic
(Reason.Rdynamic_call
pos)
8112 Typing_utils.mk_tany
env pos
8114 | _ (* _ should not happen! *) ->
8117 let should_forget_fakes = true in
8118 (env, (tel, None
, ty, should_forget_fakes))
8119 | (_, Tunion
[ty]) ->
8120 call ~
expected ~
nullsafe ?in_await
pos env ty el unpacked_element
8121 | (r, Tunion tyl
) ->
8123 List.map_env
env tyl ~f
:(fun env ty ->
8124 call ~
expected ~
nullsafe ?in_await
pos env ty el unpacked_element
)
8126 let should_forget_fakes =
8127 List.exists resl ~f
:(fun (_, _, _, forget
) -> forget
)
8129 let retl = List.map resl ~f
:(fun (_, _, x, _) -> x) in
8130 let (env, ty) = Union.union_list
env r retl in
8131 (* We shouldn't be picking arbitrarily for the TAST here, as TAST checks
8132 * depend on the types inferred. Here's we're preserving legacy behaviour
8133 * by picking the last one.
8134 * TODO: don't do this, instead use subtyping to push unions
8135 * through function types
8137 let (tel, typed_unpack_element
, _, _) = List.hd_exn
(List.rev resl
) in
8138 (env, (tel, typed_unpack_element
, ty, should_forget_fakes))
8139 | (r, Tintersection tyl
) ->
8141 TUtils.run_on_intersection
env tyl ~f
:(fun env ty ->
8142 call ~
expected ~
nullsafe ?in_await
pos env ty el unpacked_element
)
8144 let should_forget_fakes =
8145 List.for_all resl ~f
:(fun (_, _, _, forget
) -> forget
)
8147 let retl = List.map resl ~f
:(fun (_, _, x, _) -> x) in
8148 let (env, ty) = Inter.intersect_list
env r retl in
8149 (* We shouldn't be picking arbitrarily for the TAST here, as TAST checks
8150 * depend on the types inferred. Here we're preserving legacy behaviour
8151 * by picking the last one.
8152 * TODO: don't do this, instead use subtyping to push intersections
8153 * through function types
8155 let (tel, typed_unpack_element
, _, _) = List.hd_exn
(List.rev resl
) in
8156 (env, (tel, typed_unpack_element
, ty, should_forget_fakes))
8158 (* Typing of format string functions. It is dependent on the arguments (el)
8159 * so it cannot be done earlier.
8161 let pos_def = Reason.to_pos r2
in
8162 let (env, ft) = Typing_exts.retype_magic_func
env ft el in
8163 let (env, var_param
) = variadic_param env ft in
8164 (* Force subtype with expected result *)
8166 check_expected_ty "Call result" env ft.ft_ret
.et_type expected
8168 let env = Env.set_tyvar_variance
env ft.ft_ret
.et_type in
8169 let is_lambda (_, _, e) =
8176 let get_next_param_info paraml
=
8178 | param :: paraml
-> (false, Some
param, paraml
)
8179 | [] -> (true, var_param
, paraml
)
8181 let rec compute_enum_name env lty
=
8182 match get_node lty
with
8183 | Tclass
((_, enum_name
), _, _) when Env.is_enum_class
env enum_name
->
8184 (env, Some enum_name
)
8185 | Tgeneric
(name, _) ->
8186 let (env, upper_bounds) =
8187 Typing_utils.collect_enum_class_upper_bounds
env name
8190 match upper_bounds with
8191 | None
-> (env, None
)
8192 | Some upper_bound
->
8193 (* To avoid ambiguity, we only support the case where
8194 * there is a single upper bound that is an EnumClass.
8195 * We might want to relax that later (e.g. with the
8196 * support for intersections).
8199 match get_node upper_bound
with
8200 | Tclass
((_, name), _, _) when Env.is_enum_class
env name ->
8206 (* minimal support to only deal with Tvar when:
8207 * - it is the valueOf from BuiltinEnumClass.
8208 * In this case, we know the tvar as a single lowerbound,
8209 * `this` which must be an enum class.
8210 * - it is a generic "TX::T" from a where clause. We try
8211 * to look at an upper bound, if it is an enum class, or fail.
8213 * We could relax this in the future but
8214 * I want to avoid complex constraints for now.
8216 let lower_bounds = Env.get_tyvar_lower_bounds
env var
in
8217 if ITySet.cardinal
lower_bounds <> 1 then
8220 match ITySet.choose
lower_bounds with
8221 | ConstraintType
_ -> (env, None
)
8223 (match get_node lower
with
8224 | Tclass
((_, enum_name
), _, _)
8225 when Env.is_enum_class
env enum_name
->
8226 (env, Some enum_name
)
8227 | Tgeneric
_ -> compute_enum_name env lower
8231 (* Already reported, see Typing_type_wellformedness *)
8234 let check_arg env param_kind
((_, pos, arg
) as e) opt_param ~is_variadic
=
8235 match opt_param
with
8237 (* First check if the parameter is a HH\EnumClass\Label. *)
8238 let (env, label_type
) =
8239 let ety = param.fp_type
.et_type in
8240 let (env, ety) = Env.expand_type
env ety in
8242 match get_node
(TUtils.strip_dynamic env ety) with
8243 | Tnewtype
(name, _, _) ->
8244 String.equal
SN.Classes.cEnumClassLabel
name
8248 | EnumClassLabel
(None
, label_name
) when is_label ->
8249 (match get_node
(TUtils.strip_dynamic env ety) with
8250 | Tnewtype
(name, [ty_enum
; _ty_interface
], _)
8251 when String.equal
name SN.Classes.cMemberOf
8252 || String.equal
name SN.Classes.cEnumClassLabel
->
8254 (match compute_enum_name env ty_enum
with
8255 | (env, None
) -> (env, EnumClassLabelOps.ClassNotFound
)
8256 | (env, Some enum_name
) ->
8257 EnumClassLabelOps.expand
8265 (* Already reported, see Typing_type_wellformedness *)
8266 (env, EnumClassLabelOps.Invalid
))
8267 | EnumClassLabel
(Some
_, _) ->
8268 (* Full info is here, use normal inference *)
8269 (env, EnumClassLabelOps.Skip
)
8270 | _ -> (env, EnumClassLabelOps.Skip
)
8273 match label_type
with
8274 | EnumClassLabelOps.Success
(te, ty)
8275 | EnumClassLabelOps.LabelNotFound
(te, ty) ->
8279 ExpectedTy.make_and_allow_coercion_opt
8286 ~accept_using_var
:(get_fp_accept_disposable
param)
8291 let (env, err_opt) =
8292 call_param ~in_supportdyn
env param param_kind
(e, ty) ~is_variadic
8294 (env, Some
(hole_on_err ~
err_opt te, ty))
8297 ExpectedTy.make
pos Reason.URparam
(Typing_utils.mk_tany
env pos)
8299 let (env, te, ty) = expr ~
expected env e in
8300 (env, Some
(te, ty))
8302 let set_tyvar_variance_from_lambda_param env opt_param
=
8303 match opt_param
with
8305 let rec set_params_variance env ty =
8306 let (env, ty) = Env.expand_type
env ty in
8307 match get_node
ty with
8308 | Tunion
[ty] -> set_params_variance env ty
8309 | Toption
ty -> set_params_variance env ty
8310 | Tfun
{ ft_params; ft_ret
; _ } ->
8314 ~f
:(fun env param ->
8315 Env.set_tyvar_variance
env param.fp_type
.et_type)
8318 Env.set_tyvar_variance
env ft_ret
.et_type ~flip
:true
8321 set_params_variance env param.fp_type
.et_type
8324 (* Given an expected function type ft, check types for the non-unpacked
8325 * arguments. Don't check lambda expressions if check_lambdas=false *)
8326 let rec check_args check_lambdas
env el paraml
=
8328 (* We've got an argument *)
8329 | ((pk
, e), opt_result
) :: el ->
8330 (* Pick up next parameter type info *)
8331 let (is_variadic
, opt_param
, paraml
) = get_next_param_info paraml
in
8332 let (env, one_result
) =
8333 match (check_lambdas
, is_lambda e) with
8336 check_arg env pk
e opt_param ~is_variadic
8338 let env = set_tyvar_variance_from_lambda_param env opt_param
in
8340 | (true, false) -> (env, opt_result
)
8342 let (env, rl
, paraml
) = check_args check_lambdas
env el paraml
in
8343 (env, ((pk
, e), one_result
) :: rl
, paraml
)
8344 | [] -> (env, [], paraml
)
8346 (* Same as above, but checks the types of the implicit arguments, which are
8347 * read from the context *)
8348 let check_implicit_args env =
8350 Typing_coeffects.get_type
ft.ft_implicit_params
.capability
8352 if not
(TypecheckerOptions.call_coeffects
(Env.get_tcopt
env)) then
8355 let env_capability =
8356 Env.get_local_check_defined
env (pos, Typing_coeffects.capability_id
)
8359 Typing_error.Primary.(
8361 (Coeffect.Call_coeffect
8364 available_incl_unsafe
=
8365 Typing_coeffects.pretty
env env_capability;
8366 available_pos
= Typing_defs.get_pos
env_capability;
8367 required_pos
= Typing_defs.get_pos
capability;
8368 required
= Typing_coeffects.pretty
env capability;
8371 Type.sub_type
pos Reason.URnone
env env_capability capability
8372 @@ Typing_error.Callback.always
base_error
8374 let should_forget_fakes =
8375 (* If the function doesn't have write priveleges to properties, fake
8376 members cannot be reassigned, so their refinements stand. *)
8378 Typing_coeffects.get_type
ft.ft_implicit_params
.capability
8383 (MakeType.capability Reason.Rnone
SN.Capabilities.writeProperty
)
8386 (* First check the non-lambda arguments. For generic functions, this
8387 * is likely to resolve type variables to concrete types *)
8388 let rl = List.map el ~f
:(fun e -> (e, None
)) in
8389 let non_variadic_ft_params =
8390 if get_ft_variadic
ft then
8391 List.drop_last_exn
ft.ft_params
8395 let (env, rl, _) = check_args false env rl non_variadic_ft_params in
8396 (* Now check the lambda arguments, hopefully with type variables resolved *)
8397 let (env, rl, paraml
) = check_args true env rl non_variadic_ft_params in
8398 (* We expect to see results for all arguments after this second pass *)
8399 let get_param ((pk
, _), opt
) =
8401 | Some
(e, ty) -> ((pk
, e), ty)
8402 | None
-> failwith
"missing parameter in check_args"
8405 let l = List.map rl ~f
:get_param in
8408 let env = check_implicit_args env in
8409 let (env, typed_unpack_element
, arity, did_unpack
) =
8410 match unpacked_element
with
8411 | None
-> (env, None
, List.length
el, false)
8413 (* Now that we're considering an splat (Some e) we need to construct a type that
8414 * represents the remainder of the function's parameters. `paraml` represents those
8415 * remaining parameters, and the variadic parameter is stored in `var_param`. For example, given
8417 * function f(int $i, string $j, float $k = 3.14, mixed ...$m): void {}
8418 * function g((string, float, bool) $t): void {
8422 * the constraint type we want is splat([#1], [opt#2], #3).
8424 let (consumed, required_params
, optional_params
) =
8425 split_remaining_params_required_optional ft paraml
8427 let (_, p1
, _) = e in
8428 let (env, (d_required
, d_optional
, d_variadic
)) =
8429 generate_splat_type_vars
8436 let destructure_ty =
8439 ( Reason.Runpack_param
(p1
, pos_def, consumed),
8445 d_kind
= SplatUnpack
;
8448 let (env, te, ty) = expr env e in
8449 (* Populate the type variables from the expression in the splat *)
8457 Typing_error.Callback.unify_error
8462 (* Our type cannot be destructured, add a hole with `nothing`
8466 @@ Reason.Rsolve_fail
(Pos_or_decl.of_raw_pos
pos)
8468 (env, mk_hole te ~ty_have
:ty ~
ty_expect)
8470 (* We have a type that can be destructured so continue and use
8471 the type variables for the remaining parameters *)
8472 let (env, err_opts
) =
8477 ~f
:(fun (env, errs
) elt
param ->
8478 let (env, err_opt) =
8487 (env, err_opt :: errs
))
8489 let (env, err_opts
) =
8491 ~
init:(env, err_opts
)
8494 ~f
:(fun (env, errs
) elt
param ->
8495 let (env, err_opt) =
8504 (env, err_opt :: errs
))
8506 let (env, var_err_opt
) =
8507 Option.map2 d_variadic var_param ~f
:(fun v vp
->
8515 |> Option.value ~
default:(env, None
)
8517 let subtyping_errs = (List.rev err_opts
, var_err_opt
) in
8519 match (List.filter_map ~f
:Fn.id err_opts
, var_err_opt
) with
8522 let (_, pos, _) = te in
8525 ~
err_opt:(Some
(ty, pack_errs pos ty subtyping_errs))
8532 List.length
el + List.length d_required
,
8533 Option.is_some d_variadic
)
8535 (* If we unpacked an array, we don't check arity exactly. Since each
8536 * unpacked array consumes 1 or many parameters, it is nonsensical to say
8537 * that not enough args were passed in (so we don't do the min check).
8539 let () = check_arity ~did_unpack
pos pos_def ft arity in
8540 (* Variadic params cannot be inout so we can stop early *)
8541 let env = wfold_left2 inout_write_back
env non_variadic_ft_params el in
8543 if in_supportdyn
then
8544 MakeType.locl_like r2
ft.ft_ret
.et_type
8548 (env, (tel, typed_unpack_element
, ret, should_forget_fakes))
8550 when TypecheckerOptions.method_call_inference
(Env.get_tcopt
env) ->
8552 Typecheck calls with unresolved function type by constructing a
8553 suitable function type from the arguments and invoking subtyping.
8555 let (env, typed_el
, type_of_el
) =
8556 argument_list_exprs
(expr ~accept_using_var
:true) env el
8558 let (env, typed_unpacked_element
, type_of_unpacked_element
) =
8559 match unpacked_element
with
8561 let (env, typed_unpacked
, type_of_unpacked
) =
8562 expr ~accept_using_var
:true env unpacked
8564 (env, Some typed_unpacked
, Some type_of_unpacked
)
8565 | None
-> (env, None
, None
)
8567 let mk_function_supertype env pos (type_of_el
, type_of_unpacked_element
) =
8568 let mk_fun_param ty =
8570 (* Keep supertype as permissive as possible: *)
8572 ~
mode:FPnormal
(* TODO: deal with `inout` parameters *)
8573 ~accept_disposable
:false (* TODO: deal with disposables *)
8580 fp_pos
= Pos_or_decl.of_raw_pos
pos;
8582 fp_type
= MakeType.enforced ty;
8587 match type_of_unpacked_element
with
8588 | Some type_of_unpacked
->
8589 let fun_param = mk_fun_param type_of_unpacked
in
8593 (* TODO: ensure `ft_params`/`ft_where_constraints` don't affect subtyping *)
8594 let ft_tparams = [] in
8595 let ft_where_constraints = [] in
8596 let ft_params = List.map ~f
:mk_fun_param type_of_el
in
8597 let ft_implicit_params =
8600 CapDefaults
(Pos_or_decl.of_raw_pos
pos)
8601 (* TODO(coeffects) should this be a different type? *);
8604 let (env, return_ty
) = Env.fresh_type
env pos in
8608 | Some
r -> MakeType.awaitable
r return_ty
8610 let ft_ret = MakeType.enforced return_ty in
8612 (* Keep supertype as permissive as possible: *)
8614 Ast_defs.FSync
(* `FSync` fun can still return `Awaitable<_>` *)
8615 ~return_disposable
:false (* TODO: deal with disposable return *)
8616 ~returns_readonly
:false
8617 ~readonly_this
:false
8618 ~
support_dynamic_type:false
8620 ~variadic
:(not
(List.is_empty
ft_arity))
8622 let ft_ifc_decl = Typing_defs_core.default_ifc_fun_decl
in
8626 ft_where_constraints;
8627 ft_params = ft_params @ ft_arity;
8634 let fun_type = mk
(r, Tfun
fun_locl_type) in
8635 let env = Env.set_tyvar_variance
env fun_type in
8636 (env, fun_type, return_ty)
8638 let (env, fun_type, return_ty) =
8639 mk_function_supertype env pos (type_of_el
, type_of_unpacked_element
)
8648 Typing_error.Callback.unify_error
8650 let should_forget_fakes = true in
8651 (env, (typed_el
, typed_unpacked_element
, return_ty, should_forget_fakes))
8652 | (_, Tnewtype
(name, [ty], _))
8653 when String.equal
name SN.Classes.cSupportDyn
->
8656 call ~
expected ~
nullsafe ?in_await
pos env ty el unpacked_element
)
8668 bad_call env pos efty
;
8669 let env = call_untyped_unpack
env (get_pos efty
) unpacked_element
in
8670 let should_forget_fakes = true in
8671 (env, ([], None
, err_witness env pos, should_forget_fakes))
8673 and call_supportdyn ~
expected ~
nullsafe ?in_await
pos env ty el unpacked_element
8675 let (env, ty) = Env.expand_type
env ty in
8695 (MakeType.dynamic
r)
8699 and call_untyped_unpack
env f_pos unpacked_element
=
8700 match unpacked_element
with
8701 (* In the event that we don't have a known function call type, we can still
8702 * verify that any unpacked arguments (`...$args`) are something that can
8703 * be actually unpacked. *)
8706 let (env, _, ety) = expr env e ~
allow_awaitable:(*?*) false in
8707 let (_, p
, _) = e in
8708 let (env, ty) = Env.fresh_type
env p
in
8709 let destructure_ty =
8710 MakeType.simple_variadic_splat
(Reason.Runpack_param
(p
, f_pos
, 0)) ty
8718 Typing_error.Callback.unify_error
8721 * Build an environment for the true or false branch of
8722 * conditional statements.
8724 and condition ?lhs_of_null_coalesce
env tparamet
((ty, p
, e) as te : Tast.expr)
8726 let condition = condition ?lhs_of_null_coalesce
in
8728 | Aast.Hole
(e, _, _, _) -> condition env tparamet
e
8729 | Aast.True
when not tparamet
->
8730 (LEnv.drop_cont
env C.Next
, Local_id.Set.empty
)
8731 | Aast.False
when tparamet
-> (LEnv.drop_cont
env C.Next
, Local_id.Set.empty
)
8732 | Aast.Call
((_, _, Aast.Id
(_, func
)), _, [(_, te)], None
)
8733 when String.equal
SN.StdlibFunctions.is_null func
->
8734 condition_nullity ~nonnull
:(not tparamet
) env te
8735 | Aast.Binop
((Ast_defs.Eqeq
| Ast_defs.Eqeqeq
), (_, _, Aast.Null
), e)
8736 | Aast.Binop
((Ast_defs.Eqeq
| Ast_defs.Eqeqeq
), e, (_, _, Aast.Null
)) ->
8737 condition_nullity ~nonnull
:(not tparamet
) env e
8741 | Aast.Binop
(Ast_defs.Eq None
, _, _) ->
8742 let (env, ety) = Env.expand_type
env ty in
8743 (match get_node
ety with
8744 | Tprim Tbool
-> (env, Local_id.Set.empty
)
8745 | _ -> condition_nullity ~nonnull
:tparamet
env te)
8746 | Aast.Binop
(((Ast_defs.Diff
| Ast_defs.Diff2
) as op
), e1
, e2) ->
8748 if Ast_defs.(equal_bop
op Diff
) then
8753 condition env (not tparamet
) (ty, p
, Aast.Binop
(op, e1
, e2))
8754 (* Conjunction of conditions. Matches the two following forms:
8756 if (!(cond1 || cond2))
8758 | Aast.Binop
(((Ast_defs.Ampamp
| Ast_defs.Barbar
) as bop
), e1
, e2)
8759 when Bool.equal tparamet
Ast_defs.(equal_bop bop Ampamp
) ->
8760 let (env, lset1
) = condition env tparamet e1
in
8761 (* This is necessary in case there is an assignment in e2
8762 * We essentially redo what has been undone in the
8763 * `Binop (Ampamp|Barbar)` case of `expr` *)
8765 expr env (Tast.to_nast_expr
e2) ~
allow_awaitable:(*?*) false
8767 let (env, lset2
) = condition env tparamet
e2 in
8768 (env, Local_id.Set.union lset1 lset2
)
8769 (* Disjunction of conditions. Matches the two following forms:
8771 if (!(cond1 && cond2))
8773 | Aast.Binop
(((Ast_defs.Ampamp
| Ast_defs.Barbar
) as bop
), e1
, e2)
8774 when Bool.equal tparamet
Ast_defs.(equal_bop bop Barbar
) ->
8775 let (env, lset1
, lset2
) =
8779 (* Either cond1 is true and we don't know anything about cond2... *)
8780 condition env tparamet e1
)
8782 (* ... Or cond1 is false and therefore cond2 must be true *)
8783 let (env, _lset
) = condition env (not tparamet
) e1
in
8784 (* Similarly to the conjunction case, there might be an assignment in
8785 cond2 which we must account for. Again we redo what has been undone in
8786 the `Binop (Ampamp|Barbar)` case of `expr` *)
8788 expr env (Tast.to_nast_expr
e2) ~
allow_awaitable:(*?*) false
8790 condition env tparamet
e2)
8792 (env, Local_id.Set.union lset1 lset2
)
8793 | Aast.Call
((_, p
, Aast.Id
(_, f
)), _, [(_, lv
)], None
)
8794 when tparamet
&& String.equal f
SN.StdlibFunctions.is_dict_or_darray
->
8795 safely_refine_is_array env HackDictOrDArray p f lv
8796 | Aast.Call
((_, p
, Aast.Id
(_, f
)), _, [(_, lv
)], None
)
8797 when tparamet
&& String.equal f
SN.StdlibFunctions.is_vec_or_varray
->
8798 safely_refine_is_array env HackVecOrVArray p f lv
8799 | Aast.Call
((_, p
, Aast.Id
(_, f
)), _, [(_, lv
)], None
)
8800 when String.equal f
SN.StdlibFunctions.is_any_array
->
8806 (Reason.Rpredicated
(p
, f
))
8809 ( (p
, "\\HH\\AnyArray"),
8810 [(p
, Happly
((p
, "_"), [])); (p
, Happly
((p
, "_"), []))] ) )
8811 | Aast.Call
((_, p
, Aast.Id
(_, f
)), _, [(_, lv
)], None
)
8812 when tparamet
&& String.equal f
SN.StdlibFunctions.is_php_array
->
8813 safely_refine_is_array env PHPArray p f lv
8817 Aast.Class_const
((_, _, Aast.CI
(_, class_name)), (_, method_name
))
8820 [(_, shape
); (_, field)],
8823 && String.equal
class_name SN.Shapes.cShapes
8824 && String.equal method_name
SN.Shapes.keyExists
->
8825 key_exists env p shape
field
8826 | Aast.Unop
(Ast_defs.Unot
, e) -> condition env (not tparamet
) e
8827 | Aast.Is
(ivar
, h
) ->
8828 refine_for_is ~hint_first
:false env tparamet ivar
(Reason.Ris
(fst h
)) h
8829 | _ -> (env, Local_id.Set.empty
)
8831 and string2
env idl
=
8833 List.fold_left idl ~
init:(env, []) ~f
:(fun (env, tel) x ->
8834 let (env, te, ty) = expr env x ~
allow_awaitable:(*?*) false in
8835 let (_, p
, _) = x in
8837 TypecheckerOptions.enable_strict_string_concat_interp
8840 let r = Reason.Rinterp_operand p
in
8841 let (env, formatter_tyvar
) = Env.fresh_type_invariant
env p
in
8846 MakeType.arraykey r;
8848 MakeType.hh_formatstring
r formatter_tyvar
;
8851 let (env, err_opt) =
8853 ~ok
:(fun env -> (env, None
))
8854 ~
error:(fun env -> (env, Some
(ty, stringlike)))
8855 @@ Typing_ops.sub_type_res
8861 Typing_error.Callback.strict_str_interp_type_mismatch
8863 (env, hole_on_err ~
err_opt te :: tel)
8865 let env = Typing_substring.sub_string p
env ty in
8870 and user_attribute
env ua
=
8871 let (env, typed_ua_params
) =
8872 List.map_env
env ua
.ua_params ~f
:(fun env e ->
8873 let (env, te, _) = expr env e ~
allow_awaitable:(*?*) false in
8876 (env, { Aast.ua_name
= ua
.ua_name
; Aast.ua_params
= typed_ua_params
})
8878 and file_attributes
env file_attrs
=
8879 (* Disable checking of error positions, as file attributes have spans that
8880 * aren't subspans of the class or function into which they are copied *)
8881 Errors.run_with_span
Pos.none
@@ fun () ->
8882 List.map_env
env file_attrs ~f
:(fun env fa
->
8883 let (env, user_attributes
) =
8884 attributes_check_def
env SN.AttributeKinds.file fa
.fa_user_attributes
8886 let env = set_tcopt_unstable_features env fa
in
8889 Aast.fa_user_attributes
= user_attributes
;
8890 Aast.fa_namespace
= fa
.fa_namespace
;
8893 and type_param
env t
=
8894 let (env, user_attributes
) =
8895 attributes_check_def
env SN.AttributeKinds.typeparam t
.tp_user_attributes
8897 let (env, tp_parameters
) = List.map_env
env t
.tp_parameters ~f
:type_param
in
8900 Aast.tp_variance
= t
.tp_variance
;
8901 Aast.tp_name
= t
.tp_name
;
8903 Aast.tp_constraints
= t
.tp_constraints
;
8904 Aast.tp_reified
= reify_kind t
.tp_reified
;
8905 Aast.tp_user_attributes
= user_attributes
;
8908 (* Calls the method of a class, but allows the f callback to override the
8909 * return value type *)
8910 and overload_function
8911 make_call fpos p
env class_id method_id
el unpacked_element f
=
8912 let (env, _tal
, tcid
, ty) = class_expr
env [] class_id
in
8913 let (env, (fty, tal
)) =
8917 ~coerce_from_ty
:None
8923 let (env, (tel, typed_unpack_element
, res, should_forget_fakes)) =
8924 call ~
expected:None p
env fty el unpacked_element
8926 let (env, ty) = f
env fty res el tel in
8927 let (env, fty) = Env.expand_type
env fty in
8929 map_ty
fty ~f
:(function
8930 | Tfun
ft -> Tfun
{ ft with ft_ret = MakeType.unenforced
ty }
8933 let te = Tast.make_typed_expr fpos
fty (Aast.Class_const
(tcid
, method_id
)) in
8934 (make_call env te tal
tel typed_unpack_element
ty, should_forget_fakes)
8936 and update_array_type ?lhs_of_null_coalesce p
env e1
valkind =
8939 | `lvalue_subexpr
->
8940 let (env, te1, ty1
) =
8942 ~
valkind:`lvalue_subexpr
8946 ~
allow_awaitable:(*?*) false
8950 | (_, _, Lvar
(_, x)) ->
8951 (* type_mapper has updated the type in ty1 typevars, but we
8952 need to update the local variable type too *)
8953 let env = set_local env (p
, x) ty1
in
8955 | _ -> (env, te1, ty1
)
8957 | _ -> raw_expr ?lhs_of_null_coalesce
env e1 ~
allow_awaitable:(*?*) false
8960 let expr ?
expected env e =
8961 Typing_env.with_origin2
env Decl_counters.Body
(fun env ->
8962 expr ?
expected env e ~
allow_awaitable:(*?*) false)
8964 let expr_with_pure_coeffects ?
expected env e =
8965 Typing_env.with_origin2
env Decl_counters.Body
(fun env ->
8966 expr_with_pure_coeffects ?
expected env e ~
allow_awaitable:(*?*) false)
8969 Typing_env.with_origin
env Decl_counters.Body
(fun env -> stmt env st
)