2 * Copyright (c) 2017, 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 module Cls
= Decl_provider.Class
15 module MakeType
= Typing_make_type
16 module Env
= Typing_env
19 let r = Typing_reason.Renforceable
(Typing_reason.to_pos
(fst ty
)) in
22 let rec pessimize_type env ?
(trust_awaitable
=false) (ty
: decl ty
) =
23 if not
(TypecheckerOptions.pessimize_types
(Env.get_tcopt env
)) then ty
else
35 | r, Tarray
(ty1
, ty2
) ->
36 let ty1 = Option.map ~f
:(pessimize_wrap env
) ty1 in
37 let ty2 = Option.map ~f
:(pessimize_wrap env
) ty2 in
39 | r, Tdarray
(tk
, tv
) ->
40 r, Tdarray
(pessimize_wrap env tk
, pessimize_wrap env tv
)
42 r, Tvarray
(pessimize_wrap env tv
)
43 | r, Tvarray_or_darray tv
->
44 r, Tvarray_or_darray
(pessimize_wrap env tv
)
46 if Env.get_reified env x
= Aast.Reified
48 if Env.get_enforceable env x
54 r, Toption
(pessimize_type env ty
)
58 wrap_like (r, Tfun
(pessimize_fun_type env ft
))
59 | r, Tapply
((p
, x
), argl
) when Env.is_typedef x
|| Env.is_enum env x
->
60 (* Enums don't have type arguments so the next line is a no-op for them *)
61 let argl = List.map ~f
:(pessimize_wrap env
) argl in
62 wrap_like (r, Tapply
((p
, x
), argl))
63 | r, Tapply
((p
, cid
), targs
) when cid
= Naming_special_names.Classes.cAwaitable
->
66 then pessimize_type env ~trust_awaitable
:false
67 else pessimize_wrap env
in
68 r, Tapply
((p
, cid
), List.map ~
f targs
)
69 | r, Tapply
((p
, cid
), targs
) ->
70 let targs = match Env.get_class env cid
with
72 pessimize_targs env
targs (Cls.tparams cls
)
75 r, Tapply
((p
, cid
), targs)
77 let tyl = List.map ~
f:(pessimize_wrap env
) tyl in
78 wrap_like (r, Ttuple
tyl)
81 | r, Tshape
(shape_kind
, fields_map
) ->
82 let fields_map = Nast.ShapeMap.map
(fun shape_field_ty
->
83 let { sft_ty
; _
} = shape_field_ty
in
84 let sft_ty = pessimize_wrap env
sft_ty in
85 { shape_field_ty
with sft_ty }
87 wrap_like (r, Tshape
(shape_kind
, fields_map))
89 and pessimize_targs env
targs tparams
=
90 if not
(TypecheckerOptions.pessimize_types
(Env.get_tcopt env
)) then targs else
92 let new_targs = map2
targs tparams ~
f:(fun targ tparam
->
93 (* Trust reified type arguments *)
94 if tparam
.tp_reified
= Aast.Reified
96 else pessimize_wrap env targ
99 | Or_unequal_lengths.Ok
new_targs ->
101 | Or_unequal_lengths.Unequal_lengths
->
104 and pessimize_wrap env ty
=
105 let ty = pessimize_type env
ty in
108 | _
, Tany _
-> ty (* like Tany is useless *)
110 | _
, Tgeneric x
when Env.get_reified env x
<> Aast.Reified
-> ty
111 | _
, Tapply
((_
, x
), []) when x
= Naming_special_names.Typehints.wildcard
-> ty
114 (* For erased generics with constraints, add super dynamic and make the as constraints like types *)
115 and pessimize_tparam_constraints env
(t
: decl tparam
) =
116 if not
(TypecheckerOptions.pessimize_types
(Env.get_tcopt env
)) then t
else
117 match t
.tp_reified
with
120 let tp_constraints = List.map t
.tp_constraints ~
f:(fun (ck
, cstr_ty
) ->
122 | Ast_defs.Constraint_as
| Ast_defs.Constraint_eq
->
123 ck
, pessimize_wrap env cstr_ty
127 let dyn = MakeType.dynamic
(Reason.Renforceable
(fst t
.tp_name
)) in
129 (Ast_defs.Constraint_super
, dyn) :: tp_constraints in
130 { t
with tp_constraints }
132 and pessimize_fun_type env
(ft
: decl fun_type
) =
133 (* TODO: It may be necessary to pessimize ft_arity and ft_where_constraints *)
141 (* The runtime will enforce the inner type of an Awaitable in the return of an
143 let trust_awaitable = match ft_fun_kind
with
144 | Ast_defs.FAsync
| Ast_defs.FAsyncGenerator
-> true
146 let ft_ret_type = pessimize_type env ~
trust_awaitable ft_ret
.et_type
in
147 let ft_params = List.map
ft_params ~
f:(fun param
->
148 let ty = pessimize_type env param
.fp_type
.et_type
in
149 { param
with fp_type
= { param
.fp_type
with et_type
= ty } }
151 let ft_tparams = Tuple.T2.map_fst
ft_tparams
152 ~
f:(List.map ~
f:(pessimize_tparam_constraints env
)) in
155 ft_ret
= { ft_ret
with et_type
= ft_ret_type };
159 let rec is_enforceable (env
: env
) (ty: decl
ty) =
162 | Tapply
((_
, name
), _
) when Env.is_enum env name
-> false
163 | Tapply
((_
, name
), _
) when Env.is_typedef name
->
164 begin match Env.get_typedef env name
with
165 | Some
{ td_vis
= Aast.Transparent
; td_tparams
; td_type
; _
} ->
166 (* So that the check does not collide with reified generics *)
167 let env = Env.add_generic_parameters
env td_tparams
in
168 is_enforceable env td_type
170 | Tapply
((_
, name
), tyl) ->
171 begin match Env.get_class
env name
with
173 let tparams = Cls.tparams tc
in
177 let open List.Or_unequal_lengths
in
178 begin match List.fold2 ~init
:true targs tparams ~
f:(fun acc targ tparam
->
180 | _
, Tdynamic
(* We accept the inner type being dynamic regardless of reification *)
184 match tparam
.tp_reified
with
185 | Aast.Erased
-> false
186 | Aast.SoftReified
-> false
187 | Aast.Reified
-> is_enforceable env targ
&& acc
189 | Ok new_acc
-> new_acc
190 | Unequal_lengths
-> true
196 begin match Env.get_reified
env name
, Env.get_enforceable
env name
with
197 | Aast.Erased
, _
-> false
198 | Aast.SoftReified
, _
-> false
199 | Aast.Reified
, false -> false
200 | Aast.Reified
, true ->
205 | Tarray
(None
, None
) -> true
208 begin match prim
with
210 | Aast.Tnoreturn
-> false
224 (* With no parameters, we enforce varray_or_darray just like array *)
225 | Tvarray_or_darray
(_
, Tany _
) -> true
226 | Tvarray_or_darray _
-> false
228 is_enforceable env ty
230 let is_enforced env ty =
231 let enforceable = is_enforceable env ty in
236 Relative_path.prefix
|>
237 (=) Relative_path.Hhi
in
238 enforceable && not
is_hhi
240 let pessimize_type_simple env (ty: decl
ty) =
241 if not
env.pessimize
then ty else
243 | _
, Tprim
(Aast.Tvoid
| Aast.Tnoreturn
) -> ty
246 let compute_enforced_and_pessimize_ty_simple env (ty: decl
ty) =
247 let et_enforced = is_enforced env ty in
250 then pessimize_type_simple env ty
252 { et_type; et_enforced }
254 let compute_enforced_and_pessimize_fun_type_simple env (ft
: decl fun_type
) =
255 let { ft_params; ft_ret
= { et_type; _
}; _
} = ft
in
256 let ft_ret = compute_enforced_and_pessimize_ty_simple env et_type in
257 let ft_params = List.map ~
f:(fun fp
->
258 let { fp_type
= { et_type; _
}; _
} = fp
in
259 let fp_type = compute_enforced_and_pessimize_ty_simple env et_type in
262 { ft
with ft_params; ft_ret }