2 * Copyright (c) 2018, 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.
14 let get_classname_or_literal_attribute_param = function
15 | [(_
, String s
)] -> Some s
16 | [(_
, Class_const
((_
, CI
(_
, s
)), (_
, name
)))]
17 when String.equal name
SN.Members.mClass
->
21 let find_policied_attribute user_attributes
: ifc_fun_decl
=
22 match Naming_attributes.find
SN.UserAttributes.uaPolicied user_attributes
with
23 | Some
{ ua_params
; _
} ->
24 (match get_classname_or_literal_attribute_param ua_params
with
25 | Some s
-> FDPolicied
(Some s
)
26 | None
-> FDPolicied None
)
28 when Naming_attributes.mem
SN.UserAttributes.uaInferFlows user_attributes
->
30 | None
-> default_ifc_fun_decl
32 let has_constfun_attribute user_attributes
=
33 Naming_attributes.mem
SN.UserAttributes.uaConstFun user_attributes
35 let has_accept_disposable_attribute user_attributes
=
36 Naming_attributes.mem
SN.UserAttributes.uaAcceptDisposable user_attributes
38 let has_external_attribute user_attributes
=
39 Naming_attributes.mem
SN.UserAttributes.uaExternal user_attributes
41 let has_can_call_attribute user_attributes
=
42 Naming_attributes.mem
SN.UserAttributes.uaCanCall user_attributes
44 let has_atom_attribute user_attributes
=
45 Naming_attributes.mem
SN.UserAttributes.uaAtom user_attributes
47 let has_return_disposable_attribute user_attributes
=
48 Naming_attributes.mem
SN.UserAttributes.uaReturnDisposable user_attributes
50 exception Gi_reinfer_type_not_supported
52 let cut_namespace id
=
53 let ids = String.split id ~on
:'
\\'
in
56 let rec reinfer_type_to_string_exn ty
=
59 | Tnonnull
-> "nonnull"
60 | Tdynamic
-> "dynamic"
61 | Tunion
[] -> "nothing"
71 | Tarraykey
-> "arraykey"
72 | Tresource
-> "resource"
73 | Tnoreturn
-> "noreturn"
75 | Tapply
((_p
, id
), _tyl
) -> cut_namespace id
77 let s = reinfer_type_to_string_exn (get_node ty
) in
78 Printf.sprintf
"%s::%s" s (snd id
)
79 | _
-> raise Gi_reinfer_type_not_supported
81 let reinfer_type_to_string_opt ty
=
82 try Some
(reinfer_type_to_string_exn ty
)
83 with Gi_reinfer_type_not_supported
-> None
85 let must_reinfer_type tcopt
(ty
: decl_phase ty_
) =
86 let reinfer_types = GlobalOptions.tco_gi_reinfer_types tcopt
in
87 match reinfer_type_to_string_opt ty
with
89 | Some ty_str
-> List.mem
reinfer_types ty_str ~equal
:String.equal
91 let hint_to_type_opt ~is_lambda env reason hint
=
92 let ty = Option.map hint ~f
:(Decl_hint.hint env
) in
93 let tcopt = Provider_context.get_tcopt env
.Decl_env.ctx
in
94 let tco_global_inference = GlobalOptions.tco_global_inference tcopt in
95 let tvar = mk
(reason
, Tvar
0) in
96 if tco_global_inference && not is_lambda
then
101 let rec create_vars_for_reinfer_types ty =
103 | (r
, Tapply
(id
, [ty'
]))
104 when String.equal
(snd id
) SN.Classes.cAwaitable
->
105 let ty'
= create_vars_for_reinfer_types ty'
in
106 mk
(r
, Tapply
(id
, [ty'
]))
107 | (r
, Toption
ty'
) ->
108 let ty'
= create_vars_for_reinfer_types ty'
in
110 | (r
, Tapply
((_p
, id
), []))
111 when String.equal
(cut_namespace id
) "PHPism_FIXME_Array" ->
112 if must_reinfer_type tcopt (get_node
ty) then
113 let tvar = mk
(r
, Tvar
0) in
114 mk
(r
, Tvarray_or_darray
(tvar, tvar))
118 let ty = create_vars_for_reinfer_types ty in
120 | (r
, Tdarray
(tyk
, tyv
)) ->
121 let tyk = create_vars_for_reinfer_types tyk in
122 let tyv = create_vars_for_reinfer_types tyv in
123 mk
(r
, Tdarray
(tyk, tyv))
124 | (r
, Tvarray_or_darray
(tyk, tyv)) ->
125 let tyk = create_vars_for_reinfer_types tyk in
126 let tyv = create_vars_for_reinfer_types tyv in
127 mk
(r
, Tvarray_or_darray
(tyk, tyv))
129 if must_reinfer_type tcopt ty_
then
134 create_vars_for_reinfer_types ty
140 let hint_to_type ~is_lambda ~default env reason hint
=
141 Option.value (hint_to_type_opt ~is_lambda env reason hint
) ~default
143 let make_param_ty env ~is_lambda param
=
144 let param_pos = Decl_env.make_decl_pos env param
.param_pos in
146 let r = Reason.Rwitness
param_pos in
149 ~default
:(mk
(r, Typing_defs.make_tany
()))
151 (Reason.Rglobal_fun_param
param_pos)
152 (hint_of_type_hint param
.param_type_hint
)
155 match get_node
ty with
156 | t
when param
.param_is_variadic
->
157 (* When checking a call f($a, $b) to a function f(C ...$args),
158 * both $a and $b must be of type C *)
159 mk
(Reason.Rvar_param
param_pos, t
)
162 let module UA
= SN.UserAttributes
in
163 let mode = get_param_mode param
.param_callconv
in
166 fp_name
= Some param
.param_name
;
167 fp_type
= { et_type
= ty; et_enforced
= false };
172 (has_accept_disposable_attribute param
.param_user_attributes
)
173 ~has_default
:(Option.is_some param
.param_expr
)
174 ~ifc_external
:(has_external_attribute param
.param_user_attributes
)
175 ~ifc_can_call
:(has_can_call_attribute param
.param_user_attributes
)
176 ~is_atom
:(has_atom_attribute param
.param_user_attributes
)
177 ~readonly
:(Option.is_some param
.param_readonly
)
178 ~const_function
:(has_constfun_attribute param
.param_user_attributes
);
181 (** Make FunParam for the partial-mode ellipsis parameter (unnamed, and untyped) *)
182 let make_ellipsis_param_ty :
183 Decl_env.env
-> Pos.t
-> 'phase
ty Typing_defs_core.fun_param
=
185 let pos = Decl_env.make_decl_pos env
pos in
186 let r = Reason.Rwitness
pos in
187 let ty = mk
(r, Typing_defs.make_tany
()) in
191 fp_type
= { et_type
= ty; et_enforced
= false };
195 ~accept_disposable
:false
201 ~const_function
:false;
204 let ret_from_fun_kind ?
(is_constructor
= false) ~is_lambda env
pos kind hint
=
205 let pos = Decl_env.make_decl_pos env
pos in
206 let default = mk
(Reason.Rwitness
pos, Typing_defs.make_tany
()) in
208 if is_constructor
then
209 mk
(Reason.Rwitness
pos, Tprim Tvoid
)
211 hint_to_type ~is_lambda ~
default env
(Reason.Rglobal_fun_ret
pos) hint
216 | Ast_defs.FGenerator
->
217 let r = Reason.Rret_fun_kind
(pos, kind
) in
221 ((pos, SN.Classes.cGenerator
), [ret_ty (); ret_ty (); ret_ty ()]) )
222 | Ast_defs.FAsyncGenerator
->
223 let r = Reason.Rret_fun_kind
(pos, kind
) in
227 ( (pos, SN.Classes.cAsyncGenerator
),
228 [ret_ty (); ret_ty (); ret_ty ()] ) )
230 let r = Reason.Rret_fun_kind
(pos, kind
) in
231 mk
(r, Tapply
((pos, SN.Classes.cAwaitable
), [ret_ty ()]))
232 | Ast_defs.FSync
-> ret_ty ())
233 | Some _
-> ret_ty ()
235 let type_param = Decl_hint.aast_tparam_to_decl_tparam
237 let where_constraint env
(ty1
, ck
, ty2
) =
238 (Decl_hint.hint env ty1
, ck
, Decl_hint.hint env ty2
)
240 (* Functions building the types for the parameters of a function *)
241 (* It's not completely trivial because of optional arguments *)
243 let check_params paraml
=
244 (* We wish to give an error on the first non-default parameter
245 after a default parameter. That is:
246 function foo(int $x, ?int $y = null, int $z)
247 is an error on $z. *)
248 (* TODO: This check doesn't need to be done at type checking time; it is
249 entirely syntactic. When we switch over to the FFP, remove this code. *)
250 let rec loop seen_default paraml
=
254 if param
.param_is_variadic
then
256 (* Assume that a variadic parameter is the last one we need
257 to check. We've already given a parse error if the variadic
258 parameter is not last. *)
259 else if seen_default
&& Option.is_none param
.param_expr
then
260 Errors.previous_default param
.param_pos
261 (* We've seen at least one required parameter, and there's an
262 optional parameter after it. Given an error, and then stop looking
263 for more errors in this parameter list. *)
265 loop (Option.is_some param
.param_expr
) rl
269 let make_params env ~is_lambda paraml
=
270 List.map paraml ~f
:(make_param_ty env ~is_lambda
)