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 let tobj = mk
(Reason.Rwitness
p, Tobject
) in
1608 let env = Type.sub_type
p Reason.URclone
env ty tobj Errors.unify_error
in
1609 make_result
env p (Aast.Clone te
) ty
1611 if Option.is_none
(Env.get_self_ty
env) then Errors.this_var_outside_class
p;
1612 if not accept_using_var
then check_escaping_var
env (p, this
);
1613 let ty = Env.get_local
env this
in
1614 let r = Reason.Rwitness
p in
1615 let ty = mk
(r, TUtils.this_of
(mk
(r, get_node
ty))) in
1616 make_result
env p Aast.This
ty
1617 | True
-> make_result
env p Aast.True
(MakeType.bool (Reason.Rwitness
p))
1618 | False
-> make_result
env p Aast.False
(MakeType.bool (Reason.Rwitness
p))
1619 (* TODO TAST: consider checking that the integer is in range. Right now
1620 * it's possible for HHVM to fail on well-typed Hack code
1622 | Int s
-> make_result
env p (Aast.Int s
) (MakeType.int (Reason.Rwitness
p))
1624 make_result
env p (Aast.Float s
) (MakeType.float (Reason.Rwitness
p))
1625 (* TODO TAST: consider introducing a "null" type, and defining ?t to
1628 | Null
-> make_result
env p Aast.Null
(MakeType.null
(Reason.Rwitness
p))
1630 make_result
env p (Aast.String s
) (MakeType.string (Reason.Rwitness
p))
1632 let (env, tel
) = string2
env idl
in
1633 make_result
env p (Aast.String2 tel
) (MakeType.string (Reason.Rwitness
p))
1634 | PrefixedString
(n
, e
) ->
1635 if String.( <> ) n
"re" then (
1636 Errors.experimental_feature
1638 "String prefixes other than `re` are not yet supported.";
1639 expr_error env Reason.Rnone outer
1641 let (env, te
, ty) = expr env e
in
1643 let env = Typing_substring.sub_string
pe env ty in
1651 (Aast.PrefixedString
(n
, te
))
1652 (Typing_regex.type_pattern e
)
1654 | Pcre.Error
(Pcre.BadPattern
(s
, i
)) ->
1655 let s = s ^
" [" ^ string_of_int i ^
"]" in
1656 Errors.bad_regex_pattern
pe s;
1657 expr_error env (Reason.Rregex
pe) e
1658 | Typing_regex.Empty_regex_pattern
->
1659 Errors.bad_regex_pattern
pe "This pattern is empty";
1660 expr_error env (Reason.Rregex
pe) e
1661 | Typing_regex.Missing_delimiter
->
1662 Errors.bad_regex_pattern
pe "Missing delimiter(s)";
1663 expr_error env (Reason.Rregex
pe) e
1664 | Typing_regex.Invalid_global_option
->
1665 Errors.bad_regex_pattern
pe "Invalid global option(s)";
1666 expr_error env (Reason.Rregex
pe) e
1669 Errors.re_prefixed_non_string
pe "Strings with embedded expressions";
1670 expr_error env (Reason.Rregex
pe) e
1672 Errors.re_prefixed_non_string
pe "Non-strings";
1673 expr_error env (Reason.Rregex
pe) e
)
1675 let (env, fty
, _tal
) = fun_type_of_id
env x
[] [] in
1676 make_result
env p (Aast.Fun_id x
) fty
1677 | Id
((cst_pos
, cst_name
) as id) ->
1678 (match Env.get_gconst
env cst_name
with
1679 | None
when Partial.should_check_error
(Env.get_mode
env) 4106 ->
1680 Errors.unbound_global cst_pos
;
1681 let ty = err_witness env cst_pos
in
1682 make_result
env cst_pos
(Aast.Id
id) ty
1683 | None
-> make_result
env p (Aast.Id
id) (Typing_utils.mk_tany
env cst_pos
)
1685 let (env, ty) = Phase.localize_with_self ~
pos:p env ty in
1686 make_result
env p (Aast.Id
id) ty)
1687 | Method_id
(instance
, meth
) ->
1688 (* Method_id is used when creating a "method pointer" using the magic
1689 * inst_meth function.
1691 * Typing this is pretty simple, we just need to check that instance->meth
1692 * is public+not static and then return its type.
1694 let (env, te
, ty1
) = expr env instance
in
1695 let (env, (result
, _tal
)) =
1701 ~coerce_from_ty
:None
1712 Env.FakeMembers.check_instance_invalid
env instance
(snd meth
) result
1714 make_result
env p (Aast.Method_id
(te
, meth
)) result
1715 | Method_caller
(((pos, class_name) as pos_cname
), meth_name
) ->
1716 (* meth_caller('X', 'foo') desugars to:
1719 let class_ = Env.get_class
env class_name in
1721 | None
-> unbound_name env pos_cname outer
1723 (* Create a class type for the given object instantiated with unresolved
1724 * types for its type parameters.
1727 if Ast_defs.is_c_trait
(Cls.kind
class_) then
1728 Errors.meth_caller_trait
pos class_name
1731 List.map_env
env (Cls.tparams
class_) (fun env _
->
1732 Env.fresh_type
env p)
1735 List.map (Cls.tparams
class_) (fun { tp_name
= (p, n
); _
} ->
1736 (* TODO(T69551141) handle type arguments for Tgeneric *)
1737 MakeType.generic
(Reason.Rwitness
p) n
)
1739 let obj_type = MakeType.apply
(Reason.Rwitness
p) pos_cname
params in
1742 (Phase.env_with_self
env) with
1743 substs
= TUtils.make_locl_subst_for_class_tparams
class_ tvarl
;
1746 let (env, local_obj_ty
) = Phase.localize ~
ety_env env obj_type in
1747 let (env, (fty
, _tal
)) =
1752 ~coerce_from_ty
:None
1756 (CI
(pos, class_name))
1760 let (env, fty
) = Env.expand_type
env fty
in
1761 (match deref fty
with
1762 | (reason
, Tfun ftype
) ->
1763 (* We are creating a fake closure:
1764 * function(Class $x, arg_types_of(Class::meth_name))
1765 : return_type_of(Class::meth_name)
1770 substs
= TUtils.make_locl_subst_for_class_tparams
class_ tvarl
;
1774 Phase.check_tparams_constraints
1778 (Cls.tparams
class_)
1780 let (env, local_obj_ty
) = Phase.localize ~
ety_env env obj_type in
1781 let local_obj_fp = TUtils.default_fun_param local_obj_ty
in
1782 let fty = { ftype
with ft_params
= local_obj_fp :: ftype
.ft_params
} in
1785 ft_arity
= fty.ft_arity
;
1786 ft_tparams
= fty.ft_tparams
;
1787 ft_where_constraints
= fty.ft_where_constraints
;
1788 ft_params
= fty.ft_params
;
1789 ft_implicit_params
= fty.ft_implicit_params
;
1790 ft_ret
= fty.ft_ret
;
1791 (* propagate 'is_coroutine' from the method being called*)
1792 ft_flags
= fty.ft_flags
;
1793 ft_reactive
= fty.ft_reactive
;
1794 ft_ifc_decl
= fty.ft_ifc_decl
;
1800 (Aast.Method_caller
(pos_cname
, meth_name
))
1801 (mk
(reason
, Tfun
caller))
1803 (* This can happen if the method lives in PHP *)
1807 (Aast.Method_caller
(pos_cname
, meth_name
))
1808 (Typing_utils.mk_tany
env pos)))
1809 | FunctionPointer
(FP_class_const
((cpos
, cid), meth
), targs
) ->
1810 let (env, _
, ce
, cty
) =
1811 static_class_id ~check_constraints
:true cpos
env [] cid
1813 let (env, (fpty
, tal
)) =
1817 ~incl_tc
:false (* What is this? *)
1818 ~coerce_from_ty
:None
(* What is this? *)
1819 ~explicit_targs
:targs
1820 ~function_pointer
:true
1826 let env = Env.set_tyvar_variance
env fpty
in
1827 let fpty = set_function_pointer
fpty in
1831 (Aast.FunctionPointer
(FP_class_const
(ce
, meth
), tal
))
1833 | Smethod_id
((pc
, cid), meth
) ->
1834 (* Smethod_id is used when creating a "method pointer" using the magic
1835 * class_meth function.
1837 * Typing this is pretty simple, we just need to check that c::meth is
1838 * public+static and then return its type.
1840 let (class_, classname
) =
1844 (Env.get_self_class
env, Env.get_self_id
env)
1845 | CI
(_
, const
) when String.equal const
SN.PseudoConsts.g__CLASS__
->
1846 (Env.get_self_class
env, Env.get_self_id
env)
1847 | CI
(_
, id) -> (Env.get_class
env id, Some
id)
1850 let classname = Option.value classname ~default
:"" in
1853 (* The class given as a static string was not found. *)
1854 unbound_name env (pc
, classname) outer
1856 let smethod = Env.get_static_member
true env class_ (snd meth
) in
1859 (* The static method wasn't found. *)
1860 TOG.smember_not_found
1867 expr_error env Reason.Rnone outer
1868 | Some
({ ce_type
= (lazy ty); ce_pos
= (lazy ce_pos
); _
} as ce
) ->
1870 if get_ce_abstract ce
then
1873 | _
-> Errors.class_meth_abstract_call
classname (snd meth
) p ce_pos
1875 let ce_visibility = ce
.ce_visibility in
1876 let ce_deprecated = ce
.ce_deprecated in
1877 let (env, _tal
, te
, cid_ty
) =
1878 static_class_id ~check_constraints
:true pc
env [] cid
1880 let (env, cid_ty
) = Env.expand_type
env cid_ty
in
1882 match get_node cid_ty
with
1883 | Tclass
(_
, _
, tyargs) -> tyargs
1888 type_expansions
= [];
1889 substs
= TUtils.make_locl_subst_for_class_tparams
class_ tyargs;
1891 from_class
= Some
cid;
1893 on_error
= Errors.unify_error_at
p;
1896 (match deref
ty with
1899 Typing_enforceability.compute_enforced_and_pessimize_fun_type
env ft
1901 let def_pos = ce_pos
in
1903 Phase.localize_targs
1904 ~check_well_kinded
:true
1908 ~use_name
:(strip_ns
(snd meth
))
1919 use_name
= strip_ns
(snd meth
);
1921 explicit_targs
= tal
;
1928 let ty = mk
(r, Tfun
ft) in
1929 let use_pos = fst meth
in
1930 TVis.check_deprecated ~
use_pos ~
def_pos ce_deprecated;
1931 (match ce_visibility with
1932 | Vpublic
-> make_result
env p (Aast.Smethod_id
(te
, meth
)) ty
1934 Errors.private_class_meth ~
def_pos ~
use_pos;
1935 expr_error env r outer
1937 Errors.protected_class_meth ~
def_pos ~
use_pos;
1938 expr_error env r outer
)
1940 Errors.internal_error
p "We have a method which isn't callable";
1941 expr_error env r outer
)))
1943 let r = Reason.Rplaceholder
p in
1944 let ty = MakeType.void
r in
1945 make_result
env p (Aast.Lplaceholder
p) ty
1946 | Dollardollar _
when phys_equal
valkind `lvalue
->
1947 Errors.dollardollar_lvalue
p;
1948 expr_error env (Reason.Rwitness
p) outer
1949 | Dollardollar
id ->
1950 let ty = Env.get_local_check_defined
env id in
1951 let env = might_throw
env in
1952 make_result
env p (Aast.Dollardollar
id) ty
1953 | Lvar
((_
, x
) as id) ->
1954 if not accept_using_var
then check_escaping_var
env id;
1956 if check_defined
then
1957 Env.get_local_check_defined
env id
1961 make_result
env p (Aast.Lvar
id) ty
1963 let (env, tel
, tyl
) =
1966 | `lvalue_subexpr
->
1969 let (env, expected) = expand_expected_and_get_node
env expected in
1970 (match expected with
1971 | Some
(pos, ur, _
, Ttuple expected_tyl
) ->
1972 exprs_expected
(pos, ur, expected_tyl
) env el
1973 | _
-> exprs env el
)
1975 let ty = MakeType.tuple
(Reason.Rwitness
p) tyl
in
1976 make_result
env p (Aast.List tel
) ty
1977 | Pair
(th
, e1
, e2) ->
1978 let (env, expected1
, expected2
, th
) =
1980 | Some
((_
, t1
), (_
, t2
)) ->
1981 let (env, t1
, t1_expected
) = localize_targ
env t1
in
1982 let (env, t2
, t2_expected
) = localize_targ
env t2
in
1983 (env, Some t1_expected
, Some t2_expected
, Some
(t1
, t2
))
1985 (* Use expected type to determine expected element types *)
1986 (match expand_expected_and_get_node
env expected with
1987 | (env, Some
(pos, reason
, _ty
, Tclass
((_
, k
), _
, [ty1
; ty2
])))
1988 when String.equal k
SN.Collections.cPair
->
1989 let ty1_expected = ExpectedTy.make
pos reason ty1
in
1990 let ty2_expected = ExpectedTy.make
pos reason ty2
in
1991 (env, Some
ty1_expected, Some
ty2_expected, None
)
1992 | _
-> (env, None
, None
, None
))
1994 let (env, te1
, ty1
) = expr ?
expected:expected1
env e1
in
1995 let (env, te2
, ty2
) = expr ?
expected:expected2
env e2 in
2001 ~reason
:Reason.URpair_value
2003 (Reason.Rtype_variable_generics
(p1, "T1", "Pair"))
2010 ~reason
:Reason.URpair_value
2012 (Reason.Rtype_variable_generics
(p2, "T2", "Pair"))
2016 let ty = MakeType.pair
(Reason.Rwitness
p) ty1 ty2
in
2017 make_result
env p (Aast.Pair
(th
, te1
, te2
)) ty
2018 | Array_get
(e
, None
) ->
2019 let (env, te
, _
) = update_array_type
p env e
valkind in
2020 let env = might_throw
env in
2021 (* NAST check reports an error if [] is used for reading in an
2023 let ty = err_witness env p in
2024 make_result
env p (Aast.Array_get
(te
, None
)) ty
2025 | Array_get
(e1
, Some
e2) ->
2026 let (env, te1
, ty1
) =
2027 update_array_type ?lhs_of_null_coalesce
p env e1
valkind
2029 let (env, te2
, ty2
) = expr env e2 in
2030 let env = might_throw
env in
2031 let is_lvalue = phys_equal
valkind `lvalue
in
2033 Typing_array_access.array_get
2036 ?lhs_of_null_coalesce
2043 make_result
env p (Aast.Array_get
(te1
, Some te2
)) ty
2044 | Call
((pos_id
, Id
((_
, s) as id)), [], el
, None
) when is_pseudo_function
s
2046 let (env, tel
, tys
) = exprs ~accept_using_var
:true env el
in
2048 if String.equal
s SN.PseudoFunctions.hh_show
then (
2049 List.iter tys
(Typing_log.hh_show
p env);
2051 ) else if String.equal
s SN.PseudoFunctions.hh_show_env
then (
2052 Typing_log.hh_show_env
p env;
2054 ) else if String.equal
s SN.PseudoFunctions.hh_log_level
then
2056 | [(_
, String key_str
); (_
, Int level_str
)] ->
2057 Env.set_log_level
env key_str
(int_of_string level_str
)
2059 else if String.equal
s SN.PseudoFunctions.hh_force_solve
then
2060 Typing_solver.solve_all_unsolved_tyvars
env Errors.unify_error
2061 else if String.equal
s SN.PseudoFunctions.hh_loop_forever
then (
2067 let ty = MakeType.void
(Reason.Rwitness
p) in
2072 ( Tast.make_typed_expr pos_id
(TUtils.mk_tany
env pos_id
) (Aast.Id
id),
2077 | Call
(e
, explicit_targs
, el
, unpacked_element
) ->
2080 | Id
(pos, f
) when String.equal f
SN.SpecialFunctions.echo
->
2081 Typing_local_ops.enforce_output
pos env
2084 let env = might_throw
env in
2098 | FunctionPointer
(FP_id fid
, targs
) ->
2099 let (env, fty, targs
) = fun_type_of_id
env fid targs
[] in
2100 let e = Aast.FunctionPointer
(FP_id fid
, targs
) in
2101 let fty = set_function_pointer
fty in
2102 make_result
env p e fty
2103 | Binop
(Ast_defs.QuestionQuestion
, e1
, e2) ->
2104 let (env, te1
, ty1
) = raw_expr ~lhs_of_null_coalesce
:true env e1
in
2105 let (env, te2
, ty2
) = expr ?
expected env e2 in
2106 let (env, ty1'
) = Env.fresh_type
env (fst e1
) in
2111 (MakeType.nullable_locl
Reason.Rnone ty1'
)
2114 (* Essentially mimic a call to
2115 * function coalesce<Tr, Ta as Tr, Tb as Tr>(?Ta, Tb): Tr
2116 * That way we let the constraint solver take care of the union logic.
2118 let (env, ty_result
) = Env.fresh_type
env (fst
e2) in
2119 let env = SubType.sub_type
env ty1' ty_result
Errors.unify_error
in
2120 let env = SubType.sub_type
env ty2 ty_result
Errors.unify_error
in
2124 (Aast.Binop
(Ast_defs.QuestionQuestion
, te1
, te2
))
2126 (* For example, e1 += e2. This is typed and translated as if
2127 * written e1 = e1 + e2.
2128 * TODO TAST: is this right? e1 will get evaluated more than once
2130 | Binop
(Ast_defs.Eq
(Some op
), e1
, e2) ->
2132 match (op
, snd e1
) with
2133 | (Ast_defs.QuestionQuestion
, Class_get _
) ->
2134 Errors.experimental_feature
2136 "null coalesce assignment operator with static properties";
2137 expr_error env Reason.Rnone outer
2140 (p, Binop
(Ast_defs.Eq None
, e1
, (p, Binop
(op
, e1
, e2))))
2142 let (env, te_fake
, ty) = raw_expr env e_fake in
2144 match snd te_fake
with
2145 | Aast.Binop
(_
, te1
, (_
, Aast.Binop
(_
, _
, te2
))) ->
2146 let te = Aast.Binop
(Ast_defs.Eq
(Some op
), te1
, te2
) in
2147 make_result
env p te ty
2151 | Binop
(Ast_defs.Eq None
, e1
, e2) ->
2152 let (env, te2
, ty2
) = raw_expr env e2 in
2153 let (env, te1
, ty) = assign
p env e1 ty2
in
2155 if Env.env_local_reactive
env then
2156 Typing_mutability.handle_assignment_mutability
env te1
(Some
(snd te2
))
2160 make_result
env p (Aast.Binop
(Ast_defs.Eq None
, te1
, te2
)) ty
2161 | Binop
(((Ast_defs.Ampamp
| Ast_defs.Barbar
) as bop
), e1
, e2) ->
2162 let c = Ast_defs.(equal_bop bop Ampamp
) in
2163 let (env, te1
, _
) = expr env e1
in
2164 let lenv = env.lenv in
2165 let (env, _lset
) = condition env c te1
in
2166 let (env, te2
, _
) = expr env e2 in
2167 let env = { env with lenv } in
2171 (Aast.Binop
(bop
, te1
, te2
))
2172 (MakeType.bool (Reason.Rlogic_ret
p))
2173 | Binop
(bop
, e1
, e2) ->
2174 let (env, te1
, ty1
) = raw_expr env e1
in
2175 let (env, te2
, ty2
) = raw_expr env e2 in
2178 (* TODO: This could be less conservative: we only need to account for
2179 * the possibility of exception if the operator is `/` or `/=`.
2184 | _
-> might_throw
env
2186 let (env, te3
, ty) =
2187 Typing_arithmetic.binop
p env bop
(fst e1
) te1 ty1
(fst
e2) te2 ty2
2190 | Pipe
(e0
, e1
, e2) ->
2191 (* If it weren't for local variable assignment or refinement the pipe
2192 * expression e1 |> e2 could be typed using this rule (E is environment with
2193 * types for locals):
2195 * E |- e1 : ty1 E[$$:ty1] |- e2 : ty2
2196 * --------------------------------------
2199 * The possibility of e2 changing the types of locals in E means that E
2200 * can evolve, and so we need to restore $$ to its original state.
2202 let (env, te1
, ty1
) = expr env e1
in
2203 let dd_var = Local_id.make_unscoped
SN.SpecialIdents.dollardollar
in
2205 if Env.is_local_defined
env dd_var then
2206 Some
(Env.get_local_pos
env dd_var)
2210 let env = Env.set_local
env dd_var ty1
Pos.none
in
2211 let (env, te2
, ty2
) = expr env e2 in
2213 match dd_old_ty with
2214 | None
-> Env.unset_local
env dd_var
2215 | Some
(ty, pos) -> Env.set_local
env dd_var ty pos
2217 make_result
env p (Aast.Pipe
(e0
, te1
, te2
)) ty2
2219 let (env, te, ty) = raw_expr env e in
2220 let env = might_throw
env in
2221 Typing_arithmetic.unop
p env uop
te ty
2222 | Eif
(c, e1
, e2) -> eif
env ~
expected ?in_await
p c e1
e2
2223 | Class_const
((p, CI sid
), pstr
)
2224 when String.equal
(snd pstr
) "class" && Env.is_typedef
env (snd sid
) ->
2226 match Env.get_typedef
env (snd sid
) with
2227 | Some
{ td_tparams
= tparaml
; _
} ->
2228 (* Typedef type parameters cannot have constraints *)
2233 fun { tp_name
= (p, x
); _
} ->
2234 (* TODO(T69551141) handle type arguments for Tgeneric *)
2235 MakeType.generic
(Reason.Rwitness
p) x
2239 let tdef = mk
(Reason.Rwitness
p, Tapply
(sid
, params)) in
2241 mk
(Reason.Rwitness
p, Tapply
((p, SN.Classes.cTypename
), [tdef]))
2243 let (env, tparams
) =
2244 List.map_env
env tparaml
(fun env tp
->
2245 Env.fresh_type
env (fst tp
.tp_name
))
2249 (Phase.env_with_self
env) with
2250 substs
= Subst.make_locl tparaml tparams
;
2254 Phase.check_tparams_constraints ~
use_pos:p ~
ety_env env tparaml
2256 let (env, ty) = Phase.localize ~
ety_env env typename in
2257 make_result
env p (Class_const
(((p, ty), CI sid
), pstr
)) ty
2259 (* Should not expect None as we've checked whether the sid is a typedef *)
2260 expr_error env (Reason.Rwitness
p) outer
2262 | Class_const
(cid, mid
) -> class_const
env p (cid, mid
)
2263 | Class_get
((cpos
, cid), CGstring mid
, in_parens
)
2264 when Env.FakeMembers.is_valid_static
env cid (snd mid
) ->
2265 let (env, local
) = Env.FakeMembers.make_static
env cid (snd mid
) p in
2266 let local = (p, Lvar
(p, local)) in
2267 let (env, _
, ty) = expr env local in
2268 let (env, _tal
, te, _
) =
2269 static_class_id ~check_constraints
:false cpos
env [] cid
2271 make_result
env p (Aast.Class_get
(te, Aast.CGstring mid
, in_parens
)) ty
2272 | Class_get
((cpos
, cid), CGstring
((ppos
, _
) as mid
), in_parens
) ->
2273 let (env, _tal
, te, cty
) =
2274 static_class_id ~check_constraints
:false cpos
env [] cid
2276 let env = might_throw
env in
2277 let (env, (ty, _tal
)) =
2281 ~coerce_from_ty
:None
2287 let (env, ty) = Env.FakeMembers.check_static_invalid
env cid (snd mid
) ty in
2288 let env = Typing_local_ops.enforce_static_property_access ppos
env in
2289 make_result
env p (Aast.Class_get
(te, Aast.CGstring mid
, in_parens
)) ty
2290 (* Fake member property access. For example:
2291 * if ($x->f !== null) { ...$x->f... }
2293 | Class_get
(_
, CGexpr _
, _
) ->
2294 failwith
"AST should not have any CGexprs after naming"
2295 | Obj_get
(e, (pid
, Id
(py
, y
)), nf
, in_parens
)
2296 when Env.FakeMembers.is_valid
env e y
->
2297 let env = might_throw
env in
2298 let (env, local) = Env.FakeMembers.make
env e y
p in
2299 let local = (p, Lvar
(p, local)) in
2300 let (env, _
, ty) = expr env local in
2301 let (env, t_lhs
, _
) = expr ~accept_using_var
:true env e in
2302 let t_rhs = Tast.make_typed_expr pid
ty (Aast.Id
(py
, y
)) in
2303 make_result
env p (Aast.Obj_get
(t_lhs
, t_rhs, nf
, in_parens
)) ty
2304 (* Statically-known instance property access e.g. $x->f *)
2305 | Obj_get
(e1
, (pm
, Id m
), nullflavor
, in_parens
) ->
2307 match nullflavor
with
2308 | OG_nullthrows
-> None
2309 | OG_nullsafe
-> Some
p
2311 let (env, te1
, ty1
) = expr ~accept_using_var
:true env e1
in
2312 let env = might_throw
env in
2313 (* We typecheck Obj_get by checking whether it is a subtype of
2314 Thas_member(m, #1) where #1 is a fresh type variable. *)
2315 let (env, mem_ty
) = Env.fresh_type
env p in
2316 let r = Reason.Rwitness
(fst e1
) in
2322 ~class_id
:(CIexpr e1
)
2323 ~explicit_targs
:None
2325 let lty1 = LoclType ty1
in
2326 let (env, result_ty
) =
2340 (* In that case ty1 is a subtype of ?Thas_member(m, #1)
2341 and the result is ?#1 if ty1 is nullable. *)
2342 let r = Reason.Rnullsafe_op
p in
2343 let null_ty = MakeType.null
r in
2344 let (env, null_has_mem_ty
) =
2345 Union.union_i
env r has_member_ty null_ty
2356 let (env, null_or_nothing_ty
) = Inter.intersect
env ~
r null_ty ty1
in
2357 let (env, result_ty
) = Union.union env null_or_nothing_ty mem_ty
in
2360 let (env, result_ty
) =
2361 Env.FakeMembers.check_instance_invalid
env e1
(snd m
) result_ty
2368 Tast.make_typed_expr pm result_ty
(Aast.Id m
),
2372 (* Dynamic instance property access e.g. $x->$f *)
2373 | Obj_get
(e1
, e2, nullflavor
, in_parens
) ->
2374 let (env, te1
, ty1
) = expr ~accept_using_var
:true env e1
in
2375 let (env, te2
, _
) = expr env e2 in
2377 if TUtils.is_dynamic
env ty1
then
2378 MakeType.dynamic
(Reason.Rwitness
p)
2380 Typing_utils.mk_tany
env p
2382 let ((pos, _
), te2
) = te2
in
2383 let env = might_throw
env in
2384 let te2 = Tast.make_typed_expr
pos ty te2 in
2385 make_result
env p (Aast.Obj_get
(te1
, te2, nullflavor
, in_parens
)) ty
2387 make_result
env p Aast.Yield_break
(Typing_utils.mk_tany
env p)
2389 let (env, (taf
, opt_key
, value)) = array_field
env af
in
2390 let (env, send
) = Env.fresh_type
env p in
2392 match (af
, opt_key
) with
2393 | (AFvalue
(p, _
), None
) ->
2395 match Env.get_fn_kind
env with
2397 | Ast_defs.FAsync
->
2398 Errors.internal_error
p "yield found in non-generator";
2399 (env, Typing_utils.mk_tany
env p)
2400 | Ast_defs.FGenerator
-> (env, MakeType.int (Reason.Rwitness
p))
2401 | Ast_defs.FAsyncGenerator
->
2402 let (env, ty) = Env.fresh_type
env p in
2403 (env, MakeType.nullable_locl
(Reason.Ryield_asyncnull
p) ty)
2405 | (_
, Some x
) -> (env, x
)
2406 | (_
, _
) -> assert false
2409 match Env.get_fn_kind
env with
2410 | Ast_defs.FGenerator
->
2411 MakeType.generator
(Reason.Ryield_gen
p) key
value send
2412 | Ast_defs.FAsyncGenerator
->
2413 MakeType.async_generator
(Reason.Ryield_asyncgen
p) key
value send
2415 | Ast_defs.FAsync
->
2416 failwith
"Parsing should never allow this"
2418 let Typing_env_return_info.{ return_type = expected_return; _
} =
2422 Typing_coercion.coerce_type
2430 let env = Env.forget_members
env Reason.(Blame
(p, BScall
)) in
2431 let env = LEnv.save_and_merge_next_in_cont
env C.Exit
in
2436 (MakeType.nullable_locl
(Reason.Ryield_send
p) send
)
2438 let env = might_throw
env in
2439 (* Await is permitted in a using clause e.g. using (await make_handle()) *)
2440 let (env, te, rty) =
2441 expr ~is_using_clause ~in_await
:(Reason.Rwitness
p) env e
2443 let (env, ty) = Async.overload_extract_from_awaitable
env p rty in
2444 make_result
env p (Aast.Await
te) ty
2445 | New
((pos, c), explicit_targs
, el
, unpacked_element
, p1) ->
2446 let env = might_throw
env in
2447 let (env, tc
, tal
, tel
, typed_unpack_element
, ty, ctor_fty
) =
2452 ~check_not_abstract
:true
2460 let env = Env.forget_members
env Reason.(Blame
(p, BScall
)) in
2464 (Aast.New
(tc
, tal
, tel
, typed_unpack_element
, (p1, ctor_fty
)))
2466 | Record
((pos, id), field_values
) ->
2467 (match Decl_provider.get_record_def
(Env.get_ctx
env) id with
2469 if rd
.rdt_abstract
then Errors.new_abstract_record
(pos, id);
2471 let field_name (pos, expr_
) =
2473 | Aast.String name
-> Some
(pos, name
)
2475 (* TODO T44306013: Ensure that other values for field names are banned. *)
2478 let fields_declared = Typing_helpers.all_record_fields
env rd
in
2479 let fields_present =
2480 List.map field_values ~f
:(fun (name
, _value
) -> field_name name
)
2483 (* Check for missing required fields. *)
2484 let fields_present_names =
2485 List.map ~f
:snd
fields_present |> SSet.of_list
2488 (fun field_name info
->
2489 let ((field_pos
, _
), req
) = info
in
2491 | Typing_defs.ValueRequired
2492 when not
(SSet.mem
field_name fields_present_names) ->
2493 Errors.missing_record_field_name
2497 ~field_decl_pos
:field_pos
2501 (* Check for unknown fields.*)
2502 List.iter
fields_present ~f
:(fun (pos, field_name) ->
2503 if not
(SMap.mem
field_name fields_declared) then
2504 Errors.unexpected_record_field_name
2508 ~decl_pos
:(fst rd
.rdt_name
))
2509 | None
-> Errors.type_not_record
id pos);
2511 expr_error env (Reason.Rwitness
p) outer
2513 let (env, te, ty2
) = expr ?in_await
env e in
2514 let env = might_throw
env in
2517 TypecheckerOptions.experimental_feature_enabled
2519 TypecheckerOptions.experimental_forbid_nullable_cast
2520 && not
(TUtils.is_mixed
env ty2
)
2522 SubType.sub_type_or_fail
2525 (MakeType.nonnull
(get_reason ty2
))
2527 Errors.nullable_cast
p (Typing_print.error
env ty2
) (get_pos ty2
))
2531 let (env, ty) = Phase.localize_hint_with_self
env hint
in
2532 make_result
env p (Aast.Cast
(hint
, te)) ty
2533 | ExpressionTree et
-> expression_tree
{ env with in_expr_tree
= true } p et
2535 Typing_kinding.Simple.check_well_kinded_hint
env hint
;
2536 let (env, te, _
) = expr env e in
2537 make_result
env p (Aast.Is
(te, hint
)) (MakeType.bool (Reason.Rwitness
p))
2538 | As
(e, hint
, is_nullable
) ->
2539 Typing_kinding.Simple.check_well_kinded_hint
env hint
;
2540 let refine_type env lpos lty
rty =
2541 let reason = Reason.Ras lpos
in
2542 let (env, rty) = Env.expand_type
env rty in
2543 let (env, rty) = class_for_refinement
env p reason lpos lty
rty in
2544 Inter.intersect
env reason lty
rty
2546 let (env, te, expr_ty
) = expr env e in
2547 let env = might_throw
env in
2549 { (Phase.env_with_self
env) with from_class
= Some CIstatic
}
2551 let (env, hint_ty
) = Phase.localize_hint ~
ety_env env hint
in
2552 let enable_sound_dynamic =
2553 TypecheckerOptions.enable_sound_dynamic env.genv
.tcopt
2555 let is_dyn = Typing_utils.is_dynamic
env hint_ty
in
2556 ( if enable_sound_dynamic && is_dyn then
2557 let (_
: env * locl_ty
) =
2559 ~allow_subtype_of_dynamic
:true
2567 let (env, hint_ty
) =
2568 if is_dyn && not
enable_sound_dynamic then
2570 if is_instance_var
e then
2571 let (env, ivar
) = get_instance_var
env e in
2572 set_local
env ivar hint_ty
2577 else if is_nullable
&& not
is_dyn then
2578 let (env, hint_ty
) = refine_type env (fst
e) expr_ty hint_ty
in
2579 (env, MakeType.nullable_locl
(Reason.Rwitness
p) hint_ty
)
2580 else if is_instance_var
e then
2581 let (env, _
, ivar_ty
) = raw_expr env e in
2582 let (env, ((ivar_pos
, _
) as ivar
)) = get_instance_var
env e in
2583 let (env, hint_ty
) = refine_type env ivar_pos ivar_ty hint_ty
in
2584 let env = set_local
env ivar hint_ty
in
2587 refine_type env (fst
e) expr_ty hint_ty
2589 make_result
env p (Aast.As
(te, hint
, is_nullable
)) hint_ty
2598 (* Check type annotations on the lambda *)
2599 Typing_check_decls.fun_
env f
;
2600 (* Check attributes on the lambda *)
2602 attributes_check_def
env SN.AttributeKinds.lambda f
.f_user_attributes
2604 (* This is the function type as declared on the lambda itself.
2605 * If type hints are absent then use Tany instead. *)
2607 Decl_nast.fun_decl_in_env
env.decl_env ~is_lambda
:true f
2609 let { fe_type
; fe_pos
; _
} = declared_fe in
2610 let (declared_pos
, declared_ft
) =
2611 match get_node fe_type
with
2612 | Tfun
ft -> (fe_pos
, ft)
2613 | _
-> failwith
"Not a function"
2616 Typing_enforceability.compute_enforced_and_pessimize_fun_type
2620 (* When creating a closure, the 'this' type will mean the late bound type
2621 * of the current enclosing class
2624 { (Phase.env_with_self
env) with from_class
= Some CIstatic
}
2626 let (env, declared_ft) =
2630 { use_name
= "lambda"; use_pos = p; explicit_targs
= [] }
2632 ~
def_pos:declared_pos
2636 List.iter idl
(check_escaping_var
env);
2638 (* Ensure lambda arity is not ellipsis in strict mode *)
2640 match declared_ft.ft_arity
with
2641 | Fvariadic
{ fp_name
= None
; _
}
2642 when Partial.should_check_error
(Env.get_mode
env) 4223 ->
2643 Errors.ellipsis_strict_mode ~require
:`Param_name
p
2647 (* Is the return type declared? *)
2648 let is_explicit_ret = Option.is_some
(hint_of_type_hint f
.f_ret
) in
2650 Decl_fun_utils.fun_reactivity_opt
env.decl_env f
.f_user_attributes
2652 ~default
:(TR.strip_conditional_reactivity
(env_reactivity
env))
2654 let check_body_under_known_params env ?ret_ty
ft : env * _
* locl_ty
=
2655 let old_reactivity = env_reactivity
env in
2656 let env = Env.set_env_reactive
env reactivity in
2657 let ft = { ft with ft_reactive
= reactivity } in
2658 let (env, (tefun
, ty, ft)) = anon_make ?ret_ty
env p f
ft idl
is_anon in
2659 let env = Env.set_env_reactive
env old_reactivity in
2662 ( Reason.Rwitness
p,
2667 ( if is_explicit_ret then
2670 MakeType.unenforced
ty );
2673 (env, tefun
, inferred_ty)
2675 let (env, eexpected
) = expand_expected_and_get_node
env expected in
2676 (* TODO: move this into the expand_expected_and_get_node function and prune its callsites
2677 * Strip like type from function type hint *)
2679 match eexpected with
2680 | Some
(pos, ur, _
, Tunion
[ty1
; ty2
]) when is_dynamic ty1
&& is_fun ty2
2682 Some
(pos, ur, ty2
, get_node ty2
)
2686 match eexpected with
2687 | Some
(_pos
, _ur
, ty, Tfun expected_ft
) ->
2688 (* First check that arities match up *)
2689 check_lambda_arity
p (get_pos
ty) declared_ft expected_ft
;
2690 (* Use declared types for parameters in preference to those determined
2691 * by the context: they might be more general. *)
2692 let rec replace_non_declared_types
2693 params declared_ft_params expected_ft_params
=
2694 match (params, declared_ft_params
, expected_ft_params
) with
2695 | ( param
:: params,
2696 declared_ft_param
:: declared_ft_params
,
2697 expected_ft_param
:: expected_ft_params
) ->
2699 replace_non_declared_types
2704 let resolved_ft_param =
2705 if Option.is_some
(hint_of_type_hint param
.param_type_hint
) then
2708 { declared_ft_param
with fp_type
= expected_ft_param
.fp_type
}
2710 resolved_ft_param :: rest
2711 | (_
:: params, declared_ft_param
:: declared_ft_params
, []) ->
2713 replace_non_declared_types
2718 declared_ft_param
:: rest
2720 (* This means the expected_ft params list can have more parameters
2721 * than declared parameters in the lambda. For variadics, this is OK.
2725 let replace_non_declared_arity variadic declared_arity expected_arity
=
2727 | FVvariadicArg
{ param_type_hint
= (_
, Some _
); _
} -> declared_arity
2728 | FVvariadicArg _
->
2730 match (declared_arity
, expected_arity
) with
2731 | (Fvariadic declared
, Fvariadic
expected) ->
2732 Fvariadic
{ declared
with fp_type
= expected.fp_type
}
2733 | (_
, _
) -> declared_arity
2735 | _
-> declared_arity
2741 replace_non_declared_arity
2743 declared_ft.ft_arity
2744 expected_ft.ft_arity
;
2746 replace_non_declared_types
2748 declared_ft.ft_params
2749 expected_ft.ft_params
;
2750 ft_implicit_params
= declared_ft.ft_implicit_params
;
2753 (* Don't bother passing in `void` if there is no explicit return *)
2755 match get_node
expected_ft.ft_ret
.et_type
with
2756 | Tprim Tvoid
when not
is_explicit_ret -> None
2757 | _
-> Some
expected_ft.ft_ret
.et_type
2759 Typing_log.increment_feature_count
env FL.Lambda.contextual_params
;
2760 check_body_under_known_params env ?
ret_ty expected_ft
2762 let explicit_variadic_param_or_non_variadic =
2763 match f
.f_variadic
with
2764 | FVvariadicArg
{ param_type_hint
; _
} ->
2765 Option.is_some
(hint_of_type_hint param_type_hint
)
2766 | FVellipsis _
-> false
2769 (* If all parameters are annotated with explicit types, then type-check
2770 * the body under those assumptions and pick up the result type *)
2771 let all_explicit_params =
2772 List.for_all f
.f_params
(fun param
->
2773 Option.is_some
(hint_of_type_hint param
.param_type_hint
))
2775 if all_explicit_params && explicit_variadic_param_or_non_variadic then (
2776 Typing_log.increment_feature_count
2778 ( if List.is_empty f
.f_params
then
2781 FL.Lambda.explicit_params
);
2782 check_body_under_known_params env declared_ft
2785 | Some
ExpectedTy.{ ty = { et_type
; _
}; _
} when is_any et_type
->
2786 (* If the expected type is Tany env then we're passing a lambda to
2787 * an untyped function and we just assume every parameter has type
2789 * Note: we should be using 'nothing' to type the arguments. *)
2790 Typing_log.increment_feature_count
env FL.Lambda.untyped_context
;
2791 check_body_under_known_params env declared_ft
2793 (* If the expected type is something concrete but not a function
2794 * then we should reject in strict mode. Check body anyway.
2795 * Note: we should be using 'nothing' to type the arguments. *)
2796 if Partial.should_check_error
(Env.get_mode
env) 4224 then
2797 Errors.untyped_lambda_strict_mode
p;
2798 Typing_log.increment_feature_count
2800 FL.Lambda.non_function_typed_context
;
2801 check_body_under_known_params env declared_ft
2803 (* If we're in partial mode then type-check definition anyway,
2804 * so treating parameters without type hints as "untyped"
2806 if not
(Env.is_strict
env) then (
2807 Typing_log.increment_feature_count
2809 FL.Lambda.non_strict_unknown_params
;
2810 check_body_under_known_params env declared_ft
2812 Typing_log.increment_feature_count
2814 FL.Lambda.fresh_tyvar_params
;
2816 (* Replace uses of Tany that originated from "untyped" parameters or return type
2817 * with fresh type variables *)
2818 let freshen_ftype env ft =
2819 let freshen_ty env pos et
=
2820 match get_node et
.et_type
with
2822 let (env, ty) = Env.fresh_type
env pos in
2823 (env, { et
with et_type
= ty })
2824 | Tclass
(id, e, [ty])
2825 when String.equal
(snd
id) SN.Classes.cAwaitable
2827 let (env, t
) = Env.fresh_type
env pos in
2831 et_type
= mk
(get_reason et
.et_type
, Tclass
(id, e, [t
]));
2835 let freshen_untyped_param env ft_param
=
2836 let (env, fp_type
) =
2837 freshen_ty env ft_param
.fp_pos ft_param
.fp_type
2839 (env, { ft_param
with fp_type
})
2841 let (env, ft_params
) =
2842 List.map_env
env ft.ft_params
freshen_untyped_param
2844 let (env, ft_ret
) = freshen_ty env declared_pos
ft.ft_ret
in
2845 (env, { ft with ft_params
; ft_ret
})
2847 let (env, declared_ft) = freshen_ftype env declared_ft in
2849 Env.set_tyvar_variance
env (mk
(Reason.Rnone
, Tfun
declared_ft))
2851 (* TODO(jjwu): the declared_ft here is set to public,
2852 but is actually inferred from the surrounding context
2853 (don't think this matters in practice, since we check lambdas separately) *)
2854 check_body_under_known_params
2856 ~
ret_ty:declared_ft.ft_ret
.et_type
2861 | Xml
(sid
, attrl
, el
) ->
2863 let (env, _tal
, _te
, classes
) =
2864 class_id_for_new ~exact
:Nonexact
p env cid []
2866 (* OK to ignore rest of list; class_info only used for errors, and
2867 * cid = CI sid cannot produce a union of classes anyhow *)
2869 List.find_map classes ~f
:(function
2871 | `Class
(_
, class_info, _
) -> Some
class_info)
2873 let (env, _te
, obj
) =
2874 expr env (fst sid
, New
((fst sid
, cid), [], [], None
, fst sid
))
2876 let (env, typed_attrs
, attr_types
) =
2877 xhp_attribute_exprs
env class_info attrl
2880 List.map_env
env el ~f
:(fun env e ->
2881 let (env, te, _
) = expr env e in
2884 let txml = Aast.Xml
(sid
, typed_attrs
, List.rev tel
) in
2885 (match class_info with
2886 | None
-> make_result
env p txml (mk
(Reason.Runknown_class
p, Tobject
))
2887 | Some
class_info ->
2894 let (namepstr
, valpty
) = attr
in
2895 let (valp
, valty
) = valpty
in
2896 let (env, (declty
, _tal
)) =
2901 ~coerce_from_ty
:None
2909 let ureason = Reason.URxhp
(Cls.name
class_info, snd namepstr
) in
2910 Typing_coercion.coerce_type
2915 (MakeType.unenforced declty
)
2916 Errors.xhp_attribute_does_not_match_hint
2920 make_result
env p txml obj
)
2921 | Callconv
(kind
, e) ->
2922 let (env, te, ty) = expr env e in
2923 make_result
env p (Aast.Callconv
(kind
, te)) ty
2925 let (env, fdm_with_expected
) =
2926 match expand_expected_and_get_node
env expected with
2927 | (env, Some
(pos, ur, _
, Tshape
(_
, expected_fdm
))) ->
2931 match ShapeMap.find_opt k expected_fdm
with
2932 | None
-> (k
, (v
, None
))
2933 | Some sft
-> (k
, (v
, Some
(ExpectedTy.make
pos ur sft
.sft_ty
))))
2937 | _
-> (env, List.map ~f
:(fun (k
, v
) -> (k
, (v
, None
))) fdm
)
2939 (* allow_inter adds a type-variable *)
2942 ~f
:(fun env (key
, (e, expected)) ->
2943 let (env, te, ty) = expr ?
expected env e in
2944 (env, (key
, (te, ty))))
2949 let convert_expr_and_type_to_shape_field_type env (key
, (_
, ty)) =
2950 (* An expression evaluation always corresponds to a shape_field_type
2951 with sft_optional = false. *)
2952 (env, (key
, { sft_optional
= false; sft_ty
= ty }))
2954 List.map_env ~f
:convert_expr_and_type_to_shape_field_type env tfdm
2958 ~f
:(fun acc
(k
, v
) -> ShapeMap.add k v acc
)
2959 ~init
:ShapeMap.empty
2962 let env = check_shape_keys_validity
env p (ShapeMap.keys
fdm) in
2963 (* Fields are fully known, because this shape is constructed
2964 * using shape keyword and we know exactly what fields are set. *)
2968 (Aast.Shape
(List.map ~f
:(fun (k
, (te, _
)) -> (k
, te)) tfdm
))
2969 (mk
(Reason.Rwitness
p, Tshape
(Closed_shape
, fdm)))
2970 | ET_Splice
e -> et_splice
{ env with in_expr_tree
= true } p e
2972 Errors.atom_as_expr
p;
2973 make_result
env p (Aast.EnumAtom
s) (mk
(Reason.Rwitness
p, Terr
))
2975 (* let ty = err_witness env cst_pos in *)
2976 and class_const ?
(incl_tc
= false) env p ((cpos
, cid), mid
) =
2977 let (env, _tal
, ce
, cty
) =
2978 static_class_id ~check_constraints
:true cpos
env [] cid
2980 let (env, (const_ty
, _tal
)) =
2985 ~coerce_from_ty
:None
2991 make_result
env p (Aast.Class_const
(ce
, mid
)) const_ty
2992 (*****************************************************************************)
2993 (* XHP attribute/body helpers. *)
2994 (*****************************************************************************)
2997 * Process a spread operator by computing the intersection of XHP attributes
2998 * between the spread expression and the XHP constructor onto which we're
3001 and xhp_spread_attribute
env c_onto valexpr
=
3002 let (p, _
) = valexpr
in
3003 let (env, te, valty
) = expr env valexpr
in
3004 (* Build the typed attribute node *)
3005 let typed_attr = Aast.Xhp_spread
te in
3006 let (env, attr_ptys
) =
3009 | Some
class_info -> Typing_xhp.get_spread_attributes
env p class_info valty
3011 (env, typed_attr, attr_ptys
)
3014 * Simple XHP attributes (attr={expr} form) are simply interpreted as a member
3015 * variable prefixed with a colon, the types of which will be validated later
3017 and xhp_simple_attribute
env id valexpr
=
3018 let (p, _
) = valexpr
in
3019 let (env, te, valty
) = expr env valexpr
in
3020 (* This converts the attribute name to a member name. *)
3021 let name = ":" ^ snd
id in
3022 let attr_pty = ((fst
id, name), (p, valty
)) in
3023 let typed_attr = Aast.Xhp_simple
(id, te) in
3024 (env, typed_attr, [attr_pty])
3027 * Typecheck the attribute expressions - this just checks that the expressions are
3028 * valid, not that they match the declared type for the attribute and,
3029 * in case of spreads, makes sure they are XHP.
3031 and xhp_attribute_exprs
env cid attrl
=
3032 let handle_attr (env, typed_attrl
, attr_ptyl
) attr
=
3033 let (env, typed_attr, attr_ptys
) =
3035 | Xhp_simple
(id, valexpr
) -> xhp_simple_attribute
env id valexpr
3036 | Xhp_spread valexpr
-> xhp_spread_attribute
env cid valexpr
3038 (env, typed_attr :: typed_attrl
, attr_ptys
@ attr_ptyl
)
3040 let (env, typed_attrl
, attr_ptyl
) =
3041 List.fold_left ~f
:handle_attr ~init
:(env, [], []) attrl
3043 (env, List.rev typed_attrl
, List.rev attr_ptyl
)
3045 (*****************************************************************************)
3046 (* Anonymous functions. *)
3047 (*****************************************************************************)
3048 and anon_bind_param
params (env, t_params
) ty : env * Tast.fun_param list
=
3051 (* This code cannot be executed normally, because the arity is wrong
3052 * and it will error later. Bind as many parameters as we can and carry
3055 | param
:: paraml
->
3057 (match hint_of_type_hint param
.param_type_hint
with
3059 let h = Decl_hint.hint
env.decl_env
h in
3060 (* When creating a closure, the 'this' type will mean the
3061 * late bound type of the current enclosing class
3064 { (Phase.env_with_self
env) with from_class
= Some CIstatic
}
3066 let (env, h) = Phase.localize ~
ety_env env h in
3067 let pos = get_pos
h in
3069 Typing_coercion.coerce_type
3074 (MakeType.unenforced
h)
3077 (* Closures are allowed to have explicit type-hints. When
3078 * that is the case we should check that the argument passed
3079 * is compatible with the type-hint.
3080 * The body of the function should be type-checked with the
3081 * hint and not the type of the argument passed.
3082 * Otherwise it leads to strange results where
3083 * foo(?string $x = null) is called with a string and fails to
3084 * type-check. If $x is a string instead of ?string, null is not
3085 * subtype of string ...
3087 let (env, t_param
) = bind_param env (h, param
) in
3088 (env, t_params
@ [t_param
])
3091 mk
(Reason.Rlambda_param
(param
.param_pos
, get_reason
ty), get_node
ty)
3093 let (env, t_param
) = bind_param env (ty, param
) in
3094 (env, t_params
@ [t_param
]))
3096 and anon_bind_variadic
env vparam variadic_ty
=
3097 let (env, ty, pos) =
3098 match hint_of_type_hint vparam
.param_type_hint
with
3100 (* if the hint is missing, use the type we expect *)
3101 (env, variadic_ty
, get_pos variadic_ty
)
3103 let h = Decl_hint.hint
env.decl_env hint
in
3105 { (Phase.env_with_self
env) with from_class
= Some CIstatic
}
3107 let (env, h) = Phase.localize ~
ety_env env h in
3108 let pos = get_pos
h in
3110 Typing_coercion.coerce_type
3115 (MakeType.unenforced
h)
3118 (env, h, vparam
.param_pos
)
3120 let r = Reason.Rvar_param
pos in
3121 let arr_values = mk
(r, get_node
ty) in
3122 let ty = MakeType.varray
r arr_values in
3123 let (env, t_variadic
) = bind_param env (ty, vparam
) in
3126 and anon_bind_opt_param
env param
: env =
3127 match param
.param_expr
with
3129 let ty = Typing_utils.mk_tany
env param
.param_pos
in
3130 let (env, _
) = bind_param env (ty, param
) in
3133 let (env, _te
, ty) = expr env default
in
3134 Typing_sequencing.sequence_check_expr default
;
3135 let (env, _
) = bind_param env (ty, param
) in
3138 and anon_check_param
env param
=
3139 match hint_of_type_hint param
.param_type_hint
with
3142 let (env, hty
) = Phase.localize_hint_with_self
env hty
in
3143 let paramty = Env.get_local
env (Local_id.make_unscoped param
.param_name
) in
3144 let hint_pos = get_pos hty
in
3146 Typing_coercion.coerce_type
3151 (MakeType.unenforced hty
)
3156 and stash_conts_for_anon
env p is_anon captured f
=
3158 if Env.is_local_defined
env this
then
3159 (Pos.none
, this
) :: captured
3164 Option.map (Env.next_cont_opt
env) ~f
:(fun next_cont
->
3165 let initial_locals =
3167 Env.get_locals
env captured
3169 next_cont
.Typing_per_cont_env.local_types
3172 Fake.forget
(Env.get_fake_members
env) Reason.(Blame
(p, BSlambda
))
3174 let tpenv = Env.get_tpenv
env in
3175 (initial_locals, initial_fakes, tpenv))
3177 Typing_lenv.stash_and_do
env (Env.all_continuations
env) (fun env ->
3181 | Some
(initial_locals, initial_fakes, tpenv) ->
3182 let env = Env.reinitialize_locals
env in
3183 let env = Env.set_locals
env initial_locals in
3184 let env = Env.set_fake_members
env initial_fakes in
3185 let env = Env.env_with_tpenv
env tpenv in
3190 (* Make a type-checking function for an anonymous function. *)
3191 (* Here ret_ty should include Awaitable wrapper *)
3192 (* TODO: ?el is never set; so we need to fix variadic use of lambda *)
3193 and anon_make ?el ?
ret_ty env lambda_pos f
ft idl
is_anon =
3194 let nb = Nast.assert_named_body f
.f_body
in
3195 Env.anon
env.lenv env (fun env ->
3196 (* Extract capabilities from AAST and add them to the environment *)
3197 let (env, capability
) =
3198 match (f
.f_ctxs
, f
.f_unsafe_ctxs
) with
3200 (* if the closure has no explicit coeffect annotations,
3201 do _not_ insert (unsafe) capabilities into the environment;
3202 instead, rely on the fact that a capability from an enclosing
3203 scope can simply be captured, which has the same semantics
3204 as redeclaring and shadowing with another same-typed capability.
3205 This avoid unnecessary overhead in the most common case, i.e.,
3206 when a closure does not need a different (usually smaller)
3207 set of capabilities. *)
3208 (env, Env.get_local
env Typing_coeffects.local_capability_id
)
3210 let (env, cap_ty
, unsafe_cap_ty
) =
3211 type_capability
env f
.f_ctxs f
.f_unsafe_ctxs
(fst f
.f_name
)
3213 Typing_coeffects.register_capabilities
env cap_ty unsafe_cap_ty
3216 { ft with ft_implicit_params
= { capability
= CapTy capability
} }
3218 stash_conts_for_anon
env lambda_pos
is_anon idl
(fun env ->
3219 let env = Env.clear_params
env in
3220 let make_variadic_arg env varg tyl
=
3221 let remaining_types =
3222 (* It's possible the variadic arg will capture the variadic
3223 * parameter of the supplied arity (if arity is Fvariadic)
3224 * and additional supplied params.
3226 * For example in cases such as:
3227 * lambda1 = (int $a, string...$c) ==> {};
3228 * lambda1(1, "hello", ...$y); (where $y is a variadic string)
3229 * lambda1(1, "hello", "world");
3230 * then ...$c will contain "hello" and everything in $y in the first
3231 * example, and "hello" and "world" in the second example.
3233 * To account for a mismatch in arity, we take the remaining supplied
3234 * parameters and return a list of all their types. We'll use this
3235 * to create a union type when creating the typed variadic arg.
3237 let remaining_params =
3238 List.drop
ft.ft_params
(List.length f
.f_params
)
3240 List.map ~f
:(fun param
-> param
.fp_type
.et_type
) remaining_params
3242 let r = Reason.Rvar_param varg
.param_pos
in
3243 let union = Tunion
(tyl
@ remaining_types) in
3244 let (env, t_param
) = anon_bind_variadic
env varg
(mk
(r, union)) in
3245 (env, Aast.FVvariadicArg t_param
)
3247 let (env, t_variadic
) =
3248 match (f
.f_variadic
, ft.ft_arity
) with
3249 | (FVvariadicArg arg
, Fvariadic variadic
) ->
3250 make_variadic_arg env arg
[variadic
.fp_type
.et_type
]
3251 | (FVvariadicArg arg
, Fstandard
) -> make_variadic_arg env arg
[]
3252 | (FVellipsis
pos, _
) -> (env, Aast.FVellipsis
pos)
3253 | (_
, _
) -> (env, Aast.FVnonVariadic
)
3255 let params = ref f
.f_params
in
3256 let (env, t_params
) =
3258 ~f
:(anon_bind_param
params)
3260 (List.map ft.ft_params
(fun x
-> x
.fp_type
.et_type
))
3262 let env = List.fold_left ~f
:anon_bind_opt_param ~
init:env !params in
3263 let env = List.fold_left ~f
:anon_check_param ~
init:env f
.f_params
in
3268 Unify.unify_param_modes
3274 match f
.f_variadic
with
3277 TUtils.default_fun_param
3279 (mk
(Reason.Rvar_param
pos, Typing_defs.make_tany
()))
3284 let rec iter l1 l2
=
3285 match (l1
, l2
, var_param) with
3287 | ([], _
, None
) -> ()
3288 | ([], x2
:: rl2
, Some def1
) ->
3289 param_modes ~is_variadic
:true def1 x2
;
3291 | (x1
:: rl1
, x2
:: rl2
, _
) ->
3295 iter ft.ft_params x
;
3296 wfold_left2 inout_write_back
env ft.ft_params x
3298 let env = Env.set_fn_kind
env f
.f_fun_kind
in
3301 ~f
:(Decl_hint.hint
env.decl_env
)
3302 (hint_of_type_hint f
.f_ret
)
3307 (* Do we have a contextual return type? *)
3311 let (env, ret_ty) = Env.fresh_type
env lambda_pos
in
3312 (env, Typing_return.wrap_awaitable
env lambda_pos
ret_ty)
3314 (* We might need to force it to be Awaitable if it is a type variable *)
3315 Typing_return.force_awaitable
env lambda_pos
ret_ty
3318 (* If a 'this' type appears it needs to be compatible with the
3322 { (Phase.env_with_self
env) with from_class
= Some CIstatic
}
3324 Typing_return.make_return_type
(Phase.localize ~
ety_env) env ret
3329 (Typing_return.make_info
3333 ~is_explicit
:(Option.is_some
ret_ty)
3337 let local_tpenv = Env.get_tpenv
env in
3338 (* Outer pipe variables aren't available in closures. Note that
3339 * locals are restored by Env.anon after processing the closure
3344 (Local_id.make_unscoped
SN.SpecialIdents.dollardollar
)
3346 let (env, tb) = block
env nb.fb_ast
in
3347 let implicit_return = LEnv.has_next
env in
3349 if (not
implicit_return) || Nast.named_body_is_unsafe
nb then
3352 fun_implicit_return
env lambda_pos hret f
.f_fun_kind
3354 let (env, tparams
) = List.map_env
env f
.f_tparams type_param
in
3355 let (env, user_attributes
) =
3356 List.map_env
env f
.f_user_attributes user_attribute
3360 Aast.f_annotation
= Env.save
local_tpenv env;
3361 Aast.f_span
= f
.f_span
;
3362 Aast.f_mode
= f
.f_mode
;
3363 Aast.f_ret
= (hret
, hint_of_type_hint f
.f_ret
);
3364 Aast.f_name
= f
.f_name
;
3365 Aast.f_tparams
= tparams
;
3366 Aast.f_where_constraints
= f
.f_where_constraints
;
3367 Aast.f_fun_kind
= f
.f_fun_kind
;
3368 Aast.f_file_attributes
= [];
3369 Aast.f_user_attributes
= user_attributes
;
3370 Aast.f_body
= { Aast.fb_ast
= tb; fb_annotation
= () };
3371 Aast.f_ctxs
= f
.f_ctxs
;
3372 Aast.f_unsafe_ctxs
= f
.f_unsafe_ctxs
;
3373 Aast.f_params
= t_params
;
3374 Aast.f_variadic
= t_variadic
;
3375 (* TODO TAST: Variadic efuns *)
3376 Aast.f_external
= f
.f_external
;
3377 Aast.f_namespace
= f
.f_namespace
;
3378 Aast.f_doc_comment
= f
.f_doc_comment
;
3379 Aast.f_static
= f
.f_static
;
3382 let ty = mk
(Reason.Rwitness lambda_pos
, Tfun
ft) in
3384 Tast.make_typed_expr
3388 Aast.Efun
(tfun_, idl
)
3390 Aast.Lfun
(tfun_, idl
) )
3392 let env = Env.set_tyvar_variance
env ty in
3393 (env, (te, hret
, ft))
3394 (* stash_conts_for_anon *))
3397 (*****************************************************************************)
3398 (* End of anonymous functions. *)
3399 (*****************************************************************************)
3401 (*****************************************************************************)
3402 (* Expression trees *)
3403 (*****************************************************************************)
3404 and expression_tree
env p et
=
3405 let (_
, t_src_expr
, _
) = expr_any env p et
.et_src_expr
in
3406 let (env, t_desugared_expr
, ty_desugared
) = expr env et
.et_desugared_expr
in
3410 (Aast.ExpressionTree
3412 et_hint
= et
.et_hint
;
3413 et_src_expr
= t_src_expr
;
3414 et_desugared_expr
= t_desugared_expr
;
3418 and et_splice
env p e =
3419 let (env, te, ty) = expr env e in
3420 let (env, ty_visitor
) = Env.fresh_type
env p in
3421 let (env, ty_res
) = Env.fresh_type
env p in
3422 let (env, ty_infer
) = Env.fresh_type
env p in
3423 let expr_tree_type =
3424 MakeType.expr_tree
(Reason.Rsplice
p) ty_visitor ty_res ty_infer
3426 let env = SubType.sub_type
env ty expr_tree_type Errors.unify_error
in
3427 make_result
env p (Aast.ET_Splice
te) ty_infer
3429 (*****************************************************************************)
3430 (* End expression trees *)
3431 (*****************************************************************************)
3432 and type_capability
env ctxs unsafe_ctxs default_pos
=
3433 let cc = Decl_hint.aast_contexts_to_decl_capability
in
3435 match cc env.decl_env ctxs default_pos
with
3436 | CapTy
ty -> Phase.localize_with_self
env ty
3437 | CapDefaults _p
-> (env, MakeType.default_capability
)
3439 let (env, unsafe_cap_ty
) =
3440 match cc env.decl_env unsafe_ctxs default_pos
with
3441 | CapTy
ty -> Phase.localize_with_self
env ty
3443 (* default is no unsafe capabilities *)
3444 (env, MakeType.mixed (Reason.Rhint
p))
3446 (env, cap_ty
, unsafe_cap_ty
)
3448 and requires_consistent_construct
= function
3455 (* Caller will be looking for a particular form of expected type
3456 * e.g. a function type (when checking lambdas) or tuple type (when checking
3457 * tuples). First expand the expected type and elide single union; also
3458 * strip nullables, so ?t becomes t, as context will always accept a t if a ?t
3461 and expand_expected_and_get_node
env (expected : ExpectedTy.t
option) =
3463 | None
-> (env, None
)
3464 | Some
ExpectedTy.{ pos = p; reason = ur; ty = { et_type
= ty; _
}; _
} ->
3465 let (env, ty) = Env.expand_type
env ty in
3466 (match get_node
ty with
3467 | Tunion
[ty] -> (env, Some
(p, ur, ty, get_node
ty))
3468 | Toption
ty -> (env, Some
(p, ur, ty, get_node
ty))
3469 | _
-> (env, Some
(p, ur, ty, get_node
ty)))
3471 (** Do a subtype check of inferred type against expected type *)
3472 and check_expected_ty message
env inferred_ty (expected : ExpectedTy.t
option) =
3475 | Some
ExpectedTy.{ pos = p; reason = ur; ty } ->
3477 log_with_level
env "typing" 1 (fun () ->
3484 "Typing.check_expected_ty %s enforced=%b"
3488 Log_type
("inferred_ty", inferred_ty);
3489 Log_type
("expected_ty", ty.et_type
);
3492 Typing_coercion.coerce_type
p ur env inferred_ty ty Errors.unify_error
3495 ~
(expected : ExpectedTy.t
option)
3505 (* Obtain class info from the cid expression. We get multiple
3506 * results with a CIexpr that has a union type, e.g. in
3508 $classname = (mycond()? classname<A>: classname<B>);
3511 let (env, tal
, tcid
, classes
) =
3512 instantiable_cid ~exact
:Exact
p env cid explicit_targs
3514 let allow_abstract_bound_generic =
3516 | ((_
, ty), Aast.CI
(_
, tn
)) -> is_generic_equal_to tn
ty
3519 let gather (env, _tel
, _typed_unpack_element
) (cname
, class_info, c_ty
) =
3522 && Cls.abstract
class_info
3523 && (not
(requires_consistent_construct
cid))
3524 && not
allow_abstract_bound_generic
3526 uninstantiable_error
3530 (Cls.pos class_info)
3531 (Cls.name class_info)
3534 let (env, obj_ty_
, params) =
3535 let (env, c_ty
) = Env.expand_type
env c_ty
in
3536 match (cid, tal
, get_class_type c_ty
) with
3537 (* Explicit type arguments *)
3538 | (CI _
, _
:: _
, Some
(_
, _
, tyl
)) -> (env, get_node c_ty
, tyl
)
3539 | (_
, _
, class_type_opt
) ->
3541 List.map_env
env (Cls.tparams
class_info) (fun env tparam ->
3543 Env.fresh_type_reason
3545 (Reason.Rtype_variable_generics
3546 (p, snd
tparam.tp_name
, strip_ns
(snd cname
)))
3548 Typing_log.log_new_tvar_for_new_object
env p tvar cname
tparam;
3552 match class_type_opt
with
3553 | Some
(_
, Exact
, _
) -> (env, Tclass
(cname
, Exact
, params), params)
3554 | _
-> (env, Tclass
(cname
, Nonexact
, params), params)
3559 && (not is_using_clause
)
3560 && Cls.is_disposable
class_info
3562 Errors.invalid_new_disposable
p;
3563 let r_witness = Reason.Rwitness
p in
3564 let obj_ty = mk
(r_witness, obj_ty_
) in
3569 mk
(r_witness, get_node
c_ty)
3573 let ((_
, cid_ty
), _
) = tcid
in
3574 let (env, cid_ty
) = Env.expand_type
env cid_ty
in
3575 if is_generic cid_ty
then
3577 else if check_parent
then
3580 ExprDepTy.make
env cid c_ty
3582 (* Set variance according to type of `new` expression now. Lambda arguments
3583 * to the constructor might depend on it, and `call_construct` only uses
3584 * `ctor_fty` to set the variance which has void return type *)
3585 let env = Env.set_tyvar_variance
env new_ty
in
3586 let (env, tel
, typed_unpack_element
, ctor_fty
) =
3587 let env = check_expected_ty
"New" env new_ty
expected in
3588 call_construct
p env class_info params el unpacked_element
cid new_ty
3590 ( if equal_consistent_kind
(snd
(Cls.construct
class_info)) Inconsistent
then
3592 | CIstatic
-> Errors.new_inconsistent_construct
p cname `static
3593 | CIexpr _
-> Errors.new_inconsistent_construct
p cname `
classname
3597 let (env, ctor_fty
) =
3598 match fst
(Cls.construct
class_info) with
3599 | Some
({ ce_type
= (lazy ty); _
} as ce
) ->
3602 type_expansions
= [];
3604 TUtils.make_locl_subst_for_class_tparams
class_info params;
3608 on_error
= Errors.unify_error_at
p;
3611 if get_ce_abstract ce
then
3612 Errors.parent_abstract_call
3613 SN.Members.__construct
3616 let (env, ctor_fty
) = Phase.localize ~
ety_env env ty in
3618 | None
-> (env, ctor_fty
)
3620 ((env, tel
, typed_unpack_element
), (obj_ty, ctor_fty
))
3624 ((env, tel
, typed_unpack_element
), (c_ty, ctor_fty
))
3626 (* When constructing from a (classname) variable, the variable
3627 * dictates what the constructed object is going to be. This allows
3628 * for generic and dependent types to be correctly carried
3629 * through the 'new $foo()' iff the constructed obj_ty is a
3630 * supertype of the variable-dictated c_ty *)
3632 Typing_ops.sub_type
p Reason.URnone
env c_ty obj_ty Errors.unify_error
3634 ((env, tel
, typed_unpack_element
), (c_ty, ctor_fty
))
3636 let (had_dynamic
, classes
) =
3637 List.fold classes ~
init:(false, []) ~f
:(fun (seen_dynamic
, classes
) ->
3639 | `Dynamic
-> (true, classes
)
3640 | `Class
(cname
, class_info, c_ty) ->
3641 (seen_dynamic
, (cname
, class_info, c_ty) :: classes
))
3643 let ((env, tel
, typed_unpack_element
), class_types_and_ctor_types
) =
3644 List.fold_map classes ~
init:(env, [], None
) ~f
:gather
3646 let class_types_and_ctor_types =
3647 let r = Reason.Rdynamic_construct
p in
3648 let dyn = (mk
(r, Tdynamic
), mk
(r, Tdynamic
)) in
3650 dyn :: class_types_and_ctor_types
3652 class_types_and_ctor_types
3654 let (env, tel
, typed_unpack_element
, ty, ctor_fty
) =
3655 match class_types_and_ctor_types with
3657 let (env, tel
, _
) = exprs env el
in
3658 let (env, typed_unpack_element
, _
) =
3659 match unpacked_element
with
3660 | None
-> (env, None
, MakeType.nothing
Reason.Rnone
)
3661 | Some unpacked_element
->
3662 let (env, e, ty) = expr env unpacked_element
in
3665 let r = Reason.Runknown_class
p in
3666 (env, tel
, typed_unpack_element
, mk
(r, Tobject
), TUtils.terr
env r)
3667 | [(ty, ctor_fty
)] -> (env, tel
, typed_unpack_element
, ty, ctor_fty
)
3669 let (tyl
, ctyl
) = List.unzip l
in
3670 let r = Reason.Rwitness
p in
3671 (env, tel
, typed_unpack_element
, mk
(r, Tunion tyl
), mk
(r, Tunion ctyl
))
3674 let ((_
, cid_ty
), _
) = tcid
in
3675 let (env, cid_ty
) = Env.expand_type
env cid_ty
in
3676 if is_generic cid_ty
then
3678 else if check_parent
then
3681 ExprDepTy.make
env cid ty
3683 (env, tcid
, tal
, tel
, typed_unpack_element
, new_ty
, ctor_fty
)
3685 and attributes_check_def
env kind attrs
=
3686 Typing_attributes.check_def
env new_object kind attrs
3688 (** Get class infos for a class expression (e.g. `parent`, `self` or
3689 regular classnames) - which might resolve to a union or intersection
3690 of classes - and check they are instantiable.
3692 FIXME: we need to separate our instantiability into two parts. Currently,
3693 all this function is doing is checking if a given type is inhabited --
3694 that is, whether there are runtime values of type Aast. However,
3695 instantiability should be the stricter notion that T has a runtime
3696 constructor; that is, `new T()` should be valid. In particular, interfaces
3697 are inhabited, but not instantiable.
3698 To make this work with classname, we likely need to add something like
3699 concrete_classname<T>, where T cannot be an interface. *)
3700 and instantiable_cid ?
(exact
= Nonexact
) p env cid explicit_targs
:
3701 newable_class_info
=
3702 let (env, tal
, te, classes
) =
3703 class_id_for_new ~exact
p env cid explicit_targs
3705 List.iter classes
(function
3707 | `Class
((pos, name), class_info, c_ty) ->
3709 Ast_defs.(equal_class_kind
(Cls.kind
class_info) Ctrait
)
3710 || Ast_defs.(equal_class_kind
(Cls.kind
class_info) Cenum
)
3715 uninstantiable_error
env p cid (Cls.pos class_info) name pos c_ty
3721 Ast_defs.(equal_class_kind
(Cls.kind
class_info) Cabstract
)
3722 && Cls.final
class_info
3724 uninstantiable_error
env p cid (Cls.pos class_info) name pos c_ty
3727 (env, tal
, te, classes
)
3729 and uninstantiable_error
env reason_pos
cid c_tc_pos c_name c_usage_pos
c_ty =
3733 let ty_str = "This would be " ^
Typing_print.error
env c_ty in
3734 [(reason_pos
, ty_str)]
3737 Errors.uninstantiable_class c_usage_pos c_tc_pos c_name
reason_msgl
3739 and coerce_to_throwable
pos env exn_ty
=
3740 let throwable_ty = MakeType.throwable
(Reason.Rthrow
pos) in
3741 Typing_coercion.coerce_type
3746 { et_type
= throwable_ty; et_enforced
= false }
3749 and shape_field_pos
= function
3750 | Ast_defs.SFlit_int
(p, _
)
3751 | Ast_defs.SFlit_str
(p, _
) ->
3753 | Ast_defs.SFclass_const
((cls_pos
, _
), (mem_pos
, _
)) ->
3754 Pos.btw cls_pos mem_pos
3756 and check_shape_keys_validity
env pos keys
=
3757 (* If the key is a class constant, get its class name and type. *)
3758 let get_field_info env key
=
3759 let key_pos = shape_field_pos key
in
3760 (* Empty strings or literals that start with numbers are not
3761 permitted as shape field names. *)
3763 | Ast_defs.SFlit_int _
-> (env, key_pos, None
)
3764 | Ast_defs.SFlit_str
(_
, key_name
) ->
3765 if Int.equal
0 (String.length key_name
) then
3766 Errors.invalid_shape_field_name_empty
key_pos;
3767 (env, key_pos, None
)
3768 | Ast_defs.SFclass_const
(((p, cls
) as x
), y
) ->
3769 let (env, _te
, ty) = class_const
env pos ((p, CI x
), y
) in
3770 let r = Reason.Rwitness
key_pos in
3777 (MakeType.arraykey r)
3779 Errors.invalid_shape_field_type
3782 (Typing_print.error
env ty)
3785 (env, key_pos, Some
(cls
, ty))
3787 let check_field witness_pos witness_info
env key
=
3788 let (env, key_pos, key_info
) = get_field_info env key
in
3789 match (witness_info
, key_info
) with
3791 Errors.invalid_shape_field_literal
key_pos witness_pos
;
3794 Errors.invalid_shape_field_const
key_pos witness_pos
;
3796 | (None
, None
) -> env
3797 | (Some
(cls1
, ty1
), Some
(cls2
, ty2
)) ->
3798 if String.( <> ) cls1 cls2
then
3799 Errors.shape_field_class_mismatch
3806 ( Typing_solver.is_sub_type
env ty1 ty2
3807 && Typing_solver.is_sub_type
env ty2 ty1
)
3809 Errors.shape_field_type_mismatch
3812 (Typing_print.error
env ty2
)
3813 (Typing_print.error
env ty1
);
3816 (* Sort the keys by their positions since the error messages will make
3817 * more sense if we take the one that appears first as canonical and if
3818 * they are processed in source order. *)
3819 let cmp_keys x y
= Pos.compare
(shape_field_pos x
) (shape_field_pos y
) in
3820 let keys = List.sort ~compare
:cmp_keys keys in
3823 | witness
:: rest_keys
->
3824 let (env, pos, info
) = get_field_info env witness
in
3825 List.fold_left ~f
:(check_field pos info
) ~
init:env rest_keys
3827 and set_valid_rvalue
p env x
ty =
3828 let env = set_local
env (p, x
) ty in
3829 (* We are assigning a new value to the local variable, so we need to
3830 * generate a new expression id
3832 Env.set_local_expr_id
env x
(Ident.tmp
())
3834 (* Produce an error if assignment is used in the scope of the |> operator, i.e.
3835 * if $$ is in scope *)
3836 and error_if_assign_in_pipe
p env =
3837 let dd_var = Local_id.make_unscoped
SN.SpecialIdents.dollardollar
in
3838 let dd_defined = Env.is_local_defined
env dd_var in
3840 Errors.unimplemented_feature
p "Assignment within pipe expressions"
3842 (* Deal with assignment of a value of type ty2 to lvalue e1 *)
3843 and assign
p env e1 ty2
: _
* Tast.expr * Tast.ty =
3844 error_if_assign_in_pipe
p env;
3845 assign_
p Reason.URassign
env e1 ty2
3847 and is_hack_collection
env ty =
3848 Typing_solver.is_sub_type
3851 (MakeType.const_collection
Reason.Rnone
(MakeType.mixed Reason.Rnone
))
3853 and assign_
p ur env e1 ty2
=
3856 | (_
, Lvar
(_
, x
)) ->
3857 Env.forget_prefixed_members
env x
Reason.(Blame
(p, BSassignment
))
3858 (* If we ever extend fake members from $x->a to more complicated lvalues
3859 such as $x->a->b, we would need to call forget_prefixed_members on
3860 other lvalues as well. *)
3861 | (_
, Obj_get
(_
, (_
, Id
(_
, property
)), _
, _
)) ->
3862 Env.forget_suffixed_members
env property
Reason.(Blame
(p, BSassignment
))
3866 | (_
, Lvar
((_
, x
) as id)) ->
3867 let env = set_valid_rvalue
p env x ty2
in
3868 make_result
env (fst e1
) (Aast.Lvar
id) ty2
3869 | (_
, Lplaceholder
id) ->
3870 let placeholder_ty = MakeType.void
(Reason.Rplaceholder
p) in
3871 make_result
env (fst e1
) (Aast.Lplaceholder
id) placeholder_ty
3874 List.map_env
env el ~f
:(fun env _
-> Env.fresh_type
env (get_pos ty2
))
3876 let destructure_ty =
3877 MakeType.list_destructure
(Reason.Rdestructure
(fst e1
)) tyl
3879 let lty2 = LoclType ty2
in
3880 let env = Type.sub_type_i
p ur env lty2 destructure_ty Errors.unify_error
in
3881 let env = Env.set_tyvar_variance_i
env destructure_ty in
3882 let (env, reversed_tel
) =
3883 List.fold2_exn el tyl ~
init:(env, []) ~f
:(fun (env, tel
) lvalue ty2
->
3884 let (env, te, _
) = assign
p env lvalue ty2
in
3887 make_result
env (fst e1
) (Aast.List
(List.rev reversed_tel
)) ty2
3889 Obj_get
(obj
, (pm
, Id
((_
, member_name
) as m
)), nullflavor
, in_parens
) )
3891 let lenv = env.lenv in
3893 match nullflavor
with
3894 | OG_nullthrows
-> None
3895 | OG_nullsafe
-> Some
(Reason.Rnullsafe_op pobj
)
3897 let (env, tobj, obj_ty) = expr ~accept_using_var
:true env obj
in
3898 let env = might_throw
env in
3899 let (env, (result
, _tal
)) =
3904 ~coerce_from_ty
:(Some
(p, ur, ty2
))
3913 Tast.make_typed_expr
3918 Tast.make_typed_expr pm result
(Aast.Id m
),
3922 let env = { env with lenv } in
3926 let (env, local) = Env.FakeMembers.make
env obj member_name
p in
3927 let env = set_valid_rvalue
p env local ty2
in
3930 let (env, local) = Env.FakeMembers.make
env obj member_name
p in
3931 let env = set_valid_rvalue
p env local ty2
in
3933 | _
-> (env, te1, ty2
)
3936 let lenv = env.lenv in
3937 let no_fakes = LEnv.env_with_empty_fakes
env in
3938 let (env, te1, real_type
) = lvalue
no_fakes e1
in
3939 let (env, exp_real_type
) = Env.expand_type
env real_type
in
3940 let env = { env with lenv } in
3942 Typing_coercion.coerce_type
3947 (MakeType.unenforced exp_real_type
)
3951 | (_
, Class_get
(_
, CGexpr _
, _
)) ->
3952 failwith
"AST should not have any CGexprs after naming"
3953 | (_
, Class_get
((pos_classid
, x
), CGstring
(pos_member
, y
), _
)) ->
3954 let lenv = env.lenv in
3955 let no_fakes = LEnv.env_with_empty_fakes
env in
3956 let (env, te1, _
) = lvalue
no_fakes e1
in
3957 let env = { env with lenv } in
3958 let (env, ety2
) = Env.expand_type
env ty2
in
3959 (* This defers the coercion check to class_get, which looks up the appropriate target type *)
3960 let (env, _tal
, _
, cty
) =
3961 static_class_id ~check_constraints
:false pos_classid
env [] x
3963 let env = might_throw
env in
3968 ~coerce_from_ty
:(Some
(p, ur, ety2
))
3974 let (env, local) = Env.FakeMembers.make_static
env x y
p in
3975 let env = set_valid_rvalue
p env local ty2
in
3977 | (pos, Array_get
(e1
, None
)) ->
3978 let (env, te1, ty1
) = update_array_type
pos env e1 `lvalue
in
3980 Typing_array_access.assign_array_append
3989 if is_hack_collection
env ty1
then
3992 let (env, te1, _
) = assign_
p ur env e1 ty1'
in
3995 make_result
env pos (Aast.Array_get
(te1, None
)) ty2
3996 | (pos, Array_get
(e1
, Some
e)) ->
3997 let (env, te1, ty1
) = update_array_type
pos env e1 `lvalue
in
3998 let (env, te, ty) = expr env e in
4000 Typing_array_access.assign_array_get
4011 if is_hack_collection
env ty1
then
4014 let (env, te1, _
) = assign_
p ur env e1 ty1'
in
4017 (env, ((pos, ty2
), Aast.Array_get
(te1, Some
te)), ty2
)
4018 | _
-> assign_simple
p ur env e1 ty2
4020 and assign_simple
pos ur env e1 ty2
=
4021 let (env, te1, ty1
) = lvalue
env e1
in
4023 Typing_coercion.coerce_type
4028 (MakeType.unenforced ty1
)
4033 and array_field
env = function
4035 let (env, tve
, tv
) = expr env ve
in
4036 (env, (Aast.AFvalue tve
, None
, tv
))
4037 | AFkvalue
(ke
, ve
) ->
4038 let (env, tke
, tk) = expr env ke
in
4039 let (env, tve
, tv
) = expr env ve
in
4040 (env, (Aast.AFkvalue
(tke
, tve
), Some
tk, tv
))
4042 and array_value ~
(expected : ExpectedTy.t
option) env x
=
4043 let (env, te, ty) = expr ?
expected env x
in
4047 p class_name ~
(expected : ExpectedTy.t
option) env ((pos, _
) as x
) =
4048 let (env, (te, ty)) = array_value ~
expected env x
in
4049 let ty_arraykey = MakeType.arraykey (Reason.Ridx_dict
pos) in
4051 Typing_coercion.coerce_type
4053 (Reason.index_class
class_name)
4056 { et_type
= ty_arraykey; et_enforced
= true }
4061 and check_parent_construct
pos env el unpacked_element env_parent
=
4062 let check_not_abstract = false in
4063 let (env, env_parent
) = Phase.localize_with_self
env env_parent
in
4064 let (env, _tcid
, _tal
, tel
, typed_unpack_element
, parent
, fty) =
4069 ~is_using_clause
:false
4077 (* Not sure why we need to equate these types *)
4079 Type.sub_type
pos Reason.URnone
env env_parent parent
Errors.unify_error
4082 Type.sub_type
pos Reason.URnone
env parent env_parent
Errors.unify_error
4086 typed_unpack_element
,
4087 MakeType.void
(Reason.Rwitness
pos),
4091 and check_class_get
env p def_pos cid mid ce
e function_pointer
=
4093 | CIself
when get_ce_abstract ce
->
4095 match get_class_type
(Env.get_self
env) with
4096 | Some
((_
, self
), _
, _
) ->
4097 (* at runtime, self:: in a trait is a call to whatever
4098 * self:: is in the context of the non-trait "use"-ing
4099 * the trait's code *)
4101 match Env.get_class
env self
with
4102 | Some cls
when Ast_defs.(equal_class_kind
(Cls.kind cls
) Ctrait
) ->
4103 (* Ban self::some_abstract_method() in a trait, if the
4104 * method is also defined in a trait.
4106 * Abstract methods from interfaces are fine: we'll check
4107 * in the child class that we actually have an
4108 * implementation. *)
4109 (match Decl_provider.get_class
(Env.get_ctx
env) ce
.ce_origin
with
4111 when Ast_defs.(equal_class_kind
(Cls.kind meth_cls
) Ctrait
) ->
4112 Errors.self_abstract_call mid
p def_pos
4115 (* Ban self::some_abstract_method() in a class. This will
4117 Errors.self_abstract_call mid
p def_pos
4121 | CIparent
when get_ce_abstract ce
->
4122 Errors.parent_abstract_call mid
p def_pos
4123 | CI _
when get_ce_abstract ce
&& function_pointer
->
4124 Errors.abstract_function_pointer
cid mid
p def_pos
4125 | CI _
when get_ce_abstract ce
->
4126 Errors.classname_abstract_call
cid mid
p def_pos
4127 | CI
(_
, classname) when get_ce_synthesized ce
->
4128 Errors.static_synthetic_method
classname mid
p def_pos
4131 and call_parent_construct
pos env el unpacked_element
=
4132 match Env.get_parent_ty
env with
4133 | Some parent
-> check_parent_construct
pos env el unpacked_element parent
4136 let ty = Typing_utils.mk_tany
env pos in
4137 let default = (env, [], None
, ty, ty, ty) in
4138 (match get_class_type
(Env.get_self
env) with
4139 | Some
((_
, self
), _
, _
) ->
4140 (match Env.get_class
env self
with
4141 | Some trait
when Ast_defs.(equal_class_kind
(Cls.kind trait
) Ctrait
) ->
4142 (match trait_most_concrete_req_class trait
env with
4144 Errors.parent_in_trait
pos;
4146 | Some
(_
, parent_ty
) ->
4147 check_parent_construct
pos env el unpacked_element parent_ty
)
4149 if not
(Cls.members_fully_known self_tc
) then
4151 (* Don't know the hierarchy, assume it's correct *)
4153 Errors.undefined_parent
pos;
4155 | None
-> assert false)
4157 Errors.parent_outside_class
pos;
4158 let ty = err_witness env pos in
4159 (env, [], None
, ty, ty, ty))
4161 (* Depending on the kind of expression we are dealing with
4162 * The typing of call is different.
4165 ~
(expected : ExpectedTy.t
option)
4170 ((fpos
, fun_expr
) as e)
4174 let make_call env te tal tel typed_unpack_element
ty =
4175 make_result
env p (Aast.Call
(te, tal
, tel
, typed_unpack_element
)) ty
4177 (* TODO: Avoid Tany annotations in TAST by eliminating `make_call_special` *)
4178 let make_call_special env id tel
ty =
4181 (Tast.make_typed_expr fpos
(TUtils.mk_tany
env fpos
) (Aast.Id
id))
4187 (* For special functions and pseudofunctions with a definition in hhi. *)
4188 let make_call_special_from_def env id tel ty_
=
4189 let (env, fty, tal
) = fun_type_of_id
env id explicit_targs el
in
4191 match get_node
fty with
4192 | Tfun
ft -> ft.ft_ret
.et_type
4193 | _
-> ty_
(Reason.Rwitness
p)
4195 make_call env (Tast.make_typed_expr fpos
fty (Aast.Id
id)) tal tel None
ty
4197 let overload_function = overload_function make_call fpos
in
4198 let check_disposable_in_return env fty =
4199 if is_return_disposable_fun_type env fty && not is_using_clause
then
4200 Errors.invalid_new_disposable
p
4203 (* Special function `echo` *)
4204 | Id
((p, pseudo_func
) as id)
4205 when String.equal pseudo_func
SN.SpecialFunctions.echo
->
4206 let (env, tel
, _
) = exprs ~accept_using_var
:true env el
in
4207 make_call_special env id tel
(MakeType.void
(Reason.Rwitness
p))
4208 (* Special function `isset` *)
4209 | Id
((_
, pseudo_func
) as id)
4210 when String.equal pseudo_func
SN.PseudoFunctions.isset
->
4212 exprs ~accept_using_var
:true ~check_defined
:false env el
4214 if Option.is_some unpacked_element
then
4215 Errors.unpacking_disallowed_builtin_function
p pseudo_func
;
4216 make_call_special_from_def env id tel
MakeType.bool
4217 (* Special function `unset` *)
4218 | Id
((_
, pseudo_func
) as id)
4219 when String.equal pseudo_func
SN.PseudoFunctions.unset
->
4220 let (env, tel
, _
) = exprs env el
in
4221 if Option.is_some unpacked_element
then
4222 Errors.unpacking_disallowed_builtin_function
p pseudo_func
;
4223 let checked_unset_error =
4224 if Partial.should_check_error
(Env.get_mode
env) 4135 then
4225 Errors.unset_nonidx_in_strict
4231 match (el
, unpacked_element
) with
4232 | ([(_
, Array_get
((_
, Class_const _
), Some _
))], None
)
4233 when Partial.should_check_error
(Env.get_mode
env) 4011 ->
4234 Errors.const_mutation
p Pos.none
"";
4236 | ([(_
, Array_get
(ea
, Some _
))], None
) ->
4237 let (env, _te
, ty) = expr env ea
in
4238 let r = Reason.Rwitness
p in
4239 let tmixed = MakeType.mixed r in
4246 MakeType.dict
r tmixed tmixed;
4247 MakeType.keyset
r tmixed;
4248 MakeType.darray
r tmixed tmixed;
4251 SubType.sub_type_or_fail
env ty super (fun () ->
4255 ("This is " ^
Typing_print.error ~ignore_dynamic
:true env ty)
4258 checked_unset_error p [];
4262 | [(p, Obj_get
(_
, _
, OG_nullsafe
, _
))] ->
4263 Errors.nullsafe_property_write_context
p;
4264 make_call_special_from_def env id tel
(TUtils.terr
env)
4265 | _
-> make_call_special_from_def env id tel
MakeType.void
)
4266 (* Special function `array_filter` *)
4267 | Id
((_
, array_filter
) as id)
4268 when String.equal array_filter
SN.StdlibFunctions.array_filter
4269 && (not
(List.is_empty el
))
4270 && Option.is_none unpacked_element
->
4271 (* dispatch the call to typecheck the arguments *)
4272 let (env, fty, tal
) = fun_type_of_id
env id explicit_targs el
in
4273 let (env, (tel
, typed_unpack_element
, res
)) =
4274 call ~
expected p env fty el unpacked_element
4276 (* but ignore the result and overwrite it with custom return type *)
4277 let x = List.hd_exn el
in
4278 let (env, _tx
, ty) = expr env x in
4279 let explain_array_filter ty =
4280 map_reason
ty ~f
:(fun r -> Reason.Rarray_filter
(p, r))
4282 let get_value_type env tv
=
4284 if List.length el
> 1 then
4287 Typing_solver.non_null
env p tv
4289 (env, explain_array_filter tv
)
4291 let rec get_array_filter_return_type env ty =
4292 let (env, ety
) = Env.expand_type
env ty in
4293 match deref ety
with
4294 | (r, Tvarray tv
) ->
4295 let (env, tv
) = get_value_type env tv
in
4296 (env, MakeType.varray
r tv
)
4297 | (r, Tunion tyl
) ->
4298 let (env, tyl
) = List.map_env
env tyl
get_array_filter_return_type in
4299 Typing_union.union_list
env r tyl
4300 | (r, Tintersection tyl
) ->
4301 let (env, tyl
) = List.map_env
env tyl
get_array_filter_return_type in
4302 Inter.intersect_list
env r tyl
4303 | (r, Tany _
) -> (env, mk
(r, Typing_utils.tany
env))
4304 | (r, Terr
) -> (env, TUtils.terr
env r)
4306 let (env, tk) = Env.fresh_type
env p in
4307 let (env, tv
) = Env.fresh_type
env p in
4310 let keyed_container_type =
4311 MakeType.keyed_container
Reason.Rnone
tk tv
4314 SubType.sub_type
env ety
keyed_container_type Errors.unify_error
4316 let (env, tv
) = get_value_type env tv
in
4317 (env, MakeType.darray
r (explain_array_filter tk) tv
))
4321 let container_type = MakeType.container
Reason.Rnone tv
in
4323 SubType.sub_type
env ety
container_type Errors.unify_error
4325 let (env, tv
) = get_value_type env tv
in
4329 (explain_array_filter (MakeType.arraykey r))
4331 (fun _
-> (env, res
)))
4333 let (env, rty) = get_array_filter_return_type env ty in
4335 map_ty
fty ~f
:(function
4336 | Tfun
ft -> Tfun
{ ft with ft_ret
= MakeType.unenforced
rty }
4341 (Tast.make_typed_expr fpos
fty (Aast.Id
id))
4344 typed_unpack_element
4346 (* Special function `type_structure` *)
4347 | Id
(p, type_structure
)
4348 when String.equal type_structure
SN.StdlibFunctions.type_structure
4349 && Int.equal
(List.length el
) 2
4350 && Option.is_none unpacked_element
->
4354 | (p, String cst
) ->
4355 (* find the class constant implicitly defined by the typeconst *)
4358 | (_
, Class_const
(cid, (_
, x)))
4359 | (_
, Class_get
(cid, CGstring
(_
, x), _
))
4360 when String.equal
x SN.Members.mClass
->
4362 | _
-> (fst e1
, CIexpr e1
)
4364 class_const ~incl_tc
:true env p (cid, (p, cst
))
4366 Errors.illegal_type_structure
p "second argument is not a string";
4367 expr_error env (Reason.Rwitness
p) e)
4368 | _
-> assert false)
4369 (* Special function `array_map` *)
4370 | Id
((_
, array_map
) as x)
4371 when String.equal array_map
SN.StdlibFunctions.array_map
4372 && (not
(List.is_empty el
))
4373 && Option.is_none unpacked_element
->
4374 (* This uses the arity to determine a signature for array_map. But there
4375 * is more: for two-argument use of array_map, we specialize the return
4376 * type to the collection that's passed in, below. *)
4377 let (env, fty, tal
) = fun_type_of_id
env x explicit_targs el
in
4378 let (env, fty) = Env.expand_type
env fty in
4379 let r_fty = get_reason
fty in
4381 Takes a Container type and returns a function that can "pack" a type
4382 into an array of appropriate shape, preserving the key type, i.e.:
4383 array -> f, where f R = array
4384 array<X> -> f, where f R = array<R>
4385 array<X, Y> -> f, where f R = array<X, R>
4386 Vector<X> -> f where f R = array<R>
4387 KeyedContainer<X, Y> -> f, where f R = array<X, R>
4388 Container<X> -> f, where f R = array<arraykey, R>
4389 X -> f, where f R = Y
4391 let rec build_output_container env (x : locl_ty
) :
4392 env * (env -> locl_ty
-> env * locl_ty
) =
4393 let (env, x) = Env.expand_type
env x in
4395 | (r, Tvarray _
) -> (env, (fun env tr
-> (env, MakeType.varray
r tr
)))
4396 | (r, Tany _
) -> (env, (fun env _
-> (env, mk
(r, Typing_utils.tany
env))))
4397 | (r, Terr
) -> (env, (fun env _
-> (env, TUtils.terr
env r)))
4398 | (r, Tunion tyl
) ->
4399 let (env, builders
) = List.map_env
env tyl
build_output_container in
4403 List.map_env
env builders
(fun env f
-> f
env tr
)
4405 Typing_union.union_list
env r tyl
)
4406 | (r, Tintersection tyl
) ->
4407 let (env, builders
) = List.map_env
env tyl
build_output_container in
4411 List.map_env
env builders
(fun env f
-> f
env tr
)
4413 Typing_intersection.intersect_list
env r tyl
)
4415 let (env, tk) = Env.fresh_type
env p in
4416 let (env, tv
) = Env.fresh_type
env p in
4417 let try_vector env =
4418 let vector_type = MakeType.const_vector
r_fty tv
in
4419 let env = SubType.sub_type
env x vector_type Errors.unify_error
in
4420 (env, (fun env tr
-> (env, MakeType.varray
r tr
)))
4422 let try_keyed_container env =
4423 let keyed_container_type = MakeType.keyed_container
r_fty tk tv
in
4425 SubType.sub_type
env x keyed_container_type Errors.unify_error
4427 (env, (fun env tr
-> (env, MakeType.darray
r tk tr
)))
4429 let try_container env =
4430 let container_type = MakeType.container
r_fty tv
in
4431 let env = SubType.sub_type
env x container_type Errors.unify_error
in
4433 (fun env tr
-> (env, MakeType.darray
r (MakeType.arraykey r) tr
)) )
4437 (fun () -> try_vector env)
4440 (fun () -> try_keyed_container env)
4443 (fun () -> try_container env)
4445 (env, (fun env _
-> (env, Typing_utils.mk_tany
env p))))))
4450 match (deref
fty, el
) with
4451 | ((_
, Tfun funty
), [_
; x]) ->
4452 let (env, _tx
, x) = expr env x in
4453 let (env, output_container
) = build_output_container env x in
4455 match get_varray_inst funty
.ft_ret
.et_type
with
4456 | None
-> (env, fty)
4458 let (env, elem_ty
) = output_container
env elem_ty
in
4459 let ft_ret = MakeType.unenforced elem_ty
in
4460 (env, mk
(r_fty, Tfun
{ funty
with ft_ret }))
4464 let (env, (tel
, typed_unpack_element
, ty)) =
4465 call ~
expected p env fty el None
4469 (Tast.make_typed_expr fpos
fty (Aast.Id
x))
4472 typed_unpack_element
4474 (* Special function `Shapes::idx` *)
4475 | Class_const
(((_
, CI
(_
, shapes
)) as class_id
), ((_
, idx
) as method_id
))
4476 when String.equal shapes
SN.Shapes.cShapes
&& String.equal idx
SN.Shapes.idx
4485 (fun env fty res el
->
4488 let (env, _ts
, shape_ty
) = expr env shape
in
4495 ~fun_pos
:(get_reason
fty)
4496 ~shape_pos
:(fst shape
)
4497 | [shape
; field
; default] ->
4498 let (env, _ts
, shape_ty
) = expr env shape
in
4499 let (env, _td
, default_ty
) = expr env default in
4504 (Some
(fst
default, default_ty
))
4506 ~fun_pos
:(get_reason
fty)
4507 ~shape_pos
:(fst shape
)
4509 (* Special function `Shapes::at` *)
4510 | Class_const
(((_
, CI
(_
, shapes
)) as class_id
), ((_
, at
) as method_id
))
4511 when String.equal shapes
SN.Shapes.cShapes
&& String.equal at
SN.Shapes.at
4520 (fun env _fty res el
->
4523 let (env, _te
, shape_ty
) = expr env shape
in
4524 Typing_shapes.at
env ~
expr_pos:p ~shape_pos
:(fst shape
) shape_ty field
4526 (* Special function `Shapes::keyExists` *)
4528 (((_
, CI
(_
, shapes
)) as class_id
), ((_
, key_exists
) as method_id
))
4529 when String.equal shapes
SN.Shapes.cShapes
4530 && String.equal key_exists
SN.Shapes.keyExists
->
4538 (fun env fty res el
->
4541 let (env, _te
, shape_ty
) = expr env shape
in
4542 (* try accessing the field, to verify existence, but ignore
4543 * the returned type and keep the one coming from function
4544 * return type hint *)
4552 ~fun_pos
:(get_reason
fty)
4553 ~shape_pos
:(fst shape
)
4557 (* Special function `Shapes::removeKey` *)
4559 (((_
, CI
(_
, shapes
)) as class_id
), ((_
, remove_key
) as method_id
))
4560 when String.equal shapes
SN.Shapes.cShapes
4561 && String.equal remove_key
SN.Shapes.removeKey
->
4569 (fun env _ res el
->
4574 | (_
, Lvar
(_
, lvar
))
4575 | (_
, Callconv
(Ast_defs.Pinout
, (_
, Lvar
(_
, lvar
)))) ->
4576 let (env, _te
, shape_ty
) = expr env shape
in
4577 let (env, shape_ty
) =
4578 Typing_shapes.remove_key
p env shape_ty field
4580 let env = set_valid_rvalue
p env lvar shape_ty
in
4583 Errors.invalid_shape_remove_key
(fst shape
);
4587 (* Special function `Shapes::toArray` *)
4588 | Class_const
(((_
, CI
(_
, shapes
)) as class_id
), ((_
, to_array
) as method_id
))
4589 when String.equal shapes
SN.Shapes.cShapes
4590 && String.equal to_array
SN.Shapes.toArray
->
4598 (fun env _ res el
->
4601 let (env, _te
, shape_ty
) = expr env shape
in
4602 Typing_shapes.to_array
env p shape_ty res
4604 (* Special function `Shapes::toDict` *)
4605 | Class_const
(((_
, CI
(_
, shapes
)) as class_id
), ((_
, to_array
) as method_id
))
4606 when String.equal shapes
SN.Shapes.cShapes
4607 && String.equal to_array
SN.Shapes.toDict
->
4615 (fun env _ res el
->
4618 let (env, _te
, shape_ty
) = expr env shape
in
4619 Typing_shapes.to_dict
env p shape_ty res
4621 (* Special function `parent::__construct` *)
4622 | Class_const
((pos, CIparent
), ((_
, construct
) as id))
4623 when String.equal construct
SN.Members.__construct
->
4624 let (env, tel
, typed_unpack_element
, ty, pty
, ctor_fty
) =
4625 call_parent_construct
p env el unpacked_element
4629 (Tast.make_typed_expr
4632 (Aast.Class_const
(((pos, pty
), Aast.CIparent
), id)))
4633 [] (* tal: no type arguments to constructor *)
4635 typed_unpack_element
4637 (* Calling parent / class method *)
4638 | Class_const
((pos, e1
), m
) ->
4639 let (env, _tal
, tcid
, ty1
) =
4641 ~check_constraints
:(not
(Nast.equal_class_id_ e1 CIparent
))
4648 mk
(Reason.Rwitness fpos
, TUtils.this_of
(Env.get_self
env))
4650 (* In static context, you can only call parent::foo() on static methods.
4651 * In instance context, you can call parent:foo() on static
4652 * methods as well as instance methods
4655 (not
(Nast.equal_class_id_ e1 CIparent
))
4656 || Env.is_static env
4657 || class_contains_smethod
env ty1 m
4659 let (env, (fty, tal
)) =
4662 ~coerce_from_ty
:None
4671 (* parent::nonStaticFunc() is really weird. It's calling a method
4672 * defined on the parent class, but $this is still the child class.
4673 * We can deal with this by hijacking the continuation that
4674 * calculates the SN.Typehints.this type *)
4675 let k_lhs _
= this_ty in
4681 ~coerce_from_ty
:None
4691 check_disposable_in_return env fty;
4693 if Nast.equal_class_id_ e1 CIparent
then
4698 let (env, (tel
, typed_unpack_element
, ty)) =
4703 ~receiver_is_self
:(Nast.equal_class_id_ e1 CIself
)
4715 (Tast.make_typed_expr fpos
fty (Aast.Class_const
(tcid
, m
)))
4718 typed_unpack_element
4720 (* Call instance method *)
4721 | Obj_get
(e1
, (pos_id
, Id m
), nullflavor
, false)
4722 when not
(TypecheckerOptions.method_call_inference
(Env.get_tcopt
env)) ->
4723 let (env, te1, ty1
) = expr ~accept_using_var
:true env e1
in
4725 match nullflavor
with
4726 | OG_nullthrows
-> None
4727 | OG_nullsafe
-> Some
p
4729 let (env, (tfty
, tal
)) =
4733 ~
nullsafe:(Option.map ~f
:(fun p -> Reason.Rnullsafe_op
p) nullsafe)
4734 ~coerce_from_ty
:None
4742 check_disposable_in_return env tfty
;
4743 let (env, (tel
, typed_unpack_element
, ty)) =
4749 ~receiver_is_self
:false
4761 (Tast.make_typed_expr
4766 Tast.make_typed_expr pos_id tfty
(Aast.Id m
),
4771 typed_unpack_element
4773 (* Call instance method using new method call inference *)
4774 | Obj_get
(receiver
, (pos_id
, Id meth
), nullflavor
, false) ->
4776 Typecheck `Obj_get` by enforcing that:
4777 - `<instance_type>` <: `Thas_member(m, #1)`
4778 where #1 is a fresh type variable.
4780 let (env, typed_receiver
, receiver_ty
) =
4781 expr ~accept_using_var
:true env receiver
4783 let env = might_throw
env in
4785 match nullflavor
with
4786 | OG_nullthrows
-> None
4787 | OG_nullsafe
-> Some
p
4789 (* Generate a fresh type `method_ty` for the type of the
4790 instance method, i.e. #1 *)
4791 let (env, method_ty
) = Env.fresh_type
env p in
4792 (* Create `Thas_member` constraint type *)
4793 let reason = Reason.Rwitness
(fst receiver
) in
4799 ~class_id
:(CIexpr receiver
)
4800 ~explicit_targs
:(Some explicit_targs
)
4802 let env = Env.set_tyvar_variance
env method_ty
in
4803 let (env, has_method_super_ty
) =
4804 if Option.is_none
nullsafe then
4805 (env, has_method_ty)
4807 (* If null-safe, then `receiver_ty` <: `?Thas_member(m, #1)`,
4808 but *unlike* property access typing in `expr_`, we still use `#1` as
4809 our "result" if `receiver_ty` is nullable (as opposed to `?#1`),
4810 deferring null-safety handling to after `call` *)
4811 let r = Reason.Rnullsafe_op
p in
4812 let null_ty = MakeType.null
r in
4813 Union.union_i
env r has_method_ty null_ty
4820 (LoclType receiver_ty
)
4824 (* Perhaps solve for `method_ty`. Opening and closing a scope is too coarse
4825 here - type parameters are localised to fresh type variables over the
4826 course of subtyping above, and we do not want to solve these until later.
4827 Once we typecheck all function calls with a subtyping of function types,
4828 we should not need to solve early at all - transitive closure of
4829 subtyping should give enough information. *)
4831 match get_var method_ty
with
4833 Typing_solver.solve_to_equal_bound_or_wrt_variance
4840 let localize_targ env (_
, targ
) = Phase.localize_targ env targ
in
4841 let (env, typed_targs
) =
4842 List.map_env
env ~f
:(localize_targ ~check_well_kinded
:true) explicit_targs
4844 check_disposable_in_return env method_ty
;
4845 let (env, (typed_params
, typed_unpack_element
, ret_ty)) =
4851 ~receiver_is_self
:false
4862 (* If the call is nullsafe AND the receiver is nullable,
4863 make the return type nullable too *)
4865 if Option.is_some
nullsafe then
4866 let r = Reason.Rnullsafe_op
p in
4867 let null_ty = MakeType.null
r in
4868 let (env, null_or_nothing_ty
) =
4869 Inter.intersect
env ~
r null_ty receiver_ty
4871 let (env, ret_option_ty
) = Union.union env null_or_nothing_ty
ret_ty in
4872 (env, ret_option_ty
)
4878 (Tast.make_typed_expr
4883 Tast.make_typed_expr pos_id method_ty
(Aast.Id meth
),
4888 typed_unpack_element
4890 (* Function invocation *)
4892 let (env, fty, tal
) = fun_type_of_id
env x explicit_targs el
in
4893 check_disposable_in_return env fty;
4894 let (env, (tel
, typed_unpack_element
, ty)) =
4895 call ~
expected p env fty el unpacked_element
4899 (Tast.make_typed_expr fpos
fty (Aast.Fun_id
x))
4902 typed_unpack_element
4904 | Id
((_
, id) as x) ->
4905 let (env, fty, tal
) = fun_type_of_id
env x explicit_targs el
in
4906 check_disposable_in_return env fty;
4907 let (env, (tel
, typed_unpack_element
, ty)) =
4908 call ~
expected p env fty el unpacked_element
4910 let is_mutable = String.equal
id SN.Rx.mutable_
in
4911 let is_move = String.equal
id SN.Rx.move
in
4912 let is_freeze = String.equal
id SN.Rx.freeze
in
4913 (* error when rx builtins are used in non-reactive context *)
4914 if not
(Env.env_local_reactive
env) then
4916 Errors.mutable_in_nonreactive_context
p
4917 else if is_move then
4918 Errors.move_in_nonreactive_context
p
4919 else if is_freeze then
4920 Errors.freeze_in_nonreactive_context
p;
4922 (* ban unpacking when calling builtings *)
4923 if (is_mutable || is_move || is_freeze) && Option.is_some unpacked_element
4925 Errors.unpacking_disallowed_builtin_function
p id;
4927 (* adjust env for Rx\freeze or Rx\move calls *)
4930 Typing_mutability.freeze_local
p env tel
4931 else if is_move then
4932 Typing_mutability.move_local
p env tel
4938 (Tast.make_typed_expr fpos
fty (Aast.Id
x))
4941 typed_unpack_element
4944 let (env, te, fty) = expr env e in
4946 Typing_solver.expand_type_and_solve
4947 ~description_of_expected
:"a function value"
4953 check_disposable_in_return env fty;
4954 let (env, (tel
, typed_unpack_element
, ty)) =
4955 call ~
expected p env fty el unpacked_element
4960 (* tal: no type arguments to function values, as they are non-generic *)
4963 typed_unpack_element
4966 and fun_type_of_id
env x tal el
=
4967 match Env.get_fun
env (snd
x) with
4969 let (env, _
, ty) = unbound_name env x (Pos.none
, Aast.Null
) in
4971 | Some
{ fe_type
; fe_pos
; fe_deprecated
; _
} ->
4972 (match get_node fe_type
with
4975 Typing_special_fun.transform_special_fun_ty
ft x (List.length el
)
4977 let ety_env = Phase.env_with_self
env in
4979 Phase.localize_targs
4980 ~check_well_kinded
:true
4984 ~use_name
:(strip_ns
(snd
x))
4987 (List.map ~f
:snd tal
)
4990 Typing_enforceability.compute_enforced_and_pessimize_fun_type
env ft
4992 let use_pos = fst
x in
4993 let def_pos = fe_pos
in
4998 { use_name
= strip_ns
(snd
x); use_pos; explicit_targs
= tal
}
5004 let fty = mk
(get_reason fe_type
, Tfun
ft) in
5005 TVis.check_deprecated ~
use_pos ~
def_pos fe_deprecated
;
5007 | _
-> failwith
"Expected function type")
5010 * Checks if a class (given by cty) contains a given static method.
5012 * We could refactor this + class_get
5014 and class_contains_smethod
env cty
(_pos
, mid
) =
5015 let lookup_member ty =
5016 match get_class_type
ty with
5017 | Some
((_
, c), _
, _
) ->
5018 (match Env.get_class
env c with
5021 Option.is_some
@@ Env.get_static_member
true env class_ mid
)
5024 let (_env
, tyl
) = TUtils.get_concrete_supertypes
env cty
in
5025 List.exists tyl ~f
:lookup_member
5031 ?
(explicit_targs
= [])
5033 ?
(function_pointer
= false)
5038 let (env, this_ty) =
5040 this_for_method
env cid cty
5062 ?
(explicit_targs
= [])
5064 ?
(function_pointer
= false)
5069 let (env, cty
) = Env.expand_type
env cty
in
5070 match deref cty
with
5071 | (r, Tany _
) -> (env, (mk
(r, Typing_utils.tany
env), []))
5072 | (r, Terr
) -> (env, (err_witness env (Reason.to_pos
r), []))
5073 | (_
, Tdynamic
) -> (env, (cty
, []))
5074 | (_
, Tunion tyl
) ->
5076 List.map_env
env tyl
(fun env ty ->
5089 Union.union_list
env (get_reason cty
) (List.map ~f
:fst
pairs)
5092 | (_
, Tintersection tyl
) ->
5094 TUtils.run_on_intersection
env tyl ~f
:(fun env ty ->
5107 Inter.intersect_list
env (get_reason cty
) (List.map ~f
:fst
pairs)
5110 | (_
, Tnewtype
(_
, _
, ty))
5111 | (_
, Tdependent
(_
, ty)) ->
5123 | (r, Tgeneric _
) ->
5124 let (env, tyl
) = TUtils.get_concrete_supertypes
env cty
in
5125 if List.is_empty tyl
then begin
5126 Errors.non_class_member
5130 (Typing_print.error
env cty
)
5132 (env, (err_witness env p, []))
5134 let (env, ty) = Typing_intersection.intersect_list
env r tyl
in
5146 | (_
, Tclass
((_
, c), _
, paraml
)) ->
5147 let class_ = Env.get_class
env c in
5149 | None
-> (env, (Typing_utils.mk_tany
env p, []))
5151 (* We need to instantiate generic parameters in the method signature *)
5154 type_expansions
= [];
5156 substs
= TUtils.make_locl_subst_for_class_tparams
class_ paraml
;
5157 from_class
= Some
cid;
5159 on_error
= Errors.unify_error_at
p;
5162 let get_smember_from_constraints env class_info =
5164 Cls.upper_bounds_on_this_from_constraints
class_info
5166 let (env, upper_bounds) =
5167 List.map_env
env upper_bounds ~f
:(fun env up
->
5168 Phase.localize ~
ety_env env up
)
5170 let (env, inter_ty
) =
5171 Inter.intersect_list
env (Reason.Rwitness
p) upper_bounds
5185 let try_get_smember_from_constraints env class_info =
5186 Errors.try_with_error
5187 (fun () -> get_smember_from_constraints env class_info)
5189 TOG.smember_not_found
5196 (env, (TUtils.terr
env Reason.Rnone
, [])))
5201 Env.get_const
env class_ mid
5203 match Env.get_typeconst
env class_ mid
with
5205 Errors.illegal_typeconst_direct_access
p;
5207 | None
-> Env.get_const
env class_ mid
5210 | None
when Cls.has_upper_bounds_on_this_from_constraints
class_ ->
5211 try_get_smember_from_constraints env class_
5213 TOG.smember_not_found
5220 (env, (TUtils.terr
env Reason.Rnone
, []))
5221 | Some
{ cc_type
; cc_abstract
; cc_pos
; _
} ->
5222 let (env, cc_locl_type
) = Phase.localize ~
ety_env env cc_type
in
5223 ( if cc_abstract
then
5229 let cc_name = Cls.name class_ ^
"::" ^ mid
in
5230 Errors.abstract_const_usage
p cc_pos
cc_name );
5231 (env, (cc_locl_type
, []))
5233 let static_member_opt =
5234 Env.get_static_member is_method
env class_ mid
5236 (match static_member_opt with
5237 | None
when Cls.has_upper_bounds_on_this_from_constraints
class_ ->
5238 try_get_smember_from_constraints env class_
5240 TOG.smember_not_found
5247 (env, (TUtils.terr
env Reason.Rnone
, []))
5250 ce_visibility = vis
;
5251 ce_type
= (lazy member_decl_ty
);
5255 let def_pos = get_pos member_decl_ty
in
5256 TVis.check_class_access
5260 (vis
, get_ce_lsb ce
)
5263 TVis.check_deprecated ~
use_pos:p ~
def_pos ce_deprecated;
5264 check_class_get
env p def_pos c mid ce
cid function_pointer
;
5265 let (env, member_ty
, et_enforced
, tal
) =
5266 match deref member_decl_ty
with
5267 (* We special case Tfun here to allow passing in explicit tparams to localize_ft. *)
5268 | (r, Tfun
ft) when is_method
->
5269 let (env, explicit_targs
) =
5270 Phase.localize_targs
5271 ~check_well_kinded
:true
5275 ~use_name
:(strip_ns mid
)
5278 (List.map ~f
:snd explicit_targs
)
5281 Typing_enforceability.compute_enforced_and_pessimize_fun_type
5289 { use_name
= strip_ns mid
; use_pos = p; explicit_targs
}
5295 (env, mk
(r, Tfun
ft), false, explicit_targs
)
5298 let { et_type
; et_enforced
} =
5299 Typing_enforceability.compute_enforced_and_pessimize_ty
5303 let (env, member_ty
) = Phase.localize ~
ety_env env et_type
in
5304 (* TODO(T52753871) make function just return possibly_enforced_ty
5305 * after considering intersection case *)
5306 (env, member_ty
, et_enforced
, [])
5308 let (env, member_ty
) =
5309 if Cls.has_upper_bounds_on_this_from_constraints
class_ then
5310 let ((env, (member_ty'
, _
)), succeed
) =
5311 Errors.try_with_error
5312 (fun () -> (get_smember_from_constraints env class_, true))
5314 (* No eligible functions found in constraints *)
5315 ((env, (MakeType.mixed Reason.Rnone
, [])), false))
5318 Inter.intersect
env (Reason.Rwitness
p) member_ty member_ty'
5325 match coerce_from_ty
with
5327 | Some
(p, ur, ty) ->
5328 Typing_coercion.coerce_type
5333 { et_type
= member_ty
; et_enforced
}
5336 (env, (member_ty
, tal
))))
5337 | (_
, Tunapplied_alias _
) ->
5338 Typing_defs.error_Tunapplied_alias_in_illegal_context
()
5340 ( Tvar _
| Tnonnull
| Tvarray _
| Tdarray _
| Tvarray_or_darray _
5341 | Toption _
| Tprim _
| Tfun _
| Ttuple _
| Tobject
| Tshape _
| Taccess _
5343 Errors.non_class_member
5347 (Typing_print.error
env cty
)
5349 (env, (err_witness env p, []))
5351 and class_id_for_new
5352 ~exact
p env (cid : Nast.class_id_
) (explicit_targs
: Nast.targ list
) :
5353 newable_class_info
=
5354 let (env, tal
, te, cid_ty
) =
5356 ~check_targs_well_kinded
:true
5357 ~check_explicit_targs
:true
5359 ~check_constraints
:false
5365 (* Need to deal with union case *)
5366 let rec get_info res tyl
=
5368 | [] -> (env, tal
, te, res
)
5370 (match get_node
ty with
5372 | Tintersection tyl'
->
5373 get_info res
(tyl'
@ tyl
)
5375 (* Instantiation on an abstract class (e.g. from classname<T>) is
5376 * via the base type (to check constructor args), but the actual
5377 * type `ty` must be preserved. *)
5378 (match get_node
(TUtils.get_base_type
env ty) with
5379 | Tdynamic
-> get_info (`Dynamic
:: res
) tyl
5380 | Tclass
(sid
, _
, _
) ->
5381 let class_ = Env.get_class
env (snd sid
) in
5383 | None
-> get_info res tyl
5384 | Some
class_info ->
5385 (match (te, cid_ty
) with
5386 (* When computing the classes for a new T() where T is a generic,
5387 * the class must be consistent (final, final constructor, or
5388 * <<__ConsistentConstruct>>) for its constructor to be considered *)
5389 | ((_
, Aast.CI
(_
, c)), ty) when is_generic_equal_to
c ty ->
5390 (* Only have this choosing behavior for new T(), not all generic types
5391 * i.e. new classname<T>, TODO: T41190512 *)
5392 if Tast_utils.valid_newable_class
class_info then
5393 get_info (`Class
(sid
, class_info, ty) :: res
) tyl
5396 | _
-> get_info (`Class
(sid
, class_info, ty) :: res
) tyl
))
5397 | _
-> get_info res tyl
))
5399 get_info [] [cid_ty
]
5401 (* To be a valid trait declaration, all of its 'require extends' must
5402 * match; since there's no multiple inheritance, it follows that all of
5403 * the 'require extends' must belong to the same inheritance hierarchy
5404 * and one of them should be the child of all the others *)
5405 and trait_most_concrete_req_class trait
env =
5407 (Cls.all_ancestor_reqs trait
)
5411 let (_r
, (_p
, name), _paraml
) = TUtils.unwrap_class_type
ty in
5414 | Some
(c, _ty
) -> Cls.has_ancestor
c name
5420 let class_ = Env.get_class
env name in
5423 | Some
c when Ast_defs.(equal_class_kind
(Cls.kind
c) Cinterface
) ->
5425 | Some
c when Ast_defs.(equal_class_kind
(Cls.kind
c) Ctrait
) ->
5426 (* this is an error case for which Typing_check_decls spits out
5427 * an error, but does *not* currently remove the offending
5428 * 'require extends' or 'require implements' *)
5430 | Some
c -> Some
(c, ty)
5434 (* When invoking a method the class_id is used to determine what class we
5435 * lookup the method in, but the type of 'this' will be the late bound type.
5439 * public static function get(): this { return new static(); }
5441 * public static function alias(): this { return self::get(); }
5444 * In C::alias, when we invoke self::get(), 'self' is resolved to the class
5445 * in the lexical scope (C), so call C::get. However the method is executed in
5446 * the current context, so static inside C::get will be resolved to the late
5447 * bound type (get_called_class() within C::alias).
5449 * This means when determining the type of this, CIparent and CIself should be
5450 * changed to CIstatic. For the other cases of C::get() or $c::get(), we only
5451 * look at the left hand side of the '::' and use the type type associated
5454 * Thus C::get() will return a type C, while $c::get() will return the same
5457 and this_for_method
env cid default_ty
=
5462 let p = get_pos default_ty
in
5463 let (env, _tal
, _te
, ty) =
5464 static_class_id ~check_constraints
:false p env [] CIstatic
5466 ExprDepTy.make
env CIstatic
ty
5467 | _
-> (env, default_ty
)
5469 (** Resolve class expressions like `parent`, `self`, `static`, classnames
5472 ?
(check_targs_well_kinded
= false)
5474 ?
(check_explicit_targs
= false)
5475 ~
(check_constraints
: bool)
5478 (tal
: Nast.targ list
) :
5479 Nast.class_id_
-> env * Tast.targ list
* Tast.class_id
* locl_ty
=
5480 let make_result env tal
te ty = (env, tal
, ((p, ty), te), ty) in
5483 (match get_class_type
(Env.get_self
env) with
5484 | Some
((_
, self
), _
, _
) ->
5485 (match Env.get_class
env self
with
5486 | Some trait
when Ast_defs.(equal_class_kind
(Cls.kind trait
) Ctrait
) ->
5487 (match trait_most_concrete_req_class trait
env with
5489 Errors.parent_in_trait
p;
5490 make_result env [] Aast.CIparent
(err_witness env p)
5491 | Some
(_
, parent_ty
) ->
5492 (* inside a trait, parent is SN.Typehints.this, but with the
5493 * type of the most concrete class that the trait has
5494 * "require extend"-ed *)
5495 let r = Reason.Rwitness
p in
5496 let (env, parent_ty
) = Phase.localize_with_self
env parent_ty
in
5497 make_result env [] Aast.CIparent
(mk
(r, TUtils.this_of parent_ty
)))
5500 match Env.get_parent_ty
env with
5502 Errors.parent_undefined
p;
5503 mk
(Reason.none
, Typing_defs.make_tany
())
5504 | Some
parent -> parent
5506 let r = Reason.Rwitness
p in
5507 let (env, parent) = Phase.localize_with_self
env parent in
5508 (* parent is still technically the same object. *)
5513 (mk
(r, TUtils.this_of
(mk
(r, get_node
parent)))))
5516 match Env.get_parent_ty
env with
5518 Errors.parent_undefined
p;
5519 mk
(Reason.none
, Typing_defs.make_tany
())
5520 | Some
parent -> parent
5522 let r = Reason.Rwitness
p in
5523 let (env, parent) = Phase.localize_with_self
env parent in
5524 (* parent is still technically the same object. *)
5529 (mk
(r, TUtils.this_of
(mk
(r, get_node
parent)))))
5531 let this = mk
(Reason.Rwitness
p, TUtils.this_of
(Env.get_self
env)) in
5532 make_result env [] Aast.CIstatic
this
5535 match get_node
(Env.get_self
env) with
5536 | Tclass
(c, _
, tyl
) -> Tclass
(c, exact
, tyl
)
5539 make_result env [] Aast.CIself
(mk
(Reason.Rwitness
p, self))
5540 | CI
((p, id) as c) as e1
->
5542 match Env.get_pos_and_kind_of_generic
env id with
5543 | Some
(def_pos, kind
) ->
5544 let simple_kind = Typing_kinding_defs.Simple.from_full_kind kind
in
5546 Typing_kinding_defs.Simple.get_named_parameter_kinds
simple_kind
5549 Phase.localize_targs_with_kinds
5550 ~check_well_kinded
:check_targs_well_kinded
5554 ~use_name
:(strip_ns
(snd
c))
5555 ~check_explicit_targs
5558 (List.map ~f
:snd tal
)
5560 let r = Reason.Rhint
p in
5561 let type_args = List.map tal fst
in
5562 let tgeneric = MakeType.generic ~
type_args r id in
5563 make_result env tal
(Aast.CI
c) tgeneric
5565 (* Not a type parameter *)
5566 let class_ = Env.get_class
env id in
5568 | None
-> make_result env [] (Aast.CI
c) (Typing_utils.mk_tany
env p)
5570 let (env, ty, tal
) =
5572 |> Phase.localize_targs_and_check_constraints
5574 ~check_well_kinded
:check_targs_well_kinded
5576 ~
def_pos:(Cls.pos class_)
5578 ~check_explicit_targs
5582 (Cls.tparams
class_)
5584 make_result env tal
(Aast.CI
c) ty)
5586 | CIexpr
((p, _
) as e) ->
5587 let (env, te, ty) = expr env e in
5588 let rec resolve_ety env ty =
5590 Typing_solver.expand_type_and_solve
5591 ~description_of_expected
:"an object"
5597 let base_ty = TUtils.get_base_type
env ty in
5598 match deref
base_ty with
5599 | (_
, Tnewtype
(classname, [the_cls
], _
))
5600 when String.equal
classname SN.Classes.cClassname
->
5601 resolve_ety env the_cls
5605 | (r, Tunion tyl
) ->
5606 let (env, tyl
) = List.map_env
env tyl
resolve_ety in
5607 (env, MakeType.union r tyl
)
5608 | (r, Tintersection tyl
) ->
5609 let (env, tyl
) = TUtils.run_on_intersection
env tyl ~f
:resolve_ety in
5610 Inter.intersect_list
env r tyl
5611 | (_
, Tdynamic
) -> (env, base_ty)
5612 | (_
, (Tany _
| Tprim Tstring
| Tobject
)) when not
(Env.is_strict
env) ->
5613 (env, Typing_utils.mk_tany
env p)
5614 | (_
, Terr
) -> (env, err_witness env p)
5616 Errors.unknown_type
"an object" p (Reason.to_string
"It is unknown" r);
5617 (env, err_witness env p)
5618 | (_
, Tunapplied_alias _
) ->
5619 Typing_defs.error_Tunapplied_alias_in_illegal_context
()
5621 ( Tany _
| Tnonnull
| Tvarray _
| Tdarray _
| Tvarray_or_darray _
5622 | Toption _
| Tprim _
| Tfun _
| Ttuple _
| Tnewtype _
| Tdependent _
5623 | Tobject
| Tshape _
| Taccess _
) ) ->
5624 Errors.expected_class
5625 ~suffix
:(", but got " ^
Typing_print.error
env base_ty)
5627 (env, err_witness env p)
5629 let (env, result_ty
) = resolve_ety env ty in
5630 make_result env [] (Aast.CIexpr
te) result_ty
5632 and call_construct
p env class_ params el unpacked_element
cid cid_ty
=
5634 if Nast.equal_class_id_
cid CIparent
then
5635 (CIstatic
, mk
(Reason.Rwitness
p, TUtils.this_of
(Env.get_self
env)))
5641 type_expansions
= [];
5643 substs
= TUtils.make_locl_subst_for_class_tparams
class_ params;
5644 from_class
= Some
cid;
5646 on_error
= Errors.unify_error_at
p;
5650 Phase.check_tparams_constraints ~
use_pos:p ~
ety_env env (Cls.tparams
class_)
5653 Phase.check_where_constraints
5656 ~definition_pos
:(Cls.pos class_)
5659 (Cls.where_constraints
class_)
5661 if Cls.is_xhp
class_ then
5662 (env, [], None
, TUtils.mk_tany
env p)
5664 let cstr = Env.get_construct
env class_ in
5665 let mode = Env.get_mode
env in
5669 ((not
(List.is_empty el
)) || Option.is_some unpacked_element
)
5670 && (FileInfo.is_strict
mode || FileInfo.(equal_mode
mode Mpartial
))
5671 && Cls.members_fully_known
class_
5673 Errors.constructor_no_args
p;
5674 let (env, tel
, _tyl
) = exprs env el
in
5675 (env, tel
, None
, TUtils.terr
env Reason.Rnone
)
5676 | Some
{ ce_visibility = vis
; ce_type
= (lazy m
); ce_deprecated; _
} ->
5677 let def_pos = get_pos m
in
5678 TVis.check_obj_access ~
use_pos:p ~
def_pos env vis
;
5679 TVis.check_deprecated ~
use_pos:p ~
def_pos ce_deprecated;
5680 (* Obtain the type of the constructor *)
5685 Typing_enforceability.compute_enforced_and_pessimize_fun_type
env ft
5691 { use_name
= "constructor"; use_pos = p; explicit_targs
= [] }
5697 (env, mk
(r, Tfun
ft))
5699 Errors.internal_error
p "Expected function type for constructor";
5700 let ty = TUtils.terr
env r in
5703 let (env, (tel
, typed_unpack_element
, _ty
)) =
5704 call ~
expected:None
p env m el unpacked_element
5706 (env, tel
, typed_unpack_element
, m
)
5708 and check_arity ?
(did_unpack
= false) pos pos_def
ft (arity
: int) =
5709 let exp_min = Typing_defs.arity_min
ft in
5710 if arity
< exp_min then
5711 Errors.typing_too_few_args
exp_min arity
pos pos_def None
;
5712 match ft.ft_arity
with
5714 let exp_max = List.length
ft.ft_params
in
5721 if arity > exp_max then
5722 Errors.typing_too_many_args
exp_max arity pos pos_def None
5725 and check_lambda_arity lambda_pos
def_pos lambda_ft
expected_ft =
5726 match (lambda_ft
.ft_arity
, expected_ft.ft_arity
) with
5727 | (Fstandard
, Fstandard
) ->
5728 let expected_min = Typing_defs.arity_min
expected_ft in
5729 let lambda_min = Typing_defs.arity_min lambda_ft
in
5730 if lambda_min < expected_min then
5731 Errors.typing_too_few_args
expected_min lambda_min lambda_pos
def_pos None
;
5732 if lambda_min > expected_min then
5733 Errors.typing_too_many_args
5741 (* The variadic capture argument is an array listing the passed
5742 * variable arguments for the purposes of the function body; callsites
5743 * should not unify with it *)
5744 and variadic_param
env ft =
5745 match ft.ft_arity
with
5746 | Fvariadic
param -> (env, Some
param)
5747 | Fstandard
-> (env, None
)
5749 and param_modes ?
(is_variadic
= false) ({ fp_pos
; _
} as fp
) (pos, e) =
5750 match (get_fp_mode fp
, e) with
5751 | (FPnormal
, Callconv _
) ->
5752 Errors.inout_annotation_unexpected
pos fp_pos is_variadic
5753 | (FPnormal
, _
) -> ()
5754 | (FPinout
, Callconv
(Ast_defs.Pinout
, _
)) -> ()
5755 | (FPinout
, _
) -> Errors.inout_annotation_missing
pos fp_pos
5757 and inout_write_back
env { fp_type
; _
} (_
, e) =
5759 | Callconv
(Ast_defs.Pinout
, e1
) ->
5760 (* Translate the write-back semantics of inout parameters.
5762 * This matters because we want to:
5763 * (1) make sure we can write to the original argument
5764 * (modifiable lvalue check)
5765 * (2) allow for growing of locals / Tunions (type side effect)
5766 * but otherwise unify the argument type with the parameter hint
5768 let (env, _te
, _ty
) =
5769 assign_
(fst e1
) Reason.URparam_inout
env e1 fp_type
.et_type
5774 (** Typechecks a call.
5775 Returns in this order the typed expressions for the arguments, for the variadic arguments, and the return type. *)
5777 ~
(expected : ExpectedTy.t
option)
5778 ?
(method_call_info
: TR.method_call_info
option)
5779 ?
(nullsafe : Pos.t
option = None
)
5784 (el
: Nast.expr list
)
5785 (unpacked_element
: Nast.expr option) :
5786 env * (Tast.expr list
* Tast.expr option * locl_ty
) =
5788 TUtils.try_over_concrete_supertypes
env fty (fun env fty ->
5790 if TypecheckerOptions.method_call_inference
(Env.get_tcopt
env) then
5791 Env.expand_type
env fty
5793 Typing_solver.expand_type_and_solve
5794 ~description_of_expected
:"a function value"
5800 match deref efty
with
5801 | (r, ((Tprim Tnull
| Tdynamic
| Terr
| Tany _
| Tunion
[]) as ty))
5803 | Tprim Tnull
-> Option.is_some
nullsafe
5806 Option.value_map ~f
:(fun u
-> el @ [u
]) ~
default:el unpacked_element
5808 let expected_arg_ty =
5809 (* Note: We ought to be using 'mixed' here *)
5810 ExpectedTy.make
pos Reason.URparam
(Typing_utils.mk_tany
env pos)
5813 List.map_env
env el (fun env elt
->
5814 let (env, te, ty) = expr ~
expected:expected_arg_ty env elt
in
5816 if TCO.global_inference
(Env.get_tcopt
env) then
5817 match get_node efty
with
5821 Typing_coercion.coerce_type
5826 (MakeType.unenforced efty
)
5834 | (_
, Callconv
(Ast_defs.Pinout
, e1
)) ->
5835 let (env, _te
, _ty
) =
5836 assign_
(fst e1
) Reason.URparam_inout
env e1 efty
5844 call_untyped_unpack
env (Reason.to_pos
r) unpacked_element
5848 | Tprim Tnull
-> mk
(r, Tprim Tnull
)
5849 | Tdynamic
-> MakeType.dynamic
(Reason.Rdynamic_call
pos)
5852 Typing_utils.mk_tany
env pos
5854 | _
(* _ should not happen! *) ->
5857 (env, (tel
, None
, ty))
5858 | (_
, Tunion
[ty]) ->
5859 call ~
expected ~
nullsafe ?in_await
pos env ty el unpacked_element
5860 | (r, Tunion tyl
) ->
5862 List.map_env
env tyl
(fun env ty ->
5873 let retl = List.map resl ~f
:(fun (_
, _
, x) -> x) in
5874 let (env, ty) = Union.union_list
env r retl in
5875 (* We shouldn't be picking arbitrarily for the TAST here, as TAST checks
5876 * depend on the types inferred. Here's we're preserving legacy behaviour
5877 * by picking the last one.
5878 * TODO: don't do this, instead use subtyping to push unions
5879 * through function types
5881 let (tel
, typed_unpack_element
, _
) = List.hd_exn
(List.rev
resl) in
5882 (env, (tel
, typed_unpack_element
, ty))
5883 | (r, Tintersection tyl
) ->
5885 TUtils.run_on_intersection
env tyl ~f
:(fun env ty ->
5896 let retl = List.map resl ~f
:(fun (_
, _
, x) -> x) in
5897 let (env, ty) = Inter.intersect_list
env r retl in
5898 (* We shouldn't be picking arbitrarily for the TAST here, as TAST checks
5899 * depend on the types inferred. Here we're preserving legacy behaviour
5900 * by picking the last one.
5901 * TODO: don't do this, instead use subtyping to push intersections
5902 * through function types
5904 let (tel
, typed_unpack_element
, _
) = List.hd_exn
(List.rev
resl) in
5905 (env, (tel
, typed_unpack_element
, ty))
5907 (* Typing of format string functions. It is dependent on the arguments (el)
5908 * so it cannot be done earlier.
5910 let pos_def = Reason.to_pos r2
in
5911 let (env, ft) = Typing_exts.retype_magic_func
env ft el in
5912 let (env, var_param) = variadic_param
env ft in
5913 (* Force subtype with expected result *)
5915 check_expected_ty
"Call result" env ft.ft_ret.et_type
expected
5917 let env = Env.set_tyvar_variance
env ft.ft_ret.et_type
in
5925 let get_next_param_info paraml
=
5927 | param :: paraml
-> (false, Some
param, paraml
)
5928 | [] -> (true, var_param, paraml
)
5930 (* TODO: We're using plain String at the moment, until we
5931 * introduce actual atom notation (#A instead of "A")
5933 let expand_atom_in_enum env enum_name atom_name
=
5934 let cls = Env.get_class
env enum_name
in
5937 (match Env.get_const
env cls atom_name
with
5939 let dty = const_def
.cc_type
in
5940 let (env, lty
) = Phase.localize_with_self
env dty in
5941 let hi = (pos, lty
) in
5942 let te = (hi, EnumAtom atom_name
) in
5943 (env, Some
(te, lty
))
5945 Errors.atom_unknown
pos atom_name enum_name
;
5947 | None
-> (env, None
)
5949 let check_arg env ((pos, arg
) as e) opt_param ~is_variadic
=
5950 match opt_param
with
5952 (* First check if __Atom is used *)
5953 let (env, atom_type
) =
5954 let is_atom = get_fp_is_atom
param in
5955 let ety = param.fp_type
.et_type
in
5957 | EnumAtom atom_name
when is_atom ->
5958 (match get_node
ety with
5959 | Tclass
((_
, name), _
, [ty_enum
; _ty_interface
])
5960 when String.equal
name SN.Classes.cEnumMember
->
5961 (match get_node ty_enum
with
5962 | Tclass
((_
, enum_name
), _
, _
)
5963 when Env.is_enum_class
env enum_name
->
5964 expand_atom_in_enum env enum_name atom_name
5965 | Tgeneric
(name, _
) ->
5967 Typing_utils.collect_enum_class_upper_bounds
env name
5969 (* To avoid ambiguity, we only support the case where
5970 * there is a single upper bound that is an EnumClass.
5971 * We might want to relax that later (e.g. with the
5972 * support for intersections.
5973 * See Typing_check_decls.check_atom_on_param.
5975 if SSet.cardinal
upper_bounds = 1 then
5976 let enum_name = SSet.choose
upper_bounds in
5977 expand_atom_in_enum env enum_name atom_name
5981 (* Already reported, see Typing_check_decls *)
5984 (* Already reported, see Typing_check_decls *)
5986 | Class_const _
when is_atom ->
5987 Errors.atom_invalid_argument
pos;
5992 match atom_type
with
5993 | Some
(te, ty) -> (env, te, ty)
5996 ExpectedTy.make_and_allow_coercion
6002 ~accept_using_var
:(get_fp_accept_disposable
param)
6007 let env = call_param
env param (e, ty) ~is_variadic
in
6008 (env, Some
(te, ty))
6014 (Typing_utils.mk_tany
env pos)
6016 let (env, te, ty) = expr ~
expected env e in
6017 (env, Some
(te, ty))
6019 let set_tyvar_variance_from_lambda_param env opt_param
=
6020 match opt_param
with
6022 let rec set_params_variance env ty =
6023 let (env, ty) = Env.expand_type
env ty in
6024 match get_node
ty with
6025 | Tunion
[ty] -> set_params_variance env ty
6026 | Toption
ty -> set_params_variance env ty
6027 | Tfun
{ ft_params
; ft_ret; _
} ->
6031 ~f
:(fun env param ->
6032 Env.set_tyvar_variance
env param.fp_type
.et_type
)
6035 Env.set_tyvar_variance
env ft_ret.et_type ~flip
:true
6038 set_params_variance env param.fp_type
.et_type
6041 (* Given an expected function type ft, check types for the non-unpacked
6042 * arguments. Don't check lambda expressions if check_lambdas=false *)
6043 let rec check_args check_lambdas
env el paraml
=
6045 (* We've got an argument *)
6046 | (e, opt_result
) :: el ->
6047 (* Pick up next parameter type info *)
6048 let (is_variadic
, opt_param
, paraml
) =
6049 get_next_param_info paraml
6051 let (env, one_result
) =
6052 match (check_lambdas
, is_lambda e) with
6055 check_arg env e opt_param ~is_variadic
6058 set_tyvar_variance_from_lambda_param env opt_param
6061 | (true, false) -> (env, opt_result
)
6063 let (env, rl
, paraml
) = check_args check_lambdas
env el paraml
in
6064 (env, (e, one_result
) :: rl
, paraml
)
6065 | [] -> (env, [], paraml
)
6067 (* Same as above, but checks the types of the implicit arguments, which are
6068 * read from the context *)
6069 let check_implicit_args env =
6071 Typing_coeffects.get_type
ft.ft_implicit_params
.capability
6073 if not
(TypecheckerOptions.call_coeffects
(Env.get_tcopt
env)) then
6076 let env_capability =
6077 Env.get_local_check_defined
6079 (pos, Typing_coeffects.capability_id
)
6087 (fun ?code
:_c _ _
->
6088 Errors.call_coeffect_error
6090 ~available_incl_unsafe
:
6091 (Typing_print.coeffects
env env_capability)
6092 ~available_pos
:(Typing_defs.get_pos
env_capability)
6093 ~required_pos
:(Typing_defs.get_pos
capability)
6094 ~required
:(Typing_print.coeffects
env capability))
6097 (* First check the non-lambda arguments. For generic functions, this
6098 * is likely to resolve type variables to concrete types *)
6099 let rl = List.map el (fun e -> (e, None
)) in
6100 let (env, rl, _
) = check_args false env rl ft.ft_params
in
6101 (* Now check the lambda arguments, hopefully with type variables resolved *)
6102 let (env, rl, paraml
) = check_args true env rl ft.ft_params
in
6103 (* We expect to see results for all arguments after this second pass *)
6107 | None
-> failwith
"missing parameter in check_args"
6110 let l = List.map rl (fun (_
, opt
) -> get_param opt
) in
6113 let env = check_implicit_args env in
6114 let env = TR.check_call env method_call_info
pos r2
ft tys
in
6115 let (env, typed_unpack_element
, arity, did_unpack
) =
6116 match unpacked_element
with
6117 | None
-> (env, None
, List.length
el, false)
6119 (* Now that we're considering an splat (Some e) we need to construct a type that
6120 * represents the remainder of the function's parameters. `paraml` represents those
6121 * remaining parameters, and the variadic parameter is stored in `var_param`. For example, given
6123 * function f(int $i, string $j, float $k = 3.14, mixed ...$m): void {}
6124 * function g((string, float, bool) $t): void {
6128 * the constraint type we want is splat([#1], [opt#2], #3).
6130 let (consumed
, required_params
, optional_params
) =
6131 split_remaining_params_required_optional
ft paraml
6133 let (env, (d_required
, d_optional
, d_variadic
)) =
6134 generate_splat_type_vars
6141 let destructure_ty =
6144 ( Reason.Runpack_param
(fst
e, pos_def, consumed
),
6150 d_kind
= SplatUnpack
;
6153 let (env, te, ty) = expr env e in
6154 (* Populate the type variables from the expression in the splat *)
6164 (* Use the type variables for the remaining parameters *)
6170 ~f
:(fun env elt
param ->
6171 call_param
env param (e, elt
) ~is_variadic
:false)
6178 ~f
:(fun env elt
param ->
6179 call_param
env param (e, elt
) ~is_variadic
:false)
6182 Option.map2 d_variadic
var_param ~f
:(fun v vp
->
6183 call_param
env vp
(e, v
) ~is_variadic
:true)
6184 |> Option.value ~
default:env
6188 List.length
el + List.length d_required
,
6189 Option.is_some d_variadic
)
6191 (* If we unpacked an array, we don't check arity exactly. Since each
6192 * unpacked array consumes 1 or many parameters, it is nonsensical to say
6193 * that not enough args were passed in (so we don't do the min check).
6195 let () = check_arity ~did_unpack
pos pos_def ft arity in
6196 (* Variadic params cannot be inout so we can stop early *)
6197 let env = wfold_left2 inout_write_back
env ft.ft_params
el in
6199 TR.get_adjusted_return_type
env method_call_info
ft.ft_ret.et_type
6201 (env, (tel
, typed_unpack_element
, ret_ty))
6203 when TypecheckerOptions.method_call_inference
(Env.get_tcopt
env) ->
6205 Typecheck calls with unresolved function type by constructing a
6206 suitable function type from the arguments and invoking subtyping.
6208 let (env, typed_el
, type_of_el
) =
6209 exprs ~accept_using_var
:true env el
6211 let (env, typed_unpacked_element
, type_of_unpacked_element
) =
6212 match unpacked_element
with
6214 let (env, typed_unpacked
, type_of_unpacked
) =
6215 expr ~accept_using_var
:true env unpacked
6217 (env, Some typed_unpacked
, Some type_of_unpacked
)
6218 | None
-> (env, None
, None
)
6220 let mk_function_supertype
6221 env pos (type_of_el
, type_of_unpacked_element
) =
6222 let mk_fun_param ty =
6224 (* Keep supertype as permissive as possible: *)
6226 ~
mode:FPnormal
(* TODO: deal with `inout` parameters *)
6227 ~accept_disposable
:false (* TODO: deal with disposables *)
6228 ~mutability
:(Some Param_maybe_mutable
)
6237 fp_type
= MakeType.enforced ty;
6238 fp_rx_annotation
= None
;
6243 match type_of_unpacked_element
with
6244 | Some type_of_unpacked
->
6245 let fun_param = mk_fun_param type_of_unpacked
in
6249 (* TODO: ensure `ft_params`/`ft_where_constraints` don't affect subtyping *)
6250 let ft_tparams = [] in
6251 let ft_where_constraints = [] in
6252 let ft_params = List.map ~f
:mk_fun_param type_of_el
in
6253 let ft_implicit_params =
6257 (* TODO(coeffects) should this be a different type? *);
6260 let (env, return_ty
) = Env.fresh_type
env pos in
6264 | Some
r -> MakeType.awaitable
r return_ty
6266 let ft_ret = MakeType.enforced return_ty in
6267 (* A non-reactive supertype is most permissive: *)
6268 let ft_reactive = Nonreactive
in
6270 (* Keep supertype as permissive as possible: *)
6272 Ast_defs.FSync
(* `FSync` fun can still return `Awaitable<_>` *)
6273 (Some Param_maybe_mutable
)
6274 ~return_disposable
:false (* TODO: deal with disposable return *)
6275 ~returns_mutable
:false
6276 ~returns_void_to_rx
:false
6278 let ft_ifc_decl = Typing_defs_core.default_ifc_fun_decl
in
6283 ft_where_constraints;
6292 let fun_type = mk
(r, Tfun
fun_locl_type) in
6293 let env = Env.set_tyvar_variance
env fun_type in
6294 (env, fun_type, return_ty)
6296 let (env, fun_type, return_ty) =
6297 mk_function_supertype env pos (type_of_el
, type_of_unpacked_element
)
6300 Type.sub_type
pos Reason.URnone
env efty
fun_type Errors.unify_error
6302 (env, (typed_el
, typed_unpacked_element
, return_ty))
6304 bad_call
env pos efty
;
6305 let env = call_untyped_unpack
env (get_pos efty
) unpacked_element
in
6306 (env, ([], None
, err_witness env pos)))
6311 bad_call
env pos fty;
6312 let env = call_untyped_unpack
env (get_pos
fty) unpacked_element
in
6313 (env, ([], None
, err_witness env pos))
6315 and split_remaining_params_required_optional
ft remaining_params =
6316 (* Same example as above
6318 * function f(int $i, string $j, float $k = 3.14, mixed ...$m): void {}
6319 * function g((string, float, bool) $t): void {
6323 * `remaining_params` will contain [string, float] and there has been 1 parameter consumed. The min_arity
6324 * of this function is 2, so there is 1 required parameter remaining and 1 optional parameter.
6328 ~f
:(fun fp
-> not
(Typing_defs.get_fp_has_default fp
))
6331 let original_params = ft.ft_params in
6332 let consumed = List.length
original_params - List.length
remaining_params in
6333 let required_remaining = Int.max
(min_arity - consumed) 0 in
6334 let (required_params
, optional_params
) =
6335 List.split_n
remaining_params required_remaining
6337 (consumed, required_params
, optional_params
)
6339 and generate_splat_type_vars
6340 env p required_params optional_params variadic_param
=
6341 let (env, d_required
) =
6342 List.map_env
env required_params ~f
:(fun env _
-> Env.fresh_type
env p)
6344 let (env, d_optional
) =
6345 List.map_env
env optional_params ~f
:(fun env _
-> Env.fresh_type
env p)
6347 let (env, d_variadic
) =
6348 match variadic_param
with
6349 | None
-> (env, None
)
6351 let (env, ty) = Env.fresh_type
env p in
6354 (env, (d_required
, d_optional
, d_variadic
))
6356 and call_param
env param (((pos, _
) as e), arg_ty
) ~is_variadic
=
6357 param_modes ~is_variadic
param e;
6359 (* When checking params, the type 'x' may be expression dependent. Since
6360 * we store the expression id in the local env for Lvar, we want to apply
6365 | Lvar _
-> ExprDepTy.make
env (CIexpr
e) arg_ty
6366 | _
-> (env, arg_ty
)
6368 Typing_coercion.coerce_type
6376 and call_untyped_unpack
env f_pos unpacked_element
=
6377 match unpacked_element
with
6378 (* In the event that we don't have a known function call type, we can still
6379 * verify that any unpacked arguments (`...$args`) are something that can
6380 * be actually unpacked. *)
6383 let (env, _
, ety) = expr env e in
6384 let (env, ty) = Env.fresh_type
env (fst
e) in
6385 let destructure_ty =
6386 MakeType.simple_variadic_splat
(Reason.Runpack_param
(fst
e, f_pos
, 0)) ty
6396 and bad_call
env p ty = Errors.bad_call
p (Typing_print.error
env ty)
6398 and make_a_local_of
env e =
6400 | (p, Class_get
((_
, cname
), CGstring
(_
, member_name
), _
)) ->
6401 let (env, local) = Env.FakeMembers.make_static
env cname member_name
p in
6402 (env, Some
(p, local))
6405 ((((_
, This
) | (_
, Lvar _
)) as obj
), (_
, Id
(_
, member_name
)), _
, _
) )
6407 let (env, local) = Env.FakeMembers.make
env obj member_name
p in
6408 (env, Some
(p, local))
6410 | (_
, Dollardollar
x) ->
6414 (* This function captures the common bits of logic behind refinement
6415 * of the type of a local variable or a class member variable as a
6416 * result of a dynamic check (e.g., nullity check, simple type check
6417 * using functions like is_int, is_string, is_array etc.). The
6418 * argument refine is a function that takes the type of the variable
6419 * and returns a refined type (making necessary changes to the
6420 * environment, which is threaded through).
6422 * All refinement functions return, in addition to the updated
6423 * environment, a (conservative) set of all the locals that got
6424 * refined. This set is used to construct AssertEnv statmements in
6427 and refine_lvalue_type
env (((_p
, ty), _
) as te) ~refine
=
6428 let (env, ty) = refine
env ty in
6429 let e = Tast.to_nast_expr
te in
6430 let (env, localopt
) = make_a_local_of
env e in
6431 (* TODO TAST: generate an assignment to the fake local in the TAST *)
6433 | Some lid
-> (set_local
env lid
ty, Local_id.Set.singleton
(snd lid
))
6434 | None
-> (env, Local_id.Set.empty
)
6436 and condition_nullity ~nonnull
(env : env) te =
6438 (* assignment: both the rhs and lhs of the '=' must be made null/non-null *)
6439 | (_
, Aast.Binop
(Ast_defs.Eq None
, var
, te)) ->
6440 let (env, lset1
) = condition_nullity ~nonnull
env te in
6441 let (env, lset2
) = condition_nullity ~nonnull
env var
in
6442 (env, Local_id.Set.union lset1 lset2
)
6443 (* case where `Shapes::idx(...)` must be made null/non-null *)
6446 ( (_
, Aast.Class_const
((_
, Aast.CI
(_
, shapes
)), (_
, idx
))),
6450 when String.equal shapes
SN.Shapes.cShapes
&& String.equal idx
SN.Shapes.idx
6452 let field = Tast.to_nast_expr
field in
6453 let refine env shape_ty
=
6455 Typing_shapes.shapes_idx_not_null
env shape_ty
field
6459 refine_lvalue_type
env shape ~
refine
6463 Typing_solver.non_null
env p ty
6465 let r = Reason.Rwitness
(get_pos
ty) in
6466 Inter.intersect
env r ty (MakeType.null
r)
6468 refine_lvalue_type
env te ~
refine
6470 and condition_isset
env = function
6471 | (_
, Aast.Array_get
(x, _
)) -> condition_isset
env x
6472 | v
-> condition_nullity ~nonnull
:true env v
6475 * Build an environment for the true or false branch of
6476 * conditional statements.
6479 ?lhs_of_null_coalesce
env tparamet
((((p, ty) as pty
), e) as te : Tast.expr)
6481 let condition = condition ?lhs_of_null_coalesce
in
6483 | Aast.True
when not tparamet
->
6484 (LEnv.drop_cont
env C.Next
, Local_id.Set.empty
)
6485 | Aast.False
when tparamet
-> (LEnv.drop_cont
env C.Next
, Local_id.Set.empty
)
6486 | Aast.Call
((_
, Aast.Id
(_
, func
)), _
, [param], None
)
6487 when String.equal
SN.PseudoFunctions.isset func
6489 && not
(Env.is_strict
env) ->
6490 condition_isset
env param
6491 | Aast.Call
((_
, Aast.Id
(_
, func
)), _
, [te], None
)
6492 when String.equal
SN.StdlibFunctions.is_null func
->
6493 condition_nullity ~nonnull
:(not tparamet
) env te
6494 | Aast.Binop
((Ast_defs.Eqeq
| Ast_defs.Eqeqeq
), (_
, Aast.Null
), e)
6495 | Aast.Binop
((Ast_defs.Eqeq
| Ast_defs.Eqeqeq
), e, (_
, Aast.Null
)) ->
6496 condition_nullity ~nonnull
:(not tparamet
) env e
6500 | Aast.Binop
(Ast_defs.Eq None
, _
, _
) ->
6501 let (env, ety) = Env.expand_type
env ty in
6502 (match get_node
ety with
6503 | Tprim Tbool
-> (env, Local_id.Set.empty
)
6504 | _
-> condition_nullity ~nonnull
:tparamet
env te)
6505 | Aast.Binop
(((Ast_defs.Diff
| Ast_defs.Diff2
) as op
), e1
, e2) ->
6507 if Ast_defs.(equal_bop
op Diff
) then
6512 condition env (not tparamet
) (pty
, Aast.Binop
(op, e1
, e2))
6513 | Aast.Id
(_
, s) when SN.Rx.is_enabled
s ->
6514 (* when Rx\IS_ENABLED is false - switch env to non-reactive *)
6516 if not tparamet
then
6517 Env.set_env_reactive
env Nonreactive
6521 (env, Local_id.Set.empty
)
6522 (* Conjunction of conditions. Matches the two following forms:
6524 if (!(cond1 || cond2))
6526 | Aast.Binop
(((Ast_defs.Ampamp
| Ast_defs.Barbar
) as bop
), e1
, e2)
6527 when Bool.equal tparamet
Ast_defs.(equal_bop bop Ampamp
) ->
6528 let (env, lset1
) = condition env tparamet e1
in
6529 (* This is necessary in case there is an assignment in e2
6530 * We essentially redo what has been undone in the
6531 * `Binop (Ampamp|Barbar)` case of `expr` *)
6532 let (env, _
, _
) = expr env (Tast.to_nast_expr
e2) in
6533 let (env, lset2
) = condition env tparamet
e2 in
6534 (env, Local_id.Set.union lset1 lset2
)
6535 (* Disjunction of conditions. Matches the two following forms:
6537 if (!(cond1 && cond2))
6539 | Aast.Binop
(((Ast_defs.Ampamp
| Ast_defs.Barbar
) as bop
), e1
, e2)
6540 when Bool.equal tparamet
Ast_defs.(equal_bop bop Barbar
) ->
6541 let (env, lset1
, lset2
) =
6545 (* Either cond1 is true and we don't know anything about cond2... *)
6546 condition env tparamet e1
)
6548 (* ... Or cond1 is false and therefore cond2 must be true *)
6549 let (env, _lset
) = condition env (not tparamet
) e1
in
6550 (* Similarly to the conjunction case, there might be an assignment in
6551 cond2 which we must account for. Again we redo what has been undone in
6552 the `Binop (Ampamp|Barbar)` case of `expr` *)
6553 let (env, _
, _
) = expr env (Tast.to_nast_expr
e2) in
6554 condition env tparamet
e2)
6556 (env, Local_id.Set.union lset1 lset2
)
6557 | Aast.Call
(((p, _
), Aast.Id
(_
, f
)), _
, [lv
], None
)
6558 when tparamet
&& String.equal f
SN.StdlibFunctions.is_dict_or_darray
->
6559 safely_refine_is_array
env `HackDictOrDArray
p f lv
6560 | Aast.Call
(((p, _
), Aast.Id
(_
, f
)), _
, [lv
], None
)
6561 when tparamet
&& String.equal f
SN.StdlibFunctions.is_vec_or_varray
->
6562 safely_refine_is_array
env `HackVecOrVArray
p f lv
6563 | Aast.Call
(((p, _
), Aast.Id
(_
, f
)), _
, [lv
], None
)
6564 when tparamet
&& String.equal f
SN.StdlibFunctions.is_any_array
->
6565 safely_refine_is_array
env `AnyArray
p f lv
6566 | Aast.Call
(((p, _
), Aast.Id
(_
, f
)), _
, [lv
], None
)
6567 when tparamet
&& String.equal f
SN.StdlibFunctions.is_php_array
->
6568 safely_refine_is_array
env `PHPArray
p f lv
6570 ( (_
, Aast.Class_const
((_
, Aast.CI
(_
, class_name)), (_
, method_name
))),
6575 && String.equal
class_name SN.Shapes.cShapes
6576 && String.equal method_name
SN.Shapes.keyExists
->
6577 key_exists
env p shape
field
6578 | Aast.Unop
(Ast_defs.Unot
, e) -> condition env (not tparamet
) e
6579 | Aast.Is
(ivar
, h) when is_instance_var
(Tast.to_nast_expr ivar
) ->
6581 { (Phase.env_with_self
env) with from_class
= Some CIstatic
}
6583 let (env, hint_ty
) = Phase.localize_hint ~
ety_env env h in
6584 let reason = Reason.Ris
(fst
h) in
6585 let refine_type env hint_ty
=
6586 let (ivar_pos
, ivar_ty
) = fst ivar
in
6587 let (env, ivar
) = get_instance_var
env (Tast.to_nast_expr ivar
) in
6588 let (env, hint_ty
) =
6589 class_for_refinement
env p reason ivar_pos ivar_ty hint_ty
6591 let (env, refined_ty
) = Inter.intersect
env reason ivar_ty hint_ty
in
6592 (set_local
env ivar refined_ty
, Local_id.Set.singleton
(snd ivar
))
6594 let (env, hint_ty
) =
6595 if not tparamet
then
6596 Inter.non
env reason hint_ty ~approx
:TUtils.ApproxUp
6600 refine_type env hint_ty
6601 | _
-> (env, Local_id.Set.empty
)
6603 (** Transform a hint like `A<_>` to a localized type like `A<T#1>` for refinment of
6604 an instance variable. ivar_ty is the previous type of that instance variable. *)
6605 and class_for_refinement
env p reason ivar_pos ivar_ty hint_ty
=
6606 let (env, hint_ty
) = Env.expand_type
env hint_ty
in
6607 match (get_node ivar_ty
, get_node hint_ty
) with
6608 | (_
, Tclass
(((_
, cid) as _c
), _
, tyl
)) ->
6610 match Env.get_class
env cid with
6611 | Some
class_info ->
6612 let (env, tparams_with_new_names
, tyl_fresh
) =
6613 generate_fresh_tparams
env class_info reason tyl
6615 safely_refine_class_type
6623 tparams_with_new_names
6625 | None
-> (env, mk
(Reason.Rwitness ivar_pos
, Tobject
))
6627 | (Ttuple ivar_tyl
, Ttuple hint_tyl
)
6628 when Int.equal
(List.length ivar_tyl
) (List.length hint_tyl
) ->
6630 List.map2_env
env ivar_tyl hint_tyl
(fun env ivar_ty hint_ty
->
6631 class_for_refinement
env p reason ivar_pos ivar_ty hint_ty
)
6633 (env, MakeType.tuple
reason tyl
)
6634 | _
-> (env, hint_ty
)
6636 (** If we are dealing with a refinement like
6638 then class_info is the class info of MyClass and hint_tyl corresponds
6640 and generate_fresh_tparams
env class_info reason hint_tyl
=
6641 let tparams_len = List.length
(Cls.tparams
class_info) in
6642 let hint_tyl = List.take
hint_tyl tparams_len in
6643 let pad_len = tparams_len - List.length
hint_tyl in
6645 List.map hint_tyl (fun x -> Some
x) @ List.init pad_len (fun _
-> None
)
6647 let replace_wildcard env hint_ty tp
=
6649 tp_name
= (_
, tparam_name
);
6650 tp_reified
= reified
;
6657 Attributes.mem
SN.UserAttributes.uaEnforceable tp_user_attributes
6660 Attributes.mem
SN.UserAttributes.uaNewable tp_user_attributes
6665 match get_node
ty with
6666 | Tgeneric
(name, _targs
) when Env.is_fresh_generic_parameter
name ->
6667 (* TODO(T69551141) handle type arguments above and below *)
6668 (env, (Some
(tp
, name), MakeType.generic
reason name))
6669 | _
-> (env, (None
, ty))
6672 let (env, new_name
) =
6673 Env.add_fresh_generic_parameter
6680 (* TODO(T69551141) handle type arguments for Tgeneric *)
6681 (env, (Some
(tp
, new_name
), MakeType.generic
reason new_name
))
6683 let (env, tparams_and_tyl
) =
6684 List.map2_env
env hint_tyl (Cls.tparams
class_info) ~f
:replace_wildcard
6686 let (tparams_with_new_names
, tyl_fresh
) = List.unzip tparams_and_tyl
in
6687 (env, tparams_with_new_names
, tyl_fresh
)
6689 and safely_refine_class_type
6697 (tparams_with_new_names
: (decl_tparam
* string) option list
)
6699 (* Type of variable in block will be class name
6700 * with fresh type parameters *)
6702 mk
(get_reason
obj_ty, Tclass
(class_name, Nonexact
, tyl_fresh
))
6704 let tparams = Cls.tparams class_info in
6705 (* Add in constraints as assumptions on those type parameters *)
6708 type_expansions
= [];
6709 substs
= Subst.make_locl
tparams tyl_fresh
;
6711 (* In case `this` appears in constraints *)
6714 on_error
= Errors.unify_error_at
p;
6717 let add_bounds env (t
, ty_fresh
) =
6718 List.fold_left t
.tp_constraints ~
init:env ~f
:(fun env (ck
, ty) ->
6719 (* Substitute fresh type parameters for
6720 * original formals in constraint *)
6721 let (env, ty) = Phase.localize ~
ety_env env ty in
6722 SubType.add_constraint
p env ck ty_fresh
ty)
6725 List.fold_left
(List.zip_exn
tparams tyl_fresh
) ~f
:add_bounds ~
init:env
6727 (* Finally, if we have a class-test on something with static classish type,
6728 * then we can chase the hierarchy and decompose the types to deduce
6729 * further assumptions on type parameters. For example, we might have
6730 * class B<Tb> { ... }
6731 * class C extends B<int>
6732 * and have obj_ty = C and x_ty = B<T> for a generic parameter Aast.
6733 * Then SubType.add_constraint will deduce that T=int and add int as
6734 * both lower and upper bound on T in env.lenv.tpenv
6736 let (env, supertypes
) = TUtils.get_concrete_supertypes
env ivar_ty
in
6738 List.fold_left supertypes ~
init:env ~f
:(fun env ty ->
6739 SubType.add_constraint
p env Ast_defs.Constraint_as
obj_ty ty)
6741 (* It's often the case that the fresh name isn't necessary. For
6742 * example, if C<T> extends B<T>, and we have $x:B<t> for some type t
6743 * then $x is C should refine to $x:C<t>.
6744 * We take a simple approach:
6745 * For a fresh type parameter T#1, if
6746 * - There is an eqality constraint T#1 = t,
6747 * - T#1 is covariant, and T#1 has upper bound t (or mixed if absent)
6748 * - T#1 is contravariant, and T#1 has lower bound t (or nothing if absent)
6749 * then replace T#1 with t.
6750 * This is done in Type_parameter_env_ops.simplify_tpenv
6752 let (env, tparam_substs
) =
6753 Type_parameter_env_ops.simplify_tpenv
6755 (List.zip_exn tparams_with_new_names tyl_fresh
)
6759 List.map2_exn
tyl_fresh tparams_with_new_names ~f
:(fun orig_ty tparam_opt
->
6760 match tparam_opt
with
6762 | Some
(_tp
, name) -> SMap.find
name tparam_substs
)
6764 let obj_ty_simplified =
6765 mk
(get_reason
obj_ty, Tclass
(class_name, Nonexact
, tyl_fresh))
6767 (env, obj_ty_simplified)
6769 and is_instance_var
= function
6770 | (_
, (Lvar _
| This
| Dollardollar _
)) -> true
6771 | (_
, Obj_get
((_
, This
), (_
, Id _
), _
, _
)) -> true
6772 | (_
, Obj_get
((_
, Lvar _
), (_
, Id _
), _
, _
)) -> true
6773 | (_
, Class_get
(_
, _
, _
)) -> true
6776 and get_instance_var
env = function
6777 | (p, Class_get
((_
, cname
), CGstring
(_
, member_name
), _
)) ->
6778 let (env, local) = Env.FakeMembers.make_static
env cname member_name
p in
6782 ((((_
, This
) | (_
, Lvar _
)) as obj
), (_
, Id
(_
, member_name
)), _
, _
) )
6784 let (env, local) = Env.FakeMembers.make
env obj member_name
p in
6786 | (_
, Dollardollar
(p, x))
6787 | (_
, Lvar
(p, x)) ->
6789 | (p, This
) -> (env, (p, this))
6790 | _
-> failwith
"Should only be called when is_instance_var is true"
6792 (* Refine type for is_array, is_vec, is_keyset and is_dict tests
6793 * `pred_name` is the function name itself (e.g. 'is_vec')
6794 * `p` is position of the function name in the source
6795 * `arg_expr` is the argument to the function
6797 and safely_refine_is_array
env ty p pred_name arg_expr
=
6798 refine_lvalue_type
env arg_expr ~
refine:(fun env arg_ty
->
6799 let r = Reason.Rpredicated
(p, pred_name
) in
6800 let (env, tarrkey_name
) =
6801 Env.add_fresh_generic_parameter
6808 (* TODO(T69551141) handle type arguments for Tgeneric *)
6809 let tarrkey = MakeType.generic
r tarrkey_name
in
6811 SubType.add_constraint
6814 Ast_defs.Constraint_as
6816 (MakeType.arraykey r)
6818 let (env, tfresh_name
) =
6819 Env.add_fresh_generic_parameter
6826 (* TODO(T69551141) handle type arguments for Tgeneric *)
6827 let tfresh = MakeType.generic
r tfresh_name
in
6828 (* If we're refining the type for `is_array` we have a slightly more
6829 * involved process. Let's separate out that logic so we can re-use it.
6832 let safe_isarray_enabled =
6833 TypecheckerOptions.experimental_feature_enabled
6835 TypecheckerOptions.experimental_isarray
6837 let tk = MakeType.arraykey Reason.(Rvarray_or_darray_key
(to_pos
r)) in
6839 if safe_isarray_enabled then
6842 mk
(r, TUtils.tany
env)
6844 MakeType.varray_or_darray
r tk tv
6846 (* This is the refined type of e inside the branch *)
6849 | `HackDict
-> MakeType.dict
r tarrkey tfresh
6850 | `HackVec
-> MakeType.vec
r tfresh
6851 | `HackKeyset
-> MakeType.keyset
r tarrkey
6852 | `PHPArray
-> array_ty
6853 | `AnyArray
-> MakeType.any_array
r tarrkey tfresh
6854 | `HackDictOrDArray
->
6857 [MakeType.dict
r tarrkey tfresh; MakeType.darray
r tarrkey tfresh]
6858 | `HackVecOrVArray
->
6859 MakeType.union r [MakeType.vec
r tfresh; MakeType.varray
r tfresh]
6861 let ((arg_pos
, _
), _
) = arg_expr
in
6862 let (env, hint_ty) =
6863 class_for_refinement
env p r arg_pos arg_ty
hint_ty
6865 (* Add constraints on generic parameters that must
6866 * hold for refined_ty <:arg_ty. For example, if arg_ty is Traversable<T>
6867 * and refined_ty is keyset<T#1> then we know T#1 <: T.
6868 * See analogous code in safely_refine_class_type.
6870 let (env, supertypes
) = TUtils.get_concrete_supertypes
env arg_ty
in
6872 List.fold_left supertypes ~
init:env ~f
:(fun env ty ->
6873 SubType.add_constraint
p env Ast_defs.Constraint_as
hint_ty ty)
6875 Inter.intersect ~
r env hint_ty arg_ty
)
6877 and key_exists
env pos shape
field =
6878 let field = Tast.to_nast_expr
field in
6879 refine_lvalue_type
env shape ~
refine:(fun env shape_ty
->
6880 match TUtils.shape_field_name
env field with
6881 | None
-> (env, shape_ty
)
6882 | Some
field_name ->
6883 Typing_shapes.refine_shape
field_name pos env shape_ty
)
6885 and string2
env idl
=
6887 List.fold_left idl ~
init:(env, []) ~f
:(fun (env, tel
) x ->
6888 let (env, te, ty) = expr env x in
6890 let env = Typing_substring.sub_string
p env ty in
6895 and user_attribute
env ua
=
6896 let (env, typed_ua_params
) =
6897 List.map_env
env ua
.ua_params
(fun env e ->
6898 let (env, te, _
) = expr env e in
6901 (env, { Aast.ua_name
= ua
.ua_name
; Aast.ua_params
= typed_ua_params
})
6903 and file_attributes
env file_attrs
=
6904 (* Disable checking of error positions, as file attributes have spans that
6905 * aren't subspans of the class or function into which they are copied *)
6906 Errors.run_with_span
Pos.none
@@ fun () ->
6907 let uas = List.concat_map ~f
:(fun fa
-> fa
.fa_user_attributes
) file_attrs
in
6908 let env = attributes_check_def
env SN.AttributeKinds.file
uas in
6909 List.map_env
env file_attrs
(fun env fa
->
6910 let (env, user_attributes
) =
6911 List.map_env
env fa
.fa_user_attributes user_attribute
6913 let env = set_tcopt_unstable_features env fa
in
6916 Aast.fa_user_attributes
= user_attributes
;
6917 Aast.fa_namespace
= fa
.fa_namespace
;
6920 and type_param
env t
=
6922 attributes_check_def
env SN.AttributeKinds.typeparam t
.tp_user_attributes
6924 let (env, user_attributes
) =
6925 List.map_env
env t
.tp_user_attributes user_attribute
6927 let (env, tp_parameters
) = List.map_env
env t
.tp_parameters type_param
in
6930 Aast.tp_variance
= t
.tp_variance
;
6931 Aast.tp_name
= t
.tp_name
;
6933 Aast.tp_constraints
= t
.tp_constraints
;
6934 Aast.tp_reified
= reify_kind t
.tp_reified
;
6935 Aast.tp_user_attributes
= user_attributes
;
6938 and typedef_def ctx typedef
=
6939 let env = EnvFromDef.typedef_env ~origin
:Decl_counters.TopLevel ctx typedef
in
6941 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
6942 (fst typedef
.t_name
)
6947 Typing_check_decls.typedef
env typedef
;
6948 Typing_variance.typedef
env (snd typedef
.t_name
);
6951 t_name
= (t_pos
, t_name
);
6953 t_constraint
= tcstr
;
6955 t_user_attributes
= _
;
6964 let ty = Decl_hint.hint
env.decl_env hint
in
6965 (* We want to report cycles through the definition *)
6967 Phase.localize_with_self
env ~
pos:t_pos ~report_cycle
:(t_pos
, t_name
) ty
6972 let cstr = Decl_hint.hint
env.decl_env tcstr
in
6973 let (env, cstr) = Phase.localize_with_self ~
pos:t_pos
env cstr in
6976 Reason.URnewtype_cstr
6980 Errors.newtype_alias_must_satisfy_constraint
6985 | (pos, Hshape
{ nsi_allows_unknown_fields
= _
; nsi_field_map
}) ->
6986 let get_name sfi
= sfi
.sfi_name
in
6987 check_shape_keys_validity
env pos (List.map ~f
:get_name nsi_field_map
)
6991 attributes_check_def
6993 SN.AttributeKinds.typealias
6994 typedef
.t_user_attributes
6996 let (env, tparams) = List.map_env
env typedef
.t_tparams type_param
in
6997 let (env, user_attributes
) =
6998 List.map_env
env typedef
.t_user_attributes user_attribute
7001 Aast.t_annotation
= Env.save
(Env.get_tpenv
env) env;
7002 Aast.t_name
= typedef
.t_name
;
7003 Aast.t_mode
= typedef
.t_mode
;
7004 Aast.t_vis
= typedef
.t_vis
;
7005 Aast.t_user_attributes
= user_attributes
;
7006 Aast.t_constraint
= typedef
.t_constraint
;
7007 Aast.t_kind
= typedef
.t_kind
;
7008 Aast.t_tparams
= tparams;
7009 Aast.t_namespace
= typedef
.t_namespace
;
7010 Aast.t_span
= typedef
.t_span
;
7011 Aast.t_emit_id
= typedef
.t_emit_id
;
7014 (* Calls the method of a class, but allows the f callback to override the
7015 * return value type *)
7016 and overload_function
7017 make_call fpos
p env (cpos
, class_id
) method_id
el unpacked_element f
=
7018 let (env, _tal
, tcid
, ty) =
7019 static_class_id ~check_constraints
:false cpos
env [] class_id
7021 let (env, _tel
, _
) = exprs env el in
7022 let (env, (fty, tal
)) =
7026 ~coerce_from_ty
:None
7032 let (env, (tel
, typed_unpack_element
, res
)) =
7033 call ~
expected:None
p env fty el unpacked_element
7035 let (env, ty) = f
env fty res
el in
7036 let (env, fty) = Env.expand_type
env fty in
7038 map_ty
fty ~f
:(function
7039 | Tfun
ft -> Tfun
{ ft with ft_ret = MakeType.unenforced
ty }
7042 let te = Tast.make_typed_expr fpos
fty (Aast.Class_const
(tcid
, method_id
)) in
7043 make_call env te tal tel typed_unpack_element
ty
7045 and update_array_type ?lhs_of_null_coalesce
p env e1
valkind =
7048 | `lvalue_subexpr
->
7049 let (env, te1, ty1
) =
7050 raw_expr ~
valkind:`lvalue_subexpr ~check_defined
:true env e1
7054 | (_
, Lvar
(_
, x)) ->
7055 (* type_mapper has updated the type in ty1 typevars, but we
7056 need to update the local variable type too *)
7057 let env = set_valid_rvalue
p env x ty1
in
7059 | _
-> (env, te1, ty1
)
7061 | _
-> raw_expr ?lhs_of_null_coalesce
env e1
7064 let expr ?
expected env e =
7065 Typing_env.with_origin2
env Decl_counters.Body
(fun env ->
7066 expr ?
expected env e)
7069 Typing_env.with_origin
env Decl_counters.Body
(fun env -> stmt env st
)