Introduce the ConstFun attribute
[hiphop-php.git] / hphp / hack / src / decl / decl_hint.ml
blob16bcb6468beee2c60d5a59cc8708c3ea1c6dc7b6
1 (*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
8 *)
10 (*****************************************************************************)
11 (* Converts a type hint into a type *)
12 (*****************************************************************************)
13 open Hh_prelude
14 open Aast
15 open Typing_defs
17 (* Unpacking a hint for typing *)
18 let rec hint env (p, h) =
19 let h = hint_ p env h in
20 mk (Typing_reason.Rhint (Decl_env.make_decl_pos env p), h)
22 and shape_field_info_to_shape_field_type
23 env { sfi_optional; sfi_hint; sfi_name = _ } =
24 { sft_optional = sfi_optional; sft_ty = hint env sfi_hint }
26 and aast_user_attribute_to_decl_user_attribute env { ua_name; ua_params } =
28 Typing_defs.ua_name = Decl_env.make_decl_posed env ua_name;
29 ua_classname_params =
30 List.filter_map ua_params ~f:(function
31 | (_, Class_const ((_, CI (_, cls)), (_, name)))
32 when String.equal name SN.Members.mClass ->
33 Some cls
34 | _ -> None);
37 and aast_contexts_to_decl_capability env ctxs default_pos =
38 let default_pos = Decl_env.make_decl_pos env default_pos in
39 match ctxs with
40 | Some (pos, hl) ->
41 let pos = Decl_env.make_decl_pos env pos in
42 let hl = List.map ~f:(hint env) hl in
43 CapTy (Typing_make_type.intersection (Reason.Rhint pos) hl)
44 | None -> CapDefaults default_pos
46 and aast_tparam_to_decl_tparam env t =
48 tp_variance = t.Aast.tp_variance;
49 tp_name = Decl_env.make_decl_posed env t.Aast.tp_name;
50 tp_tparams =
51 List.map ~f:(aast_tparam_to_decl_tparam env) t.Aast.tp_parameters;
52 tp_constraints =
53 List.map ~f:(Tuple.T2.map_snd ~f:(hint env)) t.Aast.tp_constraints;
54 tp_reified = t.Aast.tp_reified;
55 tp_user_attributes =
56 List.map
57 ~f:(aast_user_attribute_to_decl_user_attribute env)
58 t.Aast.tp_user_attributes;
61 and hint_ p env = function
62 | Hany -> Typing_defs.make_tany ()
63 | Herr -> Terr
64 | Hmixed -> Tmixed
65 | Hnonnull -> Tnonnull
66 | Hthis -> Tthis
67 | Hdynamic -> Tdynamic
68 | Hnothing -> Tunion []
69 | Hdarray (h1, h2) -> Tdarray (hint env h1, hint env h2)
70 | Hvarray h -> Tvarray (hint env h)
71 | Hvarray_or_darray (h1, h2) ->
72 let t1 =
73 match h1 with
74 | Some h -> hint env h
75 | None -> mk (Typing_reason.Rvarray_or_darray_key p, Tprim Aast.Tarraykey)
77 Tvarray_or_darray (t1, hint env h2)
78 | Hvec_or_dict (h1, h2) ->
79 let t1 =
80 match h1 with
81 | Some h -> hint env h
82 | None -> mk (Typing_reason.Rvec_or_dict_key p, Tprim Aast.Tarraykey)
84 Tvec_or_dict (t1, hint env h2)
85 | Hprim p -> Tprim p
86 | Habstr (x, argl) ->
87 let argl = List.map argl (hint env) in
88 Tgeneric (x, argl)
89 | Hoption h ->
90 let h = hint env h in
91 Toption h
92 | Hlike h -> Tlike (hint env h)
93 | Hfun
95 hf_reactive_kind = reactivity;
96 hf_param_tys = hl;
97 hf_param_info = pil;
98 hf_variadic_ty = vh;
99 hf_ctxs = ctxs;
100 hf_return_ty = h;
101 hf_is_mutable_return = mut_ret;
102 hf_is_readonly_return = readonly_ret;
103 } ->
104 let make_param ((p, _) as x) param_info =
105 let (mutability, readonly, kind) =
106 match param_info with
107 | Some p ->
108 let mutability =
109 match p.hfparam_mutability with
110 | Some PMutable -> Some Param_borrowed_mutable
111 | Some POwnedMutable -> Some Param_owned_mutable
112 | Some PMaybeMutable -> Some Param_maybe_mutable
113 | _ -> None
115 let readonly =
116 match p.hfparam_readonlyness with
117 | Some Ast_defs.Readonly -> true
118 | _ -> false
120 let param_kind = get_param_mode p.hfparam_kind in
121 (mutability, readonly, param_kind)
122 | None -> (None, false, FPnormal)
125 fp_pos = Decl_env.make_decl_pos env p;
126 fp_name = None;
127 fp_type = possibly_enforced_hint env x;
128 fp_flags =
129 make_fp_flags
130 ~mode:kind
131 ~accept_disposable:false
132 ~mutability
133 ~has_default:
134 false
135 (* Currently do not support external and cancall on parameters of function parameters *)
136 ~ifc_external:false
137 ~ifc_can_call:false
138 ~is_atom:false
139 ~readonly
140 ~const_function:false;
141 fp_rx_annotation = None;
144 let readonly_ret =
145 match readonly_ret with
146 | Some Ast_defs.Readonly -> true
147 | None -> false
149 let paraml = List.map2_exn hl pil ~f:make_param in
150 let implicit_params =
151 let capability = aast_contexts_to_decl_capability env ctxs p in
152 { capability }
154 let ret = possibly_enforced_hint env h in
155 let arity =
156 match vh with
157 | Some t -> Fvariadic (make_param t None)
158 | None -> Fstandard
160 let reactivity =
161 match reactivity with
162 | FPure -> Pure None
163 | FNonreactive -> Nonreactive
165 Tfun
167 ft_arity = arity;
168 ft_tparams = [];
169 ft_where_constraints = [];
170 ft_params = paraml;
171 ft_implicit_params = implicit_params;
172 ft_ret = ret;
173 ft_flags =
174 make_ft_flags
175 Ast_defs.FSync
176 None
177 ~return_disposable:false
178 ~returns_void_to_rx:false
179 ~returns_mutable:mut_ret
180 ~returns_readonly:readonly_ret
181 ~readonly_this:
182 false
183 (* TODO: The constness of a function type hint is associated with
184 an attribute on the parameter, not on the hint itself.
185 Thus it's always false here, but we check for the attribute
186 in readonly_check.ml. When we decide actual syntax for this,
187 this will likely change.
189 ~const:false;
190 ft_reactive = reactivity;
191 (* TODO: handle function parameters with <<CanCall>> *)
192 ft_ifc_decl = default_ifc_fun_decl;
194 | Happly (id, argl) ->
195 let id = Decl_env.make_decl_posed env id in
196 let argl = List.map argl (hint env) in
197 Tapply (id, argl)
198 | Haccess ((_, Hvar n), [(_, id)]) -> Tgeneric ("T" ^ n ^ "@" ^ id, [])
199 | Haccess (root_ty, ids) ->
200 let root_ty = hint_ p env (snd root_ty) in
201 let rec translate res ids =
202 match ids with
203 | [] -> res
204 | id :: ids ->
205 translate
206 (Taccess
207 ( mk (Typing_reason.Rhint (Decl_env.make_decl_pos env p), res),
208 Decl_env.make_decl_posed env id ))
211 translate root_ty ids
212 | Htuple hl ->
213 let tyl = List.map hl (hint env) in
214 Ttuple tyl
215 | Hunion hl ->
216 let tyl = List.map hl (hint env) in
217 Tunion tyl
218 | Hintersection hl ->
219 let tyl = List.map hl (hint env) in
220 Tintersection tyl
221 | Hshape { nsi_allows_unknown_fields; nsi_field_map } ->
222 let shape_kind =
223 if nsi_allows_unknown_fields then
224 Open_shape
225 else
226 Closed_shape
228 let fdm =
229 List.fold_left
230 ~f:(fun acc i ->
231 TShapeMap.add
232 (TShapeField.of_ast (Decl_env.make_decl_pos env) i.sfi_name)
233 (shape_field_info_to_shape_field_type env i)
234 acc)
235 ~init:TShapeMap.empty
236 nsi_field_map
238 Tshape (shape_kind, fdm)
239 | Hsoft (p, h_) -> hint_ p env h_
240 | Hfun_context n -> Tgeneric ("Tctx" ^ n, [])
241 | Hvar n -> Tgeneric ("T" ^ n, [])
243 and possibly_enforced_hint env h =
244 (* Initially we assume that a type is not enforced at runtime.
245 * We refine this during localization
247 { et_enforced = false; et_type = hint env h }