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 (*****************************************************************************)
55 (*****************************************************************************)
57 (* A guess as to the last position we were typechecking, for use in debugging,
58 * such as figuring out what a runaway hh_server thread is doing. Updated
59 * only best-effort -- it's an approximation to point debugging in the right
60 * direction, nothing more. *)
61 let debug_last_pos = ref Pos.none
63 let debug_print_last_pos _
=
65 "Last typecheck pos: %s"
66 (Pos.string (Pos.to_absolute
!debug_last_pos))
68 (*****************************************************************************)
70 (*****************************************************************************)
72 let err_witness env p
= TUtils.terr env
(Reason.Rwitness p
)
74 (* Set all the types in an expression to the given type. *)
75 let with_type ty env
(e
: Nast.expr
) : Tast.expr
=
80 method on_'ex _ p
= (p
, ty
)
82 method on_'fb _ _
= ()
84 method on_'en _ _
= env
86 method on_'hi _ _
= ty
91 let expr_error env
(r
: Reason.t
) (e
: Nast.expr
) =
92 let ty = TUtils.terr env r
in
93 (env
, with_type ty Tast.dummy_saved_env e
, ty)
95 let expr_any env p e
=
96 let ty = Typing_utils.mk_tany env p
in
97 (env
, with_type ty Tast.dummy_saved_env e
, ty)
99 let unbound_name env
(pos
, name
) e
=
100 let strictish = Partial.should_check_error
(Env.get_mode env
) 4107 in
101 match Env.get_mode env
with
102 | FileInfo.Mstrict
->
103 Errors.unbound_name_typing pos name
;
104 expr_error env
(Reason.Rwitness pos
) e
105 | FileInfo.Mpartial
when strictish ->
106 Errors.unbound_name_typing pos name
;
107 expr_error env
(Reason.Rwitness pos
) e
109 | FileInfo.Mpartial
->
112 (* Is this type Traversable<vty> or Container<vty> for some vty? *)
113 let get_value_collection_inst ty =
114 match get_node
ty with
115 | Tclass
((_
, c
), _
, [vty
])
116 when String.equal c
SN.Collections.cTraversable
117 || String.equal c
SN.Collections.cContainer
->
119 (* If we're expecting a mixed or a nonnull then we can just assume
120 * that the element type is mixed *)
121 | Tnonnull
-> Some
(MakeType.mixed
Reason.Rnone
)
125 (* Is this type KeyedTraversable<kty,vty>
126 * or KeyedContainer<kty,vty>
129 let get_key_value_collection_inst p
ty =
130 match get_node
ty with
131 | Tclass
((_
, c
), _
, [kty
; vty
])
132 when String.equal c
SN.Collections.cKeyedTraversable
133 || String.equal c
SN.Collections.cKeyedContainer
->
135 (* If we're expecting a mixed or a nonnull then we can just assume
136 * that the key type is arraykey and the value type is mixed *)
138 let arraykey = MakeType.arraykey (Reason.Rkey_value_collection_key p
) in
139 let mixed = MakeType.mixed Reason.Rnone
in
140 Some
(arraykey, mixed)
141 | Tany _
-> Some
(ty, ty)
144 (* Is this type varray<vty> or a supertype for some vty? *)
145 let get_varray_inst ty =
146 match get_node
ty with
147 (* It's varray<vty> *)
148 | Tvarray vty
-> Some vty
149 | _
-> get_value_collection_inst ty
151 (* Is this type one of the value collection types with element type vty? *)
152 let get_vc_inst vc_kind
ty =
153 match get_node
ty with
154 | Tclass
((_
, c
), _
, [vty
]) when String.equal c
(Nast.vc_kind_to_name vc_kind
)
157 | _
-> get_value_collection_inst ty
159 (* Is this type one of the three key-value collection types
160 * e.g. dict<kty,vty> or a supertype for some kty and vty? *)
161 let get_kvc_inst p kvc_kind
ty =
162 match get_node
ty with
163 | Tclass
((_
, c
), _
, [kty
; vty
])
164 when String.equal c
(Nast.kvc_kind_to_name kvc_kind
) ->
166 | _
-> get_key_value_collection_inst p
ty
168 (* Is this type darray<kty, vty> or a supertype for some kty and vty? *)
169 let get_darray_inst p
ty =
170 match get_node
ty with
171 (* It's darray<kty, vty> *)
172 | Tdarray
(kty
, vty
) -> Some
(kty
, vty
)
173 | _
-> get_key_value_collection_inst p
ty
175 (* Check whether this is a function type that (a) either returns a disposable
176 * or (b) has the <<__ReturnDisposable>> attribute
178 let is_return_disposable_fun_type env
ty =
179 let (_env
, ty) = Env.expand_type env
ty in
180 match get_node
ty with
182 get_ft_return_disposable ft
184 (Typing_disposable.is_disposable_type env ft
.ft_ret
.et_type
)
187 (* Turn an environment into a local_id_map suitable to be embedded
188 * into an AssertEnv statement
191 match Env.next_cont_opt env
with
192 | Some
{ Typing_per_cont_env.local_types
; _
} ->
193 Some
(Local_id.Map.map
(fun (ty, pos
, _expr_id
) -> (pos
, ty)) local_types
)
196 (* Similar to annot_map above, but filters the map to only contain
197 * information about locals in lset
199 let refinement_annot_map env lset
=
200 match annot_map env
with
203 Local_id.Map.filter
(fun lid _
-> Local_id.Set.mem lid lset
) map
205 if Local_id.Map.is_empty
map then
211 let assert_env_blk ~pos ~at annotation_kind env_map_opt blk
=
212 let mk_assert map = (pos
, Aast.AssertEnv
(annotation_kind
, map)) in
213 let annot_blk = Option.to_list
(Option.map ~f
:mk_assert env_map_opt
) in
215 | `Start
-> annot_blk @ blk
216 | `End
-> blk
@ annot_blk
218 let assert_env_stmt ~pos ~at annotation_kind env_map_opt stmt
=
219 let mk_assert map = (pos
, Aast.AssertEnv
(annotation_kind
, map)) in
220 match env_map_opt
with
224 | `Start
-> [mk_assert env_map
; (pos
, stmt
)]
225 | `End
-> [(pos
, stmt
); mk_assert env_map
]
230 let set_tcopt_unstable_features env
{ fa_user_attributes
; _
} =
232 Naming_attributes.find
233 SN.UserAttributes.uaEnableUnstableFeatures
237 | Some
{ ua_name
= _
; ua_params
} ->
238 let ( = ) = String.equal
in
239 List.fold ua_params ~init
:env ~f
:(fun env feature
->
240 match snd feature
with
241 | Aast.String s
when s
= SN.UnstableFeatures.coeffects_provisional
->
242 Env.map_tcopt ~f
:TypecheckerOptions.set_coeffects env
245 (* Given a localized parameter type and parameter information, infer
246 * a type for the parameter default expression (if present) and check that
247 * it is a subtype of the parameter type (if present). If no parameter type
248 * is specified, then union with Tany. (So it's as though we did a conditional
249 * assignment of the default expression to the parameter).
250 * Set the type of the parameter in the locals environment *)
251 let rec bind_param env
(ty1
, param
) =
252 let (env
, param_te
, ty1
) =
253 match param
.param_expr
with
254 | None
-> (env
, None
, ty1
)
258 ~f
:(Decl_hint.hint env
.decl_env
)
259 (hint_of_type_hint param
.param_type_hint
)
264 | Some
ty -> Typing_enforceability.is_enforceable env
ty
266 let ty1_enforced = { et_type
= ty1
; et_enforced
= enforced } in
268 ExpectedTy.make_and_allow_coercion
273 let (env
, te
, ty2
) = expr ~
expected env e
in
274 Typing_sequencing.sequence_check_expr e
;
277 Option.is_none
(hint_of_type_hint param
.param_type_hint
)
278 && (not
@@ TCO.global_inference
(Env.get_tcopt env
))
279 (* ty1 will be Tany iff we have no type hint and we are not in
280 * 'infer missing mode'. When it ty1 is Tany we just union it with
281 * the type of the default expression *)
283 Union.union env ty1 ty2
284 (* Otherwise we have an explicit type, and the default expression type
285 * must be a subtype *)
288 Typing_coercion.coerce_type
294 Errors.parameter_default_value_wrong_type
300 let (env, user_attributes
) =
301 List.map_env
env param
.param_user_attributes user_attribute
305 Aast.param_annotation
= Tast.make_expr_annotation param
.param_pos ty1
;
306 Aast.param_type_hint
= (ty1
, hint_of_type_hint param
.param_type_hint
);
307 Aast.param_is_variadic
= param
.param_is_variadic
;
308 Aast.param_pos
= param
.param_pos
;
309 Aast.param_name
= param
.param_name
;
310 Aast.param_expr
= param_te
;
311 Aast.param_callconv
= param
.param_callconv
;
312 Aast.param_user_attributes
= user_attributes
;
313 Aast.param_visibility
= param
.param_visibility
;
316 let mode = get_param_mode param
.param_callconv
in
317 let id = Local_id.make_unscoped param
.param_name
in
318 let env = Env.set_local
env id ty1 param
.param_pos
in
319 let env = Env.set_param
env id (ty1
, param
.param_pos
, mode) in
321 if has_accept_disposable_attribute param
then
322 Env.set_using_var
env id
327 match get_param_mutability param
with
328 | Some Param_borrowed_mutable
->
332 (param
.param_pos
, Typing_mutability_env.Borrowed
)
333 | Some Param_owned_mutable
->
334 Env.add_mutable_var
env id (param
.param_pos
, Typing_mutability_env.Mutable
)
335 | Some Param_maybe_mutable
->
339 (param
.param_pos
, Typing_mutability_env.MaybeMutable
)
344 (param
.param_pos
, Typing_mutability_env.Immutable
)
348 and check_inout_return ret_pos
env =
349 let params = Local_id.Map.elements
(Env.get_params
env) in
350 List.fold
params ~init
:env ~f
:(fun env (id, (ty, param_pos
, mode)) ->
353 (* Whenever the function exits normally, we require that each local
354 * corresponding to an inout parameter be compatible with the original
355 * type for the parameter (under subtyping rules). *)
356 let (local_ty
, local_pos
) = Env.get_local_pos
env id in
357 let (env, ety
) = Env.expand_type
env local_ty
in
359 if not
(Pos.equal
Pos.none local_pos
) then
361 else if not
(Pos.equal
Pos.none ret_pos
) then
366 let param_ty = mk
(Reason.Rinout_param
(get_pos
ty), get_node
ty) in
369 Reason.URassign_inout
373 Errors.inout_return_type_mismatch
376 (*****************************************************************************)
377 (* function used to type closures, functions and methods *)
378 (*****************************************************************************)
379 and fun_ ?
(abstract
= false) ?
(disable
= false) env return
pos named_body f_kind
381 Env.with_env
env (fun env ->
382 debug_last_pos := pos;
383 let env = Env.set_return
env return
in
387 Errors.internal_error
389 ( "Type inference for this function has been disabled by the "
390 ^
SN.UserAttributes.uaDisableTypecheckerInternal
395 block
env named_body
.fb_ast
397 Typing_sequencing.sequence_check_block named_body
.fb_ast
;
398 let { Typing_env_return_info.return_type
= ret
; _
} =
403 (not
@@ LEnv.has_next
env)
405 || Nast.named_body_is_unsafe named_body
409 fun_implicit_return
env pos ret
.et_type f_kind
411 debug_last_pos := Pos.none
;
414 and fun_implicit_return
env pos ret
= function
415 | Ast_defs.FGenerator
416 | Ast_defs.FAsyncGenerator
->
419 (* A function without a terminal block has an implicit return; the
421 let env = check_inout_return
Pos.none
env in
422 let r = Reason.Rno_return
pos in
423 let rty = MakeType.void
r in
424 Typing_return.implicit_return
env pos ~
expected:ret ~actual
:rty
426 (* An async function without a terminal block has an implicit return;
427 * the Awaitable<void> type *)
428 let r = Reason.Rno_return_async
pos in
429 let rty = MakeType.awaitable
r (MakeType.void
r) in
430 Typing_return.implicit_return
env pos ~
expected:ret ~actual
:rty
433 Typing_env.with_origin
env Decl_counters.Body
@@ fun env ->
434 List.map_env
env stl ~f
:stmt
436 (* Set a local; must not be already assigned if it is a using variable *)
437 and set_local ?
(is_using_clause
= false) env (pos, x
) ty =
438 if Env.is_using_var
env x
then
439 if is_using_clause
then
440 Errors.duplicate_using_var
pos
442 Errors.illegal_disposable
pos "assigned";
443 let env = Env.set_local
env x
ty pos in
444 if is_using_clause
then
445 Env.set_using_var
env x
449 (* Check an individual component in the expression `e` in the
450 * `using (e) { ... }` statement.
451 * This consists of either
452 * a simple assignment `$x = e`, in which `$x` is the using variable, or
453 * an arbitrary expression `e`, in which case a temporary is the using
454 * variable, inaccessible in the source.
455 * Return the typed expression and its type, and any variables that must
456 * be designated as "using variables" for avoiding escapes.
458 and check_using_expr has_await
env ((pos, content
) as using_clause
) =
460 (* Simple assignment to local of form `$lvar = e` *)
461 | Binop
(Ast_defs.Eq None
, (lvar_pos
, Lvar lvar
), e
) ->
462 let (env, te
, ty) = expr ~is_using_clause
:true env e
in
464 Typing_disposable.enforce_is_disposable_type
env has_await
(fst e
) ty
466 let env = set_local ~is_using_clause
:true env lvar
ty in
467 (* We are assigning a new value to the local variable, so we need to
468 * generate a new expression id
470 let env = Env.set_local_expr_id
env (snd lvar
) (Ident.tmp
()) in
472 ( Tast.make_typed_expr
477 Tast.make_typed_expr lvar_pos
ty (Aast.Lvar lvar
),
480 (* Arbitrary expression. This will be assigned to a temporary *)
482 let (env, typed_using_clause
, ty) =
483 expr ~is_using_clause
:true env using_clause
486 Typing_disposable.enforce_is_disposable_type
env has_await
pos ty
488 (env, (typed_using_clause
, []))
490 (* Check the using clause e in
491 * `using (e) { ... }` statement (`has_await = false`) or
492 * `await using (e) { ... }` statement (`has_await = true`).
493 * `using_clauses` is a list of expressions.
494 * Return the typed expression, and any variables that must
495 * be designated as "using variables" for avoiding escapes.
497 and check_using_clause
env has_await using_clauses
=
499 List.map_env
env using_clauses
(check_using_expr has_await
)
501 let (typed_using_clauses
, vars
) = List.unzip pairs
in
502 (env, typed_using_clauses
, List.concat vars
)
504 (* Require a new construct with disposable *)
505 and enforce_return_disposable _env e
=
509 | (_
, Await
(_
, Call _
)) -> ()
510 | (p
, _
) -> Errors.invalid_return_disposable p
512 (* Wrappers around the function with the same name in Typing_lenv, which only
513 * performs the move/save and merge operation if we are in a try block or in a
514 * function with return type 'noreturn'.
515 * This enables significant perf improvement, because this is called at every
516 * function of method call, when most calls are outside of a try block. *)
517 and move_and_merge_next_in_catch
env =
518 if env.in_try
|| TFTerm.is_noreturn
env then
519 LEnv.move_and_merge_next_in_cont
env C.Catch
521 LEnv.drop_cont
env C.Next
523 and save_and_merge_next_in_catch
env =
524 if env.in_try
|| TFTerm.is_noreturn
env then
525 LEnv.save_and_merge_next_in_cont
env C.Catch
529 and might_throw
env = save_and_merge_next_in_catch
env
531 and stmt
env (pos, st
) =
532 let (env, st
) = stmt_
env pos st
in
533 Typing_debug.log_env_if_too_big
pos env;
536 and stmt_
env pos st
=
537 (* Type check a loop. f env = (env, result) checks the body of the loop.
538 * We iterate over the loop until the "next" continuation environment is
539 * stable. alias_depth is supposed to be an upper bound on this; but in
540 * certain cases this fails (e.g. a generic type grows unboundedly). TODO:
543 let infer_loop env f
=
544 let in_loop_outer = env.in_loop
in
546 if in_loop_outer then
549 Typing_alias.get_depth
(pos, st
)
551 let env = { env with in_loop
= true } in
553 (* Remember the old environment *)
554 let old_next_entry = Env.next_cont_opt
env in
555 let (env, result
) = f
env in
556 let new_next_entry = Env.next_cont_opt
env in
557 (* Finish if we reach the bound, or if the environments match *)
559 Int.equal n
alias_depth
560 || Typing_per_cont_ops.is_sub_opt_entry
561 Typing_subtype.is_sub_type
566 let env = { env with in_loop
= in_loop_outer } in
573 let env = Env.open_tyvars
env pos in
575 (Typing_solver.close_tyvars_and_solve
env Errors.unify_error
, tb
))
581 LEnv.move_and_merge_next_in_cont
env C.Fallthrough
585 (env, Aast.Fallthrough
)
587 let env = LEnv.move_and_merge_next_in_cont
env (C.Goto label
) in
589 | GotoLabel
(_
, label
) ->
590 let env = LEnv.update_next_from_conts
env [C.Next
; C.Goto label
] in
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.
663 Typing_return.strip_awaitable
(Env.get_fn_kind
env) env return_type
666 if return_explicit
then
668 (ExpectedTy.make_and_allow_coercion
675 if return_disposable
then enforce_return_disposable
env e
;
677 expr ~is_using_clause
:return_disposable ?
expected env e
680 if not
(equal_reactivity
(env_reactivity
env) Nonreactive
) then
681 Typing_mutability.handle_value_in_return
682 ~function_returns_mutable
:return_mutable
683 ~function_returns_void_for_rx
:return_void_to_rx
693 et_type
= TR.strip_condition_type_in_return
env return_type.et_type
;
696 (* This is a unify_error rather than a return_type_mismatch because the return
697 * statement is the problem, not the return type itself. *)
699 Typing_coercion.coerce_type
707 let env = LEnv.move_and_merge_next_in_cont
env C.Exit
in
708 (env, Aast.Return
(Some te
))
710 (* NOTE: leaks scope as currently implemented; this matches
711 the behavior in naming (cf. `do_stmt` in naming/naming.ml).
713 let (env, (tb
, te
)) =
714 LEnv.stash_and_do
env [C.Continue
; C.Break
; C.Do
] (fun env ->
715 let env = LEnv.save_and_merge_next_in_cont
env C.Do
in
716 let (env, _
) = block
env b
in
717 (* saving the locals in continue here even if there is no continue
718 * statement because they must be merged at the end of the loop, in
719 * case there is no iteration *)
720 let env = LEnv.save_and_merge_next_in_cont
env C.Continue
in
722 infer_loop env (fun env ->
724 LEnv.update_next_from_conts
env [C.Continue
; C.Next
]
726 (* The following is necessary in case there is an assignment in the
728 let (env, te
, _
) = expr
env e
in
729 let (env, _lset
) = condition
env true te
in
730 let env = LEnv.update_next_from_conts
env [C.Do
; C.Next
] in
731 let (env, tb
) = block
env b
in
734 let env = LEnv.update_next_from_conts
env [C.Continue
; C.Next
] in
735 let (env, te
, _
) = expr
env e
in
736 let (env, _lset
) = condition
env false te
in
737 let env = LEnv.update_next_from_conts
env [C.Break
; C.Next
] in
740 (env, Aast.Do
(tb
, te
))
742 let (env, (te
, tb
, refinement_map)) =
743 LEnv.stash_and_do
env [C.Continue
; C.Break
] (fun env ->
744 let env = LEnv.save_and_merge_next_in_cont
env C.Continue
in
746 infer_loop env (fun env ->
748 LEnv.update_next_from_conts
env [C.Continue
; C.Next
]
750 let join_map = annot_map env in
751 (* The following is necessary in case there is an assignment in the
753 let (env, te
, _
) = expr
env e
in
754 let (env, lset
) = condition
env true te
in
755 let refinement_map = refinement_annot_map env lset
in
756 (* TODO TAST: avoid repeated generation of block *)
757 let (env, tb
) = block
env b
in
759 (* Annotate loop body with join and refined environments *)
760 let assert_env_blk = assert_env_blk ~
pos ~at
:`Start
in
761 let tb = assert_env_blk Aast.Refinement
refinement_map tb in
762 let tb = assert_env_blk Aast.Join
join_map tb in
766 let env = LEnv.update_next_from_conts
env [C.Continue
; C.Next
] in
767 let (env, te
, _
) = expr
env e
in
768 let (env, lset
) = condition
env false te
in
769 let refinement_map_at_exit = refinement_annot_map env lset
in
770 let env = LEnv.update_next_from_conts
env [C.Break
; C.Next
] in
771 (env, (te
, tb, refinement_map_at_exit)))
773 let while_st = Aast.While
(te
, tb) in
774 (* Export the refined environment after the exit condition holds *)
776 assert_env_stmt ~
pos ~at
:`End
Aast.Refinement
refinement_map while_st
781 us_has_await
= has_await
;
782 us_exprs
= (loc
, using_clause
);
783 us_block
= using_block
;
786 let (env, typed_using_clause
, using_vars
) =
787 check_using_clause
env has_await using_clause
789 let (env, typed_using_block
) = block
env using_block
in
790 (* Remove any using variables from the environment, as they should not
791 * be in scope outside the block *)
792 let env = List.fold_left using_vars ~init
:env ~f
:Env.unset_local
in
797 us_has_await
= has_await
;
798 us_exprs
= (loc
, typed_using_clause
);
799 us_block
= typed_using_block
;
802 | For
(e1
, e2
, e3
, b
) ->
806 | None
-> (Pos.none
, True
)
808 let (env, (te1
, te2
, te3
, tb, refinement_map)) =
809 LEnv.stash_and_do
env [C.Continue
; C.Break
] (fun env ->
810 (* For loops leak their initalizer, but nothing that's defined in the
813 let (env, te1
, _
) = exprs
env e1
in
815 let env = LEnv.save_and_merge_next_in_cont
env C.Continue
in
816 let (env, (tb, te3
)) =
817 infer_loop env (fun env ->
818 (* The following is necessary in case there is an assignment in the
820 let (env, te2
, _
) = expr
env e2 in
821 let (env, lset
) = condition
env true te2
in
822 let refinement_map = refinement_annot_map env lset
in
823 let (env, tb) = block
env b
in
825 LEnv.update_next_from_conts
env [C.Continue
; C.Next
]
827 let join_map = annot_map env in
828 let (env, te3
, _
) = exprs
env e3
in
830 (* Export the join and refinement environments *)
831 let assert_env_blk = assert_env_blk ~
pos ~at
:`Start
in
832 let tb = assert_env_blk Aast.Refinement
refinement_map tb in
833 let tb = assert_env_blk Aast.Join
join_map tb in
837 let env = LEnv.update_next_from_conts
env [C.Continue
; C.Next
] in
838 let (env, te2
, _
) = expr
env e2 in
839 let (env, lset
) = condition
env false te2
in
840 let refinement_map_at_exit = refinement_annot_map env lset
in
841 let env = LEnv.update_next_from_conts
env [C.Break
; C.Next
] in
842 (env, (te1
, te2
, te3
, tb, refinement_map_at_exit)))
844 let for_st = Aast.For
(te1
, Some te2
, te3
, tb) in
846 assert_env_stmt ~
pos ~at
:`End
Aast.Refinement
refinement_map for_st
849 | Switch
(((pos, _
) as e
), cl
) ->
850 let (env, te
, ty) = expr
env e
in
851 (* NB: A 'continue' inside a 'switch' block is equivalent to a 'break'.
853 * http://php.net/manual/en/control-structures.continue.php *)
854 let (env, (te
, tcl
)) =
855 LEnv.stash_and_do
env [C.Continue
; C.Break
] (fun env ->
856 let parent_locals = LEnv.get_all_locals
env in
857 let case_list env = case_list parent_locals ty env pos cl
in
858 let (env, tcl
) = Env.in_case
env case_list in
860 LEnv.update_next_from_conts
env [C.Continue
; C.Break
; C.Next
]
864 (env, Aast.Switch
(te
, tcl
))
865 | Foreach
(e1
, e2, b
) ->
866 (* It's safe to do foreach over a disposable, as no leaking is possible *)
867 let (env, te1
, ty1
) = expr ~accept_using_var
:true env e1
in
868 let (env, (te1
, te2
, tb)) =
869 LEnv.stash_and_do
env [C.Continue
; C.Break
] (fun env ->
870 let env = LEnv.save_and_merge_next_in_cont
env C.Continue
in
871 let (env, tk
, tv
) = as_expr
env ty1
(fst e1
) e2 in
872 let (env, (te2
, tb)) =
873 infer_loop env (fun env ->
875 LEnv.update_next_from_conts
env [C.Continue
; C.Next
]
877 let join_map = annot_map env in
878 let (env, te2
) = bind_as_expr
env (fst e1
) tk tv
e2 in
879 let (env, tb) = block
env b
in
880 (* Export the join environment *)
881 let tb = assert_env_blk ~
pos ~at
:`Start
Aast.Join
join_map tb in
885 LEnv.update_next_from_conts
env [C.Continue
; C.Break
; C.Next
]
887 (env, (te1
, te2
, tb)))
889 (env, Aast.Foreach
(te1
, te2
, tb))
890 | Try
(tb, cl
, fb
) ->
891 let (env, ttb
, tcl
, tfb
) = try_catch
env tb cl fb
in
892 (env, Aast.Try
(ttb
, tcl
, tfb
))
893 | Awaitall
(el
, b
) ->
894 let env = might_throw
env in
896 List.fold_left el ~init
:(env, []) ~f
:(fun (env, tel
) (e1
, e2) ->
897 let (env, te2
, ty2
) = expr
env e2 in
899 Async.overload_extract_from_awaitable
env (fst
e2) ty2
903 let (env, _
, _
) = assign
(fst e1
) env (fst e1
, Lvar e1
) ty2
in
904 (env, (Some e1
, te2
) :: tel
)
905 | None
-> (env, (None
, te2
) :: tel
))
907 let (env, b
) = block
env b
in
908 (env, Aast.Awaitall
(el
, b
))
911 let (env, te
, ty) = expr
env e
in
912 let env = coerce_to_throwable
p env ty in
913 let env = move_and_merge_next_in_catch
env in
916 let env = LEnv.move_and_merge_next_in_cont
env C.Continue
in
919 let env = LEnv.move_and_merge_next_in_cont
env C.Break
in
924 "Unexpected nodes in AST. These nodes should have been removed in naming."
927 type res
. env -> (env -> env * res
) -> (env -> env * res
) -> env * res
* res
929 fun env branch1 branch2
->
930 let parent_lenv = env.lenv
in
931 let (env, tbr1
) = branch1
env in
932 let lenv1 = env.lenv
in
933 let env = { env with lenv
= parent_lenv } in
934 let (env, tbr2
) = branch2
env in
935 let lenv2 = env.lenv
in
936 let env = LEnv.union_lenvs
env parent_lenv lenv1 lenv2 in
939 and finally_cont fb
env ctx
=
940 (* The only locals in scope are the ones from the current continuation *)
941 let env = Env.env_with_locals
env @@ CMap.singleton
C.Next ctx
in
942 let (env, _tfb
) = block
env fb
in
943 (env, LEnv.get_all_locals
env)
948 let env = LEnv.update_next_from_conts
env [C.Next
; C.Finally
] in
951 let parent_locals = LEnv.get_all_locals
env in
952 (* First typecheck the finally block against all continuations merged
954 * During this phase, record errors found in the finally block, but discard
955 * the resulting environment. *)
956 let all_conts = Env.all_continuations
env in
957 let env = LEnv.update_next_from_conts
env all_conts in
958 let (env, tfb
) = block
env fb
in
959 let env = LEnv.restore_conts_from
env parent_locals all_conts in
960 (* Second, typecheck the finally block once against each continuation. This
961 * helps be more clever about what each continuation will be after the
963 * We don't want to record errors during this phase, because certain types
964 * of errors will fire wrongly. For example, if $x is nullable in some
965 * continuations but not in others, then we must use `?->` on $x, but an
966 * error will fire when typechecking the finally block againts continuations
967 * where $x is non-null. *)
968 let finally_cont env _key
= finally_cont fb
env in
969 let (env, locals_map
) =
970 Errors.ignore_
(fun () -> CMap.map_env
finally_cont env parent_locals)
972 let union env _key
= LEnv.union_contextopts
env in
973 let (env, locals
) = Try.finally_merge
union env locals_map
all_conts in
974 (Env.env_with_locals
env locals
, tfb
)
976 and try_catch
env tb cl fb
=
977 let parent_locals = LEnv.get_all_locals
env in
979 LEnv.drop_conts
env [C.Break
; C.Continue
; C.Exit
; C.Catch
; C.Finally
]
981 let (env, (ttb
, tcb
)) =
982 Env.in_try
env (fun env ->
983 let (env, ttb
) = block
env tb in
984 let env = LEnv.move_and_merge_next_in_cont
env C.Finally
in
985 let catchctx = LEnv.get_cont_option
env C.Catch
in
986 let (env, lenvtcblist
) = List.map_env
env ~f
:(catch
catchctx) cl
in
987 let (lenvl
, tcb
) = List.unzip lenvtcblist
in
988 let env = LEnv.union_lenv_list
env env.lenv lenvl
in
989 let env = LEnv.move_and_merge_next_in_cont
env C.Finally
in
992 let (env, tfb
) = finally
env fb
in
993 let env = LEnv.update_next_from_conts
env [C.Finally
] in
994 let env = LEnv.drop_cont
env C.Finally
in
996 LEnv.restore_and_merge_conts_from
999 [C.Break
; C.Continue
; C.Exit
; C.Catch
; C.Finally
]
1001 (env, ttb
, tcb
, tfb
)
1003 and case_list parent_locals ty env switch_pos cl
=
1004 let initialize_next_cont env =
1005 let env = LEnv.restore_conts_from
env parent_locals [C.Next
] in
1006 let env = LEnv.update_next_from_conts
env [C.Next
; C.Fallthrough
] in
1007 LEnv.drop_cont
env C.Fallthrough
1009 let check_fallthrough env switch_pos case_pos block rest_of_list ~is_default
=
1010 if not
@@ List.is_empty block
then
1011 match rest_of_list
with
1013 | [Default
(_
, [])] ->
1017 match LEnv.get_cont_option
env C.Next
with
1020 Errors.default_fallthrough switch_pos
1022 Errors.case_fallthrough switch_pos case_pos
1030 let make_exhaustive_equivalent_case_list env cl
=
1032 List.exists cl ~f
:(function
1037 (* If it hasn't got a default clause then we need to solve type variables
1038 * in order to check for an enum *)
1040 Env.expand_type
env ty
1042 Typing_solver.expand_type_and_solve
1044 ~description_of_expected
:"a value"
1053 SN.Classes.cHH_BuiltinEnum
1054 [MakeType.mixed Reason.Rnone
]
1056 Typing_subtype.is_sub_type_for_coercion
env ty top_type
1058 (* If there is no default case and this is not a switch on enum (since
1059 * exhaustiveness is garanteed elsewhere on enums),
1060 * then add a default case for control flow correctness
1062 if has_default || is_enum then
1065 (env, cl
@ [Default
(Pos.none
, [])], true)
1067 let rec case_list env = function
1069 | Default
(pos, b
) :: rl
->
1070 let env = initialize_next_cont env in
1071 let (env, tb) = block
env b
in
1072 check_fallthrough env switch_pos
pos b rl ~is_default
:true;
1073 let (env, tcl
) = case_list env rl
in
1074 (env, Aast.Default
(pos, tb) :: tcl
)
1075 | Case
(((pos, _
) as e
), b
) :: rl
->
1076 let env = initialize_next_cont env in
1077 let (env, te
, _
) = expr
env e
in
1078 let (env, tb) = block
env b
in
1079 check_fallthrough env switch_pos
pos b rl ~is_default
:false;
1080 let (env, tcl
) = case_list env rl
in
1081 (env, Aast.Case
(te
, tb) :: tcl
)
1083 let (env, cl
, added_empty_default
) =
1084 make_exhaustive_equivalent_case_list env cl
1086 let (env, tcl
) = case_list env cl
in
1088 if added_empty_default
then
1089 List.take
tcl (List.length
tcl - 1)
1095 and catch
catchctx env (sid
, exn_lvar
, b
) =
1096 let env = LEnv.replace_cont
env C.Next
catchctx in
1098 let ety_p = fst sid
in
1099 let (env, _
, _
, _
) = instantiable_cid
ety_p env cid [] in
1100 let (env, _tal
, _te
, ety
) =
1101 static_class_id ~check_constraints
:false ety_p env [] cid
1103 let env = coerce_to_throwable
ety_p env ety
in
1104 let env = set_local
env exn_lvar ety
in
1105 let (env, tb) = block
env b
in
1106 (env, (env.lenv
, (sid
, exn_lvar
, tb)))
1108 and as_expr
env ty1 pe e
=
1109 let env = Env.open_tyvars
env pe
in
1110 (fun (env, expected_ty
, tk
, tv
) ->
1111 let rec distribute_union env ty =
1112 let (env, ty) = Env.expand_type
env ty in
1113 match get_node
ty with
1114 | Tunion tyl
-> List.fold tyl ~init
:env ~f
:distribute_union
1116 if SubType.is_sub_type_for_union
env ty (MakeType.dynamic
Reason.Rnone
)
1118 let env = SubType.sub_type
env ty tk
Errors.unify_error
in
1119 let env = SubType.sub_type
env ty tv
Errors.unify_error
in
1122 let ur = Reason.URforeach
in
1123 Type.sub_type pe
ur env ty expected_ty
Errors.unify_error
1125 let env = distribute_union env ty1
in
1126 let env = Env.set_tyvar_variance
env expected_ty
in
1127 (Typing_solver.close_tyvars_and_solve
env Errors.unify_error
, tk
, tv
))
1129 let (env, tv
) = Env.fresh_type
env pe
in
1132 let tk = MakeType.mixed Reason.Rnone
in
1133 (env, MakeType.traversable
(Reason.Rforeach pe
) tv
, tk, tv
)
1135 let (env, tk) = Env.fresh_type
env pe
in
1136 (env, MakeType.keyed_traversable
(Reason.Rforeach pe
) tk tv
, tk, tv
)
1138 let tk = MakeType.mixed Reason.Rnone
in
1139 (env, MakeType.async_iterator
(Reason.Rasyncforeach pe
) tv
, tk, tv
)
1141 let (env, tk) = Env.fresh_type
env pe
in
1142 (env, MakeType.async_keyed_iterator
(Reason.Rasyncforeach pe
) tk tv
, tk, tv
)
1144 and bind_as_expr
env p ty1 ty2 aexpr
=
1145 let check_reassigned_mutable env te
=
1146 if Env.env_local_reactive
env then
1147 Typing_mutability.handle_assignment_mutability
env te None
1153 let (env, te
, _
) = assign
p env ev ty2
in
1154 let env = check_reassigned_mutable env te
in
1156 | Await_as_v
(p, ev
) ->
1157 let (env, te
, _
) = assign
p env ev ty2
in
1158 let env = check_reassigned_mutable env te
in
1159 (env, Aast.Await_as_v
(p, te
))
1160 | As_kv
((p, Lvar
((_
, k
) as id)), ev
) ->
1161 let env = set_valid_rvalue
p env k ty1
in
1162 let (env, te
, _
) = assign
p env ev ty2
in
1163 let tk = Tast.make_typed_expr
p ty1
(Aast.Lvar
id) in
1164 let env = check_reassigned_mutable env tk in
1165 let env = check_reassigned_mutable env te
in
1166 (env, Aast.As_kv
(tk, te
))
1167 | Await_as_kv
(p, (p1
, Lvar
((_
, k
) as id)), ev
) ->
1168 let env = set_valid_rvalue
p env k ty1
in
1169 let (env, te
, _
) = assign
p env ev ty2
in
1170 let tk = Tast.make_typed_expr p1 ty1
(Aast.Lvar
id) in
1171 let env = check_reassigned_mutable env tk in
1172 let env = check_reassigned_mutable env te
in
1173 (env, Aast.Await_as_kv
(p, tk, te
))
1175 (* TODO Probably impossible, should check that *)
1179 ?
(expected : ExpectedTy.t
option)
1180 ?
(accept_using_var
= false)
1181 ?
(is_using_clause
= false)
1183 ?
(check_defined
= true)
1191 | Some
ExpectedTy.{ reason
= r; ty = { et_type
= ty; _
}; _
} ->
1193 log_with_level
env "typing" 1 (fun () ->
1199 ( "Typing.expr " ^
Typing_reason.string_of_ureason
r,
1200 [Log_type
("expected_ty", ty)] );
1212 with Inf.InconsistentTypeVarState _
as e
->
1213 (* we don't want to catch unwanted exceptions here, eg Timeouts *)
1214 Errors.exception_occurred
p (Exception.wrap e
);
1215 make_result
env p Aast.Any
@@ err_witness env p
1218 ?
(accept_using_var
= false)
1219 ?
(is_using_clause
= false)
1220 ?
(expected : ExpectedTy.t
option)
1221 ?lhs_of_null_coalesce
1223 ?
(check_defined
= true)
1227 debug_last_pos := fst e
;
1232 ?lhs_of_null_coalesce
1240 let valkind = `lvalue
in
1241 expr_ ~
valkind ~check_defined
:false env e
1243 and lvalues
env el
=
1245 | [] -> (env, [], [])
1247 let (env, te
, ty) = lvalue
env e
in
1248 let (env, tel
, tyl
) = lvalues
env el
in
1249 (env, te
:: tel
, ty :: tyl
)
1251 and is_pseudo_function s
=
1252 String.equal s
SN.PseudoFunctions.hh_show
1253 || String.equal s
SN.PseudoFunctions.hh_show_env
1254 || String.equal s
SN.PseudoFunctions.hh_log_level
1255 || String.equal s
SN.PseudoFunctions.hh_force_solve
1256 || String.equal s
SN.PseudoFunctions.hh_loop_forever
1258 and loop_forever
env =
1259 (* forever = up to 10 minutes, to avoid accidentally stuck processes *)
1261 (* Look up things in shared memory occasionally to have a chance to be
1263 match Env.get_class
env "FOR_TEST_ONLY" with
1264 | None
-> Unix.sleep
1
1267 Utils.assert_false_log_backtrace
1268 (Some
"hh_loop_forever was looping for more than 10 minutes")
1270 (* $x ?? 0 is handled similarly to $x ?: 0, except that the latter will also
1271 * look for sketchy null checks in the condition. *)
1272 (* TODO TAST: type refinement should be made explicit in the typed AST *)
1273 and eif
env ~
(expected : ExpectedTy.t
option) ?in_await
p c e1
e2 =
1274 let condition = condition ~lhs_of_null_coalesce
:false in
1275 let (env, tc
, tyc
) = raw_expr ~lhs_of_null_coalesce
:false env c
in
1276 let parent_lenv = env.lenv
in
1277 let (env, _lset
) = condition env true tc
in
1278 let (env, te1
, ty1
) =
1281 let (env, ty) = Typing_solver.non_null
env p tyc
in
1284 let (env, te1
, ty1
) = expr ?
expected ?in_await
env e1
in
1285 (env, Some te1
, ty1
)
1287 let lenv1 = env.lenv
in
1288 let env = { env with lenv
= parent_lenv } in
1289 let (env, _lset
) = condition env false tc
in
1290 let (env, te2
, ty2
) = expr ?
expected ?in_await
env e2 in
1291 let lenv2 = env.lenv
in
1292 let env = LEnv.union_lenvs
env parent_lenv lenv1 lenv2 in
1293 let (env, ty) = Union.union env ty1 ty2
in
1294 make_result
env p (Aast.Eif
(tc
, te1
, te2
)) ty
1296 and is_parameter
env x
= Local_id.Map.mem x
(Env.get_params
env)
1298 and check_escaping_var
env (pos, x
) =
1299 if Env.is_using_var
env x
then
1300 if Local_id.equal x this
then
1301 Errors.escaping_this
pos
1302 else if is_parameter
env x
then
1303 Errors.escaping_disposable_parameter
pos
1305 Errors.escaping_disposable
pos
1310 ?
(accept_using_var
= false)
1311 ?
(expected : ExpectedTy.t
option)
1313 ?
(check_defined
= true)
1317 | [] -> (env, [], [])
1320 expr ~accept_using_var ?
expected ~
valkind ~check_defined
env e
1322 let (env, tel
, tyl
) =
1323 exprs ~accept_using_var ?
expected ~
valkind ~check_defined
env el
1325 (env, te
:: tel
, ty :: tyl
)
1327 and exprs_expected
(pos, ur, expected_tyl
) env el
=
1328 match (el
, expected_tyl
) with
1329 | ([], _
) -> (env, [], [])
1330 | (e
:: el
, expected_ty
:: expected_tyl
) ->
1331 let expected = ExpectedTy.make
pos ur expected_ty
in
1332 let (env, te
, ty) = expr ~
expected env e
in
1333 let (env, tel
, tyl
) = exprs_expected
(pos, ur, expected_tyl
) env el
in
1334 (env, te
:: tel
, ty :: tyl
)
1335 | (el
, []) -> exprs
env el
1337 and make_result
env p te
ty =
1338 (* Set the variance of any type variables that were generated according
1339 * to how they appear in the expression type *)
1340 let env = Env.set_tyvar_variance
env ty in
1341 (env, Tast.make_typed_expr
p ty te
, ty)
1343 and localize_targ
env ta
=
1345 let (env, targ
) = Phase.localize_targ ~check_well_kinded
:true env ta
in
1346 (env, targ
, ExpectedTy.make
pos Reason.URhint
(fst targ
))
1348 and set_function_pointer
ty =
1349 match get_node
ty with
1351 let ft = set_ft_is_function_pointer
ft true in
1352 mk
(get_reason
ty, Tfun
ft)
1356 ?
(expected : ExpectedTy.t
option)
1357 ?
(accept_using_var
= false)
1358 ?
(is_using_clause
= false)
1359 ?lhs_of_null_coalesce
1361 ~
(valkind : [> `lvalue
| `lvalue_subexpr
| `other
])
1365 let env = Env.open_tyvars
env p in
1366 (fun (env, te
, ty) ->
1367 let env = Typing_solver.close_tyvars_and_solve
env Errors.unify_error
in
1370 let expr = expr ~check_defined
in
1371 let exprs = exprs ~check_defined
in
1372 let raw_expr = raw_expr ~check_defined
in
1374 * Given a list of types, computes their supertype. If any of the types are
1375 * unknown (e.g., comes from PHP), the supertype will be Typing_utils.tany env.
1377 let compute_supertype
1378 ~
(expected : ExpectedTy.t
option) ~reason ~use_pos
r env tys
=
1379 let (env, supertype
) =
1381 | None
-> Env.fresh_type_reason
env r
1382 | Some
ExpectedTy.{ ty = { et_type
= ty; _
}; _
} -> (env, ty)
1384 match get_node supertype
with
1385 (* No need to check individual subtypes if expected type is mixed or any! *)
1386 | Tany _
-> (env, supertype
)
1388 let subtype_value env ty =
1389 Type.sub_type use_pos reason
env ty supertype
Errors.unify_error
1391 let env = List.fold_left tys ~init
:env ~f
:subtype_value in
1393 List.exists tys
(fun ty ->
1394 equal_locl_ty_
(get_node
ty) (Typing_utils.tany
env))
1396 (* If one of the values comes from PHP land, we have to be conservative
1397 * and consider that we don't know what the type of the values are. *)
1398 (env, Typing_utils.mk_tany
env p)
1403 * Given a 'a list and a method to extract an expr and its ty from a 'a, this
1404 * function extracts a list of exprs from the list, and computes the supertype
1405 * of all of the expressions' tys.
1407 let compute_exprs_and_supertype
1408 ~
(expected : ExpectedTy.t
option)
1409 ?
(reason
= Reason.URarray_value
)
1414 extract_expr_and_ty
=
1415 let (env, exprs_and_tys
) =
1416 List.map_env
env l
(extract_expr_and_ty ~
expected)
1418 let (exprs, tys
) = List.unzip exprs_and_tys
in
1419 let (env, supertype
) =
1420 compute_supertype ~
expected ~reason ~use_pos
r env tys
1422 (env, exprs, supertype
)
1424 let forget_fake_members env p callexpr
=
1425 (* Some functions are well known to not change the types of members, e.g.
1427 * There are a lot of usages like
1428 * if (!is_null($x->a) && !is_null($x->a->b))
1429 * where the second is_null call invalidates the first condition.
1430 * This function is a bit best effort. Add stuff here when you want
1431 * To avoid adding too many undue HH_FIXMEs. *)
1434 when String.equal func
SN.StdlibFunctions.is_null
1435 || String.equal func
SN.PseudoFunctions.isset
->
1437 | _
-> Env.forget_members
env Reason.(Blame
(p, BScall
))
1441 ~
(expected : ExpectedTy.t
option)
1449 let (env, te
, result
) =
1461 let env = forget_fake_members env p e
in
1468 failwith
"AST should not contain these nodes"
1470 let ty = Typing_utils.mk_tany
env p in
1471 make_result
env p Aast.Omitted
ty
1472 | Any
-> expr_error env (Reason.Rwitness
p) outer
1474 | ValCollection
(_
, th
, el
) ->
1475 let (get_expected_kind
, name
, subtype_val
, make_expr
, make_ty
) =
1477 | ValCollection
(kind
, _
, _
) ->
1478 let class_name = Nast.vc_kind_to_name kind
in
1484 arraykey_value
p class_name
1494 (fun th elements
-> Aast.ValCollection
(kind
, th
, elements
)),
1496 MakeType.class_type
(Reason.Rwitness
p) class_name [value_ty
] )
1501 (fun th elements
-> Aast.Varray
(th
, elements
)),
1502 (fun value_ty
-> MakeType.varray
(Reason.Rwitness
p) value_ty
) )
1504 (* The parent match makes this case impossible *)
1505 failwith
"impossible match case"
1507 (* Use expected type to determine expected element type *)
1508 let (env, elem_expected
, th
) =
1511 let (env, tv
, tv_expected
) = localize_targ
env tv
in
1512 (env, Some tv_expected
, Some tv
)
1515 match expand_expected_and_get_node
env expected with
1516 | (env, Some
(pos, ur, ety
, _
)) ->
1518 match get_expected_kind ety
with
1519 | Some vty
-> (env, Some
(ExpectedTy.make
pos ur vty
), None
)
1520 | None
-> (env, None
, None
)
1522 | _
-> (env, None
, None
)
1525 let (env, tel
, elem_ty
) =
1526 compute_exprs_and_supertype
1527 ~
expected:elem_expected
1529 ~reason
:Reason.URvector
1530 (Reason.Rtype_variable_generics
(p, "T", strip_ns name
))
1535 make_result
env p (make_expr th tel
) (make_ty elem_ty
)
1537 | KeyValCollection
(_
, th
, l
) ->
1538 let (get_expected_kind
, name
, make_expr
, make_ty
) =
1540 | KeyValCollection
(kind
, _
, _
) ->
1541 let class_name = Nast.kvc_kind_to_name kind
in
1542 ( get_kvc_inst p kind
,
1544 (fun th pairs
-> Aast.KeyValCollection
(kind
, th
, pairs
)),
1545 (fun k v
-> MakeType.class_type
(Reason.Rwitness
p) class_name [k
; v
])
1548 ( get_darray_inst p,
1550 (fun th pairs
-> Aast.Darray
(th
, pairs
)),
1551 (fun k v
-> MakeType.darray
(Reason.Rwitness
p) k v
) )
1553 (* The parent match makes this case impossible *)
1554 failwith
"impossible match case"
1556 (* Use expected type to determine expected key and value types *)
1557 let (env, kexpected
, vexpected
, th
) =
1559 | Some
((_
, tk), (_
, tv
)) ->
1560 let (env, tk, tk_expected
) = localize_targ
env tk in
1561 let (env, tv
, tv_expected
) = localize_targ
env tv
in
1562 (env, Some tk_expected
, Some tv_expected
, Some
(tk, tv
))
1564 (* no explicit typehint, fallback to supplied expect *)
1566 match expand_expected_and_get_node
env expected with
1567 | (env, Some
(pos, reason
, ety
, _
)) ->
1569 match get_expected_kind ety
with
1570 | Some
(kty
, vty
) ->
1571 let k_expected = ExpectedTy.make
pos reason kty
in
1572 let v_expected = ExpectedTy.make
pos reason vty
in
1573 (env, Some
k_expected, Some
v_expected, None
)
1574 | None
-> (env, None
, None
, None
)
1576 | _
-> (env, None
, None
, None
)
1579 let (kl
, vl
) = List.unzip l
in
1581 compute_exprs_and_supertype
1584 ~reason
:Reason.URkey
1585 (Reason.Rtype_variable_generics
(p, "Tk", strip_ns name
))
1588 (arraykey_value
p name
)
1591 compute_exprs_and_supertype
1594 ~reason
:Reason.URvalue
1595 (Reason.Rtype_variable_generics
(p, "Tv", strip_ns name
))
1600 let pairs = List.zip_exn tkl tvl
in
1601 make_result
env p (make_expr th
pairs) (make_ty k v
)
1603 let (env, te
, ty) = expr env e
in
1604 (* Clone only works on objects; anything else fatals at runtime *)
1605 let tobj = mk
(Reason.Rwitness
p, Tobject
) in
1606 let env = Type.sub_type
p Reason.URclone
env ty tobj Errors.unify_error
in
1607 make_result
env p (Aast.Clone te
) ty
1609 if Option.is_none
(Env.get_self_ty
env) then Errors.this_var_outside_class
p;
1610 if not accept_using_var
then check_escaping_var
env (p, this
);
1611 let ty = Env.get_local
env this
in
1612 let r = Reason.Rwitness
p in
1613 let ty = mk
(r, TUtils.this_of
(mk
(r, get_node
ty))) in
1614 make_result
env p Aast.This
ty
1615 | Assert
(AE_assert e
) ->
1616 let (env, te
, _
) = expr env e
in
1617 let env = LEnv.save_and_merge_next_in_cont
env C.Exit
in
1618 let (env, _lset
) = condition env true te
in
1622 (Aast.Assert
(Aast.AE_assert te
))
1623 (MakeType.void
(Reason.Rwitness
p))
1624 | True
-> make_result
env p Aast.True
(MakeType.bool (Reason.Rwitness
p))
1625 | False
-> make_result
env p Aast.False
(MakeType.bool (Reason.Rwitness
p))
1626 (* TODO TAST: consider checking that the integer is in range. Right now
1627 * it's possible for HHVM to fail on well-typed Hack code
1629 | Int s
-> make_result
env p (Aast.Int s
) (MakeType.int (Reason.Rwitness
p))
1631 make_result
env p (Aast.Float s
) (MakeType.float (Reason.Rwitness
p))
1632 (* TODO TAST: consider introducing a "null" type, and defining ?t to
1635 | Null
-> make_result
env p Aast.Null
(MakeType.null
(Reason.Rwitness
p))
1637 make_result
env p (Aast.String s
) (MakeType.string (Reason.Rwitness
p))
1639 let (env, tel
) = string2
env idl
in
1640 make_result
env p (Aast.String2 tel
) (MakeType.string (Reason.Rwitness
p))
1641 | PrefixedString
(n
, e
) ->
1642 if String.( <> ) n
"re" then (
1643 Errors.experimental_feature
1645 "String prefixes other than `re` are not yet supported.";
1646 expr_error env Reason.Rnone outer
1648 let (env, te
, ty) = expr env e
in
1650 let env = Typing_substring.sub_string
pe env ty in
1658 (Aast.PrefixedString
(n
, te
))
1659 (Typing_regex.type_pattern e
)
1661 | Pcre.Error
(Pcre.BadPattern
(s
, i
)) ->
1662 let s = s ^
" [" ^ string_of_int i ^
"]" in
1663 Errors.bad_regex_pattern
pe s;
1664 expr_error env (Reason.Rregex
pe) e
1665 | Typing_regex.Empty_regex_pattern
->
1666 Errors.bad_regex_pattern
pe "This pattern is empty";
1667 expr_error env (Reason.Rregex
pe) e
1668 | Typing_regex.Missing_delimiter
->
1669 Errors.bad_regex_pattern
pe "Missing delimiter(s)";
1670 expr_error env (Reason.Rregex
pe) e
1671 | Typing_regex.Invalid_global_option
->
1672 Errors.bad_regex_pattern
pe "Invalid global option(s)";
1673 expr_error env (Reason.Rregex
pe) e
1676 Errors.re_prefixed_non_string
pe "Strings with embedded expressions";
1677 expr_error env (Reason.Rregex
pe) e
1679 Errors.re_prefixed_non_string
pe "Non-strings";
1680 expr_error env (Reason.Rregex
pe) e
)
1682 let (env, fty
, _tal
) = fun_type_of_id
env x
[] [] in
1683 make_result
env p (Aast.Fun_id x
) fty
1684 | Id
((cst_pos
, cst_name
) as id) ->
1685 (match Env.get_gconst
env cst_name
with
1686 | None
when Partial.should_check_error
(Env.get_mode
env) 4106 ->
1687 Errors.unbound_global cst_pos
;
1688 let ty = err_witness env cst_pos
in
1689 make_result
env cst_pos
(Aast.Id
id) ty
1690 | None
-> make_result
env p (Aast.Id
id) (Typing_utils.mk_tany
env cst_pos
)
1692 let (env, ty) = Phase.localize_with_self ~
pos:p env ty in
1693 make_result
env p (Aast.Id
id) ty)
1694 | Method_id
(instance
, meth
) ->
1695 (* Method_id is used when creating a "method pointer" using the magic
1696 * inst_meth function.
1698 * Typing this is pretty simple, we just need to check that instance->meth
1699 * is public+not static and then return its type.
1701 let (env, te
, ty1
) = expr env instance
in
1702 let (env, (result
, _tal
)) =
1708 ~coerce_from_ty
:None
1719 Env.FakeMembers.check_instance_invalid
env instance
(snd meth
) result
1721 make_result
env p (Aast.Method_id
(te
, meth
)) result
1722 | Method_caller
(((pos, class_name) as pos_cname
), meth_name
) ->
1723 (* meth_caller('X', 'foo') desugars to:
1726 let class_ = Env.get_class
env class_name in
1728 | None
-> unbound_name env pos_cname outer
1730 (* Create a class type for the given object instantiated with unresolved
1731 * types for its type parameters.
1734 if Ast_defs.is_c_trait
(Cls.kind
class_) then
1735 Errors.meth_caller_trait
pos class_name
1738 List.map_env
env (Cls.tparams
class_) (fun env _
->
1739 Env.fresh_type
env p)
1742 List.map (Cls.tparams
class_) (fun { tp_name
= (p, n
); _
} ->
1743 (* TODO(T69551141) handle type arguments for Tgeneric *)
1744 MakeType.generic
(Reason.Rwitness
p) n
)
1746 let obj_type = MakeType.apply
(Reason.Rwitness
p) pos_cname
params in
1749 (Phase.env_with_self
env) with
1750 substs
= TUtils.make_locl_subst_for_class_tparams
class_ tvarl
;
1753 let (env, local_obj_ty
) = Phase.localize ~
ety_env env obj_type in
1754 let (env, (fty
, _tal
)) =
1759 ~coerce_from_ty
:None
1763 (CI
(pos, class_name))
1767 let (env, fty
) = Env.expand_type
env fty
in
1768 (match deref fty
with
1769 | (reason
, Tfun ftype
) ->
1770 (* We are creating a fake closure:
1771 * function(Class $x, arg_types_of(Class::meth_name))
1772 : return_type_of(Class::meth_name)
1777 substs
= TUtils.make_locl_subst_for_class_tparams
class_ tvarl
;
1781 Phase.check_tparams_constraints
1785 (Cls.tparams
class_)
1787 let (env, local_obj_ty
) = Phase.localize ~
ety_env env obj_type in
1788 let local_obj_fp = TUtils.default_fun_param local_obj_ty
in
1789 let fty = { ftype
with ft_params
= local_obj_fp :: ftype
.ft_params
} in
1792 ft_arity
= fty.ft_arity
;
1793 ft_tparams
= fty.ft_tparams
;
1794 ft_where_constraints
= fty.ft_where_constraints
;
1795 ft_params
= fty.ft_params
;
1796 ft_implicit_params
= fty.ft_implicit_params
;
1797 ft_ret
= fty.ft_ret
;
1798 (* propagate 'is_coroutine' from the method being called*)
1799 ft_flags
= fty.ft_flags
;
1800 ft_reactive
= fty.ft_reactive
;
1801 ft_ifc_decl
= fty.ft_ifc_decl
;
1807 (Aast.Method_caller
(pos_cname
, meth_name
))
1808 (mk
(reason
, Tfun
caller))
1810 (* This can happen if the method lives in PHP *)
1814 (Aast.Method_caller
(pos_cname
, meth_name
))
1815 (Typing_utils.mk_tany
env pos)))
1816 | FunctionPointer
(FP_class_const
((cpos
, cid), meth
), targs
) ->
1817 let (env, _
, ce
, cty
) =
1818 static_class_id ~check_constraints
:true cpos
env [] cid
1820 let (env, (fpty
, tal
)) =
1824 ~incl_tc
:false (* What is this? *)
1825 ~coerce_from_ty
:None
(* What is this? *)
1826 ~explicit_targs
:targs
1827 ~function_pointer
:true
1833 let env = Env.set_tyvar_variance
env fpty
in
1834 let fpty = set_function_pointer
fpty in
1838 (Aast.FunctionPointer
(FP_class_const
(ce
, meth
), tal
))
1840 | Smethod_id
((pc
, cid), meth
) ->
1841 (* Smethod_id is used when creating a "method pointer" using the magic
1842 * class_meth function.
1844 * Typing this is pretty simple, we just need to check that c::meth is
1845 * public+static and then return its type.
1847 let (class_, classname
) =
1851 (Env.get_self_class
env, Env.get_self_id
env)
1852 | CI
(_
, const
) when String.equal const
SN.PseudoConsts.g__CLASS__
->
1853 (Env.get_self_class
env, Env.get_self_id
env)
1854 | CI
(_
, id) -> (Env.get_class
env id, Some
id)
1857 let classname = Option.value classname ~default
:"" in
1860 (* The class given as a static string was not found. *)
1861 unbound_name env (pc
, classname) outer
1863 let smethod = Env.get_static_member
true env class_ (snd meth
) in
1866 (* The static method wasn't found. *)
1867 TOG.smember_not_found
1874 expr_error env Reason.Rnone outer
1875 | Some
({ ce_type
= (lazy ty); ce_pos
= (lazy ce_pos
); _
} as ce
) ->
1877 if get_ce_abstract ce
then
1880 | _
-> Errors.class_meth_abstract_call
classname (snd meth
) p ce_pos
1882 let ce_visibility = ce
.ce_visibility in
1883 let ce_deprecated = ce
.ce_deprecated in
1884 let (env, _tal
, te
, cid_ty
) =
1885 static_class_id ~check_constraints
:true pc
env [] cid
1887 let (env, cid_ty
) = Env.expand_type
env cid_ty
in
1889 match get_node cid_ty
with
1890 | Tclass
(_
, _
, tyargs) -> tyargs
1895 type_expansions
= [];
1896 substs
= TUtils.make_locl_subst_for_class_tparams
class_ tyargs;
1898 from_class
= Some
cid;
1900 on_error
= Errors.unify_error_at
p;
1903 (match deref
ty with
1906 Typing_enforceability.compute_enforced_and_pessimize_fun_type
env ft
1908 let def_pos = ce_pos
in
1910 Phase.localize_targs
1911 ~check_well_kinded
:true
1915 ~use_name
:(strip_ns
(snd meth
))
1926 use_name
= strip_ns
(snd meth
);
1928 explicit_targs
= tal
;
1935 let ty = mk
(r, Tfun
ft) in
1936 let use_pos = fst meth
in
1937 TVis.check_deprecated ~
use_pos ~
def_pos ce_deprecated;
1938 (match ce_visibility with
1939 | Vpublic
-> make_result
env p (Aast.Smethod_id
(te
, meth
)) ty
1941 Errors.private_class_meth ~
def_pos ~
use_pos;
1942 expr_error env r outer
1944 Errors.protected_class_meth ~
def_pos ~
use_pos;
1945 expr_error env r outer
)
1947 Errors.internal_error
p "We have a method which isn't callable";
1948 expr_error env r outer
)))
1950 let r = Reason.Rplaceholder
p in
1951 let ty = MakeType.void
r in
1952 make_result
env p (Aast.Lplaceholder
p) ty
1953 | Dollardollar _
when phys_equal
valkind `lvalue
->
1954 Errors.dollardollar_lvalue
p;
1955 expr_error env (Reason.Rwitness
p) outer
1956 | Dollardollar
id ->
1957 let ty = Env.get_local_check_defined
env id in
1958 let env = might_throw
env in
1959 make_result
env p (Aast.Dollardollar
id) ty
1960 | Lvar
((_
, x
) as id) ->
1961 if not accept_using_var
then check_escaping_var
env id;
1963 if check_defined
then
1964 Env.get_local_check_defined
env id
1968 make_result
env p (Aast.Lvar
id) ty
1970 let (env, tel
, tyl
) =
1973 | `lvalue_subexpr
->
1976 let (env, expected) = expand_expected_and_get_node
env expected in
1977 (match expected with
1978 | Some
(pos, ur, _
, Ttuple expected_tyl
) ->
1979 exprs_expected
(pos, ur, expected_tyl
) env el
1980 | _
-> exprs env el
)
1982 let ty = MakeType.tuple
(Reason.Rwitness
p) tyl
in
1983 make_result
env p (Aast.List tel
) ty
1984 | Pair
(th
, e1
, e2) ->
1985 let (env, expected1
, expected2
, th
) =
1987 | Some
((_
, t1
), (_
, t2
)) ->
1988 let (env, t1
, t1_expected
) = localize_targ
env t1
in
1989 let (env, t2
, t2_expected
) = localize_targ
env t2
in
1990 (env, Some t1_expected
, Some t2_expected
, Some
(t1
, t2
))
1992 (* Use expected type to determine expected element types *)
1993 (match expand_expected_and_get_node
env expected with
1994 | (env, Some
(pos, reason
, _ty
, Tclass
((_
, k
), _
, [ty1
; ty2
])))
1995 when String.equal k
SN.Collections.cPair
->
1996 let ty1_expected = ExpectedTy.make
pos reason ty1
in
1997 let ty2_expected = ExpectedTy.make
pos reason ty2
in
1998 (env, Some
ty1_expected, Some
ty2_expected, None
)
1999 | _
-> (env, None
, None
, None
))
2001 let (env, te1
, ty1
) = expr ?
expected:expected1
env e1
in
2002 let (env, te2
, ty2
) = expr ?
expected:expected2
env e2 in
2008 ~reason
:Reason.URpair_value
2010 (Reason.Rtype_variable_generics
(p1, "T1", "Pair"))
2017 ~reason
:Reason.URpair_value
2019 (Reason.Rtype_variable_generics
(p2, "T2", "Pair"))
2023 let ty = MakeType.pair
(Reason.Rwitness
p) ty1 ty2
in
2024 make_result
env p (Aast.Pair
(th
, te1
, te2
)) ty
2025 | Array_get
(e
, None
) ->
2026 let (env, te
, _
) = update_array_type
p env e
valkind in
2027 let env = might_throw
env in
2028 (* NAST check reports an error if [] is used for reading in an
2030 let ty = err_witness env p in
2031 make_result
env p (Aast.Array_get
(te
, None
)) ty
2032 | Array_get
(e1
, Some
e2) ->
2033 let (env, te1
, ty1
) =
2034 update_array_type ?lhs_of_null_coalesce
p env e1
valkind
2036 let (env, te2
, ty2
) = expr env e2 in
2037 let env = might_throw
env in
2038 let is_lvalue = phys_equal
valkind `lvalue
in
2040 Typing_array_access.array_get
2043 ?lhs_of_null_coalesce
2050 make_result
env p (Aast.Array_get
(te1
, Some te2
)) ty
2051 | Call
((pos_id
, Id
((_
, s) as id)), [], el
, None
) when is_pseudo_function
s
2053 let (env, tel
, tys
) = exprs ~accept_using_var
:true env el
in
2055 if String.equal
s SN.PseudoFunctions.hh_show
then (
2056 List.iter tys
(Typing_log.hh_show
p env);
2058 ) else if String.equal
s SN.PseudoFunctions.hh_show_env
then (
2059 Typing_log.hh_show_env
p env;
2061 ) else if String.equal
s SN.PseudoFunctions.hh_log_level
then
2063 | [(_
, String key_str
); (_
, Int level_str
)] ->
2064 Env.set_log_level
env key_str
(int_of_string level_str
)
2066 else if String.equal
s SN.PseudoFunctions.hh_force_solve
then
2067 Typing_solver.solve_all_unsolved_tyvars
env Errors.unify_error
2068 else if String.equal
s SN.PseudoFunctions.hh_loop_forever
then (
2074 let ty = MakeType.void
(Reason.Rwitness
p) in
2079 ( Tast.make_typed_expr pos_id
(TUtils.mk_tany
env pos_id
) (Aast.Id
id),
2084 | Call
(e
, explicit_targs
, el
, unpacked_element
) ->
2087 | Id
(pos, f
) when String.equal f
SN.SpecialFunctions.echo
->
2088 Typing_local_ops.enforce_output
pos env
2091 let env = might_throw
env in
2105 | FunctionPointer
(FP_id fid
, targs
) ->
2106 let (env, fty, targs
) = fun_type_of_id
env fid targs
[] in
2107 let e = Aast.FunctionPointer
(FP_id fid
, targs
) in
2108 let fty = set_function_pointer
fty in
2109 make_result
env p e fty
2110 | Binop
(Ast_defs.QuestionQuestion
, e1
, e2) ->
2111 let (env, te1
, ty1
) = raw_expr ~lhs_of_null_coalesce
:true env e1
in
2112 let (env, te2
, ty2
) = expr ?
expected env e2 in
2113 let (env, ty1'
) = Env.fresh_type
env (fst e1
) in
2118 (MakeType.nullable_locl
Reason.Rnone ty1'
)
2121 (* Essentially mimic a call to
2122 * function coalesce<Tr, Ta as Tr, Tb as Tr>(?Ta, Tb): Tr
2123 * That way we let the constraint solver take care of the union logic.
2125 let (env, ty_result
) = Env.fresh_type
env (fst
e2) in
2126 let env = SubType.sub_type
env ty1' ty_result
Errors.unify_error
in
2127 let env = SubType.sub_type
env ty2 ty_result
Errors.unify_error
in
2131 (Aast.Binop
(Ast_defs.QuestionQuestion
, te1
, te2
))
2133 (* For example, e1 += e2. This is typed and translated as if
2134 * written e1 = e1 + e2.
2135 * TODO TAST: is this right? e1 will get evaluated more than once
2137 | Binop
(Ast_defs.Eq
(Some op
), e1
, e2) ->
2139 match (op
, snd e1
) with
2140 | (Ast_defs.QuestionQuestion
, Class_get _
) ->
2141 Errors.experimental_feature
2143 "null coalesce assignment operator with static properties";
2144 expr_error env Reason.Rnone outer
2147 (p, Binop
(Ast_defs.Eq None
, e1
, (p, Binop
(op
, e1
, e2))))
2149 let (env, te_fake
, ty) = raw_expr env e_fake in
2151 match snd te_fake
with
2152 | Aast.Binop
(_
, te1
, (_
, Aast.Binop
(_
, _
, te2
))) ->
2153 let te = Aast.Binop
(Ast_defs.Eq
(Some op
), te1
, te2
) in
2154 make_result
env p te ty
2158 | Binop
(Ast_defs.Eq None
, e1
, e2) ->
2159 let (env, te2
, ty2
) = raw_expr env e2 in
2160 let (env, te1
, ty) = assign
p env e1 ty2
in
2162 if Env.env_local_reactive
env then
2163 Typing_mutability.handle_assignment_mutability
env te1
(Some
(snd te2
))
2167 make_result
env p (Aast.Binop
(Ast_defs.Eq None
, te1
, te2
)) ty
2168 | Binop
(((Ast_defs.Ampamp
| Ast_defs.Barbar
) as bop
), e1
, e2) ->
2169 let c = Ast_defs.(equal_bop bop Ampamp
) in
2170 let (env, te1
, _
) = expr env e1
in
2171 let lenv = env.lenv in
2172 let (env, _lset
) = condition env c te1
in
2173 let (env, te2
, _
) = expr env e2 in
2174 let env = { env with lenv } in
2178 (Aast.Binop
(bop
, te1
, te2
))
2179 (MakeType.bool (Reason.Rlogic_ret
p))
2180 | Binop
(bop
, e1
, e2) ->
2181 let (env, te1
, ty1
) = raw_expr env e1
in
2182 let (env, te2
, ty2
) = raw_expr env e2 in
2185 (* TODO: This could be less conservative: we only need to account for
2186 * the possibility of exception if the operator is `/` or `/=`.
2191 | _
-> might_throw
env
2193 let (env, te3
, ty) =
2194 Typing_arithmetic.binop
p env bop
(fst e1
) te1 ty1
(fst
e2) te2 ty2
2197 | Pipe
(e0
, e1
, e2) ->
2198 (* If it weren't for local variable assignment or refinement the pipe
2199 * expression e1 |> e2 could be typed using this rule (E is environment with
2200 * types for locals):
2202 * E |- e1 : ty1 E[$$:ty1] |- e2 : ty2
2203 * --------------------------------------
2206 * The possibility of e2 changing the types of locals in E means that E
2207 * can evolve, and so we need to restore $$ to its original state.
2209 let (env, te1
, ty1
) = expr env e1
in
2210 let dd_var = Local_id.make_unscoped
SN.SpecialIdents.dollardollar
in
2212 if Env.is_local_defined
env dd_var then
2213 Some
(Env.get_local_pos
env dd_var)
2217 let env = Env.set_local
env dd_var ty1
Pos.none
in
2218 let (env, te2
, ty2
) = expr env e2 in
2220 match dd_old_ty with
2221 | None
-> Env.unset_local
env dd_var
2222 | Some
(ty, pos) -> Env.set_local
env dd_var ty pos
2224 make_result
env p (Aast.Pipe
(e0
, te1
, te2
)) ty2
2226 let (env, te, ty) = raw_expr env e in
2227 let env = might_throw
env in
2228 Typing_arithmetic.unop
p env uop
te ty
2229 | Eif
(c, e1
, e2) -> eif
env ~
expected ?in_await
p c e1
e2
2230 | Class_const
((p, CI sid
), pstr
)
2231 when String.equal
(snd pstr
) "class" && Env.is_typedef
env (snd sid
) ->
2233 match Env.get_typedef
env (snd sid
) with
2234 | Some
{ td_tparams
= tparaml
; _
} ->
2235 (* Typedef type parameters cannot have constraints *)
2240 fun { tp_name
= (p, x
); _
} ->
2241 (* TODO(T69551141) handle type arguments for Tgeneric *)
2242 MakeType.generic
(Reason.Rwitness
p) x
2246 let tdef = mk
(Reason.Rwitness
p, Tapply
(sid
, params)) in
2248 mk
(Reason.Rwitness
p, Tapply
((p, SN.Classes.cTypename
), [tdef]))
2250 let (env, tparams
) =
2251 List.map_env
env tparaml
(fun env tp
->
2252 Env.fresh_type
env (fst tp
.tp_name
))
2256 (Phase.env_with_self
env) with
2257 substs
= Subst.make_locl tparaml tparams
;
2261 Phase.check_tparams_constraints ~
use_pos:p ~
ety_env env tparaml
2263 let (env, ty) = Phase.localize ~
ety_env env typename in
2264 make_result
env p (Class_const
(((p, ty), CI sid
), pstr
)) ty
2266 (* Should not expect None as we've checked whether the sid is a typedef *)
2267 expr_error env (Reason.Rwitness
p) outer
2269 | Class_const
(cid, mid
) -> class_const
env p (cid, mid
)
2270 | Class_get
((cpos
, cid), CGstring mid
, in_parens
)
2271 when Env.FakeMembers.is_valid_static
env cid (snd mid
) ->
2272 let (env, local
) = Env.FakeMembers.make_static
env cid (snd mid
) p in
2273 let local = (p, Lvar
(p, local)) in
2274 let (env, _
, ty) = expr env local in
2275 let (env, _tal
, te, _
) =
2276 static_class_id ~check_constraints
:false cpos
env [] cid
2278 make_result
env p (Aast.Class_get
(te, Aast.CGstring mid
, in_parens
)) ty
2279 | Class_get
((cpos
, cid), CGstring
((ppos
, _
) as mid
), in_parens
) ->
2280 let (env, _tal
, te, cty
) =
2281 static_class_id ~check_constraints
:false cpos
env [] cid
2283 let env = might_throw
env in
2284 let (env, (ty, _tal
)) =
2288 ~coerce_from_ty
:None
2294 let (env, ty) = Env.FakeMembers.check_static_invalid
env cid (snd mid
) ty in
2295 let env = Typing_local_ops.enforce_static_property_access ppos
env in
2296 make_result
env p (Aast.Class_get
(te, Aast.CGstring mid
, in_parens
)) ty
2297 (* Fake member property access. For example:
2298 * if ($x->f !== null) { ...$x->f... }
2300 | Class_get
(_
, CGexpr _
, _
) ->
2301 failwith
"AST should not have any CGexprs after naming"
2302 | Obj_get
(e, (pid
, Id
(py
, y
)), nf
, in_parens
)
2303 when Env.FakeMembers.is_valid
env e y
->
2304 let env = might_throw
env in
2305 let (env, local) = Env.FakeMembers.make
env e y
p in
2306 let local = (p, Lvar
(p, local)) in
2307 let (env, _
, ty) = expr env local in
2308 let (env, t_lhs
, _
) = expr ~accept_using_var
:true env e in
2309 let t_rhs = Tast.make_typed_expr pid
ty (Aast.Id
(py
, y
)) in
2310 make_result
env p (Aast.Obj_get
(t_lhs
, t_rhs, nf
, in_parens
)) ty
2311 (* Statically-known instance property access e.g. $x->f *)
2312 | Obj_get
(e1
, (pm
, Id m
), nullflavor
, in_parens
) ->
2314 match nullflavor
with
2315 | OG_nullthrows
-> None
2316 | OG_nullsafe
-> Some
p
2318 let (env, te1
, ty1
) = expr ~accept_using_var
:true env e1
in
2319 let env = might_throw
env in
2320 (* We typecheck Obj_get by checking whether it is a subtype of
2321 Thas_member(m, #1) where #1 is a fresh type variable. *)
2322 let (env, mem_ty
) = Env.fresh_type
env p in
2323 let r = Reason.Rwitness
(fst e1
) in
2329 ~class_id
:(CIexpr e1
)
2330 ~explicit_targs
:None
2332 let lty1 = LoclType ty1
in
2333 let (env, result_ty
) =
2347 (* In that case ty1 is a subtype of ?Thas_member(m, #1)
2348 and the result is ?#1 if ty1 is nullable. *)
2349 let r = Reason.Rnullsafe_op
p in
2350 let null_ty = MakeType.null
r in
2351 let (env, null_has_mem_ty
) =
2352 Union.union_i
env r has_member_ty null_ty
2363 let (env, null_or_nothing_ty
) = Inter.intersect
env ~
r null_ty ty1
in
2364 let (env, result_ty
) = Union.union env null_or_nothing_ty mem_ty
in
2367 let (env, result_ty
) =
2368 Env.FakeMembers.check_instance_invalid
env e1
(snd m
) result_ty
2375 Tast.make_typed_expr pm result_ty
(Aast.Id m
),
2379 (* Dynamic instance property access e.g. $x->$f *)
2380 | Obj_get
(e1
, e2, nullflavor
, in_parens
) ->
2381 let (env, te1
, ty1
) = expr ~accept_using_var
:true env e1
in
2382 let (env, te2
, _
) = expr env e2 in
2384 if TUtils.is_dynamic
env ty1
then
2385 MakeType.dynamic
(Reason.Rwitness
p)
2387 Typing_utils.mk_tany
env p
2389 let ((pos, _
), te2
) = te2
in
2390 let env = might_throw
env in
2391 let te2 = Tast.make_typed_expr
pos ty te2 in
2392 make_result
env p (Aast.Obj_get
(te1
, te2, nullflavor
, in_parens
)) ty
2394 make_result
env p Aast.Yield_break
(Typing_utils.mk_tany
env p)
2396 let (env, (taf
, opt_key
, value)) = array_field
env af
in
2397 let (env, send
) = Env.fresh_type
env p in
2399 match (af
, opt_key
) with
2400 | (AFvalue
(p, _
), None
) ->
2402 match Env.get_fn_kind
env with
2404 | Ast_defs.FAsync
->
2405 Errors.internal_error
p "yield found in non-generator";
2406 (env, Typing_utils.mk_tany
env p)
2407 | Ast_defs.FGenerator
-> (env, MakeType.int (Reason.Rwitness
p))
2408 | Ast_defs.FAsyncGenerator
->
2409 let (env, ty) = Env.fresh_type
env p in
2410 (env, MakeType.nullable_locl
(Reason.Ryield_asyncnull
p) ty)
2412 | (_
, Some x
) -> (env, x
)
2413 | (_
, _
) -> assert false
2416 match Env.get_fn_kind
env with
2417 | Ast_defs.FGenerator
->
2418 MakeType.generator
(Reason.Ryield_gen
p) key
value send
2419 | Ast_defs.FAsyncGenerator
->
2420 MakeType.async_generator
(Reason.Ryield_asyncgen
p) key
value send
2422 | Ast_defs.FAsync
->
2423 failwith
"Parsing should never allow this"
2425 let Typing_env_return_info.{ return_type = expected_return; _
} =
2429 Typing_coercion.coerce_type
2437 let env = Env.forget_members
env Reason.(Blame
(p, BScall
)) in
2438 let env = LEnv.save_and_merge_next_in_cont
env C.Exit
in
2443 (MakeType.nullable_locl
(Reason.Ryield_send
p) send
)
2445 let env = might_throw
env in
2446 (* Await is permitted in a using clause e.g. using (await make_handle()) *)
2447 let (env, te, rty) =
2448 expr ~is_using_clause ~in_await
:(Reason.Rwitness
p) env e
2450 let (env, ty) = Async.overload_extract_from_awaitable
env p rty in
2451 make_result
env p (Aast.Await
te) ty
2455 | (_
, Call
(e, explicit_targs
, el
, unpacked_element
)) ->
2456 let env = Env.open_tyvars
env p in
2457 (fun (env, te, ty) ->
2458 (Typing_solver.close_tyvars_and_solve
env Errors.unify_error
, te, ty))
2470 make_result
env p (Aast.Suspend
te) ty
2471 | New
((pos, c), explicit_targs
, el
, unpacked_element
, p1) ->
2472 let env = might_throw
env in
2473 let (env, tc
, tal
, tel
, typed_unpack_element
, ty, ctor_fty
) =
2478 ~check_not_abstract
:true
2486 let env = Env.forget_members
env Reason.(Blame
(p, BScall
)) in
2490 (Aast.New
(tc
, tal
, tel
, typed_unpack_element
, (p1, ctor_fty
)))
2492 | Record
((pos, id), field_values
) ->
2493 (match Decl_provider.get_record_def
(Env.get_ctx
env) id with
2495 if rd
.rdt_abstract
then Errors.new_abstract_record
(pos, id);
2497 let field_name (pos, expr_
) =
2499 | Aast.String name
-> Some
(pos, name
)
2501 (* TODO T44306013: Ensure that other values for field names are banned. *)
2504 let fields_declared = Typing_helpers.all_record_fields
env rd
in
2505 let fields_present =
2506 List.map field_values ~f
:(fun (name
, _value
) -> field_name name
)
2509 (* Check for missing required fields. *)
2510 let fields_present_names =
2511 List.map ~f
:snd
fields_present |> SSet.of_list
2514 (fun field_name info
->
2515 let ((field_pos
, _
), req
) = info
in
2517 | Typing_defs.ValueRequired
2518 when not
(SSet.mem
field_name fields_present_names) ->
2519 Errors.missing_record_field_name
2523 ~field_decl_pos
:field_pos
2527 (* Check for unknown fields.*)
2528 List.iter
fields_present ~f
:(fun (pos, field_name) ->
2529 if not
(SMap.mem
field_name fields_declared) then
2530 Errors.unexpected_record_field_name
2534 ~decl_pos
:(fst rd
.rdt_name
))
2535 | None
-> Errors.type_not_record
id pos);
2537 expr_error env (Reason.Rwitness
p) outer
2539 let (env, te, ty2
) = expr ?in_await
env e in
2540 let env = might_throw
env in
2543 TypecheckerOptions.experimental_feature_enabled
2545 TypecheckerOptions.experimental_forbid_nullable_cast
2546 && not
(TUtils.is_mixed
env ty2
)
2548 SubType.sub_type_or_fail
2551 (MakeType.nonnull
(get_reason ty2
))
2553 Errors.nullable_cast
p (Typing_print.error
env ty2
) (get_pos ty2
))
2557 let (env, ty) = Phase.localize_hint_with_self
env hint
in
2558 make_result
env p (Aast.Cast
(hint
, te)) ty
2559 | ExpressionTree et
-> expression_tree
env p et
2561 Typing_kinding.Simple.check_well_kinded_hint
env hint
;
2562 let (env, te, _
) = expr env e in
2563 make_result
env p (Aast.Is
(te, hint
)) (MakeType.bool (Reason.Rwitness
p))
2564 | As
(e, hint
, is_nullable
) ->
2565 Typing_kinding.Simple.check_well_kinded_hint
env hint
;
2566 let refine_type env lpos lty
rty =
2567 let reason = Reason.Ras lpos
in
2568 let (env, rty) = Env.expand_type
env rty in
2569 let (env, rty) = class_for_refinement
env p reason lpos lty
rty in
2570 Inter.intersect
env reason lty
rty
2572 let (env, te, expr_ty
) = expr env e in
2573 let env = might_throw
env in
2575 { (Phase.env_with_self
env) with from_class
= Some CIstatic
}
2577 let (env, hint_ty
) = Phase.localize_hint ~
ety_env env hint
in
2578 let (env, hint_ty
) =
2579 if Typing_utils.is_dynamic
env hint_ty
then
2581 if is_instance_var
e then
2582 let (env, ivar
) = get_instance_var
env e in
2583 set_local
env ivar hint_ty
2588 else if is_nullable
then
2589 let (env, hint_ty
) = refine_type env (fst
e) expr_ty hint_ty
in
2590 (env, MakeType.nullable_locl
(Reason.Rwitness
p) hint_ty
)
2591 else if is_instance_var
e then
2592 let (env, _
, ivar_ty
) = raw_expr env e in
2593 let (env, ((ivar_pos
, _
) as ivar
)) = get_instance_var
env e in
2594 let (env, hint_ty
) = refine_type env ivar_pos ivar_ty hint_ty
in
2595 let env = set_local
env ivar hint_ty
in
2598 refine_type env (fst
e) expr_ty hint_ty
2600 make_result
env p (Aast.As
(te, hint
, is_nullable
)) hint_ty
2609 (* Check type annotations on the lambda *)
2610 Typing_check_decls.fun_
env f
;
2611 (* Check attributes on the lambda *)
2613 attributes_check_def
env SN.AttributeKinds.lambda f
.f_user_attributes
2615 (* This is the function type as declared on the lambda itself.
2616 * If type hints are absent then use Tany instead. *)
2618 Decl_nast.fun_decl_in_env
env.decl_env ~is_lambda
:true f
2620 let { fe_type
; fe_pos
; _
} = declared_fe in
2621 let (declared_pos
, declared_ft
) =
2622 match get_node fe_type
with
2623 | Tfun
ft -> (fe_pos
, ft)
2624 | _
-> failwith
"Not a function"
2627 Typing_enforceability.compute_enforced_and_pessimize_fun_type
2631 (* When creating a closure, the 'this' type will mean the late bound type
2632 * of the current enclosing class
2635 { (Phase.env_with_self
env) with from_class
= Some CIstatic
}
2637 let (env, declared_ft) =
2641 { use_name
= "lambda"; use_pos = p; explicit_targs
= [] }
2643 ~
def_pos:declared_pos
2647 List.iter idl
(check_escaping_var
env);
2649 (* Ensure lambda arity is not ellipsis in strict mode *)
2651 match declared_ft.ft_arity
with
2652 | Fvariadic
{ fp_name
= None
; _
}
2653 when Partial.should_check_error
(Env.get_mode
env) 4223 ->
2654 Errors.ellipsis_strict_mode ~require
:`Param_name
p
2658 (* Is the return type declared? *)
2659 let is_explicit_ret = Option.is_some
(hint_of_type_hint f
.f_ret
) in
2661 Decl_fun_utils.fun_reactivity_opt
env.decl_env f
.f_user_attributes
2663 ~default
:(TR.strip_conditional_reactivity
(env_reactivity
env))
2665 let check_body_under_known_params env ?ret_ty
ft : env * _
* locl_ty
=
2666 let old_reactivity = env_reactivity
env in
2667 let env = Env.set_env_reactive
env reactivity in
2668 let ft = { ft with ft_reactive
= reactivity } in
2669 let (env, (tefun
, ty, ft)) = anon_make ?ret_ty
env p f
ft idl
is_anon in
2670 let env = Env.set_env_reactive
env old_reactivity in
2673 ( Reason.Rwitness
p,
2678 ( if is_explicit_ret then
2681 MakeType.unenforced
ty );
2684 (env, tefun
, inferred_ty)
2686 let (env, eexpected
) = expand_expected_and_get_node
env expected in
2687 (* TODO: move this into the expand_expected_and_get_node function and prune its callsites
2688 * Strip like type from function type hint *)
2690 match eexpected with
2691 | Some
(pos, ur, _
, Tunion
[ty1
; ty2
]) when is_dynamic ty1
&& is_fun ty2
2693 Some
(pos, ur, ty2
, get_node ty2
)
2697 match eexpected with
2698 | Some
(_pos
, _ur
, ty, Tfun expected_ft
) ->
2699 (* First check that arities match up *)
2700 check_lambda_arity
p (get_pos
ty) declared_ft expected_ft
;
2701 (* Use declared types for parameters in preference to those determined
2702 * by the context: they might be more general. *)
2703 let rec replace_non_declared_types
2704 params declared_ft_params expected_ft_params
=
2705 match (params, declared_ft_params
, expected_ft_params
) with
2706 | ( param
:: params,
2707 declared_ft_param
:: declared_ft_params
,
2708 expected_ft_param
:: expected_ft_params
) ->
2710 replace_non_declared_types
2715 let resolved_ft_param =
2716 if Option.is_some
(hint_of_type_hint param
.param_type_hint
) then
2719 { declared_ft_param
with fp_type
= expected_ft_param
.fp_type
}
2721 resolved_ft_param :: rest
2722 | (_
:: params, declared_ft_param
:: declared_ft_params
, []) ->
2724 replace_non_declared_types
2729 declared_ft_param
:: rest
2731 (* This means the expected_ft params list can have more parameters
2732 * than declared parameters in the lambda. For variadics, this is OK.
2736 let replace_non_declared_arity variadic declared_arity expected_arity
=
2738 | FVvariadicArg
{ param_type_hint
= (_
, Some _
); _
} -> declared_arity
2739 | FVvariadicArg _
->
2741 match (declared_arity
, expected_arity
) with
2742 | (Fvariadic declared
, Fvariadic
expected) ->
2743 Fvariadic
{ declared
with fp_type
= expected.fp_type
}
2744 | (_
, _
) -> declared_arity
2746 | _
-> declared_arity
2752 replace_non_declared_arity
2754 declared_ft.ft_arity
2755 expected_ft.ft_arity
;
2757 replace_non_declared_types
2759 declared_ft.ft_params
2760 expected_ft.ft_params
;
2761 ft_implicit_params
= declared_ft.ft_implicit_params
;
2764 (* Don't bother passing in `void` if there is no explicit return *)
2766 match get_node
expected_ft.ft_ret
.et_type
with
2767 | Tprim Tvoid
when not
is_explicit_ret -> None
2768 | _
-> Some
expected_ft.ft_ret
.et_type
2770 Typing_log.increment_feature_count
env FL.Lambda.contextual_params
;
2771 check_body_under_known_params env ?
ret_ty expected_ft
2773 let explicit_variadic_param_or_non_variadic =
2774 match f
.f_variadic
with
2775 | FVvariadicArg
{ param_type_hint
; _
} ->
2776 Option.is_some
(hint_of_type_hint param_type_hint
)
2777 | FVellipsis _
-> false
2780 (* If all parameters are annotated with explicit types, then type-check
2781 * the body under those assumptions and pick up the result type *)
2782 let all_explicit_params =
2783 List.for_all f
.f_params
(fun param
->
2784 Option.is_some
(hint_of_type_hint param
.param_type_hint
))
2786 if all_explicit_params && explicit_variadic_param_or_non_variadic then (
2787 Typing_log.increment_feature_count
2789 ( if List.is_empty f
.f_params
then
2792 FL.Lambda.explicit_params
);
2793 check_body_under_known_params env declared_ft
2796 | Some
ExpectedTy.{ ty = { et_type
; _
}; _
} when is_any et_type
->
2797 (* If the expected type is Tany env then we're passing a lambda to
2798 * an untyped function and we just assume every parameter has type
2800 * Note: we should be using 'nothing' to type the arguments. *)
2801 Typing_log.increment_feature_count
env FL.Lambda.untyped_context
;
2802 check_body_under_known_params env declared_ft
2804 (* If the expected type is something concrete but not a function
2805 * then we should reject in strict mode. Check body anyway.
2806 * Note: we should be using 'nothing' to type the arguments. *)
2807 if Partial.should_check_error
(Env.get_mode
env) 4224 then
2808 Errors.untyped_lambda_strict_mode
p;
2809 Typing_log.increment_feature_count
2811 FL.Lambda.non_function_typed_context
;
2812 check_body_under_known_params env declared_ft
2814 (* If we're in partial mode then type-check definition anyway,
2815 * so treating parameters without type hints as "untyped"
2817 if not
(Env.is_strict
env) then (
2818 Typing_log.increment_feature_count
2820 FL.Lambda.non_strict_unknown_params
;
2821 check_body_under_known_params env declared_ft
2823 Typing_log.increment_feature_count
2825 FL.Lambda.fresh_tyvar_params
;
2827 (* Replace uses of Tany that originated from "untyped" parameters or return type
2828 * with fresh type variables *)
2829 let freshen_ftype env ft =
2830 let freshen_ty env pos et
=
2831 match get_node et
.et_type
with
2833 let (env, ty) = Env.fresh_type
env pos in
2834 (env, { et
with et_type
= ty })
2835 | Tclass
(id, e, [ty])
2836 when String.equal
(snd
id) SN.Classes.cAwaitable
2838 let (env, t
) = Env.fresh_type
env pos in
2842 et_type
= mk
(get_reason et
.et_type
, Tclass
(id, e, [t
]));
2846 let freshen_untyped_param env ft_param
=
2847 let (env, fp_type
) =
2848 freshen_ty env ft_param
.fp_pos ft_param
.fp_type
2850 (env, { ft_param
with fp_type
})
2852 let (env, ft_params
) =
2853 List.map_env
env ft.ft_params
freshen_untyped_param
2855 let (env, ft_ret
) = freshen_ty env declared_pos
ft.ft_ret
in
2856 (env, { ft with ft_params
; ft_ret
})
2858 let (env, declared_ft) = freshen_ftype env declared_ft in
2860 Env.set_tyvar_variance
env (mk
(Reason.Rnone
, Tfun
declared_ft))
2862 (* TODO(jjwu): the declared_ft here is set to public,
2863 but is actually inferred from the surrounding context
2864 (don't think this matters in practice, since we check lambdas separately) *)
2865 check_body_under_known_params
2867 ~
ret_ty:declared_ft.ft_ret
.et_type
2872 | Xml
(sid
, attrl
, el
) ->
2874 let (env, _tal
, _te
, classes
) =
2875 class_id_for_new ~exact
:Nonexact
p env cid []
2880 (* OK to ignore rest of list; class_info only used for errors, and
2881 * cid = CI sid cannot produce a union of classes anyhow *)
2882 | (_
, class_info, _
) :: _
-> Some
class_info
2884 let (env, _te
, obj
) =
2885 expr env (fst sid
, New
((fst sid
, cid), [], [], None
, fst sid
))
2887 let (env, typed_attrs
, attr_types
) =
2888 xhp_attribute_exprs
env class_info attrl
2891 List.map_env
env el ~f
:(fun env e ->
2892 let (env, te, _
) = expr env e in
2895 let txml = Aast.Xml
(sid
, typed_attrs
, List.rev tel
) in
2896 (match class_info with
2897 | None
-> make_result
env p txml (mk
(Reason.Runknown_class
p, Tobject
))
2898 | Some
class_info ->
2905 let (namepstr
, valpty
) = attr
in
2906 let (valp
, valty
) = valpty
in
2907 let (env, (declty
, _tal
)) =
2912 ~coerce_from_ty
:None
2920 let ureason = Reason.URxhp
(Cls.name
class_info, snd namepstr
) in
2921 Typing_coercion.coerce_type
2926 (MakeType.unenforced declty
)
2927 Errors.xhp_attribute_does_not_match_hint
2931 make_result
env p txml obj
)
2932 | Callconv
(kind
, e) ->
2933 let (env, te, ty) = expr env e in
2934 make_result
env p (Aast.Callconv
(kind
, te)) ty
2936 let (env, fdm_with_expected
) =
2937 match expand_expected_and_get_node
env expected with
2938 | (env, Some
(pos, ur, _
, Tshape
(_
, expected_fdm
))) ->
2942 match ShapeMap.find_opt k expected_fdm
with
2943 | None
-> (k
, (v
, None
))
2944 | Some sft
-> (k
, (v
, Some
(ExpectedTy.make
pos ur sft
.sft_ty
))))
2948 | _
-> (env, List.map ~f
:(fun (k
, v
) -> (k
, (v
, None
))) fdm
)
2950 (* allow_inter adds a type-variable *)
2953 ~f
:(fun env (key
, (e, expected)) ->
2954 let (env, te, ty) = expr ?
expected env e in
2955 (env, (key
, (te, ty))))
2960 let convert_expr_and_type_to_shape_field_type env (key
, (_
, ty)) =
2961 (* An expression evaluation always corresponds to a shape_field_type
2962 with sft_optional = false. *)
2963 (env, (key
, { sft_optional
= false; sft_ty
= ty }))
2965 List.map_env ~f
:convert_expr_and_type_to_shape_field_type env tfdm
2969 ~f
:(fun acc
(k
, v
) -> ShapeMap.add k v acc
)
2970 ~init
:ShapeMap.empty
2973 let env = check_shape_keys_validity
env p (ShapeMap.keys
fdm) in
2974 (* Fields are fully known, because this shape is constructed
2975 * using shape keyword and we know exactly what fields are set. *)
2979 (Aast.Shape
(List.map ~f
:(fun (k
, (te, _
)) -> (k
, te)) tfdm
))
2980 (mk
(Reason.Rwitness
p, Tshape
(Closed_shape
, fdm)))
2981 | ET_Splice
e -> et_splice
env p e
2983 Errors.atom_as_expr
p;
2984 make_result
env p (Aast.EnumAtom
s) (mk
(Reason.Rwitness
p, Terr
))
2986 (* let ty = err_witness env cst_pos in *)
2987 and class_const ?
(incl_tc
= false) env p ((cpos
, cid), mid
) =
2988 let (env, _tal
, ce
, cty
) =
2989 static_class_id ~check_constraints
:true cpos
env [] cid
2991 let (env, (const_ty
, _tal
)) =
2996 ~coerce_from_ty
:None
3002 make_result
env p (Aast.Class_const
(ce
, mid
)) const_ty
3003 (*****************************************************************************)
3004 (* XHP attribute/body helpers. *)
3005 (*****************************************************************************)
3008 * Process a spread operator by computing the intersection of XHP attributes
3009 * between the spread expression and the XHP constructor onto which we're
3012 and xhp_spread_attribute
env c_onto valexpr
=
3013 let (p, _
) = valexpr
in
3014 let (env, te, valty
) = expr env valexpr
in
3015 (* Build the typed attribute node *)
3016 let typed_attr = Aast.Xhp_spread
te in
3017 let (env, attr_ptys
) =
3020 | Some
class_info -> Typing_xhp.get_spread_attributes
env p class_info valty
3022 (env, typed_attr, attr_ptys
)
3025 * Simple XHP attributes (attr={expr} form) are simply interpreted as a member
3026 * variable prefixed with a colon, the types of which will be validated later
3028 and xhp_simple_attribute
env id valexpr
=
3029 let (p, _
) = valexpr
in
3030 let (env, te, valty
) = expr env valexpr
in
3031 (* This converts the attribute name to a member name. *)
3032 let name = ":" ^ snd
id in
3033 let attr_pty = ((fst
id, name), (p, valty
)) in
3034 let typed_attr = Aast.Xhp_simple
(id, te) in
3035 (env, typed_attr, [attr_pty])
3038 * Typecheck the attribute expressions - this just checks that the expressions are
3039 * valid, not that they match the declared type for the attribute and,
3040 * in case of spreads, makes sure they are XHP.
3042 and xhp_attribute_exprs
env cid attrl
=
3043 let handle_attr (env, typed_attrl
, attr_ptyl
) attr
=
3044 let (env, typed_attr, attr_ptys
) =
3046 | Xhp_simple
(id, valexpr
) -> xhp_simple_attribute
env id valexpr
3047 | Xhp_spread valexpr
-> xhp_spread_attribute
env cid valexpr
3049 (env, typed_attr :: typed_attrl
, attr_ptys
@ attr_ptyl
)
3051 let (env, typed_attrl
, attr_ptyl
) =
3052 List.fold_left ~f
:handle_attr ~init
:(env, [], []) attrl
3054 (env, List.rev typed_attrl
, List.rev attr_ptyl
)
3056 (*****************************************************************************)
3057 (* Anonymous functions. *)
3058 (*****************************************************************************)
3059 and anon_bind_param
params (env, t_params
) ty : env * Tast.fun_param list
=
3062 (* This code cannot be executed normally, because the arity is wrong
3063 * and it will error later. Bind as many parameters as we can and carry
3066 | param
:: paraml
->
3068 (match hint_of_type_hint param
.param_type_hint
with
3070 let h = Decl_hint.hint
env.decl_env
h in
3071 (* When creating a closure, the 'this' type will mean the
3072 * late bound type of the current enclosing class
3075 { (Phase.env_with_self
env) with from_class
= Some CIstatic
}
3077 let (env, h) = Phase.localize ~
ety_env env h in
3078 let pos = get_pos
h in
3080 Typing_coercion.coerce_type
3085 (MakeType.unenforced
h)
3088 (* Closures are allowed to have explicit type-hints. When
3089 * that is the case we should check that the argument passed
3090 * is compatible with the type-hint.
3091 * The body of the function should be type-checked with the
3092 * hint and not the type of the argument passed.
3093 * Otherwise it leads to strange results where
3094 * foo(?string $x = null) is called with a string and fails to
3095 * type-check. If $x is a string instead of ?string, null is not
3096 * subtype of string ...
3098 let (env, t_param
) = bind_param env (h, param
) in
3099 (env, t_params
@ [t_param
])
3102 mk
(Reason.Rlambda_param
(param
.param_pos
, get_reason
ty), get_node
ty)
3104 let (env, t_param
) = bind_param env (ty, param
) in
3105 (env, t_params
@ [t_param
]))
3107 and anon_bind_variadic
env vparam variadic_ty
=
3108 let (env, ty, pos) =
3109 match hint_of_type_hint vparam
.param_type_hint
with
3111 (* if the hint is missing, use the type we expect *)
3112 (env, variadic_ty
, get_pos variadic_ty
)
3114 let h = Decl_hint.hint
env.decl_env hint
in
3116 { (Phase.env_with_self
env) with from_class
= Some CIstatic
}
3118 let (env, h) = Phase.localize ~
ety_env env h in
3119 let pos = get_pos
h in
3121 Typing_coercion.coerce_type
3126 (MakeType.unenforced
h)
3129 (env, h, vparam
.param_pos
)
3131 let r = Reason.Rvar_param
pos in
3132 let arr_values = mk
(r, get_node
ty) in
3133 let ty = MakeType.varray
r arr_values in
3134 let (env, t_variadic
) = bind_param env (ty, vparam
) in
3137 and anon_bind_opt_param
env param
: env =
3138 match param
.param_expr
with
3140 let ty = Typing_utils.mk_tany
env param
.param_pos
in
3141 let (env, _
) = bind_param env (ty, param
) in
3144 let (env, _te
, ty) = expr env default
in
3145 Typing_sequencing.sequence_check_expr default
;
3146 let (env, _
) = bind_param env (ty, param
) in
3149 and anon_check_param
env param
=
3150 match hint_of_type_hint param
.param_type_hint
with
3153 let (env, hty
) = Phase.localize_hint_with_self
env hty
in
3154 let paramty = Env.get_local
env (Local_id.make_unscoped param
.param_name
) in
3155 let hint_pos = get_pos hty
in
3157 Typing_coercion.coerce_type
3162 (MakeType.unenforced hty
)
3167 and stash_conts_for_anon
env p is_anon captured f
=
3169 if Env.is_local_defined
env this
then
3170 (Pos.none
, this
) :: captured
3175 Option.map (Env.next_cont_opt
env) ~f
:(fun next_cont
->
3176 let initial_locals =
3178 Env.get_locals
env captured
3180 next_cont
.Typing_per_cont_env.local_types
3183 Fake.forget
(Env.get_fake_members
env) Reason.(Blame
(p, BSlambda
))
3185 let tpenv = Env.get_tpenv
env in
3186 (initial_locals, initial_fakes, tpenv))
3188 Typing_lenv.stash_and_do
env (Env.all_continuations
env) (fun env ->
3192 | Some
(initial_locals, initial_fakes, tpenv) ->
3193 let env = Env.reinitialize_locals
env in
3194 let env = Env.set_locals
env initial_locals in
3195 let env = Env.set_fake_members
env initial_fakes in
3196 let env = Env.env_with_tpenv
env tpenv in
3201 (* Make a type-checking function for an anonymous function. *)
3202 (* Here ret_ty should include Awaitable wrapper *)
3203 (* TODO: ?el is never set; so we need to fix variadic use of lambda *)
3204 and anon_make ?el ?
ret_ty env lambda_pos f
ft idl
is_anon =
3205 let nb = Nast.assert_named_body f
.f_body
in
3206 Env.anon
env.lenv env (fun env ->
3207 (* Extract capabilities from AAST and add them to the environment *)
3208 let (env, capability
) =
3209 match (hint_of_type_hint f
.f_cap
, hint_of_type_hint f
.f_unsafe_cap
) with
3211 (* if the closure has no explicit coeffect annotations,
3212 do _not_ insert (unsafe) capabilities into the environment;
3213 instead, rely on the fact that a capability from an enclosing
3214 scope can simply be captured, which has the same semantics
3215 as redeclaring and shadowing with another same-typed capability.
3216 This avoid unnecessary overhead in the most common case, i.e.,
3217 when a closure does not need a different (usually smaller)
3218 set of capabilities. *)
3219 (env, Env.get_local
env Typing_coeffects.local_capability_id
)
3221 let (env, f_cap
, f_unsafe_cap
) =
3222 type_capability
env f
.f_cap f
.f_unsafe_cap
(fst f
.f_name
)
3224 Typing_coeffects.register_capabilities
3226 (type_of_type_hint f_cap
)
3227 (type_of_type_hint f_unsafe_cap
)
3230 { ft with ft_implicit_params
= { capability
= CapTy capability
} }
3232 stash_conts_for_anon
env lambda_pos
is_anon idl
(fun env ->
3233 let env = Env.clear_params
env in
3234 let make_variadic_arg env varg tyl
=
3235 let remaining_types =
3236 (* It's possible the variadic arg will capture the variadic
3237 * parameter of the supplied arity (if arity is Fvariadic)
3238 * and additional supplied params.
3240 * For example in cases such as:
3241 * lambda1 = (int $a, string...$c) ==> {};
3242 * lambda1(1, "hello", ...$y); (where $y is a variadic string)
3243 * lambda1(1, "hello", "world");
3244 * then ...$c will contain "hello" and everything in $y in the first
3245 * example, and "hello" and "world" in the second example.
3247 * To account for a mismatch in arity, we take the remaining supplied
3248 * parameters and return a list of all their types. We'll use this
3249 * to create a union type when creating the typed variadic arg.
3251 let remaining_params =
3252 List.drop
ft.ft_params
(List.length f
.f_params
)
3254 List.map ~f
:(fun param
-> param
.fp_type
.et_type
) remaining_params
3256 let r = Reason.Rvar_param varg
.param_pos
in
3257 let union = Tunion
(tyl
@ remaining_types) in
3258 let (env, t_param
) = anon_bind_variadic
env varg
(mk
(r, union)) in
3259 (env, Aast.FVvariadicArg t_param
)
3261 let (env, t_variadic
) =
3262 match (f
.f_variadic
, ft.ft_arity
) with
3263 | (FVvariadicArg arg
, Fvariadic variadic
) ->
3264 make_variadic_arg env arg
[variadic
.fp_type
.et_type
]
3265 | (FVvariadicArg arg
, Fstandard
) -> make_variadic_arg env arg
[]
3266 | (FVellipsis
pos, _
) -> (env, Aast.FVellipsis
pos)
3267 | (_
, _
) -> (env, Aast.FVnonVariadic
)
3269 let params = ref f
.f_params
in
3270 let (env, t_params
) =
3272 ~f
:(anon_bind_param
params)
3274 (List.map ft.ft_params
(fun x
-> x
.fp_type
.et_type
))
3276 let env = List.fold_left ~f
:anon_bind_opt_param ~
init:env !params in
3277 let env = List.fold_left ~f
:anon_check_param ~
init:env f
.f_params
in
3282 Unify.unify_param_modes
3288 match f
.f_variadic
with
3291 TUtils.default_fun_param
3293 (mk
(Reason.Rvar_param
pos, Typing_defs.make_tany
()))
3298 let rec iter l1 l2
=
3299 match (l1
, l2
, var_param) with
3301 | ([], _
, None
) -> ()
3302 | ([], x2
:: rl2
, Some def1
) ->
3303 param_modes ~is_variadic
:true def1 x2
;
3305 | (x1
:: rl1
, x2
:: rl2
, _
) ->
3309 iter ft.ft_params x
;
3310 wfold_left2 inout_write_back
env ft.ft_params x
3312 let env = Env.set_fn_kind
env f
.f_fun_kind
in
3315 ~f
:(Decl_hint.hint
env.decl_env
)
3316 (hint_of_type_hint f
.f_ret
)
3321 (* Do we have a contextual return type? *)
3325 let (env, ret_ty) = Env.fresh_type
env lambda_pos
in
3326 (env, Typing_return.wrap_awaitable
env lambda_pos
ret_ty)
3328 (* We might need to force it to be Awaitable if it is a type variable *)
3329 Typing_return.force_awaitable
env lambda_pos
ret_ty
3332 (* If a 'this' type appears it needs to be compatible with the
3336 { (Phase.env_with_self
env) with from_class
= Some CIstatic
}
3338 Typing_return.make_return_type
(Phase.localize ~
ety_env) env ret
3343 (Typing_return.make_info
3347 ~is_explicit
:(Option.is_some
ret_ty)
3351 let local_tpenv = Env.get_tpenv
env in
3352 (* Outer pipe variables aren't available in closures. Note that
3353 * locals are restored by Env.anon after processing the closure
3358 (Local_id.make_unscoped
SN.SpecialIdents.dollardollar
)
3360 let (env, tb) = block
env nb.fb_ast
in
3361 let implicit_return = LEnv.has_next
env in
3363 if (not
implicit_return) || Nast.named_body_is_unsafe
nb then
3366 fun_implicit_return
env lambda_pos hret f
.f_fun_kind
3368 let (env, tparams
) = List.map_env
env f
.f_tparams type_param
in
3369 let (env, user_attributes
) =
3370 List.map_env
env f
.f_user_attributes user_attribute
3372 let (env, f_cap
, f_unsafe_cap
) =
3373 type_capability
env f
.f_cap f
.f_unsafe_cap
(fst f
.f_name
)
3377 Aast.f_annotation
= Env.save
local_tpenv env;
3378 Aast.f_span
= f
.f_span
;
3379 Aast.f_mode
= f
.f_mode
;
3380 Aast.f_ret
= (hret
, hint_of_type_hint f
.f_ret
);
3381 Aast.f_name
= f
.f_name
;
3382 Aast.f_tparams
= tparams
;
3383 Aast.f_where_constraints
= f
.f_where_constraints
;
3384 Aast.f_fun_kind
= f
.f_fun_kind
;
3385 Aast.f_file_attributes
= [];
3386 Aast.f_user_attributes
= user_attributes
;
3387 Aast.f_body
= { Aast.fb_ast
= tb; fb_annotation
= () };
3390 Aast.f_params
= t_params
;
3391 Aast.f_variadic
= t_variadic
;
3392 (* TODO TAST: Variadic efuns *)
3393 Aast.f_external
= f
.f_external
;
3394 Aast.f_namespace
= f
.f_namespace
;
3395 Aast.f_doc_comment
= f
.f_doc_comment
;
3396 Aast.f_static
= f
.f_static
;
3399 let ty = mk
(Reason.Rwitness lambda_pos
, Tfun
ft) in
3401 Tast.make_typed_expr
3405 Aast.Efun
(tfun_, idl
)
3407 Aast.Lfun
(tfun_, idl
) )
3409 let env = Env.set_tyvar_variance
env ty in
3410 (env, (te, hret
, ft))
3411 (* stash_conts_for_anon *))
3414 (*****************************************************************************)
3415 (* End of anonymous functions. *)
3416 (*****************************************************************************)
3418 (*****************************************************************************)
3419 (* Expression trees *)
3420 (*****************************************************************************)
3421 and expression_tree
env p et
=
3422 let (_
, t_src_expr
, _
) = expr_any env p et
.et_src_expr
in
3423 let (env, t_desugared_expr
, ty_desugared
) = expr env et
.et_desugared_expr
in
3427 (Aast.ExpressionTree
3429 et_hint
= et
.et_hint
;
3430 et_src_expr
= t_src_expr
;
3431 et_desugared_expr
= t_desugared_expr
;
3435 and et_splice
env p e =
3436 let (env, te, ty) = expr env e in
3437 let (env, ty_visitor
) = Env.fresh_type
env p in
3438 let (env, ty_res
) = Env.fresh_type
env p in
3439 let (env, ty_infer
) = Env.fresh_type
env p in
3440 let expr_tree_type =
3441 MakeType.expr_tree
(Reason.Rsplice
p) ty_visitor ty_res ty_infer
3443 let env = SubType.sub_type
env ty expr_tree_type Errors.unify_error
in
3444 make_result
env p (Aast.ET_Splice
te) ty_infer
3446 (*****************************************************************************)
3447 (* End expression trees *)
3448 (*****************************************************************************)
3450 (* Goes from Nast.f_cap to Tast.f_cap (same for unsafe_cap) *)
3451 and type_capability
env cap unsafe_cap default_pos
=
3452 let cap_hint_opt = hint_of_type_hint cap
in
3456 ~default
:(MakeType.default_capability
(Reason.Rhint default_pos
))
3457 ~f
:(Decl_hint.hint
env.decl_env
)
3458 |> Phase.localize_with_self
env
3460 let unsafe_cap_hint_opt = hint_of_type_hint unsafe_cap
in
3461 let (env, unsafe_cap_ty
) =
3463 unsafe_cap_hint_opt (* default is no unsafe capabilities *)
3464 ~default
:(env, MakeType.mixed (Reason.Rhint default_pos
))
3465 ~f
:(Phase.localize_hint_with_self
env)
3467 (env, (cap_ty
, cap_hint_opt), (unsafe_cap_ty
, unsafe_cap_hint_opt))
3469 and requires_consistent_construct
= function
3476 (* Caller will be looking for a particular form of expected type
3477 * e.g. a function type (when checking lambdas) or tuple type (when checking
3478 * tuples). First expand the expected type and elide single union; also
3479 * strip nullables, so ?t becomes t, as context will always accept a t if a ?t
3482 and expand_expected_and_get_node
env (expected : ExpectedTy.t
option) =
3484 | None
-> (env, None
)
3485 | Some
ExpectedTy.{ pos = p; reason = ur; ty = { et_type
= ty; _
}; _
} ->
3486 let (env, ty) = Env.expand_type
env ty in
3487 (match get_node
ty with
3488 | Tunion
[ty] -> (env, Some
(p, ur, ty, get_node
ty))
3489 | Toption
ty -> (env, Some
(p, ur, ty, get_node
ty))
3490 | _
-> (env, Some
(p, ur, ty, get_node
ty)))
3492 (** Do a subtype check of inferred type against expected type *)
3493 and check_expected_ty message
env inferred_ty (expected : ExpectedTy.t
option) =
3496 | Some
ExpectedTy.{ pos = p; reason = ur; ty } ->
3498 log_with_level
env "typing" 1 (fun () ->
3505 "Typing.check_expected_ty %s enforced=%b"
3509 Log_type
("inferred_ty", inferred_ty);
3510 Log_type
("expected_ty", ty.et_type
);
3513 Typing_coercion.coerce_type
p ur env inferred_ty ty Errors.unify_error
3516 ~
(expected : ExpectedTy.t
option)
3526 (* Obtain class info from the cid expression. We get multiple
3527 * results with a CIexpr that has a union type, e.g. in
3529 $classname = (mycond()? classname<A>: classname<B>);
3532 let (env, tal
, tcid
, classes
) =
3533 instantiable_cid ~exact
:Exact
p env cid explicit_targs
3535 let allow_abstract_bound_generic =
3537 | ((_
, ty), Aast.CI
(_
, tn
)) -> is_generic_equal_to tn
ty
3540 let gather (env, _tel
, _typed_unpack_element
) (cname
, class_info, c_ty
) =
3543 && Cls.abstract
class_info
3544 && (not
(requires_consistent_construct
cid))
3545 && not
allow_abstract_bound_generic
3547 uninstantiable_error
3551 (Cls.pos class_info)
3552 (Cls.name class_info)
3555 let (env, obj_ty_
, params) =
3556 let (env, c_ty
) = Env.expand_type
env c_ty
in
3557 match (cid, tal
, get_class_type c_ty
) with
3558 (* Explicit type arguments *)
3559 | (CI _
, _
:: _
, Some
(_
, _
, tyl
)) -> (env, get_node c_ty
, tyl
)
3560 | (_
, _
, class_type_opt
) ->
3562 List.map_env
env (Cls.tparams
class_info) (fun env tparam ->
3564 Env.fresh_type_reason
3566 (Reason.Rtype_variable_generics
3567 (p, snd
tparam.tp_name
, strip_ns
(snd cname
)))
3569 Typing_log.log_new_tvar_for_new_object
env p tvar cname
tparam;
3573 match class_type_opt
with
3574 | Some
(_
, Exact
, _
) -> (env, Tclass
(cname
, Exact
, params), params)
3575 | _
-> (env, Tclass
(cname
, Nonexact
, params), params)
3580 && (not is_using_clause
)
3581 && Cls.is_disposable
class_info
3583 Errors.invalid_new_disposable
p;
3584 let r_witness = Reason.Rwitness
p in
3585 let obj_ty = mk
(r_witness, obj_ty_
) in
3590 mk
(r_witness, get_node
c_ty)
3594 let ((_
, cid_ty
), _
) = tcid
in
3595 let (env, cid_ty
) = Env.expand_type
env cid_ty
in
3596 if is_generic cid_ty
then
3598 else if check_parent
then
3601 ExprDepTy.make
env cid c_ty
3603 (* Set variance according to type of `new` expression now. Lambda arguments
3604 * to the constructor might depend on it, and `call_construct` only uses
3605 * `ctor_fty` to set the variance which has void return type *)
3606 let env = Env.set_tyvar_variance
env new_ty
in
3607 let (env, tel
, typed_unpack_element
, ctor_fty
) =
3608 let env = check_expected_ty
"New" env new_ty
expected in
3609 call_construct
p env class_info params el unpacked_element
cid new_ty
3611 ( if equal_consistent_kind
(snd
(Cls.construct
class_info)) Inconsistent
then
3613 | CIstatic
-> Errors.new_inconsistent_construct
p cname `static
3614 | CIexpr _
-> Errors.new_inconsistent_construct
p cname `
classname
3618 let (env, ctor_fty
) =
3619 match fst
(Cls.construct
class_info) with
3620 | Some
({ ce_type
= (lazy ty); _
} as ce
) ->
3623 type_expansions
= [];
3625 TUtils.make_locl_subst_for_class_tparams
class_info params;
3629 on_error
= Errors.unify_error_at
p;
3632 if get_ce_abstract ce
then
3633 Errors.parent_abstract_call
3634 SN.Members.__construct
3637 let (env, ctor_fty
) = Phase.localize ~
ety_env env ty in
3639 | None
-> (env, ctor_fty
)
3641 ((env, tel
, typed_unpack_element
), (obj_ty, ctor_fty
))
3645 ((env, tel
, typed_unpack_element
), (c_ty, ctor_fty
))
3647 (* When constructing from a (classname) variable, the variable
3648 * dictates what the constructed object is going to be. This allows
3649 * for generic and dependent types to be correctly carried
3650 * through the 'new $foo()' iff the constructed obj_ty is a
3651 * supertype of the variable-dictated c_ty *)
3653 Typing_ops.sub_type
p Reason.URnone
env c_ty obj_ty Errors.unify_error
3655 ((env, tel
, typed_unpack_element
), (c_ty, ctor_fty
))
3657 let ((env, tel
, typed_unpack_element
), class_types_and_ctor_types
) =
3658 List.fold_map classes ~
init:(env, [], None
) ~f
:gather
3660 let (env, tel
, typed_unpack_element
, ty, ctor_fty
) =
3661 match class_types_and_ctor_types
with
3663 let (env, tel
, _
) = exprs env el
in
3664 let (env, typed_unpack_element
, _
) =
3665 match unpacked_element
with
3666 | None
-> (env, None
, MakeType.nothing
Reason.Rnone
)
3667 | Some unpacked_element
->
3668 let (env, e, ty) = expr env unpacked_element
in
3671 let r = Reason.Runknown_class
p in
3672 (env, tel
, typed_unpack_element
, mk
(r, Tobject
), TUtils.terr
env r)
3673 | [(ty, ctor_fty
)] -> (env, tel
, typed_unpack_element
, ty, ctor_fty
)
3675 let (tyl
, ctyl
) = List.unzip l
in
3676 let r = Reason.Rwitness
p in
3677 (env, tel
, typed_unpack_element
, mk
(r, Tunion tyl
), mk
(r, Tunion ctyl
))
3680 let ((_
, cid_ty
), _
) = tcid
in
3681 let (env, cid_ty
) = Env.expand_type
env cid_ty
in
3682 if is_generic cid_ty
then
3684 else if check_parent
then
3687 ExprDepTy.make
env cid ty
3689 (env, tcid
, tal
, tel
, typed_unpack_element
, new_ty
, ctor_fty
)
3691 and attributes_check_def
env kind attrs
=
3692 Typing_attributes.check_def
env new_object kind attrs
3694 (** Get class infos for a class expression (e.g. `parent`, `self` or
3695 regular classnames) - which might resolve to a union or intersection
3696 of classes - and check they are instantiable.
3698 FIXME: we need to separate our instantiability into two parts. Currently,
3699 all this function is doing is checking if a given type is inhabited --
3700 that is, whether there are runtime values of type Aast. However,
3701 instantiability should be the stricter notion that T has a runtime
3702 constructor; that is, `new T()` should be valid. In particular, interfaces
3703 are inhabited, but not instantiable.
3704 To make this work with classname, we likely need to add something like
3705 concrete_classname<T>, where T cannot be an interface. *)
3706 and instantiable_cid ?
(exact
= Nonexact
) p env cid explicit_targs
=
3707 let (env, tal
, te, classes
) =
3708 class_id_for_new ~exact
p env cid explicit_targs
3710 List.iter classes
(fun ((pos, name), class_info, c_ty) ->
3712 Ast_defs.(equal_class_kind
(Cls.kind
class_info) Ctrait
)
3713 || Ast_defs.(equal_class_kind
(Cls.kind
class_info) Cenum
)
3718 uninstantiable_error
env p cid (Cls.pos class_info) name pos c_ty
3724 Ast_defs.(equal_class_kind
(Cls.kind
class_info) Cabstract
)
3725 && Cls.final
class_info
3727 uninstantiable_error
env p cid (Cls.pos class_info) name pos c_ty
3730 (env, tal
, te, classes
)
3732 and uninstantiable_error
env reason_pos
cid c_tc_pos c_name c_usage_pos
c_ty =
3736 let ty_str = "This would be " ^
Typing_print.error
env c_ty in
3737 [(reason_pos
, ty_str)]
3740 Errors.uninstantiable_class c_usage_pos c_tc_pos c_name
reason_msgl
3742 and coerce_to_throwable
pos env exn_ty
=
3743 let throwable_ty = MakeType.throwable
(Reason.Rthrow
pos) in
3744 Typing_coercion.coerce_type
3749 { et_type
= throwable_ty; et_enforced
= false }
3752 and shape_field_pos
= function
3753 | Ast_defs.SFlit_int
(p, _
)
3754 | Ast_defs.SFlit_str
(p, _
) ->
3756 | Ast_defs.SFclass_const
((cls_pos
, _
), (mem_pos
, _
)) ->
3757 Pos.btw cls_pos mem_pos
3759 and check_shape_keys_validity
env pos keys
=
3760 (* If the key is a class constant, get its class name and type. *)
3761 let get_field_info env key
=
3762 let key_pos = shape_field_pos key
in
3763 (* Empty strings or literals that start with numbers are not
3764 permitted as shape field names. *)
3766 | Ast_defs.SFlit_int _
-> (env, key_pos, None
)
3767 | Ast_defs.SFlit_str
(_
, key_name
) ->
3768 if Int.equal
0 (String.length key_name
) then
3769 Errors.invalid_shape_field_name_empty
key_pos;
3770 (env, key_pos, None
)
3771 | Ast_defs.SFclass_const
(((p, cls
) as x
), y
) ->
3772 let (env, _te
, ty) = class_const
env pos ((p, CI x
), y
) in
3773 let r = Reason.Rwitness
key_pos in
3780 (MakeType.arraykey r)
3782 Errors.invalid_shape_field_type
3785 (Typing_print.error
env ty)
3788 (env, key_pos, Some
(cls
, ty))
3790 let check_field witness_pos witness_info
env key
=
3791 let (env, key_pos, key_info
) = get_field_info env key
in
3792 match (witness_info
, key_info
) with
3794 Errors.invalid_shape_field_literal
key_pos witness_pos
;
3797 Errors.invalid_shape_field_const
key_pos witness_pos
;
3799 | (None
, None
) -> env
3800 | (Some
(cls1
, ty1
), Some
(cls2
, ty2
)) ->
3801 if String.( <> ) cls1 cls2
then
3802 Errors.shape_field_class_mismatch
3809 ( Typing_solver.is_sub_type
env ty1 ty2
3810 && Typing_solver.is_sub_type
env ty2 ty1
)
3812 Errors.shape_field_type_mismatch
3815 (Typing_print.error
env ty2
)
3816 (Typing_print.error
env ty1
);
3819 (* Sort the keys by their positions since the error messages will make
3820 * more sense if we take the one that appears first as canonical and if
3821 * they are processed in source order. *)
3822 let cmp_keys x y
= Pos.compare
(shape_field_pos x
) (shape_field_pos y
) in
3823 let keys = List.sort ~compare
:cmp_keys keys in
3826 | witness
:: rest_keys
->
3827 let (env, pos, info
) = get_field_info env witness
in
3828 List.fold_left ~f
:(check_field pos info
) ~
init:env rest_keys
3830 and set_valid_rvalue
p env x
ty =
3831 let env = set_local
env (p, x
) ty in
3832 (* We are assigning a new value to the local variable, so we need to
3833 * generate a new expression id
3835 Env.set_local_expr_id
env x
(Ident.tmp
())
3837 (* Produce an error if assignment is used in the scope of the |> operator, i.e.
3838 * if $$ is in scope *)
3839 and error_if_assign_in_pipe
p env =
3840 let dd_var = Local_id.make_unscoped
SN.SpecialIdents.dollardollar
in
3841 let dd_defined = Env.is_local_defined
env dd_var in
3843 Errors.unimplemented_feature
p "Assignment within pipe expressions"
3845 (* Deal with assignment of a value of type ty2 to lvalue e1 *)
3846 and assign
p env e1 ty2
: _
* Tast.expr * Tast.ty =
3847 error_if_assign_in_pipe
p env;
3848 assign_
p Reason.URassign
env e1 ty2
3850 and is_hack_collection
env ty =
3851 Typing_solver.is_sub_type
3854 (MakeType.const_collection
Reason.Rnone
(MakeType.mixed Reason.Rnone
))
3856 and assign_
p ur env e1 ty2
=
3859 | (_
, Lvar
(_
, x
)) ->
3860 Env.forget_prefixed_members
env x
Reason.(Blame
(p, BSassignment
))
3861 (* If we ever extend fake members from $x->a to more complicated lvalues
3862 such as $x->a->b, we would need to call forget_prefixed_members on
3863 other lvalues as well. *)
3864 | (_
, Obj_get
(_
, (_
, Id
(_
, property
)), _
, _
)) ->
3865 Env.forget_suffixed_members
env property
Reason.(Blame
(p, BSassignment
))
3869 | (_
, Lvar
((_
, x
) as id)) ->
3870 let env = set_valid_rvalue
p env x ty2
in
3871 make_result
env (fst e1
) (Aast.Lvar
id) ty2
3872 | (_
, Lplaceholder
id) ->
3873 let placeholder_ty = MakeType.void
(Reason.Rplaceholder
p) in
3874 make_result
env (fst e1
) (Aast.Lplaceholder
id) placeholder_ty
3877 List.map_env
env el ~f
:(fun env _
-> Env.fresh_type
env (get_pos ty2
))
3879 let destructure_ty =
3880 MakeType.list_destructure
(Reason.Rdestructure
(fst e1
)) tyl
3882 let lty2 = LoclType ty2
in
3883 let env = Type.sub_type_i
p ur env lty2 destructure_ty Errors.unify_error
in
3884 let env = Env.set_tyvar_variance_i
env destructure_ty in
3885 let (env, reversed_tel
) =
3886 List.fold2_exn el tyl ~
init:(env, []) ~f
:(fun (env, tel
) lvalue ty2
->
3887 let (env, te, _
) = assign
p env lvalue ty2
in
3890 make_result
env (fst e1
) (Aast.List
(List.rev reversed_tel
)) ty2
3892 Obj_get
(obj
, (pm
, Id
((_
, member_name
) as m
)), nullflavor
, in_parens
) )
3894 let lenv = env.lenv in
3896 match nullflavor
with
3897 | OG_nullthrows
-> None
3898 | OG_nullsafe
-> Some
(Reason.Rnullsafe_op pobj
)
3900 let (env, tobj, obj_ty) = expr ~accept_using_var
:true env obj
in
3901 let env = might_throw
env in
3902 let (env, (result
, _tal
)) =
3907 ~coerce_from_ty
:(Some
(p, ur, ty2
))
3916 Tast.make_typed_expr
3921 Tast.make_typed_expr pm result
(Aast.Id m
),
3925 let env = { env with lenv } in
3929 let (env, local) = Env.FakeMembers.make
env obj member_name
p in
3930 let env = set_valid_rvalue
p env local ty2
in
3933 let (env, local) = Env.FakeMembers.make
env obj member_name
p in
3934 let env = set_valid_rvalue
p env local ty2
in
3936 | _
-> (env, te1, ty2
)
3939 let lenv = env.lenv in
3940 let no_fakes = LEnv.env_with_empty_fakes
env in
3941 let (env, te1, real_type
) = lvalue
no_fakes e1
in
3942 let (env, exp_real_type
) = Env.expand_type
env real_type
in
3943 let env = { env with lenv } in
3945 Typing_coercion.coerce_type
3950 (MakeType.unenforced exp_real_type
)
3954 | (_
, Class_get
(_
, CGexpr _
, _
)) ->
3955 failwith
"AST should not have any CGexprs after naming"
3956 | (_
, Class_get
((pos_classid
, x
), CGstring
(pos_member
, y
), _
)) ->
3957 let lenv = env.lenv in
3958 let no_fakes = LEnv.env_with_empty_fakes
env in
3959 let (env, te1, _
) = lvalue
no_fakes e1
in
3960 let env = { env with lenv } in
3961 let (env, ety2
) = Env.expand_type
env ty2
in
3962 (* This defers the coercion check to class_get, which looks up the appropriate target type *)
3963 let (env, _tal
, _
, cty
) =
3964 static_class_id ~check_constraints
:false pos_classid
env [] x
3966 let env = might_throw
env in
3971 ~coerce_from_ty
:(Some
(p, ur, ety2
))
3977 let (env, local) = Env.FakeMembers.make_static
env x y
p in
3978 let env = set_valid_rvalue
p env local ty2
in
3980 | (pos, Array_get
(e1
, None
)) ->
3981 let (env, te1, ty1
) = update_array_type
pos env e1 `lvalue
in
3983 Typing_array_access.assign_array_append
3992 if is_hack_collection
env ty1
then
3995 let (env, te1, _
) = assign_
p ur env e1 ty1'
in
3998 make_result
env pos (Aast.Array_get
(te1, None
)) ty2
3999 | (pos, Array_get
(e1
, Some
e)) ->
4000 let (env, te1, ty1
) = update_array_type
pos env e1 `lvalue
in
4001 let (env, te, ty) = expr env e in
4003 Typing_array_access.assign_array_get
4014 if is_hack_collection
env ty1
then
4017 let (env, te1, _
) = assign_
p ur env e1 ty1'
in
4020 (env, ((pos, ty2
), Aast.Array_get
(te1, Some
te)), ty2
)
4021 | _
-> assign_simple
p ur env e1 ty2
4023 and assign_simple
pos ur env e1 ty2
=
4024 let (env, te1, ty1
) = lvalue
env e1
in
4026 Typing_coercion.coerce_type
4031 (MakeType.unenforced ty1
)
4036 and array_field
env = function
4038 let (env, tve
, tv
) = expr env ve
in
4039 (env, (Aast.AFvalue tve
, None
, tv
))
4040 | AFkvalue
(ke
, ve
) ->
4041 let (env, tke
, tk) = expr env ke
in
4042 let (env, tve
, tv
) = expr env ve
in
4043 (env, (Aast.AFkvalue
(tke
, tve
), Some
tk, tv
))
4045 and array_value ~
(expected : ExpectedTy.t
option) env x
=
4046 let (env, te, ty) = expr ?
expected env x
in
4050 p class_name ~
(expected : ExpectedTy.t
option) env ((pos, _
) as x
) =
4051 let (env, (te, ty)) = array_value ~
expected env x
in
4052 let ty_arraykey = MakeType.arraykey (Reason.Ridx_dict
pos) in
4054 Typing_coercion.coerce_type
4056 (Reason.index_class
class_name)
4059 { et_type
= ty_arraykey; et_enforced
= true }
4064 and check_parent_construct
pos env el unpacked_element env_parent
=
4065 let check_not_abstract = false in
4066 let (env, env_parent
) = Phase.localize_with_self
env env_parent
in
4067 let (env, _tcid
, _tal
, tel
, typed_unpack_element
, parent
, fty) =
4072 ~is_using_clause
:false
4080 (* Not sure why we need to equate these types *)
4082 Type.sub_type
pos Reason.URnone
env env_parent parent
Errors.unify_error
4085 Type.sub_type
pos Reason.URnone
env parent env_parent
Errors.unify_error
4089 typed_unpack_element
,
4090 MakeType.void
(Reason.Rwitness
pos),
4094 and check_class_get
env p def_pos cid mid ce
e function_pointer
=
4096 | CIself
when get_ce_abstract ce
->
4098 match get_class_type
(Env.get_self
env) with
4099 | Some
((_
, self
), _
, _
) ->
4100 (* at runtime, self:: in a trait is a call to whatever
4101 * self:: is in the context of the non-trait "use"-ing
4102 * the trait's code *)
4104 match Env.get_class
env self
with
4105 | Some cls
when Ast_defs.(equal_class_kind
(Cls.kind cls
) Ctrait
) ->
4106 (* Ban self::some_abstract_method() in a trait, if the
4107 * method is also defined in a trait.
4109 * Abstract methods from interfaces are fine: we'll check
4110 * in the child class that we actually have an
4111 * implementation. *)
4112 (match Decl_provider.get_class
(Env.get_ctx
env) ce
.ce_origin
with
4114 when Ast_defs.(equal_class_kind
(Cls.kind meth_cls
) Ctrait
) ->
4115 Errors.self_abstract_call mid
p def_pos
4118 (* Ban self::some_abstract_method() in a class. This will
4120 Errors.self_abstract_call mid
p def_pos
4124 | CIparent
when get_ce_abstract ce
->
4125 Errors.parent_abstract_call mid
p def_pos
4126 | CI _
when get_ce_abstract ce
&& function_pointer
->
4127 Errors.abstract_function_pointer
cid mid
p def_pos
4128 | CI _
when get_ce_abstract ce
->
4129 Errors.classname_abstract_call
cid mid
p def_pos
4130 | CI
(_
, classname) when get_ce_synthesized ce
->
4131 Errors.static_synthetic_method
classname mid
p def_pos
4134 and call_parent_construct
pos env el unpacked_element
=
4135 match Env.get_parent_ty
env with
4136 | Some parent
-> check_parent_construct
pos env el unpacked_element parent
4139 let ty = Typing_utils.mk_tany
env pos in
4140 let default = (env, [], None
, ty, ty, ty) in
4141 (match get_class_type
(Env.get_self
env) with
4142 | Some
((_
, self
), _
, _
) ->
4143 (match Env.get_class
env self
with
4144 | Some trait
when Ast_defs.(equal_class_kind
(Cls.kind trait
) Ctrait
) ->
4145 (match trait_most_concrete_req_class trait
env with
4147 Errors.parent_in_trait
pos;
4149 | Some
(_
, parent_ty
) ->
4150 check_parent_construct
pos env el unpacked_element parent_ty
)
4152 if not
(Cls.members_fully_known self_tc
) then
4154 (* Don't know the hierarchy, assume it's correct *)
4156 Errors.undefined_parent
pos;
4158 | None
-> assert false)
4160 Errors.parent_outside_class
pos;
4161 let ty = err_witness env pos in
4162 (env, [], None
, ty, ty, ty))
4164 (* Depending on the kind of expression we are dealing with
4165 * The typing of call is different.
4168 ~
(expected : ExpectedTy.t
option)
4173 ((fpos
, fun_expr
) as e)
4177 let make_call env te tal tel typed_unpack_element
ty =
4178 make_result
env p (Aast.Call
(te, tal
, tel
, typed_unpack_element
)) ty
4180 (* TODO: Avoid Tany annotations in TAST by eliminating `make_call_special` *)
4181 let make_call_special env id tel
ty =
4184 (Tast.make_typed_expr fpos
(TUtils.mk_tany
env fpos
) (Aast.Id
id))
4190 (* For special functions and pseudofunctions with a definition in hhi. *)
4191 let make_call_special_from_def env id tel ty_
=
4192 let (env, fty, tal
) = fun_type_of_id
env id explicit_targs el
in
4194 match get_node
fty with
4195 | Tfun
ft -> ft.ft_ret
.et_type
4196 | _
-> ty_
(Reason.Rwitness
p)
4198 make_call env (Tast.make_typed_expr fpos
fty (Aast.Id
id)) tal tel None
ty
4200 let overload_function = overload_function make_call fpos
in
4201 let check_disposable_in_return env fty =
4202 if is_return_disposable_fun_type env fty && not is_using_clause
then
4203 Errors.invalid_new_disposable
p
4206 (* Special function `echo` *)
4207 | Id
((p, pseudo_func
) as id)
4208 when String.equal pseudo_func
SN.SpecialFunctions.echo
->
4209 let (env, tel
, _
) = exprs ~accept_using_var
:true env el
in
4210 make_call_special env id tel
(MakeType.void
(Reason.Rwitness
p))
4211 (* Special function `isset` *)
4212 | Id
((_
, pseudo_func
) as id)
4213 when String.equal pseudo_func
SN.PseudoFunctions.isset
->
4215 exprs ~accept_using_var
:true ~check_defined
:false env el
4217 if Option.is_some unpacked_element
then
4218 Errors.unpacking_disallowed_builtin_function
p pseudo_func
;
4219 make_call_special_from_def env id tel
MakeType.bool
4220 (* Special function `unset` *)
4221 | Id
((_
, pseudo_func
) as id)
4222 when String.equal pseudo_func
SN.PseudoFunctions.unset
->
4223 let (env, tel
, _
) = exprs env el
in
4224 if Option.is_some unpacked_element
then
4225 Errors.unpacking_disallowed_builtin_function
p pseudo_func
;
4226 let checked_unset_error =
4227 if Partial.should_check_error
(Env.get_mode
env) 4135 then
4228 Errors.unset_nonidx_in_strict
4234 match (el
, unpacked_element
) with
4235 | ([(_
, Array_get
((_
, Class_const _
), Some _
))], None
)
4236 when Partial.should_check_error
(Env.get_mode
env) 4011 ->
4237 Errors.const_mutation
p Pos.none
"";
4239 | ([(_
, Array_get
(ea
, Some _
))], None
) ->
4240 let (env, _te
, ty) = expr env ea
in
4241 let r = Reason.Rwitness
p in
4242 let tmixed = MakeType.mixed r in
4249 MakeType.dict
r tmixed tmixed;
4250 MakeType.keyset
r tmixed;
4251 MakeType.darray
r tmixed tmixed;
4254 SubType.sub_type_or_fail
env ty super (fun () ->
4258 ("This is " ^
Typing_print.error ~ignore_dynamic
:true env ty)
4261 checked_unset_error p [];
4265 | [(p, Obj_get
(_
, _
, OG_nullsafe
, _
))] ->
4266 Errors.nullsafe_property_write_context
p;
4267 make_call_special_from_def env id tel
(TUtils.terr
env)
4268 | _
-> make_call_special_from_def env id tel
MakeType.void
)
4269 (* Special function `array_filter` *)
4270 | Id
((_
, array_filter
) as id)
4271 when String.equal array_filter
SN.StdlibFunctions.array_filter
4272 && (not
(List.is_empty el
))
4273 && Option.is_none unpacked_element
->
4274 (* dispatch the call to typecheck the arguments *)
4275 let (env, fty, tal
) = fun_type_of_id
env id explicit_targs el
in
4276 let (env, (tel
, typed_unpack_element
, res
)) =
4277 call ~
expected p env fty el unpacked_element
4279 (* but ignore the result and overwrite it with custom return type *)
4280 let x = List.hd_exn el
in
4281 let (env, _tx
, ty) = expr env x in
4282 let explain_array_filter ty =
4283 map_reason
ty ~f
:(fun r -> Reason.Rarray_filter
(p, r))
4285 let get_value_type env tv
=
4287 if List.length el
> 1 then
4290 Typing_solver.non_null
env p tv
4292 (env, explain_array_filter tv
)
4294 let rec get_array_filter_return_type env ty =
4295 let (env, ety
) = Env.expand_type
env ty in
4296 match deref ety
with
4297 | (r, Tvarray tv
) ->
4298 let (env, tv
) = get_value_type env tv
in
4299 (env, MakeType.varray
r tv
)
4300 | (r, Tunion tyl
) ->
4301 let (env, tyl
) = List.map_env
env tyl
get_array_filter_return_type in
4302 Typing_union.union_list
env r tyl
4303 | (r, Tintersection tyl
) ->
4304 let (env, tyl
) = List.map_env
env tyl
get_array_filter_return_type in
4305 Inter.intersect_list
env r tyl
4306 | (r, Tany _
) -> (env, mk
(r, Typing_utils.tany
env))
4307 | (r, Terr
) -> (env, TUtils.terr
env r)
4309 let (env, tk) = Env.fresh_type
env p in
4310 let (env, tv
) = Env.fresh_type
env p in
4313 let keyed_container_type =
4314 MakeType.keyed_container
Reason.Rnone
tk tv
4317 SubType.sub_type
env ety
keyed_container_type Errors.unify_error
4319 let (env, tv
) = get_value_type env tv
in
4320 (env, MakeType.darray
r (explain_array_filter tk) tv
))
4324 let container_type = MakeType.container
Reason.Rnone tv
in
4326 SubType.sub_type
env ety
container_type Errors.unify_error
4328 let (env, tv
) = get_value_type env tv
in
4332 (explain_array_filter (MakeType.arraykey r))
4334 (fun _
-> (env, res
)))
4336 let (env, rty) = get_array_filter_return_type env ty in
4338 map_ty
fty ~f
:(function
4339 | Tfun
ft -> Tfun
{ ft with ft_ret
= MakeType.unenforced
rty }
4344 (Tast.make_typed_expr fpos
fty (Aast.Id
id))
4347 typed_unpack_element
4349 (* Special function `type_structure` *)
4350 | Id
(p, type_structure
)
4351 when String.equal type_structure
SN.StdlibFunctions.type_structure
4352 && Int.equal
(List.length el
) 2
4353 && Option.is_none unpacked_element
->
4357 | (p, String cst
) ->
4358 (* find the class constant implicitly defined by the typeconst *)
4361 | (_
, Class_const
(cid, (_
, x)))
4362 | (_
, Class_get
(cid, CGstring
(_
, x), _
))
4363 when String.equal
x SN.Members.mClass
->
4365 | _
-> (fst e1
, CIexpr e1
)
4367 class_const ~incl_tc
:true env p (cid, (p, cst
))
4369 Errors.illegal_type_structure
p "second argument is not a string";
4370 expr_error env (Reason.Rwitness
p) e)
4371 | _
-> assert false)
4372 (* Special function `array_map` *)
4373 | Id
((_
, array_map
) as x)
4374 when String.equal array_map
SN.StdlibFunctions.array_map
4375 && (not
(List.is_empty el
))
4376 && Option.is_none unpacked_element
->
4377 (* This uses the arity to determine a signature for array_map. But there
4378 * is more: for two-argument use of array_map, we specialize the return
4379 * type to the collection that's passed in, below. *)
4380 let (env, fty, tal
) = fun_type_of_id
env x explicit_targs el
in
4381 let (env, fty) = Env.expand_type
env fty in
4382 let r_fty = get_reason
fty in
4384 Takes a Container type and returns a function that can "pack" a type
4385 into an array of appropriate shape, preserving the key type, i.e.:
4386 array -> f, where f R = array
4387 array<X> -> f, where f R = array<R>
4388 array<X, Y> -> f, where f R = array<X, R>
4389 Vector<X> -> f where f R = array<R>
4390 KeyedContainer<X, Y> -> f, where f R = array<X, R>
4391 Container<X> -> f, where f R = array<arraykey, R>
4392 X -> f, where f R = Y
4394 let rec build_output_container env (x : locl_ty
) :
4395 env * (env -> locl_ty
-> env * locl_ty
) =
4396 let (env, x) = Env.expand_type
env x in
4398 | (r, Tvarray _
) -> (env, (fun env tr
-> (env, MakeType.varray
r tr
)))
4399 | (r, Tany _
) -> (env, (fun env _
-> (env, mk
(r, Typing_utils.tany
env))))
4400 | (r, Terr
) -> (env, (fun env _
-> (env, TUtils.terr
env r)))
4401 | (r, Tunion tyl
) ->
4402 let (env, builders
) = List.map_env
env tyl
build_output_container in
4406 List.map_env
env builders
(fun env f
-> f
env tr
)
4408 Typing_union.union_list
env r tyl
)
4409 | (r, Tintersection tyl
) ->
4410 let (env, builders
) = List.map_env
env tyl
build_output_container in
4414 List.map_env
env builders
(fun env f
-> f
env tr
)
4416 Typing_intersection.intersect_list
env r tyl
)
4418 let (env, tk) = Env.fresh_type
env p in
4419 let (env, tv
) = Env.fresh_type
env p in
4420 let try_vector env =
4421 let vector_type = MakeType.const_vector
r_fty tv
in
4422 let env = SubType.sub_type
env x vector_type Errors.unify_error
in
4423 (env, (fun env tr
-> (env, MakeType.varray
r tr
)))
4425 let try_keyed_container env =
4426 let keyed_container_type = MakeType.keyed_container
r_fty tk tv
in
4428 SubType.sub_type
env x keyed_container_type Errors.unify_error
4430 (env, (fun env tr
-> (env, MakeType.darray
r tk tr
)))
4432 let try_container env =
4433 let container_type = MakeType.container
r_fty tv
in
4434 let env = SubType.sub_type
env x container_type Errors.unify_error
in
4436 (fun env tr
-> (env, MakeType.darray
r (MakeType.arraykey r) tr
)) )
4440 (fun () -> try_vector env)
4443 (fun () -> try_keyed_container env)
4446 (fun () -> try_container env)
4448 (env, (fun env _
-> (env, Typing_utils.mk_tany
env p))))))
4453 match (deref
fty, el
) with
4454 | ((_
, Tfun funty
), [_
; x]) ->
4455 let (env, _tx
, x) = expr env x in
4456 let (env, output_container
) = build_output_container env x in
4458 match get_varray_inst funty
.ft_ret
.et_type
with
4459 | None
-> (env, fty)
4461 let (env, elem_ty
) = output_container
env elem_ty
in
4462 let ft_ret = MakeType.unenforced elem_ty
in
4463 (env, mk
(r_fty, Tfun
{ funty
with ft_ret }))
4467 let (env, (tel
, typed_unpack_element
, ty)) =
4468 call ~
expected p env fty el None
4472 (Tast.make_typed_expr fpos
fty (Aast.Id
x))
4475 typed_unpack_element
4477 (* Special function `Shapes::idx` *)
4478 | Class_const
(((_
, CI
(_
, shapes
)) as class_id
), ((_
, idx
) as method_id
))
4479 when String.equal shapes
SN.Shapes.cShapes
&& String.equal idx
SN.Shapes.idx
4488 (fun env fty res el
->
4491 let (env, _ts
, shape_ty
) = expr env shape
in
4498 ~fun_pos
:(get_reason
fty)
4499 ~shape_pos
:(fst shape
)
4500 | [shape
; field
; default] ->
4501 let (env, _ts
, shape_ty
) = expr env shape
in
4502 let (env, _td
, default_ty
) = expr env default in
4507 (Some
(fst
default, default_ty
))
4509 ~fun_pos
:(get_reason
fty)
4510 ~shape_pos
:(fst shape
)
4512 (* Special function `Shapes::at` *)
4513 | Class_const
(((_
, CI
(_
, shapes
)) as class_id
), ((_
, at
) as method_id
))
4514 when String.equal shapes
SN.Shapes.cShapes
&& String.equal at
SN.Shapes.at
4523 (fun env _fty res el
->
4526 let (env, _te
, shape_ty
) = expr env shape
in
4527 Typing_shapes.at
env ~
expr_pos:p ~shape_pos
:(fst shape
) shape_ty field
4529 (* Special function `Shapes::keyExists` *)
4531 (((_
, CI
(_
, shapes
)) as class_id
), ((_
, key_exists
) as method_id
))
4532 when String.equal shapes
SN.Shapes.cShapes
4533 && String.equal key_exists
SN.Shapes.keyExists
->
4541 (fun env fty res el
->
4544 let (env, _te
, shape_ty
) = expr env shape
in
4545 (* try accessing the field, to verify existence, but ignore
4546 * the returned type and keep the one coming from function
4547 * return type hint *)
4555 ~fun_pos
:(get_reason
fty)
4556 ~shape_pos
:(fst shape
)
4560 (* Special function `Shapes::removeKey` *)
4562 (((_
, CI
(_
, shapes
)) as class_id
), ((_
, remove_key
) as method_id
))
4563 when String.equal shapes
SN.Shapes.cShapes
4564 && String.equal remove_key
SN.Shapes.removeKey
->
4572 (fun env _ res el
->
4577 | (_
, Lvar
(_
, lvar
))
4578 | (_
, Callconv
(Ast_defs.Pinout
, (_
, Lvar
(_
, lvar
)))) ->
4579 let (env, _te
, shape_ty
) = expr env shape
in
4580 let (env, shape_ty
) =
4581 Typing_shapes.remove_key
p env shape_ty field
4583 let env = set_valid_rvalue
p env lvar shape_ty
in
4586 Errors.invalid_shape_remove_key
(fst shape
);
4590 (* Special function `Shapes::toArray` *)
4591 | Class_const
(((_
, CI
(_
, shapes
)) as class_id
), ((_
, to_array
) as method_id
))
4592 when String.equal shapes
SN.Shapes.cShapes
4593 && String.equal to_array
SN.Shapes.toArray
->
4601 (fun env _ res el
->
4604 let (env, _te
, shape_ty
) = expr env shape
in
4605 Typing_shapes.to_array
env p shape_ty res
4607 (* Special function `Shapes::toDict` *)
4608 | Class_const
(((_
, CI
(_
, shapes
)) as class_id
), ((_
, to_array
) as method_id
))
4609 when String.equal shapes
SN.Shapes.cShapes
4610 && String.equal to_array
SN.Shapes.toDict
->
4618 (fun env _ res el
->
4621 let (env, _te
, shape_ty
) = expr env shape
in
4622 Typing_shapes.to_dict
env p shape_ty res
4624 (* Special function `parent::__construct` *)
4625 | Class_const
((pos, CIparent
), ((_
, construct
) as id))
4626 when String.equal construct
SN.Members.__construct
->
4627 let (env, tel
, typed_unpack_element
, ty, pty
, ctor_fty
) =
4628 call_parent_construct
p env el unpacked_element
4632 (Tast.make_typed_expr
4635 (Aast.Class_const
(((pos, pty
), Aast.CIparent
), id)))
4636 [] (* tal: no type arguments to constructor *)
4638 typed_unpack_element
4640 (* Calling parent / class method *)
4641 | Class_const
((pos, e1
), m
) ->
4642 let (env, _tal
, tcid
, ty1
) =
4644 ~check_constraints
:(not
(Nast.equal_class_id_ e1 CIparent
))
4651 mk
(Reason.Rwitness fpos
, TUtils.this_of
(Env.get_self
env))
4653 (* In static context, you can only call parent::foo() on static methods.
4654 * In instance context, you can call parent:foo() on static
4655 * methods as well as instance methods
4658 (not
(Nast.equal_class_id_ e1 CIparent
))
4659 || Env.is_static env
4660 || class_contains_smethod
env ty1 m
4662 let (env, (fty, tal
)) =
4665 ~coerce_from_ty
:None
4674 (* parent::nonStaticFunc() is really weird. It's calling a method
4675 * defined on the parent class, but $this is still the child class.
4676 * We can deal with this by hijacking the continuation that
4677 * calculates the SN.Typehints.this type *)
4678 let k_lhs _
= this_ty in
4684 ~coerce_from_ty
:None
4694 check_disposable_in_return env fty;
4696 if Nast.equal_class_id_ e1 CIparent
then
4701 let (env, (tel
, typed_unpack_element
, ty)) =
4706 ~receiver_is_self
:(Nast.equal_class_id_ e1 CIself
)
4718 (Tast.make_typed_expr fpos
fty (Aast.Class_const
(tcid
, m
)))
4721 typed_unpack_element
4723 (* Call instance method *)
4724 | Obj_get
(e1
, (pos_id
, Id m
), nullflavor
, false)
4725 when not
(TypecheckerOptions.method_call_inference
(Env.get_tcopt
env)) ->
4726 let (env, te1, ty1
) = expr ~accept_using_var
:true env e1
in
4728 match nullflavor
with
4729 | OG_nullthrows
-> None
4730 | OG_nullsafe
-> Some
p
4732 let (env, (tfty
, tal
)) =
4736 ~
nullsafe:(Option.map ~f
:(fun p -> Reason.Rnullsafe_op
p) nullsafe)
4737 ~coerce_from_ty
:None
4745 check_disposable_in_return env tfty
;
4746 let (env, (tel
, typed_unpack_element
, ty)) =
4752 ~receiver_is_self
:false
4764 (Tast.make_typed_expr
4769 Tast.make_typed_expr pos_id tfty
(Aast.Id m
),
4774 typed_unpack_element
4776 (* Call instance method using new method call inference *)
4777 | Obj_get
(receiver
, (pos_id
, Id meth
), nullflavor
, false) ->
4779 Typecheck `Obj_get` by enforcing that:
4780 - `<instance_type>` <: `Thas_member(m, #1)`
4781 where #1 is a fresh type variable.
4783 let (env, typed_receiver
, receiver_ty
) =
4784 expr ~accept_using_var
:true env receiver
4786 let env = might_throw
env in
4788 match nullflavor
with
4789 | OG_nullthrows
-> None
4790 | OG_nullsafe
-> Some
p
4792 (* Generate a fresh type `method_ty` for the type of the
4793 instance method, i.e. #1 *)
4794 let (env, method_ty
) = Env.fresh_type
env p in
4795 (* Create `Thas_member` constraint type *)
4796 let reason = Reason.Rwitness
(fst receiver
) in
4802 ~class_id
:(CIexpr receiver
)
4803 ~explicit_targs
:(Some explicit_targs
)
4805 let env = Env.set_tyvar_variance
env method_ty
in
4806 let (env, has_method_super_ty
) =
4807 if Option.is_none
nullsafe then
4808 (env, has_method_ty)
4810 (* If null-safe, then `receiver_ty` <: `?Thas_member(m, #1)`,
4811 but *unlike* property access typing in `expr_`, we still use `#1` as
4812 our "result" if `receiver_ty` is nullable (as opposed to `?#1`),
4813 deferring null-safety handling to after `call` *)
4814 let r = Reason.Rnullsafe_op
p in
4815 let null_ty = MakeType.null
r in
4816 Union.union_i
env r has_method_ty null_ty
4823 (LoclType receiver_ty
)
4827 (* Perhaps solve for `method_ty`. Opening and closing a scope is too coarse
4828 here - type parameters are localised to fresh type variables over the
4829 course of subtyping above, and we do not want to solve these until later.
4830 Once we typecheck all function calls with a subtyping of function types,
4831 we should not need to solve early at all - transitive closure of
4832 subtyping should give enough information. *)
4834 match get_var method_ty
with
4836 Typing_solver.solve_to_equal_bound_or_wrt_variance
4843 let localize_targ env (_
, targ
) = Phase.localize_targ env targ
in
4844 let (env, typed_targs
) =
4845 List.map_env
env ~f
:(localize_targ ~check_well_kinded
:true) explicit_targs
4847 check_disposable_in_return env method_ty
;
4848 let (env, (typed_params
, typed_unpack_element
, ret_ty)) =
4854 ~receiver_is_self
:false
4865 (* If the call is nullsafe AND the receiver is nullable,
4866 make the return type nullable too *)
4868 if Option.is_some
nullsafe then
4869 let r = Reason.Rnullsafe_op
p in
4870 let null_ty = MakeType.null
r in
4871 let (env, null_or_nothing_ty
) =
4872 Inter.intersect
env ~
r null_ty receiver_ty
4874 let (env, ret_option_ty
) = Union.union env null_or_nothing_ty
ret_ty in
4875 (env, ret_option_ty
)
4881 (Tast.make_typed_expr
4886 Tast.make_typed_expr pos_id method_ty
(Aast.Id meth
),
4891 typed_unpack_element
4893 (* Function invocation *)
4895 let (env, fty, tal
) = fun_type_of_id
env x explicit_targs el
in
4896 check_disposable_in_return env fty;
4897 let (env, (tel
, typed_unpack_element
, ty)) =
4898 call ~
expected p env fty el unpacked_element
4902 (Tast.make_typed_expr fpos
fty (Aast.Fun_id
x))
4905 typed_unpack_element
4907 | Id
((_
, id) as x) ->
4908 let (env, fty, tal
) = fun_type_of_id
env x explicit_targs el
in
4909 check_disposable_in_return env fty;
4910 let (env, (tel
, typed_unpack_element
, ty)) =
4911 call ~
expected p env fty el unpacked_element
4913 let is_mutable = String.equal
id SN.Rx.mutable_
in
4914 let is_move = String.equal
id SN.Rx.move
in
4915 let is_freeze = String.equal
id SN.Rx.freeze
in
4916 (* error when rx builtins are used in non-reactive context *)
4917 if not
(Env.env_local_reactive
env) then
4919 Errors.mutable_in_nonreactive_context
p
4920 else if is_move then
4921 Errors.move_in_nonreactive_context
p
4922 else if is_freeze then
4923 Errors.freeze_in_nonreactive_context
p;
4925 (* ban unpacking when calling builtings *)
4926 if (is_mutable || is_move || is_freeze) && Option.is_some unpacked_element
4928 Errors.unpacking_disallowed_builtin_function
p id;
4930 (* adjust env for Rx\freeze or Rx\move calls *)
4933 Typing_mutability.freeze_local
p env tel
4934 else if is_move then
4935 Typing_mutability.move_local
p env tel
4941 (Tast.make_typed_expr fpos
fty (Aast.Id
x))
4944 typed_unpack_element
4947 let (env, te, fty) = expr env e in
4949 Typing_solver.expand_type_and_solve
4950 ~description_of_expected
:"a function value"
4956 check_disposable_in_return env fty;
4957 let (env, (tel
, typed_unpack_element
, ty)) =
4958 call ~
expected p env fty el unpacked_element
4963 (* tal: no type arguments to function values, as they are non-generic *)
4966 typed_unpack_element
4969 and fun_type_of_id
env x tal el
=
4970 match Env.get_fun
env (snd
x) with
4972 let (env, _
, ty) = unbound_name env x (Pos.none
, Aast.Null
) in
4974 | Some
{ fe_type
; fe_pos
; fe_deprecated
; _
} ->
4975 (match get_node fe_type
with
4978 Typing_special_fun.transform_special_fun_ty
ft x (List.length el
)
4980 let ety_env = Phase.env_with_self
env in
4982 Phase.localize_targs
4983 ~check_well_kinded
:true
4987 ~use_name
:(strip_ns
(snd
x))
4990 (List.map ~f
:snd tal
)
4993 Typing_enforceability.compute_enforced_and_pessimize_fun_type
env ft
4995 let use_pos = fst
x in
4996 let def_pos = fe_pos
in
5001 { use_name
= strip_ns
(snd
x); use_pos; explicit_targs
= tal
}
5007 let fty = mk
(get_reason fe_type
, Tfun
ft) in
5008 TVis.check_deprecated ~
use_pos ~
def_pos fe_deprecated
;
5010 | _
-> failwith
"Expected function type")
5013 * Checks if a class (given by cty) contains a given static method.
5015 * We could refactor this + class_get
5017 and class_contains_smethod
env cty
(_pos
, mid
) =
5018 let lookup_member ty =
5019 match get_class_type
ty with
5020 | Some
((_
, c), _
, _
) ->
5021 (match Env.get_class
env c with
5024 Option.is_some
@@ Env.get_static_member
true env class_ mid
)
5027 let (_env
, tyl
) = TUtils.get_concrete_supertypes
env cty
in
5028 List.exists tyl ~f
:lookup_member
5034 ?
(explicit_targs
= [])
5036 ?
(function_pointer
= false)
5041 let (env, this_ty) =
5043 this_for_method
env cid cty
5065 ?
(explicit_targs
= [])
5067 ?
(function_pointer
= false)
5072 let (env, cty
) = Env.expand_type
env cty
in
5073 match deref cty
with
5074 | (r, Tany _
) -> (env, (mk
(r, Typing_utils.tany
env), []))
5075 | (r, Terr
) -> (env, (err_witness env (Reason.to_pos
r), []))
5076 | (_
, Tdynamic
) -> (env, (cty
, []))
5077 | (_
, Tunion tyl
) ->
5079 List.map_env
env tyl
(fun env ty ->
5092 Union.union_list
env (get_reason cty
) (List.map ~f
:fst
pairs)
5095 | (_
, Tintersection tyl
) ->
5097 TUtils.run_on_intersection
env tyl ~f
:(fun env ty ->
5110 Inter.intersect_list
env (get_reason cty
) (List.map ~f
:fst
pairs)
5113 | (_
, Tnewtype
(_
, _
, ty))
5114 | (_
, Tdependent
(_
, ty)) ->
5126 | (r, Tgeneric _
) ->
5127 let (env, tyl
) = TUtils.get_concrete_supertypes
env cty
in
5128 if List.is_empty tyl
then begin
5129 Errors.non_class_member
5133 (Typing_print.error
env cty
)
5135 (env, (err_witness env p, []))
5137 let (env, ty) = Typing_intersection.intersect_list
env r tyl
in
5149 | (_
, Tclass
((_
, c), _
, paraml
)) ->
5150 let class_ = Env.get_class
env c in
5152 | None
-> (env, (Typing_utils.mk_tany
env p, []))
5154 (* We need to instantiate generic parameters in the method signature *)
5157 type_expansions
= [];
5159 substs
= TUtils.make_locl_subst_for_class_tparams
class_ paraml
;
5160 from_class
= Some
cid;
5162 on_error
= Errors.unify_error_at
p;
5165 let get_smember_from_constraints env class_info =
5167 Cls.upper_bounds_on_this_from_constraints
class_info
5169 let (env, upper_bounds) =
5170 List.map_env
env upper_bounds ~f
:(fun env up
->
5171 Phase.localize ~
ety_env env up
)
5173 let (env, inter_ty
) =
5174 Inter.intersect_list
env (Reason.Rwitness
p) upper_bounds
5188 let try_get_smember_from_constraints env class_info =
5189 Errors.try_with_error
5190 (fun () -> get_smember_from_constraints env class_info)
5192 TOG.smember_not_found
5199 (env, (TUtils.terr
env Reason.Rnone
, [])))
5204 Env.get_const
env class_ mid
5206 match Env.get_typeconst
env class_ mid
with
5208 Errors.illegal_typeconst_direct_access
p;
5210 | None
-> Env.get_const
env class_ mid
5213 | None
when Cls.has_upper_bounds_on_this_from_constraints
class_ ->
5214 try_get_smember_from_constraints env class_
5216 TOG.smember_not_found
5223 (env, (TUtils.terr
env Reason.Rnone
, []))
5224 | Some
{ cc_type
; cc_abstract
; cc_pos
; _
} ->
5225 let (env, cc_locl_type
) = Phase.localize ~
ety_env env cc_type
in
5226 ( if cc_abstract
then
5232 let cc_name = Cls.name class_ ^
"::" ^ mid
in
5233 Errors.abstract_const_usage
p cc_pos
cc_name );
5234 (env, (cc_locl_type
, []))
5236 let static_member_opt =
5237 Env.get_static_member is_method
env class_ mid
5239 (match static_member_opt with
5240 | None
when Cls.has_upper_bounds_on_this_from_constraints
class_ ->
5241 try_get_smember_from_constraints env class_
5243 TOG.smember_not_found
5250 (env, (TUtils.terr
env Reason.Rnone
, []))
5253 ce_visibility = vis
;
5254 ce_type
= (lazy member_decl_ty
);
5258 let def_pos = get_pos member_decl_ty
in
5259 TVis.check_class_access
5263 (vis
, get_ce_lsb ce
)
5266 TVis.check_deprecated ~
use_pos:p ~
def_pos ce_deprecated;
5267 check_class_get
env p def_pos c mid ce
cid function_pointer
;
5268 let (env, member_ty
, et_enforced
, tal
) =
5269 match deref member_decl_ty
with
5270 (* We special case Tfun here to allow passing in explicit tparams to localize_ft. *)
5271 | (r, Tfun
ft) when is_method
->
5272 let (env, explicit_targs
) =
5273 Phase.localize_targs
5274 ~check_well_kinded
:true
5278 ~use_name
:(strip_ns mid
)
5281 (List.map ~f
:snd explicit_targs
)
5284 Typing_enforceability.compute_enforced_and_pessimize_fun_type
5292 { use_name
= strip_ns mid
; use_pos = p; explicit_targs
}
5298 (env, mk
(r, Tfun
ft), false, explicit_targs
)
5301 let { et_type
; et_enforced
} =
5302 Typing_enforceability.compute_enforced_and_pessimize_ty
5306 let (env, member_ty
) = Phase.localize ~
ety_env env et_type
in
5307 (* TODO(T52753871) make function just return possibly_enforced_ty
5308 * after considering intersection case *)
5309 (env, member_ty
, et_enforced
, [])
5311 let (env, member_ty
) =
5312 if Cls.has_upper_bounds_on_this_from_constraints
class_ then
5313 let ((env, (member_ty'
, _
)), succeed
) =
5314 Errors.try_with_error
5315 (fun () -> (get_smember_from_constraints env class_, true))
5317 (* No eligible functions found in constraints *)
5318 ((env, (MakeType.mixed Reason.Rnone
, [])), false))
5321 Inter.intersect
env (Reason.Rwitness
p) member_ty member_ty'
5328 match coerce_from_ty
with
5330 | Some
(p, ur, ty) ->
5331 Typing_coercion.coerce_type
5336 { et_type
= member_ty
; et_enforced
}
5339 (env, (member_ty
, tal
))))
5340 | (_
, Tunapplied_alias _
) ->
5341 Typing_defs.error_Tunapplied_alias_in_illegal_context
()
5343 ( Tvar _
| Tnonnull
| Tvarray _
| Tdarray _
| Tvarray_or_darray _
5344 | Toption _
| Tprim _
| Tfun _
| Ttuple _
| Tobject
| Tshape _
| Taccess _
5346 Errors.non_class_member
5350 (Typing_print.error
env cty
)
5352 (env, (err_witness env p, []))
5354 and class_id_for_new
5355 ~exact
p env (cid : Nast.class_id_
) (explicit_targs
: Nast.targ list
) :
5356 env * Tast.targ list
* Tast.class_id
* (sid
* Cls.t
* locl_ty
) list
=
5357 let (env, tal
, te, cid_ty
) =
5359 ~check_targs_well_kinded
:true
5360 ~check_explicit_targs
:true
5362 ~check_constraints
:false
5368 (* Need to deal with union case *)
5369 let rec get_info res tyl
=
5371 | [] -> (env, tal
, te, res
)
5373 (match get_node
ty with
5375 | Tintersection tyl'
->
5376 get_info res
(tyl'
@ tyl
)
5378 (* Instantiation on an abstract class (e.g. from classname<T>) is
5379 * via the base type (to check constructor args), but the actual
5380 * type `ty` must be preserved. *)
5381 (match get_class_type
(TUtils.get_base_type
env ty) with
5382 | Some
(sid
, _
, _
) ->
5383 let class_ = Env.get_class
env (snd sid
) in
5385 | None
-> get_info res tyl
5386 | Some
class_info ->
5387 (match (te, cid_ty
) with
5388 (* When computing the classes for a new T() where T is a generic,
5389 * the class must be consistent (final, final constructor, or
5390 * <<__ConsistentConstruct>>) for its constructor to be considered *)
5391 | ((_
, Aast.CI
(_
, c)), ty) when is_generic_equal_to
c ty ->
5392 (* Only have this choosing behavior for new T(), not all generic types
5393 * i.e. new classname<T>, TODO: T41190512 *)
5394 if Tast_utils.valid_newable_class
class_info then
5395 get_info ((sid
, class_info, ty) :: res
) tyl
5398 | _
-> get_info ((sid
, class_info, ty) :: res
) tyl
))
5399 | None
-> get_info res tyl
))
5401 get_info [] [cid_ty
]
5403 (* To be a valid trait declaration, all of its 'require extends' must
5404 * match; since there's no multiple inheritance, it follows that all of
5405 * the 'require extends' must belong to the same inheritance hierarchy
5406 * and one of them should be the child of all the others *)
5407 and trait_most_concrete_req_class trait
env =
5409 (Cls.all_ancestor_reqs trait
)
5413 let (_r
, (_p
, name), _paraml
) = TUtils.unwrap_class_type
ty in
5416 | Some
(c, _ty
) -> Cls.has_ancestor
c name
5422 let class_ = Env.get_class
env name in
5425 | Some
c when Ast_defs.(equal_class_kind
(Cls.kind
c) Cinterface
) ->
5427 | Some
c when Ast_defs.(equal_class_kind
(Cls.kind
c) Ctrait
) ->
5428 (* this is an error case for which Typing_check_decls spits out
5429 * an error, but does *not* currently remove the offending
5430 * 'require extends' or 'require implements' *)
5432 | Some
c -> Some
(c, ty)
5436 (* When invoking a method the class_id is used to determine what class we
5437 * lookup the method in, but the type of 'this' will be the late bound type.
5441 * public static function get(): this { return new static(); }
5443 * public static function alias(): this { return self::get(); }
5446 * In C::alias, when we invoke self::get(), 'self' is resolved to the class
5447 * in the lexical scope (C), so call C::get. However the method is executed in
5448 * the current context, so static inside C::get will be resolved to the late
5449 * bound type (get_called_class() within C::alias).
5451 * This means when determining the type of this, CIparent and CIself should be
5452 * changed to CIstatic. For the other cases of C::get() or $c::get(), we only
5453 * look at the left hand side of the '::' and use the type type associated
5456 * Thus C::get() will return a type C, while $c::get() will return the same
5459 and this_for_method
env cid default_ty
=
5464 let p = get_pos default_ty
in
5465 let (env, _tal
, _te
, ty) =
5466 static_class_id ~check_constraints
:false p env [] CIstatic
5468 ExprDepTy.make
env CIstatic
ty
5469 | _
-> (env, default_ty
)
5471 (** Resolve class expressions like `parent`, `self`, `static`, classnames
5474 ?
(check_targs_well_kinded
= false)
5476 ?
(check_explicit_targs
= false)
5477 ~
(check_constraints
: bool)
5480 (tal
: Nast.targ list
) :
5481 Nast.class_id_
-> env * Tast.targ list
* Tast.class_id
* locl_ty
=
5482 let make_result env tal
te ty = (env, tal
, ((p, ty), te), ty) in
5485 (match get_class_type
(Env.get_self
env) with
5486 | Some
((_
, self
), _
, _
) ->
5487 (match Env.get_class
env self
with
5488 | Some trait
when Ast_defs.(equal_class_kind
(Cls.kind trait
) Ctrait
) ->
5489 (match trait_most_concrete_req_class trait
env with
5491 Errors.parent_in_trait
p;
5492 make_result env [] Aast.CIparent
(err_witness env p)
5493 | Some
(_
, parent_ty
) ->
5494 (* inside a trait, parent is SN.Typehints.this, but with the
5495 * type of the most concrete class that the trait has
5496 * "require extend"-ed *)
5497 let r = Reason.Rwitness
p in
5498 let (env, parent_ty
) = Phase.localize_with_self
env parent_ty
in
5499 make_result env [] Aast.CIparent
(mk
(r, TUtils.this_of parent_ty
)))
5502 match Env.get_parent_ty
env with
5504 Errors.parent_undefined
p;
5505 mk
(Reason.none
, Typing_defs.make_tany
())
5506 | Some
parent -> parent
5508 let r = Reason.Rwitness
p in
5509 let (env, parent) = Phase.localize_with_self
env parent in
5510 (* parent is still technically the same object. *)
5515 (mk
(r, TUtils.this_of
(mk
(r, get_node
parent)))))
5518 match Env.get_parent_ty
env with
5520 Errors.parent_undefined
p;
5521 mk
(Reason.none
, Typing_defs.make_tany
())
5522 | Some
parent -> parent
5524 let r = Reason.Rwitness
p in
5525 let (env, parent) = Phase.localize_with_self
env parent in
5526 (* parent is still technically the same object. *)
5531 (mk
(r, TUtils.this_of
(mk
(r, get_node
parent)))))
5533 let this = mk
(Reason.Rwitness
p, TUtils.this_of
(Env.get_self
env)) in
5534 make_result env [] Aast.CIstatic
this
5537 match get_node
(Env.get_self
env) with
5538 | Tclass
(c, _
, tyl
) -> Tclass
(c, exact
, tyl
)
5541 make_result env [] Aast.CIself
(mk
(Reason.Rwitness
p, self))
5542 | CI
((p, id) as c) as e1
->
5544 match Env.get_pos_and_kind_of_generic
env id with
5545 | Some
(def_pos, kind
) ->
5546 let simple_kind = Typing_kinding_defs.Simple.from_full_kind kind
in
5548 Typing_kinding_defs.Simple.get_named_parameter_kinds
simple_kind
5551 Phase.localize_targs_with_kinds
5552 ~check_well_kinded
:check_targs_well_kinded
5556 ~use_name
:(strip_ns
(snd
c))
5557 ~check_explicit_targs
5560 (List.map ~f
:snd tal
)
5562 let r = Reason.Rhint
p in
5563 let type_args = List.map tal fst
in
5564 let tgeneric = MakeType.generic ~
type_args r id in
5565 make_result env tal
(Aast.CI
c) tgeneric
5567 (* Not a type parameter *)
5568 let class_ = Env.get_class
env id in
5570 | None
-> make_result env [] (Aast.CI
c) (Typing_utils.mk_tany
env p)
5572 let (env, ty, tal
) =
5574 |> Phase.localize_targs_and_check_constraints
5576 ~check_well_kinded
:check_targs_well_kinded
5578 ~
def_pos:(Cls.pos class_)
5580 ~check_explicit_targs
5584 (Cls.tparams
class_)
5586 make_result env tal
(Aast.CI
c) ty)
5588 | CIexpr
((p, _
) as e) ->
5589 let (env, te, ty) = expr env e in
5590 let rec resolve_ety env ty =
5592 Typing_solver.expand_type_and_solve
5593 ~description_of_expected
:"an object"
5599 let base_ty = TUtils.get_base_type
env ty in
5600 match deref
base_ty with
5601 | (_
, Tnewtype
(classname, [the_cls
], _
))
5602 when String.equal
classname SN.Classes.cClassname
->
5603 resolve_ety env the_cls
5607 | (r, Tunion tyl
) ->
5608 let (env, tyl
) = List.map_env
env tyl
resolve_ety in
5609 (env, MakeType.union r tyl
)
5610 | (r, Tintersection tyl
) ->
5611 let (env, tyl
) = TUtils.run_on_intersection
env tyl ~f
:resolve_ety in
5612 Inter.intersect_list
env r tyl
5613 | (_
, Tdynamic
) -> (env, base_ty)
5614 | (_
, (Tany _
| Tprim Tstring
| Tobject
)) when not
(Env.is_strict
env) ->
5615 (env, Typing_utils.mk_tany
env p)
5616 | (_
, Terr
) -> (env, err_witness env p)
5618 Errors.unknown_type
"an object" p (Reason.to_string
"It is unknown" r);
5619 (env, err_witness env p)
5620 | (_
, Tunapplied_alias _
) ->
5621 Typing_defs.error_Tunapplied_alias_in_illegal_context
()
5623 ( Tany _
| Tnonnull
| Tvarray _
| Tdarray _
| Tvarray_or_darray _
5624 | Toption _
| Tprim _
| Tfun _
| Ttuple _
| Tnewtype _
| Tdependent _
5625 | Tobject
| Tshape _
| Taccess _
) ) ->
5626 Errors.expected_class
5627 ~suffix
:(", but got " ^
Typing_print.error
env base_ty)
5629 (env, err_witness env p)
5631 let (env, result_ty
) = resolve_ety env ty in
5632 make_result env [] (Aast.CIexpr
te) result_ty
5634 and call_construct
p env class_ params el unpacked_element
cid cid_ty
=
5636 if Nast.equal_class_id_
cid CIparent
then
5637 (CIstatic
, mk
(Reason.Rwitness
p, TUtils.this_of
(Env.get_self
env)))
5643 type_expansions
= [];
5645 substs
= TUtils.make_locl_subst_for_class_tparams
class_ params;
5646 from_class
= Some
cid;
5648 on_error
= Errors.unify_error_at
p;
5652 Phase.check_tparams_constraints ~
use_pos:p ~
ety_env env (Cls.tparams
class_)
5655 Phase.check_where_constraints
5658 ~definition_pos
:(Cls.pos class_)
5661 (Cls.where_constraints
class_)
5663 if Cls.is_xhp
class_ then
5664 (env, [], None
, TUtils.mk_tany
env p)
5666 let cstr = Env.get_construct
env class_ in
5667 let mode = Env.get_mode
env in
5671 ((not
(List.is_empty el
)) || Option.is_some unpacked_element
)
5672 && (FileInfo.is_strict
mode || FileInfo.(equal_mode
mode Mpartial
))
5673 && Cls.members_fully_known
class_
5675 Errors.constructor_no_args
p;
5676 let (env, tel
, _tyl
) = exprs env el
in
5677 (env, tel
, None
, TUtils.terr
env Reason.Rnone
)
5678 | Some
{ ce_visibility = vis
; ce_type
= (lazy m
); ce_deprecated; _
} ->
5679 let def_pos = get_pos m
in
5680 TVis.check_obj_access ~
use_pos:p ~
def_pos env vis
;
5681 TVis.check_deprecated ~
use_pos:p ~
def_pos ce_deprecated;
5682 (* Obtain the type of the constructor *)
5687 Typing_enforceability.compute_enforced_and_pessimize_fun_type
env ft
5693 { use_name
= "constructor"; use_pos = p; explicit_targs
= [] }
5699 (env, mk
(r, Tfun
ft))
5701 Errors.internal_error
p "Expected function type for constructor";
5702 let ty = TUtils.terr
env r in
5705 let (env, (tel
, typed_unpack_element
, _ty
)) =
5706 call ~
expected:None
p env m el unpacked_element
5708 (env, tel
, typed_unpack_element
, m
)
5710 and check_arity ?
(did_unpack
= false) pos pos_def
ft (arity
: int) =
5711 let exp_min = Typing_defs.arity_min
ft in
5712 if arity
< exp_min then
5713 Errors.typing_too_few_args
exp_min arity
pos pos_def None
;
5714 match ft.ft_arity
with
5716 let exp_max = List.length
ft.ft_params
in
5723 if arity > exp_max then
5724 Errors.typing_too_many_args
exp_max arity pos pos_def None
5727 and check_lambda_arity lambda_pos
def_pos lambda_ft
expected_ft =
5728 match (lambda_ft
.ft_arity
, expected_ft.ft_arity
) with
5729 | (Fstandard
, Fstandard
) ->
5730 let expected_min = Typing_defs.arity_min
expected_ft in
5731 let lambda_min = Typing_defs.arity_min lambda_ft
in
5732 if lambda_min < expected_min then
5733 Errors.typing_too_few_args
expected_min lambda_min lambda_pos
def_pos None
;
5734 if lambda_min > expected_min then
5735 Errors.typing_too_many_args
5743 (* The variadic capture argument is an array listing the passed
5744 * variable arguments for the purposes of the function body; callsites
5745 * should not unify with it *)
5746 and variadic_param
env ft =
5747 match ft.ft_arity
with
5748 | Fvariadic
param -> (env, Some
param)
5749 | Fstandard
-> (env, None
)
5751 and param_modes ?
(is_variadic
= false) ({ fp_pos
; _
} as fp
) (pos, e) =
5752 match (get_fp_mode fp
, e) with
5753 | (FPnormal
, Callconv _
) ->
5754 Errors.inout_annotation_unexpected
pos fp_pos is_variadic
5755 | (FPnormal
, _
) -> ()
5756 | (FPinout
, Callconv
(Ast_defs.Pinout
, _
)) -> ()
5757 | (FPinout
, _
) -> Errors.inout_annotation_missing
pos fp_pos
5759 and inout_write_back
env { fp_type
; _
} (_
, e) =
5761 | Callconv
(Ast_defs.Pinout
, e1
) ->
5762 (* Translate the write-back semantics of inout parameters.
5764 * This matters because we want to:
5765 * (1) make sure we can write to the original argument
5766 * (modifiable lvalue check)
5767 * (2) allow for growing of locals / Tunions (type side effect)
5768 * but otherwise unify the argument type with the parameter hint
5770 let (env, _te
, _ty
) =
5771 assign_
(fst e1
) Reason.URparam_inout
env e1 fp_type
.et_type
5776 (** Typechecks a call.
5777 Returns in this order the typed expressions for the arguments, for the variadic arguments, and the return type. *)
5779 ~
(expected : ExpectedTy.t
option)
5780 ?
(method_call_info
: TR.method_call_info
option)
5781 ?
(nullsafe : Pos.t
option = None
)
5786 (el
: Nast.expr list
)
5787 (unpacked_element
: Nast.expr option) :
5788 env * (Tast.expr list
* Tast.expr option * locl_ty
) =
5790 TUtils.try_over_concrete_supertypes
env fty (fun env fty ->
5792 if TypecheckerOptions.method_call_inference
(Env.get_tcopt
env) then
5793 Env.expand_type
env fty
5795 Typing_solver.expand_type_and_solve
5796 ~description_of_expected
:"a function value"
5802 match deref efty
with
5803 | (r, ((Tprim Tnull
| Tdynamic
| Terr
| Tany _
| Tunion
[]) as ty))
5805 | Tprim Tnull
-> Option.is_some
nullsafe
5808 Option.value_map ~f
:(fun u
-> el @ [u
]) ~
default:el unpacked_element
5810 let expected_arg_ty =
5811 (* Note: We ought to be using 'mixed' here *)
5812 ExpectedTy.make
pos Reason.URparam
(Typing_utils.mk_tany
env pos)
5815 List.map_env
env el (fun env elt
->
5816 let (env, te, ty) = expr ~
expected:expected_arg_ty env elt
in
5818 if TCO.global_inference
(Env.get_tcopt
env) then
5819 match get_node efty
with
5823 Typing_coercion.coerce_type
5828 (MakeType.unenforced efty
)
5836 | (_
, Callconv
(Ast_defs.Pinout
, e1
)) ->
5837 let (env, _te
, _ty
) =
5838 assign_
(fst e1
) Reason.URparam_inout
env e1 efty
5846 call_untyped_unpack
env (Reason.to_pos
r) unpacked_element
5850 | Tprim Tnull
-> mk
(r, Tprim Tnull
)
5851 | Tdynamic
-> MakeType.dynamic
(Reason.Rdynamic_call
pos)
5854 Typing_utils.mk_tany
env pos
5856 | _
(* _ should not happen! *) ->
5859 (env, (tel
, None
, ty))
5860 | (_
, Tunion
[ty]) ->
5861 call ~
expected ~
nullsafe ?in_await
pos env ty el unpacked_element
5862 | (r, Tunion tyl
) ->
5864 List.map_env
env tyl
(fun env ty ->
5875 let retl = List.map resl ~f
:(fun (_
, _
, x) -> x) in
5876 let (env, ty) = Union.union_list
env r retl in
5877 (* We shouldn't be picking arbitrarily for the TAST here, as TAST checks
5878 * depend on the types inferred. Here's we're preserving legacy behaviour
5879 * by picking the last one.
5880 * TODO: don't do this, instead use subtyping to push unions
5881 * through function types
5883 let (tel
, typed_unpack_element
, _
) = List.hd_exn
(List.rev
resl) in
5884 (env, (tel
, typed_unpack_element
, ty))
5885 | (r, Tintersection tyl
) ->
5887 TUtils.run_on_intersection
env tyl ~f
:(fun env ty ->
5898 let retl = List.map resl ~f
:(fun (_
, _
, x) -> x) in
5899 let (env, ty) = Inter.intersect_list
env r retl in
5900 (* We shouldn't be picking arbitrarily for the TAST here, as TAST checks
5901 * depend on the types inferred. Here we're preserving legacy behaviour
5902 * by picking the last one.
5903 * TODO: don't do this, instead use subtyping to push intersections
5904 * through function types
5906 let (tel
, typed_unpack_element
, _
) = List.hd_exn
(List.rev
resl) in
5907 (env, (tel
, typed_unpack_element
, ty))
5909 (* Typing of format string functions. It is dependent on the arguments (el)
5910 * so it cannot be done earlier.
5912 let pos_def = Reason.to_pos r2
in
5913 let (env, ft) = Typing_exts.retype_magic_func
env ft el in
5914 let (env, var_param) = variadic_param
env ft in
5915 (* Force subtype with expected result *)
5917 check_expected_ty
"Call result" env ft.ft_ret.et_type
expected
5919 let env = Env.set_tyvar_variance
env ft.ft_ret.et_type
in
5927 let get_next_param_info paraml
=
5929 | param :: paraml
-> (false, Some
param, paraml
)
5930 | [] -> (true, var_param, paraml
)
5932 (* TODO: We're using plain String at the moment, until we
5933 * introduce actual atom notation (#A instead of "A")
5935 let expand_atom_in_enum enum_name atom_name expected_ty
=
5936 let cls = Env.get_class
env enum_name
in
5939 let constants = Cls.consts
cls in
5940 if List.Assoc.mem ~equal
:String.equal
constants atom_name
then
5941 let hi = (pos, expected_ty
) in
5942 let te = (hi, EnumAtom atom_name
) in
5943 Some
(te, expected_ty
)
5945 Errors.atom_unknown
pos atom_name enum_name
;
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 *)
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 (* Uncomment this if we want to support atoms for normal
5962 (* | Tnewtype (enum_name, _, _) when Env.is_enum env enum_name -> *)
5963 (* expand_atom_in_enum enum_name atom_name ety *)
5964 | Tclass
((_
, name), _
, [ty_enum
; _ty_interface
])
5965 when String.equal
name SN.Classes.cElt
->
5966 (match get_node ty_enum
with
5967 | Tclass
((_
, enum_name
), _
, _
)
5968 when Env.is_enum_class
env enum_name
->
5969 expand_atom_in_enum enum_name atom_name
ety
5970 | Tgeneric
(name, _
) ->
5972 Typing_utils.collect_enum_class_upper_bounds
env name
5974 (* To avoid ambiguity, we only support the case where
5975 * there is a single upper bound that is an EnumClass.
5976 * We might want to relax that later (e.g. with the
5977 * support for intersections.
5978 * See Typing_check_decls.check_atom_on_param.
5980 if SSet.cardinal
upper_bounds = 1 then
5981 let enum_name = SSet.choose
upper_bounds in
5982 expand_atom_in_enum enum_name atom_name
ety
5986 (* Already reported, see Typing_check_decls *)
5989 (* Already reported, see Typing_check_decls *)
5991 | Class_const _
when is_atom ->
5992 Errors.atom_invalid_argument
pos;
5997 match atom_type with
5998 | Some
(te, ty) -> (env, te, ty)
6001 ExpectedTy.make_and_allow_coercion
6007 ~accept_using_var
:(get_fp_accept_disposable
param)
6012 let env = call_param
env param (e, ty) ~is_variadic
in
6013 (env, Some
(te, ty))
6019 (Typing_utils.mk_tany
env pos)
6021 let (env, te, ty) = expr ~
expected env e in
6022 (env, Some
(te, ty))
6024 let set_tyvar_variance_from_lambda_param env opt_param
=
6025 match opt_param
with
6027 let rec set_params_variance env ty =
6028 let (env, ty) = Env.expand_type
env ty in
6029 match get_node
ty with
6030 | Tunion
[ty] -> set_params_variance env ty
6031 | Toption
ty -> set_params_variance env ty
6032 | Tfun
{ ft_params
; ft_ret; _
} ->
6036 ~f
:(fun env param ->
6037 Env.set_tyvar_variance
env param.fp_type
.et_type
)
6040 Env.set_tyvar_variance
env ft_ret.et_type ~flip
:true
6043 set_params_variance env param.fp_type
.et_type
6046 (* Given an expected function type ft, check types for the non-unpacked
6047 * arguments. Don't check lambda expressions if check_lambdas=false *)
6048 let rec check_args check_lambdas
env el paraml
=
6050 (* We've got an argument *)
6051 | (e, opt_result
) :: el ->
6052 (* Pick up next parameter type info *)
6053 let (is_variadic
, opt_param
, paraml
) =
6054 get_next_param_info paraml
6056 let (env, one_result
) =
6057 match (check_lambdas
, is_lambda e) with
6060 check_arg env e opt_param ~is_variadic
6063 set_tyvar_variance_from_lambda_param env opt_param
6066 | (true, false) -> (env, opt_result
)
6068 let (env, rl
, paraml
) = check_args check_lambdas
env el paraml
in
6069 (env, (e, one_result
) :: rl
, paraml
)
6070 | [] -> (env, [], paraml
)
6072 (* Same as above, but checks the types of the implicit arguments, which are
6073 * read from the context *)
6074 let check_implicit_args env =
6075 let (env, capability
) =
6076 Typing_coeffects.get_type
env ft.ft_implicit_params
.capability
6078 if not
(TypecheckerOptions.coeffects
(Env.get_tcopt
env)) then
6081 let env_capability =
6082 Env.get_local_check_defined
6084 (pos, Typing_coeffects.capability_id
)
6092 (fun ?code
:_c _subtype_error_list
->
6093 Errors.call_coeffect_error
6095 ~available_incl_unsafe
:
6096 (Typing_print.coeffects
env env_capability)
6097 ~available_pos
:(Typing_defs.get_pos
env_capability)
6098 ~required_pos
:(Typing_defs.get_pos capability
)
6099 ~required
:(Typing_print.coeffects
env capability
))
6102 (* First check the non-lambda arguments. For generic functions, this
6103 * is likely to resolve type variables to concrete types *)
6104 let rl = List.map el (fun e -> (e, None
)) in
6105 let (env, rl, _
) = check_args false env rl ft.ft_params
in
6106 (* Now check the lambda arguments, hopefully with type variables resolved *)
6107 let (env, rl, paraml
) = check_args true env rl ft.ft_params
in
6108 (* We expect to see results for all arguments after this second pass *)
6112 | None
-> failwith
"missing parameter in check_args"
6115 let l = List.map rl (fun (_
, opt
) -> get_param opt
) in
6118 let env = check_implicit_args env in
6119 let env = TR.check_call env method_call_info
pos r2
ft tys
in
6120 let (env, typed_unpack_element
, arity, did_unpack
) =
6121 match unpacked_element
with
6122 | None
-> (env, None
, List.length
el, false)
6124 (* Now that we're considering an splat (Some e) we need to construct a type that
6125 * represents the remainder of the function's parameters. `paraml` represents those
6126 * remaining parameters, and the variadic parameter is stored in `var_param`. For example, given
6128 * function f(int $i, string $j, float $k = 3.14, mixed ...$m): void {}
6129 * function g((string, float, bool) $t): void {
6133 * the constraint type we want is splat([#1], [opt#2], #3).
6135 let (consumed
, required_params
, optional_params
) =
6136 split_remaining_params_required_optional
ft paraml
6138 let (env, (d_required
, d_optional
, d_variadic
)) =
6139 generate_splat_type_vars
6146 let destructure_ty =
6149 ( Reason.Runpack_param
(fst
e, pos_def, consumed
),
6155 d_kind
= SplatUnpack
;
6158 let (env, te, ty) = expr env e in
6159 (* Populate the type variables from the expression in the splat *)
6169 (* Use the type variables for the remaining parameters *)
6175 ~f
:(fun env elt
param ->
6176 call_param
env param (e, elt
) ~is_variadic
:false)
6183 ~f
:(fun env elt
param ->
6184 call_param
env param (e, elt
) ~is_variadic
:false)
6187 Option.map2 d_variadic
var_param ~f
:(fun v vp
->
6188 call_param
env vp
(e, v
) ~is_variadic
:true)
6189 |> Option.value ~
default:env
6193 List.length
el + List.length d_required
,
6194 Option.is_some d_variadic
)
6196 (* If we unpacked an array, we don't check arity exactly. Since each
6197 * unpacked array consumes 1 or many parameters, it is nonsensical to say
6198 * that not enough args were passed in (so we don't do the min check).
6200 let () = check_arity ~did_unpack
pos pos_def ft arity in
6201 (* Variadic params cannot be inout so we can stop early *)
6202 let env = wfold_left2 inout_write_back
env ft.ft_params
el in
6204 TR.get_adjusted_return_type
env method_call_info
ft.ft_ret.et_type
6206 (env, (tel
, typed_unpack_element
, ret_ty))
6208 when TypecheckerOptions.method_call_inference
(Env.get_tcopt
env) ->
6210 Typecheck calls with unresolved function type by constructing a
6211 suitable function type from the arguments and invoking subtyping.
6213 let (env, typed_el
, type_of_el
) =
6214 exprs ~accept_using_var
:true env el
6216 let (env, typed_unpacked_element
, type_of_unpacked_element
) =
6217 match unpacked_element
with
6219 let (env, typed_unpacked
, type_of_unpacked
) =
6220 expr ~accept_using_var
:true env unpacked
6222 (env, Some typed_unpacked
, Some type_of_unpacked
)
6223 | None
-> (env, None
, None
)
6225 let mk_function_supertype
6226 env pos (type_of_el
, type_of_unpacked_element
) =
6227 let mk_fun_param ty =
6229 (* Keep supertype as permissive as possible: *)
6231 ~
mode:FPnormal
(* TODO: deal with `inout` parameters *)
6232 ~accept_disposable
:false (* TODO: deal with disposables *)
6233 ~mutability
:(Some Param_maybe_mutable
)
6242 fp_type
= MakeType.enforced ty;
6243 fp_rx_annotation
= None
;
6248 match type_of_unpacked_element
with
6249 | Some type_of_unpacked
->
6250 let fun_param = mk_fun_param type_of_unpacked
in
6254 (* TODO: ensure `ft_params`/`ft_where_constraints` don't affect subtyping *)
6255 let ft_tparams = [] in
6256 let ft_where_constraints = [] in
6257 let ft_params = List.map ~f
:mk_fun_param type_of_el
in
6258 let ft_implicit_params =
6262 (* TODO(coeffects) should this be a different type? *);
6265 let (env, return_ty
) = Env.fresh_type
env pos in
6269 | Some
r -> MakeType.awaitable
r return_ty
6271 let ft_ret = MakeType.enforced return_ty in
6272 (* A non-reactive supertype is most permissive: *)
6273 let ft_reactive = Nonreactive
in
6275 (* Keep supertype as permissive as possible: *)
6277 Ast_defs.FSync
(* `FSync` fun can still return `Awaitable<_>` *)
6278 (Some Param_maybe_mutable
)
6279 ~return_disposable
:false (* TODO: deal with disposable return *)
6280 ~returns_mutable
:false
6281 ~returns_void_to_rx
:false
6283 let ft_ifc_decl = Typing_defs_core.default_ifc_fun_decl
in
6288 ft_where_constraints;
6297 let fun_type = mk
(r, Tfun
fun_locl_type) in
6298 let env = Env.set_tyvar_variance
env fun_type in
6299 (env, fun_type, return_ty)
6301 let (env, fun_type, return_ty) =
6302 mk_function_supertype env pos (type_of_el
, type_of_unpacked_element
)
6305 Type.sub_type
pos Reason.URnone
env efty
fun_type Errors.unify_error
6307 (env, (typed_el
, typed_unpacked_element
, return_ty))
6309 bad_call
env pos efty
;
6310 let env = call_untyped_unpack
env (get_pos efty
) unpacked_element
in
6311 (env, ([], None
, err_witness env pos)))
6316 bad_call
env pos fty;
6317 let env = call_untyped_unpack
env (get_pos
fty) unpacked_element
in
6318 (env, ([], None
, err_witness env pos))
6320 and split_remaining_params_required_optional
ft remaining_params =
6321 (* Same example as above
6323 * function f(int $i, string $j, float $k = 3.14, mixed ...$m): void {}
6324 * function g((string, float, bool) $t): void {
6328 * `remaining_params` will contain [string, float] and there has been 1 parameter consumed. The min_arity
6329 * of this function is 2, so there is 1 required parameter remaining and 1 optional parameter.
6333 ~f
:(fun fp
-> not
(Typing_defs.get_fp_has_default fp
))
6336 let original_params = ft.ft_params in
6337 let consumed = List.length
original_params - List.length
remaining_params in
6338 let required_remaining = Int.max
(min_arity - consumed) 0 in
6339 let (required_params
, optional_params
) =
6340 List.split_n
remaining_params required_remaining
6342 (consumed, required_params
, optional_params
)
6344 and generate_splat_type_vars
6345 env p required_params optional_params variadic_param
=
6346 let (env, d_required
) =
6347 List.map_env
env required_params ~f
:(fun env _
-> Env.fresh_type
env p)
6349 let (env, d_optional
) =
6350 List.map_env
env optional_params ~f
:(fun env _
-> Env.fresh_type
env p)
6352 let (env, d_variadic
) =
6353 match variadic_param
with
6354 | None
-> (env, None
)
6356 let (env, ty) = Env.fresh_type
env p in
6359 (env, (d_required
, d_optional
, d_variadic
))
6361 and call_param
env param (((pos, _
) as e), arg_ty
) ~is_variadic
=
6362 param_modes ~is_variadic
param e;
6364 (* When checking params, the type 'x' may be expression dependent. Since
6365 * we store the expression id in the local env for Lvar, we want to apply
6370 | Lvar _
-> ExprDepTy.make
env (CIexpr
e) arg_ty
6371 | _
-> (env, arg_ty
)
6373 Typing_coercion.coerce_type
6381 and call_untyped_unpack
env f_pos unpacked_element
=
6382 match unpacked_element
with
6383 (* In the event that we don't have a known function call type, we can still
6384 * verify that any unpacked arguments (`...$args`) are something that can
6385 * be actually unpacked. *)
6388 let (env, _
, ety) = expr env e in
6389 let (env, ty) = Env.fresh_type
env (fst
e) in
6390 let destructure_ty =
6391 MakeType.simple_variadic_splat
(Reason.Runpack_param
(fst
e, f_pos
, 0)) ty
6401 and bad_call
env p ty = Errors.bad_call
p (Typing_print.error
env ty)
6403 and make_a_local_of
env e =
6405 | (p, Class_get
((_
, cname
), CGstring
(_
, member_name
), _
)) ->
6406 let (env, local) = Env.FakeMembers.make_static
env cname member_name
p in
6407 (env, Some
(p, local))
6410 ((((_
, This
) | (_
, Lvar _
)) as obj
), (_
, Id
(_
, member_name
)), _
, _
) )
6412 let (env, local) = Env.FakeMembers.make
env obj member_name
p in
6413 (env, Some
(p, local))
6415 | (_
, Dollardollar
x) ->
6419 (* This function captures the common bits of logic behind refinement
6420 * of the type of a local variable or a class member variable as a
6421 * result of a dynamic check (e.g., nullity check, simple type check
6422 * using functions like is_int, is_string, is_array etc.). The
6423 * argument refine is a function that takes the type of the variable
6424 * and returns a refined type (making necessary changes to the
6425 * environment, which is threaded through).
6427 * All refinement functions return, in addition to the updated
6428 * environment, a (conservative) set of all the locals that got
6429 * refined. This set is used to construct AssertEnv statmements in
6432 and refine_lvalue_type
env (((_p
, ty), _
) as te) ~refine
=
6433 let (env, ty) = refine
env ty in
6434 let e = Tast.to_nast_expr
te in
6435 let (env, localopt
) = make_a_local_of
env e in
6436 (* TODO TAST: generate an assignment to the fake local in the TAST *)
6438 | Some lid
-> (set_local
env lid
ty, Local_id.Set.singleton
(snd lid
))
6439 | None
-> (env, Local_id.Set.empty
)
6441 and condition_nullity ~nonnull
(env : env) te =
6443 (* assignment: both the rhs and lhs of the '=' must be made null/non-null *)
6444 | (_
, Aast.Binop
(Ast_defs.Eq None
, var
, te)) ->
6445 let (env, lset1
) = condition_nullity ~nonnull
env te in
6446 let (env, lset2
) = condition_nullity ~nonnull
env var
in
6447 (env, Local_id.Set.union lset1 lset2
)
6448 (* case where `Shapes::idx(...)` must be made null/non-null *)
6451 ( (_
, Aast.Class_const
((_
, Aast.CI
(_
, shapes
)), (_
, idx
))),
6455 when String.equal shapes
SN.Shapes.cShapes
&& String.equal idx
SN.Shapes.idx
6457 let field = Tast.to_nast_expr
field in
6458 let refine env shape_ty
=
6460 Typing_shapes.shapes_idx_not_null
env shape_ty
field
6464 refine_lvalue_type
env shape ~
refine
6468 Typing_solver.non_null
env p ty
6470 let r = Reason.Rwitness
(get_pos
ty) in
6471 Inter.intersect
env r ty (MakeType.null
r)
6473 refine_lvalue_type
env te ~
refine
6475 and condition_isset
env = function
6476 | (_
, Aast.Array_get
(x, _
)) -> condition_isset
env x
6477 | v
-> condition_nullity ~nonnull
:true env v
6480 * Build an environment for the true or false branch of
6481 * conditional statements.
6484 ?lhs_of_null_coalesce
env tparamet
((((p, ty) as pty
), e) as te : Tast.expr)
6486 let condition = condition ?lhs_of_null_coalesce
in
6488 | Aast.True
when not tparamet
->
6489 (LEnv.drop_cont
env C.Next
, Local_id.Set.empty
)
6490 | Aast.False
when tparamet
-> (LEnv.drop_cont
env C.Next
, Local_id.Set.empty
)
6491 | Aast.Call
((_
, Aast.Id
(_
, func
)), _
, [param], None
)
6492 when String.equal
SN.PseudoFunctions.isset func
6494 && not
(Env.is_strict
env) ->
6495 condition_isset
env param
6496 | Aast.Call
((_
, Aast.Id
(_
, func
)), _
, [te], None
)
6497 when String.equal
SN.StdlibFunctions.is_null func
->
6498 condition_nullity ~nonnull
:(not tparamet
) env te
6499 | Aast.Binop
((Ast_defs.Eqeq
| Ast_defs.Eqeqeq
), (_
, Aast.Null
), e)
6500 | Aast.Binop
((Ast_defs.Eqeq
| Ast_defs.Eqeqeq
), e, (_
, Aast.Null
)) ->
6501 condition_nullity ~nonnull
:(not tparamet
) env e
6505 | Aast.Binop
(Ast_defs.Eq None
, _
, _
) ->
6506 let (env, ety) = Env.expand_type
env ty in
6507 (match get_node
ety with
6508 | Tprim Tbool
-> (env, Local_id.Set.empty
)
6509 | _
-> condition_nullity ~nonnull
:tparamet
env te)
6510 | Aast.Binop
(((Ast_defs.Diff
| Ast_defs.Diff2
) as op
), e1
, e2) ->
6512 if Ast_defs.(equal_bop
op Diff
) then
6517 condition env (not tparamet
) (pty
, Aast.Binop
(op, e1
, e2))
6518 | Aast.Id
(_
, s) when SN.Rx.is_enabled
s ->
6519 (* when Rx\IS_ENABLED is false - switch env to non-reactive *)
6521 if not tparamet
then
6522 Env.set_env_reactive
env Nonreactive
6526 (env, Local_id.Set.empty
)
6527 (* Conjunction of conditions. Matches the two following forms:
6529 if (!(cond1 || cond2))
6531 | Aast.Binop
(((Ast_defs.Ampamp
| Ast_defs.Barbar
) as bop
), e1
, e2)
6532 when Bool.equal tparamet
Ast_defs.(equal_bop bop Ampamp
) ->
6533 let (env, lset1
) = condition env tparamet e1
in
6534 (* This is necessary in case there is an assignment in e2
6535 * We essentially redo what has been undone in the
6536 * `Binop (Ampamp|Barbar)` case of `expr` *)
6537 let (env, _
, _
) = expr env (Tast.to_nast_expr
e2) in
6538 let (env, lset2
) = condition env tparamet
e2 in
6539 (env, Local_id.Set.union lset1 lset2
)
6540 (* Disjunction of conditions. Matches the two following forms:
6542 if (!(cond1 && cond2))
6544 | Aast.Binop
(((Ast_defs.Ampamp
| Ast_defs.Barbar
) as bop
), e1
, e2)
6545 when Bool.equal tparamet
Ast_defs.(equal_bop bop Barbar
) ->
6546 let (env, lset1
, lset2
) =
6550 (* Either cond1 is true and we don't know anything about cond2... *)
6551 condition env tparamet e1
)
6553 (* ... Or cond1 is false and therefore cond2 must be true *)
6554 let (env, _lset
) = condition env (not tparamet
) e1
in
6555 (* Similarly to the conjunction case, there might be an assignment in
6556 cond2 which we must account for. Again we redo what has been undone in
6557 the `Binop (Ampamp|Barbar)` case of `expr` *)
6558 let (env, _
, _
) = expr env (Tast.to_nast_expr
e2) in
6559 condition env tparamet
e2)
6561 (env, Local_id.Set.union lset1 lset2
)
6562 | Aast.Call
(((p, _
), Aast.Id
(_
, f
)), _
, [lv
], None
)
6563 when tparamet
&& String.equal f
SN.StdlibFunctions.is_dict_or_darray
->
6564 safely_refine_is_array
env `HackDictOrDArray
p f lv
6565 | Aast.Call
(((p, _
), Aast.Id
(_
, f
)), _
, [lv
], None
)
6566 when tparamet
&& String.equal f
SN.StdlibFunctions.is_vec_or_varray
->
6567 safely_refine_is_array
env `HackVecOrVArray
p f lv
6568 | Aast.Call
(((p, _
), Aast.Id
(_
, f
)), _
, [lv
], None
)
6569 when tparamet
&& String.equal f
SN.StdlibFunctions.is_any_array
->
6570 safely_refine_is_array
env `AnyArray
p f lv
6571 | Aast.Call
(((p, _
), Aast.Id
(_
, f
)), _
, [lv
], None
)
6572 when tparamet
&& String.equal f
SN.StdlibFunctions.is_php_array
->
6573 safely_refine_is_array
env `PHPArray
p f lv
6575 ( (_
, Aast.Class_const
((_
, Aast.CI
(_
, class_name)), (_
, method_name
))),
6580 && String.equal
class_name SN.Shapes.cShapes
6581 && String.equal method_name
SN.Shapes.keyExists
->
6582 key_exists
env p shape
field
6583 | Aast.Unop
(Ast_defs.Unot
, e) -> condition env (not tparamet
) e
6584 | Aast.Is
(ivar
, h) when is_instance_var
(Tast.to_nast_expr ivar
) ->
6586 { (Phase.env_with_self
env) with from_class
= Some CIstatic
}
6588 let (env, hint_ty
) = Phase.localize_hint ~
ety_env env h in
6589 let reason = Reason.Ris
(fst
h) in
6590 let refine_type env hint_ty
=
6591 let (ivar_pos
, ivar_ty
) = fst ivar
in
6592 let (env, ivar
) = get_instance_var
env (Tast.to_nast_expr ivar
) in
6593 let (env, hint_ty
) =
6594 class_for_refinement
env p reason ivar_pos ivar_ty hint_ty
6596 let (env, refined_ty
) = Inter.intersect
env reason ivar_ty hint_ty
in
6597 (set_local
env ivar refined_ty
, Local_id.Set.singleton
(snd ivar
))
6599 let (env, hint_ty
) =
6600 if not tparamet
then
6601 Inter.non
env reason hint_ty ~approx
:TUtils.ApproxUp
6605 refine_type env hint_ty
6606 | _
-> (env, Local_id.Set.empty
)
6608 (** Transform a hint like `A<_>` to a localized type like `A<T#1>` for refinment of
6609 an instance variable. ivar_ty is the previous type of that instance variable. *)
6610 and class_for_refinement
env p reason ivar_pos ivar_ty hint_ty
=
6611 let (env, hint_ty
) = Env.expand_type
env hint_ty
in
6612 match (get_node ivar_ty
, get_node hint_ty
) with
6613 | (_
, Tclass
(((_
, cid) as _c
), _
, tyl
)) ->
6615 match Env.get_class
env cid with
6616 | Some
class_info ->
6617 let (env, tparams_with_new_names
, tyl_fresh
) =
6618 generate_fresh_tparams
env class_info reason tyl
6620 safely_refine_class_type
6628 tparams_with_new_names
6630 | None
-> (env, mk
(Reason.Rwitness ivar_pos
, Tobject
))
6632 | (Ttuple ivar_tyl
, Ttuple hint_tyl
)
6633 when Int.equal
(List.length ivar_tyl
) (List.length hint_tyl
) ->
6635 List.map2_env
env ivar_tyl hint_tyl
(fun env ivar_ty hint_ty
->
6636 class_for_refinement
env p reason ivar_pos ivar_ty hint_ty
)
6638 (env, MakeType.tuple
reason tyl
)
6639 | _
-> (env, hint_ty
)
6641 (** If we are dealing with a refinement like
6643 then class_info is the class info of MyClass and hint_tyl corresponds
6645 and generate_fresh_tparams
env class_info reason hint_tyl
=
6646 let tparams_len = List.length
(Cls.tparams
class_info) in
6647 let hint_tyl = List.take
hint_tyl tparams_len in
6648 let pad_len = tparams_len - List.length
hint_tyl in
6650 List.map hint_tyl (fun x -> Some
x) @ List.init pad_len (fun _
-> None
)
6652 let replace_wildcard env hint_ty tp
=
6654 tp_name
= (_
, tparam_name
);
6655 tp_reified
= reified
;
6662 Attributes.mem
SN.UserAttributes.uaEnforceable tp_user_attributes
6665 Attributes.mem
SN.UserAttributes.uaNewable tp_user_attributes
6670 match get_node
ty with
6671 | Tgeneric
(name, _targs
) when Env.is_fresh_generic_parameter
name ->
6672 (* TODO(T69551141) handle type arguments above and below *)
6673 (env, (Some
(tp
, name), MakeType.generic
reason name))
6674 | _
-> (env, (None
, ty))
6677 let (env, new_name
) =
6678 Env.add_fresh_generic_parameter
6685 (* TODO(T69551141) handle type arguments for Tgeneric *)
6686 (env, (Some
(tp
, new_name
), MakeType.generic
reason new_name
))
6688 let (env, tparams_and_tyl
) =
6689 List.map2_env
env hint_tyl (Cls.tparams
class_info) ~f
:replace_wildcard
6691 let (tparams_with_new_names
, tyl_fresh
) = List.unzip tparams_and_tyl
in
6692 (env, tparams_with_new_names
, tyl_fresh
)
6694 and safely_refine_class_type
6702 (tparams_with_new_names
: (decl_tparam
* string) option list
)
6704 (* Type of variable in block will be class name
6705 * with fresh type parameters *)
6707 mk
(get_reason
obj_ty, Tclass
(class_name, Nonexact
, tyl_fresh
))
6709 let tparams = Cls.tparams class_info in
6710 (* Add in constraints as assumptions on those type parameters *)
6713 type_expansions
= [];
6714 substs
= Subst.make_locl
tparams tyl_fresh
;
6716 (* In case `this` appears in constraints *)
6719 on_error
= Errors.unify_error_at
p;
6722 let add_bounds env (t
, ty_fresh
) =
6723 List.fold_left t
.tp_constraints ~
init:env ~f
:(fun env (ck
, ty) ->
6724 (* Substitute fresh type parameters for
6725 * original formals in constraint *)
6726 let (env, ty) = Phase.localize ~
ety_env env ty in
6727 SubType.add_constraint
p env ck ty_fresh
ty)
6730 List.fold_left
(List.zip_exn
tparams tyl_fresh
) ~f
:add_bounds ~
init:env
6732 (* Finally, if we have a class-test on something with static classish type,
6733 * then we can chase the hierarchy and decompose the types to deduce
6734 * further assumptions on type parameters. For example, we might have
6735 * class B<Tb> { ... }
6736 * class C extends B<int>
6737 * and have obj_ty = C and x_ty = B<T> for a generic parameter Aast.
6738 * Then SubType.add_constraint will deduce that T=int and add int as
6739 * both lower and upper bound on T in env.lenv.tpenv
6741 let (env, supertypes
) = TUtils.get_concrete_supertypes
env ivar_ty
in
6743 List.fold_left supertypes ~
init:env ~f
:(fun env ty ->
6744 SubType.add_constraint
p env Ast_defs.Constraint_as
obj_ty ty)
6746 (* It's often the case that the fresh name isn't necessary. For
6747 * example, if C<T> extends B<T>, and we have $x:B<t> for some type t
6748 * then $x is C should refine to $x:C<t>.
6749 * We take a simple approach:
6750 * For a fresh type parameter T#1, if
6751 * - There is an eqality constraint T#1 = t,
6752 * - T#1 is covariant, and T#1 has upper bound t (or mixed if absent)
6753 * - T#1 is contravariant, and T#1 has lower bound t (or nothing if absent)
6754 * then replace T#1 with t.
6755 * This is done in Type_parameter_env_ops.simplify_tpenv
6757 let (env, tparam_substs
) =
6758 Type_parameter_env_ops.simplify_tpenv
6760 (List.zip_exn tparams_with_new_names tyl_fresh
)
6764 List.map2_exn
tyl_fresh tparams_with_new_names ~f
:(fun orig_ty tparam_opt
->
6765 match tparam_opt
with
6767 | Some
(_tp
, name) -> SMap.find
name tparam_substs
)
6769 let obj_ty_simplified =
6770 mk
(get_reason
obj_ty, Tclass
(class_name, Nonexact
, tyl_fresh))
6772 (env, obj_ty_simplified)
6774 and is_instance_var
= function
6775 | (_
, (Lvar _
| This
| Dollardollar _
)) -> true
6776 | (_
, Obj_get
((_
, This
), (_
, Id _
), _
, _
)) -> true
6777 | (_
, Obj_get
((_
, Lvar _
), (_
, Id _
), _
, _
)) -> true
6778 | (_
, Class_get
(_
, _
, _
)) -> true
6781 and get_instance_var
env = function
6782 | (p, Class_get
((_
, cname
), CGstring
(_
, member_name
), _
)) ->
6783 let (env, local) = Env.FakeMembers.make_static
env cname member_name
p in
6787 ((((_
, This
) | (_
, Lvar _
)) as obj
), (_
, Id
(_
, member_name
)), _
, _
) )
6789 let (env, local) = Env.FakeMembers.make
env obj member_name
p in
6791 | (_
, Dollardollar
(p, x))
6792 | (_
, Lvar
(p, x)) ->
6794 | (p, This
) -> (env, (p, this))
6795 | _
-> failwith
"Should only be called when is_instance_var is true"
6797 (* Refine type for is_array, is_vec, is_keyset and is_dict tests
6798 * `pred_name` is the function name itself (e.g. 'is_vec')
6799 * `p` is position of the function name in the source
6800 * `arg_expr` is the argument to the function
6802 and safely_refine_is_array
env ty p pred_name arg_expr
=
6803 refine_lvalue_type
env arg_expr ~
refine:(fun env arg_ty
->
6804 let r = Reason.Rpredicated
(p, pred_name
) in
6805 let (env, tarrkey_name
) =
6806 Env.add_fresh_generic_parameter
6813 (* TODO(T69551141) handle type arguments for Tgeneric *)
6814 let tarrkey = MakeType.generic
r tarrkey_name
in
6816 SubType.add_constraint
6819 Ast_defs.Constraint_as
6821 (MakeType.arraykey r)
6823 let (env, tfresh_name
) =
6824 Env.add_fresh_generic_parameter
6831 (* TODO(T69551141) handle type arguments for Tgeneric *)
6832 let tfresh = MakeType.generic
r tfresh_name
in
6833 (* If we're refining the type for `is_array` we have a slightly more
6834 * involved process. Let's separate out that logic so we can re-use it.
6837 let safe_isarray_enabled =
6838 TypecheckerOptions.experimental_feature_enabled
6840 TypecheckerOptions.experimental_isarray
6842 let tk = MakeType.arraykey Reason.(Rvarray_or_darray_key
(to_pos
r)) in
6844 if safe_isarray_enabled then
6847 mk
(r, TUtils.tany
env)
6849 MakeType.varray_or_darray
r tk tv
6851 (* This is the refined type of e inside the branch *)
6854 | `HackDict
-> MakeType.dict
r tarrkey tfresh
6855 | `HackVec
-> MakeType.vec
r tfresh
6856 | `HackKeyset
-> MakeType.keyset
r tarrkey
6857 | `PHPArray
-> array_ty
6858 | `AnyArray
-> MakeType.any_array
r tarrkey tfresh
6859 | `HackDictOrDArray
->
6862 [MakeType.dict
r tarrkey tfresh; MakeType.darray
r tarrkey tfresh]
6863 | `HackVecOrVArray
->
6864 MakeType.union r [MakeType.vec
r tfresh; MakeType.varray
r tfresh]
6866 let ((arg_pos
, _
), _
) = arg_expr
in
6867 let (env, hint_ty) =
6868 class_for_refinement
env p r arg_pos arg_ty
hint_ty
6870 (* Add constraints on generic parameters that must
6871 * hold for refined_ty <:arg_ty. For example, if arg_ty is Traversable<T>
6872 * and refined_ty is keyset<T#1> then we know T#1 <: T.
6873 * See analogous code in safely_refine_class_type.
6875 let (env, supertypes
) = TUtils.get_concrete_supertypes
env arg_ty
in
6877 List.fold_left supertypes ~
init:env ~f
:(fun env ty ->
6878 SubType.add_constraint
p env Ast_defs.Constraint_as
hint_ty ty)
6880 Inter.intersect ~
r env hint_ty arg_ty
)
6882 and key_exists
env pos shape
field =
6883 let field = Tast.to_nast_expr
field in
6884 refine_lvalue_type
env shape ~
refine:(fun env shape_ty
->
6885 match TUtils.shape_field_name
env field with
6886 | None
-> (env, shape_ty
)
6887 | Some
field_name ->
6888 Typing_shapes.refine_shape
field_name pos env shape_ty
)
6890 and string2
env idl
=
6892 List.fold_left idl ~
init:(env, []) ~f
:(fun (env, tel
) x ->
6893 let (env, te, ty) = expr env x in
6895 let env = Typing_substring.sub_string
p env ty in
6900 and user_attribute
env ua
=
6901 let (env, typed_ua_params
) =
6902 List.map_env
env ua
.ua_params
(fun env e ->
6903 let (env, te, _
) = expr env e in
6906 (env, { Aast.ua_name
= ua
.ua_name
; Aast.ua_params
= typed_ua_params
})
6908 and file_attributes
env file_attrs
=
6909 (* Disable checking of error positions, as file attributes have spans that
6910 * aren't subspans of the class or function into which they are copied *)
6911 Errors.run_with_span
Pos.none
@@ fun () ->
6912 let uas = List.concat_map ~f
:(fun fa
-> fa
.fa_user_attributes
) file_attrs
in
6913 let env = attributes_check_def
env SN.AttributeKinds.file
uas in
6914 List.map_env
env file_attrs
(fun env fa
->
6915 let (env, user_attributes
) =
6916 List.map_env
env fa
.fa_user_attributes user_attribute
6918 let env = set_tcopt_unstable_features env fa
in
6921 Aast.fa_user_attributes
= user_attributes
;
6922 Aast.fa_namespace
= fa
.fa_namespace
;
6925 and type_param
env t
=
6927 attributes_check_def
env SN.AttributeKinds.typeparam t
.tp_user_attributes
6929 let (env, user_attributes
) =
6930 List.map_env
env t
.tp_user_attributes user_attribute
6932 let (env, tp_parameters
) = List.map_env
env t
.tp_parameters type_param
in
6935 Aast.tp_variance
= t
.tp_variance
;
6936 Aast.tp_name
= t
.tp_name
;
6938 Aast.tp_constraints
= t
.tp_constraints
;
6939 Aast.tp_reified
= reify_kind t
.tp_reified
;
6940 Aast.tp_user_attributes
= user_attributes
;
6943 and typedef_def ctx typedef
=
6944 let env = EnvFromDef.typedef_env ~origin
:Decl_counters.TopLevel ctx typedef
in
6946 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
6947 (fst typedef
.t_name
)
6952 Typing_check_decls.typedef
env typedef
;
6953 Typing_variance.typedef
env (snd typedef
.t_name
);
6956 t_name
= (t_pos
, t_name
);
6958 t_constraint
= tcstr
;
6960 t_user_attributes
= _
;
6969 let ty = Decl_hint.hint
env.decl_env hint
in
6970 (* We want to report cycles through the definition *)
6972 Phase.localize_with_self
env ~
pos:t_pos ~report_cycle
:(t_pos
, t_name
) ty
6977 let cstr = Decl_hint.hint
env.decl_env tcstr
in
6978 let (env, cstr) = Phase.localize_with_self ~
pos:t_pos
env cstr in
6981 Reason.URnewtype_cstr
6985 Errors.newtype_alias_must_satisfy_constraint
6990 | (pos, Hshape
{ nsi_allows_unknown_fields
= _
; nsi_field_map
}) ->
6991 let get_name sfi
= sfi
.sfi_name
in
6992 check_shape_keys_validity
env pos (List.map ~f
:get_name nsi_field_map
)
6996 attributes_check_def
6998 SN.AttributeKinds.typealias
6999 typedef
.t_user_attributes
7001 let (env, tparams) = List.map_env
env typedef
.t_tparams type_param
in
7002 let (env, user_attributes
) =
7003 List.map_env
env typedef
.t_user_attributes user_attribute
7006 Aast.t_annotation
= Env.save
(Env.get_tpenv
env) env;
7007 Aast.t_name
= typedef
.t_name
;
7008 Aast.t_mode
= typedef
.t_mode
;
7009 Aast.t_vis
= typedef
.t_vis
;
7010 Aast.t_user_attributes
= user_attributes
;
7011 Aast.t_constraint
= typedef
.t_constraint
;
7012 Aast.t_kind
= typedef
.t_kind
;
7013 Aast.t_tparams
= tparams;
7014 Aast.t_namespace
= typedef
.t_namespace
;
7015 Aast.t_span
= typedef
.t_span
;
7016 Aast.t_emit_id
= typedef
.t_emit_id
;
7019 (* Calls the method of a class, but allows the f callback to override the
7020 * return value type *)
7021 and overload_function
7022 make_call fpos
p env (cpos
, class_id
) method_id
el unpacked_element f
=
7023 let (env, _tal
, tcid
, ty) =
7024 static_class_id ~check_constraints
:false cpos
env [] class_id
7026 let (env, _tel
, _
) = exprs env el in
7027 let (env, (fty, tal
)) =
7031 ~coerce_from_ty
:None
7037 let (env, (tel
, typed_unpack_element
, res
)) =
7038 call ~
expected:None
p env fty el unpacked_element
7040 let (env, ty) = f
env fty res
el in
7041 let (env, fty) = Env.expand_type
env fty in
7043 map_ty
fty ~f
:(function
7044 | Tfun
ft -> Tfun
{ ft with ft_ret = MakeType.unenforced
ty }
7047 let te = Tast.make_typed_expr fpos
fty (Aast.Class_const
(tcid
, method_id
)) in
7048 make_call env te tal tel typed_unpack_element
ty
7050 and update_array_type ?lhs_of_null_coalesce
p env e1
valkind =
7053 | `lvalue_subexpr
->
7054 let (env, te1, ty1
) =
7055 raw_expr ~
valkind:`lvalue_subexpr ~check_defined
:true env e1
7059 | (_
, Lvar
(_
, x)) ->
7060 (* type_mapper has updated the type in ty1 typevars, but we
7061 need to update the local variable type too *)
7062 let env = set_valid_rvalue
p env x ty1
in
7064 | _
-> (env, te1, ty1
)
7066 | _
-> raw_expr ?lhs_of_null_coalesce
env e1
7069 let expr ?
expected env e =
7070 Typing_env.with_origin2
env Decl_counters.Body
(fun env ->
7071 expr ?
expected env e)
7074 Typing_env.with_origin
env Decl_counters.Body
(fun env -> stmt env st
)