2 * Copyright (c) 2015, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
10 (* This module implements the typing.
12 * Given an Nast.program, it infers the type of all the local
13 * variables, and checks that all the types are correct (aka
23 module TFTerm
= Typing_func_terminality
24 module TUtils
= Typing_utils
25 module Reason
= Typing_reason
26 module Type
= Typing_ops
27 module Env
= Typing_env
28 module Inf
= Typing_inference_env
29 module LEnv
= Typing_lenv
30 module Async
= Typing_async
31 module SubType
= Typing_subtype
32 module Union
= Typing_union
33 module Inter
= Typing_intersection
34 module SN
= Naming_special_names
35 module TVis
= Typing_visibility
36 module Phase
= Typing_phase
37 module TOG
= Typing_object_get
38 module Subst
= Decl_subst
39 module ExprDepTy
= Typing_dependent_type.ExprDepTy
40 module TCO
= TypecheckerOptions
41 module EnvFromDef
= Typing_env_from_def
42 module C
= Typing_continuations
44 module Try
= Typing_try
45 module FL
= FeatureLogging
46 module MakeType
= Typing_make_type
47 module Cls
= Decl_provider.Class
48 module Partial
= Partial_provider
49 module Fake
= Typing_fake_members
50 module ExpectedTy
= Typing_helpers.ExpectedTy
52 type newable_class_info
=
56 * [ `Class
of sid
* Cls.t
* locl_ty
| `Dynamic
] list
58 (*****************************************************************************)
60 (*****************************************************************************)
62 (* A guess as to the last position we were typechecking, for use in debugging,
63 * such as figuring out what a runaway hh_server thread is doing. Updated
64 * only best-effort -- it's an approximation to point debugging in the right
65 * direction, nothing more. *)
66 let debug_last_pos = ref Pos.none
68 let debug_print_last_pos _
=
70 "Last typecheck pos: %s"
71 (Pos.string (Pos.to_absolute
!debug_last_pos))
73 (*****************************************************************************)
75 (*****************************************************************************)
77 let err_witness env p
= TUtils.terr env
(Reason.Rwitness p
)
79 let triple_to_pair (env
, te
, ty
) = (env
, (te
, ty
))
81 let with_special_coeffects env cap_ty unsafe_cap_ty f
=
83 Option.map
(Env.next_cont_opt env
) ~f
:(fun next_cont
->
84 let initial_locals = next_cont
.Typing_per_cont_env.local_types
in
85 let tpenv = Env.get_tpenv env
in
86 (initial_locals, tpenv))
88 Typing_lenv.stash_and_do env
(Env.all_continuations env
) (fun env
->
92 | Some
(initial_locals, tpenv) ->
93 let env = Env.reinitialize_locals
env in
94 let env = Env.set_locals
env initial_locals in
95 let env = Env.env_with_tpenv
env tpenv in
99 Typing_coeffects.register_capabilities
env cap_ty unsafe_cap_ty
103 (* Set all the types in an expression to the given type. *)
104 let with_type ty
env (e
: Nast.expr
) : Tast.expr
=
109 method on_'ex _ p
= (p
, ty
)
111 method on_'fb _ _
= ()
113 method on_'en _ _
= env
115 method on_'hi _ _
= ty
120 let expr_error env (r
: Reason.t
) (e
: Nast.expr
) =
121 let ty = TUtils.terr
env r
in
122 (env, with_type ty Tast.dummy_saved_env e
, ty)
124 let expr_any env p e
=
125 let ty = Typing_utils.mk_tany
env p
in
126 (env, with_type ty Tast.dummy_saved_env e
, ty)
128 let unbound_name env (pos
, name
) e
=
129 let strictish = Partial.should_check_error
(Env.get_mode
env) 4107 in
130 match Env.get_mode
env with
131 | FileInfo.Mstrict
->
132 Errors.unbound_name_typing pos name
;
133 expr_error env (Reason.Rwitness pos
) e
134 | FileInfo.Mpartial
when strictish ->
135 Errors.unbound_name_typing pos name
;
136 expr_error env (Reason.Rwitness pos
) e
138 | FileInfo.Mpartial
->
141 (* Is this type Traversable<vty> or Container<vty> for some vty? *)
142 let get_value_collection_inst ty =
143 match get_node
ty with
144 | Tclass
((_
, c
), _
, [vty
])
145 when String.equal c
SN.Collections.cTraversable
146 || String.equal c
SN.Collections.cContainer
->
148 (* If we're expecting a mixed or a nonnull then we can just assume
149 * that the element type is mixed *)
150 | Tnonnull
-> Some
(MakeType.mixed
Reason.Rnone
)
154 (* Is this type KeyedTraversable<kty,vty>
155 * or KeyedContainer<kty,vty>
158 let get_key_value_collection_inst p
ty =
159 match get_node
ty with
160 | Tclass
((_
, c
), _
, [kty
; vty
])
161 when String.equal c
SN.Collections.cKeyedTraversable
162 || String.equal c
SN.Collections.cKeyedContainer
->
164 (* If we're expecting a mixed or a nonnull then we can just assume
165 * that the key type is arraykey and the value type is mixed *)
167 let arraykey = MakeType.arraykey (Reason.Rkey_value_collection_key p
) in
168 let mixed = MakeType.mixed Reason.Rnone
in
169 Some
(arraykey, mixed)
170 | Tany _
-> Some
(ty, ty)
173 (* Is this type varray<vty> or a supertype for some vty? *)
174 let get_varray_inst ty =
175 match get_node
ty with
176 (* It's varray<vty> *)
177 | Tvarray vty
-> Some vty
178 | _
-> get_value_collection_inst ty
180 (* Is this type one of the value collection types with element type vty? *)
181 let get_vc_inst vc_kind
ty =
182 match get_node
ty with
183 | Tclass
((_
, c
), _
, [vty
]) when String.equal c
(Nast.vc_kind_to_name vc_kind
)
186 | _
-> get_value_collection_inst ty
188 (* Is this type one of the three key-value collection types
189 * e.g. dict<kty,vty> or a supertype for some kty and vty? *)
190 let get_kvc_inst p kvc_kind
ty =
191 match get_node
ty with
192 | Tclass
((_
, c
), _
, [kty
; vty
])
193 when String.equal c
(Nast.kvc_kind_to_name kvc_kind
) ->
195 | _
-> get_key_value_collection_inst p
ty
197 (* Is this type darray<kty, vty> or a supertype for some kty and vty? *)
198 let get_darray_inst p
ty =
199 match get_node
ty with
200 (* It's darray<kty, vty> *)
201 | Tdarray
(kty
, vty
) -> Some
(kty
, vty
)
202 | _
-> get_key_value_collection_inst p
ty
204 (* Check whether this is a function type that (a) either returns a disposable
205 * or (b) has the <<__ReturnDisposable>> attribute
207 let is_return_disposable_fun_type env ty =
208 let (_env
, ty) = Env.expand_type
env ty in
209 match get_node
ty with
211 get_ft_return_disposable ft
213 (Typing_disposable.is_disposable_type
env ft
.ft_ret
.et_type
)
216 (* Turn an environment into a local_id_map suitable to be embedded
217 * into an AssertEnv statement
220 match Env.next_cont_opt
env with
221 | Some
{ Typing_per_cont_env.local_types
; _
} ->
222 Some
(Local_id.Map.map
(fun (ty, pos
, _expr_id
) -> (pos
, ty)) local_types
)
225 (* Similar to annot_map above, but filters the map to only contain
226 * information about locals in lset
228 let refinement_annot_map env lset
=
229 match annot_map env with
232 Local_id.Map.filter
(fun lid _
-> Local_id.Set.mem lid lset
) map
234 if Local_id.Map.is_empty
map then
240 let assert_env_blk ~pos ~at annotation_kind env_map_opt blk
=
241 let mk_assert map = (pos
, Aast.AssertEnv
(annotation_kind
, map)) in
242 let annot_blk = Option.to_list
(Option.map ~f
:mk_assert env_map_opt
) in
244 | `Start
-> annot_blk @ blk
245 | `End
-> blk
@ annot_blk
247 let assert_env_stmt ~pos ~at annotation_kind env_map_opt stmt
=
248 let mk_assert map = (pos
, Aast.AssertEnv
(annotation_kind
, map)) in
249 match env_map_opt
with
251 let stmt = (pos
, stmt) in
254 | `Start
-> [mk_assert env_map
; stmt]
255 | `End
-> [stmt; mk_assert env_map
]
260 let set_tcopt_unstable_features env { fa_user_attributes
; _
} =
262 Naming_attributes.find
263 SN.UserAttributes.uaEnableUnstableFeatures
267 | Some
{ ua_name
= _
; ua_params
} ->
268 let ( = ) = String.equal
in
269 List.fold ua_params ~
init:env ~f
:(fun env feature
->
270 match snd feature
with
271 | Aast.String s
when s
= SN.UnstableFeatures.ifc
->
272 Env.map_tcopt ~f
:TypecheckerOptions.enable_ifc
env
273 | Aast.String s
when s
= SN.UnstableFeatures.readonly
->
274 Env.map_tcopt ~f
:(fun t
-> TypecheckerOptions.set_readonly t
true) env
275 | Aast.String s
when s
= SN.UnstableFeatures.expression_trees
->
278 TypecheckerOptions.set_tco_enable_expression_trees t
true)
282 (* Given a localized parameter type and parameter information, infer
283 * a type for the parameter default expression (if present) and check that
284 * it is a subtype of the parameter type (if present). If no parameter type
285 * is specified, then union with Tany. (So it's as though we did a conditional
286 * assignment of the default expression to the parameter).
287 * Set the type of the parameter in the locals environment *)
288 let rec bind_param env ?
(immutable
= false) (ty1
, param
) =
289 let (env, param_te
, ty1
) =
290 match param
.param_expr
with
291 | None
-> (env, None
, ty1
)
295 ~f
:(Decl_hint.hint
env.decl_env
)
296 (hint_of_type_hint param
.param_type_hint
)
301 | Some
ty -> Typing_enforceability.get_enforcement
env ty
303 let ty1_enforced = { et_type
= ty1
; et_enforced
= enforced } in
305 ExpectedTy.make_and_allow_coercion_opt
311 let (env, (te
, ty2
)) =
312 let r = Reason.Rwitness_from_decl param
.param_pos
in
313 let pure = MakeType.mixed r in
317 (* Accessing statics for default arguments is allowed *)
318 (param
.param_pos
, SN.Capabilities.accessStaticVariable
)
320 |> Phase.localize_with_self
env ~ignore_errors
:false
322 with_special_coeffects env cap
pure @@ fun env ->
323 expr ?
expected env e ~allow_awaitable
:(*?*) false |> triple_to_pair
325 Typing_sequencing.sequence_check_expr e
;
328 Option.is_none
(hint_of_type_hint param
.param_type_hint
)
329 && (not
@@ TCO.global_inference
(Env.get_tcopt
env))
330 (* ty1 will be Tany iff we have no type hint and we are not in
331 * 'infer missing mode'. When it ty1 is Tany we just union it with
332 * the type of the default expression *)
334 Union.union
env ty1 ty2
335 (* Otherwise we have an explicit type, and the default expression type
336 * must be a subtype *)
339 Typing_coercion.coerce_type
345 Errors.parameter_default_value_wrong_type
351 let (env, user_attributes
) =
352 List.map_env
env param
.param_user_attributes user_attribute
356 Aast.param_annotation
= Tast.make_expr_annotation param
.param_pos ty1
;
357 Aast.param_type_hint
= (ty1
, hint_of_type_hint param
.param_type_hint
);
358 Aast.param_is_variadic
= param
.param_is_variadic
;
359 Aast.param_pos
= param
.param_pos
;
360 Aast.param_name
= param
.param_name
;
361 Aast.param_expr
= param_te
;
362 Aast.param_callconv
= param
.param_callconv
;
363 Aast.param_readonly
= param
.param_readonly
;
364 Aast.param_user_attributes
= user_attributes
;
365 Aast.param_visibility
= param
.param_visibility
;
368 let mode = get_param_mode param
.param_callconv
in
369 let id = Local_id.make_unscoped param
.param_name
in
370 let env = Env.set_local ~immutable
env id ty1 param
.param_pos
in
371 let env = Env.set_param
env id (ty1
, param
.param_pos
, mode) in
373 if has_accept_disposable_attribute param
then
374 Env.set_using_var
env id
380 and check_inout_return ret_pos
env =
381 let params = Local_id.Map.elements
(Env.get_params
env) in
382 List.fold
params ~
init:env ~f
:(fun env (id, (ty, param_pos
, mode)) ->
385 (* Whenever the function exits normally, we require that each local
386 * corresponding to an inout parameter be compatible with the original
387 * type for the parameter (under subtyping rules). *)
388 let (local_ty
, local_pos
) = Env.get_local_pos
env id in
389 let (env, ety
) = Env.expand_type
env local_ty
in
391 if not
(Pos.equal
Pos.none local_pos
) then
393 else if not
(Pos.equal
Pos.none ret_pos
) then
398 let param_ty = mk
(Reason.Rinout_param
(get_pos
ty), get_node
ty) in
401 Reason.URassign_inout
405 Errors.inout_return_type_mismatch
408 (*****************************************************************************)
409 (* function used to type closures, functions and methods *)
410 (*****************************************************************************)
411 and fun_ ?
(abstract
= false) ?
(disable
= false) env return
pos named_body f_kind
413 Env.with_env
env (fun env ->
414 debug_last_pos := pos;
415 let env = Env.set_return
env return
in
419 Errors.internal_error
421 ( "Type inference for this function has been disabled by the "
422 ^
SN.UserAttributes.uaDisableTypecheckerInternal
427 block
env named_body
.fb_ast
429 Typing_sequencing.sequence_check_block named_body
.fb_ast
;
430 let { Typing_env_return_info.return_type
= ret
; _
} =
433 let has_implicit_return = LEnv.has_next
env in
434 let named_body_is_unsafe = Nast.named_body_is_unsafe named_body
in
436 if (not
has_implicit_return) || abstract
|| named_body_is_unsafe then
439 fun_implicit_return
env pos ret
.et_type f_kind
442 Typing_env.set_fun_tast_info
444 { Tast.has_implicit_return; Tast.named_body_is_unsafe }
446 debug_last_pos := Pos.none
;
449 and fun_implicit_return
env pos ret
= function
450 | Ast_defs.FGenerator
451 | Ast_defs.FAsyncGenerator
->
454 (* A function without a terminal block has an implicit return; the
456 let env = check_inout_return
Pos.none
env in
457 let r = Reason.Rno_return
pos in
458 let rty = MakeType.void
r in
459 Typing_return.implicit_return
env pos ~
expected:ret ~actual
:rty
461 (* An async function without a terminal block has an implicit return;
462 * the Awaitable<void> type *)
463 let r = Reason.Rno_return_async
pos in
464 let rty = MakeType.awaitable
r (MakeType.void
r) in
465 Typing_return.implicit_return
env pos ~
expected:ret ~actual
:rty
468 Typing_env.with_origin
env Decl_counters.Body
@@ fun env ->
469 (* To insert an `AssertEnv`, `stmt` might return a `Block`. We eliminate it here
470 to keep ASTs `Block`-free. *)
472 List.fold ~
init:(env, []) stl ~f
:(fun (env, stl
) st
->
473 let (env, st
) = stmt env st
in
474 (* Accumulate statements in reverse order *)
477 | (_
, Aast.Block
stl'
) -> List.rev
stl'
@ stl
484 (* Set a local; must not be already assigned if it is a using variable *)
485 and set_local ?
(is_using_clause
= false) env (pos, x
) ty =
486 if Env.is_using_var
env x
then
487 if is_using_clause
then
488 Errors.duplicate_using_var
pos
490 Errors.illegal_disposable
pos "assigned";
491 let env = Env.set_local
env x
ty pos in
492 if is_using_clause
then
493 Env.set_using_var
env x
497 (* Ensure that `ty` is a subtype of IDisposable (for `using`) or
498 * IAsyncDisposable (for `await using`)
500 and has_dispose_method
env has_await p e
ty =
503 SN.Members.__disposeAsync
507 let (env, (tfty
, _tal
)) =
517 ~on_error
:(Errors.using_error p has_await
)
521 let (env, (_tel
, _typed_unpack_element
, _ty
)) =
522 call ~
expected:None p
env tfty
[] None
526 (* Check an individual component in the expression `e` in the
527 * `using (e) { ... }` statement.
528 * This consists of either
529 * a simple assignment `$x = e`, in which `$x` is the using variable, or
530 * an arbitrary expression `e`, in which case a temporary is the using
531 * variable, inaccessible in the source.
532 * Return the typed expression and its type, and any variables that must
533 * be designated as "using variables" for avoiding escapes.
535 and check_using_expr has_await
env ((pos, content
) as using_clause
) =
537 (* Simple assignment to local of form `$lvar = e` *)
538 | Binop
(Ast_defs.Eq None
, (lvar_pos
, Lvar lvar
), e
) ->
540 expr ~is_using_clause
:true env e ~allow_awaitable
:(*?*) false
542 let env = has_dispose_method
env has_await
pos e
ty in
543 let env = set_local ~is_using_clause
:true env lvar
ty in
544 (* We are assigning a new value to the local variable, so we need to
545 * generate a new expression id
547 let env = Env.set_local_expr_id
env (snd lvar
) (Ident.tmp
()) in
549 ( Tast.make_typed_expr
554 Tast.make_typed_expr lvar_pos
ty (Aast.Lvar lvar
),
557 (* Arbitrary expression. This will be assigned to a temporary *)
559 let (env, typed_using_clause
, ty) =
560 expr ~is_using_clause
:true env using_clause ~allow_awaitable
:(*?*) false
562 let env = has_dispose_method
env has_await
pos using_clause
ty in
563 (env, (typed_using_clause
, []))
565 (* Check the using clause e in
566 * `using (e) { ... }` statement (`has_await = false`) or
567 * `await using (e) { ... }` statement (`has_await = true`).
568 * `using_clauses` is a list of expressions.
569 * Return the typed expression, and any variables that must
570 * be designated as "using variables" for avoiding escapes.
572 and check_using_clause
env has_await using_clauses
=
574 List.map_env
env using_clauses
(check_using_expr has_await
)
576 let (typed_using_clauses
, vars
) = List.unzip pairs
in
577 (env, typed_using_clauses
, List.concat vars
)
579 (* Require a new construct with disposable *)
580 and enforce_return_disposable _env e
=
584 | (_
, Await
(_
, Call _
)) -> ()
585 | (p
, _
) -> Errors.invalid_return_disposable p
587 (* Wrappers around the function with the same name in Typing_lenv, which only
588 * performs the move/save and merge operation if we are in a try block or in a
589 * function with return type 'noreturn'.
590 * This enables significant perf improvement, because this is called at every
591 * function of method call, when most calls are outside of a try block. *)
592 and move_and_merge_next_in_catch
env =
593 if env.in_try
|| TFTerm.is_noreturn
env then
594 LEnv.move_and_merge_next_in_cont
env C.Catch
596 LEnv.drop_cont
env C.Next
598 and save_and_merge_next_in_catch
env =
599 if env.in_try
|| TFTerm.is_noreturn
env then
600 LEnv.save_and_merge_next_in_cont
env C.Catch
604 and might_throw
env = save_and_merge_next_in_catch
env
606 and stmt env (pos, st
) =
607 let (env, st
) = stmt_
env pos st
in
608 Typing_debug.log_env_if_too_big
pos env;
611 and stmt_
env pos st
=
612 let expr ?
(allow_awaitable
= (*?*) false) = expr ~allow_awaitable
in
613 let exprs = exprs ~allow_awaitable
:(*?*) false in
614 (* Type check a loop. f env = (env, result) checks the body of the loop.
615 * We iterate over the loop until the "next" continuation environment is
616 * stable. alias_depth is supposed to be an upper bound on this; but in
617 * certain cases this fails (e.g. a generic type grows unboundedly). TODO:
620 let infer_loop env f
=
621 let in_loop_outer = env.in_loop
in
623 if in_loop_outer then
626 Typing_alias.get_depth
(pos, st
)
628 let env = { env with in_loop
= true } in
630 (* Remember the old environment *)
631 let old_next_entry = Env.next_cont_opt
env in
632 let (env, result
) = f
env in
633 let new_next_entry = Env.next_cont_opt
env in
634 (* Finish if we reach the bound, or if the environments match *)
636 Int.equal n
alias_depth
637 || Typing_per_cont_ops.is_sub_opt_entry
638 Typing_subtype.is_sub_type
643 let env = { env with in_loop
= in_loop_outer } in
650 let env = Env.open_tyvars
env pos in
652 (Typing_solver.close_tyvars_and_solve
env Errors.unify_error
, tb
))
658 LEnv.move_and_merge_next_in_cont
env C.Fallthrough
662 (env, Aast.Fallthrough
)
663 | Noop
-> (env, Aast.Noop
)
664 | AssertEnv _
-> (env, Aast.Noop
)
666 let env = LEnv.move_and_merge_next_in_cont
env C.Exit
in
667 (env, Aast.Yield_break
)
669 let (env, te
, _
) = expr env e
in
671 if TFTerm.typed_expression_exits te
then
672 LEnv.move_and_merge_next_in_cont
env C.Exit
678 let assert_refinement_env =
679 assert_env_blk ~
pos ~at
:`Start
Aast.Refinement
681 let (env, te
, _
) = expr env e
in
682 let (env, tb1
, tb2
) =
686 let (env, lset
) = condition
env true te
in
687 let refinement_map = refinement_annot_map env lset
in
688 let (env, b1
) = block
env b1
in
689 let b1 = assert_refinement_env refinement_map b1 in
692 let (env, lset
) = condition
env false te
in
693 let refinement_map = refinement_annot_map env lset
in
694 let (env, b2
) = block
env b2
in
695 let b2 = assert_refinement_env refinement_map b2 in
698 (* TODO TAST: annotate with joined types *)
699 (env, Aast.If
(te
, tb1
, tb2
))
701 let env = check_inout_return
pos env in
702 let rty = MakeType.void
(Reason.Rwitness
pos) in
703 let { Typing_env_return_info.return_type
= expected_return
; _
} =
706 let expected_return =
707 Typing_return.strip_awaitable
(Env.get_fn_kind
env) env expected_return
710 match Env.get_fn_kind
env with
711 | Ast_defs.FGenerator
712 | Ast_defs.FAsyncGenerator
->
715 Typing_return.implicit_return
718 ~
expected:expected_return.et_type
721 let env = LEnv.move_and_merge_next_in_cont
env C.Exit
in
722 (env, Aast.Return None
)
724 let env = check_inout_return
pos env in
725 let expr_pos = fst e
in
726 let Typing_env_return_info.
731 return_dynamically_callable
= _
;
736 Typing_return.strip_awaitable
(Env.get_fn_kind
env) env return_type
739 if return_explicit
then
741 (ExpectedTy.make_and_allow_coercion
748 if return_disposable
then enforce_return_disposable
env e
;
750 expr ~is_using_clause
:return_disposable ?
expected env e
752 (* This is a unify_error rather than a return_type_mismatch because the return
753 * statement is the problem, not the return type itself. *)
755 Typing_coercion.coerce_type
763 let env = LEnv.move_and_merge_next_in_cont
env C.Exit
in
764 (env, Aast.Return
(Some te
))
766 (* NOTE: leaks scope as currently implemented; this matches
767 the behavior in naming (cf. `do_stmt` in naming/naming.ml).
769 let (env, (tb
, te
)) =
770 LEnv.stash_and_do
env [C.Continue
; C.Break
; C.Do
] (fun env ->
771 let env = LEnv.save_and_merge_next_in_cont
env C.Do
in
772 let (env, _
) = block
env b
in
773 (* saving the locals in continue here even if there is no continue
774 * statement because they must be merged at the end of the loop, in
775 * case there is no iteration *)
776 let env = LEnv.save_and_merge_next_in_cont
env C.Continue
in
778 infer_loop env (fun env ->
780 LEnv.update_next_from_conts
env [C.Continue
; C.Next
]
782 (* The following is necessary in case there is an assignment in the
784 let (env, te
, _
) = expr env e
in
785 let (env, _lset
) = condition
env true te
in
786 let env = LEnv.update_next_from_conts
env [C.Do
; C.Next
] in
787 let (env, tb
) = block
env b
in
790 let env = LEnv.update_next_from_conts
env [C.Continue
; C.Next
] in
791 let (env, te
, _
) = expr env e
in
792 let (env, _lset
) = condition
env false te
in
793 let env = LEnv.update_next_from_conts
env [C.Break
; C.Next
] in
796 (env, Aast.Do
(tb
, te
))
798 let (env, (te
, tb
, refinement_map)) =
799 LEnv.stash_and_do
env [C.Continue
; C.Break
] (fun env ->
800 let env = LEnv.save_and_merge_next_in_cont
env C.Continue
in
802 infer_loop env (fun env ->
804 LEnv.update_next_from_conts
env [C.Continue
; C.Next
]
806 let join_map = annot_map env in
807 (* The following is necessary in case there is an assignment in the
809 let (env, te
, _
) = expr env e
in
810 let (env, lset
) = condition
env true te
in
811 let refinement_map = refinement_annot_map env lset
in
812 (* TODO TAST: avoid repeated generation of block *)
813 let (env, tb
) = block
env b
in
815 (* Annotate loop body with join and refined environments *)
816 let assert_env_blk = assert_env_blk ~
pos ~at
:`Start
in
817 let tb = assert_env_blk Aast.Refinement
refinement_map tb in
818 let tb = assert_env_blk Aast.Join
join_map tb in
822 let env = LEnv.update_next_from_conts
env [C.Continue
; C.Next
] in
823 let (env, te
, _
) = expr env e
in
824 let (env, lset
) = condition
env false te
in
825 let refinement_map_at_exit = refinement_annot_map env lset
in
826 let env = LEnv.update_next_from_conts
env [C.Break
; C.Next
] in
827 (env, (te
, tb, refinement_map_at_exit)))
829 let while_st = Aast.While
(te
, tb) in
830 (* Export the refined environment after the exit condition holds *)
832 assert_env_stmt ~
pos ~at
:`End
Aast.Refinement
refinement_map while_st
837 us_has_await
= has_await
;
838 us_exprs
= (loc
, using_clause
);
839 us_block
= using_block
;
842 let (env, typed_using_clause
, using_vars
) =
843 check_using_clause
env has_await using_clause
845 let (env, typed_using_block
) = block
env using_block
in
846 (* Remove any using variables from the environment, as they should not
847 * be in scope outside the block *)
848 let env = List.fold_left using_vars ~
init:env ~f
:Env.unset_local
in
853 us_has_await
= has_await
;
854 us_exprs
= (loc
, typed_using_clause
);
855 us_block
= typed_using_block
;
858 | For
(e1
, e2
, e3
, b
) ->
862 | None
-> (Pos.none
, True
)
864 let (env, (te1
, te2
, te3
, tb, refinement_map)) =
865 LEnv.stash_and_do
env [C.Continue
; C.Break
] (fun env ->
866 (* For loops leak their initalizer, but nothing that's defined in the
869 let (env, te1
, _
) = exprs env e1
in
871 let env = LEnv.save_and_merge_next_in_cont
env C.Continue
in
872 let (env, (tb, te3
)) =
873 infer_loop env (fun env ->
874 (* The following is necessary in case there is an assignment in the
876 let (env, te2
, _
) = expr env e2 in
877 let (env, lset
) = condition
env true te2
in
878 let refinement_map = refinement_annot_map env lset
in
879 let (env, tb) = block
env b
in
881 LEnv.update_next_from_conts
env [C.Continue
; C.Next
]
883 let join_map = annot_map env in
884 let (env, te3
, _
) = exprs env e3
in
886 (* Export the join and refinement environments *)
887 let assert_env_blk = assert_env_blk ~
pos ~at
:`Start
in
888 let tb = assert_env_blk Aast.Refinement
refinement_map tb in
889 let tb = assert_env_blk Aast.Join
join_map tb in
893 let env = LEnv.update_next_from_conts
env [C.Continue
; C.Next
] in
894 let (env, te2
, _
) = expr env e2 in
895 let (env, lset
) = condition
env false te2
in
896 let refinement_map_at_exit = refinement_annot_map env lset
in
897 let env = LEnv.update_next_from_conts
env [C.Break
; C.Next
] in
898 (env, (te1
, te2
, te3
, tb, refinement_map_at_exit)))
900 let for_st = Aast.For
(te1
, Some te2
, te3
, tb) in
902 assert_env_stmt ~
pos ~at
:`End
Aast.Refinement
refinement_map for_st
905 | Switch
(((pos, _
) as e
), cl
) ->
906 let (env, te
, ty) = expr env e
in
907 (* NB: A 'continue' inside a 'switch' block is equivalent to a 'break'.
909 * http://php.net/manual/en/control-structures.continue.php *)
910 let (env, (te
, tcl
)) =
911 LEnv.stash_and_do
env [C.Continue
; C.Break
] (fun env ->
912 let parent_locals = LEnv.get_all_locals
env in
913 let case_list env = case_list parent_locals ty env pos cl
in
914 let (env, tcl
) = Env.in_case
env case_list in
916 LEnv.update_next_from_conts
env [C.Continue
; C.Break
; C.Next
]
920 (env, Aast.Switch
(te
, tcl
))
921 | Foreach
(e1
, e2, b
) ->
922 (* It's safe to do foreach over a disposable, as no leaking is possible *)
923 let (env, te1
, ty1
) = expr ~accept_using_var
:true env e1
in
924 let (env, (te1
, te2
, tb)) =
925 LEnv.stash_and_do
env [C.Continue
; C.Break
] (fun env ->
926 let env = LEnv.save_and_merge_next_in_cont
env C.Continue
in
927 let (env, tk
, tv
) = as_expr
env ty1
(fst e1
) e2 in
928 let (env, (te2
, tb)) =
929 infer_loop env (fun env ->
931 LEnv.update_next_from_conts
env [C.Continue
; C.Next
]
933 let join_map = annot_map env in
934 let (env, te2
) = bind_as_expr
env (fst e1
) tk tv
e2 in
935 let (env, tb) = block
env b
in
936 (* Export the join environment *)
937 let tb = assert_env_blk ~
pos ~at
:`Start
Aast.Join
join_map tb in
941 LEnv.update_next_from_conts
env [C.Continue
; C.Break
; C.Next
]
943 (env, (te1
, te2
, tb)))
945 (env, Aast.Foreach
(te1
, te2
, tb))
946 | Try
(tb, cl
, fb
) ->
947 let (env, ttb
, tcl
, tfb
) = try_catch
env tb cl fb
in
948 (env, Aast.Try
(ttb
, tcl
, tfb
))
949 | Awaitall
(el
, b
) ->
950 let env = might_throw
env in
952 List.fold_left el ~
init:(env, []) ~f
:(fun (env, tel
) (e1
, e2) ->
953 let (env, te2
, ty2
) = expr env e2 ~allow_awaitable
:true in
955 Async.overload_extract_from_awaitable
env (fst
e2) ty2
959 let (env, _
, _
) = assign
(fst e1
) env (fst e1
, Lvar e1
) ty2
in
960 (env, (Some e1
, te2
) :: tel
)
961 | None
-> (env, (None
, te2
) :: tel
))
963 let (env, b
) = block
env b
in
964 (env, Aast.Awaitall
(el
, b
))
967 let (env, te
, ty) = expr env e
in
968 let env = coerce_to_throwable
p env ty in
969 let env = move_and_merge_next_in_catch
env in
972 let env = LEnv.move_and_merge_next_in_cont
env C.Continue
in
975 let env = LEnv.move_and_merge_next_in_cont
env C.Break
in
980 "Unexpected nodes in AST. These nodes should have been removed in naming."
983 type res
. env -> (env -> env * res
) -> (env -> env * res
) -> env * res
* res
985 fun env branch1 branch2
->
986 let parent_lenv = env.lenv
in
987 let (env, tbr1
) = branch1
env in
988 let lenv1 = env.lenv
in
989 let env = { env with lenv
= parent_lenv } in
990 let (env, tbr2
) = branch2
env in
991 let lenv2 = env.lenv
in
992 let env = LEnv.union_lenvs
env parent_lenv lenv1 lenv2 in
995 and finally_cont fb
env ctx
=
996 (* The only locals in scope are the ones from the current continuation *)
997 let env = Env.env_with_locals
env @@ CMap.singleton
C.Next ctx
in
998 let (env, _tfb
) = block
env fb
in
999 (env, LEnv.get_all_locals
env)
1001 and finally
env fb
=
1004 let env = LEnv.update_next_from_conts
env [C.Next
; C.Finally
] in
1007 let parent_locals = LEnv.get_all_locals
env in
1008 (* First typecheck the finally block against all continuations merged
1010 * During this phase, record errors found in the finally block, but discard
1011 * the resulting environment. *)
1012 let all_conts = Env.all_continuations
env in
1013 let env = LEnv.update_next_from_conts
env all_conts in
1014 let (env, tfb
) = block
env fb
in
1015 let env = LEnv.restore_conts_from
env parent_locals all_conts in
1016 (* Second, typecheck the finally block once against each continuation. This
1017 * helps be more clever about what each continuation will be after the
1019 * We don't want to record errors during this phase, because certain types
1020 * of errors will fire wrongly. For example, if $x is nullable in some
1021 * continuations but not in others, then we must use `?->` on $x, but an
1022 * error will fire when typechecking the finally block againts continuations
1023 * where $x is non-null. *)
1024 let finally_cont env _key
= finally_cont fb
env in
1025 let (env, locals_map
) =
1026 Errors.ignore_
(fun () -> CMap.map_env
finally_cont env parent_locals)
1028 let union env _key
= LEnv.union_contextopts
env in
1029 let (env, locals
) = Try.finally_merge
union env locals_map
all_conts in
1030 (Env.env_with_locals
env locals
, tfb
)
1032 and try_catch
env tb cl fb
=
1033 let parent_locals = LEnv.get_all_locals
env in
1035 LEnv.drop_conts
env [C.Break
; C.Continue
; C.Exit
; C.Catch
; C.Finally
]
1037 let (env, (ttb
, tcb
)) =
1038 Env.in_try
env (fun env ->
1039 let (env, ttb
) = block
env tb in
1040 let env = LEnv.move_and_merge_next_in_cont
env C.Finally
in
1041 let catchctx = LEnv.get_cont_option
env C.Catch
in
1042 let (env, lenvtcblist
) = List.map_env
env ~f
:(catch
catchctx) cl
in
1043 let (lenvl
, tcb
) = List.unzip lenvtcblist
in
1044 let env = LEnv.union_lenv_list
env env.lenv lenvl
in
1045 let env = LEnv.move_and_merge_next_in_cont
env C.Finally
in
1048 let (env, tfb
) = finally
env fb
in
1049 let env = LEnv.update_next_from_conts
env [C.Finally
] in
1050 let env = LEnv.drop_cont
env C.Finally
in
1052 LEnv.restore_and_merge_conts_from
1055 [C.Break
; C.Continue
; C.Exit
; C.Catch
; C.Finally
]
1057 (env, ttb
, tcb
, tfb
)
1059 and case_list parent_locals ty env switch_pos cl
=
1060 let initialize_next_cont env =
1061 let env = LEnv.restore_conts_from
env parent_locals [C.Next
] in
1062 let env = LEnv.update_next_from_conts
env [C.Next
; C.Fallthrough
] in
1063 LEnv.drop_cont
env C.Fallthrough
1065 let check_fallthrough env switch_pos case_pos block rest_of_list ~is_default
=
1066 if (not
(List.is_empty block
)) && not
(List.is_empty rest_of_list
) then
1067 match LEnv.get_cont_option
env C.Next
with
1070 Errors.default_fallthrough switch_pos
1072 Errors.case_fallthrough switch_pos case_pos
1076 (* below, we try to find out if the switch is exhaustive *)
1078 List.exists cl ~f
:(function
1083 (* If it hasn't got a default clause then we need to solve type variables
1084 * in order to check for an enum *)
1086 Env.expand_type
env ty
1088 Typing_solver.expand_type_and_solve
1090 ~description_of_expected
:"a value"
1095 (* leverage that enums are checked for exhaustivity *)
1100 SN.Classes.cHH_BuiltinEnum
1101 [MakeType.mixed Reason.Rnone
]
1103 Typing_subtype.is_sub_type_for_coercion
env ty top_type
1105 (* register that the runtime may throw in case we cannot prove
1106 that the switch is exhaustive *)
1107 if has_default || is_enum then
1112 let rec case_list env = function
1114 | Default
(pos, b
) :: rl
->
1115 let env = initialize_next_cont env in
1116 let (env, tb) = block
env b
in
1117 check_fallthrough env switch_pos
pos b rl ~is_default
:true;
1118 let (env, tcl
) = case_list env rl
in
1119 (env, Aast.Default
(pos, tb) :: tcl
)
1120 | Case
(((pos, _
) as e
), b
) :: rl
->
1121 let env = initialize_next_cont env in
1122 let (env, te
, _
) = expr env e ~allow_awaitable
:(*?*) false in
1123 let (env, tb) = block
env b
in
1124 check_fallthrough env switch_pos
pos b rl ~is_default
:false;
1125 let (env, tcl
) = case_list env rl
in
1126 (env, Aast.Case
(te
, tb) :: tcl
)
1130 and catch
catchctx env (sid
, exn_lvar
, b
) =
1131 let env = LEnv.replace_cont
env C.Next
catchctx in
1133 let ety_p = fst sid
in
1134 let (env, _
, _
, _
) = instantiable_cid
ety_p env cid [] in
1135 let (env, _tal
, _te
, ety
) =
1136 static_class_id ~check_constraints
:false ety_p env [] cid
1138 let env = coerce_to_throwable
ety_p env ety
in
1139 let (p, x
) = exn_lvar
in
1140 let env = set_valid_rvalue
p env x ety
in
1141 let (env, tb) = block
env b
in
1142 (env, (env.lenv
, (sid
, exn_lvar
, tb)))
1144 and as_expr
env ty1 pe e
=
1145 let env = Env.open_tyvars
env pe
in
1146 let (env, tv
) = Env.fresh_type
env pe
in
1147 let (env, expected_ty
, tk
, tv
) =
1150 let tk = MakeType.mixed Reason.Rnone
in
1151 (env, MakeType.traversable
(Reason.Rforeach pe
) tv
, tk, tv
)
1153 let (env, tk) = Env.fresh_type
env pe
in
1154 (env, MakeType.keyed_traversable
(Reason.Rforeach pe
) tk tv
, tk, tv
)
1156 let tk = MakeType.mixed Reason.Rnone
in
1157 (env, MakeType.async_iterator
(Reason.Rasyncforeach pe
) tv
, tk, tv
)
1159 let (env, tk) = Env.fresh_type
env pe
in
1161 MakeType.async_keyed_iterator
(Reason.Rasyncforeach pe
) tk tv
,
1165 let rec distribute_union env ty =
1166 let (env, ty) = Env.expand_type
env ty in
1167 match get_node
ty with
1168 | Tunion tyl
-> List.fold tyl ~
init:env ~f
:distribute_union
1170 if SubType.is_sub_type_for_union
env ty (MakeType.dynamic
Reason.Rnone
)
1172 let env = SubType.sub_type
env ty tk Errors.unify_error
in
1173 let env = SubType.sub_type
env ty tv
Errors.unify_error
in
1176 let ur = Reason.URforeach
in
1177 Type.sub_type pe
ur env ty expected_ty
Errors.unify_error
1179 let env = distribute_union env ty1
in
1180 let env = Env.set_tyvar_variance
env expected_ty
in
1181 (Typing_solver.close_tyvars_and_solve
env Errors.unify_error
, tk, tv
)
1183 and bind_as_expr
env p ty1 ty2 aexpr
=
1186 let (env, te
, _
) = assign
p env ev ty2
in
1188 | Await_as_v
(p, ev
) ->
1189 let (env, te
, _
) = assign
p env ev ty2
in
1190 (env, Aast.Await_as_v
(p, te
))
1191 | As_kv
((p, Lvar
((_
, k
) as id)), ev
) ->
1192 let env = set_valid_rvalue
p env k ty1
in
1193 let (env, te
, _
) = assign
p env ev ty2
in
1194 let tk = Tast.make_typed_expr
p ty1
(Aast.Lvar
id) in
1195 (env, Aast.As_kv
(tk, te
))
1196 | Await_as_kv
(p, (p1
, Lvar
((_
, k
) as id)), ev
) ->
1197 let env = set_valid_rvalue
p env k ty1
in
1198 let (env, te
, _
) = assign
p env ev ty2
in
1199 let tk = Tast.make_typed_expr p1 ty1
(Aast.Lvar
id) in
1200 (env, Aast.Await_as_kv
(p, tk, te
))
1202 (* TODO Probably impossible, should check that *)
1206 ?
(expected : ExpectedTy.t
option)
1207 ?
(accept_using_var
= false)
1208 ?
(is_using_clause
= false)
1210 ?
(check_defined
= true)
1219 | Some
ExpectedTy.{ reason
= r; ty = { et_type
= ty; _
}; _
} ->
1221 log_with_level
env "typing" 1 (fun () ->
1227 ( "Typing.expr " ^
Typing_reason.string_of_ureason
r,
1228 [Log_type
("expected_ty", ty)] );
1241 with Inf.InconsistentTypeVarState _
as e
->
1242 (* we don't want to catch unwanted exceptions here, eg Timeouts *)
1243 Errors.exception_occurred
p (Exception.wrap e
);
1244 make_result
env p Aast.Any
@@ err_witness env p
1246 (* Some (legacy) special functions are allowed in initializers,
1247 therefore treat them as pure and insert the matching capabilities. *)
1248 and expr_with_pure_coeffects
1249 ?
(expected : ExpectedTy.t
option) ~allow_awaitable
env e
=
1250 let pure = MakeType.mixed (Reason.Rwitness
(fst e
)) in
1251 let (env, (te
, ty)) =
1252 with_special_coeffects env pure pure @@ fun env ->
1253 expr env e ?
expected ~allow_awaitable
|> triple_to_pair
1258 ?
(accept_using_var
= false)
1259 ?
(is_using_clause
= false)
1260 ?
(expected : ExpectedTy.t
option)
1261 ?lhs_of_null_coalesce
1263 ?
(check_defined
= true)
1268 debug_last_pos := fst e
;
1273 ?lhs_of_null_coalesce
1282 let valkind = `lvalue
in
1283 expr_ ~
valkind ~check_defined
:false env e ~allow_awaitable
:(*?*) false
1285 and lvalues
env el
=
1287 | [] -> (env, [], [])
1289 let (env, te
, ty) = lvalue
env e
in
1290 let (env, tel
, tyl
) = lvalues
env el
in
1291 (env, te
:: tel
, ty :: tyl
)
1293 (* These functions invoke special printing functions for Typing_env. They do not
1294 * appear in user code, but we still check top level function calls against their
1296 and typing_env_pseudofunctions
=
1297 SN.PseudoFunctions.(
1298 String.Hash_set.of_list
1299 ~growth_allowed
:false
1300 [hh_show
; hh_show_env
; hh_log_level
; hh_force_solve
; hh_loop_forever
])
1302 and loop_forever
env =
1303 (* forever = up to 10 minutes, to avoid accidentally stuck processes *)
1305 (* Look up things in shared memory occasionally to have a chance to be
1307 match Env.get_class
env "FOR_TEST_ONLY" with
1308 | None
-> Unix.sleep
1
1311 Utils.assert_false_log_backtrace
1312 (Some
"hh_loop_forever was looping for more than 10 minutes")
1314 (* $x ?? 0 is handled similarly to $x ?: 0, except that the latter will also
1315 * look for sketchy null checks in the condition. *)
1316 (* TODO TAST: type refinement should be made explicit in the typed AST *)
1317 and eif
env ~
(expected : ExpectedTy.t
option) ?in_await
p c e1
e2 =
1318 let condition = condition ~lhs_of_null_coalesce
:false in
1319 let (env, tc
, tyc
) =
1320 raw_expr ~lhs_of_null_coalesce
:false env c ~allow_awaitable
:false
1322 let parent_lenv = env.lenv
in
1323 let (env, _lset
) = condition env true tc
in
1324 let (env, te1
, ty1
) =
1327 let (env, ty) = Typing_solver.non_null
env p tyc
in
1330 let (env, te1
, ty1
) =
1331 expr ?
expected ?in_await
env e1 ~allow_awaitable
:true
1333 (env, Some te1
, ty1
)
1335 let lenv1 = env.lenv
in
1336 let env = { env with lenv
= parent_lenv } in
1337 let (env, _lset
) = condition env false tc
in
1338 let (env, te2
, ty2
) = expr ?
expected ?in_await
env e2 ~allow_awaitable
:true in
1339 let lenv2 = env.lenv
in
1340 let env = LEnv.union_lenvs
env parent_lenv lenv1 lenv2 in
1341 let (env, ty) = Union.union env ty1 ty2
in
1342 make_result
env p (Aast.Eif
(tc
, te1
, te2
)) ty
1344 and is_parameter
env x
= Local_id.Map.mem x
(Env.get_params
env)
1346 and check_escaping_var
env (pos, x
) =
1347 if Env.is_using_var
env x
then
1348 if Local_id.equal x this
then
1349 Errors.escaping_this
pos
1350 else if is_parameter
env x
then
1351 Errors.escaping_disposable_parameter
pos
1353 Errors.escaping_disposable
pos
1358 ?
(accept_using_var
= false)
1359 ?
(expected : ExpectedTy.t
option)
1361 ?
(check_defined
= true)
1366 | [] -> (env, [], [])
1378 let (env, tel
, tyl
) =
1388 (env, te
:: tel
, ty :: tyl
)
1390 and exprs_expected
(pos, ur, expected_tyl
) env el
=
1391 match (el
, expected_tyl
) with
1392 | ([], _
) -> (env, [], [])
1393 | (e
:: el
, expected_ty
:: expected_tyl
) ->
1394 let expected = ExpectedTy.make
pos ur expected_ty
in
1395 let (env, te
, ty) = expr ~
expected env e ~allow_awaitable
:(*?*) false in
1396 let (env, tel
, tyl
) = exprs_expected
(pos, ur, expected_tyl
) env el
in
1397 (env, te
:: tel
, ty :: tyl
)
1398 | (el
, []) -> exprs env el ~allow_awaitable
:(*?*) false
1400 and make_result
env p te
ty =
1401 (* Set the variance of any type variables that were generated according
1402 * to how they appear in the expression type *)
1403 let env = Env.set_tyvar_variance
env ty in
1404 (env, Tast.make_typed_expr
p ty te
, ty)
1406 and localize_targ
env ta
=
1408 let (env, targ
) = Phase.localize_targ ~check_well_kinded
:true env ta
in
1409 (env, targ
, ExpectedTy.make
pos Reason.URhint
(fst targ
))
1411 and set_function_pointer
ty =
1412 match get_node
ty with
1414 let ft = set_ft_is_function_pointer
ft true in
1415 mk
(get_reason
ty, Tfun
ft)
1419 ?
(expected : ExpectedTy.t
option)
1420 ?
(accept_using_var
= false)
1421 ?
(is_using_clause
= false)
1422 ?lhs_of_null_coalesce
1425 ~
(valkind : [> `lvalue
| `lvalue_subexpr
| `other
])
1429 let env = Env.open_tyvars
env p in
1430 (fun (env, te
, ty) ->
1431 let env = Typing_solver.close_tyvars_and_solve
env Errors.unify_error
in
1434 let expr ?
(allow_awaitable
= allow_awaitable
) =
1435 expr ~check_defined ~allow_awaitable
1437 let exprs = exprs ~check_defined ~allow_awaitable
in
1438 let raw_expr ?
(allow_awaitable
= allow_awaitable
) =
1439 raw_expr ~check_defined ~allow_awaitable
1442 * Given a list of types, computes their supertype. If any of the types are
1443 * unknown (e.g., comes from PHP), the supertype will be Typing_utils.tany env.
1445 let compute_supertype
1446 ~
(expected : ExpectedTy.t
option) ~reason ~use_pos
r env tys
=
1447 let (env, supertype
) =
1449 | None
-> Env.fresh_type_reason
env r
1450 | Some
ExpectedTy.{ ty = { et_type
= ty; _
}; _
} -> (env, ty)
1452 match get_node supertype
with
1453 (* No need to check individual subtypes if expected type is mixed or any! *)
1454 | Tany _
-> (env, supertype
)
1456 let subtype_value env ty =
1457 Type.sub_type use_pos reason
env ty supertype
Errors.unify_error
1459 let env = List.fold_left tys ~
init:env ~f
:subtype_value in
1461 List.exists tys
(fun ty ->
1462 equal_locl_ty_
(get_node
ty) (Typing_utils.tany
env))
1464 (* If one of the values comes from PHP land, we have to be conservative
1465 * and consider that we don't know what the type of the values are. *)
1466 (env, Typing_utils.mk_tany
env p)
1471 * Given a 'a list and a method to extract an expr and its ty from a 'a, this
1472 * function extracts a list of exprs from the list, and computes the supertype
1473 * of all of the expressions' tys.
1475 let compute_exprs_and_supertype
1476 ~
(expected : ExpectedTy.t
option)
1477 ?
(reason
= Reason.URarray_value
)
1482 extract_expr_and_ty
=
1483 let (env, exprs_and_tys
) =
1484 List.map_env
env l
(extract_expr_and_ty ~
expected)
1486 let (exprs, tys
) = List.unzip exprs_and_tys
in
1487 let (env, supertype
) =
1488 compute_supertype ~
expected ~reason ~use_pos
r env tys
1490 (env, exprs, supertype
)
1492 let forget_fake_members env p callexpr
=
1493 (* Some functions are well known to not change the types of members, e.g.
1495 * There are a lot of usages like
1496 * if (!is_null($x->a) && !is_null($x->a->b))
1497 * where the second is_null call invalidates the first condition.
1498 * This function is a bit best effort. Add stuff here when you want
1499 * To avoid adding too many undue HH_FIXMEs. *)
1502 when String.equal func
SN.StdlibFunctions.is_null
1503 || String.equal func
SN.PseudoFunctions.isset
->
1505 | _
-> Env.forget_members
env Reason.(Blame
(p, BScall
))
1509 ~
(expected : ExpectedTy.t
option)
1529 let env = forget_fake_members env p e
in
1536 failwith
"AST should not contain these nodes"
1538 let ty = Typing_utils.mk_tany
env p in
1539 make_result
env p Aast.Omitted
ty
1540 | Any
-> expr_error env (Reason.Rwitness
p) outer
1542 | ValCollection
(_
, th
, el
) ->
1543 let (get_expected_kind
, name
, subtype_val
, make_expr
, make_ty
) =
1545 | ValCollection
(kind
, _
, _
) ->
1546 let class_name = Nast.vc_kind_to_name kind
in
1552 arraykey_value
p class_name true
1561 (fun th elements
-> Aast.ValCollection
(kind
, th
, elements
)),
1563 MakeType.class_type
(Reason.Rwitness
p) class_name [value_ty
] )
1566 TypecheckerOptions.hack_arr_dv_arrs
(Env.get_tcopt
env)
1572 (fun th elements
-> Aast.ValCollection
(Vec
, th
, elements
)),
1574 MakeType.varray ~
unification (Reason.Rhack_arr_dv_arrs
p) value_ty
1580 (fun th elements
-> Aast.Varray
(th
, elements
)),
1582 MakeType.varray ~
unification (Reason.Rwitness
p) value_ty
)
1584 (* The parent match makes this case impossible *)
1585 failwith
"impossible match case"
1587 (* Use expected type to determine expected element type *)
1588 let (env, elem_expected
, th
) =
1591 let (env, tv
, tv_expected
) = localize_targ
env tv
in
1592 (env, Some tv_expected
, Some tv
)
1595 match expand_expected_and_get_node
env expected with
1596 | (env, Some
(pos, ur, ety
, _
)) ->
1598 match get_expected_kind ety
with
1599 | Some vty
-> (env, Some
(ExpectedTy.make
pos ur vty
), None
)
1600 | None
-> (env, None
, None
)
1602 | _
-> (env, None
, None
)
1605 let (env, tel
, elem_ty
) =
1606 compute_exprs_and_supertype
1607 ~
expected:elem_expected
1609 ~reason
:Reason.URvector
1610 (Reason.Rtype_variable_generics
(p, "T", strip_ns name
))
1615 make_result
env p (make_expr th tel
) (make_ty elem_ty
)
1617 | KeyValCollection
(_
, th
, l
) ->
1618 let (get_expected_kind
, name
, make_expr
, make_ty
) =
1620 | KeyValCollection
(kind
, _
, _
) ->
1621 let class_name = Nast.kvc_kind_to_name kind
in
1622 ( get_kvc_inst p kind
,
1624 (fun th pairs
-> Aast.KeyValCollection
(kind
, th
, pairs
)),
1625 (fun k v
-> MakeType.class_type
(Reason.Rwitness
p) class_name [k
; v
])
1629 TypecheckerOptions.hack_arr_dv_arrs
(Env.get_tcopt
env)
1631 let name = "darray" in
1633 ( get_kvc_inst p Dict
,
1635 (fun th pairs
-> Aast.KeyValCollection
(Dict
, th
, pairs
)),
1637 MakeType.darray ~
unification (Reason.Rhack_arr_dv_arrs
p) k v
)
1639 ( get_darray_inst p,
1641 (fun th pairs
-> Aast.Darray
(th
, pairs
)),
1642 (fun k v
-> MakeType.darray ~
unification (Reason.Rwitness
p) k v
) )
1644 (* The parent match makes this case impossible *)
1645 failwith
"impossible match case"
1647 (* Use expected type to determine expected key and value types *)
1648 let (env, kexpected
, vexpected
, th
) =
1650 | Some
((_
, tk), (_
, tv
)) ->
1651 let (env, tk, tk_expected
) = localize_targ
env tk in
1652 let (env, tv
, tv_expected
) = localize_targ
env tv
in
1653 (env, Some tk_expected
, Some tv_expected
, Some
(tk, tv
))
1655 (* no explicit typehint, fallback to supplied expect *)
1657 match expand_expected_and_get_node
env expected with
1658 | (env, Some
(pos, reason
, ety
, _
)) ->
1660 match get_expected_kind ety
with
1661 | Some
(kty
, vty
) ->
1662 let k_expected = ExpectedTy.make
pos reason kty
in
1663 let v_expected = ExpectedTy.make
pos reason vty
in
1664 (env, Some
k_expected, Some
v_expected, None
)
1665 | None
-> (env, None
, None
, None
)
1667 | _
-> (env, None
, None
, None
)
1670 let (kl
, vl
) = List.unzip l
in
1672 compute_exprs_and_supertype
1675 ~reason
:Reason.URkey
1676 (Reason.Rtype_variable_generics
(p, "Tk", strip_ns
name))
1679 (arraykey_value
p name false)
1682 compute_exprs_and_supertype
1685 ~reason
:Reason.URvalue
1686 (Reason.Rtype_variable_generics
(p, "Tv", strip_ns
name))
1691 let pairs = List.zip_exn tkl tvl
in
1692 make_result
env p (make_expr th
pairs) (make_ty k v
)
1694 let (env, te
, ty) = expr env e
in
1695 (* Clone only works on objects; anything else fatals at runtime.
1696 * Constructing a call `e`->__clone() checks that `e` is an object and
1697 * checks coeffects on __clone *)
1698 let (env, (tfty
, _tal
)) =
1704 ~coerce_from_ty
:None
1706 ~class_id
:(CIexpr e
)
1707 ~member_id
:(p, SN.Members.__clone
)
1708 ~on_error
:Errors.unify_error
1712 let (env, (_tel
, _typed_unpack_element
, _ty
)) =
1713 call ~
expected:None
p env tfty
[] None
1715 make_result
env p (Aast.Clone te
) ty
1717 if Option.is_none
(Env.get_self_ty
env) then Errors.this_var_outside_class
p;
1718 if not accept_using_var
then check_escaping_var
env (p, this
);
1719 let ty = Env.get_local
env this
in
1720 let r = Reason.Rwitness
p in
1721 let ty = mk
(r, TUtils.this_of
(mk
(r, get_node
ty))) in
1722 make_result
env p Aast.This
ty
1723 | True
-> make_result
env p Aast.True
(MakeType.bool (Reason.Rwitness
p))
1724 | False
-> make_result
env p Aast.False
(MakeType.bool (Reason.Rwitness
p))
1725 (* TODO TAST: consider checking that the integer is in range. Right now
1726 * it's possible for HHVM to fail on well-typed Hack code
1728 | Int s
-> make_result
env p (Aast.Int s
) (MakeType.int (Reason.Rwitness
p))
1730 make_result
env p (Aast.Float s
) (MakeType.float (Reason.Rwitness
p))
1731 (* TODO TAST: consider introducing a "null" type, and defining ?t to
1734 | Null
-> make_result
env p Aast.Null
(MakeType.null
(Reason.Rwitness
p))
1736 make_result
env p (Aast.String s
) (MakeType.string (Reason.Rwitness
p))
1738 let (env, tel
) = string2
env idl
in
1739 make_result
env p (Aast.String2 tel
) (MakeType.string (Reason.Rwitness
p))
1740 | PrefixedString
(n
, e
) ->
1741 if String.( <> ) n
"re" then (
1742 Errors.experimental_feature
1744 "String prefixes other than `re` are not yet supported.";
1745 expr_error env Reason.Rnone outer
1747 let (env, te
, ty) = expr env e
in
1749 let env = Typing_substring.sub_string
pe env ty in
1757 (Aast.PrefixedString
(n
, te
))
1758 (Typing_regex.type_pattern e
)
1760 | Pcre.Error
(Pcre.BadPattern
(s
, i
)) ->
1761 let s = s ^
" [" ^ string_of_int i ^
"]" in
1762 Errors.bad_regex_pattern
pe s;
1763 expr_error env (Reason.Rregex
pe) e
1764 | Typing_regex.Empty_regex_pattern
->
1765 Errors.bad_regex_pattern
pe "This pattern is empty";
1766 expr_error env (Reason.Rregex
pe) e
1767 | Typing_regex.Missing_delimiter
->
1768 Errors.bad_regex_pattern
pe "Missing delimiter(s)";
1769 expr_error env (Reason.Rregex
pe) e
1770 | Typing_regex.Invalid_global_option
->
1771 Errors.bad_regex_pattern
pe "Invalid global option(s)";
1772 expr_error env (Reason.Rregex
pe) e
1775 Errors.re_prefixed_non_string
pe "Strings with embedded expressions";
1776 expr_error env (Reason.Rregex
pe) e
1778 Errors.re_prefixed_non_string
pe "Non-strings";
1779 expr_error env (Reason.Rregex
pe) e
)
1781 let (env, fty
, _tal
) = fun_type_of_id
env x
[] [] in
1782 make_result
env p (Aast.Fun_id x
) fty
1783 | Id
((cst_pos
, cst_name
) as id) ->
1784 (match Env.get_gconst
env cst_name
with
1785 | None
when Partial.should_check_error
(Env.get_mode
env) 4106 ->
1786 Errors.unbound_global cst_pos
;
1787 let ty = err_witness env cst_pos
in
1788 make_result
env cst_pos
(Aast.Id
id) ty
1789 | None
-> make_result
env p (Aast.Id
id) (Typing_utils.mk_tany
env cst_pos
)
1792 Phase.localize_with_self
env ~ignore_errors
:true const
.cd_type
1794 make_result
env p (Aast.Id
id) ty)
1795 | Method_id
(instance
, meth) ->
1796 (* Method_id is used when creating a "method pointer" using the magic
1797 * inst_meth function.
1799 * Typing this is pretty simple, we just need to check that instance->meth
1800 * is public+not static and then return its type.
1802 let (env, te
, ty1
) = expr env instance
in
1803 let (env, (result
, _tal
)) =
1809 ~coerce_from_ty
:None
1811 ~class_id
:(CIexpr instance
)
1813 ~on_error
:Errors.unify_error
1818 Env.FakeMembers.check_instance_invalid
env instance
(snd
meth) result
1820 make_result
env p (Aast.Method_id
(te
, meth)) result
1821 | Method_caller
(((pos, class_name) as pos_cname
), meth_name
) ->
1822 (* meth_caller('X', 'foo') desugars to:
1825 let class_ = Env.get_class
env class_name in
1827 | None
-> unbound_name env pos_cname outer
1829 (* Create a class type for the given object instantiated with unresolved
1830 * types for its type parameters.
1833 if Ast_defs.is_c_trait
(Cls.kind
class_) then
1834 Errors.meth_caller_trait
pos class_name
1837 List.map_env
env (Cls.tparams
class_) (fun env _
->
1838 Env.fresh_type
env p)
1841 List.map (Cls.tparams
class_) (fun { tp_name
= (p, n
); _
} ->
1842 (* TODO(T69551141) handle type arguments for Tgeneric *)
1843 MakeType.generic
(Reason.Rwitness_from_decl
p) n
)
1846 MakeType.apply
(Reason.Rwitness_from_decl
p) pos_cname
params
1850 (Phase.env_with_self
env ~on_error
:(Errors.invalid_type_hint
pos)) with
1851 substs
= TUtils.make_locl_subst_for_class_tparams
class_ tvarl
;
1854 let (env, local_obj_ty
) = Phase.localize ~
ety_env env obj_type in
1855 let (env, (fty
, _tal
)) =
1861 ~coerce_from_ty
:None
1863 ~class_id
:(CI
(pos, class_name))
1864 ~member_id
:meth_name
1865 ~on_error
:Errors.unify_error
1869 let (env, fty
) = Env.expand_type
env fty
in
1870 (match deref fty
with
1871 | (reason
, Tfun ftype
) ->
1872 (* We are creating a fake closure:
1873 * function(Class $x, arg_types_of(Class::meth_name))
1874 : return_type_of(Class::meth_name)
1879 on_error
= Errors.leave_unchanged_default_invalid_type_hint_code
;
1883 Phase.check_tparams_constraints
1887 (Cls.tparams
class_)
1889 let local_obj_fp = TUtils.default_fun_param local_obj_ty
in
1890 let fty = { ftype
with ft_params
= local_obj_fp :: ftype
.ft_params
} in
1893 ft_arity
= fty.ft_arity
;
1894 ft_tparams
= fty.ft_tparams
;
1895 ft_where_constraints
= fty.ft_where_constraints
;
1896 ft_params
= fty.ft_params
;
1897 ft_implicit_params
= fty.ft_implicit_params
;
1898 ft_ret
= fty.ft_ret
;
1899 (* propagate 'is_coroutine' from the method being called*)
1900 ft_flags
= fty.ft_flags
;
1901 ft_ifc_decl
= fty.ft_ifc_decl
;
1907 (Aast.Method_caller
(pos_cname
, meth_name
))
1908 (mk
(reason
, Tfun
caller))
1910 (* This can happen if the method lives in PHP *)
1914 (Aast.Method_caller
(pos_cname
, meth_name
))
1915 (Typing_utils.mk_tany
env pos)))
1916 | FunctionPointer
(FP_class_const
((cpos
, cid), meth), targs
) ->
1917 let (env, _
, ce
, cty
) =
1918 static_class_id ~check_constraints
:true cpos
env [] cid
1920 let (env, (fpty
, tal
)) =
1924 ~incl_tc
:false (* What is this? *)
1925 ~coerce_from_ty
:None
(* What is this? *)
1926 ~explicit_targs
:targs
1927 ~is_function_pointer
:true
1933 let env = Env.set_tyvar_variance
env fpty
in
1934 let fpty = set_function_pointer
fpty in
1938 (Aast.FunctionPointer
(FP_class_const
(ce
, meth), tal
))
1940 | Smethod_id
((pc
, cid), meth) ->
1941 (* Smethod_id is used when creating a "method pointer" using the magic
1942 * class_meth function.
1944 * Typing this is pretty simple, we just need to check that c::meth is
1945 * public+static and then return its type.
1947 let (class_, classname
) =
1951 (Env.get_self_class
env, Env.get_self_id
env)
1952 | CI
(_
, const
) when String.equal const
SN.PseudoConsts.g__CLASS__
->
1953 (Env.get_self_class
env, Env.get_self_id
env)
1954 | CI
(_
, id) -> (Env.get_class
env id, Some
id)
1957 let classname = Option.value classname ~default
:"" in
1960 (* The class given as a static string was not found. *)
1961 unbound_name env (pc
, classname) outer
1963 let smethod = Env.get_static_member
true env class_ (snd
meth) in
1966 (* The static method wasn't found. *)
1967 TOG.smember_not_found
1971 ~is_function_pointer
:false
1975 expr_error env Reason.Rnone outer
1976 | Some
({ ce_type
= (lazy ty); ce_pos
= (lazy ce_pos
); _
} as ce
) ->
1978 if get_ce_abstract ce
then
1981 | _
-> Errors.class_meth_abstract_call
classname (snd
meth) p ce_pos
1983 let ce_visibility = ce
.ce_visibility in
1984 let ce_deprecated = ce
.ce_deprecated in
1985 let (env, _tal
, te
, cid_ty
) =
1986 static_class_id ~exact
:Exact ~check_constraints
:true pc
env [] cid
1988 let (env, cid_ty
) = Env.expand_type
env cid_ty
in
1990 match get_node cid_ty
with
1991 | Tclass
(_
, _
, tyargs) -> tyargs
1996 type_expansions
= [];
1997 substs
= TUtils.make_locl_subst_for_class_tparams
class_ tyargs;
1999 on_error
= Errors.ignore_error
;
2002 let r = get_reason
ty |> Typing_reason.localize
in
2003 (match get_node
ty with
2006 Typing_enforceability.compute_enforced_and_pessimize_fun_type
env ft
2008 let def_pos = ce_pos
in
2010 Phase.localize_targs
2011 ~check_well_kinded
:true
2015 ~use_name
:(strip_ns
(snd
meth))
2026 use_name
= strip_ns
(snd
meth);
2028 explicit_targs
= tal
;
2035 let ty = mk
(r, Tfun
ft) in
2036 let use_pos = fst
meth in
2037 TVis.check_deprecated ~
use_pos ~
def_pos ce_deprecated;
2038 (match ce_visibility with
2039 | Vpublic
-> make_result
env p (Aast.Smethod_id
(te
, meth)) ty
2041 Errors.private_class_meth ~
def_pos ~
use_pos;
2042 expr_error env r outer
2044 Errors.protected_class_meth ~
def_pos ~
use_pos;
2045 expr_error env r outer
)
2047 Errors.internal_error
p "We have a method which isn't callable";
2048 expr_error env r outer
)))
2050 let r = Reason.Rplaceholder
p in
2051 let ty = MakeType.void
r in
2052 make_result
env p (Aast.Lplaceholder
p) ty
2053 | Dollardollar _
when phys_equal
valkind `lvalue
->
2054 Errors.dollardollar_lvalue
p;
2055 expr_error env (Reason.Rwitness
p) outer
2056 | Dollardollar
id ->
2057 let ty = Env.get_local_check_defined
env id in
2058 let env = might_throw
env in
2059 make_result
env p (Aast.Dollardollar
id) ty
2060 | Lvar
((_
, x
) as id) ->
2061 if not accept_using_var
then check_escaping_var
env id;
2063 if check_defined
then
2064 Env.get_local_check_defined
env id
2068 make_result
env p (Aast.Lvar
id) ty
2070 let (env, tel
, tyl
) =
2073 | `lvalue_subexpr
->
2076 let (env, expected) = expand_expected_and_get_node
env expected in
2077 (match expected with
2078 | Some
(pos, ur, _
, Ttuple expected_tyl
) ->
2079 exprs_expected
(pos, ur, expected_tyl
) env el
2080 | _
-> exprs env el
)
2082 let ty = MakeType.tuple
(Reason.Rwitness
p) tyl
in
2083 make_result
env p (Aast.List tel
) ty
2084 | Pair
(th
, e1
, e2) ->
2085 let (env, expected1
, expected2
, th
) =
2087 | Some
((_
, t1
), (_
, t2
)) ->
2088 let (env, t1
, t1_expected
) = localize_targ
env t1
in
2089 let (env, t2
, t2_expected
) = localize_targ
env t2
in
2090 (env, Some t1_expected
, Some t2_expected
, Some
(t1
, t2
))
2092 (* Use expected type to determine expected element types *)
2093 (match expand_expected_and_get_node
env expected with
2094 | (env, Some
(pos, reason
, _ty
, Tclass
((_
, k
), _
, [ty1
; ty2
])))
2095 when String.equal k
SN.Collections.cPair
->
2096 let ty1_expected = ExpectedTy.make
pos reason ty1
in
2097 let ty2_expected = ExpectedTy.make
pos reason ty2
in
2098 (env, Some
ty1_expected, Some
ty2_expected, None
)
2099 | _
-> (env, None
, None
, None
))
2101 let (env, te1
, ty1
) = expr ?
expected:expected1
env e1
in
2102 let (env, te2
, ty2
) = expr ?
expected:expected2
env e2 in
2108 ~reason
:Reason.URpair_value
2110 (Reason.Rtype_variable_generics
(p1, "T1", "Pair"))
2117 ~reason
:Reason.URpair_value
2119 (Reason.Rtype_variable_generics
(p2, "T2", "Pair"))
2123 let ty = MakeType.pair
(Reason.Rwitness
p) ty1 ty2
in
2124 make_result
env p (Aast.Pair
(th
, te1
, te2
)) ty
2125 | Array_get
(e
, None
) ->
2126 let (env, te
, _
) = update_array_type
p env e
valkind in
2127 let env = might_throw
env in
2128 (* NAST check reports an error if [] is used for reading in an
2130 let ty = err_witness env p in
2131 make_result
env p (Aast.Array_get
(te
, None
)) ty
2132 | Array_get
(e1
, Some
e2) ->
2133 let (env, te1
, ty1
) =
2134 update_array_type ?lhs_of_null_coalesce
p env e1
valkind
2136 let (env, te2
, ty2
) = expr env e2 in
2137 let env = might_throw
env in
2138 let is_lvalue = phys_equal
valkind `lvalue
in
2140 Typing_array_access.array_get
2143 ?lhs_of_null_coalesce
2150 make_result
env p (Aast.Array_get
(te1
, Some te2
)) ty
2151 | Call
((pos_id
, Id
((_
, s) as id)), [], el
, None
)
2152 when Hash_set.mem typing_env_pseudofunctions
s ->
2153 let (env, tel
, tys
) = exprs ~accept_using_var
:true env el
in
2155 if String.equal
s SN.PseudoFunctions.hh_show
then (
2156 List.iter tys
(Typing_log.hh_show
p env);
2158 ) else if String.equal
s SN.PseudoFunctions.hh_show_env
then (
2159 Typing_log.hh_show_env
p env;
2161 ) else if String.equal
s SN.PseudoFunctions.hh_log_level
then
2163 | [(_
, String key_str
); (_
, Int level_str
)] ->
2164 Env.set_log_level
env key_str
(int_of_string level_str
)
2166 else if String.equal
s SN.PseudoFunctions.hh_force_solve
then
2167 Typing_solver.solve_all_unsolved_tyvars
env Errors.unify_error
2168 else if String.equal
s SN.PseudoFunctions.hh_loop_forever
then (
2174 let ty = MakeType.void
(Reason.Rwitness
p) in
2179 ( Tast.make_typed_expr pos_id
(TUtils.mk_tany
env pos_id
) (Aast.Id
id),
2184 | Call
(e
, explicit_targs
, el
, unpacked_element
) ->
2187 | Id
(pos, f
) when String.equal f
SN.SpecialFunctions.echo
->
2188 Typing_local_ops.enforce_io
pos env
2191 let env = might_throw
env in
2202 | FunctionPointer
(FP_id fid
, targs
) ->
2203 let (env, fty, targs
) = fun_type_of_id
env fid targs
[] in
2204 let e = Aast.FunctionPointer
(FP_id fid
, targs
) in
2205 let fty = set_function_pointer
fty in
2206 make_result
env p e fty
2207 | Binop
(Ast_defs.QuestionQuestion
, e1
, e2) ->
2208 let (env, te1
, ty1
) =
2209 raw_expr ~lhs_of_null_coalesce
:true env e1 ~allow_awaitable
:true
2211 let (env, te2
, ty2
) = expr ?
expected env e2 ~allow_awaitable
:true in
2212 let (env, ty1'
) = Env.fresh_type
env (fst e1
) in
2217 (MakeType.nullable_locl
Reason.Rnone ty1'
)
2220 (* Essentially mimic a call to
2221 * function coalesce<Tr, Ta as Tr, Tb as Tr>(?Ta, Tb): Tr
2222 * That way we let the constraint solver take care of the union logic.
2224 let (env, ty_result
) = Env.fresh_type
env (fst
e2) in
2225 let env = SubType.sub_type
env ty1' ty_result
Errors.unify_error
in
2226 let env = SubType.sub_type
env ty2 ty_result
Errors.unify_error
in
2230 (Aast.Binop
(Ast_defs.QuestionQuestion
, te1
, te2
))
2232 | Binop
(Ast_defs.Eq op_opt
, e1
, e2) ->
2233 let make_result env p te
ty =
2234 let (env, te
, ty) = make_result env p te
ty in
2235 let env = Typing_local_ops.check_assignment
env te
in
2239 (* For example, e1 += e2. This is typed and translated as if
2240 * written e1 = e1 + e2.
2241 * TODO TAST: is this right? e1 will get evaluated more than once
2245 match (op
, snd e1
) with
2246 | (Ast_defs.QuestionQuestion
, Class_get _
) ->
2247 Errors.experimental_feature
2249 "null coalesce assignment operator with static properties";
2250 expr_error env Reason.Rnone outer
2253 (p, Binop
(Ast_defs.Eq None
, e1
, (p, Binop
(op
, e1
, e2))))
2255 let (env, te_fake
, ty) = raw_expr env e_fake in
2257 match snd te_fake
with
2258 | Aast.Binop
(_
, te1
, (_
, Aast.Binop
(_
, _
, te2
))) ->
2259 let te = Aast.Binop
(Ast_defs.Eq
(Some op
), te1
, te2
) in
2260 make_result env p te ty
2265 let (env, te2
, ty2
) = raw_expr env e2 in
2266 let (env, te1
, ty) = assign
p env e1 ty2
in
2267 make_result env p (Aast.Binop
(Ast_defs.Eq None
, te1
, te2
)) ty)
2268 | Binop
(((Ast_defs.Ampamp
| Ast_defs.Barbar
) as bop
), e1
, e2) ->
2269 let c = Ast_defs.(equal_bop bop Ampamp
) in
2270 let (env, te1
, _
) = expr env e1
in
2271 let lenv = env.lenv in
2272 let (env, _lset
) = condition env c te1
in
2273 let (env, te2
, _
) = expr env e2 in
2274 let env = { env with lenv } in
2278 (Aast.Binop
(bop
, te1
, te2
))
2279 (MakeType.bool (Reason.Rlogic_ret
p))
2280 | Binop
(bop
, e1
, e2) ->
2281 let (env, te1
, ty1
) = raw_expr env e1
in
2282 let (env, te2
, ty2
) = raw_expr env e2 in
2285 (* TODO: This could be less conservative: we only need to account for
2286 * the possibility of exception if the operator is `/` or `/=`.
2291 | _
-> might_throw
env
2293 let (env, te3
, ty) =
2294 Typing_arithmetic.binop
p env bop
(fst e1
) te1 ty1
(fst
e2) te2 ty2
2297 | Pipe
(e0
, e1
, e2) ->
2298 (* If it weren't for local variable assignment or refinement the pipe
2299 * expression e1 |> e2 could be typed using this rule (E is environment with
2300 * types for locals):
2302 * E |- e1 : ty1 E[$$:ty1] |- e2 : ty2
2303 * --------------------------------------
2306 * The possibility of e2 changing the types of locals in E means that E
2307 * can evolve, and so we need to restore $$ to its original state.
2309 let (env, te1
, ty1
) = expr env e1
in
2310 let dd_var = Local_id.make_unscoped
SN.SpecialIdents.dollardollar
in
2312 if Env.is_local_defined
env dd_var then
2313 Some
(Env.get_local_pos
env dd_var)
2317 let env = Env.set_local
env dd_var ty1
Pos.none
in
2318 let (env, te2
, ty2
) = expr env e2 ~allow_awaitable
:true in
2320 match dd_old_ty with
2321 | None
-> Env.unset_local
env dd_var
2322 | Some
(ty, pos) -> Env.set_local
env dd_var ty pos
2324 let (env, te, ty) = make_result env p (Aast.Pipe
(e0
, te1
, te2
)) ty2
in
2327 let (env, te, ty) = raw_expr env e in
2328 let env = might_throw
env in
2329 let (env, tuop
, ty) = Typing_arithmetic.unop
p env uop
te ty in
2330 let env = Typing_local_ops.check_assignment
env te in
2332 | Eif
(c, e1
, e2) -> eif
env ~
expected ?in_await
p c e1
e2
2333 | Class_const
((p, CI sid
), pstr
)
2334 when String.equal
(snd pstr
) "class" && Env.is_typedef
env (snd sid
) ->
2336 match Env.get_typedef
env (snd sid
) with
2337 | Some
{ td_tparams
= tparaml
; _
} ->
2338 (* Typedef type parameters cannot have constraints *)
2343 fun { tp_name
= (p, x
); _
} ->
2344 (* TODO(T69551141) handle type arguments for Tgeneric *)
2345 MakeType.generic
(Reason.Rwitness_from_decl
p) x
2349 let tdef = mk
(Reason.Rwitness_from_decl
p, Tapply
(sid
, params)) in
2352 ( Reason.Rwitness_from_decl
p,
2353 Tapply
((p, SN.Classes.cTypename
), [tdef]) )
2355 let (env, tparams
) =
2356 List.map_env
env tparaml
(fun env tp
->
2357 Env.fresh_type
env (fst tp
.tp_name
))
2361 (Phase.env_with_self
2363 ~on_error
:Errors.leave_unchanged_default_invalid_type_hint_code
)
2365 substs
= Subst.make_locl tparaml tparams
;
2369 Phase.check_tparams_constraints ~
use_pos:p ~
ety_env env tparaml
2371 let (env, ty) = Phase.localize ~
ety_env env typename in
2372 make_result env p (Class_const
(((p, ty), CI sid
), pstr
)) ty
2374 (* Should not expect None as we've checked whether the sid is a typedef *)
2375 expr_error env (Reason.Rwitness
p) outer
2377 | Class_const
(cid, mid
) -> class_const
env p (cid, mid
)
2378 | Class_get
((cpos
, cid), CGstring mid
, in_parens
)
2379 when Env.FakeMembers.is_valid_static
env cid (snd mid
) ->
2380 let (env, local
) = Env.FakeMembers.make_static
env cid (snd mid
) p in
2381 let local = (p, Lvar
(p, local)) in
2382 let (env, _
, ty) = expr env local in
2383 let (env, _tal
, te, _
) =
2384 static_class_id ~check_constraints
:false cpos
env [] cid
2386 make_result env p (Aast.Class_get
(te, Aast.CGstring mid
, in_parens
)) ty
2387 | Class_get
((cpos
, cid), CGstring
((ppos
, _
) as mid
), in_parens
) ->
2388 let (env, _tal
, te, cty
) =
2389 static_class_id ~check_constraints
:false cpos
env [] cid
2391 let env = might_throw
env in
2392 let (env, (ty, _tal
)) =
2396 ~coerce_from_ty
:None
2402 let (env, ty) = Env.FakeMembers.check_static_invalid
env cid (snd mid
) ty in
2403 let env = Typing_local_ops.enforce_static_property_access ppos
env in
2404 make_result env p (Aast.Class_get
(te, Aast.CGstring mid
, in_parens
)) ty
2405 (* Fake member property access. For example:
2406 * if ($x->f !== null) { ...$x->f... }
2408 | Class_get
(_
, CGexpr _
, _
) ->
2409 failwith
"AST should not have any CGexprs after naming"
2410 | Obj_get
(e, (pid
, Id
(py
, y
)), nf
, in_parens
)
2411 when Env.FakeMembers.is_valid
env e y
->
2412 let env = might_throw
env in
2413 let (env, local) = Env.FakeMembers.make
env e y
p in
2414 let local = (p, Lvar
(p, local)) in
2415 let (env, _
, ty) = expr env local in
2416 let (env, t_lhs
, _
) = expr ~accept_using_var
:true env e in
2417 let t_rhs = Tast.make_typed_expr pid
ty (Aast.Id
(py
, y
)) in
2418 make_result env p (Aast.Obj_get
(t_lhs
, t_rhs, nf
, in_parens
)) ty
2419 (* Statically-known instance property access e.g. $x->f *)
2420 | Obj_get
(e1
, (pm
, Id m
), nullflavor
, in_parens
) ->
2422 match nullflavor
with
2423 | OG_nullthrows
-> None
2424 | OG_nullsafe
-> Some
p
2426 let (env, te1
, ty1
) = expr ~accept_using_var
:true env e1
in
2427 let env = might_throw
env in
2428 (* We typecheck Obj_get by checking whether it is a subtype of
2429 Thas_member(m, #1) where #1 is a fresh type variable. *)
2430 let (env, mem_ty
) = Env.fresh_type
env p in
2431 let r = Reason.Rwitness
(fst e1
) in
2437 ~class_id
:(CIexpr e1
)
2438 ~explicit_targs
:None
2440 let lty1 = LoclType ty1
in
2441 let (env, result_ty
) =
2455 (* In that case ty1 is a subtype of ?Thas_member(m, #1)
2456 and the result is ?#1 if ty1 is nullable. *)
2457 let r = Reason.Rnullsafe_op
p in
2458 let null_ty = MakeType.null
r in
2459 let (env, null_has_mem_ty
) =
2460 Union.union_i
env r has_member_ty null_ty
2471 let (env, null_or_nothing_ty
) = Inter.intersect
env ~
r null_ty ty1
in
2472 let (env, result_ty
) = Union.union env null_or_nothing_ty mem_ty
in
2475 let (env, result_ty
) =
2476 Env.FakeMembers.check_instance_invalid
env e1
(snd m
) result_ty
2483 Tast.make_typed_expr pm result_ty
(Aast.Id m
),
2487 (* Dynamic instance property access e.g. $x->$f *)
2488 | Obj_get
(e1
, e2, nullflavor
, in_parens
) ->
2489 let (env, te1
, ty1
) = expr ~accept_using_var
:true env e1
in
2490 let (env, te2
, _
) = expr env e2 in
2492 if TUtils.is_dynamic
env ty1
then
2493 MakeType.dynamic
(Reason.Rwitness
p)
2495 Typing_utils.mk_tany
env p
2497 let ((pos, _
), te2
) = te2
in
2498 let env = might_throw
env in
2499 let te2 = Tast.make_typed_expr
pos ty te2 in
2500 make_result env p (Aast.Obj_get
(te1
, te2, nullflavor
, in_parens
)) ty
2502 let (env, (taf
, opt_key
, value)) = array_field ~allow_awaitable
env af
in
2503 let (env, send
) = Env.fresh_type
env p in
2505 match (af
, opt_key
) with
2506 | (AFvalue
(p, _
), None
) ->
2508 match Env.get_fn_kind
env with
2510 | Ast_defs.FAsync
->
2511 Errors.internal_error
p "yield found in non-generator";
2512 (env, Typing_utils.mk_tany
env p)
2513 | Ast_defs.FGenerator
-> (env, MakeType.int (Reason.Rwitness
p))
2514 | Ast_defs.FAsyncGenerator
->
2515 let (env, ty) = Env.fresh_type
env p in
2516 (env, MakeType.nullable_locl
(Reason.Ryield_asyncnull
p) ty)
2518 | (_
, Some x
) -> (env, x
)
2519 | (_
, _
) -> assert false
2522 match Env.get_fn_kind
env with
2523 | Ast_defs.FGenerator
->
2524 MakeType.generator
(Reason.Ryield_gen
p) key
value send
2525 | Ast_defs.FAsyncGenerator
->
2526 MakeType.async_generator
(Reason.Ryield_asyncgen
p) key
value send
2528 | Ast_defs.FAsync
->
2529 failwith
"Parsing should never allow this"
2531 let Typing_env_return_info.{ return_type = expected_return; _
} =
2535 Typing_coercion.coerce_type
2543 let env = Env.forget_members
env Reason.(Blame
(p, BScall
)) in
2544 let env = LEnv.save_and_merge_next_in_cont
env C.Exit
in
2549 (MakeType.nullable_locl
(Reason.Ryield_send
p) send
)
2551 let env = might_throw
env in
2552 (* Await is permitted in a using clause e.g. using (await make_handle()) *)
2553 let (env, te, rty) =
2556 ~in_await
:(Reason.Rwitness
p)
2559 ~allow_awaitable
:true
2561 let (env, ty) = Async.overload_extract_from_awaitable
env p rty in
2562 make_result env p (Aast.Await
te) ty
2564 (* Basically ignore the readonly since it does not affect the type of the result *)
2565 let (env, te, rty) = expr ~is_using_clause
env e in
2566 make_result env p (Aast.ReadonlyExpr
te) rty
2567 | New
((pos, c), explicit_targs
, el
, unpacked_element
, p1) ->
2568 let env = might_throw
env in
2569 let (env, tc
, tal
, tel
, typed_unpack_element
, ty, ctor_fty
) =
2574 ~check_not_abstract
:true
2582 let env = Env.forget_members
env Reason.(Blame
(p, BScall
)) in
2586 (Aast.New
(tc
, tal
, tel
, typed_unpack_element
, (p1, ctor_fty
)))
2588 | Record
((pos, id), field_values
) ->
2589 (match Decl_provider.get_record_def
(Env.get_ctx
env) id with
2591 if rd
.rdt_abstract
then Errors.new_abstract_record
(pos, id);
2593 let field_name (pos, expr_
) =
2595 | Aast.String
name -> Some
(pos, name)
2597 (* TODO T44306013: Ensure that other values for field names are banned. *)
2600 let fields_declared = Typing_helpers.all_record_fields
env rd
in
2601 let fields_present =
2602 List.map field_values ~f
:(fun (name, _value
) -> field_name name)
2605 (* Check for missing required fields. *)
2606 let fields_present_names =
2607 List.map ~f
:snd
fields_present |> SSet.of_list
2610 (fun field_name info
->
2611 let ((field_pos
, _
), req
) = info
in
2613 | Typing_defs.ValueRequired
2614 when not
(SSet.mem
field_name fields_present_names) ->
2615 Errors.missing_record_field_name
2619 ~field_decl_pos
:field_pos
2623 (* Check for unknown fields.*)
2624 List.iter
fields_present ~f
:(fun (pos, field_name) ->
2625 if not
(SMap.mem
field_name fields_declared) then
2626 Errors.unexpected_record_field_name
2630 ~decl_pos
:(fst rd
.rdt_name
))
2631 | None
-> Errors.type_not_record
id pos);
2633 expr_error env (Reason.Rwitness
p) outer
2635 let (env, te, ty2
) = expr ?in_await
env e in
2636 let env = might_throw
env in
2639 TypecheckerOptions.experimental_feature_enabled
2641 TypecheckerOptions.experimental_forbid_nullable_cast
2642 && not
(TUtils.is_mixed
env ty2
)
2644 SubType.sub_type_or_fail
2647 (MakeType.nonnull
(get_reason ty2
))
2649 Errors.nullable_cast
p (Typing_print.error
env ty2
) (get_pos ty2
))
2654 Phase.localize_hint_with_self
env ~ignore_errors
:false hint
2656 make_result env p (Aast.Cast
(hint
, te)) ty
2657 | ExpressionTree et
-> expression_tree
{ env with in_expr_tree
= true } p et
2659 Typing_kinding.Simple.check_well_kinded_hint
env hint
;
2660 let (env, te, _
) = expr env e in
2661 make_result env p (Aast.Is
(te, hint
)) (MakeType.bool (Reason.Rwitness
p))
2662 | As
(e, hint
, is_nullable
) ->
2663 Typing_kinding.Simple.check_well_kinded_hint
env hint
;
2664 let refine_type env lpos lty
rty =
2665 let reason = Reason.Ras lpos
in
2666 let (env, rty) = Env.expand_type
env rty in
2667 let (env, rty) = class_for_refinement
env p reason lpos lty
rty in
2668 Inter.intersect
env reason lty
rty
2670 let (env, te, expr_ty
) = expr env e in
2671 let env = might_throw
env in
2672 let (env, hint_ty
) =
2673 Phase.localize_hint_with_self
env ~ignore_errors
:false hint
2675 let enable_sound_dynamic =
2676 TypecheckerOptions.enable_sound_dynamic env.genv
.tcopt
2678 let is_dyn = Typing_utils.is_dynamic
env hint_ty
in
2679 ( if enable_sound_dynamic && is_dyn then
2680 let (_
: env * locl_ty
) =
2682 ~coerce
:(Some
Typing_logic.CoerceToDynamic
)
2690 let (env, hint_ty
) =
2691 if is_dyn && not
enable_sound_dynamic then
2693 if is_instance_var
e then
2694 let (env, ivar
) = get_instance_var
env e in
2695 set_local
env ivar hint_ty
2700 else if is_nullable
&& not
is_dyn then
2701 let (env, hint_ty
) = refine_type env (fst
e) expr_ty hint_ty
in
2702 (env, MakeType.nullable_locl
(Reason.Rwitness
p) hint_ty
)
2703 else if is_instance_var
e then
2704 let (env, _
, ivar_ty
) = raw_expr env e in
2705 let (env, ((ivar_pos
, _
) as ivar
)) = get_instance_var
env e in
2706 let (env, hint_ty
) = refine_type env ivar_pos ivar_ty hint_ty
in
2707 let env = set_local
env ivar hint_ty
in
2710 refine_type env (fst
e) expr_ty hint_ty
2712 make_result env p (Aast.As
(te, hint
, is_nullable
)) hint_ty
2721 (* Check type annotations on the lambda *)
2722 Typing_check_decls.fun_
env f
;
2723 (* Check attributes on the lambda *)
2725 attributes_check_def
env SN.AttributeKinds.lambda f
.f_user_attributes
2727 (* This is the function type as declared on the lambda itself.
2728 * If type hints are absent then use Tany instead. *)
2730 Decl_nast.fun_decl_in_env
env.decl_env ~is_lambda
:true f
2732 let { fe_type
; fe_pos
; _
} = declared_fe in
2733 let (declared_pos
, declared_ft
) =
2734 match get_node fe_type
with
2735 | Tfun
ft -> (fe_pos
, ft)
2736 | _
-> failwith
"Not a function"
2739 Typing_enforceability.compute_enforced_and_pessimize_fun_type
2743 (* When creating a closure, the 'this' type will mean the late bound type
2744 * of the current enclosing class
2749 ~on_error
:Errors.leave_unchanged_default_invalid_type_hint_code
2751 let (env, declared_ft) =
2755 { use_name
= "lambda"; use_pos = p; explicit_targs
= [] }
2757 ~
def_pos:declared_pos
2761 List.iter idl
(check_escaping_var
env);
2763 (* Ensure lambda arity is not ellipsis in strict mode *)
2765 match declared_ft.ft_arity
with
2766 | Fvariadic
{ fp_name
= None
; _
}
2767 when Partial.should_check_error
(Env.get_mode
env) 4223 ->
2768 Errors.ellipsis_strict_mode ~require
:`Param_name
p
2772 (* Is the return type declared? *)
2773 let is_explicit_ret = Option.is_some
(hint_of_type_hint f
.f_ret
) in
2774 let check_body_under_known_params env ?ret_ty
ft : env * _
* locl_ty
=
2775 let (env, (tefun
, ty, ft)) =
2776 closure_make ?ret_ty
env p f
ft idl
is_anon
2780 ( Reason.Rwitness
p,
2785 ( if is_explicit_ret then
2788 MakeType.unenforced
ty );
2791 (env, tefun
, inferred_ty)
2793 let (env, eexpected
) = expand_expected_and_get_node
env expected in
2794 (* TODO: move this into the expand_expected_and_get_node function and prune its callsites
2795 * Strip like type from function type hint *)
2797 match eexpected with
2798 | Some
(pos, ur, _
, Tunion
[ty1
; ty2
]) when is_dynamic ty1
&& is_fun ty2
2800 Some
(pos, ur, ty2
, get_node ty2
)
2804 match eexpected with
2805 | Some
(_pos
, _ur
, ty, Tfun expected_ft
) ->
2806 (* First check that arities match up *)
2807 check_lambda_arity
p (get_pos
ty) declared_ft expected_ft
;
2808 (* Use declared types for parameters in preference to those determined
2809 * by the context (expected parameters): they might be more general. *)
2810 let rec replace_non_declared_types declared_ft_params expected_ft_params
2812 match (declared_ft_params
, expected_ft_params
) with
2813 | ( declared_ft_param
:: declared_ft_params
,
2814 expected_ft_param
:: expected_ft_params
) ->
2816 replace_non_declared_types declared_ft_params expected_ft_params
2818 (* If the type parameter did not have a type hint, it is Tany and
2819 we use the expected type instead. Otherwise, declared type takes
2821 let resolved_ft_param =
2822 if TUtils.is_any
env declared_ft_param
.fp_type
.et_type
then
2823 { declared_ft_param
with fp_type
= expected_ft_param
.fp_type
}
2827 resolved_ft_param :: rest
2829 (* Morally, this case should match on ([],[]) because we already
2830 check arity mismatch between declared and expected types. We
2831 handle it more generally here to be graceful. *)
2834 (* This means the expected_ft params list can have more parameters
2835 * than declared parameters in the lambda. For variadics, this is OK.
2839 let replace_non_declared_arity variadic declared_arity expected_arity
=
2841 | FVvariadicArg
{ param_type_hint
= (_
, Some _
); _
} -> declared_arity
2842 | FVvariadicArg _
->
2844 match (declared_arity
, expected_arity
) with
2845 | (Fvariadic declared
, Fvariadic
expected) ->
2846 Fvariadic
{ declared
with fp_type
= expected.fp_type
}
2847 | (_
, _
) -> declared_arity
2849 | _
-> declared_arity
2855 replace_non_declared_arity
2857 declared_ft.ft_arity
2858 expected_ft.ft_arity
;
2860 replace_non_declared_types
2861 declared_ft.ft_params
2862 expected_ft.ft_params
;
2863 ft_implicit_params
= declared_ft.ft_implicit_params
;
2866 (* Don't bother passing in `void` if there is no explicit return *)
2868 match get_node
expected_ft.ft_ret
.et_type
with
2869 | Tprim Tvoid
when not
is_explicit_ret -> None
2870 | _
-> Some
expected_ft.ft_ret
.et_type
2872 Typing_log.increment_feature_count
env FL.Lambda.contextual_params
;
2873 check_body_under_known_params env ?
ret_ty expected_ft
2875 let explicit_variadic_param_or_non_variadic =
2876 match f
.f_variadic
with
2877 | FVvariadicArg
{ param_type_hint
; _
} ->
2878 Option.is_some
(hint_of_type_hint param_type_hint
)
2879 | FVellipsis _
-> false
2882 (* If all parameters are annotated with explicit types, then type-check
2883 * the body under those assumptions and pick up the result type *)
2884 let all_explicit_params =
2885 List.for_all f
.f_params
(fun param
->
2886 Option.is_some
(hint_of_type_hint param
.param_type_hint
))
2888 if all_explicit_params && explicit_variadic_param_or_non_variadic then (
2889 Typing_log.increment_feature_count
2891 ( if List.is_empty f
.f_params
then
2894 FL.Lambda.explicit_params
);
2895 check_body_under_known_params env declared_ft
2898 | Some
ExpectedTy.{ ty = { et_type
; _
}; _
} when is_any et_type
->
2899 (* If the expected type is Tany env then we're passing a lambda to
2900 * an untyped function and we just assume every parameter has type
2902 * Note: we should be using 'nothing' to type the arguments. *)
2903 Typing_log.increment_feature_count
env FL.Lambda.untyped_context
;
2904 check_body_under_known_params env declared_ft
2905 | Some
ExpectedTy.{ ty = { et_type
; _
}; _
}
2906 when TUtils.is_mixed
env et_type
|| TUtils.is_dynamic
env et_type
->
2907 (* If the expected type of a lambda is mixed or dynamic, we
2908 * decompose the expected type into a function type where the
2909 * undeclared parameters and the return type are set to the expected
2910 * type of lambda, i.e., mixed or dynamic.
2912 * For an expected mixed type, one could argue that the lambda
2913 * doesn't even need to be checked as it can't be called (there is
2914 * no downcast to function type). Thus, we should be using nothing
2915 * to type the arguments. But generally users are very confused by
2916 * the use of nothing and would expect the lambda body to be
2917 * checked as though it could be called.
2919 let replace_non_declared_type declared_ft_param
=
2921 TUtils.is_any
env declared_ft_param
.fp_type
.et_type
2923 if is_undeclared then
2924 let enforced_ty = { et_enforced
= Unenforced
; et_type
} in
2925 { declared_ft_param
with fp_type
= enforced_ty }
2931 List.map ~f
:replace_non_declared_type declared_ft.ft_params
2933 { declared_ft with ft_params }
2935 let ret_ty = et_type
in
2936 check_body_under_known_params env ~
ret_ty expected_ft
2938 (* If the expected type is something concrete but not a function
2939 * then we should reject in strict mode. Check body anyway.
2940 * Note: we should be using 'nothing' to type the arguments. *)
2941 if Partial.should_check_error
(Env.get_mode
env) 4224 then
2942 Errors.untyped_lambda_strict_mode
p;
2943 Typing_log.increment_feature_count
2945 FL.Lambda.non_function_typed_context
;
2946 check_body_under_known_params env declared_ft
2948 (* If we're in partial mode then type-check definition anyway,
2949 * so treating parameters without type hints as "untyped"
2951 if not
(Env.is_strict
env) then (
2952 Typing_log.increment_feature_count
2954 FL.Lambda.non_strict_unknown_params
;
2955 check_body_under_known_params env declared_ft
2957 Typing_log.increment_feature_count
2959 FL.Lambda.fresh_tyvar_params
;
2961 (* Replace uses of Tany that originated from "untyped" parameters or return type
2962 * with fresh type variables *)
2963 let freshen_ftype env ft =
2964 let freshen_ty env pos et
=
2965 match get_node et
.et_type
with
2967 let (env, ty) = Env.fresh_type
env pos in
2968 (env, { et
with et_type
= ty })
2969 | Tclass
(id, e, [ty])
2970 when String.equal
(snd
id) SN.Classes.cAwaitable
2972 let (env, t
) = Env.fresh_type
env pos in
2976 et_type
= mk
(get_reason et
.et_type
, Tclass
(id, e, [t
]));
2980 let freshen_untyped_param env ft_param
=
2981 let (env, fp_type
) =
2982 freshen_ty env ft_param
.fp_pos ft_param
.fp_type
2984 (env, { ft_param
with fp_type
})
2986 let (env, ft_params) =
2987 List.map_env
env ft.ft_params freshen_untyped_param
2989 let (env, ft_ret
) = freshen_ty env declared_pos
ft.ft_ret
in
2990 (env, { ft with ft_params; ft_ret
})
2992 let (env, declared_ft) = freshen_ftype env declared_ft in
2994 Env.set_tyvar_variance
env (mk
(Reason.Rnone
, Tfun
declared_ft))
2996 (* TODO(jjwu): the declared_ft here is set to public,
2997 but is actually inferred from the surrounding context
2998 (don't think this matters in practice, since we check lambdas separately) *)
2999 check_body_under_known_params
3001 ~
ret_ty:declared_ft.ft_ret
.et_type
3006 | Xml
(sid
, attrl
, el
) ->
3008 let (env, _tal
, _te
, classes
) =
3009 class_id_for_new ~exact
:Nonexact
p env cid []
3011 (* OK to ignore rest of list; class_info only used for errors, and
3012 * cid = CI sid cannot produce a union of classes anyhow *)
3014 List.find_map classes ~f
:(function
3016 | `Class
(_
, class_info, _
) -> Some
class_info)
3018 let (env, te, obj
) =
3019 (* New statements derived from Xml literals are of the following form:
3022 * darray<string,mixed> $attributes,
3023 * varray<mixed> $children,
3028 let new_exp = Typing_xhp.rewrite_xml_into_new
p sid attrl el
in
3029 expr ?
expected env new_exp
3033 | (_
, New
(_
, _
, [_
; (_
, Varray
(_
, children
)); _
; _
], _
, _
)) -> children
3035 (* We end up in this case when the cosntructed new expression does
3039 let (env, typed_attrs
) = xhp_attribute_exprs
env class_info attrl sid obj
in
3040 let txml = Aast.Xml
(sid
, typed_attrs
, tchildren) in
3041 (match class_info with
3042 | None
-> make_result env p txml (mk
(Reason.Runknown_class
p, Tobject
))
3043 | Some _
-> make_result env p txml obj
)
3044 | Callconv
(kind
, e) ->
3045 let (env, te, ty) = expr env e in
3046 make_result env p (Aast.Callconv
(kind
, te)) ty
3048 let (env, fdm_with_expected
) =
3049 match expand_expected_and_get_node
env expected with
3050 | (env, Some
(pos, ur, _
, Tshape
(_
, expected_fdm
))) ->
3054 let tk = TShapeField.of_ast
(fun p -> p) k
in
3055 match TShapeMap.find_opt
tk expected_fdm
with
3056 | None
-> (k
, (v
, None
))
3057 | Some sft
-> (k
, (v
, Some
(ExpectedTy.make
pos ur sft
.sft_ty
))))
3061 | _
-> (env, List.map ~f
:(fun (k
, v
) -> (k
, (v
, None
))) fdm
)
3063 (* allow_inter adds a type-variable *)
3066 ~f
:(fun env (key
, (e, expected)) ->
3067 let (env, te, ty) = expr ?
expected env e in
3068 (env, (key
, (te, ty))))
3073 let convert_expr_and_type_to_shape_field_type env (key
, (_
, ty)) =
3074 (* An expression evaluation always corresponds to a shape_field_type
3075 with sft_optional = false. *)
3076 (env, (key
, { sft_optional
= false; sft_ty
= ty }))
3078 List.map_env ~f
:convert_expr_and_type_to_shape_field_type env tfdm
3082 ~f
:(fun acc
(k
, v
) ->
3083 let tk = TShapeField.of_ast
(fun p -> p) k
in
3084 TShapeMap.add
tk v acc
)
3085 ~
init:TShapeMap.empty
3088 let env = check_shape_keys_validity
env p (List.map tfdm ~f
:fst
) in
3089 (* Fields are fully known, because this shape is constructed
3090 * using shape keyword and we know exactly what fields are set. *)
3094 (Aast.Shape
(List.map ~f
:(fun (k
, (te, _
)) -> (k
, te)) tfdm
))
3095 (mk
(Reason.Rwitness
p, Tshape
(Closed_shape
, fdm)))
3096 | ET_Splice
e -> et_splice
{ env with in_expr_tree
= true } p e
3098 Errors.atom_as_expr
p;
3099 make_result env p (Aast.EnumAtom
s) (mk
(Reason.Rwitness
p, Terr
))
3101 (* let ty = err_witness env cst_pos in *)
3102 and class_const ?
(incl_tc
= false) env p ((cpos
, cid), mid
) =
3103 let (env, _tal
, ce
, cty
) =
3104 static_class_id ~check_constraints
:true cpos
env [] cid
3107 match get_node cty
with
3108 | Tclass
((_
, n
), _
, _
) when Env.is_enum_class
env n
->
3109 Typing_local_ops.enforce_enum_class_variant
p env
3112 let (env, (const_ty
, _tal
)) =
3117 ~coerce_from_ty
:None
3123 make_result env p (Aast.Class_const
(ce
, mid
)) const_ty
3125 (*****************************************************************************)
3126 (* XHP attribute/body helpers. *)
3127 (*****************************************************************************)
3128 and xhp_attribute_decl_ty
env sid obj attr
=
3129 let (namepstr
, valpty
) = attr
in
3130 let (valp
, valty
) = valpty
in
3131 let (env, (declty
, _tal
)) =
3137 ~coerce_from_ty
:None
3141 ~on_error
:Errors.unify_error
3145 let ureason = Reason.URxhp
(snd sid
, snd namepstr
) in
3147 Typing_coercion.coerce_type
3152 (MakeType.unenforced declty
)
3153 Errors.xhp_attribute_does_not_match_hint
3158 * Process a spread operator by computing the intersection of XHP attributes
3159 * between the spread expression and the XHP constructor onto which we're
3162 and xhp_spread_attribute
env c_onto valexpr sid obj
=
3163 let (p, _
) = valexpr
in
3164 let (env, te, valty
) = expr env valexpr ~allow_awaitable
:(*?*) false in
3165 (* Build the typed attribute node *)
3166 let typed_attr = Aast.Xhp_spread
te in
3167 let (env, attr_ptys
) =
3170 | Some
class_info -> Typing_xhp.get_spread_attributes
env p class_info valty
3177 let (env, _
) = xhp_attribute_decl_ty
env sid obj attr
in
3184 * Simple XHP attributes (attr={expr} form) are simply interpreted as a member
3185 * variable prefixed with a colon.
3187 and xhp_simple_attribute
env id valexpr sid obj
=
3188 let (p, _
) = valexpr
in
3189 let (env, te, valty
) = expr env valexpr ~allow_awaitable
:(*?*) false in
3190 (* This converts the attribute name to a member name. *)
3191 let name = ":" ^ snd
id in
3192 let attr_pty = ((fst
id, name), (p, valty
)) in
3193 let (env, decl_ty
) = xhp_attribute_decl_ty
env sid obj
attr_pty in
3195 Aast.Xhp_simple
{ xs_name
= id; xs_type
= decl_ty
; xs_expr
= te }
3200 * Typecheck the attribute expressions - this just checks that the expressions are
3201 * valid, not that they match the declared type for the attribute and,
3202 * in case of spreads, makes sure they are XHP.
3204 and xhp_attribute_exprs
env cls_decl attrl sid obj
=
3205 let handle_attr (env, typed_attrl
) attr
=
3206 let (env, typed_attr) =
3208 | Xhp_simple
{ xs_name
= id; xs_expr
= valexpr
; _
} ->
3209 xhp_simple_attribute
env id valexpr sid obj
3210 | Xhp_spread valexpr
-> xhp_spread_attribute
env cls_decl valexpr sid obj
3212 (env, typed_attr :: typed_attrl
)
3214 let (env, typed_attrl
) =
3215 List.fold_left ~f
:handle_attr ~
init:(env, []) attrl
3217 (env, List.rev typed_attrl
)
3219 (*****************************************************************************)
3220 (* Anonymous functions & lambdas. *)
3221 (*****************************************************************************)
3222 and closure_bind_param
params (env, t_params
) ty : env * Tast.fun_param list
=
3225 (* This code cannot be executed normally, because the arity is wrong
3226 * and it will error later. Bind as many parameters as we can and carry
3229 | param
:: paraml
->
3231 (match hint_of_type_hint param
.param_type_hint
with
3234 (* When creating a closure, the 'this' type will mean the
3235 * late bound type of the current enclosing class
3237 let (env, h
) = Phase.localize_hint_with_self
env ~ignore_errors
:false h
in
3239 Typing_coercion.coerce_type
3244 (MakeType.unenforced h
)
3247 (* Closures are allowed to have explicit type-hints. When
3248 * that is the case we should check that the argument passed
3249 * is compatible with the type-hint.
3250 * The body of the function should be type-checked with the
3251 * hint and not the type of the argument passed.
3252 * Otherwise it leads to strange results where
3253 * foo(?string $x = null) is called with a string and fails to
3254 * type-check. If $x is a string instead of ?string, null is not
3255 * subtype of string ...
3257 let (env, t_param
) = bind_param env (h
, param
) in
3258 (env, t_params
@ [t_param
])
3261 mk
(Reason.Rlambda_param
(param
.param_pos
, get_reason
ty), get_node
ty)
3263 let (env, t_param
) = bind_param env (ty, param
) in
3264 (env, t_params
@ [t_param
]))
3266 and closure_bind_variadic
env vparam variadic_ty
=
3267 let (env, ty, pos) =
3268 match hint_of_type_hint vparam
.param_type_hint
with
3270 (* if the hint is missing, use the type we expect *)
3271 (env, variadic_ty
, get_pos variadic_ty
)
3274 Phase.localize_hint_with_self
env ~ignore_errors
:false hint
3276 let pos = get_pos h
in
3278 Typing_coercion.coerce_type
3283 (MakeType.unenforced h
)
3286 (env, h
, vparam
.param_pos
)
3288 let r = Reason.Rvar_param
pos in
3289 let arr_values = mk
(r, get_node
ty) in
3290 let unification = TypecheckerOptions.hack_arr_dv_arrs
(Env.get_tcopt
env) in
3291 let ty = MakeType.varray ~
unification r arr_values in
3292 let (env, t_variadic
) = bind_param env (ty, vparam
) in
3295 and closure_bind_opt_param
env param
: env =
3296 match param
.param_expr
with
3298 let ty = Typing_utils.mk_tany
env param
.param_pos
in
3299 let (env, _
) = bind_param env (ty, param
) in
3302 let (env, _te
, ty) = expr env default ~allow_awaitable
:(*?*) false in
3303 Typing_sequencing.sequence_check_expr default
;
3304 let (env, _
) = bind_param env (ty, param
) in
3307 and closure_check_param
env param
=
3308 match hint_of_type_hint param
.param_type_hint
with
3312 Phase.localize_hint_with_self
env ~ignore_errors
:false hty
3314 let paramty = Env.get_local
env (Local_id.make_unscoped param
.param_name
) in
3315 let hint_pos = get_pos hty
in
3317 Typing_coercion.coerce_type
3322 (MakeType.unenforced hty
)
3327 and stash_conts_for_closure
env p is_anon captured f
=
3329 if is_anon && TypecheckerOptions.any_coeffects
(Env.get_tcopt
env) then
3331 (Pos.none
, local_capability_id
) :: (Pos.none
, capability_id
) :: captured)
3336 if Env.is_local_defined
env this
then
3337 (Pos.none
, this
) :: captured
3342 Option.map (Env.next_cont_opt
env) ~f
:(fun next_cont
->
3343 let initial_locals =
3345 Env.get_locals
env captured
3347 next_cont
.Typing_per_cont_env.local_types
3350 Fake.forget
(Env.get_fake_members
env) Reason.(Blame
(p, BSlambda
))
3352 let tpenv = Env.get_tpenv
env in
3353 (initial_locals, initial_fakes, tpenv))
3355 Typing_lenv.stash_and_do
env (Env.all_continuations
env) (fun env ->
3359 | Some
(initial_locals, initial_fakes, tpenv) ->
3360 let env = Env.reinitialize_locals
env in
3361 let env = Env.set_locals
env initial_locals in
3362 let env = Env.set_fake_members
env initial_fakes in
3363 let env = Env.env_with_tpenv
env tpenv in
3368 (* Make a type-checking function for an anonymous function or lambda. *)
3369 (* Here ret_ty should include Awaitable wrapper *)
3370 (* TODO: ?el is never set; so we need to fix variadic use of lambda *)
3371 and closure_make ?el ?
ret_ty env lambda_pos f
ft idl
is_anon =
3372 let nb = Nast.assert_named_body f
.f_body
in
3373 Env.closure
env.lenv env (fun env ->
3374 (* Extract capabilities from AAST and add them to the environment *)
3375 let (env, capability
) =
3376 match (f
.f_ctxs
, f
.f_unsafe_ctxs
) with
3378 (* if the closure has no explicit coeffect annotations,
3379 do _not_ insert (unsafe) capabilities into the environment;
3380 instead, rely on the fact that a capability from an enclosing
3381 scope can simply be captured, which has the same semantics
3382 as redeclaring and shadowing with another same-typed capability.
3383 This avoid unnecessary overhead in the most common case, i.e.,
3384 when a closure does not need a different (usually smaller)
3385 set of capabilities. *)
3386 (env, Env.get_local
env Typing_coeffects.local_capability_id
)
3388 let (env, cap_ty
, unsafe_cap_ty
) =
3389 type_capability
env f
.f_ctxs f
.f_unsafe_ctxs
(fst f
.f_name
)
3391 Typing_coeffects.register_capabilities
env cap_ty unsafe_cap_ty
3394 { ft with ft_implicit_params
= { capability
= CapTy capability
} }
3396 stash_conts_for_closure
env lambda_pos
is_anon idl
(fun env ->
3397 let env = Env.clear_params
env in
3398 let make_variadic_arg env varg tyl
=
3399 let remaining_types =
3400 (* It's possible the variadic arg will capture the variadic
3401 * parameter of the supplied arity (if arity is Fvariadic)
3402 * and additional supplied params.
3404 * For example in cases such as:
3405 * lambda1 = (int $a, string...$c) ==> {};
3406 * lambda1(1, "hello", ...$y); (where $y is a variadic string)
3407 * lambda1(1, "hello", "world");
3408 * then ...$c will contain "hello" and everything in $y in the first
3409 * example, and "hello" and "world" in the second example.
3411 * To account for a mismatch in arity, we take the remaining supplied
3412 * parameters and return a list of all their types. We'll use this
3413 * to create a union type when creating the typed variadic arg.
3415 let remaining_params =
3416 List.drop
ft.ft_params (List.length f
.f_params
)
3418 List.map ~f
:(fun param
-> param
.fp_type
.et_type
) remaining_params
3420 let r = Reason.Rvar_param varg
.param_pos
in
3421 let union = Tunion
(tyl
@ remaining_types) in
3422 let (env, t_param
) =
3423 closure_bind_variadic
env varg
(mk
(r, union))
3425 (env, Aast.FVvariadicArg t_param
)
3427 let (env, t_variadic
) =
3428 match (f
.f_variadic
, ft.ft_arity
) with
3429 | (FVvariadicArg arg
, Fvariadic variadic
) ->
3430 make_variadic_arg env arg
[variadic
.fp_type
.et_type
]
3431 | (FVvariadicArg arg
, Fstandard
) -> make_variadic_arg env arg
[]
3432 | (FVellipsis
pos, _
) -> (env, Aast.FVellipsis
pos)
3433 | (_
, _
) -> (env, Aast.FVnonVariadic
)
3435 let params = ref f
.f_params
in
3436 let (env, t_params
) =
3438 ~f
:(closure_bind_param
params)
3440 (List.map ft.ft_params (fun x
-> x
.fp_type
.et_type
))
3443 List.fold_left ~f
:closure_bind_opt_param ~
init:env !params
3446 List.fold_left ~f
:closure_check_param ~
init:env f
.f_params
3452 Unify.unify_param_modes
3458 match f
.f_variadic
with
3461 TUtils.default_fun_param
3463 (mk
(Reason.Rvar_param
pos, Typing_defs.make_tany
()))
3468 let rec iter l1 l2
=
3469 match (l1
, l2
, var_param) with
3471 | ([], _
, None
) -> ()
3472 | ([], x2
:: rl2
, Some def1
) ->
3473 param_modes ~is_variadic
:true def1 x2
;
3475 | (x1
:: rl1
, x2
:: rl2
, _
) ->
3479 iter ft.ft_params x
;
3480 wfold_left2 inout_write_back
env ft.ft_params x
3482 let env = Env.set_fn_kind
env f
.f_fun_kind
in
3485 ~f
:(Decl_hint.hint
env.decl_env
)
3486 (hint_of_type_hint f
.f_ret
)
3491 (* Do we have a contextual return type? *)
3495 let (env, ret_ty) = Env.fresh_type
env lambda_pos
in
3496 (env, Typing_return.wrap_awaitable
env lambda_pos
ret_ty)
3498 (* We might need to force it to be Awaitable if it is a type variable *)
3499 Typing_return.force_awaitable
env lambda_pos
ret_ty
3502 (* If a 'this' type appears it needs to be compatible with the
3509 Errors.leave_unchanged_default_invalid_type_hint_code
3511 Typing_return.make_return_type
(Phase.localize ~
ety_env) env ret
3516 (Typing_return.make_info
3520 ~is_explicit
:(Option.is_some
ret_ty)
3524 let local_tpenv = Env.get_tpenv
env in
3525 (* Outer pipe variables aren't available in closures. Note that
3526 * locals are restored by Env.closure after processing the closure
3531 (Local_id.make_unscoped
SN.SpecialIdents.dollardollar
)
3533 let (env, tb) = block
env nb.fb_ast
in
3534 let has_implicit_return = LEnv.has_next
env in
3535 let named_body_is_unsafe = Nast.named_body_is_unsafe nb in
3537 if (not
has_implicit_return) || Nast.named_body_is_unsafe nb then
3540 fun_implicit_return
env lambda_pos hret f
.f_fun_kind
3543 Typing_env.set_fun_tast_info
3545 { Tast.has_implicit_return; Tast.named_body_is_unsafe }
3547 let (env, tparams
) = List.map_env
env f
.f_tparams type_param
in
3548 let (env, user_attributes
) =
3549 List.map_env
env f
.f_user_attributes user_attribute
3553 Aast.f_annotation
= Env.save
local_tpenv env;
3554 Aast.f_span
= f
.f_span
;
3555 Aast.f_mode
= f
.f_mode
;
3556 Aast.f_ret
= (hret
, hint_of_type_hint f
.f_ret
);
3557 Aast.f_readonly_ret
= f
.f_readonly_ret
;
3558 Aast.f_name
= f
.f_name
;
3559 Aast.f_tparams
= tparams
;
3560 Aast.f_where_constraints
= f
.f_where_constraints
;
3561 Aast.f_fun_kind
= f
.f_fun_kind
;
3562 Aast.f_file_attributes
= [];
3563 Aast.f_user_attributes
= user_attributes
;
3564 Aast.f_body
= { Aast.fb_ast
= tb; fb_annotation
= () };
3565 Aast.f_ctxs
= f
.f_ctxs
;
3566 Aast.f_unsafe_ctxs
= f
.f_unsafe_ctxs
;
3567 Aast.f_params
= t_params
;
3568 Aast.f_variadic
= t_variadic
;
3569 (* TODO TAST: Variadic efuns *)
3570 Aast.f_external
= f
.f_external
;
3571 Aast.f_namespace
= f
.f_namespace
;
3572 Aast.f_doc_comment
= f
.f_doc_comment
;
3573 Aast.f_static
= f
.f_static
;
3576 let ty = mk
(Reason.Rwitness lambda_pos
, Tfun
ft) in
3578 Tast.make_typed_expr
3582 Aast.Efun
(tfun_, idl
)
3584 Aast.Lfun
(tfun_, idl
) )
3586 let env = Env.set_tyvar_variance
env ty in
3587 (env, (te, hret
, ft))
3588 (* stash_conts_for_anon *))
3591 (*****************************************************************************)
3592 (* End of anonymous functions & lambdas. *)
3593 (*****************************************************************************)
3595 (*****************************************************************************)
3596 (* Expression trees *)
3597 (*****************************************************************************)
3598 and expression_tree
env p et
=
3599 let (env, t_desugared_expr
, ty_desugared
) =
3600 expr env et
.et_desugared_expr ~allow_awaitable
:(*?*) false
3605 (Aast.ExpressionTree
3606 { et_hint
= et
.et_hint
; et_desugared_expr
= t_desugared_expr
})
3609 and et_splice
env p e =
3610 let (env, te, ty) = expr env e ~allow_awaitable
:(*?*) false in
3611 let (env, ty_visitor
) = Env.fresh_type
env p in
3612 let (env, ty_res
) = Env.fresh_type
env p in
3613 let (env, ty_infer
) = Env.fresh_type
env p in
3614 let spliceable_type =
3615 MakeType.spliceable
(Reason.Rsplice
p) ty_visitor ty_res ty_infer
3617 let env = SubType.sub_type
env ty spliceable_type Errors.unify_error
in
3618 make_result env p (Aast.ET_Splice
te) ty_infer
3620 (*****************************************************************************)
3621 (* End expression trees *)
3622 (*****************************************************************************)
3623 and type_capability
env ctxs unsafe_ctxs default_pos
=
3624 (* No need to repeat the following check (saves time) for unsafe_ctx
3625 because it's synthetic and well-kinded by construction *)
3626 Option.iter ctxs ~f
:(fun (_pos
, hl
) ->
3627 List.iter hl
(Typing_kinding.Simple.check_well_kinded_hint
env));
3629 let cc = Decl_hint.aast_contexts_to_decl_capability
in
3630 let (decl_pos
, (env, cap_ty
)) =
3631 match cc env.decl_env ctxs default_pos
with
3633 (get_pos
ty, Phase.localize_with_self
env ~ignore_errors
:false ty)
3634 | CapDefaults
p -> (p, (env, MakeType.default_capability
p))
3636 if TypecheckerOptions.strict_contexts
(Env.get_tcopt
env) then
3637 Typing_coeffects.validate_capability
env decl_pos cap_ty
;
3638 let (env, unsafe_cap_ty
) =
3639 match cc env.decl_env unsafe_ctxs default_pos
with
3640 | CapTy
ty -> Phase.localize_with_self
env ~ignore_errors
:false ty
3642 (* default is no unsafe capabilities *)
3643 (env, MakeType.mixed (Reason.Rhint
p))
3645 (env, cap_ty
, unsafe_cap_ty
)
3647 and requires_consistent_construct
= function
3654 (* Caller will be looking for a particular form of expected type
3655 * e.g. a function type (when checking lambdas) or tuple type (when checking
3656 * tuples). First expand the expected type and elide single union; also
3657 * strip nullables, so ?t becomes t, as context will always accept a t if a ?t
3660 and expand_expected_and_get_node
env (expected : ExpectedTy.t
option) =
3662 | None
-> (env, None
)
3663 | Some
ExpectedTy.{ pos = p; reason = ur; ty = { et_type
= ty; _
}; _
} ->
3664 let (env, ty) = Env.expand_type
env ty in
3665 (match get_node
ty with
3666 | Tunion
[ty] -> (env, Some
(p, ur, ty, get_node
ty))
3667 | Toption
ty -> (env, Some
(p, ur, ty, get_node
ty))
3668 | _
-> (env, Some
(p, ur, ty, get_node
ty)))
3670 (** Do a subtype check of inferred type against expected type *)
3671 and check_expected_ty message
env inferred_ty (expected : ExpectedTy.t
option) =
3674 | Some
ExpectedTy.{ pos = p; reason = ur; ty } ->
3676 log_with_level
env "typing" 1 (fun () ->
3683 "Typing.check_expected_ty %s enforced=%s"
3685 (match ty.et_enforced
with
3686 | Unenforced
-> "unenforced"
3687 | Enforced
-> "enforced"
3688 | PartiallyEnforced
-> "partially enforced"),
3690 Log_type
("inferred_ty", inferred_ty);
3691 Log_type
("expected_ty", ty.et_type
);
3694 Typing_coercion.coerce_type
p ur env inferred_ty ty Errors.unify_error
3697 ~
(expected : ExpectedTy.t
option)
3707 (* Obtain class info from the cid expression. We get multiple
3708 * results with a CIexpr that has a union type, e.g. in
3710 $classname = (mycond()? classname<A>: classname<B>);
3713 let (env, tal
, tcid
, classes
) =
3714 instantiable_cid ~exact
:Exact
p env cid explicit_targs
3716 let allow_abstract_bound_generic =
3718 | ((_
, ty), Aast.CI
(_
, tn
)) -> is_generic_equal_to tn
ty
3721 let gather (env, _tel
, _typed_unpack_element
) (cname
, class_info, c_ty
) =
3724 && Cls.abstract
class_info
3725 && (not
(requires_consistent_construct
cid))
3726 && not
allow_abstract_bound_generic
3728 uninstantiable_error
3732 (Cls.pos class_info)
3733 (Cls.name class_info)
3736 let (env, obj_ty_
, params) =
3737 let (env, c_ty
) = Env.expand_type
env c_ty
in
3738 match (cid, tal
, get_class_type c_ty
) with
3739 (* Explicit type arguments *)
3740 | (CI _
, _
:: _
, Some
(_
, _
, tyl
)) -> (env, get_node c_ty
, tyl
)
3741 | (_
, _
, class_type_opt
) ->
3743 List.map_env
env (Cls.tparams
class_info) (fun env tparam ->
3745 Env.fresh_type_reason
3747 (Reason.Rtype_variable_generics
3748 (p, snd
tparam.tp_name
, strip_ns
(snd cname
)))
3750 Typing_log.log_new_tvar_for_new_object
env p tvar cname
tparam;
3754 match class_type_opt
with
3755 | Some
(_
, Exact
, _
) -> (env, Tclass
(cname
, Exact
, params), params)
3756 | _
-> (env, Tclass
(cname
, Nonexact
, params), params)
3761 && (not is_using_clause
)
3762 && Cls.is_disposable
class_info
3764 Errors.invalid_new_disposable
p;
3765 let r_witness = Reason.Rwitness
p in
3766 let obj_ty = mk
(r_witness, obj_ty_
) in
3771 mk
(r_witness, get_node
c_ty)
3775 let ((_
, cid_ty
), _
) = tcid
in
3776 let (env, cid_ty
) = Env.expand_type
env cid_ty
in
3777 if is_generic cid_ty
then
3779 else if check_parent
then
3782 ExprDepTy.make
env cid c_ty
3784 (* Set variance according to type of `new` expression now. Lambda arguments
3785 * to the constructor might depend on it, and `call_construct` only uses
3786 * `ctor_fty` to set the variance which has void return type *)
3787 let env = Env.set_tyvar_variance
env new_ty
in
3788 let (env, tel
, typed_unpack_element
, ctor_fty
) =
3789 let env = check_expected_ty
"New" env new_ty
expected in
3790 call_construct
p env class_info params el unpacked_element
cid new_ty
3792 ( if equal_consistent_kind
(snd
(Cls.construct
class_info)) Inconsistent
then
3794 | CIstatic
-> Errors.new_inconsistent_construct
p cname `static
3795 | CIexpr _
-> Errors.new_inconsistent_construct
p cname `
classname
3799 let (env, ctor_fty
) =
3800 match fst
(Cls.construct
class_info) with
3801 | Some
({ ce_type
= (lazy ty); _
} as ce
) ->
3804 type_expansions
= [];
3806 TUtils.make_locl_subst_for_class_tparams
class_info params;
3808 on_error
= Errors.ignore_error
;
3811 if get_ce_abstract ce
then
3812 Errors.parent_abstract_call
3813 SN.Members.__construct
3816 let (env, ctor_fty
) = Phase.localize ~
ety_env env ty in
3818 | None
-> (env, ctor_fty
)
3820 ((env, tel
, typed_unpack_element
), (obj_ty, ctor_fty
))
3824 ((env, tel
, typed_unpack_element
), (c_ty, ctor_fty
))
3826 (* When constructing from a (classname) variable, the variable
3827 * dictates what the constructed object is going to be. This allows
3828 * for generic and dependent types to be correctly carried
3829 * through the 'new $foo()' iff the constructed obj_ty is a
3830 * supertype of the variable-dictated c_ty *)
3832 Typing_ops.sub_type
p Reason.URnone
env c_ty obj_ty Errors.unify_error
3834 ((env, tel
, typed_unpack_element
), (c_ty, ctor_fty
))
3836 let (had_dynamic
, classes
) =
3837 List.fold classes ~
init:(false, []) ~f
:(fun (seen_dynamic
, classes
) ->
3839 | `Dynamic
-> (true, classes
)
3840 | `Class
(cname
, class_info, c_ty) ->
3841 (seen_dynamic
, (cname
, class_info, c_ty) :: classes
))
3843 let ((env, tel
, typed_unpack_element
), class_types_and_ctor_types
) =
3844 List.fold_map classes ~
init:(env, [], None
) ~f
:gather
3846 let class_types_and_ctor_types =
3847 let r = Reason.Rdynamic_construct
p in
3848 let dyn = (mk
(r, Tdynamic
), mk
(r, Tdynamic
)) in
3850 dyn :: class_types_and_ctor_types
3852 class_types_and_ctor_types
3854 let (env, tel
, typed_unpack_element
, ty, ctor_fty
) =
3855 match class_types_and_ctor_types with
3857 let (env, tel
, _
) = exprs env el ~allow_awaitable
:(*?*) false in
3858 let (env, typed_unpack_element
, _
) =
3859 match unpacked_element
with
3860 | None
-> (env, None
, MakeType.nothing
Reason.Rnone
)
3861 | Some unpacked_element
->
3863 expr env unpacked_element ~allow_awaitable
:(*?*) false
3867 let r = Reason.Runknown_class
p in
3868 (env, tel
, typed_unpack_element
, mk
(r, Tobject
), TUtils.terr
env r)
3869 | [(ty, ctor_fty
)] -> (env, tel
, typed_unpack_element
, ty, ctor_fty
)
3871 let (tyl
, ctyl
) = List.unzip l
in
3872 let r = Reason.Rwitness
p in
3873 (env, tel
, typed_unpack_element
, mk
(r, Tunion tyl
), mk
(r, Tunion ctyl
))
3876 let ((_
, cid_ty
), _
) = tcid
in
3877 let (env, cid_ty
) = Env.expand_type
env cid_ty
in
3878 if is_generic cid_ty
then
3880 else if check_parent
then
3883 ExprDepTy.make
env cid ty
3885 (env, tcid
, tal
, tel
, typed_unpack_element
, new_ty
, ctor_fty
)
3887 and attributes_check_def
env kind attrs
=
3888 (* TODO(coeffects) change to mixed after changing those constructors to pure *)
3889 let defaults = MakeType.default_capability
Pos.none
in
3891 Typing_lenv.stash_and_do
env (Env.all_continuations
env) (fun env ->
3893 fst
@@ Typing_coeffects.register_capabilities
env defaults defaults
3895 (Typing_attributes.check_def
env new_object kind attrs
, ()))
3899 (** Get class infos for a class expression (e.g. `parent`, `self` or
3900 regular classnames) - which might resolve to a union or intersection
3901 of classes - and check they are instantiable.
3903 FIXME: we need to separate our instantiability into two parts. Currently,
3904 all this function is doing is checking if a given type is inhabited --
3905 that is, whether there are runtime values of type Aast. However,
3906 instantiability should be the stricter notion that T has a runtime
3907 constructor; that is, `new T()` should be valid. In particular, interfaces
3908 are inhabited, but not instantiable.
3909 To make this work with classname, we likely need to add something like
3910 concrete_classname<T>, where T cannot be an interface. *)
3911 and instantiable_cid ?
(exact
= Nonexact
) p env cid explicit_targs
:
3912 newable_class_info
=
3913 let (env, tal
, te, classes
) =
3914 class_id_for_new ~exact
p env cid explicit_targs
3916 List.iter classes
(function
3918 | `Class
((pos, name), class_info, c_ty) ->
3920 Ast_defs.(equal_class_kind
(Cls.kind
class_info) Ctrait
)
3921 || Ast_defs.(equal_class_kind
(Cls.kind
class_info) Cenum
)
3926 uninstantiable_error
env p cid (Cls.pos class_info) name pos c_ty
3932 Ast_defs.(equal_class_kind
(Cls.kind
class_info) Cabstract
)
3933 && Cls.final
class_info
3935 uninstantiable_error
env p cid (Cls.pos class_info) name pos c_ty
3938 (env, tal
, te, classes
)
3940 and uninstantiable_error
env reason_pos
cid c_tc_pos c_name c_usage_pos
c_ty =
3944 let ty_str = "This would be " ^
Typing_print.error
env c_ty in
3945 Some
(reason_pos
, ty_str)
3948 Errors.uninstantiable_class c_usage_pos c_tc_pos c_name
reason
3950 and coerce_to_throwable
pos env exn_ty
=
3951 let throwable_ty = MakeType.throwable
(Reason.Rthrow
pos) in
3952 Typing_coercion.coerce_type
3957 { et_type
= throwable_ty; et_enforced
= Unenforced
}
3960 and shape_field_pos
= function
3961 | Ast_defs.SFlit_int
(p, _
)
3962 | Ast_defs.SFlit_str
(p, _
) ->
3964 | Ast_defs.SFclass_const
((cls_pos
, _
), (mem_pos
, _
)) ->
3965 Pos.btw cls_pos mem_pos
3967 and check_shape_keys_validity
:
3968 env -> pos -> Ast_defs.shape_field_name list
-> env =
3970 (* If the key is a class constant, get its class name and type. *)
3971 let get_field_info env key
=
3972 let key_pos = shape_field_pos key
in
3973 (* Empty strings or literals that start with numbers are not
3974 permitted as shape field names. *)
3976 | Ast_defs.SFlit_int _
-> (env, key_pos, None
)
3977 | Ast_defs.SFlit_str
(_
, key_name
) ->
3978 if Int.equal
0 (String.length key_name
) then
3979 Errors.invalid_shape_field_name_empty
key_pos;
3980 (env, key_pos, None
)
3981 | Ast_defs.SFclass_const
(((p, cls
) as x
), y
) ->
3982 let (env, _te
, ty) = class_const
env pos ((p, CI x
), y
) in
3983 let r = Reason.Rwitness
key_pos in
3990 (MakeType.arraykey r)
3992 Errors.invalid_shape_field_type
3995 (Typing_print.error
env ty)
3998 (env, key_pos, Some
(cls
, ty))
4000 let check_field witness_pos witness_info
env key
=
4001 let (env, key_pos, key_info
) = get_field_info env key
in
4002 match (witness_info
, key_info
) with
4004 Errors.invalid_shape_field_literal
key_pos witness_pos
;
4007 Errors.invalid_shape_field_const
key_pos witness_pos
;
4009 | (None
, None
) -> env
4010 | (Some
(cls1
, ty1
), Some
(cls2
, ty2
)) ->
4011 if String.( <> ) cls1 cls2
then
4012 Errors.shape_field_class_mismatch
4019 ( Typing_solver.is_sub_type
env ty1 ty2
4020 && Typing_solver.is_sub_type
env ty2 ty1
)
4022 Errors.shape_field_type_mismatch
4025 (Typing_print.error
env ty2
)
4026 (Typing_print.error
env ty1
);
4029 (* Sort the keys by their positions since the error messages will make
4030 * more sense if we take the one that appears first as canonical and if
4031 * they are processed in source order. *)
4032 let cmp_keys x y
= Pos.compare
(shape_field_pos x
) (shape_field_pos y
) in
4033 let keys = List.sort ~compare
:cmp_keys keys in
4036 | witness
:: rest_keys
->
4037 let (env, pos, info
) = get_field_info env witness
in
4038 List.fold_left ~f
:(check_field pos info
) ~
init:env rest_keys
4040 and set_valid_rvalue
p env x
ty =
4041 let env = set_local
env (p, x
) ty in
4042 (* We are assigning a new value to the local variable, so we need to
4043 * generate a new expression id
4045 Env.set_local_expr_id
env x
(Ident.tmp
())
4047 (* Produce an error if assignment is used in the scope of the |> operator, i.e.
4048 * if $$ is in scope *)
4049 and error_if_assign_in_pipe
p env =
4050 let dd_var = Local_id.make_unscoped
SN.SpecialIdents.dollardollar
in
4051 let dd_defined = Env.is_local_defined
env dd_var in
4053 Errors.unimplemented_feature
p "Assignment within pipe expressions"
4055 (* Deal with assignment of a value of type ty2 to lvalue e1 *)
4056 and assign
p env e1 ty2
: _
* Tast.expr * Tast.ty =
4057 error_if_assign_in_pipe
p env;
4058 assign_
p Reason.URassign
env e1 ty2
4060 and is_hack_collection
env ty =
4061 (* TODO(like types) This fails if a collection is used as a parameter under
4062 * pessimization, because ~Vector<int> </: ConstCollection<mixed>. This is the
4063 * test we use to see whether to update the expression id for expressions
4064 * $vector[0] = $x and $vector[] = $x. If this is false, the receiver is assumed
4065 * to be a Hack array which are COW. This approximation breaks down in the presence
4066 * of dynamic. It is unclear whether we should change an expression id if the
4067 * receiver is dynamic. *)
4068 Typing_solver.is_sub_type
4071 (MakeType.const_collection
Reason.Rnone
(MakeType.mixed Reason.Rnone
))
4073 and assign_
p ur env e1 ty2
=
4074 let allow_awaitable = (*?*) false in
4077 | (_
, Lvar
(_
, x
)) ->
4078 Env.forget_prefixed_members
env x
Reason.(Blame
(p, BSassignment
))
4079 (* If we ever extend fake members from $x->a to more complicated lvalues
4080 such as $x->a->b, we would need to call forget_prefixed_members on
4081 other lvalues as well. *)
4082 | (_
, Obj_get
(_
, (_
, Id
(_
, property
)), _
, _
)) ->
4083 Env.forget_suffixed_members
env property
Reason.(Blame
(p, BSassignment
))
4087 | (_
, Lvar
((_
, x
) as id)) ->
4088 let env = set_valid_rvalue
p env x ty2
in
4089 make_result env (fst e1
) (Aast.Lvar
id) ty2
4090 | (_
, Lplaceholder
id) ->
4091 let placeholder_ty = MakeType.void
(Reason.Rplaceholder
p) in
4092 make_result env (fst e1
) (Aast.Lplaceholder
id) placeholder_ty
4095 List.map_env
env el ~f
:(fun env _
-> Env.fresh_type
env (get_pos ty2
))
4097 let destructure_ty =
4098 MakeType.list_destructure
(Reason.Rdestructure
(fst e1
)) tyl
4100 let lty2 = LoclType ty2
in
4101 let env = Type.sub_type_i
p ur env lty2 destructure_ty Errors.unify_error
in
4102 let env = Env.set_tyvar_variance_i
env destructure_ty in
4103 let (env, reversed_tel
) =
4104 List.fold2_exn el tyl ~
init:(env, []) ~f
:(fun (env, tel
) lvalue ty2
->
4105 let (env, te, _
) = assign
p env lvalue ty2
in
4108 make_result env (fst e1
) (Aast.List
(List.rev reversed_tel
)) ty2
4110 Obj_get
(obj
, (pm
, Id
((_
, member_name
) as m
)), nullflavor
, in_parens
) )
4112 let lenv = env.lenv in
4114 match nullflavor
with
4115 | OG_nullthrows
-> None
4116 | OG_nullsafe
-> Some
(Reason.Rnullsafe_op pobj
)
4118 let (env, tobj
, obj_ty) =
4119 expr ~accept_using_var
:true env obj ~
allow_awaitable
4121 let env = might_throw
env in
4122 let (env, (result
, _tal
)) =
4128 ~coerce_from_ty
:(Some
(p, ur, ty2
))
4130 ~class_id
:(CIexpr e1
)
4132 ~on_error
:Errors.unify_error
4137 Tast.make_typed_expr
4142 Tast.make_typed_expr pm result
(Aast.Id m
),
4146 let env = { env with lenv } in
4150 let (env, local) = Env.FakeMembers.make
env obj member_name
p in
4151 let env = set_valid_rvalue
p env local ty2
in
4154 let (env, local) = Env.FakeMembers.make
env obj member_name
p in
4155 let env = set_valid_rvalue
p env local ty2
in
4157 | _
-> (env, te1, ty2
)
4160 let lenv = env.lenv in
4161 let no_fakes = LEnv.env_with_empty_fakes
env in
4162 let (env, te1, real_type
) = lvalue
no_fakes e1
in
4163 let (env, exp_real_type
) = Env.expand_type
env real_type
in
4164 let env = { env with lenv } in
4166 Typing_coercion.coerce_type
4171 (MakeType.unenforced exp_real_type
)
4175 | (_
, Class_get
(_
, CGexpr _
, _
)) ->
4176 failwith
"AST should not have any CGexprs after naming"
4177 | (_
, Class_get
((pos_classid
, x
), CGstring
(pos_member
, y
), _
)) ->
4178 let lenv = env.lenv in
4179 let no_fakes = LEnv.env_with_empty_fakes
env in
4180 let (env, te1, _
) = lvalue
no_fakes e1
in
4181 let env = { env with lenv } in
4182 let (env, ety2
) = Env.expand_type
env ty2
in
4183 (* This defers the coercion check to class_get, which looks up the appropriate target type *)
4184 let (env, _tal
, _
, cty
) =
4185 static_class_id ~check_constraints
:false pos_classid
env [] x
4187 let env = might_throw
env in
4192 ~coerce_from_ty
:(Some
(p, ur, ety2
))
4198 let (env, local) = Env.FakeMembers.make_static
env x y
p in
4199 let env = set_valid_rvalue
p env local ty2
in
4201 | (pos, Array_get
(e1
, None
)) ->
4202 let (env, te1, ty1
) = update_array_type
pos env e1 `lvalue
in
4204 Typing_array_access.assign_array_append
4213 if is_hack_collection
env ty1
then
4216 let (env, te1, _
) = assign_
p ur env e1 ty1'
in
4219 make_result env pos (Aast.Array_get
(te1, None
)) ty2
4220 | (pos, Array_get
(e1
, Some
e)) ->
4221 let (env, te1, ty1
) = update_array_type
pos env e1 `lvalue
in
4222 let (env, te, ty) = expr env e ~
allow_awaitable in
4224 Typing_array_access.assign_array_get
4235 if is_hack_collection
env ty1
then
4238 let (env, te1, _
) = assign_
p ur env e1 ty1'
in
4241 (env, ((pos, ty2
), Aast.Array_get
(te1, Some
te)), ty2
)
4242 | _
-> assign_simple
p ur env e1 ty2
4244 and assign_simple
pos ur env e1 ty2
=
4245 let (env, te1, ty1
) = lvalue
env e1
in
4247 Typing_coercion.coerce_type
4252 (MakeType.unenforced ty1
)
4257 and array_field
env ~
allow_awaitable = function
4259 let (env, tve
, tv
) = expr env ve ~
allow_awaitable in
4260 (env, (Aast.AFvalue tve
, None
, tv
))
4261 | AFkvalue
(ke
, ve
) ->
4262 let (env, tke
, tk) = expr env ke ~
allow_awaitable in
4263 let (env, tve
, tv
) = expr env ve ~
allow_awaitable in
4264 (env, (Aast.AFkvalue
(tke
, tve
), Some
tk, tv
))
4266 and array_value ~
(expected : ExpectedTy.t
option) env x
=
4267 let (env, te, ty) = expr ?
expected env x ~
allow_awaitable:(*?*) false in
4271 p class_name is_set ~
(expected : ExpectedTy.t
option) env ((pos, _
) as x
) =
4272 let (env, (te, ty)) = array_value ~
expected env x
in
4273 let (ty_arraykey
, reason) =
4275 ( MakeType.arraykey (Reason.Rset_element
pos),
4276 Reason.set_element
class_name )
4278 (MakeType.arraykey (Reason.Ridx_dict
pos), Reason.index_class
class_name)
4281 Typing_coercion.coerce_type
4286 { et_type
= ty_arraykey
; et_enforced
= Enforced
}
4291 and check_parent_construct
pos env el unpacked_element env_parent
=
4292 let check_not_abstract = false in
4293 let (env, env_parent
) =
4294 Phase.localize_with_self
env ~ignore_errors
:true env_parent
4296 let (env, _tcid
, _tal
, tel
, typed_unpack_element
, parent
, fty) =
4301 ~is_using_clause
:false
4309 (* Not sure why we need to equate these types *)
4311 Type.sub_type
pos Reason.URnone
env env_parent parent
Errors.unify_error
4314 Type.sub_type
pos Reason.URnone
env parent env_parent
Errors.unify_error
4318 typed_unpack_element
,
4319 MakeType.void
(Reason.Rwitness
pos),
4323 and check_class_get
env p def_pos cid mid ce
e function_pointer
=
4325 | CIself
when get_ce_abstract ce
->
4327 match Env.get_self_id
env with
4329 (* at runtime, self:: in a trait is a call to whatever
4330 * self:: is in the context of the non-trait "use"-ing
4331 * the trait's code *)
4333 match Env.get_class
env self
with
4334 | Some cls
when Ast_defs.(equal_class_kind
(Cls.kind cls
) Ctrait
) ->
4335 (* Ban self::some_abstract_method() in a trait, if the
4336 * method is also defined in a trait.
4338 * Abstract methods from interfaces are fine: we'll check
4339 * in the child class that we actually have an
4340 * implementation. *)
4341 (match Decl_provider.get_class
(Env.get_ctx
env) ce
.ce_origin
with
4343 when Ast_defs.(equal_class_kind
(Cls.kind meth_cls
) Ctrait
) ->
4344 Errors.self_abstract_call mid
p def_pos
4347 (* Ban self::some_abstract_method() in a class. This will
4349 Errors.self_abstract_call mid
p def_pos
4353 | CIparent
when get_ce_abstract ce
->
4354 Errors.parent_abstract_call mid
p def_pos
4355 | CI _
when get_ce_abstract ce
&& function_pointer
->
4356 Errors.abstract_function_pointer
cid mid
p def_pos
4357 | CI _
when get_ce_abstract ce
->
4358 Errors.classname_abstract_call
cid mid
p def_pos
4359 | CI
(_
, classname) when get_ce_synthesized ce
->
4360 Errors.static_synthetic_method
classname mid
p def_pos
4363 and call_parent_construct
pos env el unpacked_element
=
4364 match Env.get_parent_ty
env with
4365 | Some parent
-> check_parent_construct
pos env el unpacked_element parent
4368 let ty = Typing_utils.mk_tany
env pos in
4369 let default = (env, [], None
, ty, ty, ty) in
4370 (match Env.get_self_id
env with
4372 (match Env.get_class
env self
with
4373 | Some trait
when Ast_defs.(equal_class_kind
(Cls.kind trait
) Ctrait
) ->
4374 (match trait_most_concrete_req_class trait
env with
4376 Errors.parent_in_trait
pos;
4378 | Some
(_
, parent_ty
) ->
4379 check_parent_construct
pos env el unpacked_element parent_ty
)
4381 if not
(Cls.members_fully_known self_tc
) then
4383 (* Don't know the hierarchy, assume it's correct *)
4385 Errors.undefined_parent
pos;
4387 | None
-> assert false)
4389 Errors.parent_outside_class
pos;
4390 let ty = err_witness env pos in
4391 (env, [], None
, ty, ty, ty))
4393 (* Depending on the kind of expression we are dealing with
4394 * The typing of call is different.
4397 ~
(expected : ExpectedTy.t
option)
4402 ((fpos
, fun_expr
) as e)
4406 let expr = expr ~
allow_awaitable:(*?*) false in
4407 let exprs = exprs ~
allow_awaitable:(*?*) false in
4408 let make_call env te tal tel typed_unpack_element
ty =
4409 make_result env p (Aast.Call
(te, tal
, tel
, typed_unpack_element
)) ty
4411 (* TODO: Avoid Tany annotations in TAST by eliminating `make_call_special` *)
4412 let make_call_special env id tel
ty =
4415 (Tast.make_typed_expr fpos
(TUtils.mk_tany
env fpos
) (Aast.Id
id))
4421 (* For special functions and pseudofunctions with a definition in hhi. *)
4422 let make_call_special_from_def env id tel ty_
=
4423 let (env, fty, tal
) = fun_type_of_id
env id explicit_targs el
in
4425 match get_node
fty with
4426 | Tfun
ft -> ft.ft_ret
.et_type
4427 | _
-> ty_
(Reason.Rwitness
p)
4429 make_call env (Tast.make_typed_expr fpos
fty (Aast.Id
id)) tal tel None
ty
4431 let overload_function = overload_function make_call fpos
in
4432 let check_disposable_in_return env fty =
4433 if is_return_disposable_fun_type env fty && not is_using_clause
then
4434 Errors.invalid_new_disposable
p
4436 let dispatch_id env ((_
, _
) as id) =
4437 let (env, fty, tal
) = fun_type_of_id
env id explicit_targs el
in
4438 check_disposable_in_return env fty;
4439 let (env, (tel
, typed_unpack_element
, ty)) =
4440 call ~
expected p env fty el unpacked_element
4444 (Tast.make_typed_expr fpos
fty (Aast.Id
id))
4447 typed_unpack_element
4450 let dispatch_class_const env (pos, e1
) m
=
4451 let (env, _tal
, tcid
, ty1
) =
4453 ~check_constraints
:(not
(Nast.equal_class_id_ e1 CIparent
))
4459 (* In static context, you can only call parent::foo() on static methods.
4460 * In instance context, you can call parent:foo() on static
4461 * methods as well as instance methods
4464 (not
(Nast.equal_class_id_ e1 CIparent
))
4465 || Env.is_static env
4466 || class_contains_smethod
env ty1 m
4468 let (env, (fty, tal
)) =
4469 match Env.get_self_ty
env with
4470 | Some this_ty
when not
is_static ->
4471 (* parent::nonStaticFunc() is really weird. It's calling a method
4472 * defined on the parent class, but $this is still the child class.
4479 ~coerce_from_ty
:None
4483 ~on_error
:Errors.unify_error
4489 ~coerce_from_ty
:None
4498 check_disposable_in_return env fty;
4499 let (env, (tel
, typed_unpack_element
, ty)) =
4500 call ~
expected p env fty el unpacked_element
4504 (Tast.make_typed_expr fpos
fty (Aast.Class_const
(tcid
, m
)))
4507 typed_unpack_element
4511 (* Special top-level function *)
4512 | Id
((pos, x
) as id) when SN.StdlibFunctions.needs_special_dispatch x
->
4515 (* Special function `echo` *)
4516 | echo
when String.equal echo
SN.SpecialFunctions.echo
->
4517 let (env, tel
, _
) = exprs ~accept_using_var
:true env el
in
4518 make_call_special env id tel
(MakeType.void
(Reason.Rwitness
pos))
4520 | unsafe_cast
when String.equal unsafe_cast
SN.PseudoFunctions.unsafe_cast
4523 Int.(List.length el
= 1)
4524 && TypecheckerOptions.ignore_unsafe_cast
(Env.get_tcopt
env)
4526 let original_expr = List.hd_exn el
in
4527 expr env original_expr
4529 Errors.unsafe_cast
p;
4530 (* dispatch_id also covers arity errors *)
4533 (* Special function `isset` *)
4534 | isset
when String.equal isset
SN.PseudoFunctions.isset
->
4536 exprs ~accept_using_var
:true ~check_defined
:false env el
4538 if Option.is_some unpacked_element
then
4539 Errors.unpacking_disallowed_builtin_function
p isset
;
4540 make_call_special_from_def env id tel
MakeType.bool
4541 (* Special function `unset` *)
4542 | unset
when String.equal unset
SN.PseudoFunctions.unset
->
4543 let (env, tel
, _
) = exprs env el
in
4544 if Option.is_some unpacked_element
then
4545 Errors.unpacking_disallowed_builtin_function
p unset
;
4546 let env = Typing_local_ops.check_unset_target
env tel
in
4547 let checked_unset_error =
4548 if Partial.should_check_error
(Env.get_mode
env) 4135 then
4549 Errors.unset_nonidx_in_strict
4555 match (el
, unpacked_element
) with
4556 | ([(_
, Array_get
((_
, Class_const _
), Some _
))], None
)
4557 when Partial.should_check_error
(Env.get_mode
env) 4011 ->
4558 Errors.const_mutation
p Pos.none
"";
4560 | ([(_
, Array_get
(ea
, Some _
))], None
) ->
4561 let (env, _te
, ty) = expr env ea
in
4562 let r = Reason.Rwitness
p in
4563 let tmixed = MakeType.mixed r in
4565 TypecheckerOptions.hack_arr_dv_arrs
(Env.get_tcopt
env)
4573 MakeType.dict
r tmixed tmixed;
4574 MakeType.keyset
r tmixed;
4575 MakeType.darray ~
unification r tmixed tmixed;
4578 SubType.sub_type_or_fail
env ty super (fun () ->
4583 ^
Typing_print.error ~ignore_dynamic
:true env ty )
4586 checked_unset_error p [];
4590 | [(p, Obj_get
(_
, _
, OG_nullsafe
, _
))] ->
4591 Errors.nullsafe_property_write_context
p;
4592 make_call_special_from_def env id tel
(TUtils.terr
env)
4593 | _
-> make_call_special_from_def env id tel
MakeType.void
)
4594 (* Special function `array_filter` *)
4596 when String.equal array_filter
SN.StdlibFunctions.array_filter
4597 && (not
(List.is_empty el
))
4598 && Option.is_none unpacked_element
->
4599 (* dispatch the call to typecheck the arguments *)
4600 let (env, fty, tal
) = fun_type_of_id
env id explicit_targs el
in
4601 let (env, (tel
, typed_unpack_element
, res
)) =
4602 call ~
expected p env fty el unpacked_element
4604 (* but ignore the result and overwrite it with custom return type *)
4605 let x = List.hd_exn el
in
4606 let (env, _tx
, ty) = expr env x in
4607 let explain_array_filter ty =
4608 map_reason
ty ~f
:(fun r -> Reason.Rarray_filter
(p, r))
4610 let get_value_type env tv
=
4612 if List.length el
> 1 then
4615 Typing_solver.non_null
env p tv
4617 (env, explain_array_filter tv
)
4619 let rec get_array_filter_return_type env ty =
4620 let (env, ety
) = Env.expand_type
env ty in
4621 match deref ety
with
4622 | (r, Tvarray tv
) ->
4623 let (env, tv
) = get_value_type env tv
in
4625 TypecheckerOptions.hack_arr_dv_arrs
(Env.get_tcopt
env)
4627 (env, MakeType.varray ~
unification r tv
)
4628 | (r, Tunion tyl
) ->
4630 List.map_env
env tyl
get_array_filter_return_type
4632 Typing_union.union_list
env r tyl
4633 | (r, Tintersection tyl
) ->
4635 List.map_env
env tyl
get_array_filter_return_type
4637 Inter.intersect_list
env r tyl
4638 | (r, Tany _
) -> (env, mk
(r, Typing_utils.tany
env))
4639 | (r, Terr
) -> (env, TUtils.terr
env r)
4641 let (env, tk) = Env.fresh_type
env p in
4642 let (env, tv
) = Env.fresh_type
env p in
4644 TypecheckerOptions.hack_arr_dv_arrs
(Env.get_tcopt
env)
4648 let keyed_container_type =
4649 MakeType.keyed_container
Reason.Rnone
tk tv
4655 keyed_container_type
4658 let (env, tv
) = get_value_type env tv
in
4660 MakeType.darray ~
unification r (explain_array_filter tk) tv
))
4664 let container_type = MakeType.container
Reason.Rnone tv
in
4666 SubType.sub_type
env ety
container_type Errors.unify_error
4668 let (env, tv
) = get_value_type env tv
in
4673 (explain_array_filter (MakeType.arraykey r))
4675 (fun _
-> (env, res
)))
4677 let (env, rty) = get_array_filter_return_type env ty in
4679 map_ty
fty ~f
:(function
4680 | Tfun
ft -> Tfun
{ ft with ft_ret
= MakeType.unenforced
rty }
4685 (Tast.make_typed_expr fpos
fty (Aast.Id
id))
4688 typed_unpack_element
4690 (* Special function `type_structure` *)
4692 when String.equal type_structure
SN.StdlibFunctions.type_structure
4693 && Int.equal
(List.length el
) 2
4694 && Option.is_none unpacked_element
->
4698 | (p, String cst
) ->
4699 (* find the class constant implicitly defined by the typeconst *)
4702 | (_
, Class_const
(cid, (_
, x)))
4703 | (_
, Class_get
(cid, CGstring
(_
, x), _
))
4704 when String.equal
x SN.Members.mClass
->
4706 | _
-> (fst e1
, CIexpr e1
)
4708 class_const ~incl_tc
:true env p (cid, (p, cst
))
4710 Errors.illegal_type_structure
pos "second argument is not a string";
4711 expr_error env (Reason.Rwitness
pos) e)
4712 | _
-> assert false)
4713 (* Special function `array_map` *)
4715 when String.equal array_map
SN.StdlibFunctions.array_map
4716 && (not
(List.is_empty el
))
4717 && Option.is_none unpacked_element
->
4718 (* This uses the arity to determine a signature for array_map. But there
4719 * is more: for two-argument use of array_map, we specialize the return
4720 * type to the collection that's passed in, below. *)
4721 let (env, fty, tal
) = fun_type_of_id
env id explicit_targs el
in
4722 let (env, fty) = Env.expand_type
env fty in
4723 let r_fty = get_reason
fty in
4725 Takes a Container type and returns a function that can "pack" a type
4726 into an array of appropriate shape, preserving the key type, i.e.:
4727 array -> f, where f R = array
4728 array<X> -> f, where f R = array<R>
4729 array<X, Y> -> f, where f R = array<X, R>
4730 Vector<X> -> f where f R = array<R>
4731 KeyedContainer<X, Y> -> f, where f R = array<X, R>
4732 Container<X> -> f, where f R = array<arraykey, R>
4733 X -> f, where f R = Y
4735 let rec build_output_container env (x : locl_ty
) :
4736 env * (env -> locl_ty
-> env * locl_ty
) =
4737 let (env, x) = Env.expand_type
env x in
4743 TypecheckerOptions.hack_arr_dv_arrs
(Env.get_tcopt
env)
4745 (env, MakeType.varray ~
unification r tr
) )
4747 (env, (fun env _
-> (env, mk
(r, Typing_utils.tany
env))))
4748 | (r, Terr
) -> (env, (fun env _
-> (env, TUtils.terr
env r)))
4749 | (r, Tunion tyl
) ->
4750 let (env, builders
) = List.map_env
env tyl
build_output_container in
4754 List.map_env
env builders
(fun env f
-> f
env tr
)
4756 Typing_union.union_list
env r tyl
)
4757 | (r, Tintersection tyl
) ->
4758 let (env, builders
) = List.map_env
env tyl
build_output_container in
4762 List.map_env
env builders
(fun env f
-> f
env tr
)
4764 Typing_intersection.intersect_list
env r tyl
)
4766 let (env, tk) = Env.fresh_type
env p in
4767 let (env, tv
) = Env.fresh_type
env p in
4769 TypecheckerOptions.hack_arr_dv_arrs
(Env.get_tcopt
env)
4771 let try_vector env =
4772 let vector_type = MakeType.const_vector
r_fty tv
in
4773 let env = SubType.sub_type
env x vector_type Errors.unify_error
in
4774 (env, (fun env tr
-> (env, MakeType.varray ~
unification r tr
)))
4776 let try_keyed_container env =
4777 let keyed_container_type = MakeType.keyed_container
r_fty tk tv
in
4779 SubType.sub_type
env x keyed_container_type Errors.unify_error
4781 (env, (fun env tr
-> (env, MakeType.darray ~
unification r tk tr
)))
4783 let try_container env =
4784 let container_type = MakeType.container
r_fty tv
in
4786 SubType.sub_type
env x container_type Errors.unify_error
4790 (env, MakeType.darray ~
unification r (MakeType.arraykey r) tr
)
4795 (fun () -> try_vector env)
4798 (fun () -> try_keyed_container env)
4801 (fun () -> try_container env)
4803 (env, (fun env _
-> (env, Typing_utils.mk_tany
env p))))))
4808 match (deref
fty, el
) with
4809 | ((_
, Tfun funty
), [_
; x]) ->
4810 let (env, _tx
, x) = expr env x in
4811 let (env, output_container
) = build_output_container env x in
4813 match get_varray_inst funty
.ft_ret
.et_type
with
4814 | None
-> (env, fty)
4816 let (env, elem_ty
) = output_container
env elem_ty
in
4817 let ft_ret = MakeType.unenforced elem_ty
in
4818 (env, mk
(r_fty, Tfun
{ funty
with ft_ret }))
4822 let (env, (tel
, typed_unpack_element
, ty)) =
4823 call ~
expected p env fty el None
4827 (Tast.make_typed_expr fpos
fty (Aast.Id
id))
4830 typed_unpack_element
4832 | _
-> dispatch_id env id
4834 (* Special Shapes:: function *)
4835 | Class_const
(((_
, CI
(_
, shapes
)) as class_id
), ((_
, x) as method_id
))
4836 when String.equal shapes
SN.Shapes.cShapes
->
4839 (* Special function `Shapes::idx` *)
4840 | idx
when String.equal idx
SN.Shapes.idx
->
4848 (fun env fty res el
->
4851 let (env, _ts
, shape_ty
) = expr env shape
in
4858 ~fun_pos
:(get_reason
fty)
4859 ~shape_pos
:(fst shape
)
4860 | [shape
; field
; default] ->
4861 let (env, _ts
, shape_ty
) = expr env shape
in
4862 let (env, _td
, default_ty
) = expr env default in
4867 (Some
(fst
default, default_ty
))
4869 ~fun_pos
:(get_reason
fty)
4870 ~shape_pos
:(fst shape
)
4872 (* Special function `Shapes::at` *)
4873 | at
when String.equal at
SN.Shapes.at
->
4881 (fun env _fty res el
->
4884 let (env, _te
, shape_ty
) = expr env shape
in
4888 ~shape_pos
:(fst shape
)
4892 (* Special function `Shapes::keyExists` *)
4893 | key_exists
when String.equal key_exists
SN.Shapes.keyExists
->
4901 (fun env fty res el
->
4904 let (env, _te
, shape_ty
) = expr env shape
in
4905 (* try accessing the field, to verify existence, but ignore
4906 * the returned type and keep the one coming from function
4907 * return type hint *)
4915 ~fun_pos
:(get_reason
fty)
4916 ~shape_pos
:(fst shape
)
4920 (* Special function `Shapes::removeKey` *)
4921 | remove_key
when String.equal remove_key
SN.Shapes.removeKey
->
4929 (fun env _ res el
->
4934 | (_
, Lvar
(_
, lvar
))
4935 | (_
, Callconv
(Ast_defs.Pinout
, (_
, Lvar
(_
, lvar
)))) ->
4936 let (env, _te
, shape_ty
) = expr env shape
in
4937 let (env, shape_ty
) =
4938 Typing_shapes.remove_key
p env shape_ty field
4940 let env = set_valid_rvalue
p env lvar shape_ty
in
4943 Errors.invalid_shape_remove_key
(fst shape
);
4947 (* Special function `Shapes::toArray` *)
4948 | to_array
when String.equal to_array
SN.Shapes.toArray
->
4956 (fun env _ res el
->
4959 let (env, _te
, shape_ty
) = expr env shape
in
4960 Typing_shapes.to_array
env p shape_ty res
4962 (* Special function `Shapes::toDict` *)
4963 | to_dict
when String.equal to_dict
SN.Shapes.toDict
->
4971 (fun env _ res el
->
4974 let (env, _te
, shape_ty
) = expr env shape
in
4975 Typing_shapes.to_dict
env p shape_ty res
4977 | _
-> dispatch_class_const env class_id method_id
4979 (* Special function `parent::__construct` *)
4980 | Class_const
((pos, CIparent
), ((_
, construct
) as id))
4981 when String.equal construct
SN.Members.__construct
->
4982 let (env, tel
, typed_unpack_element
, ty, pty
, ctor_fty
) =
4983 call_parent_construct
p env el unpacked_element
4987 (Tast.make_typed_expr
4990 (Aast.Class_const
(((pos, pty
), Aast.CIparent
), id)))
4991 [] (* tal: no type arguments to constructor *)
4993 typed_unpack_element
4995 (* Calling parent / class method *)
4996 | Class_const
(class_id
, m
) -> dispatch_class_const env class_id m
4997 (* Call instance method *)
4998 | Obj_get
(e1
, (pos_id
, Id m
), nullflavor
, false)
4999 when not
(TypecheckerOptions.method_call_inference
(Env.get_tcopt
env)) ->
5000 let (env, te1, ty1
) = expr ~accept_using_var
:true env e1
in
5002 match nullflavor
with
5003 | OG_nullthrows
-> None
5004 | OG_nullsafe
-> Some
p
5006 let (env, (tfty
, tal
)) =
5011 ~
nullsafe:(Option.map ~f
:(fun p -> Reason.Rnullsafe_op
p) nullsafe)
5012 ~coerce_from_ty
:None
5014 ~class_id
:(CIexpr e1
)
5016 ~on_error
:Errors.unify_error
5020 check_disposable_in_return env tfty
;
5021 let (env, (tel
, typed_unpack_element
, ty)) =
5022 call ~
nullsafe ~
expected p env tfty el unpacked_element
5026 (Tast.make_typed_expr
5031 Tast.make_typed_expr pos_id tfty
(Aast.Id m
),
5036 typed_unpack_element
5038 (* Call instance method using new method call inference *)
5039 | Obj_get
(receiver
, (pos_id
, Id
meth), nullflavor
, false) ->
5041 Typecheck `Obj_get` by enforcing that:
5042 - `<instance_type>` <: `Thas_member(m, #1)`
5043 where #1 is a fresh type variable.
5045 let (env, typed_receiver
, receiver_ty
) =
5046 expr ~accept_using_var
:true env receiver
5048 let env = might_throw
env in
5050 match nullflavor
with
5051 | OG_nullthrows
-> None
5052 | OG_nullsafe
-> Some
p
5054 (* Generate a fresh type `method_ty` for the type of the
5055 instance method, i.e. #1 *)
5056 let (env, method_ty
) = Env.fresh_type
env p in
5057 (* Create `Thas_member` constraint type *)
5058 let reason = Reason.Rwitness
(fst receiver
) in
5064 ~class_id
:(CIexpr receiver
)
5065 ~explicit_targs
:(Some explicit_targs
)
5067 let env = Env.set_tyvar_variance
env method_ty
in
5068 let (env, has_method_super_ty
) =
5069 if Option.is_none
nullsafe then
5070 (env, has_method_ty)
5072 (* If null-safe, then `receiver_ty` <: `?Thas_member(m, #1)`,
5073 but *unlike* property access typing in `expr_`, we still use `#1` as
5074 our "result" if `receiver_ty` is nullable (as opposed to `?#1`),
5075 deferring null-safety handling to after `call` *)
5076 let r = Reason.Rnullsafe_op
p in
5077 let null_ty = MakeType.null
r in
5078 Union.union_i
env r has_method_ty null_ty
5085 (LoclType receiver_ty
)
5089 (* Perhaps solve for `method_ty`. Opening and closing a scope is too coarse
5090 here - type parameters are localised to fresh type variables over the
5091 course of subtyping above, and we do not want to solve these until later.
5092 Once we typecheck all function calls with a subtyping of function types,
5093 we should not need to solve early at all - transitive closure of
5094 subtyping should give enough information. *)
5096 match get_var method_ty
with
5098 Typing_solver.solve_to_equal_bound_or_wrt_variance
5105 let localize_targ env (_
, targ
) = Phase.localize_targ env targ
in
5106 let (env, typed_targs
) =
5107 List.map_env
env ~f
:(localize_targ ~check_well_kinded
:true) explicit_targs
5109 check_disposable_in_return env method_ty
;
5110 let (env, (typed_params
, typed_unpack_element
, ret_ty)) =
5111 call ~
nullsafe ~
expected ?in_await
p env method_ty el unpacked_element
5113 (* If the call is nullsafe AND the receiver is nullable,
5114 make the return type nullable too *)
5116 if Option.is_some
nullsafe then
5117 let r = Reason.Rnullsafe_op
p in
5118 let null_ty = MakeType.null
r in
5119 let (env, null_or_nothing_ty
) =
5120 Inter.intersect
env ~
r null_ty receiver_ty
5122 let (env, ret_option_ty
) = Union.union env null_or_nothing_ty
ret_ty in
5123 (env, ret_option_ty
)
5129 (Tast.make_typed_expr
5134 Tast.make_typed_expr pos_id method_ty
(Aast.Id
meth),
5139 typed_unpack_element
5141 (* Function invocation *)
5143 let (env, fty, tal
) = fun_type_of_id
env x explicit_targs el
in
5144 check_disposable_in_return env fty;
5145 let (env, (tel
, typed_unpack_element
, ty)) =
5146 call ~
expected p env fty el unpacked_element
5150 (Tast.make_typed_expr fpos
fty (Aast.Fun_id
x))
5153 typed_unpack_element
5155 | Id
id -> dispatch_id env id
5157 let (env, te, fty) = expr env e in
5159 Typing_solver.expand_type_and_solve
5160 ~description_of_expected
:"a function value"
5166 check_disposable_in_return env fty;
5167 let (env, (tel
, typed_unpack_element
, ty)) =
5168 call ~
expected p env fty el unpacked_element
5173 (* tal: no type arguments to function values, as they are non-generic *)
5176 typed_unpack_element
5179 and fun_type_of_id
env x tal el
=
5180 match Env.get_fun
env (snd
x) with
5182 let (env, _
, ty) = unbound_name env x (Pos.none
, Aast.Null
) in
5184 | Some
{ fe_type
; fe_pos
; fe_deprecated
; _
} ->
5185 (match get_node fe_type
with
5188 Typing_special_fun.transform_special_fun_ty
ft x (List.length el
)
5190 let ety_env = Phase.env_with_self
env ~on_error
:Errors.ignore_error
in
5192 Phase.localize_targs
5193 ~check_well_kinded
:true
5197 ~use_name
:(strip_ns
(snd
x))
5200 (List.map ~f
:snd tal
)
5203 Typing_enforceability.compute_enforced_and_pessimize_fun_type
env ft
5205 let use_pos = fst
x in
5206 let def_pos = fe_pos
in
5211 { use_name
= strip_ns
(snd
x); use_pos; explicit_targs
= tal
}
5217 let fty = mk
(get_reason fe_type
|> Typing_reason.localize
, Tfun
ft) in
5218 TVis.check_deprecated ~
use_pos ~
def_pos fe_deprecated
;
5220 | _
-> failwith
"Expected function type")
5223 * Checks if a class (given by cty) contains a given static method.
5225 * We could refactor this + class_get
5227 and class_contains_smethod
env cty
(_pos
, mid
) =
5228 let lookup_member ty =
5229 match get_class_type
ty with
5230 | Some
((_
, c), _
, _
) ->
5231 (match Env.get_class
env c with
5234 Option.is_some
@@ Env.get_static_member
true env class_ mid
)
5237 let (_env
, tyl
) = TUtils.get_concrete_supertypes
env cty
in
5238 List.exists tyl ~f
:lookup_member
5244 ?
(explicit_targs
= [])
5246 ?
(is_function_pointer
= false)
5251 let (env, this_ty
) =
5253 this_for_method
env cid cty
5264 ~is_function_pointer
5275 ?
(explicit_targs
= [])
5277 ?
(is_function_pointer
= false)
5282 let (env, cty
) = Env.expand_type
env cty
in
5283 match deref cty
with
5284 | (r, Tany _
) -> (env, (mk
(r, Typing_utils.tany
env), []))
5285 | (r, Terr
) -> (env, (err_witness env (Reason.to_pos
r), []))
5286 | (_
, Tdynamic
) -> (env, (cty
, []))
5287 | (_
, Tunion tyl
) ->
5289 List.map_env
env tyl
(fun env ty ->
5296 ~is_function_pointer
5303 Union.union_list
env (get_reason cty
) (List.map ~f
:fst
pairs)
5306 | (_
, Tintersection tyl
) ->
5308 TUtils.run_on_intersection
env tyl ~f
:(fun env ty ->
5315 ~is_function_pointer
5322 Inter.intersect_list
env (get_reason cty
) (List.map ~f
:fst
pairs)
5325 | (_
, Tnewtype
(_
, _
, ty))
5326 | (_
, Tdependent
(_
, ty)) ->
5334 ~is_function_pointer
5339 | (r, Tgeneric _
) ->
5340 let (env, tyl
) = TUtils.get_concrete_supertypes
env cty
in
5341 if List.is_empty tyl
then begin
5342 Errors.non_class_member
5346 (Typing_print.error
env cty
)
5348 (env, (err_witness env p, []))
5350 let (env, ty) = Typing_intersection.intersect_list
env r tyl
in
5358 ~is_function_pointer
5363 | (_
, Tclass
((_
, c), _
, paraml
)) ->
5364 let class_ = Env.get_class
env c in
5366 | None
-> (env, (Typing_utils.mk_tany
env p, []))
5368 let (env, this_ty
) = ExprDepTy.make
env cid this_ty
in
5369 (* We need to instantiate generic parameters in the method signature *)
5372 type_expansions
= [];
5374 substs
= TUtils.make_locl_subst_for_class_tparams
class_ paraml
;
5375 on_error
= Errors.ignore_error
;
5378 let get_smember_from_constraints env class_info =
5380 Cls.upper_bounds_on_this_from_constraints
class_info
5382 let (env, upper_bounds) =
5383 List.map_env
env upper_bounds ~f
:(fun env up
->
5384 Phase.localize ~
ety_env env up
)
5386 let (env, inter_ty
) =
5387 Inter.intersect_list
env (Reason.Rwitness
p) upper_bounds
5396 ~is_function_pointer
5402 let try_get_smember_from_constraints env class_info =
5403 Errors.try_with_error
5404 (fun () -> get_smember_from_constraints env class_info)
5406 TOG.smember_not_found
5410 ~is_function_pointer
5414 (env, (TUtils.terr
env Reason.Rnone
, [])))
5419 Env.get_const
env class_ mid
5421 match Env.get_typeconst
env class_ mid
with
5423 Errors.illegal_typeconst_direct_access
p;
5425 | None
-> Env.get_const
env class_ mid
5428 | None
when Cls.has_upper_bounds_on_this_from_constraints
class_ ->
5429 try_get_smember_from_constraints env class_
5431 TOG.smember_not_found
5435 ~is_function_pointer
5439 (env, (TUtils.terr
env Reason.Rnone
, []))
5440 | Some
{ cc_type
; cc_abstract
; cc_pos
; _
} ->
5441 let (env, cc_locl_type
) = Phase.localize ~
ety_env env cc_type
in
5442 ( if cc_abstract
then
5448 let cc_name = Cls.name class_ ^
"::" ^ mid
in
5449 Errors.abstract_const_usage
p cc_pos
cc_name );
5450 (env, (cc_locl_type
, []))
5452 let static_member_opt =
5453 Env.get_static_member is_method
env class_ mid
5455 (match static_member_opt with
5456 | None
when Cls.has_upper_bounds_on_this_from_constraints
class_ ->
5457 try_get_smember_from_constraints env class_
5459 TOG.smember_not_found
5463 ~is_function_pointer
5467 (env, (TUtils.terr
env Reason.Rnone
, []))
5470 ce_visibility = vis
;
5471 ce_type
= (lazy member_decl_ty
);
5475 let def_pos = get_pos member_decl_ty
in
5476 TVis.check_class_access
5480 (vis
, get_ce_lsb ce
)
5483 TVis.check_deprecated ~
use_pos:p ~
def_pos ce_deprecated;
5484 check_class_get
env p def_pos c mid ce
cid is_function_pointer
;
5485 let (env, member_ty
, et_enforced
, tal
) =
5486 match deref member_decl_ty
with
5487 (* We special case Tfun here to allow passing in explicit tparams to localize_ft. *)
5488 | (r, Tfun
ft) when is_method
->
5489 let (env, explicit_targs
) =
5490 Phase.localize_targs
5491 ~check_well_kinded
:true
5495 ~use_name
:(strip_ns mid
)
5498 (List.map ~f
:snd explicit_targs
)
5501 Typing_enforceability.compute_enforced_and_pessimize_fun_type
5509 { use_name
= strip_ns mid
; use_pos = p; explicit_targs
}
5516 mk
(Typing_reason.localize
r, Tfun
ft),
5521 let { et_type
; et_enforced
} =
5522 Typing_enforceability.compute_enforced_and_pessimize_ty
5526 let (env, member_ty
) = Phase.localize ~
ety_env env et_type
in
5527 (* TODO(T52753871) make function just return possibly_enforced_ty
5528 * after considering intersection case *)
5529 (env, member_ty
, et_enforced
, [])
5531 let (env, member_ty
) =
5532 if Cls.has_upper_bounds_on_this_from_constraints
class_ then
5533 let ((env, (member_ty'
, _
)), succeed
) =
5534 Errors.try_with_error
5535 (fun () -> (get_smember_from_constraints env class_, true))
5537 (* No eligible functions found in constraints *)
5538 ((env, (MakeType.mixed Reason.Rnone
, [])), false))
5541 Inter.intersect
env (Reason.Rwitness
p) member_ty member_ty'
5548 match coerce_from_ty
with
5550 | Some
(p, ur, ty) ->
5551 Typing_coercion.coerce_type
5556 { et_type
= member_ty
; et_enforced
}
5559 (env, (member_ty
, tal
))))
5560 | (_
, Tunapplied_alias _
) ->
5561 Typing_defs.error_Tunapplied_alias_in_illegal_context
()
5563 ( Tvar _
| Tnonnull
| Tvarray _
| Tdarray _
| Tvarray_or_darray _
5564 | Tvec_or_dict _
| Toption _
| Tprim _
| Tfun _
| Ttuple _
| Tobject
5565 | Tshape _
| Taccess _
) ) ->
5566 Errors.non_class_member
5570 (Typing_print.error
env cty
)
5572 (env, (err_witness env p, []))
5574 and class_id_for_new
5575 ~exact
p env (cid : Nast.class_id_
) (explicit_targs
: Nast.targ list
) :
5576 newable_class_info
=
5577 let (env, tal
, te, cid_ty
) =
5579 ~check_targs_well_kinded
:true
5580 ~check_explicit_targs
:true
5582 ~check_constraints
:false
5588 (* Need to deal with union case *)
5589 let rec get_info res tyl
=
5591 | [] -> (env, tal
, te, res
)
5593 (match get_node
ty with
5595 | Tintersection tyl'
->
5596 get_info res
(tyl'
@ tyl
)
5598 (* Instantiation on an abstract class (e.g. from classname<T>) is
5599 * via the base type (to check constructor args), but the actual
5600 * type `ty` must be preserved. *)
5601 (match get_node
(TUtils.get_base_type
env ty) with
5602 | Tdynamic
-> get_info (`Dynamic
:: res
) tyl
5603 | Tclass
(sid
, _
, _
) ->
5604 let class_ = Env.get_class
env (snd sid
) in
5606 | None
-> get_info res tyl
5607 | Some
class_info ->
5608 (match (te, cid_ty
) with
5609 (* When computing the classes for a new T() where T is a generic,
5610 * the class must be consistent (final, final constructor, or
5611 * <<__ConsistentConstruct>>) for its constructor to be considered *)
5612 | ((_
, Aast.CI
(_
, c)), ty) when is_generic_equal_to
c ty ->
5613 (* Only have this choosing behavior for new T(), not all generic types
5614 * i.e. new classname<T>, TODO: T41190512 *)
5615 if Tast_utils.valid_newable_class
class_info then
5616 get_info (`Class
(sid
, class_info, ty) :: res
) tyl
5619 | _
-> get_info (`Class
(sid
, class_info, ty) :: res
) tyl
))
5620 | _
-> get_info res tyl
))
5622 get_info [] [cid_ty
]
5624 (* To be a valid trait declaration, all of its 'require extends' must
5625 * match; since there's no multiple inheritance, it follows that all of
5626 * the 'require extends' must belong to the same inheritance hierarchy
5627 * and one of them should be the child of all the others *)
5628 and trait_most_concrete_req_class trait
env =
5630 (Cls.all_ancestor_reqs trait
)
5634 let (_r
, (_p
, name), _paraml
) = TUtils.unwrap_class_type
ty in
5637 | Some
(c, _ty
) -> Cls.has_ancestor
c name
5643 let class_ = Env.get_class
env name in
5646 | Some
c when Ast_defs.(equal_class_kind
(Cls.kind
c) Cinterface
) ->
5648 | Some
c when Ast_defs.(equal_class_kind
(Cls.kind
c) Ctrait
) ->
5649 (* this is an error case for which Typing_check_decls spits out
5650 * an error, but does *not* currently remove the offending
5651 * 'require extends' or 'require implements' *)
5653 | Some
c -> Some
(c, ty)
5657 (* When invoking a method the class_id is used to determine what class we
5658 * lookup the method in, but the type of 'this' will be the late bound type.
5662 * public static function get(): this { return new static(); }
5664 * public static function alias(): this { return self::get(); }
5667 * In C::alias, when we invoke self::get(), 'self' is resolved to the class
5668 * in the lexical scope (C), so call C::get. However the method is executed in
5669 * the current context, so static inside C::get will be resolved to the late
5670 * bound type (get_called_class() within C::alias).
5672 * This means when determining the type of this, CIparent and CIself should be
5673 * changed to CIstatic. For the other cases of C::get() or $c::get(), we only
5674 * look at the left hand side of the '::' and use the type type associated
5677 * Thus C::get() will return a type C, while $c::get() will return the same
5680 and this_for_method
env cid default_ty
=
5685 let p = get_pos default_ty
in
5686 let (env, _tal
, _te
, ty) =
5687 static_class_id ~check_constraints
:false p env [] CIstatic
5689 ExprDepTy.make
env CIstatic
ty
5690 | _
-> (env, default_ty
)
5692 (** Resolve class expressions like `parent`, `self`, `static`, classnames
5695 ?
(check_targs_well_kinded
= false)
5697 ?
(check_explicit_targs
= false)
5698 ~
(check_constraints
: bool)
5701 (tal
: Nast.targ list
) :
5702 Nast.class_id_
-> env * Tast.targ list
* Tast.class_id
* locl_ty
=
5703 let make_result env tal
te ty = (env, tal
, ((p, ty), te), ty) in
5706 (match Env.get_self_id
env with
5708 (match Env.get_class
env self
with
5709 | Some trait
when Ast_defs.(equal_class_kind
(Cls.kind trait
) Ctrait
) ->
5710 (match trait_most_concrete_req_class trait
env with
5712 Errors.parent_in_trait
p;
5713 make_result env [] Aast.CIparent
(err_witness env p)
5714 | Some
(_
, parent_ty
) ->
5715 (* inside a trait, parent is SN.Typehints.this, but with the
5716 * type of the most concrete class that the trait has
5717 * "require extend"-ed *)
5718 let r = Reason.Rwitness
p in
5719 let (env, parent_ty
) =
5720 Phase.localize_with_self
env ~ignore_errors
:true parent_ty
5722 make_result env [] Aast.CIparent
(mk
(r, TUtils.this_of parent_ty
)))
5725 match Env.get_parent_ty
env with
5727 Errors.parent_undefined
p;
5728 mk
(Reason.none
, Typing_defs.make_tany
())
5729 | Some
parent -> parent
5731 let r = Reason.Rwitness
p in
5733 Phase.localize_with_self
env ~ignore_errors
:true parent
5735 (* parent is still technically the same object. *)
5740 (mk
(r, TUtils.this_of
(mk
(r, get_node
parent)))))
5743 match Env.get_parent_ty
env with
5745 Errors.parent_undefined
p;
5746 mk
(Reason.none
, Typing_defs.make_tany
())
5747 | Some
parent -> parent
5749 let r = Reason.Rwitness
p in
5751 Phase.localize_with_self
env ~ignore_errors
:true parent
5753 (* parent is still technically the same object. *)
5758 (mk
(r, TUtils.this_of
(mk
(r, get_node
parent)))))
5761 match Env.get_self_ty
env with
5762 | Some
ty -> mk
(Reason.Rwitness
p, TUtils.this_of
ty)
5764 (* Naming phase has already checked and replaced CIstatic with CI if outside a class *)
5765 Errors.internal_error
p "Unexpected CIstatic";
5766 Typing_utils.mk_tany
env p
5768 make_result env [] Aast.CIstatic
ty
5771 match Env.get_self_class_type
env with
5772 | Some
(c, _
, tyl
) -> mk
(Reason.Rwitness
p, Tclass
(c, exact
, tyl
))
5774 (* Naming phase has already checked and replaced CIself with CI if outside a class *)
5775 Errors.internal_error
p "Unexpected CIself";
5776 Typing_utils.mk_tany
env p
5778 make_result env [] Aast.CIself
ty
5779 | CI
((p, id) as c) ->
5781 match Env.get_pos_and_kind_of_generic
env id with
5782 | Some
(def_pos, kind
) ->
5783 let simple_kind = Typing_kinding_defs.Simple.from_full_kind kind
in
5785 Typing_kinding_defs.Simple.get_named_parameter_kinds
simple_kind
5788 Phase.localize_targs_with_kinds
5789 ~check_well_kinded
:check_targs_well_kinded
5793 ~use_name
:(strip_ns
(snd
c))
5794 ~check_explicit_targs
5797 (List.map ~f
:snd tal
)
5799 let r = Reason.Rhint
p in
5800 let type_args = List.map tal fst
in
5801 let tgeneric = MakeType.generic ~
type_args r id in
5802 make_result env tal
(Aast.CI
c) tgeneric
5804 (* Not a type parameter *)
5805 let class_ = Env.get_class
env id in
5807 | None
-> make_result env [] (Aast.CI
c) (Typing_utils.mk_tany
env p)
5809 let (env, ty, tal
) =
5811 |> Phase.localize_targs_and_check_constraints
5813 ~check_well_kinded
:check_targs_well_kinded
5815 ~
def_pos:(Cls.pos class_)
5817 ~check_explicit_targs
5820 (Cls.tparams
class_)
5822 make_result env tal
(Aast.CI
c) ty)
5824 | CIexpr
((p, _
) as e) ->
5825 let (env, te, ty) = expr env e ~
allow_awaitable:(*?*) false in
5826 let rec resolve_ety env ty =
5828 Typing_solver.expand_type_and_solve
5829 ~description_of_expected
:"an object"
5835 let base_ty = TUtils.get_base_type
env ty in
5836 match deref
base_ty with
5837 | (_
, Tnewtype
(classname, [the_cls
], _
))
5838 when String.equal
classname SN.Classes.cClassname
->
5839 resolve_ety env the_cls
5843 | (r, Tunion tyl
) ->
5844 let (env, tyl
) = List.map_env
env tyl
resolve_ety in
5845 (env, MakeType.union r tyl
)
5846 | (r, Tintersection tyl
) ->
5847 let (env, tyl
) = TUtils.run_on_intersection
env tyl ~f
:resolve_ety in
5848 Inter.intersect_list
env r tyl
5849 | (_
, Tdynamic
) -> (env, base_ty)
5850 | (_
, (Tany _
| Tprim Tstring
| Tobject
)) when not
(Env.is_strict
env) ->
5851 (env, Typing_utils.mk_tany
env p)
5852 | (_
, Terr
) -> (env, err_witness env p)
5854 Errors.unknown_type
"an object" p (Reason.to_string
"It is unknown" r);
5855 (env, err_witness env p)
5856 | (_
, Tunapplied_alias _
) ->
5857 Typing_defs.error_Tunapplied_alias_in_illegal_context
()
5859 ( Tany _
| Tnonnull
| Tvarray _
| Tdarray _
| Tvarray_or_darray _
5860 | Tvec_or_dict _
| Toption _
| Tprim _
| Tfun _
| Ttuple _
5861 | Tnewtype _
| Tdependent _
| Tobject
| Tshape _
| Taccess _
) ) ->
5862 Errors.expected_class
5863 ~suffix
:(", but got " ^
Typing_print.error
env base_ty)
5865 (env, err_witness env p)
5867 let (env, result_ty
) = resolve_ety env ty in
5868 make_result env [] (Aast.CIexpr
te) result_ty
5870 and call_construct
p env class_ params el unpacked_element
cid cid_ty
=
5872 match Env.get_self_ty
env with
5873 | Some
ty when Nast.equal_class_id_
cid CIparent
->
5874 mk
(Reason.Rwitness
p, TUtils.this_of
ty)
5879 type_expansions
= [];
5881 substs
= TUtils.make_locl_subst_for_class_tparams
class_ params;
5882 on_error
= Errors.unify_error_at
p;
5886 Phase.check_tparams_constraints ~
use_pos:p ~
ety_env env (Cls.tparams
class_)
5889 Phase.check_where_constraints
5892 ~definition_pos
:(Cls.pos class_)
5895 (Cls.where_constraints
class_)
5897 let cstr = Env.get_construct
env class_ in
5898 let mode = Env.get_mode
env in
5902 ((not
(List.is_empty el
)) || Option.is_some unpacked_element
)
5903 && (FileInfo.is_strict
mode || FileInfo.(equal_mode
mode Mpartial
))
5904 && Cls.members_fully_known
class_
5906 Errors.constructor_no_args
p;
5907 let (env, tel
, _tyl
) = exprs env el ~
allow_awaitable:(*?*) false in
5908 (env, tel
, None
, TUtils.terr
env Reason.Rnone
)
5909 | Some
{ ce_visibility = vis
; ce_type
= (lazy m
); ce_deprecated; _
} ->
5910 let def_pos = get_pos m
in
5911 TVis.check_obj_access ~
use_pos:p ~
def_pos env vis
;
5912 TVis.check_deprecated ~
use_pos:p ~
def_pos ce_deprecated;
5913 (* Obtain the type of the constructor *)
5915 let r = get_reason m
|> Typing_reason.localize
in
5916 match get_node m
with
5919 Typing_enforceability.compute_enforced_and_pessimize_fun_type
env ft
5921 (* This creates type variables for non-denotable type parameters on constructors.
5922 * These are notably different from the tparams on the class, which are handled
5923 * at the top of this function. User-written type parameters on constructors
5924 * are still a parse error. This is a no-op if ft.ft_tparams is empty. *)
5925 let (env, implicit_constructor_targs
) =
5926 Phase.localize_targs
5927 ~check_well_kinded
:true
5931 ~use_name
:"constructor"
5941 use_name
= "constructor";
5943 explicit_targs
= implicit_constructor_targs
;
5950 (env, mk
(r, Tfun
ft))
5952 Errors.internal_error
p "Expected function type for constructor";
5953 let ty = TUtils.terr
env r in
5956 let (env, (tel
, typed_unpack_element
, _ty
)) =
5957 call ~
expected:None
p env m el unpacked_element
5959 (env, tel
, typed_unpack_element
, m
)
5961 and check_arity ?
(did_unpack
= false) pos pos_def
ft (arity
: int) =
5962 let exp_min = Typing_defs.arity_min
ft in
5963 if arity
< exp_min then
5964 Errors.typing_too_few_args
exp_min arity
pos pos_def None
;
5965 match ft.ft_arity
with
5967 let exp_max = List.length
ft.ft_params in
5974 if arity > exp_max then
5975 Errors.typing_too_many_args
exp_max arity pos pos_def None
5978 and check_lambda_arity lambda_pos
def_pos lambda_ft
expected_ft =
5979 match (lambda_ft
.ft_arity
, expected_ft.ft_arity
) with
5980 | (Fstandard
, Fstandard
) ->
5981 let expected_min = Typing_defs.arity_min
expected_ft in
5982 let lambda_min = Typing_defs.arity_min lambda_ft
in
5983 if lambda_min < expected_min then
5984 Errors.typing_too_few_args
expected_min lambda_min lambda_pos
def_pos None
;
5985 if lambda_min > expected_min then
5986 Errors.typing_too_many_args
5994 (* The variadic capture argument is an array listing the passed
5995 * variable arguments for the purposes of the function body; callsites
5996 * should not unify with it *)
5997 and variadic_param
env ft =
5998 match ft.ft_arity
with
5999 | Fvariadic
param -> (env, Some
param)
6000 | Fstandard
-> (env, None
)
6002 and param_modes ?
(is_variadic
= false) ({ fp_pos
; _
} as fp
) (pos, e) =
6003 match (get_fp_mode fp
, e) with
6004 | (FPnormal
, Callconv _
) ->
6005 Errors.inout_annotation_unexpected
pos fp_pos is_variadic
6006 | (FPnormal
, _
) -> ()
6007 | (FPinout
, Callconv
(Ast_defs.Pinout
, _
)) -> ()
6008 | (FPinout
, _
) -> Errors.inout_annotation_missing
pos fp_pos
6010 and inout_write_back
env { fp_type
; _
} (_
, e) =
6012 | Callconv
(Ast_defs.Pinout
, e1
) ->
6013 (* Translate the write-back semantics of inout parameters.
6015 * This matters because we want to:
6016 * (1) make sure we can write to the original argument
6017 * (modifiable lvalue check)
6018 * (2) allow for growing of locals / Tunions (type side effect)
6019 * but otherwise unify the argument type with the parameter hint
6021 let (env, _te
, _ty
) =
6022 assign_
(fst e1
) Reason.URparam_inout
env e1 fp_type
.et_type
6027 (** Typechecks a call.
6028 Returns in this order the typed expressions for the arguments, for the variadic arguments, and the return type. *)
6030 ~
(expected : ExpectedTy.t
option)
6031 ?
(nullsafe : Pos.t
option = None
)
6036 (el
: Nast.expr list
)
6037 (unpacked_element
: Nast.expr option) :
6038 env * (Tast.expr list
* Tast.expr option * locl_ty
) =
6039 let expr = expr ~
allow_awaitable:(*?*) false in
6040 let exprs = exprs ~
allow_awaitable:(*?*) false in
6041 let (env, tyl
) = TUtils.get_concrete_supertypes
env fty in
6042 if List.is_empty tyl
then begin
6043 bad_call
env pos fty;
6044 let env = call_untyped_unpack
env (get_pos
fty) unpacked_element
in
6045 (env, ([], None
, err_witness env pos))
6048 Typing_intersection.intersect_list
env (get_reason
fty) tyl
6051 if TypecheckerOptions.method_call_inference
(Env.get_tcopt
env) then
6052 Env.expand_type
env fty
6054 Typing_solver.expand_type_and_solve
6055 ~description_of_expected
:"a function value"
6061 match deref efty
with
6062 | (r, Tdynamic
) when TCO.enable_sound_dynamic (Env.get_tcopt
env) ->
6063 let ty = MakeType.dynamic
(Reason.Rdynamic_call
pos) in
6065 (* Need to check that the type of the unpacked_element can be,
6066 * coerced to dynamic, just like all of the other arguments, in addition
6067 * to the check below in call_untyped_unpack, that it is unpackable.
6068 * We don't need to unpack and check each type because a tuple is
6069 * coercible iff it's constituent types are. *)
6070 Option.value_map ~f
:(fun u
-> el @ [u
]) ~
default:el unpacked_element
6073 List.map_env
env el (fun env elt
->
6074 (* TODO(sowens): Pass the expected type to expr *)
6075 let (env, te, e_ty
) = expr env elt
in
6078 | (_
, Callconv
(Ast_defs.Pinout
, e1
)) ->
6079 let (env, _te
, _ty
) =
6080 assign_
(fst e1
) Reason.URparam_inout
env e1 efty
6086 Typing_coercion.coerce_type
6092 Typing_defs_core.et_type
= ty;
6093 Typing_defs_core.et_enforced
= Unenforced
;
6099 let env = call_untyped_unpack
env (Reason.to_pos
r) unpacked_element
in
6100 (env, (tel
, None
, ty))
6101 | (r, ((Tprim Tnull
| Tdynamic
| Terr
| Tany _
| Tunion
[]) as ty))
6103 | Tprim Tnull
-> Option.is_some
nullsafe
6106 Option.value_map ~f
:(fun u
-> el @ [u
]) ~
default:el unpacked_element
6108 let expected_arg_ty =
6109 (* Note: We ought to be using 'mixed' here *)
6110 ExpectedTy.make
pos Reason.URparam
(Typing_utils.mk_tany
env pos)
6113 List.map_env
env el (fun env elt
->
6114 let (env, te, ty) = expr ~
expected:expected_arg_ty env elt
in
6116 if TCO.global_inference
(Env.get_tcopt
env) then
6117 match get_node efty
with
6121 Typing_coercion.coerce_type
6126 (MakeType.unenforced efty
)
6134 | (_
, Callconv
(Ast_defs.Pinout
, e1
)) ->
6135 let (env, _te
, _ty
) =
6136 assign_
(fst e1
) Reason.URparam_inout
env e1 efty
6143 let env = call_untyped_unpack
env (Reason.to_pos
r) unpacked_element
in
6146 | Tprim Tnull
-> mk
(r, Tprim Tnull
)
6147 | Tdynamic
-> MakeType.dynamic
(Reason.Rdynamic_call
pos)
6150 Typing_utils.mk_tany
env pos
6152 | _
(* _ should not happen! *) ->
6155 (env, (tel
, None
, ty))
6156 | (_
, Tunion
[ty]) ->
6157 call ~
expected ~
nullsafe ?in_await
pos env ty el unpacked_element
6158 | (r, Tunion tyl
) ->
6160 List.map_env
env tyl
(fun env ty ->
6161 call ~
expected ~
nullsafe ?in_await
pos env ty el unpacked_element
)
6163 let retl = List.map resl ~f
:(fun (_
, _
, x) -> x) in
6164 let (env, ty) = Union.union_list
env r retl in
6165 (* We shouldn't be picking arbitrarily for the TAST here, as TAST checks
6166 * depend on the types inferred. Here's we're preserving legacy behaviour
6167 * by picking the last one.
6168 * TODO: don't do this, instead use subtyping to push unions
6169 * through function types
6171 let (tel
, typed_unpack_element
, _
) = List.hd_exn
(List.rev resl
) in
6172 (env, (tel
, typed_unpack_element
, ty))
6173 | (r, Tintersection tyl
) ->
6175 TUtils.run_on_intersection
env tyl ~f
:(fun env ty ->
6176 call ~
expected ~
nullsafe ?in_await
pos env ty el unpacked_element
)
6178 let retl = List.map resl ~f
:(fun (_
, _
, x) -> x) in
6179 let (env, ty) = Inter.intersect_list
env r retl in
6180 (* We shouldn't be picking arbitrarily for the TAST here, as TAST checks
6181 * depend on the types inferred. Here we're preserving legacy behaviour
6182 * by picking the last one.
6183 * TODO: don't do this, instead use subtyping to push intersections
6184 * through function types
6186 let (tel
, typed_unpack_element
, _
) = List.hd_exn
(List.rev resl
) in
6187 (env, (tel
, typed_unpack_element
, ty))
6189 (* Typing of format string functions. It is dependent on the arguments (el)
6190 * so it cannot be done earlier.
6192 let pos_def = Reason.to_pos r2
in
6193 let (env, ft) = Typing_exts.retype_magic_func
env ft el in
6194 let (env, var_param) = variadic_param
env ft in
6195 (* Force subtype with expected result *)
6197 check_expected_ty
"Call result" env ft.ft_ret.et_type
expected
6199 let env = Env.set_tyvar_variance
env ft.ft_ret.et_type
in
6207 let get_next_param_info paraml
=
6209 | param :: paraml
-> (false, Some
param, paraml
)
6210 | [] -> (true, var_param, paraml
)
6212 let expand_atom_in_enum pos env enum_name atom_name
=
6213 let cls = Env.get_class
env enum_name
in
6216 (match Env.get_const
env cls atom_name
with
6218 let dty = const_def
.cc_type
in
6220 Phase.localize_with_self
env ~ignore_errors
:true dty
6222 let hi = (pos, lty
) in
6223 let te = (hi, EnumAtom atom_name
) in
6224 (env, Some
(te, lty
))
6226 Errors.atom_unknown
pos atom_name enum_name
;
6227 let r = Reason.Rwitness
pos in
6228 let ty = Typing_utils.terr
env r in
6229 let te = ((pos, ty), EnumAtom atom_name
) in
6230 (env, Some
(te, ty)))
6231 | None
-> (env, None
)
6233 let check_arg env ((pos, arg
) as e) opt_param ~is_variadic
=
6234 match opt_param
with
6236 (* First check if __Atom is used *)
6237 let (env, atom_type
) =
6238 let is_atom = get_fp_is_atom
param in
6239 let ety = param.fp_type
.et_type
in
6241 | EnumAtom atom_name
when is_atom ->
6242 (match get_node
ety with
6243 | Tnewtype
(name, [ty_enum
; _ty_interface
], _
)
6244 when String.equal
name SN.Classes.cMemberOf
->
6245 (match get_node ty_enum
with
6246 | Tclass
((_
, enum_name
), _
, _
)
6247 when Env.is_enum_class
env enum_name
->
6248 expand_atom_in_enum pos env enum_name atom_name
6249 | Tgeneric
(name, _
) ->
6251 Typing_utils.collect_enum_class_upper_bounds
env name
6253 (* To avoid ambiguity, we only support the case where
6254 * there is a single upper bound that is an EnumClass.
6255 * We might want to relax that later (e.g. with the
6256 * support for intersections.
6257 * See Typing_check_decls.check_atom_on_param.
6259 if SSet.cardinal
upper_bounds = 1 then
6260 let enum_name = SSet.choose
upper_bounds in
6261 expand_atom_in_enum pos env enum_name atom_name
6265 (* Already reported, see Typing_check_decls *)
6268 (* Already reported, see Typing_check_decls *)
6270 | Class_const _
when is_atom ->
6271 Errors.atom_invalid_argument
pos;
6276 match atom_type
with
6277 | Some
(te, ty) -> (env, te, ty)
6280 ExpectedTy.make_and_allow_coercion_opt
6287 ~accept_using_var
:(get_fp_accept_disposable
param)
6292 let env = call_param
env param (e, ty) ~is_variadic
in
6293 (env, Some
(te, ty))
6296 ExpectedTy.make
pos Reason.URparam
(Typing_utils.mk_tany
env pos)
6298 let (env, te, ty) = expr ~
expected env e in
6299 (env, Some
(te, ty))
6301 let set_tyvar_variance_from_lambda_param env opt_param
=
6302 match opt_param
with
6304 let rec set_params_variance env ty =
6305 let (env, ty) = Env.expand_type
env ty in
6306 match get_node
ty with
6307 | Tunion
[ty] -> set_params_variance env ty
6308 | Toption
ty -> set_params_variance env ty
6309 | Tfun
{ ft_params; ft_ret; _
} ->
6313 ~f
:(fun env param ->
6314 Env.set_tyvar_variance
env param.fp_type
.et_type
)
6317 Env.set_tyvar_variance
env ft_ret.et_type ~flip
:true
6320 set_params_variance env param.fp_type
.et_type
6323 (* Given an expected function type ft, check types for the non-unpacked
6324 * arguments. Don't check lambda expressions if check_lambdas=false *)
6325 let rec check_args check_lambdas
env el paraml
=
6327 (* We've got an argument *)
6328 | (e, opt_result
) :: el ->
6329 (* Pick up next parameter type info *)
6330 let (is_variadic
, opt_param
, paraml
) = get_next_param_info paraml
in
6331 let (env, one_result
) =
6332 match (check_lambdas
, is_lambda e) with
6335 check_arg env e opt_param ~is_variadic
6337 let env = set_tyvar_variance_from_lambda_param env opt_param
in
6339 | (true, false) -> (env, opt_result
)
6341 let (env, rl
, paraml
) = check_args check_lambdas
env el paraml
in
6342 (env, (e, one_result
) :: rl
, paraml
)
6343 | [] -> (env, [], paraml
)
6345 (* Same as above, but checks the types of the implicit arguments, which are
6346 * read from the context *)
6347 let check_implicit_args env =
6349 Typing_coeffects.get_type
ft.ft_implicit_params
.capability
6351 if not
(TypecheckerOptions.call_coeffects
(Env.get_tcopt
env)) then
6354 let env_capability =
6355 Env.get_local_check_defined
env (pos, Typing_coeffects.capability_id
)
6363 (fun ?code
:_c _ _
->
6364 Errors.call_coeffect_error
6366 ~available_incl_unsafe
:
6367 (Typing_print.coeffects
env env_capability)
6368 ~available_pos
:(Typing_defs.get_pos
env_capability)
6369 ~required_pos
:(Typing_defs.get_pos
capability)
6370 ~required
:(Typing_print.coeffects
env capability))
6373 (* First check the non-lambda arguments. For generic functions, this
6374 * is likely to resolve type variables to concrete types *)
6375 let rl = List.map el (fun e -> (e, None
)) in
6376 let (env, rl, _
) = check_args false env rl ft.ft_params in
6377 (* Now check the lambda arguments, hopefully with type variables resolved *)
6378 let (env, rl, paraml
) = check_args true env rl ft.ft_params in
6379 (* We expect to see results for all arguments after this second pass *)
6383 | None
-> failwith
"missing parameter in check_args"
6386 let l = List.map rl (fun (_
, opt
) -> get_param opt
) in
6389 let env = check_implicit_args env in
6390 let (env, typed_unpack_element
, arity, did_unpack
) =
6391 match unpacked_element
with
6392 | None
-> (env, None
, List.length
el, false)
6394 (* Now that we're considering an splat (Some e) we need to construct a type that
6395 * represents the remainder of the function's parameters. `paraml` represents those
6396 * remaining parameters, and the variadic parameter is stored in `var_param`. For example, given
6398 * function f(int $i, string $j, float $k = 3.14, mixed ...$m): void {}
6399 * function g((string, float, bool) $t): void {
6403 * the constraint type we want is splat([#1], [opt#2], #3).
6405 let (consumed
, required_params
, optional_params
) =
6406 split_remaining_params_required_optional
ft paraml
6408 let (env, (d_required
, d_optional
, d_variadic
)) =
6409 generate_splat_type_vars
6416 let destructure_ty =
6419 ( Reason.Runpack_param
(fst
e, pos_def, consumed
),
6425 d_kind
= SplatUnpack
;
6428 let (env, te, ty) = expr env e in
6429 (* Populate the type variables from the expression in the splat *)
6439 (* Use the type variables for the remaining parameters *)
6445 ~f
:(fun env elt
param ->
6446 call_param
env param (e, elt
) ~is_variadic
:false)
6453 ~f
:(fun env elt
param ->
6454 call_param
env param (e, elt
) ~is_variadic
:false)
6457 Option.map2 d_variadic
var_param ~f
:(fun v vp
->
6458 call_param
env vp
(e, v
) ~is_variadic
:true)
6459 |> Option.value ~
default:env
6463 List.length
el + List.length d_required
,
6464 Option.is_some d_variadic
)
6466 (* If we unpacked an array, we don't check arity exactly. Since each
6467 * unpacked array consumes 1 or many parameters, it is nonsensical to say
6468 * that not enough args were passed in (so we don't do the min check).
6470 let () = check_arity ~did_unpack
pos pos_def ft arity in
6471 (* Variadic params cannot be inout so we can stop early *)
6472 let env = wfold_left2 inout_write_back
env ft.ft_params el in
6473 (env, (tel
, typed_unpack_element
, ft.ft_ret.et_type
))
6475 when TypecheckerOptions.method_call_inference
(Env.get_tcopt
env) ->
6477 Typecheck calls with unresolved function type by constructing a
6478 suitable function type from the arguments and invoking subtyping.
6480 let (env, typed_el
, type_of_el
) = exprs ~accept_using_var
:true env el in
6481 let (env, typed_unpacked_element
, type_of_unpacked_element
) =
6482 match unpacked_element
with
6484 let (env, typed_unpacked
, type_of_unpacked
) =
6485 expr ~accept_using_var
:true env unpacked
6487 (env, Some typed_unpacked
, Some type_of_unpacked
)
6488 | None
-> (env, None
, None
)
6490 let mk_function_supertype env pos (type_of_el
, type_of_unpacked_element
) =
6491 let mk_fun_param ty =
6493 (* Keep supertype as permissive as possible: *)
6495 ~
mode:FPnormal
(* TODO: deal with `inout` parameters *)
6496 ~accept_disposable
:false (* TODO: deal with disposables *)
6502 ~const_function
:false
6507 fp_type
= MakeType.enforced ty;
6512 match type_of_unpacked_element
with
6513 | Some type_of_unpacked
->
6514 let fun_param = mk_fun_param type_of_unpacked
in
6518 (* TODO: ensure `ft_params`/`ft_where_constraints` don't affect subtyping *)
6519 let ft_tparams = [] in
6520 let ft_where_constraints = [] in
6521 let ft_params = List.map ~f
:mk_fun_param type_of_el
in
6522 let ft_implicit_params =
6526 (* TODO(coeffects) should this be a different type? *);
6529 let (env, return_ty
) = Env.fresh_type
env pos in
6533 | Some
r -> MakeType.awaitable
r return_ty
6535 let ft_ret = MakeType.enforced return_ty in
6537 (* Keep supertype as permissive as possible: *)
6539 Ast_defs.FSync
(* `FSync` fun can still return `Awaitable<_>` *)
6540 ~return_disposable
:false (* TODO: deal with disposable return *)
6541 ~returns_readonly
:false
6542 ~readonly_this
:false
6545 let ft_ifc_decl = Typing_defs_core.default_ifc_fun_decl
in
6550 ft_where_constraints;
6558 let fun_type = mk
(r, Tfun
fun_locl_type) in
6559 let env = Env.set_tyvar_variance
env fun_type in
6560 (env, fun_type, return_ty)
6562 let (env, fun_type, return_ty) =
6563 mk_function_supertype env pos (type_of_el
, type_of_unpacked_element
)
6566 Type.sub_type
pos Reason.URnone
env efty
fun_type Errors.unify_error
6568 (env, (typed_el
, typed_unpacked_element
, return_ty))
6570 bad_call
env pos efty
;
6571 let env = call_untyped_unpack
env (get_pos efty
) unpacked_element
in
6572 (env, ([], None
, err_witness env pos))
6574 and split_remaining_params_required_optional
ft remaining_params =
6575 (* Same example as above
6577 * function f(int $i, string $j, float $k = 3.14, mixed ...$m): void {}
6578 * function g((string, float, bool) $t): void {
6582 * `remaining_params` will contain [string, float] and there has been 1 parameter consumed. The min_arity
6583 * of this function is 2, so there is 1 required parameter remaining and 1 optional parameter.
6587 ~f
:(fun fp
-> not
(Typing_defs.get_fp_has_default fp
))
6590 let original_params = ft.ft_params in
6591 let consumed = List.length
original_params - List.length
remaining_params in
6592 let required_remaining = Int.max
(min_arity - consumed) 0 in
6593 let (required_params
, optional_params
) =
6594 List.split_n
remaining_params required_remaining
6596 (consumed, required_params
, optional_params
)
6598 and generate_splat_type_vars
6599 env p required_params optional_params variadic_param
=
6600 let (env, d_required
) =
6601 List.map_env
env required_params ~f
:(fun env _
-> Env.fresh_type
env p)
6603 let (env, d_optional
) =
6604 List.map_env
env optional_params ~f
:(fun env _
-> Env.fresh_type
env p)
6606 let (env, d_variadic
) =
6607 match variadic_param
with
6608 | None
-> (env, None
)
6610 let (env, ty) = Env.fresh_type
env p in
6613 (env, (d_required
, d_optional
, d_variadic
))
6615 and call_param
env param (((pos, _
) as e), arg_ty
) ~is_variadic
=
6616 param_modes ~is_variadic
param e;
6618 (* When checking params, the type 'x' may be expression dependent. Since
6619 * we store the expression id in the local env for Lvar, we want to apply
6624 | Lvar _
-> ExprDepTy.make
env (CIexpr
e) arg_ty
6625 | _
-> (env, arg_ty
)
6627 Typing_coercion.coerce_type
6635 and call_untyped_unpack
env f_pos unpacked_element
=
6636 match unpacked_element
with
6637 (* In the event that we don't have a known function call type, we can still
6638 * verify that any unpacked arguments (`...$args`) are something that can
6639 * be actually unpacked. *)
6642 let (env, _
, ety) = expr env e ~
allow_awaitable:(*?*) false in
6643 let (env, ty) = Env.fresh_type
env (fst
e) in
6644 let destructure_ty =
6645 MakeType.simple_variadic_splat
(Reason.Runpack_param
(fst
e, f_pos
, 0)) ty
6655 and bad_call
env p ty = Errors.bad_call
p (Typing_print.error
env ty)
6657 and make_a_local_of
env e =
6659 | (p, Class_get
((_
, cname
), CGstring
(_
, member_name
), _
)) ->
6660 let (env, local) = Env.FakeMembers.make_static
env cname member_name
p in
6661 (env, Some
(p, local))
6664 ((((_
, This
) | (_
, Lvar _
)) as obj
), (_
, Id
(_
, member_name
)), _
, _
) )
6666 let (env, local) = Env.FakeMembers.make
env obj member_name
p in
6667 (env, Some
(p, local))
6669 | (_
, Dollardollar
x) ->
6673 (* This function captures the common bits of logic behind refinement
6674 * of the type of a local variable or a class member variable as a
6675 * result of a dynamic check (e.g., nullity check, simple type check
6676 * using functions like is_int, is_string, is_array etc.). The
6677 * argument refine is a function that takes the type of the variable
6678 * and returns a refined type (making necessary changes to the
6679 * environment, which is threaded through).
6681 * All refinement functions return, in addition to the updated
6682 * environment, a (conservative) set of all the locals that got
6683 * refined. This set is used to construct AssertEnv statmements in
6686 and refine_lvalue_type
env (((_p
, ty), _
) as te) ~refine
=
6687 let (env, ty) = refine
env ty in
6688 let e = Tast.to_nast_expr
te in
6689 let (env, localopt
) = make_a_local_of
env e in
6690 (* TODO TAST: generate an assignment to the fake local in the TAST *)
6692 | Some lid
-> (set_local
env lid
ty, Local_id.Set.singleton
(snd lid
))
6693 | None
-> (env, Local_id.Set.empty
)
6695 and condition_nullity ~nonnull
(env : env) te =
6697 (* assignment: both the rhs and lhs of the '=' must be made null/non-null *)
6698 | (_
, Aast.Binop
(Ast_defs.Eq None
, var
, te)) ->
6699 let (env, lset1
) = condition_nullity ~nonnull
env te in
6700 let (env, lset2
) = condition_nullity ~nonnull
env var
in
6701 (env, Local_id.Set.union lset1 lset2
)
6702 (* case where `Shapes::idx(...)` must be made null/non-null *)
6705 ( (_
, Aast.Class_const
((_
, Aast.CI
(_
, shapes
)), (_
, idx
))),
6709 when String.equal shapes
SN.Shapes.cShapes
&& String.equal idx
SN.Shapes.idx
6711 let field = Tast.to_nast_expr
field in
6712 let refine env shape_ty
=
6714 Typing_shapes.shapes_idx_not_null
env shape_ty
field
6718 refine_lvalue_type
env shape ~
refine
6722 Typing_solver.non_null
env p ty
6724 let r = Reason.Rwitness
(get_pos
ty) in
6725 Inter.intersect
env r ty (MakeType.null
r)
6727 refine_lvalue_type
env te ~
refine
6729 and condition_isset
env = function
6730 | (_
, Aast.Array_get
(x, _
)) -> condition_isset
env x
6731 | v
-> condition_nullity ~nonnull
:true env v
6734 * Build an environment for the true or false branch of
6735 * conditional statements.
6738 ?lhs_of_null_coalesce
env tparamet
((((p, ty) as pty
), e) as te : Tast.expr)
6740 let condition = condition ?lhs_of_null_coalesce
in
6742 | Aast.True
when not tparamet
->
6743 (LEnv.drop_cont
env C.Next
, Local_id.Set.empty
)
6744 | Aast.False
when tparamet
-> (LEnv.drop_cont
env C.Next
, Local_id.Set.empty
)
6745 | Aast.Call
((_
, Aast.Id
(_
, func
)), _
, [param], None
)
6746 when String.equal
SN.PseudoFunctions.isset func
6748 && not
(Env.is_strict
env) ->
6749 condition_isset
env param
6750 | Aast.Call
((_
, Aast.Id
(_
, func
)), _
, [te], None
)
6751 when String.equal
SN.StdlibFunctions.is_null func
->
6752 condition_nullity ~nonnull
:(not tparamet
) env te
6753 | Aast.Binop
((Ast_defs.Eqeq
| Ast_defs.Eqeqeq
), (_
, Aast.Null
), e)
6754 | Aast.Binop
((Ast_defs.Eqeq
| Ast_defs.Eqeqeq
), e, (_
, Aast.Null
)) ->
6755 condition_nullity ~nonnull
:(not tparamet
) env e
6759 | Aast.Binop
(Ast_defs.Eq None
, _
, _
) ->
6760 let (env, ety) = Env.expand_type
env ty in
6761 (match get_node
ety with
6762 | Tprim Tbool
-> (env, Local_id.Set.empty
)
6763 | _
-> condition_nullity ~nonnull
:tparamet
env te)
6764 | Aast.Binop
(((Ast_defs.Diff
| Ast_defs.Diff2
) as op
), e1
, e2) ->
6766 if Ast_defs.(equal_bop
op Diff
) then
6771 condition env (not tparamet
) (pty
, Aast.Binop
(op, e1
, e2))
6772 | Aast.Id
(p, s) when String.equal
s SN.Rx.is_enabled
->
6773 (* when Rx\IS_ENABLED is false - switch env to non-reactive *)
6775 if not tparamet
then
6776 if TypecheckerOptions.any_coeffects
(Env.get_tcopt
env) then
6777 let env = Typing_local_ops.enforce_rx_is_enabled
p env in
6778 let defaults = MakeType.default_capability
Pos.none
in
6779 fst
@@ Typing_coeffects.register_capabilities
env defaults defaults
6785 (env, Local_id.Set.empty
)
6786 (* Conjunction of conditions. Matches the two following forms:
6788 if (!(cond1 || cond2))
6790 | Aast.Binop
(((Ast_defs.Ampamp
| Ast_defs.Barbar
) as bop
), e1
, e2)
6791 when Bool.equal tparamet
Ast_defs.(equal_bop bop Ampamp
) ->
6792 let (env, lset1
) = condition env tparamet e1
in
6793 (* This is necessary in case there is an assignment in e2
6794 * We essentially redo what has been undone in the
6795 * `Binop (Ampamp|Barbar)` case of `expr` *)
6797 expr env (Tast.to_nast_expr
e2) ~
allow_awaitable:(*?*) false
6799 let (env, lset2
) = condition env tparamet
e2 in
6800 (env, Local_id.Set.union lset1 lset2
)
6801 (* Disjunction of conditions. Matches the two following forms:
6803 if (!(cond1 && cond2))
6805 | Aast.Binop
(((Ast_defs.Ampamp
| Ast_defs.Barbar
) as bop
), e1
, e2)
6806 when Bool.equal tparamet
Ast_defs.(equal_bop bop Barbar
) ->
6807 let (env, lset1
, lset2
) =
6811 (* Either cond1 is true and we don't know anything about cond2... *)
6812 condition env tparamet e1
)
6814 (* ... Or cond1 is false and therefore cond2 must be true *)
6815 let (env, _lset
) = condition env (not tparamet
) e1
in
6816 (* Similarly to the conjunction case, there might be an assignment in
6817 cond2 which we must account for. Again we redo what has been undone in
6818 the `Binop (Ampamp|Barbar)` case of `expr` *)
6820 expr env (Tast.to_nast_expr
e2) ~
allow_awaitable:(*?*) false
6822 condition env tparamet
e2)
6824 (env, Local_id.Set.union lset1 lset2
)
6825 | Aast.Call
(((p, _
), Aast.Id
(_
, f
)), _
, [lv
], None
)
6826 when tparamet
&& String.equal f
SN.StdlibFunctions.is_dict_or_darray
->
6827 safely_refine_is_array
env `HackDictOrDArray
p f lv
6828 | Aast.Call
(((p, _
), Aast.Id
(_
, f
)), _
, [lv
], None
)
6829 when tparamet
&& String.equal f
SN.StdlibFunctions.is_vec_or_varray
->
6830 safely_refine_is_array
env `HackVecOrVArray
p f lv
6831 | Aast.Call
(((p, _
), Aast.Id
(_
, f
)), _
, [lv
], None
)
6832 when tparamet
&& String.equal f
SN.StdlibFunctions.is_any_array
->
6833 safely_refine_is_array
env `AnyArray
p f lv
6834 | Aast.Call
(((p, _
), Aast.Id
(_
, f
)), _
, [lv
], None
)
6835 when tparamet
&& String.equal f
SN.StdlibFunctions.is_php_array
->
6836 safely_refine_is_array
env `PHPArray
p f lv
6838 ( (_
, Aast.Class_const
((_
, Aast.CI
(_
, class_name)), (_
, method_name
))),
6843 && String.equal
class_name SN.Shapes.cShapes
6844 && String.equal method_name
SN.Shapes.keyExists
->
6845 key_exists
env p shape
field
6846 | Aast.Unop
(Ast_defs.Unot
, e) -> condition env (not tparamet
) e
6847 | Aast.Is
(ivar
, h
) when is_instance_var
(Tast.to_nast_expr ivar
) ->
6848 let (env, hint_ty
) =
6849 Phase.localize_hint_with_self
env ~ignore_errors
:false h
6851 let reason = Reason.Ris
(fst h
) in
6852 let refine_type env hint_ty
=
6853 let (ivar_pos
, ivar_ty
) = fst ivar
in
6854 let (env, ivar
) = get_instance_var
env (Tast.to_nast_expr ivar
) in
6855 let (env, hint_ty
) =
6856 class_for_refinement
env p reason ivar_pos ivar_ty hint_ty
6858 let (env, refined_ty
) = Inter.intersect
env reason ivar_ty hint_ty
in
6859 (set_local
env ivar refined_ty
, Local_id.Set.singleton
(snd ivar
))
6861 let (env, hint_ty
) =
6862 if not tparamet
then
6863 Inter.non
env reason hint_ty ~approx
:TUtils.ApproxUp
6867 refine_type env hint_ty
6868 | _
-> (env, Local_id.Set.empty
)
6870 (** Transform a hint like `A<_>` to a localized type like `A<T#1>` for refinement of
6871 an instance variable. ivar_ty is the previous type of that instance variable. *)
6872 and class_for_refinement
env p reason ivar_pos ivar_ty hint_ty
=
6873 let (env, hint_ty
) = Env.expand_type
env hint_ty
in
6874 match (get_node ivar_ty
, get_node hint_ty
) with
6875 | (_
, Tclass
(((_
, cid) as _c
), _
, tyl
)) ->
6877 match Env.get_class
env cid with
6878 | Some
class_info ->
6879 let (env, tparams_with_new_names
, tyl_fresh
) =
6880 generate_fresh_tparams
env class_info reason tyl
6882 safely_refine_class_type
6890 tparams_with_new_names
6892 | None
-> (env, mk
(Reason.Rwitness ivar_pos
, Tobject
))
6894 | (Ttuple ivar_tyl
, Ttuple hint_tyl
)
6895 when Int.equal
(List.length ivar_tyl
) (List.length hint_tyl
) ->
6897 List.map2_env
env ivar_tyl hint_tyl
(fun env ivar_ty hint_ty
->
6898 class_for_refinement
env p reason ivar_pos ivar_ty hint_ty
)
6900 (env, MakeType.tuple
reason tyl
)
6901 | _
-> (env, hint_ty
)
6903 (** If we are dealing with a refinement like
6905 then class_info is the class info of MyClass and hint_tyl corresponds
6907 and generate_fresh_tparams
env class_info reason hint_tyl
=
6908 let tparams_len = List.length
(Cls.tparams
class_info) in
6909 let hint_tyl = List.take
hint_tyl tparams_len in
6910 let pad_len = tparams_len - List.length
hint_tyl in
6912 List.map hint_tyl (fun x -> Some
x) @ List.init pad_len (fun _
-> None
)
6914 let replace_wildcard env hint_ty tp
=
6916 tp_name
= (_
, tparam_name
);
6917 tp_reified
= reified
;
6924 Attributes.mem
SN.UserAttributes.uaEnforceable tp_user_attributes
6927 Attributes.mem
SN.UserAttributes.uaNewable tp_user_attributes
6932 match get_node
ty with
6933 | Tgeneric
(name, _targs
) when Env.is_fresh_generic_parameter
name ->
6934 (* TODO(T69551141) handle type arguments above and below *)
6935 (env, (Some
(tp
, name), MakeType.generic
reason name))
6936 | _
-> (env, (None
, ty))
6939 let (env, new_name
) =
6940 Env.add_fresh_generic_parameter
6947 (* TODO(T69551141) handle type arguments for Tgeneric *)
6948 (env, (Some
(tp
, new_name
), MakeType.generic
reason new_name
))
6950 let (env, tparams_and_tyl
) =
6951 List.map2_env
env hint_tyl (Cls.tparams
class_info) ~f
:replace_wildcard
6953 let (tparams_with_new_names
, tyl_fresh
) = List.unzip tparams_and_tyl
in
6954 (env, tparams_with_new_names
, tyl_fresh
)
6956 and safely_refine_class_type
6964 (tparams_with_new_names
: (decl_tparam
* string) option list
)
6966 (* Type of variable in block will be class name
6967 * with fresh type parameters *)
6969 mk
(get_reason
obj_ty, Tclass
(class_name, Nonexact
, tyl_fresh
))
6971 let tparams = Cls.tparams class_info in
6972 (* Add in constraints as assumptions on those type parameters *)
6975 type_expansions
= [];
6976 substs
= Subst.make_locl
tparams tyl_fresh
;
6978 on_error
= Errors.ignore_error
;
6981 let add_bounds env (t
, ty_fresh
) =
6982 List.fold_left t
.tp_constraints ~
init:env ~f
:(fun env (ck
, ty) ->
6983 (* Substitute fresh type parameters for
6984 * original formals in constraint *)
6985 let (env, ty) = Phase.localize ~
ety_env env ty in
6986 SubType.add_constraint
p env ck ty_fresh
ty)
6989 List.fold_left
(List.zip_exn
tparams tyl_fresh
) ~f
:add_bounds ~
init:env
6991 (* Finally, if we have a class-test on something with static classish type,
6992 * then we can chase the hierarchy and decompose the types to deduce
6993 * further assumptions on type parameters. For example, we might have
6994 * class B<Tb> { ... }
6995 * class C extends B<int>
6996 * and have obj_ty = C and x_ty = B<T> for a generic parameter Aast.
6997 * Then SubType.add_constraint will deduce that T=int and add int as
6998 * both lower and upper bound on T in env.lenv.tpenv
7000 let (env, supertypes
) = TUtils.get_concrete_supertypes
env ivar_ty
in
7002 List.fold_left supertypes ~
init:env ~f
:(fun env ty ->
7003 SubType.add_constraint
p env Ast_defs.Constraint_as
obj_ty ty)
7005 (* It's often the case that the fresh name isn't necessary. For
7006 * example, if C<T> extends B<T>, and we have $x:B<t> for some type t
7007 * then $x is C should refine to $x:C<t>.
7008 * We take a simple approach:
7009 * For a fresh type parameter T#1, if
7010 * - There is an eqality constraint T#1 = t,
7011 * - T#1 is covariant, and T#1 has upper bound t (or mixed if absent)
7012 * - T#1 is contravariant, and T#1 has lower bound t (or nothing if absent)
7013 * then replace T#1 with t.
7014 * This is done in Type_parameter_env_ops.simplify_tpenv
7016 let (env, tparam_substs
) =
7017 Type_parameter_env_ops.simplify_tpenv
7019 (List.zip_exn tparams_with_new_names tyl_fresh
)
7023 List.map2_exn
tyl_fresh tparams_with_new_names ~f
:(fun orig_ty tparam_opt
->
7024 match tparam_opt
with
7026 | Some
(_tp
, name) -> SMap.find
name tparam_substs
)
7028 let obj_ty_simplified =
7029 mk
(get_reason
obj_ty, Tclass
(class_name, Nonexact
, tyl_fresh))
7031 (env, obj_ty_simplified)
7033 and is_instance_var
= function
7034 | (_
, (Lvar _
| This
| Dollardollar _
)) -> true
7035 | (_
, Obj_get
((_
, This
), (_
, Id _
), _
, _
)) -> true
7036 | (_
, Obj_get
((_
, Lvar _
), (_
, Id _
), _
, _
)) -> true
7037 | (_
, Class_get
(_
, _
, _
)) -> true
7040 and get_instance_var
env = function
7041 | (p, Class_get
((_
, cname
), CGstring
(_
, member_name
), _
)) ->
7042 let (env, local) = Env.FakeMembers.make_static
env cname member_name
p in
7046 ((((_
, This
) | (_
, Lvar _
)) as obj
), (_
, Id
(_
, member_name
)), _
, _
) )
7048 let (env, local) = Env.FakeMembers.make
env obj member_name
p in
7050 | (_
, Dollardollar
(p, x))
7051 | (_
, Lvar
(p, x)) ->
7053 | (p, This
) -> (env, (p, this
))
7054 | _
-> failwith
"Should only be called when is_instance_var is true"
7056 (* Refine type for is_array, is_vec, is_keyset and is_dict tests
7057 * `pred_name` is the function name itself (e.g. 'is_vec')
7058 * `p` is position of the function name in the source
7059 * `arg_expr` is the argument to the function
7061 and safely_refine_is_array
env ty p pred_name arg_expr
=
7062 refine_lvalue_type
env arg_expr ~
refine:(fun env arg_ty
->
7063 let r = Reason.Rpredicated
(p, pred_name
) in
7064 let (env, tarrkey_name
) =
7065 Env.add_fresh_generic_parameter
7072 (* TODO(T69551141) handle type arguments for Tgeneric *)
7073 let tarrkey = MakeType.generic
r tarrkey_name
in
7075 SubType.add_constraint
7078 Ast_defs.Constraint_as
7080 (MakeType.arraykey r)
7082 let (env, tfresh_name
) =
7083 Env.add_fresh_generic_parameter
7090 (* TODO(T69551141) handle type arguments for Tgeneric *)
7091 let tfresh = MakeType.generic
r tfresh_name
in
7092 (* If we're refining the type for `is_array` we have a slightly more
7093 * involved process. Let's separate out that logic so we can re-use it.
7096 TypecheckerOptions.hack_arr_dv_arrs
(Env.get_tcopt
env)
7099 let safe_isarray_enabled =
7100 TypecheckerOptions.experimental_feature_enabled
7102 TypecheckerOptions.experimental_isarray
7104 let tk = MakeType.arraykey Reason.(Rvarray_or_darray_key
(to_pos
r)) in
7106 if safe_isarray_enabled then
7109 mk
(r, TUtils.tany
env)
7111 MakeType.varray_or_darray ~
unification r tk tv
7113 (* This is the refined type of e inside the branch *)
7116 | `HackDict
-> MakeType.dict
r tarrkey tfresh
7117 | `HackVec
-> MakeType.vec
r tfresh
7118 | `HackKeyset
-> MakeType.keyset
r tarrkey
7119 | `PHPArray
-> array_ty
7120 | `AnyArray
-> MakeType.any_array
r tarrkey tfresh
7121 | `HackDictOrDArray
->
7125 MakeType.dict
r tarrkey tfresh;
7126 MakeType.darray ~
unification r tarrkey tfresh;
7128 | `HackVecOrVArray
->
7131 [MakeType.vec
r tfresh; MakeType.varray ~
unification r tfresh]
7133 let ((arg_pos
, _
), _
) = arg_expr
in
7134 let (env, hint_ty) =
7135 class_for_refinement
env p r arg_pos arg_ty
hint_ty
7137 (* Add constraints on generic parameters that must
7138 * hold for refined_ty <:arg_ty. For example, if arg_ty is Traversable<T>
7139 * and refined_ty is keyset<T#1> then we know T#1 <: T.
7140 * See analogous code in safely_refine_class_type.
7142 let (env, supertypes
) = TUtils.get_concrete_supertypes
env arg_ty
in
7144 List.fold_left supertypes ~
init:env ~f
:(fun env ty ->
7145 SubType.add_constraint
p env Ast_defs.Constraint_as
hint_ty ty)
7147 Inter.intersect ~
r env hint_ty arg_ty
)
7149 and key_exists
env pos shape
field =
7150 let field = Tast.to_nast_expr
field in
7151 refine_lvalue_type
env shape ~
refine:(fun env shape_ty
->
7152 match TUtils.shape_field_name
env field with
7153 | None
-> (env, shape_ty
)
7154 | Some
field_name ->
7155 let field_name = TShapeField.of_ast
(fun p -> p) field_name in
7156 Typing_shapes.refine_shape
field_name pos env shape_ty
)
7158 and string2
env idl
=
7160 List.fold_left idl ~
init:(env, []) ~f
:(fun (env, tel
) x ->
7161 let (env, te, ty) = expr env x ~
allow_awaitable:(*?*) false in
7164 TypecheckerOptions.enable_strict_string_concat_interp
7167 let r = Reason.Rinterp_operand
p in
7168 let (env, formatter_tyvar
) = Env.fresh_invariant_type_var
env p in
7173 MakeType.arraykey r;
7174 MakeType.new_type
r SN.Classes.cHHFormatString
[formatter_tyvar
];
7184 Errors.strict_str_interp_type_mismatch
7188 let env = Typing_substring.sub_string
p env ty in
7193 and user_attribute
env ua
=
7194 let (env, typed_ua_params
) =
7195 List.map_env
env ua
.ua_params
(fun env e ->
7196 let (env, te, _
) = expr env e ~
allow_awaitable:(*?*) false in
7199 (env, { Aast.ua_name
= ua
.ua_name
; Aast.ua_params
= typed_ua_params
})
7201 and file_attributes
env file_attrs
=
7202 (* Disable checking of error positions, as file attributes have spans that
7203 * aren't subspans of the class or function into which they are copied *)
7204 Errors.run_with_span
Pos.none
@@ fun () ->
7205 let uas = List.concat_map ~f
:(fun fa
-> fa
.fa_user_attributes
) file_attrs
in
7206 let env = attributes_check_def
env SN.AttributeKinds.file
uas in
7207 List.map_env
env file_attrs
(fun env fa
->
7208 let (env, user_attributes
) =
7209 List.map_env
env fa
.fa_user_attributes user_attribute
7211 let env = set_tcopt_unstable_features env fa
in
7214 Aast.fa_user_attributes
= user_attributes
;
7215 Aast.fa_namespace
= fa
.fa_namespace
;
7218 and type_param
env t
=
7220 attributes_check_def
env SN.AttributeKinds.typeparam t
.tp_user_attributes
7222 let (env, user_attributes
) =
7223 List.map_env
env t
.tp_user_attributes user_attribute
7225 let (env, tp_parameters
) = List.map_env
env t
.tp_parameters type_param
in
7228 Aast.tp_variance
= t
.tp_variance
;
7229 Aast.tp_name
= t
.tp_name
;
7231 Aast.tp_constraints
= t
.tp_constraints
;
7232 Aast.tp_reified
= reify_kind t
.tp_reified
;
7233 Aast.tp_user_attributes
= user_attributes
;
7236 and typedef_def ctx typedef
=
7237 let env = EnvFromDef.typedef_env ~origin
:Decl_counters.TopLevel ctx typedef
in
7239 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
7240 (fst typedef
.t_name
)
7242 ~ignore_errors
:false
7246 Typing_check_decls.typedef
env typedef
;
7247 Typing_variance.typedef
env typedef
;
7250 t_name
= (t_pos
, t_name
);
7252 t_constraint
= tcstr
;
7254 t_user_attributes
= _
;
7264 Phase.localize_hint_with_self
7266 ~ignore_errors
:false
7267 ~report_cycle
:(t_pos
, t_name
)
7274 Phase.localize_hint_with_self
env ~ignore_errors
:false tcstr
7278 Reason.URnewtype_cstr
7282 Errors.newtype_alias_must_satisfy_constraint
7287 | (pos, Hshape
{ nsi_allows_unknown_fields
= _
; nsi_field_map
}) ->
7288 let get_name sfi
= sfi
.sfi_name
in
7289 check_shape_keys_validity
env pos (List.map ~f
:get_name nsi_field_map
)
7293 attributes_check_def
7295 SN.AttributeKinds.typealias
7296 typedef
.t_user_attributes
7298 let (env, tparams) = List.map_env
env typedef
.t_tparams type_param
in
7299 let (env, user_attributes
) =
7300 List.map_env
env typedef
.t_user_attributes user_attribute
7303 Aast.t_annotation
= Env.save
(Env.get_tpenv
env) env;
7304 Aast.t_name
= typedef
.t_name
;
7305 Aast.t_mode
= typedef
.t_mode
;
7306 Aast.t_vis
= typedef
.t_vis
;
7307 Aast.t_user_attributes
= user_attributes
;
7308 Aast.t_constraint
= typedef
.t_constraint
;
7309 Aast.t_kind
= typedef
.t_kind
;
7310 Aast.t_tparams
= tparams;
7311 Aast.t_namespace
= typedef
.t_namespace
;
7312 Aast.t_span
= typedef
.t_span
;
7313 Aast.t_emit_id
= typedef
.t_emit_id
;
7316 (* Calls the method of a class, but allows the f callback to override the
7317 * return value type *)
7318 and overload_function
7319 make_call fpos
p env (cpos
, class_id
) method_id
el unpacked_element f
=
7320 let (env, _tal
, tcid
, ty) =
7321 static_class_id ~check_constraints
:false cpos
env [] class_id
7323 let (env, _tel
, _
) = exprs env el ~
allow_awaitable:(*?*) false in
7324 let (env, (fty, tal
)) =
7328 ~coerce_from_ty
:None
7334 let (env, (tel
, typed_unpack_element
, res
)) =
7335 call ~
expected:None
p env fty el unpacked_element
7337 let (env, ty) = f
env fty res
el in
7338 let (env, fty) = Env.expand_type
env fty in
7340 map_ty
fty ~f
:(function
7341 | Tfun
ft -> Tfun
{ ft with ft_ret = MakeType.unenforced
ty }
7344 let te = Tast.make_typed_expr fpos
fty (Aast.Class_const
(tcid
, method_id
)) in
7345 make_call env te tal tel typed_unpack_element
ty
7347 and update_array_type ?lhs_of_null_coalesce
p env e1
valkind =
7350 | `lvalue_subexpr
->
7351 let (env, te1, ty1
) =
7353 ~
valkind:`lvalue_subexpr
7357 ~
allow_awaitable:(*?*) false
7361 | (_
, Lvar
(_
, x)) ->
7362 (* type_mapper has updated the type in ty1 typevars, but we
7363 need to update the local variable type too *)
7364 let env = set_local
env (p, x) ty1
in
7366 | _
-> (env, te1, ty1
)
7368 | _
-> raw_expr ?lhs_of_null_coalesce
env e1 ~
allow_awaitable:(*?*) false
7371 let expr ?
expected env e =
7372 Typing_env.with_origin2
env Decl_counters.Body
(fun env ->
7373 expr ?
expected env e ~
allow_awaitable:(*?*) false)
7375 let expr_with_pure_coeffects ?
expected env e =
7376 Typing_env.with_origin2
env Decl_counters.Body
(fun env ->
7377 expr_with_pure_coeffects ?
expected env e ~
allow_awaitable:(*?*) false)
7380 Typing_env.with_origin
env Decl_counters.Body
(fun env -> stmt env st
)