2 * Copyright (c) 2015, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
10 (* This module implements the typing.
12 * Given an Nast.program, it infers the type of all the local
13 * variables, and checks that all the types are correct (aka
23 module TFTerm
= Typing_func_terminality
24 module TUtils
= Typing_utils
25 module Reason
= Typing_reason
26 module Type
= Typing_ops
27 module Env
= Typing_env
28 module Inf
= Typing_inference_env
29 module LEnv
= Typing_lenv
30 module Async
= Typing_async
31 module SubType
= Typing_subtype
32 module Union
= Typing_union
33 module Inter
= Typing_intersection
34 module SN
= Naming_special_names
35 module TVis
= Typing_visibility
36 module Phase
= Typing_phase
37 module TOG
= Typing_object_get
38 module Subst
= Decl_subst
39 module ExprDepTy
= Typing_dependent_type.ExprDepTy
40 module TCO
= TypecheckerOptions
41 module EnvFromDef
= Typing_env_from_def
42 module C
= Typing_continuations
44 module Try
= Typing_try
45 module TR
= Typing_reactivity
46 module FL
= FeatureLogging
47 module MakeType
= Typing_make_type
48 module Cls
= Decl_provider.Class
49 module Partial
= Partial_provider
50 module Fake
= Typing_fake_members
51 module ExpectedTy
= Typing_helpers.ExpectedTy
53 type newable_class_info
=
57 * [ `Class
of sid
* Cls.t
* locl_ty
| `Dynamic
] list
59 (*****************************************************************************)
61 (*****************************************************************************)
63 (* A guess as to the last position we were typechecking, for use in debugging,
64 * such as figuring out what a runaway hh_server thread is doing. Updated
65 * only best-effort -- it's an approximation to point debugging in the right
66 * direction, nothing more. *)
67 let debug_last_pos = ref Pos.none
69 let debug_print_last_pos _
=
71 "Last typecheck pos: %s"
72 (Pos.string (Pos.to_absolute
!debug_last_pos))
74 (*****************************************************************************)
76 (*****************************************************************************)
78 let err_witness env p
= TUtils.terr env
(Reason.Rwitness p
)
80 (* Set all the types in an expression to the given type. *)
81 let with_type ty env
(e
: Nast.expr
) : Tast.expr
=
86 method on_'ex _ p
= (p
, ty
)
88 method on_'fb _ _
= ()
90 method on_'en _ _
= env
92 method on_'hi _ _
= ty
97 let expr_error env
(r
: Reason.t
) (e
: Nast.expr
) =
98 let ty = TUtils.terr env r
in
99 (env
, with_type ty Tast.dummy_saved_env e
, ty)
101 let expr_any env p e
=
102 let ty = Typing_utils.mk_tany env p
in
103 (env
, with_type ty Tast.dummy_saved_env e
, ty)
105 let unbound_name env
(pos
, name
) e
=
106 let strictish = Partial.should_check_error
(Env.get_mode env
) 4107 in
107 match Env.get_mode env
with
108 | FileInfo.Mstrict
->
109 Errors.unbound_name_typing pos name
;
110 expr_error env
(Reason.Rwitness pos
) e
111 | FileInfo.Mpartial
when strictish ->
112 Errors.unbound_name_typing pos name
;
113 expr_error env
(Reason.Rwitness pos
) e
115 | FileInfo.Mpartial
->
118 (* Is this type Traversable<vty> or Container<vty> for some vty? *)
119 let get_value_collection_inst ty =
120 match get_node
ty with
121 | Tclass
((_
, c
), _
, [vty
])
122 when String.equal c
SN.Collections.cTraversable
123 || String.equal c
SN.Collections.cContainer
->
125 (* If we're expecting a mixed or a nonnull then we can just assume
126 * that the element type is mixed *)
127 | Tnonnull
-> Some
(MakeType.mixed
Reason.Rnone
)
131 (* Is this type KeyedTraversable<kty,vty>
132 * or KeyedContainer<kty,vty>
135 let get_key_value_collection_inst p
ty =
136 match get_node
ty with
137 | Tclass
((_
, c
), _
, [kty
; vty
])
138 when String.equal c
SN.Collections.cKeyedTraversable
139 || String.equal c
SN.Collections.cKeyedContainer
->
141 (* If we're expecting a mixed or a nonnull then we can just assume
142 * that the key type is arraykey and the value type is mixed *)
144 let arraykey = MakeType.arraykey (Reason.Rkey_value_collection_key p
) in
145 let mixed = MakeType.mixed Reason.Rnone
in
146 Some
(arraykey, mixed)
147 | Tany _
-> Some
(ty, ty)
150 (* Is this type varray<vty> or a supertype for some vty? *)
151 let get_varray_inst ty =
152 match get_node
ty with
153 (* It's varray<vty> *)
154 | Tvarray vty
-> Some vty
155 | _
-> get_value_collection_inst ty
157 (* Is this type one of the value collection types with element type vty? *)
158 let get_vc_inst vc_kind
ty =
159 match get_node
ty with
160 | Tclass
((_
, c
), _
, [vty
]) when String.equal c
(Nast.vc_kind_to_name vc_kind
)
163 | _
-> get_value_collection_inst ty
165 (* Is this type one of the three key-value collection types
166 * e.g. dict<kty,vty> or a supertype for some kty and vty? *)
167 let get_kvc_inst p kvc_kind
ty =
168 match get_node
ty with
169 | Tclass
((_
, c
), _
, [kty
; vty
])
170 when String.equal c
(Nast.kvc_kind_to_name kvc_kind
) ->
172 | _
-> get_key_value_collection_inst p
ty
174 (* Is this type darray<kty, vty> or a supertype for some kty and vty? *)
175 let get_darray_inst p
ty =
176 match get_node
ty with
177 (* It's darray<kty, vty> *)
178 | Tdarray
(kty
, vty
) -> Some
(kty
, vty
)
179 | _
-> get_key_value_collection_inst p
ty
181 (* Check whether this is a function type that (a) either returns a disposable
182 * or (b) has the <<__ReturnDisposable>> attribute
184 let is_return_disposable_fun_type env
ty =
185 let (_env
, ty) = Env.expand_type env
ty in
186 match get_node
ty with
188 get_ft_return_disposable ft
190 (Typing_disposable.is_disposable_type env ft
.ft_ret
.et_type
)
193 (* Turn an environment into a local_id_map suitable to be embedded
194 * into an AssertEnv statement
197 match Env.next_cont_opt env
with
198 | Some
{ Typing_per_cont_env.local_types
; _
} ->
199 Some
(Local_id.Map.map
(fun (ty, pos
, _expr_id
) -> (pos
, ty)) local_types
)
202 (* Similar to annot_map above, but filters the map to only contain
203 * information about locals in lset
205 let refinement_annot_map env lset
=
206 match annot_map env
with
209 Local_id.Map.filter
(fun lid _
-> Local_id.Set.mem lid lset
) map
211 if Local_id.Map.is_empty
map then
217 let assert_env_blk ~pos ~at annotation_kind env_map_opt blk
=
218 let mk_assert map = (pos
, Aast.AssertEnv
(annotation_kind
, map)) in
219 let annot_blk = Option.to_list
(Option.map ~f
:mk_assert env_map_opt
) in
221 | `Start
-> annot_blk @ blk
222 | `End
-> blk
@ annot_blk
224 let assert_env_stmt ~pos ~at annotation_kind env_map_opt stmt
=
225 let mk_assert map = (pos
, Aast.AssertEnv
(annotation_kind
, map)) in
226 match env_map_opt
with
230 | `Start
-> [mk_assert env_map
; (pos
, stmt
)]
231 | `End
-> [(pos
, stmt
); mk_assert env_map
]
236 let set_tcopt_unstable_features env
{ fa_user_attributes
; _
} =
238 Naming_attributes.find
239 SN.UserAttributes.uaEnableUnstableFeatures
243 | Some
{ ua_name
= _
; ua_params
} ->
244 let ( = ) = String.equal
in
245 List.fold ua_params ~init
:env ~f
:(fun env feature
->
246 match snd feature
with
247 | Aast.String s
when s
= SN.UnstableFeatures.ifc
->
248 Env.map_tcopt ~f
:TypecheckerOptions.enable_ifc env
251 (* Given a localized parameter type and parameter information, infer
252 * a type for the parameter default expression (if present) and check that
253 * it is a subtype of the parameter type (if present). If no parameter type
254 * is specified, then union with Tany. (So it's as though we did a conditional
255 * assignment of the default expression to the parameter).
256 * Set the type of the parameter in the locals environment *)
257 let rec bind_param env
(ty1
, param
) =
258 let (env
, param_te
, ty1
) =
259 match param
.param_expr
with
260 | None
-> (env
, None
, ty1
)
264 ~f
:(Decl_hint.hint env
.decl_env
)
265 (hint_of_type_hint param
.param_type_hint
)
270 | Some
ty -> Typing_enforceability.is_enforceable env
ty
272 let ty1_enforced = { et_type
= ty1
; et_enforced
= enforced } in
274 ExpectedTy.make_and_allow_coercion
279 let (env
, te
, ty2
) = expr ~
expected env e
in
280 Typing_sequencing.sequence_check_expr e
;
283 Option.is_none
(hint_of_type_hint param
.param_type_hint
)
284 && (not
@@ TCO.global_inference
(Env.get_tcopt env
))
285 (* ty1 will be Tany iff we have no type hint and we are not in
286 * 'infer missing mode'. When it ty1 is Tany we just union it with
287 * the type of the default expression *)
289 Union.union env ty1 ty2
290 (* Otherwise we have an explicit type, and the default expression type
291 * must be a subtype *)
294 Typing_coercion.coerce_type
300 Errors.parameter_default_value_wrong_type
306 let (env, user_attributes
) =
307 List.map_env
env param
.param_user_attributes user_attribute
311 Aast.param_annotation
= Tast.make_expr_annotation param
.param_pos ty1
;
312 Aast.param_type_hint
= (ty1
, hint_of_type_hint param
.param_type_hint
);
313 Aast.param_is_variadic
= param
.param_is_variadic
;
314 Aast.param_pos
= param
.param_pos
;
315 Aast.param_name
= param
.param_name
;
316 Aast.param_expr
= param_te
;
317 Aast.param_callconv
= param
.param_callconv
;
318 Aast.param_user_attributes
= user_attributes
;
319 Aast.param_visibility
= param
.param_visibility
;
322 let mode = get_param_mode param
.param_callconv
in
323 let id = Local_id.make_unscoped param
.param_name
in
324 let env = Env.set_local
env id ty1 param
.param_pos
in
325 let env = Env.set_param
env id (ty1
, param
.param_pos
, mode) in
327 if has_accept_disposable_attribute param
then
328 Env.set_using_var
env id
333 match get_param_mutability param
with
334 | Some Param_borrowed_mutable
->
338 (param
.param_pos
, Typing_mutability_env.Borrowed
)
339 | Some Param_owned_mutable
->
340 Env.add_mutable_var
env id (param
.param_pos
, Typing_mutability_env.Mutable
)
341 | Some Param_maybe_mutable
->
345 (param
.param_pos
, Typing_mutability_env.MaybeMutable
)
350 (param
.param_pos
, Typing_mutability_env.Immutable
)
354 and check_inout_return ret_pos
env =
355 let params = Local_id.Map.elements
(Env.get_params
env) in
356 List.fold
params ~init
:env ~f
:(fun env (id, (ty, param_pos
, mode)) ->
359 (* Whenever the function exits normally, we require that each local
360 * corresponding to an inout parameter be compatible with the original
361 * type for the parameter (under subtyping rules). *)
362 let (local_ty
, local_pos
) = Env.get_local_pos
env id in
363 let (env, ety
) = Env.expand_type
env local_ty
in
365 if not
(Pos.equal
Pos.none local_pos
) then
367 else if not
(Pos.equal
Pos.none ret_pos
) then
372 let param_ty = mk
(Reason.Rinout_param
(get_pos
ty), get_node
ty) in
375 Reason.URassign_inout
379 Errors.inout_return_type_mismatch
382 (*****************************************************************************)
383 (* function used to type closures, functions and methods *)
384 (*****************************************************************************)
385 and fun_ ?
(abstract
= false) ?
(disable
= false) env return
pos named_body f_kind
387 Env.with_env
env (fun env ->
388 debug_last_pos := pos;
389 let env = Env.set_return
env return
in
393 Errors.internal_error
395 ( "Type inference for this function has been disabled by the "
396 ^
SN.UserAttributes.uaDisableTypecheckerInternal
401 block
env named_body
.fb_ast
403 Typing_sequencing.sequence_check_block named_body
.fb_ast
;
404 let { Typing_env_return_info.return_type
= ret
; _
} =
409 (not
@@ LEnv.has_next
env)
411 || Nast.named_body_is_unsafe named_body
415 fun_implicit_return
env pos ret
.et_type f_kind
417 debug_last_pos := Pos.none
;
420 and fun_implicit_return
env pos ret
= function
421 | Ast_defs.FGenerator
422 | Ast_defs.FAsyncGenerator
->
425 (* A function without a terminal block has an implicit return; the
427 let env = check_inout_return
Pos.none
env in
428 let r = Reason.Rno_return
pos in
429 let rty = MakeType.void
r in
430 Typing_return.implicit_return
env pos ~
expected:ret ~actual
:rty
432 (* An async function without a terminal block has an implicit return;
433 * the Awaitable<void> type *)
434 let r = Reason.Rno_return_async
pos in
435 let rty = MakeType.awaitable
r (MakeType.void
r) in
436 Typing_return.implicit_return
env pos ~
expected:ret ~actual
:rty
439 Typing_env.with_origin
env Decl_counters.Body
@@ fun env ->
440 List.map_env
env stl ~f
:stmt
442 (* Set a local; must not be already assigned if it is a using variable *)
443 and set_local ?
(is_using_clause
= false) env (pos, x
) ty =
444 if Env.is_using_var
env x
then
445 if is_using_clause
then
446 Errors.duplicate_using_var
pos
448 Errors.illegal_disposable
pos "assigned";
449 let env = Env.set_local
env x
ty pos in
450 if is_using_clause
then
451 Env.set_using_var
env x
455 (* Check an individual component in the expression `e` in the
456 * `using (e) { ... }` statement.
457 * This consists of either
458 * a simple assignment `$x = e`, in which `$x` is the using variable, or
459 * an arbitrary expression `e`, in which case a temporary is the using
460 * variable, inaccessible in the source.
461 * Return the typed expression and its type, and any variables that must
462 * be designated as "using variables" for avoiding escapes.
464 and check_using_expr has_await
env ((pos, content
) as using_clause
) =
466 (* Simple assignment to local of form `$lvar = e` *)
467 | Binop
(Ast_defs.Eq None
, (lvar_pos
, Lvar lvar
), e
) ->
468 let (env, te
, ty) = expr ~is_using_clause
:true env e
in
470 Typing_disposable.enforce_is_disposable_type
env has_await
(fst e
) ty
472 let env = set_local ~is_using_clause
:true env lvar
ty in
473 (* We are assigning a new value to the local variable, so we need to
474 * generate a new expression id
476 let env = Env.set_local_expr_id
env (snd lvar
) (Ident.tmp
()) in
478 ( Tast.make_typed_expr
483 Tast.make_typed_expr lvar_pos
ty (Aast.Lvar lvar
),
486 (* Arbitrary expression. This will be assigned to a temporary *)
488 let (env, typed_using_clause
, ty) =
489 expr ~is_using_clause
:true env using_clause
492 Typing_disposable.enforce_is_disposable_type
env has_await
pos ty
494 (env, (typed_using_clause
, []))
496 (* Check the using clause e in
497 * `using (e) { ... }` statement (`has_await = false`) or
498 * `await using (e) { ... }` statement (`has_await = true`).
499 * `using_clauses` is a list of expressions.
500 * Return the typed expression, and any variables that must
501 * be designated as "using variables" for avoiding escapes.
503 and check_using_clause
env has_await using_clauses
=
505 List.map_env
env using_clauses
(check_using_expr has_await
)
507 let (typed_using_clauses
, vars
) = List.unzip pairs
in
508 (env, typed_using_clauses
, List.concat vars
)
510 (* Require a new construct with disposable *)
511 and enforce_return_disposable _env e
=
515 | (_
, Await
(_
, Call _
)) -> ()
516 | (p
, _
) -> Errors.invalid_return_disposable p
518 (* Wrappers around the function with the same name in Typing_lenv, which only
519 * performs the move/save and merge operation if we are in a try block or in a
520 * function with return type 'noreturn'.
521 * This enables significant perf improvement, because this is called at every
522 * function of method call, when most calls are outside of a try block. *)
523 and move_and_merge_next_in_catch
env =
524 if env.in_try
|| TFTerm.is_noreturn
env then
525 LEnv.move_and_merge_next_in_cont
env C.Catch
527 LEnv.drop_cont
env C.Next
529 and save_and_merge_next_in_catch
env =
530 if env.in_try
|| TFTerm.is_noreturn
env then
531 LEnv.save_and_merge_next_in_cont
env C.Catch
535 and might_throw
env = save_and_merge_next_in_catch
env
537 and stmt
env (pos, st
) =
538 let (env, st
) = stmt_
env pos st
in
539 Typing_debug.log_env_if_too_big
pos env;
542 and stmt_
env pos st
=
543 (* Type check a loop. f env = (env, result) checks the body of the loop.
544 * We iterate over the loop until the "next" continuation environment is
545 * stable. alias_depth is supposed to be an upper bound on this; but in
546 * certain cases this fails (e.g. a generic type grows unboundedly). TODO:
549 let infer_loop env f
=
550 let in_loop_outer = env.in_loop
in
552 if in_loop_outer then
555 Typing_alias.get_depth
(pos, st
)
557 let env = { env with in_loop
= true } in
559 (* Remember the old environment *)
560 let old_next_entry = Env.next_cont_opt
env in
561 let (env, result
) = f
env in
562 let new_next_entry = Env.next_cont_opt
env in
563 (* Finish if we reach the bound, or if the environments match *)
565 Int.equal n
alias_depth
566 || Typing_per_cont_ops.is_sub_opt_entry
567 Typing_subtype.is_sub_type
572 let env = { env with in_loop
= in_loop_outer } in
579 let env = Env.open_tyvars
env pos in
581 (Typing_solver.close_tyvars_and_solve
env Errors.unify_error
, tb
))
587 LEnv.move_and_merge_next_in_cont
env C.Fallthrough
591 (env, Aast.Fallthrough
)
592 | Noop
-> (env, Aast.Noop
)
593 | AssertEnv _
-> (env, Aast.Noop
)
595 let (env, te
, _
) = expr
env e
in
597 if TFTerm.typed_expression_exits te
then
598 LEnv.move_and_merge_next_in_cont
env C.Exit
604 let assert_refinement_env =
605 assert_env_blk ~
pos ~at
:`Start
Aast.Refinement
607 let (env, te
, _
) = expr
env e
in
608 let (env, tb1
, tb2
) =
612 let (env, lset
) = condition
env true te
in
613 let refinement_map = refinement_annot_map env lset
in
614 let (env, b1
) = block
env b1
in
615 let b1 = assert_refinement_env refinement_map b1 in
618 let (env, lset
) = condition
env false te
in
619 let refinement_map = refinement_annot_map env lset
in
620 let (env, b2
) = block
env b2
in
621 let b2 = assert_refinement_env refinement_map b2 in
624 (* TODO TAST: annotate with joined types *)
625 (env, Aast.If
(te
, tb1
, tb2
))
627 let env = check_inout_return
pos env in
628 let rty = MakeType.void
(Reason.Rwitness
pos) in
629 let { Typing_env_return_info.return_type
= expected_return
; _
} =
632 let expected_return =
633 Typing_return.strip_awaitable
(Env.get_fn_kind
env) env expected_return
636 match Env.get_fn_kind
env with
637 | Ast_defs.FGenerator
638 | Ast_defs.FAsyncGenerator
->
641 Typing_return.implicit_return
644 ~
expected:expected_return.et_type
647 let env = LEnv.move_and_merge_next_in_cont
env C.Exit
in
648 (env, Aast.Return None
)
650 let env = check_inout_return
pos env in
651 let expr_pos = fst e
in
652 let Typing_env_return_info.
659 return_dynamically_callable
= _
;
664 Typing_return.strip_awaitable
(Env.get_fn_kind
env) env return_type
667 if return_explicit
then
669 (ExpectedTy.make_and_allow_coercion
676 if return_disposable
then enforce_return_disposable
env e
;
678 expr ~is_using_clause
:return_disposable ?
expected env e
681 if not
(equal_reactivity
(env_reactivity
env) Nonreactive
) then
682 Typing_mutability.handle_value_in_return
683 ~function_returns_mutable
:return_mutable
684 ~function_returns_void_for_rx
:return_void_to_rx
694 et_type
= TR.strip_condition_type_in_return
env return_type.et_type
;
697 (* This is a unify_error rather than a return_type_mismatch because the return
698 * statement is the problem, not the return type itself. *)
700 Typing_coercion.coerce_type
708 let env = LEnv.move_and_merge_next_in_cont
env C.Exit
in
709 (env, Aast.Return
(Some te
))
711 (* NOTE: leaks scope as currently implemented; this matches
712 the behavior in naming (cf. `do_stmt` in naming/naming.ml).
714 let (env, (tb
, te
)) =
715 LEnv.stash_and_do
env [C.Continue
; C.Break
; C.Do
] (fun env ->
716 let env = LEnv.save_and_merge_next_in_cont
env C.Do
in
717 let (env, _
) = block
env b
in
718 (* saving the locals in continue here even if there is no continue
719 * statement because they must be merged at the end of the loop, in
720 * case there is no iteration *)
721 let env = LEnv.save_and_merge_next_in_cont
env C.Continue
in
723 infer_loop env (fun env ->
725 LEnv.update_next_from_conts
env [C.Continue
; C.Next
]
727 (* The following is necessary in case there is an assignment in the
729 let (env, te
, _
) = expr
env e
in
730 let (env, _lset
) = condition
env true te
in
731 let env = LEnv.update_next_from_conts
env [C.Do
; C.Next
] in
732 let (env, tb
) = block
env b
in
735 let env = LEnv.update_next_from_conts
env [C.Continue
; C.Next
] in
736 let (env, te
, _
) = expr
env e
in
737 let (env, _lset
) = condition
env false te
in
738 let env = LEnv.update_next_from_conts
env [C.Break
; C.Next
] in
741 (env, Aast.Do
(tb
, te
))
743 let (env, (te
, tb
, refinement_map)) =
744 LEnv.stash_and_do
env [C.Continue
; C.Break
] (fun env ->
745 let env = LEnv.save_and_merge_next_in_cont
env C.Continue
in
747 infer_loop env (fun env ->
749 LEnv.update_next_from_conts
env [C.Continue
; C.Next
]
751 let join_map = annot_map env in
752 (* The following is necessary in case there is an assignment in the
754 let (env, te
, _
) = expr
env e
in
755 let (env, lset
) = condition
env true te
in
756 let refinement_map = refinement_annot_map env lset
in
757 (* TODO TAST: avoid repeated generation of block *)
758 let (env, tb
) = block
env b
in
760 (* Annotate loop body with join and refined environments *)
761 let assert_env_blk = assert_env_blk ~
pos ~at
:`Start
in
762 let tb = assert_env_blk Aast.Refinement
refinement_map tb in
763 let tb = assert_env_blk Aast.Join
join_map tb in
767 let env = LEnv.update_next_from_conts
env [C.Continue
; C.Next
] in
768 let (env, te
, _
) = expr
env e
in
769 let (env, lset
) = condition
env false te
in
770 let refinement_map_at_exit = refinement_annot_map env lset
in
771 let env = LEnv.update_next_from_conts
env [C.Break
; C.Next
] in
772 (env, (te
, tb, refinement_map_at_exit)))
774 let while_st = Aast.While
(te
, tb) in
775 (* Export the refined environment after the exit condition holds *)
777 assert_env_stmt ~
pos ~at
:`End
Aast.Refinement
refinement_map while_st
782 us_has_await
= has_await
;
783 us_exprs
= (loc
, using_clause
);
784 us_block
= using_block
;
787 let (env, typed_using_clause
, using_vars
) =
788 check_using_clause
env has_await using_clause
790 let (env, typed_using_block
) = block
env using_block
in
791 (* Remove any using variables from the environment, as they should not
792 * be in scope outside the block *)
793 let env = List.fold_left using_vars ~init
:env ~f
:Env.unset_local
in
798 us_has_await
= has_await
;
799 us_exprs
= (loc
, typed_using_clause
);
800 us_block
= typed_using_block
;
803 | For
(e1
, e2
, e3
, b
) ->
807 | None
-> (Pos.none
, True
)
809 let (env, (te1
, te2
, te3
, tb, refinement_map)) =
810 LEnv.stash_and_do
env [C.Continue
; C.Break
] (fun env ->
811 (* For loops leak their initalizer, but nothing that's defined in the
814 let (env, te1
, _
) = exprs
env e1
in
816 let env = LEnv.save_and_merge_next_in_cont
env C.Continue
in
817 let (env, (tb, te3
)) =
818 infer_loop env (fun env ->
819 (* The following is necessary in case there is an assignment in the
821 let (env, te2
, _
) = expr
env e2 in
822 let (env, lset
) = condition
env true te2
in
823 let refinement_map = refinement_annot_map env lset
in
824 let (env, tb) = block
env b
in
826 LEnv.update_next_from_conts
env [C.Continue
; C.Next
]
828 let join_map = annot_map env in
829 let (env, te3
, _
) = exprs
env e3
in
831 (* Export the join and refinement environments *)
832 let assert_env_blk = assert_env_blk ~
pos ~at
:`Start
in
833 let tb = assert_env_blk Aast.Refinement
refinement_map tb in
834 let tb = assert_env_blk Aast.Join
join_map tb in
838 let env = LEnv.update_next_from_conts
env [C.Continue
; C.Next
] in
839 let (env, te2
, _
) = expr
env e2 in
840 let (env, lset
) = condition
env false te2
in
841 let refinement_map_at_exit = refinement_annot_map env lset
in
842 let env = LEnv.update_next_from_conts
env [C.Break
; C.Next
] in
843 (env, (te1
, te2
, te3
, tb, refinement_map_at_exit)))
845 let for_st = Aast.For
(te1
, Some te2
, te3
, tb) in
847 assert_env_stmt ~
pos ~at
:`End
Aast.Refinement
refinement_map for_st
850 | Switch
(((pos, _
) as e
), cl
) ->
851 let (env, te
, ty) = expr
env e
in
852 (* NB: A 'continue' inside a 'switch' block is equivalent to a 'break'.
854 * http://php.net/manual/en/control-structures.continue.php *)
855 let (env, (te
, tcl
)) =
856 LEnv.stash_and_do
env [C.Continue
; C.Break
] (fun env ->
857 let parent_locals = LEnv.get_all_locals
env in
858 let case_list env = case_list parent_locals ty env pos cl
in
859 let (env, tcl
) = Env.in_case
env case_list in
861 LEnv.update_next_from_conts
env [C.Continue
; C.Break
; C.Next
]
865 (env, Aast.Switch
(te
, tcl
))
866 | Foreach
(e1
, e2, b
) ->
867 (* It's safe to do foreach over a disposable, as no leaking is possible *)
868 let (env, te1
, ty1
) = expr ~accept_using_var
:true env e1
in
869 let (env, (te1
, te2
, tb)) =
870 LEnv.stash_and_do
env [C.Continue
; C.Break
] (fun env ->
871 let env = LEnv.save_and_merge_next_in_cont
env C.Continue
in
872 let (env, tk
, tv
) = as_expr
env ty1
(fst e1
) e2 in
873 let (env, (te2
, tb)) =
874 infer_loop env (fun env ->
876 LEnv.update_next_from_conts
env [C.Continue
; C.Next
]
878 let join_map = annot_map env in
879 let (env, te2
) = bind_as_expr
env (fst e1
) tk tv
e2 in
880 let (env, tb) = block
env b
in
881 (* Export the join environment *)
882 let tb = assert_env_blk ~
pos ~at
:`Start
Aast.Join
join_map tb in
886 LEnv.update_next_from_conts
env [C.Continue
; C.Break
; C.Next
]
888 (env, (te1
, te2
, tb)))
890 (env, Aast.Foreach
(te1
, te2
, tb))
891 | Try
(tb, cl
, fb
) ->
892 let (env, ttb
, tcl
, tfb
) = try_catch
env tb cl fb
in
893 (env, Aast.Try
(ttb
, tcl
, tfb
))
894 | Awaitall
(el
, b
) ->
895 let env = might_throw
env in
897 List.fold_left el ~init
:(env, []) ~f
:(fun (env, tel
) (e1
, e2) ->
898 let (env, te2
, ty2
) = expr
env e2 in
900 Async.overload_extract_from_awaitable
env (fst
e2) ty2
904 let (env, _
, _
) = assign
(fst e1
) env (fst e1
, Lvar e1
) ty2
in
905 (env, (Some e1
, te2
) :: tel
)
906 | None
-> (env, (None
, te2
) :: tel
))
908 let (env, b
) = block
env b
in
909 (env, Aast.Awaitall
(el
, b
))
912 let (env, te
, ty) = expr
env e
in
913 let env = coerce_to_throwable
p env ty in
914 let env = move_and_merge_next_in_catch
env in
917 let env = LEnv.move_and_merge_next_in_cont
env C.Continue
in
920 let env = LEnv.move_and_merge_next_in_cont
env C.Break
in
925 "Unexpected nodes in AST. These nodes should have been removed in naming."
928 type res
. env -> (env -> env * res
) -> (env -> env * res
) -> env * res
* res
930 fun env branch1 branch2
->
931 let parent_lenv = env.lenv
in
932 let (env, tbr1
) = branch1
env in
933 let lenv1 = env.lenv
in
934 let env = { env with lenv
= parent_lenv } in
935 let (env, tbr2
) = branch2
env in
936 let lenv2 = env.lenv
in
937 let env = LEnv.union_lenvs
env parent_lenv lenv1 lenv2 in
940 and finally_cont fb
env ctx
=
941 (* The only locals in scope are the ones from the current continuation *)
942 let env = Env.env_with_locals
env @@ CMap.singleton
C.Next ctx
in
943 let (env, _tfb
) = block
env fb
in
944 (env, LEnv.get_all_locals
env)
949 let env = LEnv.update_next_from_conts
env [C.Next
; C.Finally
] in
952 let parent_locals = LEnv.get_all_locals
env in
953 (* First typecheck the finally block against all continuations merged
955 * During this phase, record errors found in the finally block, but discard
956 * the resulting environment. *)
957 let all_conts = Env.all_continuations
env in
958 let env = LEnv.update_next_from_conts
env all_conts in
959 let (env, tfb
) = block
env fb
in
960 let env = LEnv.restore_conts_from
env parent_locals all_conts in
961 (* Second, typecheck the finally block once against each continuation. This
962 * helps be more clever about what each continuation will be after the
964 * We don't want to record errors during this phase, because certain types
965 * of errors will fire wrongly. For example, if $x is nullable in some
966 * continuations but not in others, then we must use `?->` on $x, but an
967 * error will fire when typechecking the finally block againts continuations
968 * where $x is non-null. *)
969 let finally_cont env _key
= finally_cont fb
env in
970 let (env, locals_map
) =
971 Errors.ignore_
(fun () -> CMap.map_env
finally_cont env parent_locals)
973 let union env _key
= LEnv.union_contextopts
env in
974 let (env, locals
) = Try.finally_merge
union env locals_map
all_conts in
975 (Env.env_with_locals
env locals
, tfb
)
977 and try_catch
env tb cl fb
=
978 let parent_locals = LEnv.get_all_locals
env in
980 LEnv.drop_conts
env [C.Break
; C.Continue
; C.Exit
; C.Catch
; C.Finally
]
982 let (env, (ttb
, tcb
)) =
983 Env.in_try
env (fun env ->
984 let (env, ttb
) = block
env tb in
985 let env = LEnv.move_and_merge_next_in_cont
env C.Finally
in
986 let catchctx = LEnv.get_cont_option
env C.Catch
in
987 let (env, lenvtcblist
) = List.map_env
env ~f
:(catch
catchctx) cl
in
988 let (lenvl
, tcb
) = List.unzip lenvtcblist
in
989 let env = LEnv.union_lenv_list
env env.lenv lenvl
in
990 let env = LEnv.move_and_merge_next_in_cont
env C.Finally
in
993 let (env, tfb
) = finally
env fb
in
994 let env = LEnv.update_next_from_conts
env [C.Finally
] in
995 let env = LEnv.drop_cont
env C.Finally
in
997 LEnv.restore_and_merge_conts_from
1000 [C.Break
; C.Continue
; C.Exit
; C.Catch
; C.Finally
]
1002 (env, ttb
, tcb
, tfb
)
1004 and case_list parent_locals ty env switch_pos cl
=
1005 let initialize_next_cont env =
1006 let env = LEnv.restore_conts_from
env parent_locals [C.Next
] in
1007 let env = LEnv.update_next_from_conts
env [C.Next
; C.Fallthrough
] in
1008 LEnv.drop_cont
env C.Fallthrough
1010 let check_fallthrough env switch_pos case_pos block rest_of_list ~is_default
=
1011 if not
@@ List.is_empty block
then
1012 match rest_of_list
with
1014 | [Default
(_
, [])] ->
1018 match LEnv.get_cont_option
env C.Next
with
1021 Errors.default_fallthrough switch_pos
1023 Errors.case_fallthrough switch_pos case_pos
1031 let make_exhaustive_equivalent_case_list env cl
=
1033 List.exists cl ~f
:(function
1038 (* If it hasn't got a default clause then we need to solve type variables
1039 * in order to check for an enum *)
1041 Env.expand_type
env ty
1043 Typing_solver.expand_type_and_solve
1045 ~description_of_expected
:"a value"
1054 SN.Classes.cHH_BuiltinEnum
1055 [MakeType.mixed Reason.Rnone
]
1057 Typing_subtype.is_sub_type_for_coercion
env ty top_type
1059 (* If there is no default case and this is not a switch on enum (since
1060 * exhaustiveness is garanteed elsewhere on enums),
1061 * then add a default case for control flow correctness
1063 if has_default || is_enum then
1066 (env, cl
@ [Default
(Pos.none
, [])], true)
1068 let rec case_list env = function
1070 | Default
(pos, b
) :: rl
->
1071 let env = initialize_next_cont env in
1072 let (env, tb) = block
env b
in
1073 check_fallthrough env switch_pos
pos b rl ~is_default
:true;
1074 let (env, tcl
) = case_list env rl
in
1075 (env, Aast.Default
(pos, tb) :: tcl
)
1076 | Case
(((pos, _
) as e
), b
) :: rl
->
1077 let env = initialize_next_cont env in
1078 let (env, te
, _
) = expr
env e
in
1079 let (env, tb) = block
env b
in
1080 check_fallthrough env switch_pos
pos b rl ~is_default
:false;
1081 let (env, tcl
) = case_list env rl
in
1082 (env, Aast.Case
(te
, tb) :: tcl
)
1084 let (env, cl
, added_empty_default
) =
1085 make_exhaustive_equivalent_case_list env cl
1087 let (env, tcl
) = case_list env cl
in
1089 if added_empty_default
then
1090 List.take
tcl (List.length
tcl - 1)
1096 and catch
catchctx env (sid
, exn_lvar
, b
) =
1097 let env = LEnv.replace_cont
env C.Next
catchctx in
1099 let ety_p = fst sid
in
1100 let (env, _
, _
, _
) = instantiable_cid
ety_p env cid [] in
1101 let (env, _tal
, _te
, ety
) =
1102 static_class_id ~check_constraints
:false ety_p env [] cid
1104 let env = coerce_to_throwable
ety_p env ety
in
1105 let env = set_local
env exn_lvar ety
in
1106 let (env, tb) = block
env b
in
1107 (env, (env.lenv
, (sid
, exn_lvar
, tb)))
1109 and as_expr
env ty1 pe e
=
1110 let env = Env.open_tyvars
env pe
in
1111 let (env, tv
) = Env.fresh_type
env pe
in
1112 let (env, expected_ty
, tk
, tv
) =
1115 let tk = MakeType.mixed Reason.Rnone
in
1116 (env, MakeType.traversable
(Reason.Rforeach pe
) tv
, tk, tv
)
1118 let (env, tk) = Env.fresh_type
env pe
in
1119 (env, MakeType.keyed_traversable
(Reason.Rforeach pe
) tk tv
, tk, tv
)
1121 let tk = MakeType.mixed Reason.Rnone
in
1122 (env, MakeType.async_iterator
(Reason.Rasyncforeach pe
) tv
, tk, tv
)
1124 let (env, tk) = Env.fresh_type
env pe
in
1126 MakeType.async_keyed_iterator
(Reason.Rasyncforeach pe
) tk tv
,
1130 let rec distribute_union env ty =
1131 let (env, ty) = Env.expand_type
env ty in
1132 match get_node
ty with
1133 | Tunion tyl
-> List.fold tyl ~init
:env ~f
:distribute_union
1135 if SubType.is_sub_type_for_union
env ty (MakeType.dynamic
Reason.Rnone
)
1137 let env = SubType.sub_type
env ty tk Errors.unify_error
in
1138 let env = SubType.sub_type
env ty tv
Errors.unify_error
in
1141 let ur = Reason.URforeach
in
1142 Type.sub_type pe
ur env ty expected_ty
Errors.unify_error
1144 let env = distribute_union env ty1
in
1145 let env = Env.set_tyvar_variance
env expected_ty
in
1146 (Typing_solver.close_tyvars_and_solve
env Errors.unify_error
, tk, tv
)
1148 and bind_as_expr
env p ty1 ty2 aexpr
=
1149 let check_reassigned_mutable env te
=
1150 if Env.env_local_reactive
env then
1151 Typing_mutability.handle_assignment_mutability
env te None
1157 let (env, te
, _
) = assign
p env ev ty2
in
1158 let env = check_reassigned_mutable env te
in
1160 | Await_as_v
(p, ev
) ->
1161 let (env, te
, _
) = assign
p env ev ty2
in
1162 let env = check_reassigned_mutable env te
in
1163 (env, Aast.Await_as_v
(p, te
))
1164 | As_kv
((p, Lvar
((_
, k
) as id)), ev
) ->
1165 let env = set_valid_rvalue
p env k ty1
in
1166 let (env, te
, _
) = assign
p env ev ty2
in
1167 let tk = Tast.make_typed_expr
p ty1
(Aast.Lvar
id) in
1168 let env = check_reassigned_mutable env tk in
1169 let env = check_reassigned_mutable env te
in
1170 (env, Aast.As_kv
(tk, te
))
1171 | Await_as_kv
(p, (p1
, Lvar
((_
, k
) as id)), ev
) ->
1172 let env = set_valid_rvalue
p env k ty1
in
1173 let (env, te
, _
) = assign
p env ev ty2
in
1174 let tk = Tast.make_typed_expr p1 ty1
(Aast.Lvar
id) in
1175 let env = check_reassigned_mutable env tk in
1176 let env = check_reassigned_mutable env te
in
1177 (env, Aast.Await_as_kv
(p, tk, te
))
1179 (* TODO Probably impossible, should check that *)
1183 ?
(expected : ExpectedTy.t
option)
1184 ?
(accept_using_var
= false)
1185 ?
(is_using_clause
= false)
1187 ?
(check_defined
= true)
1195 | Some
ExpectedTy.{ reason
= r; ty = { et_type
= ty; _
}; _
} ->
1197 log_with_level
env "typing" 1 (fun () ->
1203 ( "Typing.expr " ^
Typing_reason.string_of_ureason
r,
1204 [Log_type
("expected_ty", ty)] );
1216 with Inf.InconsistentTypeVarState _
as e
->
1217 (* we don't want to catch unwanted exceptions here, eg Timeouts *)
1218 Errors.exception_occurred
p (Exception.wrap e
);
1219 make_result
env p Aast.Any
@@ err_witness env p
1222 ?
(accept_using_var
= false)
1223 ?
(is_using_clause
= false)
1224 ?
(expected : ExpectedTy.t
option)
1225 ?lhs_of_null_coalesce
1227 ?
(check_defined
= true)
1231 debug_last_pos := fst e
;
1236 ?lhs_of_null_coalesce
1244 let valkind = `lvalue
in
1245 expr_ ~
valkind ~check_defined
:false env e
1247 and lvalues
env el
=
1249 | [] -> (env, [], [])
1251 let (env, te
, ty) = lvalue
env e
in
1252 let (env, tel
, tyl
) = lvalues
env el
in
1253 (env, te
:: tel
, ty :: tyl
)
1255 and is_pseudo_function s
=
1256 String.equal s
SN.PseudoFunctions.hh_show
1257 || String.equal s
SN.PseudoFunctions.hh_show_env
1258 || String.equal s
SN.PseudoFunctions.hh_log_level
1259 || String.equal s
SN.PseudoFunctions.hh_force_solve
1260 || String.equal s
SN.PseudoFunctions.hh_loop_forever
1262 and loop_forever
env =
1263 (* forever = up to 10 minutes, to avoid accidentally stuck processes *)
1265 (* Look up things in shared memory occasionally to have a chance to be
1267 match Env.get_class
env "FOR_TEST_ONLY" with
1268 | None
-> Unix.sleep
1
1271 Utils.assert_false_log_backtrace
1272 (Some
"hh_loop_forever was looping for more than 10 minutes")
1274 (* $x ?? 0 is handled similarly to $x ?: 0, except that the latter will also
1275 * look for sketchy null checks in the condition. *)
1276 (* TODO TAST: type refinement should be made explicit in the typed AST *)
1277 and eif
env ~
(expected : ExpectedTy.t
option) ?in_await
p c e1
e2 =
1278 let condition = condition ~lhs_of_null_coalesce
:false in
1279 let (env, tc
, tyc
) = raw_expr ~lhs_of_null_coalesce
:false env c
in
1280 let parent_lenv = env.lenv
in
1281 let (env, _lset
) = condition env true tc
in
1282 let (env, te1
, ty1
) =
1285 let (env, ty) = Typing_solver.non_null
env p tyc
in
1288 let (env, te1
, ty1
) = expr ?
expected ?in_await
env e1
in
1289 (env, Some te1
, ty1
)
1291 let lenv1 = env.lenv
in
1292 let env = { env with lenv
= parent_lenv } in
1293 let (env, _lset
) = condition env false tc
in
1294 let (env, te2
, ty2
) = expr ?
expected ?in_await
env e2 in
1295 let lenv2 = env.lenv
in
1296 let env = LEnv.union_lenvs
env parent_lenv lenv1 lenv2 in
1297 let (env, ty) = Union.union env ty1 ty2
in
1298 make_result
env p (Aast.Eif
(tc
, te1
, te2
)) ty
1300 and is_parameter
env x
= Local_id.Map.mem x
(Env.get_params
env)
1302 and check_escaping_var
env (pos, x
) =
1303 if Env.is_using_var
env x
then
1304 if Local_id.equal x this
then
1305 Errors.escaping_this
pos
1306 else if is_parameter
env x
then
1307 Errors.escaping_disposable_parameter
pos
1309 Errors.escaping_disposable
pos
1314 ?
(accept_using_var
= false)
1315 ?
(expected : ExpectedTy.t
option)
1317 ?
(check_defined
= true)
1321 | [] -> (env, [], [])
1324 expr ~accept_using_var ?
expected ~
valkind ~check_defined
env e
1326 let (env, tel
, tyl
) =
1327 exprs ~accept_using_var ?
expected ~
valkind ~check_defined
env el
1329 (env, te
:: tel
, ty :: tyl
)
1331 and exprs_expected
(pos, ur, expected_tyl
) env el
=
1332 match (el
, expected_tyl
) with
1333 | ([], _
) -> (env, [], [])
1334 | (e
:: el
, expected_ty
:: expected_tyl
) ->
1335 let expected = ExpectedTy.make
pos ur expected_ty
in
1336 let (env, te
, ty) = expr ~
expected env e
in
1337 let (env, tel
, tyl
) = exprs_expected
(pos, ur, expected_tyl
) env el
in
1338 (env, te
:: tel
, ty :: tyl
)
1339 | (el
, []) -> exprs
env el
1341 and make_result
env p te
ty =
1342 (* Set the variance of any type variables that were generated according
1343 * to how they appear in the expression type *)
1344 let env = Env.set_tyvar_variance
env ty in
1345 (env, Tast.make_typed_expr
p ty te
, ty)
1347 and localize_targ
env ta
=
1349 let (env, targ
) = Phase.localize_targ ~check_well_kinded
:true env ta
in
1350 (env, targ
, ExpectedTy.make
pos Reason.URhint
(fst targ
))
1352 and set_function_pointer
ty =
1353 match get_node
ty with
1355 let ft = set_ft_is_function_pointer
ft true in
1356 mk
(get_reason
ty, Tfun
ft)
1360 ?
(expected : ExpectedTy.t
option)
1361 ?
(accept_using_var
= false)
1362 ?
(is_using_clause
= false)
1363 ?lhs_of_null_coalesce
1365 ~
(valkind : [> `lvalue
| `lvalue_subexpr
| `other
])
1369 let env = Env.open_tyvars
env p in
1370 (fun (env, te
, ty) ->
1371 let env = Typing_solver.close_tyvars_and_solve
env Errors.unify_error
in
1374 let expr = expr ~check_defined
in
1375 let exprs = exprs ~check_defined
in
1376 let raw_expr = raw_expr ~check_defined
in
1378 * Given a list of types, computes their supertype. If any of the types are
1379 * unknown (e.g., comes from PHP), the supertype will be Typing_utils.tany env.
1381 let compute_supertype
1382 ~
(expected : ExpectedTy.t
option) ~reason ~use_pos
r env tys
=
1383 let (env, supertype
) =
1385 | None
-> Env.fresh_type_reason
env r
1386 | Some
ExpectedTy.{ ty = { et_type
= ty; _
}; _
} -> (env, ty)
1388 match get_node supertype
with
1389 (* No need to check individual subtypes if expected type is mixed or any! *)
1390 | Tany _
-> (env, supertype
)
1392 let subtype_value env ty =
1393 Type.sub_type use_pos reason
env ty supertype
Errors.unify_error
1395 let env = List.fold_left tys ~init
:env ~f
:subtype_value in
1397 List.exists tys
(fun ty ->
1398 equal_locl_ty_
(get_node
ty) (Typing_utils.tany
env))
1400 (* If one of the values comes from PHP land, we have to be conservative
1401 * and consider that we don't know what the type of the values are. *)
1402 (env, Typing_utils.mk_tany
env p)
1407 * Given a 'a list and a method to extract an expr and its ty from a 'a, this
1408 * function extracts a list of exprs from the list, and computes the supertype
1409 * of all of the expressions' tys.
1411 let compute_exprs_and_supertype
1412 ~
(expected : ExpectedTy.t
option)
1413 ?
(reason
= Reason.URarray_value
)
1418 extract_expr_and_ty
=
1419 let (env, exprs_and_tys
) =
1420 List.map_env
env l
(extract_expr_and_ty ~
expected)
1422 let (exprs, tys
) = List.unzip exprs_and_tys
in
1423 let (env, supertype
) =
1424 compute_supertype ~
expected ~reason ~use_pos
r env tys
1426 (env, exprs, supertype
)
1428 let forget_fake_members env p callexpr
=
1429 (* Some functions are well known to not change the types of members, e.g.
1431 * There are a lot of usages like
1432 * if (!is_null($x->a) && !is_null($x->a->b))
1433 * where the second is_null call invalidates the first condition.
1434 * This function is a bit best effort. Add stuff here when you want
1435 * To avoid adding too many undue HH_FIXMEs. *)
1438 when String.equal func
SN.StdlibFunctions.is_null
1439 || String.equal func
SN.PseudoFunctions.isset
->
1441 | _
-> Env.forget_members
env Reason.(Blame
(p, BScall
))
1445 ~
(expected : ExpectedTy.t
option)
1453 let (env, te
, result
) =
1465 let env = forget_fake_members env p e
in
1471 failwith
"AST should not contain these nodes"
1473 let ty = Typing_utils.mk_tany
env p in
1474 make_result
env p Aast.Omitted
ty
1475 | Any
-> expr_error env (Reason.Rwitness
p) outer
1477 | ValCollection
(_
, th
, el
) ->
1478 let (get_expected_kind
, name
, subtype_val
, make_expr
, make_ty
) =
1480 | ValCollection
(kind
, _
, _
) ->
1481 let class_name = Nast.vc_kind_to_name kind
in
1487 arraykey_value
p class_name
1496 (fun th elements
-> Aast.ValCollection
(kind
, th
, elements
)),
1498 MakeType.class_type
(Reason.Rwitness
p) class_name [value_ty
] )
1503 (fun th elements
-> Aast.Varray
(th
, elements
)),
1504 (fun value_ty
-> MakeType.varray
(Reason.Rwitness
p) value_ty
) )
1506 (* The parent match makes this case impossible *)
1507 failwith
"impossible match case"
1509 (* Use expected type to determine expected element type *)
1510 let (env, elem_expected
, th
) =
1513 let (env, tv
, tv_expected
) = localize_targ
env tv
in
1514 (env, Some tv_expected
, Some tv
)
1517 match expand_expected_and_get_node
env expected with
1518 | (env, Some
(pos, ur, ety
, _
)) ->
1520 match get_expected_kind ety
with
1521 | Some vty
-> (env, Some
(ExpectedTy.make
pos ur vty
), None
)
1522 | None
-> (env, None
, None
)
1524 | _
-> (env, None
, None
)
1527 let (env, tel
, elem_ty
) =
1528 compute_exprs_and_supertype
1529 ~
expected:elem_expected
1531 ~reason
:Reason.URvector
1532 (Reason.Rtype_variable_generics
(p, "T", strip_ns name
))
1537 make_result
env p (make_expr th tel
) (make_ty elem_ty
)
1539 | KeyValCollection
(_
, th
, l
) ->
1540 let (get_expected_kind
, name
, make_expr
, make_ty
) =
1542 | KeyValCollection
(kind
, _
, _
) ->
1543 let class_name = Nast.kvc_kind_to_name kind
in
1544 ( get_kvc_inst p kind
,
1546 (fun th pairs
-> Aast.KeyValCollection
(kind
, th
, pairs
)),
1547 (fun k v
-> MakeType.class_type
(Reason.Rwitness
p) class_name [k
; v
])
1550 ( get_darray_inst p,
1552 (fun th pairs
-> Aast.Darray
(th
, pairs
)),
1553 (fun k v
-> MakeType.darray
(Reason.Rwitness
p) k v
) )
1555 (* The parent match makes this case impossible *)
1556 failwith
"impossible match case"
1558 (* Use expected type to determine expected key and value types *)
1559 let (env, kexpected
, vexpected
, th
) =
1561 | Some
((_
, tk), (_
, tv
)) ->
1562 let (env, tk, tk_expected
) = localize_targ
env tk in
1563 let (env, tv
, tv_expected
) = localize_targ
env tv
in
1564 (env, Some tk_expected
, Some tv_expected
, Some
(tk, tv
))
1566 (* no explicit typehint, fallback to supplied expect *)
1568 match expand_expected_and_get_node
env expected with
1569 | (env, Some
(pos, reason
, ety
, _
)) ->
1571 match get_expected_kind ety
with
1572 | Some
(kty
, vty
) ->
1573 let k_expected = ExpectedTy.make
pos reason kty
in
1574 let v_expected = ExpectedTy.make
pos reason vty
in
1575 (env, Some
k_expected, Some
v_expected, None
)
1576 | None
-> (env, None
, None
, None
)
1578 | _
-> (env, None
, None
, None
)
1581 let (kl
, vl
) = List.unzip l
in
1583 compute_exprs_and_supertype
1586 ~reason
:Reason.URkey
1587 (Reason.Rtype_variable_generics
(p, "Tk", strip_ns name
))
1590 (arraykey_value
p name
)
1593 compute_exprs_and_supertype
1596 ~reason
:Reason.URvalue
1597 (Reason.Rtype_variable_generics
(p, "Tv", strip_ns name
))
1602 let pairs = List.zip_exn tkl tvl
in
1603 make_result
env p (make_expr th
pairs) (make_ty k v
)
1605 let (env, te
, ty) = expr env e
in
1606 (* Clone only works on objects; anything else fatals at runtime.
1607 * Constructing a call `e`->__clone() checks that `e` is an object and
1608 * checks coeffects on __clone *)
1613 Obj_get
(e
, (p, Id
(p, SN.Members.__clone
)), OG_nullthrows
, false)
1619 let (env, _te
, _ty
) = expr env clone_call in
1620 make_result
env p (Aast.Clone te
) ty
1622 if Option.is_none
(Env.get_self_ty
env) then Errors.this_var_outside_class
p;
1623 if not accept_using_var
then check_escaping_var
env (p, this
);
1624 let ty = Env.get_local
env this
in
1625 let r = Reason.Rwitness
p in
1626 let ty = mk
(r, TUtils.this_of
(mk
(r, get_node
ty))) in
1627 make_result
env p Aast.This
ty
1628 | True
-> make_result
env p Aast.True
(MakeType.bool (Reason.Rwitness
p))
1629 | False
-> make_result
env p Aast.False
(MakeType.bool (Reason.Rwitness
p))
1630 (* TODO TAST: consider checking that the integer is in range. Right now
1631 * it's possible for HHVM to fail on well-typed Hack code
1633 | Int s
-> make_result
env p (Aast.Int s
) (MakeType.int (Reason.Rwitness
p))
1635 make_result
env p (Aast.Float s
) (MakeType.float (Reason.Rwitness
p))
1636 (* TODO TAST: consider introducing a "null" type, and defining ?t to
1639 | Null
-> make_result
env p Aast.Null
(MakeType.null
(Reason.Rwitness
p))
1641 make_result
env p (Aast.String s
) (MakeType.string (Reason.Rwitness
p))
1643 let (env, tel
) = string2
env idl
in
1644 make_result
env p (Aast.String2 tel
) (MakeType.string (Reason.Rwitness
p))
1645 | PrefixedString
(n
, e
) ->
1646 if String.( <> ) n
"re" then (
1647 Errors.experimental_feature
1649 "String prefixes other than `re` are not yet supported.";
1650 expr_error env Reason.Rnone outer
1652 let (env, te
, ty) = expr env e
in
1654 let env = Typing_substring.sub_string
pe env ty in
1662 (Aast.PrefixedString
(n
, te
))
1663 (Typing_regex.type_pattern e
)
1665 | Pcre.Error
(Pcre.BadPattern
(s
, i
)) ->
1666 let s = s ^
" [" ^ string_of_int i ^
"]" in
1667 Errors.bad_regex_pattern
pe s;
1668 expr_error env (Reason.Rregex
pe) e
1669 | Typing_regex.Empty_regex_pattern
->
1670 Errors.bad_regex_pattern
pe "This pattern is empty";
1671 expr_error env (Reason.Rregex
pe) e
1672 | Typing_regex.Missing_delimiter
->
1673 Errors.bad_regex_pattern
pe "Missing delimiter(s)";
1674 expr_error env (Reason.Rregex
pe) e
1675 | Typing_regex.Invalid_global_option
->
1676 Errors.bad_regex_pattern
pe "Invalid global option(s)";
1677 expr_error env (Reason.Rregex
pe) e
1680 Errors.re_prefixed_non_string
pe "Strings with embedded expressions";
1681 expr_error env (Reason.Rregex
pe) e
1683 Errors.re_prefixed_non_string
pe "Non-strings";
1684 expr_error env (Reason.Rregex
pe) e
)
1686 let (env, fty
, _tal
) = fun_type_of_id
env x
[] [] in
1687 make_result
env p (Aast.Fun_id x
) fty
1688 | Id
((cst_pos
, cst_name
) as id) ->
1689 (match Env.get_gconst
env cst_name
with
1690 | None
when Partial.should_check_error
(Env.get_mode
env) 4106 ->
1691 Errors.unbound_global cst_pos
;
1692 let ty = err_witness env cst_pos
in
1693 make_result
env cst_pos
(Aast.Id
id) ty
1694 | None
-> make_result
env p (Aast.Id
id) (Typing_utils.mk_tany
env cst_pos
)
1696 let (env, ty) = Phase.localize_with_self ~
pos:p env ty in
1697 make_result
env p (Aast.Id
id) ty)
1698 | Method_id
(instance
, meth
) ->
1699 (* Method_id is used when creating a "method pointer" using the magic
1700 * inst_meth function.
1702 * Typing this is pretty simple, we just need to check that instance->meth
1703 * is public+not static and then return its type.
1705 let (env, te
, ty1
) = expr env instance
in
1706 let (env, (result
, _tal
)) =
1712 ~coerce_from_ty
:None
1723 Env.FakeMembers.check_instance_invalid
env instance
(snd meth
) result
1725 make_result
env p (Aast.Method_id
(te
, meth
)) result
1726 | Method_caller
(((pos, class_name) as pos_cname
), meth_name
) ->
1727 (* meth_caller('X', 'foo') desugars to:
1730 let class_ = Env.get_class
env class_name in
1732 | None
-> unbound_name env pos_cname outer
1734 (* Create a class type for the given object instantiated with unresolved
1735 * types for its type parameters.
1738 if Ast_defs.is_c_trait
(Cls.kind
class_) then
1739 Errors.meth_caller_trait
pos class_name
1742 List.map_env
env (Cls.tparams
class_) (fun env _
->
1743 Env.fresh_type
env p)
1746 List.map (Cls.tparams
class_) (fun { tp_name
= (p, n
); _
} ->
1747 (* TODO(T69551141) handle type arguments for Tgeneric *)
1748 MakeType.generic
(Reason.Rwitness
p) n
)
1750 let obj_type = MakeType.apply
(Reason.Rwitness
p) pos_cname
params in
1753 (Phase.env_with_self
env) with
1754 substs
= TUtils.make_locl_subst_for_class_tparams
class_ tvarl
;
1757 let (env, local_obj_ty
) = Phase.localize ~
ety_env env obj_type in
1758 let (env, (fty
, _tal
)) =
1763 ~coerce_from_ty
:None
1767 (CI
(pos, class_name))
1771 let (env, fty
) = Env.expand_type
env fty
in
1772 (match deref fty
with
1773 | (reason
, Tfun ftype
) ->
1774 (* We are creating a fake closure:
1775 * function(Class $x, arg_types_of(Class::meth_name))
1776 : return_type_of(Class::meth_name)
1781 substs
= TUtils.make_locl_subst_for_class_tparams
class_ tvarl
;
1785 Phase.check_tparams_constraints
1789 (Cls.tparams
class_)
1791 let (env, local_obj_ty
) = Phase.localize ~
ety_env env obj_type in
1792 let local_obj_fp = TUtils.default_fun_param local_obj_ty
in
1793 let fty = { ftype
with ft_params
= local_obj_fp :: ftype
.ft_params
} in
1796 ft_arity
= fty.ft_arity
;
1797 ft_tparams
= fty.ft_tparams
;
1798 ft_where_constraints
= fty.ft_where_constraints
;
1799 ft_params
= fty.ft_params
;
1800 ft_implicit_params
= fty.ft_implicit_params
;
1801 ft_ret
= fty.ft_ret
;
1802 (* propagate 'is_coroutine' from the method being called*)
1803 ft_flags
= fty.ft_flags
;
1804 ft_reactive
= fty.ft_reactive
;
1805 ft_ifc_decl
= fty.ft_ifc_decl
;
1811 (Aast.Method_caller
(pos_cname
, meth_name
))
1812 (mk
(reason
, Tfun
caller))
1814 (* This can happen if the method lives in PHP *)
1818 (Aast.Method_caller
(pos_cname
, meth_name
))
1819 (Typing_utils.mk_tany
env pos)))
1820 | FunctionPointer
(FP_class_const
((cpos
, cid), meth
), targs
) ->
1821 let (env, _
, ce
, cty
) =
1822 static_class_id ~check_constraints
:true cpos
env [] cid
1824 let (env, (fpty
, tal
)) =
1828 ~incl_tc
:false (* What is this? *)
1829 ~coerce_from_ty
:None
(* What is this? *)
1830 ~explicit_targs
:targs
1831 ~function_pointer
:true
1837 let env = Env.set_tyvar_variance
env fpty
in
1838 let fpty = set_function_pointer
fpty in
1842 (Aast.FunctionPointer
(FP_class_const
(ce
, meth
), tal
))
1844 | Smethod_id
((pc
, cid), meth
) ->
1845 (* Smethod_id is used when creating a "method pointer" using the magic
1846 * class_meth function.
1848 * Typing this is pretty simple, we just need to check that c::meth is
1849 * public+static and then return its type.
1851 let (class_, classname
) =
1855 (Env.get_self_class
env, Env.get_self_id
env)
1856 | CI
(_
, const
) when String.equal const
SN.PseudoConsts.g__CLASS__
->
1857 (Env.get_self_class
env, Env.get_self_id
env)
1858 | CI
(_
, id) -> (Env.get_class
env id, Some
id)
1861 let classname = Option.value classname ~default
:"" in
1864 (* The class given as a static string was not found. *)
1865 unbound_name env (pc
, classname) outer
1867 let smethod = Env.get_static_member
true env class_ (snd meth
) in
1870 (* The static method wasn't found. *)
1871 TOG.smember_not_found
1878 expr_error env Reason.Rnone outer
1879 | Some
({ ce_type
= (lazy ty); ce_pos
= (lazy ce_pos
); _
} as ce
) ->
1881 if get_ce_abstract ce
then
1884 | _
-> Errors.class_meth_abstract_call
classname (snd meth
) p ce_pos
1886 let ce_visibility = ce
.ce_visibility in
1887 let ce_deprecated = ce
.ce_deprecated in
1888 let (env, _tal
, te
, cid_ty
) =
1889 static_class_id ~check_constraints
:true pc
env [] cid
1891 let (env, cid_ty
) = Env.expand_type
env cid_ty
in
1893 match get_node cid_ty
with
1894 | Tclass
(_
, _
, tyargs) -> tyargs
1899 type_expansions
= [];
1900 substs
= TUtils.make_locl_subst_for_class_tparams
class_ tyargs;
1902 from_class
= Some
cid;
1904 on_error
= Errors.unify_error_at
p;
1907 (match deref
ty with
1910 Typing_enforceability.compute_enforced_and_pessimize_fun_type
env ft
1912 let def_pos = ce_pos
in
1914 Phase.localize_targs
1915 ~check_well_kinded
:true
1919 ~use_name
:(strip_ns
(snd meth
))
1930 use_name
= strip_ns
(snd meth
);
1932 explicit_targs
= tal
;
1939 let ty = mk
(r, Tfun
ft) in
1940 let use_pos = fst meth
in
1941 TVis.check_deprecated ~
use_pos ~
def_pos ce_deprecated;
1942 (match ce_visibility with
1943 | Vpublic
-> make_result
env p (Aast.Smethod_id
(te
, meth
)) ty
1945 Errors.private_class_meth ~
def_pos ~
use_pos;
1946 expr_error env r outer
1948 Errors.protected_class_meth ~
def_pos ~
use_pos;
1949 expr_error env r outer
)
1951 Errors.internal_error
p "We have a method which isn't callable";
1952 expr_error env r outer
)))
1954 let r = Reason.Rplaceholder
p in
1955 let ty = MakeType.void
r in
1956 make_result
env p (Aast.Lplaceholder
p) ty
1957 | Dollardollar _
when phys_equal
valkind `lvalue
->
1958 Errors.dollardollar_lvalue
p;
1959 expr_error env (Reason.Rwitness
p) outer
1960 | Dollardollar
id ->
1961 let ty = Env.get_local_check_defined
env id in
1962 let env = might_throw
env in
1963 make_result
env p (Aast.Dollardollar
id) ty
1964 | Lvar
((_
, x
) as id) ->
1965 if not accept_using_var
then check_escaping_var
env id;
1967 if check_defined
then
1968 Env.get_local_check_defined
env id
1972 make_result
env p (Aast.Lvar
id) ty
1974 let (env, tel
, tyl
) =
1977 | `lvalue_subexpr
->
1980 let (env, expected) = expand_expected_and_get_node
env expected in
1981 (match expected with
1982 | Some
(pos, ur, _
, Ttuple expected_tyl
) ->
1983 exprs_expected
(pos, ur, expected_tyl
) env el
1984 | _
-> exprs env el
)
1986 let ty = MakeType.tuple
(Reason.Rwitness
p) tyl
in
1987 make_result
env p (Aast.List tel
) ty
1988 | Pair
(th
, e1
, e2) ->
1989 let (env, expected1
, expected2
, th
) =
1991 | Some
((_
, t1
), (_
, t2
)) ->
1992 let (env, t1
, t1_expected
) = localize_targ
env t1
in
1993 let (env, t2
, t2_expected
) = localize_targ
env t2
in
1994 (env, Some t1_expected
, Some t2_expected
, Some
(t1
, t2
))
1996 (* Use expected type to determine expected element types *)
1997 (match expand_expected_and_get_node
env expected with
1998 | (env, Some
(pos, reason
, _ty
, Tclass
((_
, k
), _
, [ty1
; ty2
])))
1999 when String.equal k
SN.Collections.cPair
->
2000 let ty1_expected = ExpectedTy.make
pos reason ty1
in
2001 let ty2_expected = ExpectedTy.make
pos reason ty2
in
2002 (env, Some
ty1_expected, Some
ty2_expected, None
)
2003 | _
-> (env, None
, None
, None
))
2005 let (env, te1
, ty1
) = expr ?
expected:expected1
env e1
in
2006 let (env, te2
, ty2
) = expr ?
expected:expected2
env e2 in
2012 ~reason
:Reason.URpair_value
2014 (Reason.Rtype_variable_generics
(p1, "T1", "Pair"))
2021 ~reason
:Reason.URpair_value
2023 (Reason.Rtype_variable_generics
(p2, "T2", "Pair"))
2027 let ty = MakeType.pair
(Reason.Rwitness
p) ty1 ty2
in
2028 make_result
env p (Aast.Pair
(th
, te1
, te2
)) ty
2029 | Array_get
(e
, None
) ->
2030 let (env, te
, _
) = update_array_type
p env e
valkind in
2031 let env = might_throw
env in
2032 (* NAST check reports an error if [] is used for reading in an
2034 let ty = err_witness env p in
2035 make_result
env p (Aast.Array_get
(te
, None
)) ty
2036 | Array_get
(e1
, Some
e2) ->
2037 let (env, te1
, ty1
) =
2038 update_array_type ?lhs_of_null_coalesce
p env e1
valkind
2040 let (env, te2
, ty2
) = expr env e2 in
2041 let env = might_throw
env in
2042 let is_lvalue = phys_equal
valkind `lvalue
in
2044 Typing_array_access.array_get
2047 ?lhs_of_null_coalesce
2054 make_result
env p (Aast.Array_get
(te1
, Some te2
)) ty
2055 | Call
((pos_id
, Id
((_
, s) as id)), [], el
, None
) when is_pseudo_function
s
2057 let (env, tel
, tys
) = exprs ~accept_using_var
:true env el
in
2059 if String.equal
s SN.PseudoFunctions.hh_show
then (
2060 List.iter tys
(Typing_log.hh_show
p env);
2062 ) else if String.equal
s SN.PseudoFunctions.hh_show_env
then (
2063 Typing_log.hh_show_env
p env;
2065 ) else if String.equal
s SN.PseudoFunctions.hh_log_level
then
2067 | [(_
, String key_str
); (_
, Int level_str
)] ->
2068 Env.set_log_level
env key_str
(int_of_string level_str
)
2070 else if String.equal
s SN.PseudoFunctions.hh_force_solve
then
2071 Typing_solver.solve_all_unsolved_tyvars
env Errors.unify_error
2072 else if String.equal
s SN.PseudoFunctions.hh_loop_forever
then (
2078 let ty = MakeType.void
(Reason.Rwitness
p) in
2083 ( Tast.make_typed_expr pos_id
(TUtils.mk_tany
env pos_id
) (Aast.Id
id),
2088 | Call
(e
, explicit_targs
, el
, unpacked_element
) ->
2091 | Id
(pos, f
) when String.equal f
SN.SpecialFunctions.echo
->
2092 Typing_local_ops.enforce_output
pos env
2095 let env = might_throw
env in
2106 | FunctionPointer
(FP_id fid
, targs
) ->
2107 let (env, fty, targs
) = fun_type_of_id
env fid targs
[] in
2108 let e = Aast.FunctionPointer
(FP_id fid
, targs
) in
2109 let fty = set_function_pointer
fty in
2110 make_result
env p e fty
2111 | Binop
(Ast_defs.QuestionQuestion
, e1
, e2) ->
2112 let (env, te1
, ty1
) = raw_expr ~lhs_of_null_coalesce
:true env e1
in
2113 let (env, te2
, ty2
) = expr ?
expected env e2 in
2114 let (env, ty1'
) = Env.fresh_type
env (fst e1
) in
2119 (MakeType.nullable_locl
Reason.Rnone ty1'
)
2122 (* Essentially mimic a call to
2123 * function coalesce<Tr, Ta as Tr, Tb as Tr>(?Ta, Tb): Tr
2124 * That way we let the constraint solver take care of the union logic.
2126 let (env, ty_result
) = Env.fresh_type
env (fst
e2) in
2127 let env = SubType.sub_type
env ty1' ty_result
Errors.unify_error
in
2128 let env = SubType.sub_type
env ty2 ty_result
Errors.unify_error
in
2132 (Aast.Binop
(Ast_defs.QuestionQuestion
, te1
, te2
))
2134 | Binop
(Ast_defs.Eq op_opt
, e1
, e2) ->
2135 let make_result env p te
ty =
2136 let (env, te
, ty) = make_result env p te
ty in
2137 let env = Typing_reactivity.check_assignment
env te
in
2141 (* For example, e1 += e2. This is typed and translated as if
2142 * written e1 = e1 + e2.
2143 * TODO TAST: is this right? e1 will get evaluated more than once
2147 match (op
, snd e1
) with
2148 | (Ast_defs.QuestionQuestion
, Class_get _
) ->
2149 Errors.experimental_feature
2151 "null coalesce assignment operator with static properties";
2152 expr_error env Reason.Rnone outer
2155 (p, Binop
(Ast_defs.Eq None
, e1
, (p, Binop
(op
, e1
, e2))))
2157 let (env, te_fake
, ty) = raw_expr env e_fake in
2159 match snd te_fake
with
2160 | Aast.Binop
(_
, te1
, (_
, Aast.Binop
(_
, _
, te2
))) ->
2161 let te = Aast.Binop
(Ast_defs.Eq
(Some op
), te1
, te2
) in
2162 make_result env p te ty
2167 let (env, te2
, ty2
) = raw_expr env e2 in
2168 let (env, te1
, ty) = assign
p env e1 ty2
in
2170 if Env.env_local_reactive
env then
2171 Typing_mutability.handle_assignment_mutability
2178 make_result env p (Aast.Binop
(Ast_defs.Eq None
, te1
, te2
)) ty)
2179 | Binop
(((Ast_defs.Ampamp
| Ast_defs.Barbar
) as bop
), e1
, e2) ->
2180 let c = Ast_defs.(equal_bop bop Ampamp
) in
2181 let (env, te1
, _
) = expr env e1
in
2182 let lenv = env.lenv in
2183 let (env, _lset
) = condition env c te1
in
2184 let (env, te2
, _
) = expr env e2 in
2185 let env = { env with lenv } in
2189 (Aast.Binop
(bop
, te1
, te2
))
2190 (MakeType.bool (Reason.Rlogic_ret
p))
2191 | Binop
(bop
, e1
, e2) ->
2192 let (env, te1
, ty1
) = raw_expr env e1
in
2193 let (env, te2
, ty2
) = raw_expr env e2 in
2196 (* TODO: This could be less conservative: we only need to account for
2197 * the possibility of exception if the operator is `/` or `/=`.
2202 | _
-> might_throw
env
2204 let (env, te3
, ty) =
2205 Typing_arithmetic.binop
p env bop
(fst e1
) te1 ty1
(fst
e2) te2 ty2
2208 | Pipe
(e0
, e1
, e2) ->
2209 (* If it weren't for local variable assignment or refinement the pipe
2210 * expression e1 |> e2 could be typed using this rule (E is environment with
2211 * types for locals):
2213 * E |- e1 : ty1 E[$$:ty1] |- e2 : ty2
2214 * --------------------------------------
2217 * The possibility of e2 changing the types of locals in E means that E
2218 * can evolve, and so we need to restore $$ to its original state.
2220 let (env, te1
, ty1
) = expr env e1
in
2221 let dd_var = Local_id.make_unscoped
SN.SpecialIdents.dollardollar
in
2223 if Env.is_local_defined
env dd_var then
2224 Some
(Env.get_local_pos
env dd_var)
2228 let env = Env.set_local
env dd_var ty1
Pos.none
in
2229 let (env, te2
, ty2
) = expr env e2 in
2231 match dd_old_ty with
2232 | None
-> Env.unset_local
env dd_var
2233 | Some
(ty, pos) -> Env.set_local
env dd_var ty pos
2235 make_result env p (Aast.Pipe
(e0
, te1
, te2
)) ty2
2237 let (env, te, ty) = raw_expr env e in
2238 let env = might_throw
env in
2239 let (env, tuop
, ty) = Typing_arithmetic.unop
p env uop
te ty in
2240 let env = Typing_reactivity.check_assignment
env tuop
in
2242 | Eif
(c, e1
, e2) -> eif
env ~
expected ?in_await
p c e1
e2
2243 | Class_const
((p, CI sid
), pstr
)
2244 when String.equal
(snd pstr
) "class" && Env.is_typedef
env (snd sid
) ->
2246 match Env.get_typedef
env (snd sid
) with
2247 | Some
{ td_tparams
= tparaml
; _
} ->
2248 (* Typedef type parameters cannot have constraints *)
2253 fun { tp_name
= (p, x
); _
} ->
2254 (* TODO(T69551141) handle type arguments for Tgeneric *)
2255 MakeType.generic
(Reason.Rwitness
p) x
2259 let tdef = mk
(Reason.Rwitness
p, Tapply
(sid
, params)) in
2261 mk
(Reason.Rwitness
p, Tapply
((p, SN.Classes.cTypename
), [tdef]))
2263 let (env, tparams
) =
2264 List.map_env
env tparaml
(fun env tp
->
2265 Env.fresh_type
env (fst tp
.tp_name
))
2269 (Phase.env_with_self
env) with
2270 substs
= Subst.make_locl tparaml tparams
;
2274 Phase.check_tparams_constraints ~
use_pos:p ~
ety_env env tparaml
2276 let (env, ty) = Phase.localize ~
ety_env env typename in
2277 make_result env p (Class_const
(((p, ty), CI sid
), pstr
)) ty
2279 (* Should not expect None as we've checked whether the sid is a typedef *)
2280 expr_error env (Reason.Rwitness
p) outer
2282 | Class_const
(cid, mid
) -> class_const
env p (cid, mid
)
2283 | Class_get
((cpos
, cid), CGstring mid
, in_parens
)
2284 when Env.FakeMembers.is_valid_static
env cid (snd mid
) ->
2285 let (env, local
) = Env.FakeMembers.make_static
env cid (snd mid
) p in
2286 let local = (p, Lvar
(p, local)) in
2287 let (env, _
, ty) = expr env local in
2288 let (env, _tal
, te, _
) =
2289 static_class_id ~check_constraints
:false cpos
env [] cid
2291 make_result env p (Aast.Class_get
(te, Aast.CGstring mid
, in_parens
)) ty
2292 | Class_get
((cpos
, cid), CGstring
((ppos
, _
) as mid
), in_parens
) ->
2293 let (env, _tal
, te, cty
) =
2294 static_class_id ~check_constraints
:false cpos
env [] cid
2296 let env = might_throw
env in
2297 let (env, (ty, _tal
)) =
2301 ~coerce_from_ty
:None
2307 let (env, ty) = Env.FakeMembers.check_static_invalid
env cid (snd mid
) ty in
2308 let env = Typing_local_ops.enforce_static_property_access ppos
env in
2309 make_result env p (Aast.Class_get
(te, Aast.CGstring mid
, in_parens
)) ty
2310 (* Fake member property access. For example:
2311 * if ($x->f !== null) { ...$x->f... }
2313 | Class_get
(_
, CGexpr _
, _
) ->
2314 failwith
"AST should not have any CGexprs after naming"
2315 | Obj_get
(e, (pid
, Id
(py
, y
)), nf
, in_parens
)
2316 when Env.FakeMembers.is_valid
env e y
->
2317 let env = might_throw
env in
2318 let (env, local) = Env.FakeMembers.make
env e y
p in
2319 let local = (p, Lvar
(p, local)) in
2320 let (env, _
, ty) = expr env local in
2321 let (env, t_lhs
, _
) = expr ~accept_using_var
:true env e in
2322 let t_rhs = Tast.make_typed_expr pid
ty (Aast.Id
(py
, y
)) in
2323 make_result env p (Aast.Obj_get
(t_lhs
, t_rhs, nf
, in_parens
)) ty
2324 (* Statically-known instance property access e.g. $x->f *)
2325 | Obj_get
(e1
, (pm
, Id m
), nullflavor
, in_parens
) ->
2327 match nullflavor
with
2328 | OG_nullthrows
-> None
2329 | OG_nullsafe
-> Some
p
2331 let (env, te1
, ty1
) = expr ~accept_using_var
:true env e1
in
2332 let env = might_throw
env in
2333 (* We typecheck Obj_get by checking whether it is a subtype of
2334 Thas_member(m, #1) where #1 is a fresh type variable. *)
2335 let (env, mem_ty
) = Env.fresh_type
env p in
2336 let r = Reason.Rwitness
(fst e1
) in
2342 ~class_id
:(CIexpr e1
)
2343 ~explicit_targs
:None
2345 let lty1 = LoclType ty1
in
2346 let (env, result_ty
) =
2360 (* In that case ty1 is a subtype of ?Thas_member(m, #1)
2361 and the result is ?#1 if ty1 is nullable. *)
2362 let r = Reason.Rnullsafe_op
p in
2363 let null_ty = MakeType.null
r in
2364 let (env, null_has_mem_ty
) =
2365 Union.union_i
env r has_member_ty null_ty
2376 let (env, null_or_nothing_ty
) = Inter.intersect
env ~
r null_ty ty1
in
2377 let (env, result_ty
) = Union.union env null_or_nothing_ty mem_ty
in
2380 let (env, result_ty
) =
2381 Env.FakeMembers.check_instance_invalid
env e1
(snd m
) result_ty
2388 Tast.make_typed_expr pm result_ty
(Aast.Id m
),
2392 (* Dynamic instance property access e.g. $x->$f *)
2393 | Obj_get
(e1
, e2, nullflavor
, in_parens
) ->
2394 let (env, te1
, ty1
) = expr ~accept_using_var
:true env e1
in
2395 let (env, te2
, _
) = expr env e2 in
2397 if TUtils.is_dynamic
env ty1
then
2398 MakeType.dynamic
(Reason.Rwitness
p)
2400 Typing_utils.mk_tany
env p
2402 let ((pos, _
), te2
) = te2
in
2403 let env = might_throw
env in
2404 let te2 = Tast.make_typed_expr
pos ty te2 in
2405 make_result env p (Aast.Obj_get
(te1
, te2, nullflavor
, in_parens
)) ty
2407 make_result env p Aast.Yield_break
(Typing_utils.mk_tany
env p)
2409 let (env, (taf
, opt_key
, value)) = array_field
env af
in
2410 let (env, send
) = Env.fresh_type
env p in
2412 match (af
, opt_key
) with
2413 | (AFvalue
(p, _
), None
) ->
2415 match Env.get_fn_kind
env with
2417 | Ast_defs.FAsync
->
2418 Errors.internal_error
p "yield found in non-generator";
2419 (env, Typing_utils.mk_tany
env p)
2420 | Ast_defs.FGenerator
-> (env, MakeType.int (Reason.Rwitness
p))
2421 | Ast_defs.FAsyncGenerator
->
2422 let (env, ty) = Env.fresh_type
env p in
2423 (env, MakeType.nullable_locl
(Reason.Ryield_asyncnull
p) ty)
2425 | (_
, Some x
) -> (env, x
)
2426 | (_
, _
) -> assert false
2429 match Env.get_fn_kind
env with
2430 | Ast_defs.FGenerator
->
2431 MakeType.generator
(Reason.Ryield_gen
p) key
value send
2432 | Ast_defs.FAsyncGenerator
->
2433 MakeType.async_generator
(Reason.Ryield_asyncgen
p) key
value send
2435 | Ast_defs.FAsync
->
2436 failwith
"Parsing should never allow this"
2438 let Typing_env_return_info.{ return_type = expected_return; _
} =
2442 Typing_coercion.coerce_type
2450 let env = Env.forget_members
env Reason.(Blame
(p, BScall
)) in
2451 let env = LEnv.save_and_merge_next_in_cont
env C.Exit
in
2456 (MakeType.nullable_locl
(Reason.Ryield_send
p) send
)
2458 let env = might_throw
env in
2459 (* Await is permitted in a using clause e.g. using (await make_handle()) *)
2460 let (env, te, rty) =
2461 expr ~is_using_clause ~in_await
:(Reason.Rwitness
p) env e
2463 let (env, ty) = Async.overload_extract_from_awaitable
env p rty in
2464 make_result env p (Aast.Await
te) ty
2465 | New
((pos, c), explicit_targs
, el
, unpacked_element
, p1) ->
2466 let env = might_throw
env in
2467 let (env, tc
, tal
, tel
, typed_unpack_element
, ty, ctor_fty
) =
2472 ~check_not_abstract
:true
2480 let env = Env.forget_members
env Reason.(Blame
(p, BScall
)) in
2484 (Aast.New
(tc
, tal
, tel
, typed_unpack_element
, (p1, ctor_fty
)))
2486 | Record
((pos, id), field_values
) ->
2487 (match Decl_provider.get_record_def
(Env.get_ctx
env) id with
2489 if rd
.rdt_abstract
then Errors.new_abstract_record
(pos, id);
2491 let field_name (pos, expr_
) =
2493 | Aast.String name
-> Some
(pos, name
)
2495 (* TODO T44306013: Ensure that other values for field names are banned. *)
2498 let fields_declared = Typing_helpers.all_record_fields
env rd
in
2499 let fields_present =
2500 List.map field_values ~f
:(fun (name
, _value
) -> field_name name
)
2503 (* Check for missing required fields. *)
2504 let fields_present_names =
2505 List.map ~f
:snd
fields_present |> SSet.of_list
2508 (fun field_name info
->
2509 let ((field_pos
, _
), req
) = info
in
2511 | Typing_defs.ValueRequired
2512 when not
(SSet.mem
field_name fields_present_names) ->
2513 Errors.missing_record_field_name
2517 ~field_decl_pos
:field_pos
2521 (* Check for unknown fields.*)
2522 List.iter
fields_present ~f
:(fun (pos, field_name) ->
2523 if not
(SMap.mem
field_name fields_declared) then
2524 Errors.unexpected_record_field_name
2528 ~decl_pos
:(fst rd
.rdt_name
))
2529 | None
-> Errors.type_not_record
id pos);
2531 expr_error env (Reason.Rwitness
p) outer
2533 let (env, te, ty2
) = expr ?in_await
env e in
2534 let env = might_throw
env in
2537 TypecheckerOptions.experimental_feature_enabled
2539 TypecheckerOptions.experimental_forbid_nullable_cast
2540 && not
(TUtils.is_mixed
env ty2
)
2542 SubType.sub_type_or_fail
2545 (MakeType.nonnull
(get_reason ty2
))
2547 Errors.nullable_cast
p (Typing_print.error
env ty2
) (get_pos ty2
))
2551 let (env, ty) = Phase.localize_hint_with_self
env hint
in
2552 make_result env p (Aast.Cast
(hint
, te)) ty
2553 | ExpressionTree et
-> expression_tree
{ env with in_expr_tree
= true } p et
2555 Typing_kinding.Simple.check_well_kinded_hint
env hint
;
2556 let (env, te, _
) = expr env e in
2557 make_result env p (Aast.Is
(te, hint
)) (MakeType.bool (Reason.Rwitness
p))
2558 | As
(e, hint
, is_nullable
) ->
2559 Typing_kinding.Simple.check_well_kinded_hint
env hint
;
2560 let refine_type env lpos lty
rty =
2561 let reason = Reason.Ras lpos
in
2562 let (env, rty) = Env.expand_type
env rty in
2563 let (env, rty) = class_for_refinement
env p reason lpos lty
rty in
2564 Inter.intersect
env reason lty
rty
2566 let (env, te, expr_ty
) = expr env e in
2567 let env = might_throw
env in
2569 { (Phase.env_with_self
env) with from_class
= Some CIstatic
}
2571 let (env, hint_ty
) = Phase.localize_hint ~
ety_env env hint
in
2572 let enable_sound_dynamic =
2573 TypecheckerOptions.enable_sound_dynamic env.genv
.tcopt
2575 let is_dyn = Typing_utils.is_dynamic
env hint_ty
in
2576 ( if enable_sound_dynamic && is_dyn then
2577 let (_
: env * locl_ty
) =
2579 ~allow_subtype_of_dynamic
:true
2587 let (env, hint_ty
) =
2588 if is_dyn && not
enable_sound_dynamic then
2590 if is_instance_var
e then
2591 let (env, ivar
) = get_instance_var
env e in
2592 set_local
env ivar hint_ty
2597 else if is_nullable
&& not
is_dyn then
2598 let (env, hint_ty
) = refine_type env (fst
e) expr_ty hint_ty
in
2599 (env, MakeType.nullable_locl
(Reason.Rwitness
p) hint_ty
)
2600 else if is_instance_var
e then
2601 let (env, _
, ivar_ty
) = raw_expr env e in
2602 let (env, ((ivar_pos
, _
) as ivar
)) = get_instance_var
env e in
2603 let (env, hint_ty
) = refine_type env ivar_pos ivar_ty hint_ty
in
2604 let env = set_local
env ivar hint_ty
in
2607 refine_type env (fst
e) expr_ty hint_ty
2609 make_result env p (Aast.As
(te, hint
, is_nullable
)) hint_ty
2618 (* Check type annotations on the lambda *)
2619 Typing_check_decls.fun_
env f
;
2620 (* Check attributes on the lambda *)
2622 attributes_check_def
env SN.AttributeKinds.lambda f
.f_user_attributes
2624 (* This is the function type as declared on the lambda itself.
2625 * If type hints are absent then use Tany instead. *)
2627 Decl_nast.fun_decl_in_env
env.decl_env ~is_lambda
:true f
2629 let { fe_type
; fe_pos
; _
} = declared_fe in
2630 let (declared_pos
, declared_ft
) =
2631 match get_node fe_type
with
2632 | Tfun
ft -> (fe_pos
, ft)
2633 | _
-> failwith
"Not a function"
2636 Typing_enforceability.compute_enforced_and_pessimize_fun_type
2640 (* When creating a closure, the 'this' type will mean the late bound type
2641 * of the current enclosing class
2644 { (Phase.env_with_self
env) with from_class
= Some CIstatic
}
2646 let (env, declared_ft) =
2650 { use_name
= "lambda"; use_pos = p; explicit_targs
= [] }
2652 ~
def_pos:declared_pos
2656 List.iter idl
(check_escaping_var
env);
2658 (* Ensure lambda arity is not ellipsis in strict mode *)
2660 match declared_ft.ft_arity
with
2661 | Fvariadic
{ fp_name
= None
; _
}
2662 when Partial.should_check_error
(Env.get_mode
env) 4223 ->
2663 Errors.ellipsis_strict_mode ~require
:`Param_name
p
2667 (* Is the return type declared? *)
2668 let is_explicit_ret = Option.is_some
(hint_of_type_hint f
.f_ret
) in
2670 Decl_fun_utils.fun_reactivity_opt
env.decl_env f
.f_user_attributes
2672 ~default
:(TR.strip_conditional_reactivity
(env_reactivity
env))
2674 let check_body_under_known_params env ?ret_ty
ft : env * _
* locl_ty
=
2675 let old_reactivity = env_reactivity
env in
2676 let env = Env.set_env_reactive
env reactivity in
2677 let ft = { ft with ft_reactive
= reactivity } in
2678 let (env, (tefun
, ty, ft)) = anon_make ?ret_ty
env p f
ft idl
is_anon in
2679 let env = Env.set_env_reactive
env old_reactivity in
2682 ( Reason.Rwitness
p,
2687 ( if is_explicit_ret then
2690 MakeType.unenforced
ty );
2693 (env, tefun
, inferred_ty)
2695 let (env, eexpected
) = expand_expected_and_get_node
env expected in
2696 (* TODO: move this into the expand_expected_and_get_node function and prune its callsites
2697 * Strip like type from function type hint *)
2699 match eexpected with
2700 | Some
(pos, ur, _
, Tunion
[ty1
; ty2
]) when is_dynamic ty1
&& is_fun ty2
2702 Some
(pos, ur, ty2
, get_node ty2
)
2706 match eexpected with
2707 | Some
(_pos
, _ur
, ty, Tfun expected_ft
) ->
2708 (* First check that arities match up *)
2709 check_lambda_arity
p (get_pos
ty) declared_ft expected_ft
;
2710 (* Use declared types for parameters in preference to those determined
2711 * by the context: they might be more general. *)
2712 let rec replace_non_declared_types
2713 params declared_ft_params expected_ft_params
=
2714 match (params, declared_ft_params
, expected_ft_params
) with
2715 | ( param
:: params,
2716 declared_ft_param
:: declared_ft_params
,
2717 expected_ft_param
:: expected_ft_params
) ->
2719 replace_non_declared_types
2724 let resolved_ft_param =
2725 if Option.is_some
(hint_of_type_hint param
.param_type_hint
) then
2728 { declared_ft_param
with fp_type
= expected_ft_param
.fp_type
}
2730 resolved_ft_param :: rest
2731 | (_
:: params, declared_ft_param
:: declared_ft_params
, []) ->
2733 replace_non_declared_types
2738 declared_ft_param
:: rest
2740 (* This means the expected_ft params list can have more parameters
2741 * than declared parameters in the lambda. For variadics, this is OK.
2745 let replace_non_declared_arity variadic declared_arity expected_arity
=
2747 | FVvariadicArg
{ param_type_hint
= (_
, Some _
); _
} -> declared_arity
2748 | FVvariadicArg _
->
2750 match (declared_arity
, expected_arity
) with
2751 | (Fvariadic declared
, Fvariadic
expected) ->
2752 Fvariadic
{ declared
with fp_type
= expected.fp_type
}
2753 | (_
, _
) -> declared_arity
2755 | _
-> declared_arity
2761 replace_non_declared_arity
2763 declared_ft.ft_arity
2764 expected_ft.ft_arity
;
2766 replace_non_declared_types
2768 declared_ft.ft_params
2769 expected_ft.ft_params
;
2770 ft_implicit_params
= declared_ft.ft_implicit_params
;
2773 (* Don't bother passing in `void` if there is no explicit return *)
2775 match get_node
expected_ft.ft_ret
.et_type
with
2776 | Tprim Tvoid
when not
is_explicit_ret -> None
2777 | _
-> Some
expected_ft.ft_ret
.et_type
2779 Typing_log.increment_feature_count
env FL.Lambda.contextual_params
;
2780 check_body_under_known_params env ?
ret_ty expected_ft
2782 let explicit_variadic_param_or_non_variadic =
2783 match f
.f_variadic
with
2784 | FVvariadicArg
{ param_type_hint
; _
} ->
2785 Option.is_some
(hint_of_type_hint param_type_hint
)
2786 | FVellipsis _
-> false
2789 (* If all parameters are annotated with explicit types, then type-check
2790 * the body under those assumptions and pick up the result type *)
2791 let all_explicit_params =
2792 List.for_all f
.f_params
(fun param
->
2793 Option.is_some
(hint_of_type_hint param
.param_type_hint
))
2795 if all_explicit_params && explicit_variadic_param_or_non_variadic then (
2796 Typing_log.increment_feature_count
2798 ( if List.is_empty f
.f_params
then
2801 FL.Lambda.explicit_params
);
2802 check_body_under_known_params env declared_ft
2805 | Some
ExpectedTy.{ ty = { et_type
; _
}; _
} when is_any et_type
->
2806 (* If the expected type is Tany env then we're passing a lambda to
2807 * an untyped function and we just assume every parameter has type
2809 * Note: we should be using 'nothing' to type the arguments. *)
2810 Typing_log.increment_feature_count
env FL.Lambda.untyped_context
;
2811 check_body_under_known_params env declared_ft
2813 (* If the expected type is something concrete but not a function
2814 * then we should reject in strict mode. Check body anyway.
2815 * Note: we should be using 'nothing' to type the arguments. *)
2816 if Partial.should_check_error
(Env.get_mode
env) 4224 then
2817 Errors.untyped_lambda_strict_mode
p;
2818 Typing_log.increment_feature_count
2820 FL.Lambda.non_function_typed_context
;
2821 check_body_under_known_params env declared_ft
2823 (* If we're in partial mode then type-check definition anyway,
2824 * so treating parameters without type hints as "untyped"
2826 if not
(Env.is_strict
env) then (
2827 Typing_log.increment_feature_count
2829 FL.Lambda.non_strict_unknown_params
;
2830 check_body_under_known_params env declared_ft
2832 Typing_log.increment_feature_count
2834 FL.Lambda.fresh_tyvar_params
;
2836 (* Replace uses of Tany that originated from "untyped" parameters or return type
2837 * with fresh type variables *)
2838 let freshen_ftype env ft =
2839 let freshen_ty env pos et
=
2840 match get_node et
.et_type
with
2842 let (env, ty) = Env.fresh_type
env pos in
2843 (env, { et
with et_type
= ty })
2844 | Tclass
(id, e, [ty])
2845 when String.equal
(snd
id) SN.Classes.cAwaitable
2847 let (env, t
) = Env.fresh_type
env pos in
2851 et_type
= mk
(get_reason et
.et_type
, Tclass
(id, e, [t
]));
2855 let freshen_untyped_param env ft_param
=
2856 let (env, fp_type
) =
2857 freshen_ty env ft_param
.fp_pos ft_param
.fp_type
2859 (env, { ft_param
with fp_type
})
2861 let (env, ft_params
) =
2862 List.map_env
env ft.ft_params
freshen_untyped_param
2864 let (env, ft_ret
) = freshen_ty env declared_pos
ft.ft_ret
in
2865 (env, { ft with ft_params
; ft_ret
})
2867 let (env, declared_ft) = freshen_ftype env declared_ft in
2869 Env.set_tyvar_variance
env (mk
(Reason.Rnone
, Tfun
declared_ft))
2871 (* TODO(jjwu): the declared_ft here is set to public,
2872 but is actually inferred from the surrounding context
2873 (don't think this matters in practice, since we check lambdas separately) *)
2874 check_body_under_known_params
2876 ~
ret_ty:declared_ft.ft_ret
.et_type
2881 | Xml
(sid
, attrl
, el
) ->
2883 let (env, _tal
, _te
, classes
) =
2884 class_id_for_new ~exact
:Nonexact
p env cid []
2886 (* OK to ignore rest of list; class_info only used for errors, and
2887 * cid = CI sid cannot produce a union of classes anyhow *)
2889 List.find_map classes ~f
:(function
2891 | `Class
(_
, class_info, _
) -> Some
class_info)
2893 let (env, _te
, obj
) =
2894 expr env (fst sid
, New
((fst sid
, cid), [], [], None
, fst sid
))
2896 let (env, typed_attrs
, attr_types
) =
2897 xhp_attribute_exprs
env class_info attrl
2900 List.map_env
env el ~f
:(fun env e ->
2901 let (env, te, _
) = expr env e in
2904 let txml = Aast.Xml
(sid
, typed_attrs
, List.rev tel
) in
2905 (match class_info with
2906 | None
-> make_result env p txml (mk
(Reason.Runknown_class
p, Tobject
))
2907 | Some
class_info ->
2914 let (namepstr
, valpty
) = attr
in
2915 let (valp
, valty
) = valpty
in
2916 let (env, (declty
, _tal
)) =
2921 ~coerce_from_ty
:None
2929 let ureason = Reason.URxhp
(Cls.name
class_info, snd namepstr
) in
2930 Typing_coercion.coerce_type
2935 (MakeType.unenforced declty
)
2936 Errors.xhp_attribute_does_not_match_hint
2940 make_result env p txml obj
)
2941 | Callconv
(kind
, e) ->
2942 let (env, te, ty) = expr env e in
2943 make_result env p (Aast.Callconv
(kind
, te)) ty
2945 let (env, fdm_with_expected
) =
2946 match expand_expected_and_get_node
env expected with
2947 | (env, Some
(pos, ur, _
, Tshape
(_
, expected_fdm
))) ->
2951 match ShapeMap.find_opt k expected_fdm
with
2952 | None
-> (k
, (v
, None
))
2953 | Some sft
-> (k
, (v
, Some
(ExpectedTy.make
pos ur sft
.sft_ty
))))
2957 | _
-> (env, List.map ~f
:(fun (k
, v
) -> (k
, (v
, None
))) fdm
)
2959 (* allow_inter adds a type-variable *)
2962 ~f
:(fun env (key
, (e, expected)) ->
2963 let (env, te, ty) = expr ?
expected env e in
2964 (env, (key
, (te, ty))))
2969 let convert_expr_and_type_to_shape_field_type env (key
, (_
, ty)) =
2970 (* An expression evaluation always corresponds to a shape_field_type
2971 with sft_optional = false. *)
2972 (env, (key
, { sft_optional
= false; sft_ty
= ty }))
2974 List.map_env ~f
:convert_expr_and_type_to_shape_field_type env tfdm
2978 ~f
:(fun acc
(k
, v
) -> ShapeMap.add k v acc
)
2979 ~init
:ShapeMap.empty
2982 let env = check_shape_keys_validity
env p (ShapeMap.keys
fdm) in
2983 (* Fields are fully known, because this shape is constructed
2984 * using shape keyword and we know exactly what fields are set. *)
2988 (Aast.Shape
(List.map ~f
:(fun (k
, (te, _
)) -> (k
, te)) tfdm
))
2989 (mk
(Reason.Rwitness
p, Tshape
(Closed_shape
, fdm)))
2990 | ET_Splice
e -> et_splice
{ env with in_expr_tree
= true } p e
2992 Errors.atom_as_expr
p;
2993 make_result env p (Aast.EnumAtom
s) (mk
(Reason.Rwitness
p, Terr
))
2995 (* let ty = err_witness env cst_pos in *)
2996 and class_const ?
(incl_tc
= false) env p ((cpos
, cid), mid
) =
2997 let (env, _tal
, ce
, cty
) =
2998 static_class_id ~check_constraints
:true cpos
env [] cid
3000 let (env, (const_ty
, _tal
)) =
3005 ~coerce_from_ty
:None
3011 make_result env p (Aast.Class_const
(ce
, mid
)) const_ty
3012 (*****************************************************************************)
3013 (* XHP attribute/body helpers. *)
3014 (*****************************************************************************)
3017 * Process a spread operator by computing the intersection of XHP attributes
3018 * between the spread expression and the XHP constructor onto which we're
3021 and xhp_spread_attribute
env c_onto valexpr
=
3022 let (p, _
) = valexpr
in
3023 let (env, te, valty
) = expr env valexpr
in
3024 (* Build the typed attribute node *)
3025 let typed_attr = Aast.Xhp_spread
te in
3026 let (env, attr_ptys
) =
3029 | Some
class_info -> Typing_xhp.get_spread_attributes
env p class_info valty
3031 (env, typed_attr, attr_ptys
)
3034 * Simple XHP attributes (attr={expr} form) are simply interpreted as a member
3035 * variable prefixed with a colon, the types of which will be validated later
3037 and xhp_simple_attribute
env id valexpr
=
3038 let (p, _
) = valexpr
in
3039 let (env, te, valty
) = expr env valexpr
in
3040 (* This converts the attribute name to a member name. *)
3041 let name = ":" ^ snd
id in
3042 let attr_pty = ((fst
id, name), (p, valty
)) in
3043 let typed_attr = Aast.Xhp_simple
(id, te) in
3044 (env, typed_attr, [attr_pty])
3047 * Typecheck the attribute expressions - this just checks that the expressions are
3048 * valid, not that they match the declared type for the attribute and,
3049 * in case of spreads, makes sure they are XHP.
3051 and xhp_attribute_exprs
env cid attrl
=
3052 let handle_attr (env, typed_attrl
, attr_ptyl
) attr
=
3053 let (env, typed_attr, attr_ptys
) =
3055 | Xhp_simple
(id, valexpr
) -> xhp_simple_attribute
env id valexpr
3056 | Xhp_spread valexpr
-> xhp_spread_attribute
env cid valexpr
3058 (env, typed_attr :: typed_attrl
, attr_ptys
@ attr_ptyl
)
3060 let (env, typed_attrl
, attr_ptyl
) =
3061 List.fold_left ~f
:handle_attr ~init
:(env, [], []) attrl
3063 (env, List.rev typed_attrl
, List.rev attr_ptyl
)
3065 (*****************************************************************************)
3066 (* Anonymous functions. *)
3067 (*****************************************************************************)
3068 and anon_bind_param
params (env, t_params
) ty : env * Tast.fun_param list
=
3071 (* This code cannot be executed normally, because the arity is wrong
3072 * and it will error later. Bind as many parameters as we can and carry
3075 | param
:: paraml
->
3077 (match hint_of_type_hint param
.param_type_hint
with
3079 let h = Decl_hint.hint
env.decl_env
h in
3080 (* When creating a closure, the 'this' type will mean the
3081 * late bound type of the current enclosing class
3084 { (Phase.env_with_self
env) with from_class
= Some CIstatic
}
3086 let (env, h) = Phase.localize ~
ety_env env h in
3087 let pos = get_pos
h in
3089 Typing_coercion.coerce_type
3094 (MakeType.unenforced
h)
3097 (* Closures are allowed to have explicit type-hints. When
3098 * that is the case we should check that the argument passed
3099 * is compatible with the type-hint.
3100 * The body of the function should be type-checked with the
3101 * hint and not the type of the argument passed.
3102 * Otherwise it leads to strange results where
3103 * foo(?string $x = null) is called with a string and fails to
3104 * type-check. If $x is a string instead of ?string, null is not
3105 * subtype of string ...
3107 let (env, t_param
) = bind_param env (h, param
) in
3108 (env, t_params
@ [t_param
])
3111 mk
(Reason.Rlambda_param
(param
.param_pos
, get_reason
ty), get_node
ty)
3113 let (env, t_param
) = bind_param env (ty, param
) in
3114 (env, t_params
@ [t_param
]))
3116 and anon_bind_variadic
env vparam variadic_ty
=
3117 let (env, ty, pos) =
3118 match hint_of_type_hint vparam
.param_type_hint
with
3120 (* if the hint is missing, use the type we expect *)
3121 (env, variadic_ty
, get_pos variadic_ty
)
3123 let h = Decl_hint.hint
env.decl_env hint
in
3125 { (Phase.env_with_self
env) with from_class
= Some CIstatic
}
3127 let (env, h) = Phase.localize ~
ety_env env h in
3128 let pos = get_pos
h in
3130 Typing_coercion.coerce_type
3135 (MakeType.unenforced
h)
3138 (env, h, vparam
.param_pos
)
3140 let r = Reason.Rvar_param
pos in
3141 let arr_values = mk
(r, get_node
ty) in
3142 let ty = MakeType.varray
r arr_values in
3143 let (env, t_variadic
) = bind_param env (ty, vparam
) in
3146 and anon_bind_opt_param
env param
: env =
3147 match param
.param_expr
with
3149 let ty = Typing_utils.mk_tany
env param
.param_pos
in
3150 let (env, _
) = bind_param env (ty, param
) in
3153 let (env, _te
, ty) = expr env default
in
3154 Typing_sequencing.sequence_check_expr default
;
3155 let (env, _
) = bind_param env (ty, param
) in
3158 and anon_check_param
env param
=
3159 match hint_of_type_hint param
.param_type_hint
with
3162 let (env, hty
) = Phase.localize_hint_with_self
env hty
in
3163 let paramty = Env.get_local
env (Local_id.make_unscoped param
.param_name
) in
3164 let hint_pos = get_pos hty
in
3166 Typing_coercion.coerce_type
3171 (MakeType.unenforced hty
)
3176 and stash_conts_for_anon
env p is_anon captured f
=
3178 if is_anon && TypecheckerOptions.any_coeffects
(Env.get_tcopt
env) then
3180 (Pos.none
, local_capability_id
) :: (Pos.none
, capability_id
) :: captured)
3185 if Env.is_local_defined
env this
then
3186 (Pos.none
, this
) :: captured
3191 Option.map (Env.next_cont_opt
env) ~f
:(fun next_cont
->
3192 let initial_locals =
3194 Env.get_locals
env captured
3196 next_cont
.Typing_per_cont_env.local_types
3199 Fake.forget
(Env.get_fake_members
env) Reason.(Blame
(p, BSlambda
))
3201 let tpenv = Env.get_tpenv
env in
3202 (initial_locals, initial_fakes, tpenv))
3204 Typing_lenv.stash_and_do
env (Env.all_continuations
env) (fun env ->
3208 | Some
(initial_locals, initial_fakes, tpenv) ->
3209 let env = Env.reinitialize_locals
env in
3210 let env = Env.set_locals
env initial_locals in
3211 let env = Env.set_fake_members
env initial_fakes in
3212 let env = Env.env_with_tpenv
env tpenv in
3217 (* Make a type-checking function for an anonymous function. *)
3218 (* Here ret_ty should include Awaitable wrapper *)
3219 (* TODO: ?el is never set; so we need to fix variadic use of lambda *)
3220 and anon_make ?el ?
ret_ty env lambda_pos f
ft idl
is_anon =
3221 let nb = Nast.assert_named_body f
.f_body
in
3222 Env.anon
env.lenv env (fun env ->
3223 (* Extract capabilities from AAST and add them to the environment *)
3224 let (env, capability
) =
3225 match (f
.f_ctxs
, f
.f_unsafe_ctxs
) with
3227 (* if the closure has no explicit coeffect annotations,
3228 do _not_ insert (unsafe) capabilities into the environment;
3229 instead, rely on the fact that a capability from an enclosing
3230 scope can simply be captured, which has the same semantics
3231 as redeclaring and shadowing with another same-typed capability.
3232 This avoid unnecessary overhead in the most common case, i.e.,
3233 when a closure does not need a different (usually smaller)
3234 set of capabilities. *)
3235 (env, Env.get_local
env Typing_coeffects.local_capability_id
)
3237 let (env, cap_ty
, unsafe_cap_ty
) =
3238 type_capability
env f
.f_ctxs f
.f_unsafe_ctxs
(fst f
.f_name
)
3240 Typing_coeffects.register_capabilities
env cap_ty unsafe_cap_ty
3243 { ft with ft_implicit_params
= { capability
= CapTy capability
} }
3245 stash_conts_for_anon
env lambda_pos
is_anon idl
(fun env ->
3246 let env = Env.clear_params
env in
3247 let make_variadic_arg env varg tyl
=
3248 let remaining_types =
3249 (* It's possible the variadic arg will capture the variadic
3250 * parameter of the supplied arity (if arity is Fvariadic)
3251 * and additional supplied params.
3253 * For example in cases such as:
3254 * lambda1 = (int $a, string...$c) ==> {};
3255 * lambda1(1, "hello", ...$y); (where $y is a variadic string)
3256 * lambda1(1, "hello", "world");
3257 * then ...$c will contain "hello" and everything in $y in the first
3258 * example, and "hello" and "world" in the second example.
3260 * To account for a mismatch in arity, we take the remaining supplied
3261 * parameters and return a list of all their types. We'll use this
3262 * to create a union type when creating the typed variadic arg.
3264 let remaining_params =
3265 List.drop
ft.ft_params
(List.length f
.f_params
)
3267 List.map ~f
:(fun param
-> param
.fp_type
.et_type
) remaining_params
3269 let r = Reason.Rvar_param varg
.param_pos
in
3270 let union = Tunion
(tyl
@ remaining_types) in
3271 let (env, t_param
) = anon_bind_variadic
env varg
(mk
(r, union)) in
3272 (env, Aast.FVvariadicArg t_param
)
3274 let (env, t_variadic
) =
3275 match (f
.f_variadic
, ft.ft_arity
) with
3276 | (FVvariadicArg arg
, Fvariadic variadic
) ->
3277 make_variadic_arg env arg
[variadic
.fp_type
.et_type
]
3278 | (FVvariadicArg arg
, Fstandard
) -> make_variadic_arg env arg
[]
3279 | (FVellipsis
pos, _
) -> (env, Aast.FVellipsis
pos)
3280 | (_
, _
) -> (env, Aast.FVnonVariadic
)
3282 let params = ref f
.f_params
in
3283 let (env, t_params
) =
3285 ~f
:(anon_bind_param
params)
3287 (List.map ft.ft_params
(fun x
-> x
.fp_type
.et_type
))
3289 let env = List.fold_left ~f
:anon_bind_opt_param ~
init:env !params in
3290 let env = List.fold_left ~f
:anon_check_param ~
init:env f
.f_params
in
3295 Unify.unify_param_modes
3301 match f
.f_variadic
with
3304 TUtils.default_fun_param
3306 (mk
(Reason.Rvar_param
pos, Typing_defs.make_tany
()))
3311 let rec iter l1 l2
=
3312 match (l1
, l2
, var_param) with
3314 | ([], _
, None
) -> ()
3315 | ([], x2
:: rl2
, Some def1
) ->
3316 param_modes ~is_variadic
:true def1 x2
;
3318 | (x1
:: rl1
, x2
:: rl2
, _
) ->
3322 iter ft.ft_params x
;
3323 wfold_left2 inout_write_back
env ft.ft_params x
3325 let env = Env.set_fn_kind
env f
.f_fun_kind
in
3328 ~f
:(Decl_hint.hint
env.decl_env
)
3329 (hint_of_type_hint f
.f_ret
)
3334 (* Do we have a contextual return type? *)
3338 let (env, ret_ty) = Env.fresh_type
env lambda_pos
in
3339 (env, Typing_return.wrap_awaitable
env lambda_pos
ret_ty)
3341 (* We might need to force it to be Awaitable if it is a type variable *)
3342 Typing_return.force_awaitable
env lambda_pos
ret_ty
3345 (* If a 'this' type appears it needs to be compatible with the
3349 { (Phase.env_with_self
env) with from_class
= Some CIstatic
}
3351 Typing_return.make_return_type
(Phase.localize ~
ety_env) env ret
3356 (Typing_return.make_info
3360 ~is_explicit
:(Option.is_some
ret_ty)
3364 let local_tpenv = Env.get_tpenv
env in
3365 (* Outer pipe variables aren't available in closures. Note that
3366 * locals are restored by Env.anon after processing the closure
3371 (Local_id.make_unscoped
SN.SpecialIdents.dollardollar
)
3373 let (env, tb) = block
env nb.fb_ast
in
3374 let implicit_return = LEnv.has_next
env in
3376 if (not
implicit_return) || Nast.named_body_is_unsafe
nb then
3379 fun_implicit_return
env lambda_pos hret f
.f_fun_kind
3381 let (env, tparams
) = List.map_env
env f
.f_tparams type_param
in
3382 let (env, user_attributes
) =
3383 List.map_env
env f
.f_user_attributes user_attribute
3387 Aast.f_annotation
= Env.save
local_tpenv env;
3388 Aast.f_span
= f
.f_span
;
3389 Aast.f_mode
= f
.f_mode
;
3390 Aast.f_ret
= (hret
, hint_of_type_hint f
.f_ret
);
3391 Aast.f_name
= f
.f_name
;
3392 Aast.f_tparams
= tparams
;
3393 Aast.f_where_constraints
= f
.f_where_constraints
;
3394 Aast.f_fun_kind
= f
.f_fun_kind
;
3395 Aast.f_file_attributes
= [];
3396 Aast.f_user_attributes
= user_attributes
;
3397 Aast.f_body
= { Aast.fb_ast
= tb; fb_annotation
= () };
3398 Aast.f_ctxs
= f
.f_ctxs
;
3399 Aast.f_unsafe_ctxs
= f
.f_unsafe_ctxs
;
3400 Aast.f_params
= t_params
;
3401 Aast.f_variadic
= t_variadic
;
3402 (* TODO TAST: Variadic efuns *)
3403 Aast.f_external
= f
.f_external
;
3404 Aast.f_namespace
= f
.f_namespace
;
3405 Aast.f_doc_comment
= f
.f_doc_comment
;
3406 Aast.f_static
= f
.f_static
;
3409 let ty = mk
(Reason.Rwitness lambda_pos
, Tfun
ft) in
3411 Tast.make_typed_expr
3415 Aast.Efun
(tfun_, idl
)
3417 Aast.Lfun
(tfun_, idl
) )
3419 let env = Env.set_tyvar_variance
env ty in
3420 (env, (te, hret
, ft))
3421 (* stash_conts_for_anon *))
3424 (*****************************************************************************)
3425 (* End of anonymous functions. *)
3426 (*****************************************************************************)
3428 (*****************************************************************************)
3429 (* Expression trees *)
3430 (*****************************************************************************)
3431 and expression_tree
env p et
=
3432 let (_
, t_src_expr
, _
) = expr_any env p et
.et_src_expr
in
3433 let (env, t_desugared_expr
, ty_desugared
) = expr env et
.et_desugared_expr
in
3437 (Aast.ExpressionTree
3439 et_hint
= et
.et_hint
;
3440 et_src_expr
= t_src_expr
;
3441 et_desugared_expr
= t_desugared_expr
;
3445 and et_splice
env p e =
3446 let (env, te, ty) = expr env e in
3447 let (env, ty_visitor
) = Env.fresh_type
env p in
3448 let (env, ty_res
) = Env.fresh_type
env p in
3449 let (env, ty_infer
) = Env.fresh_type
env p in
3450 let expr_tree_type =
3451 MakeType.expr_tree
(Reason.Rsplice
p) ty_visitor ty_res ty_infer
3453 let env = SubType.sub_type
env ty expr_tree_type Errors.unify_error
in
3454 make_result env p (Aast.ET_Splice
te) ty_infer
3456 (*****************************************************************************)
3457 (* End expression trees *)
3458 (*****************************************************************************)
3459 and type_capability
env ctxs unsafe_ctxs default_pos
=
3460 let cc = Decl_hint.aast_contexts_to_decl_capability
in
3462 match cc env.decl_env ctxs default_pos
with
3463 | CapTy
ty -> Phase.localize_with_self
env ty
3464 | CapDefaults _p
-> (env, MakeType.default_capability
)
3466 let (env, unsafe_cap_ty
) =
3467 match cc env.decl_env unsafe_ctxs default_pos
with
3468 | CapTy
ty -> Phase.localize_with_self
env ty
3470 (* default is no unsafe capabilities *)
3471 (env, MakeType.mixed (Reason.Rhint
p))
3473 (env, cap_ty
, unsafe_cap_ty
)
3475 and requires_consistent_construct
= function
3482 (* Caller will be looking for a particular form of expected type
3483 * e.g. a function type (when checking lambdas) or tuple type (when checking
3484 * tuples). First expand the expected type and elide single union; also
3485 * strip nullables, so ?t becomes t, as context will always accept a t if a ?t
3488 and expand_expected_and_get_node
env (expected : ExpectedTy.t
option) =
3490 | None
-> (env, None
)
3491 | Some
ExpectedTy.{ pos = p; reason = ur; ty = { et_type
= ty; _
}; _
} ->
3492 let (env, ty) = Env.expand_type
env ty in
3493 (match get_node
ty with
3494 | Tunion
[ty] -> (env, Some
(p, ur, ty, get_node
ty))
3495 | Toption
ty -> (env, Some
(p, ur, ty, get_node
ty))
3496 | _
-> (env, Some
(p, ur, ty, get_node
ty)))
3498 (** Do a subtype check of inferred type against expected type *)
3499 and check_expected_ty message
env inferred_ty (expected : ExpectedTy.t
option) =
3502 | Some
ExpectedTy.{ pos = p; reason = ur; ty } ->
3504 log_with_level
env "typing" 1 (fun () ->
3511 "Typing.check_expected_ty %s enforced=%b"
3515 Log_type
("inferred_ty", inferred_ty);
3516 Log_type
("expected_ty", ty.et_type
);
3519 Typing_coercion.coerce_type
p ur env inferred_ty ty Errors.unify_error
3522 ~
(expected : ExpectedTy.t
option)
3532 (* Obtain class info from the cid expression. We get multiple
3533 * results with a CIexpr that has a union type, e.g. in
3535 $classname = (mycond()? classname<A>: classname<B>);
3538 let (env, tal
, tcid
, classes
) =
3539 instantiable_cid ~exact
:Exact
p env cid explicit_targs
3541 let allow_abstract_bound_generic =
3543 | ((_
, ty), Aast.CI
(_
, tn
)) -> is_generic_equal_to tn
ty
3546 let gather (env, _tel
, _typed_unpack_element
) (cname
, class_info, c_ty
) =
3549 && Cls.abstract
class_info
3550 && (not
(requires_consistent_construct
cid))
3551 && not
allow_abstract_bound_generic
3553 uninstantiable_error
3557 (Cls.pos class_info)
3558 (Cls.name class_info)
3561 let (env, obj_ty_
, params) =
3562 let (env, c_ty
) = Env.expand_type
env c_ty
in
3563 match (cid, tal
, get_class_type c_ty
) with
3564 (* Explicit type arguments *)
3565 | (CI _
, _
:: _
, Some
(_
, _
, tyl
)) -> (env, get_node c_ty
, tyl
)
3566 | (_
, _
, class_type_opt
) ->
3568 List.map_env
env (Cls.tparams
class_info) (fun env tparam ->
3570 Env.fresh_type_reason
3572 (Reason.Rtype_variable_generics
3573 (p, snd
tparam.tp_name
, strip_ns
(snd cname
)))
3575 Typing_log.log_new_tvar_for_new_object
env p tvar cname
tparam;
3579 match class_type_opt
with
3580 | Some
(_
, Exact
, _
) -> (env, Tclass
(cname
, Exact
, params), params)
3581 | _
-> (env, Tclass
(cname
, Nonexact
, params), params)
3586 && (not is_using_clause
)
3587 && Cls.is_disposable
class_info
3589 Errors.invalid_new_disposable
p;
3590 let r_witness = Reason.Rwitness
p in
3591 let obj_ty = mk
(r_witness, obj_ty_
) in
3596 mk
(r_witness, get_node
c_ty)
3600 let ((_
, cid_ty
), _
) = tcid
in
3601 let (env, cid_ty
) = Env.expand_type
env cid_ty
in
3602 if is_generic cid_ty
then
3604 else if check_parent
then
3607 ExprDepTy.make
env cid c_ty
3609 (* Set variance according to type of `new` expression now. Lambda arguments
3610 * to the constructor might depend on it, and `call_construct` only uses
3611 * `ctor_fty` to set the variance which has void return type *)
3612 let env = Env.set_tyvar_variance
env new_ty
in
3613 let (env, tel
, typed_unpack_element
, ctor_fty
) =
3614 let env = check_expected_ty
"New" env new_ty
expected in
3615 call_construct
p env class_info params el unpacked_element
cid new_ty
3617 ( if equal_consistent_kind
(snd
(Cls.construct
class_info)) Inconsistent
then
3619 | CIstatic
-> Errors.new_inconsistent_construct
p cname `static
3620 | CIexpr _
-> Errors.new_inconsistent_construct
p cname `
classname
3624 let (env, ctor_fty
) =
3625 match fst
(Cls.construct
class_info) with
3626 | Some
({ ce_type
= (lazy ty); _
} as ce
) ->
3629 type_expansions
= [];
3631 TUtils.make_locl_subst_for_class_tparams
class_info params;
3635 on_error
= Errors.unify_error_at
p;
3638 if get_ce_abstract ce
then
3639 Errors.parent_abstract_call
3640 SN.Members.__construct
3643 let (env, ctor_fty
) = Phase.localize ~
ety_env env ty in
3645 | None
-> (env, ctor_fty
)
3647 ((env, tel
, typed_unpack_element
), (obj_ty, ctor_fty
))
3651 ((env, tel
, typed_unpack_element
), (c_ty, ctor_fty
))
3653 (* When constructing from a (classname) variable, the variable
3654 * dictates what the constructed object is going to be. This allows
3655 * for generic and dependent types to be correctly carried
3656 * through the 'new $foo()' iff the constructed obj_ty is a
3657 * supertype of the variable-dictated c_ty *)
3659 Typing_ops.sub_type
p Reason.URnone
env c_ty obj_ty Errors.unify_error
3661 ((env, tel
, typed_unpack_element
), (c_ty, ctor_fty
))
3663 let (had_dynamic
, classes
) =
3664 List.fold classes ~
init:(false, []) ~f
:(fun (seen_dynamic
, classes
) ->
3666 | `Dynamic
-> (true, classes
)
3667 | `Class
(cname
, class_info, c_ty) ->
3668 (seen_dynamic
, (cname
, class_info, c_ty) :: classes
))
3670 let ((env, tel
, typed_unpack_element
), class_types_and_ctor_types
) =
3671 List.fold_map classes ~
init:(env, [], None
) ~f
:gather
3673 let class_types_and_ctor_types =
3674 let r = Reason.Rdynamic_construct
p in
3675 let dyn = (mk
(r, Tdynamic
), mk
(r, Tdynamic
)) in
3677 dyn :: class_types_and_ctor_types
3679 class_types_and_ctor_types
3681 let (env, tel
, typed_unpack_element
, ty, ctor_fty
) =
3682 match class_types_and_ctor_types with
3684 let (env, tel
, _
) = exprs env el
in
3685 let (env, typed_unpack_element
, _
) =
3686 match unpacked_element
with
3687 | None
-> (env, None
, MakeType.nothing
Reason.Rnone
)
3688 | Some unpacked_element
->
3689 let (env, e, ty) = expr env unpacked_element
in
3692 let r = Reason.Runknown_class
p in
3693 (env, tel
, typed_unpack_element
, mk
(r, Tobject
), TUtils.terr
env r)
3694 | [(ty, ctor_fty
)] -> (env, tel
, typed_unpack_element
, ty, ctor_fty
)
3696 let (tyl
, ctyl
) = List.unzip l
in
3697 let r = Reason.Rwitness
p in
3698 (env, tel
, typed_unpack_element
, mk
(r, Tunion tyl
), mk
(r, Tunion ctyl
))
3701 let ((_
, cid_ty
), _
) = tcid
in
3702 let (env, cid_ty
) = Env.expand_type
env cid_ty
in
3703 if is_generic cid_ty
then
3705 else if check_parent
then
3708 ExprDepTy.make
env cid ty
3710 (env, tcid
, tal
, tel
, typed_unpack_element
, new_ty
, ctor_fty
)
3712 and attributes_check_def
env kind attrs
=
3713 (* TODO(coeffects) change to mixed after changing those constructors to pure *)
3714 let defaults = MakeType.default_capability
in
3716 Typing_lenv.stash_and_do
env (Env.all_continuations
env) (fun env ->
3718 fst
@@ Typing_coeffects.register_capabilities
env defaults defaults
3720 (Typing_attributes.check_def
env new_object kind attrs
, ()))
3724 (** Get class infos for a class expression (e.g. `parent`, `self` or
3725 regular classnames) - which might resolve to a union or intersection
3726 of classes - and check they are instantiable.
3728 FIXME: we need to separate our instantiability into two parts. Currently,
3729 all this function is doing is checking if a given type is inhabited --
3730 that is, whether there are runtime values of type Aast. However,
3731 instantiability should be the stricter notion that T has a runtime
3732 constructor; that is, `new T()` should be valid. In particular, interfaces
3733 are inhabited, but not instantiable.
3734 To make this work with classname, we likely need to add something like
3735 concrete_classname<T>, where T cannot be an interface. *)
3736 and instantiable_cid ?
(exact
= Nonexact
) p env cid explicit_targs
:
3737 newable_class_info
=
3738 let (env, tal
, te, classes
) =
3739 class_id_for_new ~exact
p env cid explicit_targs
3741 List.iter classes
(function
3743 | `Class
((pos, name), class_info, c_ty) ->
3745 Ast_defs.(equal_class_kind
(Cls.kind
class_info) Ctrait
)
3746 || Ast_defs.(equal_class_kind
(Cls.kind
class_info) Cenum
)
3751 uninstantiable_error
env p cid (Cls.pos class_info) name pos c_ty
3757 Ast_defs.(equal_class_kind
(Cls.kind
class_info) Cabstract
)
3758 && Cls.final
class_info
3760 uninstantiable_error
env p cid (Cls.pos class_info) name pos c_ty
3763 (env, tal
, te, classes
)
3765 and uninstantiable_error
env reason_pos
cid c_tc_pos c_name c_usage_pos
c_ty =
3769 let ty_str = "This would be " ^
Typing_print.error
env c_ty in
3770 [(reason_pos
, ty_str)]
3773 Errors.uninstantiable_class c_usage_pos c_tc_pos c_name
reason_msgl
3775 and coerce_to_throwable
pos env exn_ty
=
3776 let throwable_ty = MakeType.throwable
(Reason.Rthrow
pos) in
3777 Typing_coercion.coerce_type
3782 { et_type
= throwable_ty; et_enforced
= false }
3785 and shape_field_pos
= function
3786 | Ast_defs.SFlit_int
(p, _
)
3787 | Ast_defs.SFlit_str
(p, _
) ->
3789 | Ast_defs.SFclass_const
((cls_pos
, _
), (mem_pos
, _
)) ->
3790 Pos.btw cls_pos mem_pos
3792 and check_shape_keys_validity
env pos keys
=
3793 (* If the key is a class constant, get its class name and type. *)
3794 let get_field_info env key
=
3795 let key_pos = shape_field_pos key
in
3796 (* Empty strings or literals that start with numbers are not
3797 permitted as shape field names. *)
3799 | Ast_defs.SFlit_int _
-> (env, key_pos, None
)
3800 | Ast_defs.SFlit_str
(_
, key_name
) ->
3801 if Int.equal
0 (String.length key_name
) then
3802 Errors.invalid_shape_field_name_empty
key_pos;
3803 (env, key_pos, None
)
3804 | Ast_defs.SFclass_const
(((p, cls
) as x
), y
) ->
3805 let (env, _te
, ty) = class_const
env pos ((p, CI x
), y
) in
3806 let r = Reason.Rwitness
key_pos in
3813 (MakeType.arraykey r)
3815 Errors.invalid_shape_field_type
3818 (Typing_print.error
env ty)
3821 (env, key_pos, Some
(cls
, ty))
3823 let check_field witness_pos witness_info
env key
=
3824 let (env, key_pos, key_info
) = get_field_info env key
in
3825 match (witness_info
, key_info
) with
3827 Errors.invalid_shape_field_literal
key_pos witness_pos
;
3830 Errors.invalid_shape_field_const
key_pos witness_pos
;
3832 | (None
, None
) -> env
3833 | (Some
(cls1
, ty1
), Some
(cls2
, ty2
)) ->
3834 if String.( <> ) cls1 cls2
then
3835 Errors.shape_field_class_mismatch
3842 ( Typing_solver.is_sub_type
env ty1 ty2
3843 && Typing_solver.is_sub_type
env ty2 ty1
)
3845 Errors.shape_field_type_mismatch
3848 (Typing_print.error
env ty2
)
3849 (Typing_print.error
env ty1
);
3852 (* Sort the keys by their positions since the error messages will make
3853 * more sense if we take the one that appears first as canonical and if
3854 * they are processed in source order. *)
3855 let cmp_keys x y
= Pos.compare
(shape_field_pos x
) (shape_field_pos y
) in
3856 let keys = List.sort ~compare
:cmp_keys keys in
3859 | witness
:: rest_keys
->
3860 let (env, pos, info
) = get_field_info env witness
in
3861 List.fold_left ~f
:(check_field pos info
) ~
init:env rest_keys
3863 and set_valid_rvalue
p env x
ty =
3864 let env = set_local
env (p, x
) ty in
3865 (* We are assigning a new value to the local variable, so we need to
3866 * generate a new expression id
3868 Env.set_local_expr_id
env x
(Ident.tmp
())
3870 (* Produce an error if assignment is used in the scope of the |> operator, i.e.
3871 * if $$ is in scope *)
3872 and error_if_assign_in_pipe
p env =
3873 let dd_var = Local_id.make_unscoped
SN.SpecialIdents.dollardollar
in
3874 let dd_defined = Env.is_local_defined
env dd_var in
3876 Errors.unimplemented_feature
p "Assignment within pipe expressions"
3878 (* Deal with assignment of a value of type ty2 to lvalue e1 *)
3879 and assign
p env e1 ty2
: _
* Tast.expr * Tast.ty =
3880 error_if_assign_in_pipe
p env;
3881 assign_
p Reason.URassign
env e1 ty2
3883 and is_hack_collection
env ty =
3884 Typing_solver.is_sub_type
3887 (MakeType.const_collection
Reason.Rnone
(MakeType.mixed Reason.Rnone
))
3889 and assign_
p ur env e1 ty2
=
3892 | (_
, Lvar
(_
, x
)) ->
3893 Env.forget_prefixed_members
env x
Reason.(Blame
(p, BSassignment
))
3894 (* If we ever extend fake members from $x->a to more complicated lvalues
3895 such as $x->a->b, we would need to call forget_prefixed_members on
3896 other lvalues as well. *)
3897 | (_
, Obj_get
(_
, (_
, Id
(_
, property
)), _
, _
)) ->
3898 Env.forget_suffixed_members
env property
Reason.(Blame
(p, BSassignment
))
3902 | (_
, Lvar
((_
, x
) as id)) ->
3903 let env = set_valid_rvalue
p env x ty2
in
3904 make_result env (fst e1
) (Aast.Lvar
id) ty2
3905 | (_
, Lplaceholder
id) ->
3906 let placeholder_ty = MakeType.void
(Reason.Rplaceholder
p) in
3907 make_result env (fst e1
) (Aast.Lplaceholder
id) placeholder_ty
3910 List.map_env
env el ~f
:(fun env _
-> Env.fresh_type
env (get_pos ty2
))
3912 let destructure_ty =
3913 MakeType.list_destructure
(Reason.Rdestructure
(fst e1
)) tyl
3915 let lty2 = LoclType ty2
in
3916 let env = Type.sub_type_i
p ur env lty2 destructure_ty Errors.unify_error
in
3917 let env = Env.set_tyvar_variance_i
env destructure_ty in
3918 let (env, reversed_tel
) =
3919 List.fold2_exn el tyl ~
init:(env, []) ~f
:(fun (env, tel
) lvalue ty2
->
3920 let (env, te, _
) = assign
p env lvalue ty2
in
3923 make_result env (fst e1
) (Aast.List
(List.rev reversed_tel
)) ty2
3925 Obj_get
(obj
, (pm
, Id
((_
, member_name
) as m
)), nullflavor
, in_parens
) )
3927 let lenv = env.lenv in
3929 match nullflavor
with
3930 | OG_nullthrows
-> None
3931 | OG_nullsafe
-> Some
(Reason.Rnullsafe_op pobj
)
3933 let (env, tobj
, obj_ty) = expr ~accept_using_var
:true env obj
in
3934 let env = might_throw
env in
3935 let (env, (result
, _tal
)) =
3940 ~coerce_from_ty
:(Some
(p, ur, ty2
))
3949 Tast.make_typed_expr
3954 Tast.make_typed_expr pm result
(Aast.Id m
),
3958 let env = { env with lenv } in
3962 let (env, local) = Env.FakeMembers.make
env obj member_name
p in
3963 let env = set_valid_rvalue
p env local ty2
in
3966 let (env, local) = Env.FakeMembers.make
env obj member_name
p in
3967 let env = set_valid_rvalue
p env local ty2
in
3969 | _
-> (env, te1, ty2
)
3972 let lenv = env.lenv in
3973 let no_fakes = LEnv.env_with_empty_fakes
env in
3974 let (env, te1, real_type
) = lvalue
no_fakes e1
in
3975 let (env, exp_real_type
) = Env.expand_type
env real_type
in
3976 let env = { env with lenv } in
3978 Typing_coercion.coerce_type
3983 (MakeType.unenforced exp_real_type
)
3987 | (_
, Class_get
(_
, CGexpr _
, _
)) ->
3988 failwith
"AST should not have any CGexprs after naming"
3989 | (_
, Class_get
((pos_classid
, x
), CGstring
(pos_member
, y
), _
)) ->
3990 let lenv = env.lenv in
3991 let no_fakes = LEnv.env_with_empty_fakes
env in
3992 let (env, te1, _
) = lvalue
no_fakes e1
in
3993 let env = { env with lenv } in
3994 let (env, ety2
) = Env.expand_type
env ty2
in
3995 (* This defers the coercion check to class_get, which looks up the appropriate target type *)
3996 let (env, _tal
, _
, cty
) =
3997 static_class_id ~check_constraints
:false pos_classid
env [] x
3999 let env = might_throw
env in
4004 ~coerce_from_ty
:(Some
(p, ur, ety2
))
4010 let (env, local) = Env.FakeMembers.make_static
env x y
p in
4011 let env = set_valid_rvalue
p env local ty2
in
4013 | (pos, Array_get
(e1
, None
)) ->
4014 let (env, te1, ty1
) = update_array_type
pos env e1 `lvalue
in
4016 Typing_array_access.assign_array_append
4025 if is_hack_collection
env ty1
then
4028 let (env, te1, _
) = assign_
p ur env e1 ty1'
in
4031 make_result env pos (Aast.Array_get
(te1, None
)) ty2
4032 | (pos, Array_get
(e1
, Some
e)) ->
4033 let (env, te1, ty1
) = update_array_type
pos env e1 `lvalue
in
4034 let (env, te, ty) = expr env e in
4036 Typing_array_access.assign_array_get
4047 if is_hack_collection
env ty1
then
4050 let (env, te1, _
) = assign_
p ur env e1 ty1'
in
4053 (env, ((pos, ty2
), Aast.Array_get
(te1, Some
te)), ty2
)
4054 | _
-> assign_simple
p ur env e1 ty2
4056 and assign_simple
pos ur env e1 ty2
=
4057 let (env, te1, ty1
) = lvalue
env e1
in
4059 Typing_coercion.coerce_type
4064 (MakeType.unenforced ty1
)
4069 and array_field
env = function
4071 let (env, tve
, tv
) = expr env ve
in
4072 (env, (Aast.AFvalue tve
, None
, tv
))
4073 | AFkvalue
(ke
, ve
) ->
4074 let (env, tke
, tk) = expr env ke
in
4075 let (env, tve
, tv
) = expr env ve
in
4076 (env, (Aast.AFkvalue
(tke
, tve
), Some
tk, tv
))
4078 and array_value ~
(expected : ExpectedTy.t
option) env x
=
4079 let (env, te, ty) = expr ?
expected env x
in
4083 p class_name ~
(expected : ExpectedTy.t
option) env ((pos, _
) as x
) =
4084 let (env, (te, ty)) = array_value ~
expected env x
in
4085 let ty_arraykey = MakeType.arraykey (Reason.Ridx_dict
pos) in
4087 Typing_coercion.coerce_type
4089 (Reason.index_class
class_name)
4092 { et_type
= ty_arraykey; et_enforced
= true }
4097 and check_parent_construct
pos env el unpacked_element env_parent
=
4098 let check_not_abstract = false in
4099 let (env, env_parent
) = Phase.localize_with_self
env env_parent
in
4100 let (env, _tcid
, _tal
, tel
, typed_unpack_element
, parent
, fty) =
4105 ~is_using_clause
:false
4113 (* Not sure why we need to equate these types *)
4115 Type.sub_type
pos Reason.URnone
env env_parent parent
Errors.unify_error
4118 Type.sub_type
pos Reason.URnone
env parent env_parent
Errors.unify_error
4122 typed_unpack_element
,
4123 MakeType.void
(Reason.Rwitness
pos),
4127 and check_class_get
env p def_pos cid mid ce
e function_pointer
=
4129 | CIself
when get_ce_abstract ce
->
4131 match get_class_type
(Env.get_self
env) with
4132 | Some
((_
, self
), _
, _
) ->
4133 (* at runtime, self:: in a trait is a call to whatever
4134 * self:: is in the context of the non-trait "use"-ing
4135 * the trait's code *)
4137 match Env.get_class
env self
with
4138 | Some cls
when Ast_defs.(equal_class_kind
(Cls.kind cls
) Ctrait
) ->
4139 (* Ban self::some_abstract_method() in a trait, if the
4140 * method is also defined in a trait.
4142 * Abstract methods from interfaces are fine: we'll check
4143 * in the child class that we actually have an
4144 * implementation. *)
4145 (match Decl_provider.get_class
(Env.get_ctx
env) ce
.ce_origin
with
4147 when Ast_defs.(equal_class_kind
(Cls.kind meth_cls
) Ctrait
) ->
4148 Errors.self_abstract_call mid
p def_pos
4151 (* Ban self::some_abstract_method() in a class. This will
4153 Errors.self_abstract_call mid
p def_pos
4157 | CIparent
when get_ce_abstract ce
->
4158 Errors.parent_abstract_call mid
p def_pos
4159 | CI _
when get_ce_abstract ce
&& function_pointer
->
4160 Errors.abstract_function_pointer
cid mid
p def_pos
4161 | CI _
when get_ce_abstract ce
->
4162 Errors.classname_abstract_call
cid mid
p def_pos
4163 | CI
(_
, classname) when get_ce_synthesized ce
->
4164 Errors.static_synthetic_method
classname mid
p def_pos
4167 and call_parent_construct
pos env el unpacked_element
=
4168 match Env.get_parent_ty
env with
4169 | Some parent
-> check_parent_construct
pos env el unpacked_element parent
4172 let ty = Typing_utils.mk_tany
env pos in
4173 let default = (env, [], None
, ty, ty, ty) in
4174 (match get_class_type
(Env.get_self
env) with
4175 | Some
((_
, self
), _
, _
) ->
4176 (match Env.get_class
env self
with
4177 | Some trait
when Ast_defs.(equal_class_kind
(Cls.kind trait
) Ctrait
) ->
4178 (match trait_most_concrete_req_class trait
env with
4180 Errors.parent_in_trait
pos;
4182 | Some
(_
, parent_ty
) ->
4183 check_parent_construct
pos env el unpacked_element parent_ty
)
4185 if not
(Cls.members_fully_known self_tc
) then
4187 (* Don't know the hierarchy, assume it's correct *)
4189 Errors.undefined_parent
pos;
4191 | None
-> assert false)
4193 Errors.parent_outside_class
pos;
4194 let ty = err_witness env pos in
4195 (env, [], None
, ty, ty, ty))
4197 (* Depending on the kind of expression we are dealing with
4198 * The typing of call is different.
4201 ~
(expected : ExpectedTy.t
option)
4206 ((fpos
, fun_expr
) as e)
4210 let make_call env te tal tel typed_unpack_element
ty =
4211 make_result env p (Aast.Call
(te, tal
, tel
, typed_unpack_element
)) ty
4213 (* TODO: Avoid Tany annotations in TAST by eliminating `make_call_special` *)
4214 let make_call_special env id tel
ty =
4217 (Tast.make_typed_expr fpos
(TUtils.mk_tany
env fpos
) (Aast.Id
id))
4223 (* For special functions and pseudofunctions with a definition in hhi. *)
4224 let make_call_special_from_def env id tel ty_
=
4225 let (env, fty, tal
) = fun_type_of_id
env id explicit_targs el
in
4227 match get_node
fty with
4228 | Tfun
ft -> ft.ft_ret
.et_type
4229 | _
-> ty_
(Reason.Rwitness
p)
4231 make_call env (Tast.make_typed_expr fpos
fty (Aast.Id
id)) tal tel None
ty
4233 let overload_function = overload_function make_call fpos
in
4234 let check_disposable_in_return env fty =
4235 if is_return_disposable_fun_type env fty && not is_using_clause
then
4236 Errors.invalid_new_disposable
p
4239 (* Special function `echo` *)
4240 | Id
((p, pseudo_func
) as id)
4241 when String.equal pseudo_func
SN.SpecialFunctions.echo
->
4242 let (env, tel
, _
) = exprs ~accept_using_var
:true env el
in
4243 make_call_special env id tel
(MakeType.void
(Reason.Rwitness
p))
4244 (* Special function `isset` *)
4245 | Id
((_
, pseudo_func
) as id)
4246 when String.equal pseudo_func
SN.PseudoFunctions.isset
->
4248 exprs ~accept_using_var
:true ~check_defined
:false env el
4250 if Option.is_some unpacked_element
then
4251 Errors.unpacking_disallowed_builtin_function
p pseudo_func
;
4252 make_call_special_from_def env id tel
MakeType.bool
4253 (* Special function `unset` *)
4254 | Id
((_
, pseudo_func
) as id)
4255 when String.equal pseudo_func
SN.PseudoFunctions.unset
->
4256 let (env, tel
, _
) = exprs env el
in
4257 let env = Typing_reactivity.check_unset_target
env tel
in
4258 if Option.is_some unpacked_element
then
4259 Errors.unpacking_disallowed_builtin_function
p pseudo_func
;
4260 let checked_unset_error =
4261 if Partial.should_check_error
(Env.get_mode
env) 4135 then
4262 Errors.unset_nonidx_in_strict
4268 match (el
, unpacked_element
) with
4269 | ([(_
, Array_get
((_
, Class_const _
), Some _
))], None
)
4270 when Partial.should_check_error
(Env.get_mode
env) 4011 ->
4271 Errors.const_mutation
p Pos.none
"";
4273 | ([(_
, Array_get
(ea
, Some _
))], None
) ->
4274 let (env, _te
, ty) = expr env ea
in
4275 let r = Reason.Rwitness
p in
4276 let tmixed = MakeType.mixed r in
4283 MakeType.dict
r tmixed tmixed;
4284 MakeType.keyset
r tmixed;
4285 MakeType.darray
r tmixed tmixed;
4288 SubType.sub_type_or_fail
env ty super (fun () ->
4292 ("This is " ^
Typing_print.error ~ignore_dynamic
:true env ty)
4295 checked_unset_error p [];
4299 | [(p, Obj_get
(_
, _
, OG_nullsafe
, _
))] ->
4300 Errors.nullsafe_property_write_context
p;
4301 make_call_special_from_def env id tel
(TUtils.terr
env)
4302 | _
-> make_call_special_from_def env id tel
MakeType.void
)
4303 (* Special function `array_filter` *)
4304 | Id
((_
, array_filter
) as id)
4305 when String.equal array_filter
SN.StdlibFunctions.array_filter
4306 && (not
(List.is_empty el
))
4307 && Option.is_none unpacked_element
->
4308 (* dispatch the call to typecheck the arguments *)
4309 let (env, fty, tal
) = fun_type_of_id
env id explicit_targs el
in
4310 let (env, (tel
, typed_unpack_element
, res
)) =
4311 call ~
expected p env fty el unpacked_element
4313 (* but ignore the result and overwrite it with custom return type *)
4314 let x = List.hd_exn el
in
4315 let (env, _tx
, ty) = expr env x in
4316 let explain_array_filter ty =
4317 map_reason
ty ~f
:(fun r -> Reason.Rarray_filter
(p, r))
4319 let get_value_type env tv
=
4321 if List.length el
> 1 then
4324 Typing_solver.non_null
env p tv
4326 (env, explain_array_filter tv
)
4328 let rec get_array_filter_return_type env ty =
4329 let (env, ety
) = Env.expand_type
env ty in
4330 match deref ety
with
4331 | (r, Tvarray tv
) ->
4332 let (env, tv
) = get_value_type env tv
in
4333 (env, MakeType.varray
r tv
)
4334 | (r, Tunion tyl
) ->
4335 let (env, tyl
) = List.map_env
env tyl
get_array_filter_return_type in
4336 Typing_union.union_list
env r tyl
4337 | (r, Tintersection tyl
) ->
4338 let (env, tyl
) = List.map_env
env tyl
get_array_filter_return_type in
4339 Inter.intersect_list
env r tyl
4340 | (r, Tany _
) -> (env, mk
(r, Typing_utils.tany
env))
4341 | (r, Terr
) -> (env, TUtils.terr
env r)
4343 let (env, tk) = Env.fresh_type
env p in
4344 let (env, tv
) = Env.fresh_type
env p in
4347 let keyed_container_type =
4348 MakeType.keyed_container
Reason.Rnone
tk tv
4351 SubType.sub_type
env ety
keyed_container_type Errors.unify_error
4353 let (env, tv
) = get_value_type env tv
in
4354 (env, MakeType.darray
r (explain_array_filter tk) tv
))
4358 let container_type = MakeType.container
Reason.Rnone tv
in
4360 SubType.sub_type
env ety
container_type Errors.unify_error
4362 let (env, tv
) = get_value_type env tv
in
4366 (explain_array_filter (MakeType.arraykey r))
4368 (fun _
-> (env, res
)))
4370 let (env, rty) = get_array_filter_return_type env ty in
4372 map_ty
fty ~f
:(function
4373 | Tfun
ft -> Tfun
{ ft with ft_ret
= MakeType.unenforced
rty }
4378 (Tast.make_typed_expr fpos
fty (Aast.Id
id))
4381 typed_unpack_element
4383 (* Special function `type_structure` *)
4384 | Id
(p, type_structure
)
4385 when String.equal type_structure
SN.StdlibFunctions.type_structure
4386 && Int.equal
(List.length el
) 2
4387 && Option.is_none unpacked_element
->
4391 | (p, String cst
) ->
4392 (* find the class constant implicitly defined by the typeconst *)
4395 | (_
, Class_const
(cid, (_
, x)))
4396 | (_
, Class_get
(cid, CGstring
(_
, x), _
))
4397 when String.equal
x SN.Members.mClass
->
4399 | _
-> (fst e1
, CIexpr e1
)
4401 class_const ~incl_tc
:true env p (cid, (p, cst
))
4403 Errors.illegal_type_structure
p "second argument is not a string";
4404 expr_error env (Reason.Rwitness
p) e)
4405 | _
-> assert false)
4406 (* Special function `array_map` *)
4407 | Id
((_
, array_map
) as x)
4408 when String.equal array_map
SN.StdlibFunctions.array_map
4409 && (not
(List.is_empty el
))
4410 && Option.is_none unpacked_element
->
4411 (* This uses the arity to determine a signature for array_map. But there
4412 * is more: for two-argument use of array_map, we specialize the return
4413 * type to the collection that's passed in, below. *)
4414 let (env, fty, tal
) = fun_type_of_id
env x explicit_targs el
in
4415 let (env, fty) = Env.expand_type
env fty in
4416 let r_fty = get_reason
fty in
4418 Takes a Container type and returns a function that can "pack" a type
4419 into an array of appropriate shape, preserving the key type, i.e.:
4420 array -> f, where f R = array
4421 array<X> -> f, where f R = array<R>
4422 array<X, Y> -> f, where f R = array<X, R>
4423 Vector<X> -> f where f R = array<R>
4424 KeyedContainer<X, Y> -> f, where f R = array<X, R>
4425 Container<X> -> f, where f R = array<arraykey, R>
4426 X -> f, where f R = Y
4428 let rec build_output_container env (x : locl_ty
) :
4429 env * (env -> locl_ty
-> env * locl_ty
) =
4430 let (env, x) = Env.expand_type
env x in
4432 | (r, Tvarray _
) -> (env, (fun env tr
-> (env, MakeType.varray
r tr
)))
4433 | (r, Tany _
) -> (env, (fun env _
-> (env, mk
(r, Typing_utils.tany
env))))
4434 | (r, Terr
) -> (env, (fun env _
-> (env, TUtils.terr
env r)))
4435 | (r, Tunion tyl
) ->
4436 let (env, builders
) = List.map_env
env tyl
build_output_container in
4440 List.map_env
env builders
(fun env f
-> f
env tr
)
4442 Typing_union.union_list
env r tyl
)
4443 | (r, Tintersection tyl
) ->
4444 let (env, builders
) = List.map_env
env tyl
build_output_container in
4448 List.map_env
env builders
(fun env f
-> f
env tr
)
4450 Typing_intersection.intersect_list
env r tyl
)
4452 let (env, tk) = Env.fresh_type
env p in
4453 let (env, tv
) = Env.fresh_type
env p in
4454 let try_vector env =
4455 let vector_type = MakeType.const_vector
r_fty tv
in
4456 let env = SubType.sub_type
env x vector_type Errors.unify_error
in
4457 (env, (fun env tr
-> (env, MakeType.varray
r tr
)))
4459 let try_keyed_container env =
4460 let keyed_container_type = MakeType.keyed_container
r_fty tk tv
in
4462 SubType.sub_type
env x keyed_container_type Errors.unify_error
4464 (env, (fun env tr
-> (env, MakeType.darray
r tk tr
)))
4466 let try_container env =
4467 let container_type = MakeType.container
r_fty tv
in
4468 let env = SubType.sub_type
env x container_type Errors.unify_error
in
4470 (fun env tr
-> (env, MakeType.darray
r (MakeType.arraykey r) tr
)) )
4474 (fun () -> try_vector env)
4477 (fun () -> try_keyed_container env)
4480 (fun () -> try_container env)
4482 (env, (fun env _
-> (env, Typing_utils.mk_tany
env p))))))
4487 match (deref
fty, el
) with
4488 | ((_
, Tfun funty
), [_
; x]) ->
4489 let (env, _tx
, x) = expr env x in
4490 let (env, output_container
) = build_output_container env x in
4492 match get_varray_inst funty
.ft_ret
.et_type
with
4493 | None
-> (env, fty)
4495 let (env, elem_ty
) = output_container
env elem_ty
in
4496 let ft_ret = MakeType.unenforced elem_ty
in
4497 (env, mk
(r_fty, Tfun
{ funty
with ft_ret }))
4501 let (env, (tel
, typed_unpack_element
, ty)) =
4502 call ~
expected p env fty el None
4506 (Tast.make_typed_expr fpos
fty (Aast.Id
x))
4509 typed_unpack_element
4511 (* Special function `Shapes::idx` *)
4512 | Class_const
(((_
, CI
(_
, shapes
)) as class_id
), ((_
, idx
) as method_id
))
4513 when String.equal shapes
SN.Shapes.cShapes
&& String.equal idx
SN.Shapes.idx
4522 (fun env fty res el
->
4525 let (env, _ts
, shape_ty
) = expr env shape
in
4532 ~fun_pos
:(get_reason
fty)
4533 ~shape_pos
:(fst shape
)
4534 | [shape
; field
; default] ->
4535 let (env, _ts
, shape_ty
) = expr env shape
in
4536 let (env, _td
, default_ty
) = expr env default in
4541 (Some
(fst
default, default_ty
))
4543 ~fun_pos
:(get_reason
fty)
4544 ~shape_pos
:(fst shape
)
4546 (* Special function `Shapes::at` *)
4547 | Class_const
(((_
, CI
(_
, shapes
)) as class_id
), ((_
, at
) as method_id
))
4548 when String.equal shapes
SN.Shapes.cShapes
&& String.equal at
SN.Shapes.at
4557 (fun env _fty res el
->
4560 let (env, _te
, shape_ty
) = expr env shape
in
4561 Typing_shapes.at
env ~
expr_pos:p ~shape_pos
:(fst shape
) shape_ty field
4563 (* Special function `Shapes::keyExists` *)
4565 (((_
, CI
(_
, shapes
)) as class_id
), ((_
, key_exists
) as method_id
))
4566 when String.equal shapes
SN.Shapes.cShapes
4567 && String.equal key_exists
SN.Shapes.keyExists
->
4575 (fun env fty res el
->
4578 let (env, _te
, shape_ty
) = expr env shape
in
4579 (* try accessing the field, to verify existence, but ignore
4580 * the returned type and keep the one coming from function
4581 * return type hint *)
4589 ~fun_pos
:(get_reason
fty)
4590 ~shape_pos
:(fst shape
)
4594 (* Special function `Shapes::removeKey` *)
4596 (((_
, CI
(_
, shapes
)) as class_id
), ((_
, remove_key
) as method_id
))
4597 when String.equal shapes
SN.Shapes.cShapes
4598 && String.equal remove_key
SN.Shapes.removeKey
->
4606 (fun env _ res el
->
4611 | (_
, Lvar
(_
, lvar
))
4612 | (_
, Callconv
(Ast_defs.Pinout
, (_
, Lvar
(_
, lvar
)))) ->
4613 let (env, _te
, shape_ty
) = expr env shape
in
4614 let (env, shape_ty
) =
4615 Typing_shapes.remove_key
p env shape_ty field
4617 let env = set_valid_rvalue
p env lvar shape_ty
in
4620 Errors.invalid_shape_remove_key
(fst shape
);
4624 (* Special function `Shapes::toArray` *)
4625 | Class_const
(((_
, CI
(_
, shapes
)) as class_id
), ((_
, to_array
) as method_id
))
4626 when String.equal shapes
SN.Shapes.cShapes
4627 && String.equal to_array
SN.Shapes.toArray
->
4635 (fun env _ res el
->
4638 let (env, _te
, shape_ty
) = expr env shape
in
4639 Typing_shapes.to_array
env p shape_ty res
4641 (* Special function `Shapes::toDict` *)
4642 | Class_const
(((_
, CI
(_
, shapes
)) as class_id
), ((_
, to_array
) as method_id
))
4643 when String.equal shapes
SN.Shapes.cShapes
4644 && String.equal to_array
SN.Shapes.toDict
->
4652 (fun env _ res el
->
4655 let (env, _te
, shape_ty
) = expr env shape
in
4656 Typing_shapes.to_dict
env p shape_ty res
4658 (* Special function `parent::__construct` *)
4659 | Class_const
((pos, CIparent
), ((_
, construct
) as id))
4660 when String.equal construct
SN.Members.__construct
->
4661 let (env, tel
, typed_unpack_element
, ty, pty
, ctor_fty
) =
4662 call_parent_construct
p env el unpacked_element
4666 (Tast.make_typed_expr
4669 (Aast.Class_const
(((pos, pty
), Aast.CIparent
), id)))
4670 [] (* tal: no type arguments to constructor *)
4672 typed_unpack_element
4674 (* Calling parent / class method *)
4675 | Class_const
((pos, e1
), m
) ->
4676 let (env, _tal
, tcid
, ty1
) =
4678 ~check_constraints
:(not
(Nast.equal_class_id_ e1 CIparent
))
4685 mk
(Reason.Rwitness fpos
, TUtils.this_of
(Env.get_self
env))
4687 (* In static context, you can only call parent::foo() on static methods.
4688 * In instance context, you can call parent:foo() on static
4689 * methods as well as instance methods
4692 (not
(Nast.equal_class_id_ e1 CIparent
))
4693 || Env.is_static env
4694 || class_contains_smethod
env ty1 m
4696 let (env, (fty, tal
)) =
4699 ~coerce_from_ty
:None
4708 (* parent::nonStaticFunc() is really weird. It's calling a method
4709 * defined on the parent class, but $this is still the child class.
4710 * We can deal with this by hijacking the continuation that
4711 * calculates the SN.Typehints.this type *)
4712 let k_lhs _
= this_ty in
4718 ~coerce_from_ty
:None
4728 check_disposable_in_return env fty;
4730 if Nast.equal_class_id_ e1 CIparent
then
4735 let (env, (tel
, typed_unpack_element
, ty)) =
4740 ~receiver_is_self
:(Nast.equal_class_id_ e1 CIself
)
4752 (Tast.make_typed_expr fpos
fty (Aast.Class_const
(tcid
, m
)))
4755 typed_unpack_element
4757 (* Call instance method *)
4758 | Obj_get
(e1
, (pos_id
, Id m
), nullflavor
, false)
4759 when not
(TypecheckerOptions.method_call_inference
(Env.get_tcopt
env)) ->
4760 let (env, te1, ty1
) = expr ~accept_using_var
:true env e1
in
4762 match nullflavor
with
4763 | OG_nullthrows
-> None
4764 | OG_nullsafe
-> Some
p
4766 let (env, (tfty
, tal
)) =
4770 ~
nullsafe:(Option.map ~f
:(fun p -> Reason.Rnullsafe_op
p) nullsafe)
4771 ~coerce_from_ty
:None
4779 check_disposable_in_return env tfty
;
4780 let (env, (tel
, typed_unpack_element
, ty)) =
4786 ~receiver_is_self
:false
4798 (Tast.make_typed_expr
4803 Tast.make_typed_expr pos_id tfty
(Aast.Id m
),
4808 typed_unpack_element
4810 (* Call instance method using new method call inference *)
4811 | Obj_get
(receiver
, (pos_id
, Id meth
), nullflavor
, false) ->
4813 Typecheck `Obj_get` by enforcing that:
4814 - `<instance_type>` <: `Thas_member(m, #1)`
4815 where #1 is a fresh type variable.
4817 let (env, typed_receiver
, receiver_ty
) =
4818 expr ~accept_using_var
:true env receiver
4820 let env = might_throw
env in
4822 match nullflavor
with
4823 | OG_nullthrows
-> None
4824 | OG_nullsafe
-> Some
p
4826 (* Generate a fresh type `method_ty` for the type of the
4827 instance method, i.e. #1 *)
4828 let (env, method_ty
) = Env.fresh_type
env p in
4829 (* Create `Thas_member` constraint type *)
4830 let reason = Reason.Rwitness
(fst receiver
) in
4836 ~class_id
:(CIexpr receiver
)
4837 ~explicit_targs
:(Some explicit_targs
)
4839 let env = Env.set_tyvar_variance
env method_ty
in
4840 let (env, has_method_super_ty
) =
4841 if Option.is_none
nullsafe then
4842 (env, has_method_ty)
4844 (* If null-safe, then `receiver_ty` <: `?Thas_member(m, #1)`,
4845 but *unlike* property access typing in `expr_`, we still use `#1` as
4846 our "result" if `receiver_ty` is nullable (as opposed to `?#1`),
4847 deferring null-safety handling to after `call` *)
4848 let r = Reason.Rnullsafe_op
p in
4849 let null_ty = MakeType.null
r in
4850 Union.union_i
env r has_method_ty null_ty
4857 (LoclType receiver_ty
)
4861 (* Perhaps solve for `method_ty`. Opening and closing a scope is too coarse
4862 here - type parameters are localised to fresh type variables over the
4863 course of subtyping above, and we do not want to solve these until later.
4864 Once we typecheck all function calls with a subtyping of function types,
4865 we should not need to solve early at all - transitive closure of
4866 subtyping should give enough information. *)
4868 match get_var method_ty
with
4870 Typing_solver.solve_to_equal_bound_or_wrt_variance
4877 let localize_targ env (_
, targ
) = Phase.localize_targ env targ
in
4878 let (env, typed_targs
) =
4879 List.map_env
env ~f
:(localize_targ ~check_well_kinded
:true) explicit_targs
4881 check_disposable_in_return env method_ty
;
4882 let (env, (typed_params
, typed_unpack_element
, ret_ty)) =
4888 ~receiver_is_self
:false
4899 (* If the call is nullsafe AND the receiver is nullable,
4900 make the return type nullable too *)
4902 if Option.is_some
nullsafe then
4903 let r = Reason.Rnullsafe_op
p in
4904 let null_ty = MakeType.null
r in
4905 let (env, null_or_nothing_ty
) =
4906 Inter.intersect
env ~
r null_ty receiver_ty
4908 let (env, ret_option_ty
) = Union.union env null_or_nothing_ty
ret_ty in
4909 (env, ret_option_ty
)
4915 (Tast.make_typed_expr
4920 Tast.make_typed_expr pos_id method_ty
(Aast.Id meth
),
4925 typed_unpack_element
4927 (* Function invocation *)
4929 let (env, fty, tal
) = fun_type_of_id
env x explicit_targs el
in
4930 check_disposable_in_return env fty;
4931 let (env, (tel
, typed_unpack_element
, ty)) =
4932 call ~
expected p env fty el unpacked_element
4936 (Tast.make_typed_expr fpos
fty (Aast.Fun_id
x))
4939 typed_unpack_element
4941 | Id
((_
, id) as x) ->
4942 let (env, fty, tal
) = fun_type_of_id
env x explicit_targs el
in
4943 check_disposable_in_return env fty;
4944 let (env, (tel
, typed_unpack_element
, ty)) =
4945 call ~
expected p env fty el unpacked_element
4947 let is_mutable = String.equal
id SN.Rx.mutable_
in
4948 let is_move = String.equal
id SN.Rx.move
in
4949 let is_freeze = String.equal
id SN.Rx.freeze
in
4950 (* error when rx builtins are used in non-reactive context *)
4951 if not
(Env.env_local_reactive
env) then
4953 Errors.mutable_in_nonreactive_context
p
4954 else if is_move then
4955 Errors.move_in_nonreactive_context
p
4956 else if is_freeze then
4957 Errors.freeze_in_nonreactive_context
p;
4959 (* ban unpacking when calling builtings *)
4960 if (is_mutable || is_move || is_freeze) && Option.is_some unpacked_element
4962 Errors.unpacking_disallowed_builtin_function
p id;
4964 (* adjust env for Rx\freeze or Rx\move calls *)
4967 Typing_mutability.freeze_local
p env tel
4968 else if is_move then
4969 Typing_mutability.move_local
p env tel
4975 (Tast.make_typed_expr fpos
fty (Aast.Id
x))
4978 typed_unpack_element
4981 let (env, te, fty) = expr env e in
4983 Typing_solver.expand_type_and_solve
4984 ~description_of_expected
:"a function value"
4990 check_disposable_in_return env fty;
4991 let (env, (tel
, typed_unpack_element
, ty)) =
4992 call ~
expected p env fty el unpacked_element
4997 (* tal: no type arguments to function values, as they are non-generic *)
5000 typed_unpack_element
5003 and fun_type_of_id
env x tal el
=
5004 match Env.get_fun
env (snd
x) with
5006 let (env, _
, ty) = unbound_name env x (Pos.none
, Aast.Null
) in
5008 | Some
{ fe_type
; fe_pos
; fe_deprecated
; _
} ->
5009 (match get_node fe_type
with
5012 Typing_special_fun.transform_special_fun_ty
ft x (List.length el
)
5014 let ety_env = Phase.env_with_self
env in
5016 Phase.localize_targs
5017 ~check_well_kinded
:true
5021 ~use_name
:(strip_ns
(snd
x))
5024 (List.map ~f
:snd tal
)
5027 Typing_enforceability.compute_enforced_and_pessimize_fun_type
env ft
5029 let use_pos = fst
x in
5030 let def_pos = fe_pos
in
5035 { use_name
= strip_ns
(snd
x); use_pos; explicit_targs
= tal
}
5041 let fty = mk
(get_reason fe_type
, Tfun
ft) in
5042 TVis.check_deprecated ~
use_pos ~
def_pos fe_deprecated
;
5044 | _
-> failwith
"Expected function type")
5047 * Checks if a class (given by cty) contains a given static method.
5049 * We could refactor this + class_get
5051 and class_contains_smethod
env cty
(_pos
, mid
) =
5052 let lookup_member ty =
5053 match get_class_type
ty with
5054 | Some
((_
, c), _
, _
) ->
5055 (match Env.get_class
env c with
5058 Option.is_some
@@ Env.get_static_member
true env class_ mid
)
5061 let (_env
, tyl
) = TUtils.get_concrete_supertypes
env cty
in
5062 List.exists tyl ~f
:lookup_member
5068 ?
(explicit_targs
= [])
5070 ?
(function_pointer
= false)
5075 let (env, this_ty) =
5077 this_for_method
env cid cty
5099 ?
(explicit_targs
= [])
5101 ?
(function_pointer
= false)
5106 let (env, cty
) = Env.expand_type
env cty
in
5107 match deref cty
with
5108 | (r, Tany _
) -> (env, (mk
(r, Typing_utils.tany
env), []))
5109 | (r, Terr
) -> (env, (err_witness env (Reason.to_pos
r), []))
5110 | (_
, Tdynamic
) -> (env, (cty
, []))
5111 | (_
, Tunion tyl
) ->
5113 List.map_env
env tyl
(fun env ty ->
5126 Union.union_list
env (get_reason cty
) (List.map ~f
:fst
pairs)
5129 | (_
, Tintersection tyl
) ->
5131 TUtils.run_on_intersection
env tyl ~f
:(fun env ty ->
5144 Inter.intersect_list
env (get_reason cty
) (List.map ~f
:fst
pairs)
5147 | (_
, Tnewtype
(_
, _
, ty))
5148 | (_
, Tdependent
(_
, ty)) ->
5160 | (r, Tgeneric _
) ->
5161 let (env, tyl
) = TUtils.get_concrete_supertypes
env cty
in
5162 if List.is_empty tyl
then begin
5163 Errors.non_class_member
5167 (Typing_print.error
env cty
)
5169 (env, (err_witness env p, []))
5171 let (env, ty) = Typing_intersection.intersect_list
env r tyl
in
5183 | (_
, Tclass
((_
, c), _
, paraml
)) ->
5184 let class_ = Env.get_class
env c in
5186 | None
-> (env, (Typing_utils.mk_tany
env p, []))
5188 (* We need to instantiate generic parameters in the method signature *)
5191 type_expansions
= [];
5193 substs
= TUtils.make_locl_subst_for_class_tparams
class_ paraml
;
5194 from_class
= Some
cid;
5196 on_error
= Errors.unify_error_at
p;
5199 let get_smember_from_constraints env class_info =
5201 Cls.upper_bounds_on_this_from_constraints
class_info
5203 let (env, upper_bounds) =
5204 List.map_env
env upper_bounds ~f
:(fun env up
->
5205 Phase.localize ~
ety_env env up
)
5207 let (env, inter_ty
) =
5208 Inter.intersect_list
env (Reason.Rwitness
p) upper_bounds
5222 let try_get_smember_from_constraints env class_info =
5223 Errors.try_with_error
5224 (fun () -> get_smember_from_constraints env class_info)
5226 TOG.smember_not_found
5233 (env, (TUtils.terr
env Reason.Rnone
, [])))
5238 Env.get_const
env class_ mid
5240 match Env.get_typeconst
env class_ mid
with
5242 Errors.illegal_typeconst_direct_access
p;
5244 | None
-> Env.get_const
env class_ mid
5247 | None
when Cls.has_upper_bounds_on_this_from_constraints
class_ ->
5248 try_get_smember_from_constraints env class_
5250 TOG.smember_not_found
5257 (env, (TUtils.terr
env Reason.Rnone
, []))
5258 | Some
{ cc_type
; cc_abstract
; cc_pos
; _
} ->
5259 let (env, cc_locl_type
) = Phase.localize ~
ety_env env cc_type
in
5260 ( if cc_abstract
then
5266 let cc_name = Cls.name class_ ^
"::" ^ mid
in
5267 Errors.abstract_const_usage
p cc_pos
cc_name );
5268 (env, (cc_locl_type
, []))
5270 let static_member_opt =
5271 Env.get_static_member is_method
env class_ mid
5273 (match static_member_opt with
5274 | None
when Cls.has_upper_bounds_on_this_from_constraints
class_ ->
5275 try_get_smember_from_constraints env class_
5277 TOG.smember_not_found
5284 (env, (TUtils.terr
env Reason.Rnone
, []))
5287 ce_visibility = vis
;
5288 ce_type
= (lazy member_decl_ty
);
5292 let def_pos = get_pos member_decl_ty
in
5293 TVis.check_class_access
5297 (vis
, get_ce_lsb ce
)
5300 TVis.check_deprecated ~
use_pos:p ~
def_pos ce_deprecated;
5301 check_class_get
env p def_pos c mid ce
cid function_pointer
;
5302 let (env, member_ty
, et_enforced
, tal
) =
5303 match deref member_decl_ty
with
5304 (* We special case Tfun here to allow passing in explicit tparams to localize_ft. *)
5305 | (r, Tfun
ft) when is_method
->
5306 let (env, explicit_targs
) =
5307 Phase.localize_targs
5308 ~check_well_kinded
:true
5312 ~use_name
:(strip_ns mid
)
5315 (List.map ~f
:snd explicit_targs
)
5318 Typing_enforceability.compute_enforced_and_pessimize_fun_type
5326 { use_name
= strip_ns mid
; use_pos = p; explicit_targs
}
5332 (env, mk
(r, Tfun
ft), false, explicit_targs
)
5335 let { et_type
; et_enforced
} =
5336 Typing_enforceability.compute_enforced_and_pessimize_ty
5340 let (env, member_ty
) = Phase.localize ~
ety_env env et_type
in
5341 (* TODO(T52753871) make function just return possibly_enforced_ty
5342 * after considering intersection case *)
5343 (env, member_ty
, et_enforced
, [])
5345 let (env, member_ty
) =
5346 if Cls.has_upper_bounds_on_this_from_constraints
class_ then
5347 let ((env, (member_ty'
, _
)), succeed
) =
5348 Errors.try_with_error
5349 (fun () -> (get_smember_from_constraints env class_, true))
5351 (* No eligible functions found in constraints *)
5352 ((env, (MakeType.mixed Reason.Rnone
, [])), false))
5355 Inter.intersect
env (Reason.Rwitness
p) member_ty member_ty'
5362 match coerce_from_ty
with
5364 | Some
(p, ur, ty) ->
5365 Typing_coercion.coerce_type
5370 { et_type
= member_ty
; et_enforced
}
5373 (env, (member_ty
, tal
))))
5374 | (_
, Tunapplied_alias _
) ->
5375 Typing_defs.error_Tunapplied_alias_in_illegal_context
()
5377 ( Tvar _
| Tnonnull
| Tvarray _
| Tdarray _
| Tvarray_or_darray _
5378 | Toption _
| Tprim _
| Tfun _
| Ttuple _
| Tobject
| Tshape _
| Taccess _
5380 Errors.non_class_member
5384 (Typing_print.error
env cty
)
5386 (env, (err_witness env p, []))
5388 and class_id_for_new
5389 ~exact
p env (cid : Nast.class_id_
) (explicit_targs
: Nast.targ list
) :
5390 newable_class_info
=
5391 let (env, tal
, te, cid_ty
) =
5393 ~check_targs_well_kinded
:true
5394 ~check_explicit_targs
:true
5396 ~check_constraints
:false
5402 (* Need to deal with union case *)
5403 let rec get_info res tyl
=
5405 | [] -> (env, tal
, te, res
)
5407 (match get_node
ty with
5409 | Tintersection tyl'
->
5410 get_info res
(tyl'
@ tyl
)
5412 (* Instantiation on an abstract class (e.g. from classname<T>) is
5413 * via the base type (to check constructor args), but the actual
5414 * type `ty` must be preserved. *)
5415 (match get_node
(TUtils.get_base_type
env ty) with
5416 | Tdynamic
-> get_info (`Dynamic
:: res
) tyl
5417 | Tclass
(sid
, _
, _
) ->
5418 let class_ = Env.get_class
env (snd sid
) in
5420 | None
-> get_info res tyl
5421 | Some
class_info ->
5422 (match (te, cid_ty
) with
5423 (* When computing the classes for a new T() where T is a generic,
5424 * the class must be consistent (final, final constructor, or
5425 * <<__ConsistentConstruct>>) for its constructor to be considered *)
5426 | ((_
, Aast.CI
(_
, c)), ty) when is_generic_equal_to
c ty ->
5427 (* Only have this choosing behavior for new T(), not all generic types
5428 * i.e. new classname<T>, TODO: T41190512 *)
5429 if Tast_utils.valid_newable_class
class_info then
5430 get_info (`Class
(sid
, class_info, ty) :: res
) tyl
5433 | _
-> get_info (`Class
(sid
, class_info, ty) :: res
) tyl
))
5434 | _
-> get_info res tyl
))
5436 get_info [] [cid_ty
]
5438 (* To be a valid trait declaration, all of its 'require extends' must
5439 * match; since there's no multiple inheritance, it follows that all of
5440 * the 'require extends' must belong to the same inheritance hierarchy
5441 * and one of them should be the child of all the others *)
5442 and trait_most_concrete_req_class trait
env =
5444 (Cls.all_ancestor_reqs trait
)
5448 let (_r
, (_p
, name), _paraml
) = TUtils.unwrap_class_type
ty in
5451 | Some
(c, _ty
) -> Cls.has_ancestor
c name
5457 let class_ = Env.get_class
env name in
5460 | Some
c when Ast_defs.(equal_class_kind
(Cls.kind
c) Cinterface
) ->
5462 | Some
c when Ast_defs.(equal_class_kind
(Cls.kind
c) Ctrait
) ->
5463 (* this is an error case for which Typing_check_decls spits out
5464 * an error, but does *not* currently remove the offending
5465 * 'require extends' or 'require implements' *)
5467 | Some
c -> Some
(c, ty)
5471 (* When invoking a method the class_id is used to determine what class we
5472 * lookup the method in, but the type of 'this' will be the late bound type.
5476 * public static function get(): this { return new static(); }
5478 * public static function alias(): this { return self::get(); }
5481 * In C::alias, when we invoke self::get(), 'self' is resolved to the class
5482 * in the lexical scope (C), so call C::get. However the method is executed in
5483 * the current context, so static inside C::get will be resolved to the late
5484 * bound type (get_called_class() within C::alias).
5486 * This means when determining the type of this, CIparent and CIself should be
5487 * changed to CIstatic. For the other cases of C::get() or $c::get(), we only
5488 * look at the left hand side of the '::' and use the type type associated
5491 * Thus C::get() will return a type C, while $c::get() will return the same
5494 and this_for_method
env cid default_ty
=
5499 let p = get_pos default_ty
in
5500 let (env, _tal
, _te
, ty) =
5501 static_class_id ~check_constraints
:false p env [] CIstatic
5503 ExprDepTy.make
env CIstatic
ty
5504 | _
-> (env, default_ty
)
5506 (** Resolve class expressions like `parent`, `self`, `static`, classnames
5509 ?
(check_targs_well_kinded
= false)
5511 ?
(check_explicit_targs
= false)
5512 ~
(check_constraints
: bool)
5515 (tal
: Nast.targ list
) :
5516 Nast.class_id_
-> env * Tast.targ list
* Tast.class_id
* locl_ty
=
5517 let make_result env tal
te ty = (env, tal
, ((p, ty), te), ty) in
5520 (match get_class_type
(Env.get_self
env) with
5521 | Some
((_
, self
), _
, _
) ->
5522 (match Env.get_class
env self
with
5523 | Some trait
when Ast_defs.(equal_class_kind
(Cls.kind trait
) Ctrait
) ->
5524 (match trait_most_concrete_req_class trait
env with
5526 Errors.parent_in_trait
p;
5527 make_result env [] Aast.CIparent
(err_witness env p)
5528 | Some
(_
, parent_ty
) ->
5529 (* inside a trait, parent is SN.Typehints.this, but with the
5530 * type of the most concrete class that the trait has
5531 * "require extend"-ed *)
5532 let r = Reason.Rwitness
p in
5533 let (env, parent_ty
) = Phase.localize_with_self
env parent_ty
in
5534 make_result env [] Aast.CIparent
(mk
(r, TUtils.this_of parent_ty
)))
5537 match Env.get_parent_ty
env with
5539 Errors.parent_undefined
p;
5540 mk
(Reason.none
, Typing_defs.make_tany
())
5541 | Some
parent -> parent
5543 let r = Reason.Rwitness
p in
5544 let (env, parent) = Phase.localize_with_self
env parent in
5545 (* parent is still technically the same object. *)
5550 (mk
(r, TUtils.this_of
(mk
(r, get_node
parent)))))
5553 match Env.get_parent_ty
env with
5555 Errors.parent_undefined
p;
5556 mk
(Reason.none
, Typing_defs.make_tany
())
5557 | Some
parent -> parent
5559 let r = Reason.Rwitness
p in
5560 let (env, parent) = Phase.localize_with_self
env parent in
5561 (* parent is still technically the same object. *)
5566 (mk
(r, TUtils.this_of
(mk
(r, get_node
parent)))))
5568 let this = mk
(Reason.Rwitness
p, TUtils.this_of
(Env.get_self
env)) in
5569 make_result env [] Aast.CIstatic
this
5572 match get_node
(Env.get_self
env) with
5573 | Tclass
(c, _
, tyl
) -> Tclass
(c, exact
, tyl
)
5576 make_result env [] Aast.CIself
(mk
(Reason.Rwitness
p, self))
5577 | CI
((p, id) as c) as e1
->
5579 match Env.get_pos_and_kind_of_generic
env id with
5580 | Some
(def_pos, kind
) ->
5581 let simple_kind = Typing_kinding_defs.Simple.from_full_kind kind
in
5583 Typing_kinding_defs.Simple.get_named_parameter_kinds
simple_kind
5586 Phase.localize_targs_with_kinds
5587 ~check_well_kinded
:check_targs_well_kinded
5591 ~use_name
:(strip_ns
(snd
c))
5592 ~check_explicit_targs
5595 (List.map ~f
:snd tal
)
5597 let r = Reason.Rhint
p in
5598 let type_args = List.map tal fst
in
5599 let tgeneric = MakeType.generic ~
type_args r id in
5600 make_result env tal
(Aast.CI
c) tgeneric
5602 (* Not a type parameter *)
5603 let class_ = Env.get_class
env id in
5605 | None
-> make_result env [] (Aast.CI
c) (Typing_utils.mk_tany
env p)
5607 let (env, ty, tal
) =
5609 |> Phase.localize_targs_and_check_constraints
5611 ~check_well_kinded
:check_targs_well_kinded
5613 ~
def_pos:(Cls.pos class_)
5615 ~check_explicit_targs
5619 (Cls.tparams
class_)
5621 make_result env tal
(Aast.CI
c) ty)
5623 | CIexpr
((p, _
) as e) ->
5624 let (env, te, ty) = expr env e in
5625 let rec resolve_ety env ty =
5627 Typing_solver.expand_type_and_solve
5628 ~description_of_expected
:"an object"
5634 let base_ty = TUtils.get_base_type
env ty in
5635 match deref
base_ty with
5636 | (_
, Tnewtype
(classname, [the_cls
], _
))
5637 when String.equal
classname SN.Classes.cClassname
->
5638 resolve_ety env the_cls
5642 | (r, Tunion tyl
) ->
5643 let (env, tyl
) = List.map_env
env tyl
resolve_ety in
5644 (env, MakeType.union r tyl
)
5645 | (r, Tintersection tyl
) ->
5646 let (env, tyl
) = TUtils.run_on_intersection
env tyl ~f
:resolve_ety in
5647 Inter.intersect_list
env r tyl
5648 | (_
, Tdynamic
) -> (env, base_ty)
5649 | (_
, (Tany _
| Tprim Tstring
| Tobject
)) when not
(Env.is_strict
env) ->
5650 (env, Typing_utils.mk_tany
env p)
5651 | (_
, Terr
) -> (env, err_witness env p)
5653 Errors.unknown_type
"an object" p (Reason.to_string
"It is unknown" r);
5654 (env, err_witness env p)
5655 | (_
, Tunapplied_alias _
) ->
5656 Typing_defs.error_Tunapplied_alias_in_illegal_context
()
5658 ( Tany _
| Tnonnull
| Tvarray _
| Tdarray _
| Tvarray_or_darray _
5659 | Toption _
| Tprim _
| Tfun _
| Ttuple _
| Tnewtype _
| Tdependent _
5660 | Tobject
| Tshape _
| Taccess _
) ) ->
5661 Errors.expected_class
5662 ~suffix
:(", but got " ^
Typing_print.error
env base_ty)
5664 (env, err_witness env p)
5666 let (env, result_ty
) = resolve_ety env ty in
5667 make_result env [] (Aast.CIexpr
te) result_ty
5669 and call_construct
p env class_ params el unpacked_element
cid cid_ty
=
5671 if Nast.equal_class_id_
cid CIparent
then
5672 (CIstatic
, mk
(Reason.Rwitness
p, TUtils.this_of
(Env.get_self
env)))
5678 type_expansions
= [];
5680 substs
= TUtils.make_locl_subst_for_class_tparams
class_ params;
5681 from_class
= Some
cid;
5683 on_error
= Errors.unify_error_at
p;
5687 Phase.check_tparams_constraints ~
use_pos:p ~
ety_env env (Cls.tparams
class_)
5690 Phase.check_where_constraints
5693 ~definition_pos
:(Cls.pos class_)
5696 (Cls.where_constraints
class_)
5698 if Cls.is_xhp
class_ then
5699 (env, [], None
, TUtils.mk_tany
env p)
5701 let cstr = Env.get_construct
env class_ in
5702 let mode = Env.get_mode
env in
5706 ((not
(List.is_empty el
)) || Option.is_some unpacked_element
)
5707 && (FileInfo.is_strict
mode || FileInfo.(equal_mode
mode Mpartial
))
5708 && Cls.members_fully_known
class_
5710 Errors.constructor_no_args
p;
5711 let (env, tel
, _tyl
) = exprs env el
in
5712 (env, tel
, None
, TUtils.terr
env Reason.Rnone
)
5713 | Some
{ ce_visibility = vis
; ce_type
= (lazy m
); ce_deprecated; _
} ->
5714 let def_pos = get_pos m
in
5715 TVis.check_obj_access ~
use_pos:p ~
def_pos env vis
;
5716 TVis.check_deprecated ~
use_pos:p ~
def_pos ce_deprecated;
5717 (* Obtain the type of the constructor *)
5722 Typing_enforceability.compute_enforced_and_pessimize_fun_type
env ft
5724 (* This creates type variables for non-denotable type parameters on constructors.
5725 * These are notably different from the tparams on the class, which are handled
5726 * at the top of this function. User-written type parameters on constructors
5727 * are still a parse error. This is a no-op if ft.ft_tparams is empty. *)
5728 let (env, implicit_constructor_targs
) =
5729 Phase.localize_targs
5730 ~check_well_kinded
:true
5734 ~use_name
:"constructor"
5744 use_name
= "constructor";
5746 explicit_targs
= implicit_constructor_targs
;
5753 (env, mk
(r, Tfun
ft))
5755 Errors.internal_error
p "Expected function type for constructor";
5756 let ty = TUtils.terr
env r in
5759 let (env, (tel
, typed_unpack_element
, _ty
)) =
5760 call ~
expected:None
p env m el unpacked_element
5762 (env, tel
, typed_unpack_element
, m
)
5764 and check_arity ?
(did_unpack
= false) pos pos_def
ft (arity
: int) =
5765 let exp_min = Typing_defs.arity_min
ft in
5766 if arity
< exp_min then
5767 Errors.typing_too_few_args
exp_min arity
pos pos_def None
;
5768 match ft.ft_arity
with
5770 let exp_max = List.length
ft.ft_params
in
5777 if arity > exp_max then
5778 Errors.typing_too_many_args
exp_max arity pos pos_def None
5781 and check_lambda_arity lambda_pos
def_pos lambda_ft
expected_ft =
5782 match (lambda_ft
.ft_arity
, expected_ft.ft_arity
) with
5783 | (Fstandard
, Fstandard
) ->
5784 let expected_min = Typing_defs.arity_min
expected_ft in
5785 let lambda_min = Typing_defs.arity_min lambda_ft
in
5786 if lambda_min < expected_min then
5787 Errors.typing_too_few_args
expected_min lambda_min lambda_pos
def_pos None
;
5788 if lambda_min > expected_min then
5789 Errors.typing_too_many_args
5797 (* The variadic capture argument is an array listing the passed
5798 * variable arguments for the purposes of the function body; callsites
5799 * should not unify with it *)
5800 and variadic_param
env ft =
5801 match ft.ft_arity
with
5802 | Fvariadic
param -> (env, Some
param)
5803 | Fstandard
-> (env, None
)
5805 and param_modes ?
(is_variadic
= false) ({ fp_pos
; _
} as fp
) (pos, e) =
5806 match (get_fp_mode fp
, e) with
5807 | (FPnormal
, Callconv _
) ->
5808 Errors.inout_annotation_unexpected
pos fp_pos is_variadic
5809 | (FPnormal
, _
) -> ()
5810 | (FPinout
, Callconv
(Ast_defs.Pinout
, _
)) -> ()
5811 | (FPinout
, _
) -> Errors.inout_annotation_missing
pos fp_pos
5813 and inout_write_back
env { fp_type
; _
} (_
, e) =
5815 | Callconv
(Ast_defs.Pinout
, e1
) ->
5816 (* Translate the write-back semantics of inout parameters.
5818 * This matters because we want to:
5819 * (1) make sure we can write to the original argument
5820 * (modifiable lvalue check)
5821 * (2) allow for growing of locals / Tunions (type side effect)
5822 * but otherwise unify the argument type with the parameter hint
5824 let (env, _te
, _ty
) =
5825 assign_
(fst e1
) Reason.URparam_inout
env e1 fp_type
.et_type
5830 (** Typechecks a call.
5831 Returns in this order the typed expressions for the arguments, for the variadic arguments, and the return type. *)
5833 ~
(expected : ExpectedTy.t
option)
5834 ?
(method_call_info
: TR.method_call_info
option)
5835 ?
(nullsafe : Pos.t
option = None
)
5840 (el
: Nast.expr list
)
5841 (unpacked_element
: Nast.expr option) :
5842 env * (Tast.expr list
* Tast.expr option * locl_ty
) =
5844 TUtils.try_over_concrete_supertypes
env fty (fun env fty ->
5846 if TypecheckerOptions.method_call_inference
(Env.get_tcopt
env) then
5847 Env.expand_type
env fty
5849 Typing_solver.expand_type_and_solve
5850 ~description_of_expected
:"a function value"
5856 match deref efty
with
5857 | (r, ((Tprim Tnull
| Tdynamic
| Terr
| Tany _
| Tunion
[]) as ty))
5859 | Tprim Tnull
-> Option.is_some
nullsafe
5862 Option.value_map ~f
:(fun u
-> el @ [u
]) ~
default:el unpacked_element
5864 let expected_arg_ty =
5865 (* Note: We ought to be using 'mixed' here *)
5866 ExpectedTy.make
pos Reason.URparam
(Typing_utils.mk_tany
env pos)
5869 List.map_env
env el (fun env elt
->
5870 let (env, te, ty) = expr ~
expected:expected_arg_ty env elt
in
5872 if TCO.global_inference
(Env.get_tcopt
env) then
5873 match get_node efty
with
5877 Typing_coercion.coerce_type
5882 (MakeType.unenforced efty
)
5890 | (_
, Callconv
(Ast_defs.Pinout
, e1
)) ->
5891 let (env, _te
, _ty
) =
5892 assign_
(fst e1
) Reason.URparam_inout
env e1 efty
5900 call_untyped_unpack
env (Reason.to_pos
r) unpacked_element
5904 | Tprim Tnull
-> mk
(r, Tprim Tnull
)
5905 | Tdynamic
-> MakeType.dynamic
(Reason.Rdynamic_call
pos)
5908 Typing_utils.mk_tany
env pos
5910 | _
(* _ should not happen! *) ->
5913 (env, (tel
, None
, ty))
5914 | (_
, Tunion
[ty]) ->
5915 call ~
expected ~
nullsafe ?in_await
pos env ty el unpacked_element
5916 | (r, Tunion tyl
) ->
5918 List.map_env
env tyl
(fun env ty ->
5929 let retl = List.map resl ~f
:(fun (_
, _
, x) -> x) in
5930 let (env, ty) = Union.union_list
env r retl in
5931 (* We shouldn't be picking arbitrarily for the TAST here, as TAST checks
5932 * depend on the types inferred. Here's we're preserving legacy behaviour
5933 * by picking the last one.
5934 * TODO: don't do this, instead use subtyping to push unions
5935 * through function types
5937 let (tel
, typed_unpack_element
, _
) = List.hd_exn
(List.rev
resl) in
5938 (env, (tel
, typed_unpack_element
, ty))
5939 | (r, Tintersection tyl
) ->
5941 TUtils.run_on_intersection
env tyl ~f
:(fun env ty ->
5952 let retl = List.map resl ~f
:(fun (_
, _
, x) -> x) in
5953 let (env, ty) = Inter.intersect_list
env r retl in
5954 (* We shouldn't be picking arbitrarily for the TAST here, as TAST checks
5955 * depend on the types inferred. Here we're preserving legacy behaviour
5956 * by picking the last one.
5957 * TODO: don't do this, instead use subtyping to push intersections
5958 * through function types
5960 let (tel
, typed_unpack_element
, _
) = List.hd_exn
(List.rev
resl) in
5961 (env, (tel
, typed_unpack_element
, ty))
5963 (* Typing of format string functions. It is dependent on the arguments (el)
5964 * so it cannot be done earlier.
5966 let pos_def = Reason.to_pos r2
in
5967 let (env, ft) = Typing_exts.retype_magic_func
env ft el in
5968 let (env, var_param) = variadic_param
env ft in
5969 (* Force subtype with expected result *)
5971 check_expected_ty
"Call result" env ft.ft_ret.et_type
expected
5973 let env = Env.set_tyvar_variance
env ft.ft_ret.et_type
in
5981 let get_next_param_info paraml
=
5983 | param :: paraml
-> (false, Some
param, paraml
)
5984 | [] -> (true, var_param, paraml
)
5986 (* TODO: We're using plain String at the moment, until we
5987 * introduce actual atom notation (#A instead of "A")
5989 let expand_atom_in_enum env enum_name atom_name
=
5990 let cls = Env.get_class
env enum_name
in
5993 (match Env.get_const
env cls atom_name
with
5995 let dty = const_def
.cc_type
in
5996 let (env, lty
) = Phase.localize_with_self
env dty in
5997 let hi = (pos, lty
) in
5998 let te = (hi, EnumAtom atom_name
) in
5999 (env, Some
(te, lty
))
6001 Errors.atom_unknown
pos atom_name enum_name
;
6003 | None
-> (env, None
)
6005 let check_arg env ((pos, arg
) as e) opt_param ~is_variadic
=
6006 match opt_param
with
6008 (* First check if __Atom is used *)
6009 let (env, atom_type
) =
6010 let is_atom = get_fp_is_atom
param in
6011 let ety = param.fp_type
.et_type
in
6013 | EnumAtom atom_name
when is_atom ->
6014 (match get_node
ety with
6015 | Tclass
((_
, name), _
, [ty_enum
; _ty_interface
])
6016 when String.equal
name SN.Classes.cEnumMember
->
6017 (match get_node ty_enum
with
6018 | Tclass
((_
, enum_name
), _
, _
)
6019 when Env.is_enum_class
env enum_name
->
6020 expand_atom_in_enum env enum_name atom_name
6021 | Tgeneric
(name, _
) ->
6023 Typing_utils.collect_enum_class_upper_bounds
env name
6025 (* To avoid ambiguity, we only support the case where
6026 * there is a single upper bound that is an EnumClass.
6027 * We might want to relax that later (e.g. with the
6028 * support for intersections.
6029 * See Typing_check_decls.check_atom_on_param.
6031 if SSet.cardinal
upper_bounds = 1 then
6032 let enum_name = SSet.choose
upper_bounds in
6033 expand_atom_in_enum env enum_name atom_name
6037 (* Already reported, see Typing_check_decls *)
6040 (* Already reported, see Typing_check_decls *)
6042 | Class_const _
when is_atom ->
6043 Errors.atom_invalid_argument
pos;
6048 match atom_type
with
6049 | Some
(te, ty) -> (env, te, ty)
6052 ExpectedTy.make_and_allow_coercion
6058 ~accept_using_var
:(get_fp_accept_disposable
param)
6063 let env = call_param
env param (e, ty) ~is_variadic
in
6064 (env, Some
(te, ty))
6070 (Typing_utils.mk_tany
env pos)
6072 let (env, te, ty) = expr ~
expected env e in
6073 (env, Some
(te, ty))
6075 let set_tyvar_variance_from_lambda_param env opt_param
=
6076 match opt_param
with
6078 let rec set_params_variance env ty =
6079 let (env, ty) = Env.expand_type
env ty in
6080 match get_node
ty with
6081 | Tunion
[ty] -> set_params_variance env ty
6082 | Toption
ty -> set_params_variance env ty
6083 | Tfun
{ ft_params
; ft_ret; _
} ->
6087 ~f
:(fun env param ->
6088 Env.set_tyvar_variance
env param.fp_type
.et_type
)
6091 Env.set_tyvar_variance
env ft_ret.et_type ~flip
:true
6094 set_params_variance env param.fp_type
.et_type
6097 (* Given an expected function type ft, check types for the non-unpacked
6098 * arguments. Don't check lambda expressions if check_lambdas=false *)
6099 let rec check_args check_lambdas
env el paraml
=
6101 (* We've got an argument *)
6102 | (e, opt_result
) :: el ->
6103 (* Pick up next parameter type info *)
6104 let (is_variadic
, opt_param
, paraml
) =
6105 get_next_param_info paraml
6107 let (env, one_result
) =
6108 match (check_lambdas
, is_lambda e) with
6111 check_arg env e opt_param ~is_variadic
6114 set_tyvar_variance_from_lambda_param env opt_param
6117 | (true, false) -> (env, opt_result
)
6119 let (env, rl
, paraml
) = check_args check_lambdas
env el paraml
in
6120 (env, (e, one_result
) :: rl
, paraml
)
6121 | [] -> (env, [], paraml
)
6123 (* Same as above, but checks the types of the implicit arguments, which are
6124 * read from the context *)
6125 let check_implicit_args env =
6127 Typing_coeffects.get_type
ft.ft_implicit_params
.capability
6129 if not
(TypecheckerOptions.call_coeffects
(Env.get_tcopt
env)) then
6132 let env_capability =
6133 Env.get_local_check_defined
6135 (pos, Typing_coeffects.capability_id
)
6143 (fun ?code
:_c _ _
->
6144 Errors.call_coeffect_error
6146 ~available_incl_unsafe
:
6147 (Typing_print.coeffects
env env_capability)
6148 ~available_pos
:(Typing_defs.get_pos
env_capability)
6149 ~required_pos
:(Typing_defs.get_pos
capability)
6150 ~required
:(Typing_print.coeffects
env capability))
6153 (* First check the non-lambda arguments. For generic functions, this
6154 * is likely to resolve type variables to concrete types *)
6155 let rl = List.map el (fun e -> (e, None
)) in
6156 let (env, rl, _
) = check_args false env rl ft.ft_params
in
6157 (* Now check the lambda arguments, hopefully with type variables resolved *)
6158 let (env, rl, paraml
) = check_args true env rl ft.ft_params
in
6159 (* We expect to see results for all arguments after this second pass *)
6163 | None
-> failwith
"missing parameter in check_args"
6166 let l = List.map rl (fun (_
, opt
) -> get_param opt
) in
6169 let env = check_implicit_args env in
6170 let env = TR.check_call env method_call_info
pos r2
ft tys
in
6171 let (env, typed_unpack_element
, arity, did_unpack
) =
6172 match unpacked_element
with
6173 | None
-> (env, None
, List.length
el, false)
6175 (* Now that we're considering an splat (Some e) we need to construct a type that
6176 * represents the remainder of the function's parameters. `paraml` represents those
6177 * remaining parameters, and the variadic parameter is stored in `var_param`. For example, given
6179 * function f(int $i, string $j, float $k = 3.14, mixed ...$m): void {}
6180 * function g((string, float, bool) $t): void {
6184 * the constraint type we want is splat([#1], [opt#2], #3).
6186 let (consumed
, required_params
, optional_params
) =
6187 split_remaining_params_required_optional
ft paraml
6189 let (env, (d_required
, d_optional
, d_variadic
)) =
6190 generate_splat_type_vars
6197 let destructure_ty =
6200 ( Reason.Runpack_param
(fst
e, pos_def, consumed
),
6206 d_kind
= SplatUnpack
;
6209 let (env, te, ty) = expr env e in
6210 (* Populate the type variables from the expression in the splat *)
6220 (* Use the type variables for the remaining parameters *)
6226 ~f
:(fun env elt
param ->
6227 call_param
env param (e, elt
) ~is_variadic
:false)
6234 ~f
:(fun env elt
param ->
6235 call_param
env param (e, elt
) ~is_variadic
:false)
6238 Option.map2 d_variadic
var_param ~f
:(fun v vp
->
6239 call_param
env vp
(e, v
) ~is_variadic
:true)
6240 |> Option.value ~
default:env
6244 List.length
el + List.length d_required
,
6245 Option.is_some d_variadic
)
6247 (* If we unpacked an array, we don't check arity exactly. Since each
6248 * unpacked array consumes 1 or many parameters, it is nonsensical to say
6249 * that not enough args were passed in (so we don't do the min check).
6251 let () = check_arity ~did_unpack
pos pos_def ft arity in
6252 (* Variadic params cannot be inout so we can stop early *)
6253 let env = wfold_left2 inout_write_back
env ft.ft_params
el in
6255 TR.get_adjusted_return_type
env method_call_info
ft.ft_ret.et_type
6257 (env, (tel
, typed_unpack_element
, ret_ty))
6259 when TypecheckerOptions.method_call_inference
(Env.get_tcopt
env) ->
6261 Typecheck calls with unresolved function type by constructing a
6262 suitable function type from the arguments and invoking subtyping.
6264 let (env, typed_el
, type_of_el
) =
6265 exprs ~accept_using_var
:true env el
6267 let (env, typed_unpacked_element
, type_of_unpacked_element
) =
6268 match unpacked_element
with
6270 let (env, typed_unpacked
, type_of_unpacked
) =
6271 expr ~accept_using_var
:true env unpacked
6273 (env, Some typed_unpacked
, Some type_of_unpacked
)
6274 | None
-> (env, None
, None
)
6276 let mk_function_supertype
6277 env pos (type_of_el
, type_of_unpacked_element
) =
6278 let mk_fun_param ty =
6280 (* Keep supertype as permissive as possible: *)
6282 ~
mode:FPnormal
(* TODO: deal with `inout` parameters *)
6283 ~accept_disposable
:false (* TODO: deal with disposables *)
6284 ~mutability
:(Some Param_maybe_mutable
)
6293 fp_type
= MakeType.enforced ty;
6294 fp_rx_annotation
= None
;
6299 match type_of_unpacked_element
with
6300 | Some type_of_unpacked
->
6301 let fun_param = mk_fun_param type_of_unpacked
in
6305 (* TODO: ensure `ft_params`/`ft_where_constraints` don't affect subtyping *)
6306 let ft_tparams = [] in
6307 let ft_where_constraints = [] in
6308 let ft_params = List.map ~f
:mk_fun_param type_of_el
in
6309 let ft_implicit_params =
6313 (* TODO(coeffects) should this be a different type? *);
6316 let (env, return_ty
) = Env.fresh_type
env pos in
6320 | Some
r -> MakeType.awaitable
r return_ty
6322 let ft_ret = MakeType.enforced return_ty in
6323 (* A non-reactive supertype is most permissive: *)
6324 let ft_reactive = Nonreactive
in
6326 (* Keep supertype as permissive as possible: *)
6328 Ast_defs.FSync
(* `FSync` fun can still return `Awaitable<_>` *)
6329 (Some Param_maybe_mutable
)
6330 ~return_disposable
:false (* TODO: deal with disposable return *)
6331 ~returns_mutable
:false
6332 ~returns_void_to_rx
:false
6334 let ft_ifc_decl = Typing_defs_core.default_ifc_fun_decl
in
6339 ft_where_constraints;
6348 let fun_type = mk
(r, Tfun
fun_locl_type) in
6349 let env = Env.set_tyvar_variance
env fun_type in
6350 (env, fun_type, return_ty)
6352 let (env, fun_type, return_ty) =
6353 mk_function_supertype env pos (type_of_el
, type_of_unpacked_element
)
6356 Type.sub_type
pos Reason.URnone
env efty
fun_type Errors.unify_error
6358 (env, (typed_el
, typed_unpacked_element
, return_ty))
6360 bad_call
env pos efty
;
6361 let env = call_untyped_unpack
env (get_pos efty
) unpacked_element
in
6362 (env, ([], None
, err_witness env pos)))
6367 bad_call
env pos fty;
6368 let env = call_untyped_unpack
env (get_pos
fty) unpacked_element
in
6369 (env, ([], None
, err_witness env pos))
6371 and split_remaining_params_required_optional
ft remaining_params =
6372 (* Same example as above
6374 * function f(int $i, string $j, float $k = 3.14, mixed ...$m): void {}
6375 * function g((string, float, bool) $t): void {
6379 * `remaining_params` will contain [string, float] and there has been 1 parameter consumed. The min_arity
6380 * of this function is 2, so there is 1 required parameter remaining and 1 optional parameter.
6384 ~f
:(fun fp
-> not
(Typing_defs.get_fp_has_default fp
))
6387 let original_params = ft.ft_params in
6388 let consumed = List.length
original_params - List.length
remaining_params in
6389 let required_remaining = Int.max
(min_arity - consumed) 0 in
6390 let (required_params
, optional_params
) =
6391 List.split_n
remaining_params required_remaining
6393 (consumed, required_params
, optional_params
)
6395 and generate_splat_type_vars
6396 env p required_params optional_params variadic_param
=
6397 let (env, d_required
) =
6398 List.map_env
env required_params ~f
:(fun env _
-> Env.fresh_type
env p)
6400 let (env, d_optional
) =
6401 List.map_env
env optional_params ~f
:(fun env _
-> Env.fresh_type
env p)
6403 let (env, d_variadic
) =
6404 match variadic_param
with
6405 | None
-> (env, None
)
6407 let (env, ty) = Env.fresh_type
env p in
6410 (env, (d_required
, d_optional
, d_variadic
))
6412 and call_param
env param (((pos, _
) as e), arg_ty
) ~is_variadic
=
6413 param_modes ~is_variadic
param e;
6415 (* When checking params, the type 'x' may be expression dependent. Since
6416 * we store the expression id in the local env for Lvar, we want to apply
6421 | Lvar _
-> ExprDepTy.make
env (CIexpr
e) arg_ty
6422 | _
-> (env, arg_ty
)
6424 Typing_coercion.coerce_type
6432 and call_untyped_unpack
env f_pos unpacked_element
=
6433 match unpacked_element
with
6434 (* In the event that we don't have a known function call type, we can still
6435 * verify that any unpacked arguments (`...$args`) are something that can
6436 * be actually unpacked. *)
6439 let (env, _
, ety) = expr env e in
6440 let (env, ty) = Env.fresh_type
env (fst
e) in
6441 let destructure_ty =
6442 MakeType.simple_variadic_splat
(Reason.Runpack_param
(fst
e, f_pos
, 0)) ty
6452 and bad_call
env p ty = Errors.bad_call
p (Typing_print.error
env ty)
6454 and make_a_local_of
env e =
6456 | (p, Class_get
((_
, cname
), CGstring
(_
, member_name
), _
)) ->
6457 let (env, local) = Env.FakeMembers.make_static
env cname member_name
p in
6458 (env, Some
(p, local))
6461 ((((_
, This
) | (_
, Lvar _
)) as obj
), (_
, Id
(_
, member_name
)), _
, _
) )
6463 let (env, local) = Env.FakeMembers.make
env obj member_name
p in
6464 (env, Some
(p, local))
6466 | (_
, Dollardollar
x) ->
6470 (* This function captures the common bits of logic behind refinement
6471 * of the type of a local variable or a class member variable as a
6472 * result of a dynamic check (e.g., nullity check, simple type check
6473 * using functions like is_int, is_string, is_array etc.). The
6474 * argument refine is a function that takes the type of the variable
6475 * and returns a refined type (making necessary changes to the
6476 * environment, which is threaded through).
6478 * All refinement functions return, in addition to the updated
6479 * environment, a (conservative) set of all the locals that got
6480 * refined. This set is used to construct AssertEnv statmements in
6483 and refine_lvalue_type
env (((_p
, ty), _
) as te) ~refine
=
6484 let (env, ty) = refine
env ty in
6485 let e = Tast.to_nast_expr
te in
6486 let (env, localopt
) = make_a_local_of
env e in
6487 (* TODO TAST: generate an assignment to the fake local in the TAST *)
6489 | Some lid
-> (set_local
env lid
ty, Local_id.Set.singleton
(snd lid
))
6490 | None
-> (env, Local_id.Set.empty
)
6492 and condition_nullity ~nonnull
(env : env) te =
6494 (* assignment: both the rhs and lhs of the '=' must be made null/non-null *)
6495 | (_
, Aast.Binop
(Ast_defs.Eq None
, var
, te)) ->
6496 let (env, lset1
) = condition_nullity ~nonnull
env te in
6497 let (env, lset2
) = condition_nullity ~nonnull
env var
in
6498 (env, Local_id.Set.union lset1 lset2
)
6499 (* case where `Shapes::idx(...)` must be made null/non-null *)
6502 ( (_
, Aast.Class_const
((_
, Aast.CI
(_
, shapes
)), (_
, idx
))),
6506 when String.equal shapes
SN.Shapes.cShapes
&& String.equal idx
SN.Shapes.idx
6508 let field = Tast.to_nast_expr
field in
6509 let refine env shape_ty
=
6511 Typing_shapes.shapes_idx_not_null
env shape_ty
field
6515 refine_lvalue_type
env shape ~
refine
6519 Typing_solver.non_null
env p ty
6521 let r = Reason.Rwitness
(get_pos
ty) in
6522 Inter.intersect
env r ty (MakeType.null
r)
6524 refine_lvalue_type
env te ~
refine
6526 and condition_isset
env = function
6527 | (_
, Aast.Array_get
(x, _
)) -> condition_isset
env x
6528 | v
-> condition_nullity ~nonnull
:true env v
6531 * Build an environment for the true or false branch of
6532 * conditional statements.
6535 ?lhs_of_null_coalesce
env tparamet
((((p, ty) as pty
), e) as te : Tast.expr)
6537 let condition = condition ?lhs_of_null_coalesce
in
6539 | Aast.True
when not tparamet
->
6540 (LEnv.drop_cont
env C.Next
, Local_id.Set.empty
)
6541 | Aast.False
when tparamet
-> (LEnv.drop_cont
env C.Next
, Local_id.Set.empty
)
6542 | Aast.Call
((_
, Aast.Id
(_
, func
)), _
, [param], None
)
6543 when String.equal
SN.PseudoFunctions.isset func
6545 && not
(Env.is_strict
env) ->
6546 condition_isset
env param
6547 | Aast.Call
((_
, Aast.Id
(_
, func
)), _
, [te], None
)
6548 when String.equal
SN.StdlibFunctions.is_null func
->
6549 condition_nullity ~nonnull
:(not tparamet
) env te
6550 | Aast.Binop
((Ast_defs.Eqeq
| Ast_defs.Eqeqeq
), (_
, Aast.Null
), e)
6551 | Aast.Binop
((Ast_defs.Eqeq
| Ast_defs.Eqeqeq
), e, (_
, Aast.Null
)) ->
6552 condition_nullity ~nonnull
:(not tparamet
) env e
6556 | Aast.Binop
(Ast_defs.Eq None
, _
, _
) ->
6557 let (env, ety) = Env.expand_type
env ty in
6558 (match get_node
ety with
6559 | Tprim Tbool
-> (env, Local_id.Set.empty
)
6560 | _
-> condition_nullity ~nonnull
:tparamet
env te)
6561 | Aast.Binop
(((Ast_defs.Diff
| Ast_defs.Diff2
) as op
), e1
, e2) ->
6563 if Ast_defs.(equal_bop
op Diff
) then
6568 condition env (not tparamet
) (pty
, Aast.Binop
(op, e1
, e2))
6569 | Aast.Id
(_
, s) when SN.Rx.is_enabled
s ->
6570 (* when Rx\IS_ENABLED is false - switch env to non-reactive *)
6572 if not tparamet
then
6573 Env.set_env_reactive
env Nonreactive
6577 (env, Local_id.Set.empty
)
6578 (* Conjunction of conditions. Matches the two following forms:
6580 if (!(cond1 || cond2))
6582 | Aast.Binop
(((Ast_defs.Ampamp
| Ast_defs.Barbar
) as bop
), e1
, e2)
6583 when Bool.equal tparamet
Ast_defs.(equal_bop bop Ampamp
) ->
6584 let (env, lset1
) = condition env tparamet e1
in
6585 (* This is necessary in case there is an assignment in e2
6586 * We essentially redo what has been undone in the
6587 * `Binop (Ampamp|Barbar)` case of `expr` *)
6588 let (env, _
, _
) = expr env (Tast.to_nast_expr
e2) in
6589 let (env, lset2
) = condition env tparamet
e2 in
6590 (env, Local_id.Set.union lset1 lset2
)
6591 (* Disjunction of conditions. Matches the two following forms:
6593 if (!(cond1 && cond2))
6595 | Aast.Binop
(((Ast_defs.Ampamp
| Ast_defs.Barbar
) as bop
), e1
, e2)
6596 when Bool.equal tparamet
Ast_defs.(equal_bop bop Barbar
) ->
6597 let (env, lset1
, lset2
) =
6601 (* Either cond1 is true and we don't know anything about cond2... *)
6602 condition env tparamet e1
)
6604 (* ... Or cond1 is false and therefore cond2 must be true *)
6605 let (env, _lset
) = condition env (not tparamet
) e1
in
6606 (* Similarly to the conjunction case, there might be an assignment in
6607 cond2 which we must account for. Again we redo what has been undone in
6608 the `Binop (Ampamp|Barbar)` case of `expr` *)
6609 let (env, _
, _
) = expr env (Tast.to_nast_expr
e2) in
6610 condition env tparamet
e2)
6612 (env, Local_id.Set.union lset1 lset2
)
6613 | Aast.Call
(((p, _
), Aast.Id
(_
, f
)), _
, [lv
], None
)
6614 when tparamet
&& String.equal f
SN.StdlibFunctions.is_dict_or_darray
->
6615 safely_refine_is_array
env `HackDictOrDArray
p f lv
6616 | Aast.Call
(((p, _
), Aast.Id
(_
, f
)), _
, [lv
], None
)
6617 when tparamet
&& String.equal f
SN.StdlibFunctions.is_vec_or_varray
->
6618 safely_refine_is_array
env `HackVecOrVArray
p f lv
6619 | Aast.Call
(((p, _
), Aast.Id
(_
, f
)), _
, [lv
], None
)
6620 when tparamet
&& String.equal f
SN.StdlibFunctions.is_any_array
->
6621 safely_refine_is_array
env `AnyArray
p f lv
6622 | Aast.Call
(((p, _
), Aast.Id
(_
, f
)), _
, [lv
], None
)
6623 when tparamet
&& String.equal f
SN.StdlibFunctions.is_php_array
->
6624 safely_refine_is_array
env `PHPArray
p f lv
6626 ( (_
, Aast.Class_const
((_
, Aast.CI
(_
, class_name)), (_
, method_name
))),
6631 && String.equal
class_name SN.Shapes.cShapes
6632 && String.equal method_name
SN.Shapes.keyExists
->
6633 key_exists
env p shape
field
6634 | Aast.Unop
(Ast_defs.Unot
, e) -> condition env (not tparamet
) e
6635 | Aast.Is
(ivar
, h) when is_instance_var
(Tast.to_nast_expr ivar
) ->
6637 { (Phase.env_with_self
env) with from_class
= Some CIstatic
}
6639 let (env, hint_ty
) = Phase.localize_hint ~
ety_env env h in
6640 let reason = Reason.Ris
(fst
h) in
6641 let refine_type env hint_ty
=
6642 let (ivar_pos
, ivar_ty
) = fst ivar
in
6643 let (env, ivar
) = get_instance_var
env (Tast.to_nast_expr ivar
) in
6644 let (env, hint_ty
) =
6645 class_for_refinement
env p reason ivar_pos ivar_ty hint_ty
6647 let (env, refined_ty
) = Inter.intersect
env reason ivar_ty hint_ty
in
6648 (set_local
env ivar refined_ty
, Local_id.Set.singleton
(snd ivar
))
6650 let (env, hint_ty
) =
6651 if not tparamet
then
6652 Inter.non
env reason hint_ty ~approx
:TUtils.ApproxUp
6656 refine_type env hint_ty
6657 | _
-> (env, Local_id.Set.empty
)
6659 (** Transform a hint like `A<_>` to a localized type like `A<T#1>` for refinment of
6660 an instance variable. ivar_ty is the previous type of that instance variable. *)
6661 and class_for_refinement
env p reason ivar_pos ivar_ty hint_ty
=
6662 let (env, hint_ty
) = Env.expand_type
env hint_ty
in
6663 match (get_node ivar_ty
, get_node hint_ty
) with
6664 | (_
, Tclass
(((_
, cid) as _c
), _
, tyl
)) ->
6666 match Env.get_class
env cid with
6667 | Some
class_info ->
6668 let (env, tparams_with_new_names
, tyl_fresh
) =
6669 generate_fresh_tparams
env class_info reason tyl
6671 safely_refine_class_type
6679 tparams_with_new_names
6681 | None
-> (env, mk
(Reason.Rwitness ivar_pos
, Tobject
))
6683 | (Ttuple ivar_tyl
, Ttuple hint_tyl
)
6684 when Int.equal
(List.length ivar_tyl
) (List.length hint_tyl
) ->
6686 List.map2_env
env ivar_tyl hint_tyl
(fun env ivar_ty hint_ty
->
6687 class_for_refinement
env p reason ivar_pos ivar_ty hint_ty
)
6689 (env, MakeType.tuple
reason tyl
)
6690 | _
-> (env, hint_ty
)
6692 (** If we are dealing with a refinement like
6694 then class_info is the class info of MyClass and hint_tyl corresponds
6696 and generate_fresh_tparams
env class_info reason hint_tyl
=
6697 let tparams_len = List.length
(Cls.tparams
class_info) in
6698 let hint_tyl = List.take
hint_tyl tparams_len in
6699 let pad_len = tparams_len - List.length
hint_tyl in
6701 List.map hint_tyl (fun x -> Some
x) @ List.init pad_len (fun _
-> None
)
6703 let replace_wildcard env hint_ty tp
=
6705 tp_name
= (_
, tparam_name
);
6706 tp_reified
= reified
;
6713 Attributes.mem
SN.UserAttributes.uaEnforceable tp_user_attributes
6716 Attributes.mem
SN.UserAttributes.uaNewable tp_user_attributes
6721 match get_node
ty with
6722 | Tgeneric
(name, _targs
) when Env.is_fresh_generic_parameter
name ->
6723 (* TODO(T69551141) handle type arguments above and below *)
6724 (env, (Some
(tp
, name), MakeType.generic
reason name))
6725 | _
-> (env, (None
, ty))
6728 let (env, new_name
) =
6729 Env.add_fresh_generic_parameter
6736 (* TODO(T69551141) handle type arguments for Tgeneric *)
6737 (env, (Some
(tp
, new_name
), MakeType.generic
reason new_name
))
6739 let (env, tparams_and_tyl
) =
6740 List.map2_env
env hint_tyl (Cls.tparams
class_info) ~f
:replace_wildcard
6742 let (tparams_with_new_names
, tyl_fresh
) = List.unzip tparams_and_tyl
in
6743 (env, tparams_with_new_names
, tyl_fresh
)
6745 and safely_refine_class_type
6753 (tparams_with_new_names
: (decl_tparam
* string) option list
)
6755 (* Type of variable in block will be class name
6756 * with fresh type parameters *)
6758 mk
(get_reason
obj_ty, Tclass
(class_name, Nonexact
, tyl_fresh
))
6760 let tparams = Cls.tparams class_info in
6761 (* Add in constraints as assumptions on those type parameters *)
6764 type_expansions
= [];
6765 substs
= Subst.make_locl
tparams tyl_fresh
;
6767 (* In case `this` appears in constraints *)
6770 on_error
= Errors.unify_error_at
p;
6773 let add_bounds env (t
, ty_fresh
) =
6774 List.fold_left t
.tp_constraints ~
init:env ~f
:(fun env (ck
, ty) ->
6775 (* Substitute fresh type parameters for
6776 * original formals in constraint *)
6777 let (env, ty) = Phase.localize ~
ety_env env ty in
6778 SubType.add_constraint
p env ck ty_fresh
ty)
6781 List.fold_left
(List.zip_exn
tparams tyl_fresh
) ~f
:add_bounds ~
init:env
6783 (* Finally, if we have a class-test on something with static classish type,
6784 * then we can chase the hierarchy and decompose the types to deduce
6785 * further assumptions on type parameters. For example, we might have
6786 * class B<Tb> { ... }
6787 * class C extends B<int>
6788 * and have obj_ty = C and x_ty = B<T> for a generic parameter Aast.
6789 * Then SubType.add_constraint will deduce that T=int and add int as
6790 * both lower and upper bound on T in env.lenv.tpenv
6792 let (env, supertypes
) = TUtils.get_concrete_supertypes
env ivar_ty
in
6794 List.fold_left supertypes ~
init:env ~f
:(fun env ty ->
6795 SubType.add_constraint
p env Ast_defs.Constraint_as
obj_ty ty)
6797 (* It's often the case that the fresh name isn't necessary. For
6798 * example, if C<T> extends B<T>, and we have $x:B<t> for some type t
6799 * then $x is C should refine to $x:C<t>.
6800 * We take a simple approach:
6801 * For a fresh type parameter T#1, if
6802 * - There is an eqality constraint T#1 = t,
6803 * - T#1 is covariant, and T#1 has upper bound t (or mixed if absent)
6804 * - T#1 is contravariant, and T#1 has lower bound t (or nothing if absent)
6805 * then replace T#1 with t.
6806 * This is done in Type_parameter_env_ops.simplify_tpenv
6808 let (env, tparam_substs
) =
6809 Type_parameter_env_ops.simplify_tpenv
6811 (List.zip_exn tparams_with_new_names tyl_fresh
)
6815 List.map2_exn
tyl_fresh tparams_with_new_names ~f
:(fun orig_ty tparam_opt
->
6816 match tparam_opt
with
6818 | Some
(_tp
, name) -> SMap.find
name tparam_substs
)
6820 let obj_ty_simplified =
6821 mk
(get_reason
obj_ty, Tclass
(class_name, Nonexact
, tyl_fresh))
6823 (env, obj_ty_simplified)
6825 and is_instance_var
= function
6826 | (_
, (Lvar _
| This
| Dollardollar _
)) -> true
6827 | (_
, Obj_get
((_
, This
), (_
, Id _
), _
, _
)) -> true
6828 | (_
, Obj_get
((_
, Lvar _
), (_
, Id _
), _
, _
)) -> true
6829 | (_
, Class_get
(_
, _
, _
)) -> true
6832 and get_instance_var
env = function
6833 | (p, Class_get
((_
, cname
), CGstring
(_
, member_name
), _
)) ->
6834 let (env, local) = Env.FakeMembers.make_static
env cname member_name
p in
6838 ((((_
, This
) | (_
, Lvar _
)) as obj
), (_
, Id
(_
, member_name
)), _
, _
) )
6840 let (env, local) = Env.FakeMembers.make
env obj member_name
p in
6842 | (_
, Dollardollar
(p, x))
6843 | (_
, Lvar
(p, x)) ->
6845 | (p, This
) -> (env, (p, this))
6846 | _
-> failwith
"Should only be called when is_instance_var is true"
6848 (* Refine type for is_array, is_vec, is_keyset and is_dict tests
6849 * `pred_name` is the function name itself (e.g. 'is_vec')
6850 * `p` is position of the function name in the source
6851 * `arg_expr` is the argument to the function
6853 and safely_refine_is_array
env ty p pred_name arg_expr
=
6854 refine_lvalue_type
env arg_expr ~
refine:(fun env arg_ty
->
6855 let r = Reason.Rpredicated
(p, pred_name
) in
6856 let (env, tarrkey_name
) =
6857 Env.add_fresh_generic_parameter
6864 (* TODO(T69551141) handle type arguments for Tgeneric *)
6865 let tarrkey = MakeType.generic
r tarrkey_name
in
6867 SubType.add_constraint
6870 Ast_defs.Constraint_as
6872 (MakeType.arraykey r)
6874 let (env, tfresh_name
) =
6875 Env.add_fresh_generic_parameter
6882 (* TODO(T69551141) handle type arguments for Tgeneric *)
6883 let tfresh = MakeType.generic
r tfresh_name
in
6884 (* If we're refining the type for `is_array` we have a slightly more
6885 * involved process. Let's separate out that logic so we can re-use it.
6888 let safe_isarray_enabled =
6889 TypecheckerOptions.experimental_feature_enabled
6891 TypecheckerOptions.experimental_isarray
6893 let tk = MakeType.arraykey Reason.(Rvarray_or_darray_key
(to_pos
r)) in
6895 if safe_isarray_enabled then
6898 mk
(r, TUtils.tany
env)
6900 MakeType.varray_or_darray
r tk tv
6902 (* This is the refined type of e inside the branch *)
6905 | `HackDict
-> MakeType.dict
r tarrkey tfresh
6906 | `HackVec
-> MakeType.vec
r tfresh
6907 | `HackKeyset
-> MakeType.keyset
r tarrkey
6908 | `PHPArray
-> array_ty
6909 | `AnyArray
-> MakeType.any_array
r tarrkey tfresh
6910 | `HackDictOrDArray
->
6913 [MakeType.dict
r tarrkey tfresh; MakeType.darray
r tarrkey tfresh]
6914 | `HackVecOrVArray
->
6915 MakeType.union r [MakeType.vec
r tfresh; MakeType.varray
r tfresh]
6917 let ((arg_pos
, _
), _
) = arg_expr
in
6918 let (env, hint_ty) =
6919 class_for_refinement
env p r arg_pos arg_ty
hint_ty
6921 (* Add constraints on generic parameters that must
6922 * hold for refined_ty <:arg_ty. For example, if arg_ty is Traversable<T>
6923 * and refined_ty is keyset<T#1> then we know T#1 <: T.
6924 * See analogous code in safely_refine_class_type.
6926 let (env, supertypes
) = TUtils.get_concrete_supertypes
env arg_ty
in
6928 List.fold_left supertypes ~
init:env ~f
:(fun env ty ->
6929 SubType.add_constraint
p env Ast_defs.Constraint_as
hint_ty ty)
6931 Inter.intersect ~
r env hint_ty arg_ty
)
6933 and key_exists
env pos shape
field =
6934 let field = Tast.to_nast_expr
field in
6935 refine_lvalue_type
env shape ~
refine:(fun env shape_ty
->
6936 match TUtils.shape_field_name
env field with
6937 | None
-> (env, shape_ty
)
6938 | Some
field_name ->
6939 Typing_shapes.refine_shape
field_name pos env shape_ty
)
6941 and string2
env idl
=
6943 List.fold_left idl ~
init:(env, []) ~f
:(fun (env, tel
) x ->
6944 let (env, te, ty) = expr env x in
6946 let env = Typing_substring.sub_string
p env ty in
6951 and user_attribute
env ua
=
6952 let (env, typed_ua_params
) =
6953 List.map_env
env ua
.ua_params
(fun env e ->
6954 let (env, te, _
) = expr env e in
6957 (env, { Aast.ua_name
= ua
.ua_name
; Aast.ua_params
= typed_ua_params
})
6959 and file_attributes
env file_attrs
=
6960 (* Disable checking of error positions, as file attributes have spans that
6961 * aren't subspans of the class or function into which they are copied *)
6962 Errors.run_with_span
Pos.none
@@ fun () ->
6963 let uas = List.concat_map ~f
:(fun fa
-> fa
.fa_user_attributes
) file_attrs
in
6964 let env = attributes_check_def
env SN.AttributeKinds.file
uas in
6965 List.map_env
env file_attrs
(fun env fa
->
6966 let (env, user_attributes
) =
6967 List.map_env
env fa
.fa_user_attributes user_attribute
6969 let env = set_tcopt_unstable_features env fa
in
6972 Aast.fa_user_attributes
= user_attributes
;
6973 Aast.fa_namespace
= fa
.fa_namespace
;
6976 and type_param
env t
=
6978 attributes_check_def
env SN.AttributeKinds.typeparam t
.tp_user_attributes
6980 let (env, user_attributes
) =
6981 List.map_env
env t
.tp_user_attributes user_attribute
6983 let (env, tp_parameters
) = List.map_env
env t
.tp_parameters type_param
in
6986 Aast.tp_variance
= t
.tp_variance
;
6987 Aast.tp_name
= t
.tp_name
;
6989 Aast.tp_constraints
= t
.tp_constraints
;
6990 Aast.tp_reified
= reify_kind t
.tp_reified
;
6991 Aast.tp_user_attributes
= user_attributes
;
6994 and typedef_def ctx typedef
=
6995 let env = EnvFromDef.typedef_env ~origin
:Decl_counters.TopLevel ctx typedef
in
6997 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
6998 (fst typedef
.t_name
)
7003 Typing_check_decls.typedef
env typedef
;
7004 Typing_variance.typedef
env (snd typedef
.t_name
);
7007 t_name
= (t_pos
, t_name
);
7009 t_constraint
= tcstr
;
7011 t_user_attributes
= _
;
7020 let ty = Decl_hint.hint
env.decl_env hint
in
7021 (* We want to report cycles through the definition *)
7023 Phase.localize_with_self
env ~
pos:t_pos ~report_cycle
:(t_pos
, t_name
) ty
7028 let cstr = Decl_hint.hint
env.decl_env tcstr
in
7029 let (env, cstr) = Phase.localize_with_self ~
pos:t_pos
env cstr in
7032 Reason.URnewtype_cstr
7036 Errors.newtype_alias_must_satisfy_constraint
7041 | (pos, Hshape
{ nsi_allows_unknown_fields
= _
; nsi_field_map
}) ->
7042 let get_name sfi
= sfi
.sfi_name
in
7043 check_shape_keys_validity
env pos (List.map ~f
:get_name nsi_field_map
)
7047 attributes_check_def
7049 SN.AttributeKinds.typealias
7050 typedef
.t_user_attributes
7052 let (env, tparams) = List.map_env
env typedef
.t_tparams type_param
in
7053 let (env, user_attributes
) =
7054 List.map_env
env typedef
.t_user_attributes user_attribute
7057 Aast.t_annotation
= Env.save
(Env.get_tpenv
env) env;
7058 Aast.t_name
= typedef
.t_name
;
7059 Aast.t_mode
= typedef
.t_mode
;
7060 Aast.t_vis
= typedef
.t_vis
;
7061 Aast.t_user_attributes
= user_attributes
;
7062 Aast.t_constraint
= typedef
.t_constraint
;
7063 Aast.t_kind
= typedef
.t_kind
;
7064 Aast.t_tparams
= tparams;
7065 Aast.t_namespace
= typedef
.t_namespace
;
7066 Aast.t_span
= typedef
.t_span
;
7067 Aast.t_emit_id
= typedef
.t_emit_id
;
7070 (* Calls the method of a class, but allows the f callback to override the
7071 * return value type *)
7072 and overload_function
7073 make_call fpos
p env (cpos
, class_id
) method_id
el unpacked_element f
=
7074 let (env, _tal
, tcid
, ty) =
7075 static_class_id ~check_constraints
:false cpos
env [] class_id
7077 let (env, _tel
, _
) = exprs env el in
7078 let (env, (fty, tal
)) =
7082 ~coerce_from_ty
:None
7088 let (env, (tel
, typed_unpack_element
, res
)) =
7089 call ~
expected:None
p env fty el unpacked_element
7091 let (env, ty) = f
env fty res
el in
7092 let (env, fty) = Env.expand_type
env fty in
7094 map_ty
fty ~f
:(function
7095 | Tfun
ft -> Tfun
{ ft with ft_ret = MakeType.unenforced
ty }
7098 let te = Tast.make_typed_expr fpos
fty (Aast.Class_const
(tcid
, method_id
)) in
7099 make_call env te tal tel typed_unpack_element
ty
7101 and update_array_type ?lhs_of_null_coalesce
p env e1
valkind =
7104 | `lvalue_subexpr
->
7105 let (env, te1, ty1
) =
7106 raw_expr ~
valkind:`lvalue_subexpr ~check_defined
:true env e1
7110 | (_
, Lvar
(_
, x)) ->
7111 (* type_mapper has updated the type in ty1 typevars, but we
7112 need to update the local variable type too *)
7113 let env = set_valid_rvalue
p env x ty1
in
7115 | _
-> (env, te1, ty1
)
7117 | _
-> raw_expr ?lhs_of_null_coalesce
env e1
7120 let expr ?
expected env e =
7121 Typing_env.with_origin2
env Decl_counters.Body
(fun env ->
7122 expr ?
expected env e)
7125 Typing_env.with_origin
env Decl_counters.Body
(fun env -> stmt env st
)