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.
15 module Reason
= Typing_reason
16 module MakeType
= Typing_make_type
17 module Phase
= Typing_phase
18 module TUtils
= Typing_utils
19 module Env
= Typing_env
21 let enforce_param_not_disposable env param ty
=
22 if has_accept_disposable_attribute param
then
26 (Typing_disposable.is_disposable_type env ty
)
28 Typing_error.Primary.Invalid_disposable_hint
29 { pos
= param
.param_pos
; class_name
= Utils.strip_ns class_name
})
31 let check_param_has_hint env param ty
=
33 if Env.is_hhi env
then
35 else if Option.is_none
(hint_of_type_hint param
.param_type_hint
) then
37 (if param
.param_is_variadic
then
38 Typing_error.Primary.Expecting_type_hint_variadic param
.param_pos
40 Typing_error.Primary.Expecting_type_hint param
.param_pos
)
42 (* We do not permit hints to implement IDisposable or IAsyncDisposable *)
43 enforce_param_not_disposable env param ty
45 Option.iter
prim_err_opt ~f
:(fun err
->
46 Errors.add_typing_error
@@ Typing_error.primary err
)
48 (* This function is used to determine the type of an argument.
49 * When we want to type-check the body of a function, we need to
50 * introduce the type of the arguments of the function in the environment
51 * Let's take an example, we want to check the code of foo:
53 * function foo(int $x): int {
54 * // CALL TO make_param_type on (int $x)
55 * // Now we know that the type of $x is int
57 * return $x; // in the environment $x is an int, the code is correct
60 * When we localize, we want to resolve to "static" or "$this" depending on
61 * the context. Even though we are passing in CIstatic, resolve_with_class_id
62 * is smart enough to know what to do. Why do this? Consider the following
65 * abstract const type T;
67 * private this::T $val;
69 * final public function __construct(this::T $x) {
73 * public static function create(this::T $x): this {
74 * return new static($x);
78 * class D extends C { const type T = int; }
80 * In __construct() we want to be able to assign $x to $this->val. The type of
81 * $this->val will expand to '$this::T', so we need $x to also be '$this::T'.
82 * We can do this soundly because when we construct a new class such as,
83 * 'new D(0)' we can determine the late static bound type (D) and resolve
84 * 'this::T' to 'D::T' which is int.
86 * A similar line of reasoning is applied for the static method create.
88 let make_param_local_ty ~dynamic_mode env decl_hint param
=
89 let r = Reason.Rwitness param
.param_pos
in
90 let ((env
, ty_err_opt
), ty
) =
92 | None
-> ((env
, None
), mk
(r, TUtils.tany env
))
94 let { et_type
= ty
; et_enforced
} =
95 Typing_enforceability.compute_enforced_and_pessimize_ty
96 ~explicitly_untrusted
:param
.param_is_variadic
100 (* If a non-inout parameter hint has the form ~t, where t is enforced,
101 * then we know that the parameter has type t after enforcement.
104 match (get_node
ty, et_enforced
, param
.param_callconv
) with
105 | (Tlike
ty, Enforced
, Ast_defs.Pnormal
) -> ty
108 Phase.localize_no_subst env ~ignore_errors
:false ty
110 Option.iter ty_err_opt ~f
:Errors.add_typing_error
;
112 match get_node
ty with
113 | t
when param
.param_is_variadic
->
114 (* when checking the body of a function with a variadic
115 * argument, "f(C ...$args)", $args is a varray<C> *)
116 let r = Reason.Rvar_param param
.param_pos
in
117 let arr_values = mk
(r, t
) in
118 MakeType.varray
r arr_values
121 (* Don't check (again) for existence of hint in dynamic mode *)
122 if not dynamic_mode
then check_param_has_hint env param
ty;
125 let make_param_local_tys ~dynamic_mode env decl_tys params
=
126 List.zip_exn params decl_tys
127 |> List.map_env env ~f
:(fun env
(param
, hint
) ->
131 Typing_make_type.dynamic
132 (Reason.Rsupport_dynamic_type
133 (Pos_or_decl.of_raw_pos param
.param_pos
))
136 | Some
ty when Typing_enforceability.is_enforceable env
ty ->
138 (Typing_make_type.intersection
139 (Reason.Rsupport_dynamic_type
Pos_or_decl.none
)
145 make_param_local_ty ~dynamic_mode env
ty param
)