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
16 open Option.Monad_infix
22 module FunUtils
= Decl_fun_utils
23 module Reason
= Typing_reason
24 module Env
= Typing_env
25 module MakeType
= Typing_make_type
26 module Type
= Typing_ops
27 module Phase
= Typing_phase
28 module Subst
= Decl_subst
29 module EnvFromDef
= Typing_env_from_def
30 module Partial
= Partial_provider
31 module TUtils
= Typing_utils
32 module TCO
= TypecheckerOptions
33 module Cls
= Decl_provider.Class
34 module SN
= Naming_special_names
36 (* The two following functions enable us to retrieve the function (or class)
37 header from the shared mem. Note that they only return a non None value if
38 global inference is on *)
39 let get_decl_function_header env function_id
=
40 let is_global_inference_on = TCO.global_inference
(Env.get_tcopt env
) in
41 if is_global_inference_on then
42 match Decl_provider.get_fun
(Env.get_ctx env
) function_id
with
43 | Some
{ fe_type
; _
} ->
45 match get_node fe_type
with
46 | Tfun fun_type
-> Some fun_type
53 and get_decl_method_header tcopt cls method_id ~is_static
=
54 let is_global_inference_on = TCO.global_inference tcopt
in
55 if is_global_inference_on then
56 match Cls.get_any_method ~is_static cls method_id
with
57 | Some
{ ce_type
= (lazy ty
); _
} ->
59 match get_node ty
with
60 | Tfun fun_type
-> Some fun_type
67 let get_callable_variadicity ~pos env variadicity_decl_ty
= function
68 | FVvariadicArg vparam
->
70 Typing_param.make_param_local_ty env variadicity_decl_ty vparam
72 Typing_param.check_param_has_hint env vparam ty
;
73 let (env
, t_variadic
) = Typing.bind_param env
(ty
, vparam
) in
74 (env
, Aast.FVvariadicArg t_variadic
)
76 if Partial.should_check_error
(Env.get_mode env
) 4223 then
77 Errors.ellipsis_strict_mode ~require
:`Type_and_param_name pos
;
78 (env
, Aast.FVellipsis p
)
79 | FVnonVariadic
-> (env
, Aast.FVnonVariadic
)
81 let merge_hint_with_decl_hint env type_hint decl_ty
=
82 let contains_tvar decl_ty
=
85 | Some decl_ty
-> TUtils.contains_tvar_decl decl_ty
87 if contains_tvar decl_ty
then
90 Option.map type_hint ~f
:(Decl_hint.hint env
.decl_env
)
92 (* During the decl phase we can, for global inference, add "improved type hints".
93 That is we can say that some missing type hints are in fact global tyvars.
94 In that case to get the real type hint we must merge the type hint present
95 in the ast with the one we created during the decl phase. This function does
96 exactly this for the return type, the parameters and the variadic parameters.
98 let merge_decl_header_with_hints ~params ~ret ~variadic decl_header env
=
100 merge_hint_with_decl_hint
102 (hint_of_type_hint ret
)
104 ~f
:(fun { ft_ret
= { et_type
; _
}; _
} -> et_type
)
108 match decl_header
with
112 merge_hint_with_decl_hint
114 (hint_of_type_hint h
.param_type_hint
)
117 | Some
{ ft_params
; _
} ->
118 List.zip_exn params ft_params
119 |> List.map ~f
:(fun (h
, { fp_type
= { et_type
; _
}; _
}) ->
120 merge_hint_with_decl_hint
122 (hint_of_type_hint h
.param_type_hint
)
125 let variadicity_decl_ty =
126 match (decl_header
, variadic
) with
127 | ( Some
{ ft_arity
= Fvariadic
{ fp_type
= { et_type
; _
}; _
}; _
},
128 FVvariadicArg fp
) ->
129 merge_hint_with_decl_hint
131 (hint_of_type_hint fp
.param_type_hint
)
133 | (_
, FVvariadicArg fp
) ->
134 merge_hint_with_decl_hint env
(hint_of_type_hint fp
.param_type_hint
) None
137 (ret_decl_ty, params_decl_ty, variadicity_decl_ty)
139 let function_dynamically_callable
140 env f
params_decl_ty variadicity_decl_ty ret_locl_ty
=
141 let env = { env with in_support_dynamic_type_method_check
= true } in
142 let interface_check =
143 Typing_dynamic.sound_dynamic_interface_check
145 (variadicity_decl_ty :: params_decl_ty)
148 let function_body_check () =
149 (* Here the body of the function is typechecked again to ensure it is safe
150 * to call it from a dynamic context (eg. under dyn..dyn->dyn assumptions).
151 * The code below must be kept in sync with with the fun_def checks.
153 let make_dynamic pos
=
154 Typing_make_type.dynamic
(Reason.Rsupport_dynamic_type pos
)
156 let dynamic_return_ty = make_dynamic (get_pos ret_locl_ty
) in
157 let dynamic_return_info =
158 Typing_env_return_info.
160 return_type
= MakeType.unenforced
dynamic_return_ty;
161 return_disposable
= false;
162 return_explicit
= true;
163 return_dynamically_callable
= true;
166 let (env, param_tys
) =
167 List.zip_exn f
.f_params
params_decl_ty
168 |> List.map_env
env ~f
:(fun env (param
, hint
) ->
170 make_dynamic @@ Pos_or_decl.of_raw_pos param
.param_pos
174 | Some
ty when Typing_enforceability.is_enforceable
env ty ->
175 Typing_make_type.intersection
176 (Reason.Rsupport_dynamic_type
Pos_or_decl.none
)
180 Typing_param.make_param_local_ty
env (Some
ty) param
)
182 let params_need_immutable = Typing_coeffects.get_ctx_vars f
.f_ctxs
in
184 (* In this pass, bind_param_and_check receives a pair where the lhs is
185 * either Tdynamic or TInstersection of the original type and TDynamic,
186 * but the fun_param is still referencing the source hint. We amend
187 * the source hint to keep in in sync before calling bind_param
188 * so the right enforcement is computed.
190 let bind_param_and_check env lty_and_param
=
191 let (ty, param
) = lty_and_param
in
192 let name = param
.param_name
in
193 let (hi
, hopt
) = param
.param_type_hint
in
195 Option.map
hopt ~f
:(fun (p
, h
) ->
196 if Typing_utils.is_tintersection
env ty then
197 (p
, Hintersection
[(p
, h
); (p
, Hdynamic
)])
201 let param_type_hint = (hi
, hopt) in
202 let param = (ty, { param with param_type_hint }) in
204 List.exists ~f
:(String.equal
name) params_need_immutable
206 let (env, fun_param
) = Typing.bind_param ~
immutable env param in
211 (List.zip_exn param_tys f
.f_params
)
212 ~f
:bind_param_and_check
215 let pos = fst f
.f_name
in
216 let (env, t_variadic
) =
217 get_callable_variadicity
220 (Some
(make_dynamic @@ Pos_or_decl.of_raw_pos
pos))
224 set_tyvars_variance_in_callable
env dynamic_return_ty param_tys t_variadic
227 Naming_attributes.mem
228 SN.UserAttributes.uaDisableTypecheckerInternal
234 let (_
: env * Tast.stmt list
) =
235 Typing.fun_ ~
disable env dynamic_return_info pos f
.f_body f
.f_fun_kind
239 Errors.function_is_not_dynamically_callable
pos (snd f
.f_name
) error
)
241 if not
interface_check then function_body_check ()
244 (Tast.fun_def * Typing_inference_env.t_global_with_pos
) option =
246 Counters.count
Counters.Category.Typecheck
@@ fun () ->
247 Errors.run_with_span
f.f_span
@@ fun () ->
248 let env = EnvFromDef.fun_env ~origin
:Decl_counters.TopLevel ctx fd
in
249 with_timeout
env f.f_name
@@ fun env ->
250 (* reset the expression dependent display ids for each function body *)
251 Reason.expr_display_id_map
:= IMap.empty
;
252 let pos = fst
f.f_name
in
253 let decl_header = get_decl_function_header env (snd
f.f_name
) in
254 let env = Env.open_tyvars
env (fst
f.f_name
) in
255 let env = Env.set_env_callable_pos
env pos in
256 let env = Env.set_env_pessimize
env in
257 let (env, user_attributes
) =
258 Typing.attributes_check_def
env SN.AttributeKinds.fn
f.f_user_attributes
260 let (env, file_attrs
) = Typing.file_attributes
env fd
.fd_file_attributes
in
261 let (env, cap_ty
, unsafe_cap_ty
) =
262 Typing_coeffects.type_capability
env f.f_ctxs
f.f_unsafe_ctxs
(fst
f.f_name
)
266 @@ Typing_modules.of_maybe_string
267 @@ Naming_attributes_params.get_module_attribute
f.f_user_attributes
272 (Naming_attributes.mem
SN.UserAttributes.uaInternal
f.f_user_attributes
)
276 Naming_attributes.mem
277 SN.UserAttributes.uaSupportDynamicType
280 Env.set_support_dynamic_type
env true
284 Typing_type_wellformedness.fun_
env f;
286 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
290 f.f_where_constraints
292 let env = Env.set_fn_kind
env f.f_fun_kind
in
293 let (return_decl_ty
, params_decl_ty, variadicity_decl_ty) =
294 merge_decl_header_with_hints
297 ~variadic
:f.f_variadic
301 let (env, return_ty
) =
302 match return_decl_ty
with
304 (env, Typing_return.make_default_return ~is_method
:false env f.f_name
)
306 let localize env ty =
307 Phase.localize_no_subst
env ~ignore_errors
:false ty
309 Typing_return.make_return_type
localize env ty
312 match snd
f.f_ret
with
313 | Some
(ret_pos, _
) -> ret_pos
314 | None
-> fst
f.f_name
316 let (env, return_ty
) =
317 Typing_return.force_return_kind
env ret_pos return_ty
320 Typing_return.make_info
325 ~is_explicit
:(Option.is_some
(hint_of_type_hint
f.f_ret
))
330 Typing_coeffects.register_capabilities
env cap_ty unsafe_cap_ty
332 let sound_dynamic_check_saved_env = env in
333 let (env, param_tys
) =
334 List.zip_exn
f.f_params
params_decl_ty
335 |> List.map_env
env ~
f:(fun env (param, hint
) ->
336 Typing_param.make_param_local_ty
env hint
param)
338 let check_has_hint p t
= Typing_param.check_param_has_hint
env p t
in
339 List.iter2_exn ~
f:check_has_hint f.f_params param_tys
;
340 let params_need_immutable = Typing_coeffects.get_ctx_vars
f.f_ctxs
in
341 let can_read_globals =
342 Typing_subtype.is_sub_type
345 (MakeType.capability
(get_reason cap_ty
) SN.Capabilities.accessGlobals
)
347 let (env, typed_params
) =
348 let bind_param_and_check env param =
349 let name = (snd
param).param_name
in
351 List.exists ~
f:(String.equal
name) params_need_immutable
353 let (env, fun_param
) =
354 Typing.bind_param ~
immutable ~
can_read_globals env param
358 List.map_env
env (List.zip_exn param_tys
f.f_params
) ~
f:bind_param_and_check
360 let (env, t_variadic
) =
361 get_callable_variadicity ~
pos env variadicity_decl_ty f.f_variadic
364 set_tyvars_variance_in_callable
env return_ty param_tys t_variadic
366 let local_tpenv = Env.get_tpenv
env in
368 Naming_attributes.mem
369 SN.UserAttributes.uaDisableTypecheckerInternal
372 Typing_memoize.check_function
env f;
373 let (env, tb
) = Typing.fun_ ~
disable env return pos f.f_body
f.f_fun_kind
in
375 match hint_of_type_hint
f.f_ret
with
377 if Partial.should_check_error
(Env.get_mode
env) 4030 then
378 Errors.expecting_return_type_hint
pos
381 let (env, tparams
) = List.map_env
env f.f_tparams ~
f:Typing.type_param
in
382 let env = Typing_solver.close_tyvars_and_solve
env in
383 let env = Typing_solver.solve_all_unsolved_tyvars
env in
385 TypecheckerOptions.enable_sound_dynamic
386 (Provider_context.get_tcopt
(Env.get_ctx
env))
387 && Env.get_support_dynamic_type
env
389 function_dynamically_callable
390 sound_dynamic_check_saved_env
398 Aast.f_annotation
= Env.save
local_tpenv env;
399 Aast.f_readonly_this
= f.f_readonly_this
;
400 Aast.f_span
= f.f_span
;
401 Aast.f_readonly_ret
= f.f_readonly_ret
;
402 Aast.f_ret
= (return_ty
, hint_of_type_hint
f.f_ret
);
403 Aast.f_name
= f.f_name
;
404 Aast.f_tparams
= tparams
;
405 Aast.f_where_constraints
= f.f_where_constraints
;
406 Aast.f_variadic
= t_variadic
;
407 Aast.f_params
= typed_params
;
408 Aast.f_ctxs
= f.f_ctxs
;
409 Aast.f_unsafe_ctxs
= f.f_unsafe_ctxs
;
410 Aast.f_fun_kind
= f.f_fun_kind
;
411 Aast.f_user_attributes
= user_attributes
;
412 Aast.f_body
= { Aast.fb_ast
= tb
};
413 Aast.f_external
= f.f_external
;
414 Aast.f_doc_comment
= f.f_doc_comment
;
419 Aast.fd_mode
= fd
.fd_mode
;
421 Aast.fd_file_attributes
= file_attrs
;
422 Aast.fd_namespace
= fd
.fd_namespace
;
425 let (_env
, global_inference_env
) = Env.extract_global_inference_env
env in
426 (fundef, (pos, global_inference_env
))
428 let method_dynamically_callable
429 env cls m
params_decl_ty variadicity_decl_ty ret_locl_ty
=
430 let env = { env with in_support_dynamic_type_method_check
= true } in
431 (* Add `dynamic` lower and upper bound to any type parameters that are marked <<__RequireDynamic>> *)
432 let env_with_require_dynamic =
433 Typing_dynamic.add_require_dynamic_bounds
env cls
435 let interface_check =
436 Typing_dynamic.sound_dynamic_interface_check
437 env_with_require_dynamic
438 (variadicity_decl_ty :: params_decl_ty)
441 let method_body_check () =
442 (* Here the body of the method is typechecked again to ensure it is safe
443 * to call it from a dynamic context (eg. under dyn..dyn->dyn assumptions).
444 * The code below must be kept in sync with with the method_def checks.
446 let make_dynamic pos =
447 Typing_make_type.dynamic
(Reason.Rsupport_dynamic_type
pos)
449 let dynamic_return_ty = make_dynamic (get_pos ret_locl_ty
) in
450 let dynamic_return_info =
451 Typing_env_return_info.
453 return_type
= MakeType.unenforced
dynamic_return_ty;
454 return_disposable
= false;
455 return_explicit
= true;
456 return_dynamically_callable
= true;
459 let (env, param_tys
) =
460 List.zip_exn m
.m_params
params_decl_ty
461 |> List.map_env
env ~
f:(fun env (param, hint
) ->
463 make_dynamic @@ Pos_or_decl.of_raw_pos
param.param_pos
467 | Some
ty when Typing_enforceability.is_enforceable
env ty ->
468 Typing_make_type.intersection
469 (Reason.Rsupport_dynamic_type
Pos_or_decl.none
)
473 Typing_param.make_param_local_ty
env (Some
ty) param)
475 let params_need_immutable = Typing_coeffects.get_ctx_vars m
.m_ctxs
in
477 (* In this pass, bind_param_and_check receives a pair where the lhs is
478 * either Tdynamic or TInstersection of the original type and TDynamic,
479 * but the fun_param is still referencing the source hint. We amend
480 * the source hint to keep in in sync before calling bind_param
481 * so the right enforcement is computed.
483 let bind_param_and_check env lty_and_param
=
484 let (ty, param) = lty_and_param
in
485 let name = param.param_name
in
486 let (hi
, hopt) = param.param_type_hint in
488 Option.map
hopt ~
f:(fun (p
, h
) ->
489 if Typing_utils.is_tintersection
env ty then
490 (p
, Hintersection
[(p
, h
); (p
, Hdynamic
)])
494 let param_type_hint = (hi
, hopt) in
495 let param = (ty, { param with param_type_hint }) in
497 List.exists ~
f:(String.equal
name) params_need_immutable
499 let (env, fun_param
) = Typing.bind_param ~
immutable env param in
504 (List.zip_exn param_tys m
.m_params
)
505 ~
f:bind_param_and_check
508 let pos = fst m
.m_name
in
509 let (env, t_variadic
) =
510 get_callable_variadicity
513 (Some
(make_dynamic @@ Pos_or_decl.of_raw_pos
pos))
517 set_tyvars_variance_in_callable
env dynamic_return_ty param_tys t_variadic
521 if Cls.get_support_dynamic_type cls
then
523 Typing_make_type.intersection
524 (Reason.Rsupport_dynamic_type
Pos_or_decl.none
)
525 [Env.get_local
env this
; make_dynamic Pos_or_decl.none
]
527 Env.set_local
env this
this_ty Pos.none
533 Naming_attributes.mem
534 SN.UserAttributes.uaDisableTypecheckerInternal
540 let (_
: env * Tast.stmt list
) =
542 ~abstract
:m
.m_abstract
552 Errors.method_is_not_dynamically_callable
556 (Env.get_support_dynamic_type
env)
560 if not
interface_check then method_body_check ()
562 let method_def ~is_disposable
env cls m
=
563 Errors.run_with_span m
.m_span
@@ fun () ->
564 with_timeout
env m
.m_name
@@ fun env ->
565 FunUtils.check_params m
.m_params
;
566 let initial_env = env in
567 (* reset the expression dependent display ids for each method body *)
568 Reason.expr_display_id_map
:= IMap.empty
;
570 get_decl_method_header
574 ~is_static
:m
.m_static
576 let pos = fst m
.m_name
in
577 let env = Env.open_tyvars
env (fst m
.m_name
) in
578 let env = Env.reinitialize_locals
env in
579 let env = Env.set_env_callable_pos
env pos in
580 let (env, user_attributes
) =
581 Typing.attributes_check_def
env SN.AttributeKinds.mthd m
.m_user_attributes
585 Naming_attributes.mem
586 SN.UserAttributes.uaSupportDynamicType
589 Env.set_support_dynamic_type
env true
593 let (env, cap_ty
, unsafe_cap_ty
) =
594 Typing_coeffects.type_capability
env m
.m_ctxs m
.m_unsafe_ctxs
(fst m
.m_name
)
597 Typing_coeffects.register_capabilities
env cap_ty unsafe_cap_ty
599 let is_ctor = String.equal
(snd m
.m_name
) SN.Members.__construct
in
600 let env = Env.set_fun_is_constructor
env is_ctor in
602 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
606 m
.m_where_constraints
609 match Env.get_self_ty
env with
610 | Some
ty when not
(Env.is_static
env) ->
611 Env.set_local
env this
(MakeType.this
(get_reason
ty)) Pos.none
615 if is_disposable
then
616 Env.set_using_var
env this
620 let env = Env.clear_params
env in
621 let (ret_decl_ty, params_decl_ty, variadicity_decl_ty) =
622 merge_decl_header_with_hints
625 ~variadic
:m
.m_variadic
629 let env = Env.set_fn_kind
env m
.m_fun_kind
in
631 match ret_decl_ty with
633 (env, Typing_return.make_default_return ~is_method
:true env m
.m_name
)
635 (* If a 'this' type appears it needs to be compatible with the
639 empty_expand_env_with_on_error
640 (Env.invalid_type_hint_assert_primary_pos_in_current_decl
env)
642 Typing_return.make_return_type
(Phase.localize ~
ety_env) env ret
645 match snd m
.m_ret
with
646 | Some
(ret_pos, _
) -> ret_pos
647 | None
-> fst m
.m_name
649 let (env, locl_ty
) = Typing_return.force_return_kind
env ret_pos locl_ty
in
651 Typing_return.make_info
656 ~is_explicit
:(Option.is_some
(hint_of_type_hint m
.m_ret
))
660 let sound_dynamic_check_saved_env = env in
661 let (env, param_tys
) =
662 List.zip_exn m
.m_params
params_decl_ty
663 |> List.map_env
env ~
f:(fun env (param, hint
) ->
664 Typing_param.make_param_local_ty
env hint
param)
666 let param_fn p t
= Typing_param.check_param_has_hint
env p t
in
667 List.iter2_exn ~
f:param_fn m
.m_params param_tys
;
668 Typing_memoize.check_method
env m
;
669 let params_need_immutable = Typing_coeffects.get_ctx_vars m
.m_ctxs
in
670 let can_read_globals =
671 Typing_subtype.is_sub_type
674 (MakeType.capability
(get_reason cap_ty
) SN.Capabilities.accessGlobals
)
676 let (env, typed_params
) =
677 let bind_param_and_check env param =
678 let name = (snd
param).param_name
in
680 List.exists ~
f:(String.equal
name) params_need_immutable
682 let (env, fun_param
) =
683 Typing.bind_param ~
immutable ~
can_read_globals env param
687 List.map_env
env (List.zip_exn param_tys m
.m_params
) ~
f:bind_param_and_check
689 let (env, t_variadic
) =
690 get_callable_variadicity ~
pos env variadicity_decl_ty m
.m_variadic
692 let env = set_tyvars_variance_in_callable
env locl_ty param_tys t_variadic
in
694 let local_tpenv = Env.get_tpenv
env in
696 Naming_attributes.mem
697 SN.UserAttributes.uaDisableTypecheckerInternal
701 Typing.fun_ ~abstract
:m
.m_abstract ~
disable env return pos nb m
.m_fun_kind
704 match hint_of_type_hint m
.m_ret
with
705 | None
when String.equal
(snd m
.m_name
) SN.Members.__construct
->
706 Some
(pos, Hprim Tvoid
)
708 if Partial.should_check_error
(Env.get_mode
env) 4030 then
709 Errors.expecting_return_type_hint
pos;
711 | Some _
-> hint_of_type_hint m
.m_ret
713 let m = { m with m_ret
= (fst
m.m_ret
, type_hint'
) } in
714 let (env, tparams
) = List.map_env
env m.m_tparams ~
f:Typing.type_param
in
715 let env = Typing_solver.close_tyvars_and_solve
env in
716 let env = Typing_solver.solve_all_unsolved_tyvars
env in
718 (* if the enclosing class method is annotated with
719 * <<__SupportDynamicType>>, check that the method is dynamically callable *)
720 let check_support_dynamic_type =
721 (not
env.inside_constructor
)
722 && Env.get_support_dynamic_type
env
723 && not
(Aast.equal_visibility
m.m_visibility Private
)
726 TypecheckerOptions.enable_sound_dynamic
727 (Provider_context.get_tcopt
(Env.get_ctx
env))
728 && check_support_dynamic_type
730 method_dynamically_callable
731 sound_dynamic_check_saved_env
739 Aast.m_annotation
= Env.save
local_tpenv env;
740 Aast.m_span
= m.m_span
;
741 Aast.m_final
= m.m_final
;
742 Aast.m_static
= m.m_static
;
743 Aast.m_abstract
= m.m_abstract
;
744 Aast.m_visibility
= m.m_visibility
;
745 Aast.m_readonly_this
= m.m_readonly_this
;
746 Aast.m_name
= m.m_name
;
747 Aast.m_tparams
= tparams
;
748 Aast.m_where_constraints
= m.m_where_constraints
;
749 Aast.m_variadic
= t_variadic
;
750 Aast.m_params
= typed_params
;
751 Aast.m_ctxs
= m.m_ctxs
;
752 Aast.m_unsafe_ctxs
= m.m_unsafe_ctxs
;
753 Aast.m_fun_kind
= m.m_fun_kind
;
754 Aast.m_user_attributes
= user_attributes
;
755 Aast.m_readonly_ret
= m.m_readonly_ret
;
756 Aast.m_ret
= (locl_ty
, hint_of_type_hint
m.m_ret
);
757 Aast.m_body
= { Aast.fb_ast
= tb
};
758 Aast.m_external
= m.m_external
;
759 Aast.m_doc_comment
= m.m_doc_comment
;
762 let (env, global_inference_env
) = Env.extract_global_inference_env
env in
763 let _env = Env.log_env_change
"method_def" initial_env env in
764 (method_def, (pos, global_inference_env
))
766 (** Checks that extending this parent is legal - e.g. it is not final and not const. *)
767 let check_parent env class_def class_type
=
768 match Env.get_parent_class
env with
769 | Some parent_type
->
770 let position = fst class_def
.c_name
in
771 if Cls.const class_type
&& not
(Cls.const parent_type
) then
772 Errors.self_const_parent_not
position;
773 if Cls.final parent_type
then
774 Errors.extend_final
position (Cls.pos parent_type
) (Cls.name parent_type
)
777 let sealed_subtype ctx
(c
: Nast.class_
) ~is_enum ~hard_error
=
778 let parent_name = snd c
.c_name
in
779 let is_sealed (attr
: Nast.user_attribute
) =
780 String.equal
(snd attr
.ua_name
) SN.UserAttributes.uaSealed
782 match List.find c
.c_user_attributes ~
f:is_sealed with
784 | Some sealed_attr
->
785 let iter_item ((_
, pos, expr_
) : Nast.expr
) =
787 | Class_const
((_
, _
, cid
), _
) ->
788 let klass_name = Nast.class_id_to_str cid
in
789 let klass = Decl_provider.get_class ctx
klass_name in
793 let includes_ancestor =
795 match Cls.enum_type decl
with
799 match get_node x
with
800 | Tapply
((_
, name), _
) -> String.equal
name parent_name
803 List.exists enum_ty
.te_includes ~
f:check
805 Cls.has_ancestor decl
parent_name
807 if not
includes_ancestor then
808 let parent_pos = pos in
809 let child_pos = Cls.pos decl
in
810 let child_name = Cls.name decl
in
811 let (child_kind
, verb
) =
812 match Cls.kind decl
with
813 | Ast_defs.Cclass _
-> ("Class", "extend")
814 | Ast_defs.Cinterface
-> ("Interface", "implement")
815 | Ast_defs.Ctrait
-> ("Trait", "use")
816 | Ast_defs.Cenum
-> ("Enum", "use")
817 | Ast_defs.Cenum_class _
-> ("Enum Class", "extend")
820 Errors.sealed_not_subtype
828 Lint.sealed_not_subtype
834 (* unit below is fine because error cases are handled as Parsing[1002] *)
837 List.iter sealed_attr
.ua_params ~
f:iter_item
839 let check_parent_sealed (child_pos, child_type
) parent_type
=
840 match Cls.sealed_whitelist parent_type
with
843 let parent_pos = Cls.pos parent_type
in
844 let parent_name = Cls.name parent_type
in
845 let child_name = Cls.name child_type
in
846 let check kind action
=
847 if not
(SSet.mem
child_name whitelist
) then
848 Errors.extend_sealed
child_pos parent_pos parent_name kind action
851 match (Cls.kind parent_type
, Cls.kind child_type
) with
852 | (Ast_defs.Cinterface
, Ast_defs.Cinterface
) -> check "interface" "extend"
853 | (Ast_defs.Cinterface
, _
) -> check "interface" "implement"
854 | (Ast_defs.Ctrait
, _
) -> check "trait" "use"
855 | (Ast_defs.Cclass _
, _
) -> check "class" "extend"
856 | (Ast_defs.Cenum_class _
, _
) -> check "enum class" "extend"
857 | (Ast_defs.Cenum
, _
) -> check "enum" "use"
860 let check_parents_sealed env child_def child_type
=
862 match child_def
.c_enum
with
863 | Some enum
-> enum
.e_includes
864 | None
-> child_def
.c_extends
866 let parents = parents @ child_def
.c_implements
@ child_def
.c_uses
in
867 List.iter
parents ~
f:(function
868 | (_
, Happly
((_
, name), _
)) ->
870 match Env.get_class_dep
env name with
871 | Some parent_type
->
872 check_parent_sealed (fst child_def
.c_name
, child_type
) parent_type
877 (* Reject multiple instantiations of the same generic interface
878 * in extends and implements clauses.
879 * e.g. disallow class C implements I<string>, I<int>
881 * O(n^2) but we don't expect number of instantiated interfaces to be large
883 let rec check_implements_or_extends_unique impl
=
886 | (hint
, ty) :: rest
->
887 (match get_node
ty with
888 | Tapply
((_
, name), _
:: _
) ->
889 let (pos_list
, rest
) =
890 List.partition_map rest ~
f:(fun (h
, ty) ->
891 match get_node
ty with
892 | Tapply
((pos'
, name'
), _
) when String.equal
name name'
->
894 | _
-> Second
(h
, ty))
896 if not
(List.is_empty pos_list
) then
897 Errors.duplicate_interface
(fst hint
) name pos_list
;
898 check_implements_or_extends_unique rest
899 | _
-> check_implements_or_extends_unique rest
)
901 let check_constructor_dep env deps
=
902 List.iter deps ~
f:(fun ((p
, _dep_hint
), dep
) ->
903 match get_node dep
with
904 | Tapply
((_
, class_name
), _
) ->
905 Env.make_depend_on_constructor
env class_name
907 Errors.expected_class ~suffix
:" or interface but got a generic" p
908 | _
-> Errors.expected_class ~suffix
:" or interface" p
)
910 (** For const classes, check that members from traits are all constant. *)
911 let check_non_const_trait_members pos env use_list
=
912 let (_
, trait
, _
) = Decl_utils.unwrap_class_hint use_list
in
913 match Env.get_class
env trait
with
914 | Some c
when Ast_defs.is_c_trait
(Cls.kind c
) ->
915 List.iter
(Cls.props c
) ~
f:(fun (x
, ce
) ->
916 if not
(get_ce_const ce
) then Errors.trait_prop_const_class
pos x
)
919 let check_consistent_enum_inclusion
920 included_cls
((dest_cls_pos
, dest_cls
) : Pos.t
* Cls.t
) =
921 let included_kind = Cls.kind included_cls
in
922 let dest_kind = Cls.kind dest_cls
in
923 match (Cls.enum_type included_cls
, Cls.enum_type dest_cls
) with
924 | (Some included_e
, Some dest_e
) ->
925 (* ensure that the base types are identical *)
926 if not
(Typing_defs.equal_decl_ty included_e
.te_base dest_e
.te_base
) then
927 Errors.incompatible_enum_inclusion_base
930 (Cls.name included_cls
);
931 (* ensure that the visibility constraint are compatible *)
932 (match (included_e
.te_constraint
, dest_e
.te_constraint
) with
934 Errors.incompatible_enum_inclusion_constraint
937 (Cls.name included_cls
)
939 (* ensure normal enums can't include enum classes *)
941 Ast_defs.is_c_enum_class
included_kind
942 && not
(Ast_defs.is_c_enum_class
dest_kind)
944 Errors.wrong_extend_kind
945 ~
parent_pos:(Cls.pos included_cls
)
946 ~parent_kind
:included_kind
947 ~
parent_name:(Cls.name included_cls
)
948 ~
child_pos:dest_cls_pos
949 ~child_kind
:dest_kind
950 ~
child_name:(Cls.name dest_cls
)
952 Errors.enum_inclusion_not_enum
955 (Cls.name included_cls
)
958 let is_enum_or_enum_class k
= Ast_defs.is_c_enum k
|| Ast_defs.is_c_enum_class k
960 let check_enum_includes env cls
=
961 let is_abstract = function
962 | CCAbstract has_default
-> not has_default
963 | CCConcrete
-> false
965 (* checks that there are no duplicated enum-constants when folded-decls are enabled *)
966 if is_enum_or_enum_class cls
.c_kind
then (
967 let (dest_class_pos
, dest_class_name
) = cls
.c_name
in
968 let enum_constant_map = ref SMap.empty
in
969 (* prepopulate the map with the constants declared in cls *)
970 List.iter cls
.c_consts ~
f:(fun cc
->
974 (fst cc
.cc_id
, dest_class_name
)
976 (* for all included enums *)
978 Aast.enum_includes_map cls
.c_enum ~
f:(fun ce
->
979 List.filter_map ce
.e_includes ~
f:(fun ie
->
982 (match Env.get_class
env (snd sid
) with
984 | Some ie_cls
-> Some
(fst ie
, ie_cls
))
987 List.iter
included_enums ~
f:(fun (ie_pos
, ie_cls
) ->
988 let src_class_name = Cls.name ie_cls
in
989 (* 1. Check for consistency *)
990 (match Env.get_class
env dest_class_name
with
992 | Some cls
-> check_consistent_enum_inclusion ie_cls
(ie_pos
, cls
));
993 (* 2. Check for duplicates *)
994 List.iter
(Cls.consts ie_cls
) ~
f:(fun (const_name
, class_const
) ->
995 (if String.equal const_name
"class" then
997 (* TODO: Check with @fzn *)
998 else if is_abstract class_const
.cc_abstract
then
1000 else if SMap.mem const_name
!enum_constant_map then
1001 (* distinguish between multiple inherit and redeclare *)
1002 let (origin_const_pos
, origin_class_name
) =
1003 SMap.find const_name
!enum_constant_map
1005 if String.equal origin_class_name dest_class_name
then
1007 Errors.redeclaring_classish_const
1013 else if String.( <> ) origin_class_name class_const
.cc_origin
then
1014 (* check for diamond inclusion, if not raise an error about multiple inherit *)
1015 Errors.reinheriting_classish_const
1022 enum_constant_map :=
1025 (dest_class_pos
, class_const
.cc_origin
)
1026 !enum_constant_map))
1029 let shallow_decl_enabled (ctx
: Provider_context.t
) : bool =
1030 TypecheckerOptions.shallow_class_decl
(Provider_context.get_tcopt ctx
)
1032 let skip_hierarchy_checks (ctx
: Provider_context.t
) : bool =
1033 TypecheckerOptions.skip_hierarchy_checks (Provider_context.get_tcopt ctx
)
1035 let class_type_param env ct
=
1036 let (env, tparam_list
) = List.map_env
env ct ~
f:Typing.type_param
in
1039 (** Checks that a dynamic element is also dynamic in the parents. *)
1040 let check_dynamic_class_element get_static_elt element_name dyn_pos ~elt_type
=
1041 (* The non-static properties that we get passed do not start with '$', but the
1042 static properties we want to look up do, so add it. *)
1045 | `Method
-> element_name
1046 | `Property
-> "$" ^ element_name
1048 match get_static_elt
id with
1050 | Some static_element
->
1051 let (lazy ty) = static_element
.ce_type
in
1052 Errors.static_redeclared_as_dynamic
1058 (** Checks that a static element is also static in the parents. *)
1059 let check_static_class_element get_dyn_elt element_name static_pos ~elt_type
=
1060 (* The static properties that we get passed in start with '$', but the
1061 non-static properties we're matching against don't, so we need to detect
1062 that and remove it if present. *)
1063 let element_name = String_utils.lstrip
element_name "$" in
1064 match get_dyn_elt
element_name with
1066 | Some dyn_element
->
1067 let (lazy ty) = dyn_element
.ce_type
in
1068 Errors.dynamic_redeclared_as_static
1074 (** Error if there are abstract methods that this class is supposed to provide
1075 implementation for. *)
1076 let check_extend_abstract_meth ~is_final p seq
=
1077 List.iter seq ~
f:(fun (x
, ce
) ->
1078 match ce
.ce_type
with
1079 | (lazy ty) when get_ce_abstract ce
&& is_fun
ty ->
1080 Errors.implement_abstract ~is_final p
(get_pos
ty) "method" x
1083 let check_extend_abstract_prop ~is_final p seq
=
1084 List.iter seq ~
f:(fun (x
, ce
) ->
1085 if get_ce_abstract ce
then
1086 let ce_pos = Lazy.force ce
.ce_type
|> get_pos
in
1087 Errors.implement_abstract ~is_final p
ce_pos "property" x
)
1089 (* Type constants must be bound to a concrete type for non-abstract classes.
1091 let check_extend_abstract_typeconst ~is_final p seq
=
1092 List.iter seq ~
f:(fun (x
, tc
) ->
1093 match tc
.ttc_kind
with
1095 Errors.implement_abstract
1103 let check_extend_abstract_const ~is_final p seq
=
1104 List.iter seq ~
f:(fun (x
, cc
) ->
1105 match cc
.cc_abstract
with
1106 | CCAbstract _
when not cc
.cc_synthesized
->
1107 let cc_pos = get_pos cc
.cc_type
in
1108 Errors.implement_abstract ~is_final p
cc_pos "constant" x
1111 (** Error if there are abstract members that this class is supposed to provide
1112 implementation for. *)
1113 let check_extend_abstract (pc
, tc
) =
1115 let open Ast_defs
in
1116 match Cls.kind tc
with
1125 let is_final = Cls.final tc
in
1126 if is_concrete || is_final then (
1127 let constructor_as_list cstr
=
1129 >>| (fun cstr
-> (SN.Members.__construct
, cstr
))
1132 check_extend_abstract_meth ~
is_final pc
(Cls.methods tc
);
1133 check_extend_abstract_meth
1136 (Cls.construct tc
|> constructor_as_list);
1137 check_extend_abstract_meth ~
is_final pc
(Cls.smethods tc
);
1138 check_extend_abstract_prop ~
is_final pc
(Cls.sprops tc
);
1139 check_extend_abstract_const ~
is_final pc
(Cls.consts tc
);
1140 check_extend_abstract_typeconst ~
is_final pc
(Cls.typeconsts tc
)
1143 exception Found
of Pos_or_decl.t
1145 let contains_generic : Typing_defs.decl_ty
-> Pos_or_decl.t
option =
1149 inherit [_
] Type_visitor.decl_type_visitor
as super
1151 method! on_type
env ty =
1152 match get_node
ty with
1153 | Tgeneric _
-> raise
(Found
(get_pos
ty))
1154 | _
-> super#on_type
env ty
1158 visitor#on_type
() ty;
1163 (** Check whether the type of a static property (class variable) contains
1164 any generic type parameters. Outside of traits, this is illegal as static
1165 * properties are shared across all generic instantiations. *)
1166 let check_no_generic_static_property env tc
=
1167 if Ast_defs.is_c_trait
(Cls.kind tc
) then
1171 |> List.iter ~
f:(fun (_prop_name
, prop
) ->
1172 let (lazy ty) = prop
.ce_type
in
1173 let var_type_pos = get_pos
ty in
1174 let class_pos = Cls.pos tc
in
1175 match contains_generic ty with
1177 | Some generic_pos
->
1179 (* If the static property is inherited from another trait, the position may be
1180 * in a different file. *)
1181 (Env.fill_in_pos_filename_if_in_current_decl
env generic_pos
)
1182 ~
f:(fun generic_pos
->
1183 Errors.static_property_type_generic_param
1188 let get_decl_prop_ty env cls ~is_static prop_id
=
1189 let is_global_inference_on = TCO.global_inference
(Env.get_tcopt
env) in
1190 if is_global_inference_on then
1193 (* this is very ad-hoc, but this is how we do it in the decl-heap *)
1194 Cls.get_sprop cls
("$" ^ prop_id
)
1196 Cls.get_prop cls prop_id
1199 | None
-> failwith
"error: could not find property in decl heap"
1200 | Some
{ ce_type
; _
} -> Some
(Lazy.force ce_type
)
1208 c_tconst_name
= (pos, _
) as id;
1210 c_tconst_user_attributes
;
1212 c_tconst_doc_comment
;
1215 if is_enum_or_enum_class cls
.c_kind
then
1216 Errors.cannot_declare_constant `enum
pos cls
.c_name
;
1218 let name = snd cls
.c_name ^
"::" ^ snd
id in
1219 (* Check constraints and report cycles through the definition *)
1221 match c_tconst_kind
with
1223 { c_atc_as_constraint
; c_atc_super_constraint
; c_atc_default
= Some
ty }
1226 Phase.localize_hint_no_subst
1227 ~ignore_errors
:false
1228 ~report_cycle
:(pos, name)
1233 match c_atc_as_constraint
with
1236 Phase.localize_hint_no_subst ~ignore_errors
:false env as_
1240 Reason.URtypeconst_cstr
1248 match c_atc_super_constraint
with
1251 Phase.localize_hint_no_subst ~ignore_errors
:false env super
1255 Reason.URtypeconst_cstr
1263 | TCConcrete
{ c_tc_type
= ty } ->
1265 Phase.localize_hint_no_subst
1266 ~ignore_errors
:false
1267 ~report_cycle
:(pos, name)
1275 (* TODO(T88552052): should this check be happening for defaults
1276 * Does this belong here at all? *)
1278 match c_tconst_kind
with
1279 | TCConcrete
{ c_tc_type
= (_
, Hshape
{ nsi_field_map
; _
}) }
1280 | TCAbstract
{ c_atc_default
= Some
(_
, Hshape
{ nsi_field_map
; _
}); _
} ->
1281 let get_name sfi
= sfi
.sfi_name
in
1282 Typing_shapes.check_shape_keys_validity
1284 (List.map ~
f:get_name nsi_field_map
)
1288 let (env, user_attributes
) =
1289 Typing.attributes_check_def
1291 SN.AttributeKinds.typeconst
1292 c_tconst_user_attributes
1296 Aast.c_tconst_name
= id;
1298 Aast.c_tconst_user_attributes
= user_attributes
;
1300 Aast.c_tconst_doc_comment
;
1301 Aast.c_tconst_is_ctx
;
1304 (* This should agree with the set of expressions whose type can be inferred in
1305 * Decl_utils.infer_const
1307 let is_literal_expr (_
, _
, e
) =
1316 | Unop
((Ast_defs.Uminus
| Ast_defs.Uplus
), (_
, _
, (Int _
| Float _
))) -> true
1319 let class_const_def ~in_enum_class c
env cc
=
1320 let { cc_type
= h
; cc_id
= id; cc_kind
= k
; _
} = cc
in
1321 let (env, hint_ty
, opt_expected
) =
1326 | CCAbstract None
-> ()
1327 | CCAbstract
(Some e
(* default *))
1330 (not
(is_literal_expr e
))
1331 && Partial.should_check_error c
.c_mode
2035
1332 && not
(is_enum_or_enum_class c
.c_kind
)
1334 Errors.missing_typehint
(fst
id)
1336 let (env, ty) = Env.fresh_type
env (fst
id) in
1337 (env, MakeType.unenforced
ty, None
)
1339 let ty = Decl_hint.hint
env.decl_env h
in
1340 let ty = Typing_enforceability.compute_enforced_ty
env ty in
1342 Phase.localize_possibly_enforced_no_subst
env ~ignore_errors
:false ty
1344 (* Removing the HH\MemberOf wrapper in case of enum classes so the
1345 * following call to expr_* has the right expected type
1348 if in_enum_class
then
1349 match get_node
ty.et_type
with
1350 | Tnewtype
(memberof
, [_
; et_type
], _
)
1351 when String.equal memberof
SN.Classes.cMemberOf
->
1359 Some
(ExpectedTy.make_and_allow_coercion
(fst
id) Reason.URhint
opt_ty)
1363 (* Lifted out to closure to illustrate which variables are captured *)
1364 Typing_coercion.coerce_type
1370 Errors.class_constant_value_does_not_match_hint
1372 let type_and_check env e
=
1373 let (env, (te
, ty'
)) =
1375 expr_with_pure_coeffects ?expected
:opt_expected
env e
|> triple_to_pair
)
1377 let env = check env ty'
in
1380 let (env, kind
, ty) =
1382 | CCConcrete
((_
, e_pos
, _
) as e
) when in_enum_class
->
1383 let (env, cap
, unsafe_cap
) =
1384 (* Enum class constant initializers are restricted to be `write_props` *)
1385 let make_hint pos s
= (pos, Aast.Happly
((pos, s
), [])) in
1386 let enum_class_ctx =
1387 Some
(e_pos
, [make_hint e_pos
SN.Capabilities.write_props
])
1389 Typing_coeffects.type_capability
env enum_class_ctx enum_class_ctx e_pos
1391 let (env, (te
, ty'
)) =
1393 with_special_coeffects
env cap unsafe_cap
@@ fun env ->
1394 expr
env ?expected
:opt_expected e
|> triple_to_pair
)
1397 match deref hint_ty
.et_type
with
1398 | (r
, Tnewtype
(memberof
, [enum_name
; _
], _
))
1399 when String.equal memberof
SN.Classes.cMemberOf
->
1400 let lift r
ty = mk
(r
, Tnewtype
(memberof
, [enum_name
; ty], ty)) in
1401 let (te_ty
, p
, te
) = te
in
1402 let te = (lift (get_reason te_ty
) te_ty
, p
, te) in
1403 let ty'
= lift r
ty'
in
1407 let env = check env ty'
in
1408 (env, Aast.CCConcrete
te, ty'
)
1410 let (env, te, ty'
) = type_and_check env e
in
1411 (env, Aast.CCConcrete
te, ty'
)
1412 | CCAbstract
(Some default
) ->
1413 let (env, tdefault
, ty'
) = type_and_check env default
in
1414 (env, CCAbstract
(Some tdefault
), ty'
)
1415 | CCAbstract None
-> (env, CCAbstract None
, hint_ty
.et_type
)
1419 Aast.cc_type
= cc
.cc_type
;
1420 Aast.cc_id
= cc
.cc_id
;
1421 Aast.cc_kind
= kind
;
1422 Aast.cc_doc_comment
= cc
.cc_doc_comment
;
1426 let class_constr_def ~is_disposable
env cls constructor
=
1427 let env = { env with inside_constructor
= true } in
1428 Option.bind constructor ~
f:(method_def ~is_disposable
env cls
)
1430 (** Type-check a property declaration, with optional initializer *)
1431 let class_var_def ~is_static cls
env cv
=
1432 (* First pick up and localize the hint if it exists *)
1434 merge_hint_with_decl_hint
1436 (hint_of_type_hint cv
.cv_type
)
1437 (get_decl_prop_ty env cls ~is_static
(snd cv
.cv_id
))
1439 let (env, expected
) =
1441 | None
-> (env, None
)
1443 let decl_cty = Typing_enforceability.compute_enforced_ty
env decl_cty in
1445 Phase.localize_possibly_enforced_no_subst
1447 ~ignore_errors
:false
1451 Some
(ExpectedTy.make_and_allow_coercion cv
.cv_span
Reason.URhint cty
)
1455 (* Next check the expression, passing in expected type if present *)
1456 let (env, typed_cv_expr
) =
1457 match cv
.cv_expr
with
1458 | None
-> (env, None
)
1460 let (env, te, ty) = Typing.expr_with_pure_coeffects
env ?
expected e
in
1461 (* Check that the inferred type is a subtype of the expected type.
1462 * Eventually this will be the responsibility of `expr`
1467 | Some
ExpectedTy.{ pos = p
; reason
= ur
; ty = cty
} ->
1468 Typing_coercion.coerce_type
1474 Errors.class_property_initializer_type_does_not_match_hint
1479 let (env, user_attributes
) =
1480 Typing.attributes_check_def
1483 SN.AttributeKinds.staticProperty
1485 SN.AttributeKinds.instProperty
)
1486 cv
.cv_user_attributes
1489 Option.is_none
(hint_of_type_hint cv
.cv_type
)
1490 && Partial.should_check_error
(Env.get_mode
env) 2001
1492 Errors.prop_without_typehint
1493 (string_of_visibility cv
.cv_visibility
)
1495 let (env, global_inference_env
) = Env.extract_global_inference_env
env in
1496 let ((cv_type_ty
, _
) as cv_type
) =
1499 (expected.ExpectedTy.ty.et_type
, hint_of_type_hint cv
.cv_type
)
1500 | None
-> Tast.dummy_type_hint
(hint_of_type_hint cv
.cv_type
)
1502 (* if the class implements dynamic, then check that the type of the property
1503 * is enforceable (for writing) and coerces to dynamic (for reading) *)
1505 TypecheckerOptions.enable_sound_dynamic
1506 (Provider_context.get_tcopt
(Env.get_ctx
env))
1507 && Cls.get_support_dynamic_type cls
1508 && not
(Aast.equal_visibility cv
.cv_visibility Private
)
1510 let env_with_require_dynamic =
1511 Typing_dynamic.add_require_dynamic_bounds
env cls
1513 Option.iter
decl_cty ~
f:(fun ty ->
1514 Typing_dynamic.check_property_sound_for_dynamic_write
1515 ~on_error
:Errors.property_is_not_enforceable
1516 env_with_require_dynamic
1521 Typing_dynamic.check_property_sound_for_dynamic_read
1522 ~on_error
:Errors.property_is_not_dynamic
1523 env_with_require_dynamic
1530 Aast.cv_final
= cv
.cv_final
;
1531 Aast.cv_xhp_attr
= cv
.cv_xhp_attr
;
1532 Aast.cv_abstract
= cv
.cv_abstract
;
1533 Aast.cv_visibility
= cv
.cv_visibility
;
1535 Aast.cv_id
= cv
.cv_id
;
1536 Aast.cv_expr
= typed_cv_expr
;
1537 Aast.cv_user_attributes
= user_attributes
;
1538 Aast.cv_is_promoted_variadic
= cv
.cv_is_promoted_variadic
;
1539 Aast.cv_doc_comment
= cv
.cv_doc_comment
;
1540 (* Can make None to save space *)
1541 Aast.cv_is_static
= is_static
;
1542 Aast.cv_span
= cv
.cv_span
;
1543 Aast.cv_readonly
= cv
.cv_readonly
;
1545 (cv
.cv_span
, global_inference_env
) ) )
1547 (** Check the where constraints of the parents of a class *)
1548 let check_class_parents_where_constraints env pc impl
=
1549 let check_where_constraints env ((p
, _hint
), decl_ty
) =
1550 let (env, locl_ty
) =
1551 Phase.localize_no_subst
env ~ignore_errors
:false decl_ty
1553 match get_node
(TUtils.get_base_type
env locl_ty
) with
1554 | Tclass
(cls
, _
, tyl
) ->
1555 (match Env.get_class
env (snd cls
) with
1556 | Some cls
when not
(List.is_empty
(Cls.where_constraints cls
)) ->
1557 let tc_tparams = Cls.tparams cls
in
1560 (empty_expand_env_with_on_error
1561 (Env.unify_error_assert_primary_pos_in_current_decl
env))
1563 substs
= Subst.make_locl
tc_tparams tyl
;
1566 Phase.check_where_constraints
1569 ~definition_pos
:(Pos_or_decl.of_raw_pos p
)
1572 (Cls.where_constraints cls
)
1576 List.fold impl ~init
:env ~
f:check_where_constraints
1578 let check_generic_class_with_SupportDynamicType env c
parents =
1579 let (pc
, c_name
) = c
.c_name
in
1580 let check_support_dynamic_type =
1581 Naming_attributes.mem
1582 SN.UserAttributes.uaSupportDynamicType
1586 TypecheckerOptions.enable_sound_dynamic
1587 (Provider_context.get_tcopt
(Env.get_ctx
env))
1588 && check_support_dynamic_type
1590 (* Any class that extends a class or implements an interface
1591 * that declares <<__SupportDynamicType>> must itself declare
1592 * <<__SupportDynamicType>>. This is checked elsewhere. But if any generic
1593 * parameters are marked <<__RequireDynamic>> then we must check that the
1594 * conditional support for dynamic is sound.
1597 * and C<T1,..,Tn> extends t
1598 * then C<T1,...,Tn> <: dynamic
1601 MakeType.dynamic
(Reason.Rdynamic_coercion
(Reason.Rwitness pc
))
1604 List.fold
parents ~init
:env ~
f:(fun env (_
, ty) ->
1605 let (env, lty
) = Phase.localize_no_subst
env ~ignore_errors
:true ty in
1606 match get_node lty
with
1607 | Tclass
((_
, name), _
, _
) ->
1609 match Env.get_class
env name with
1610 | Some c
when Cls.get_support_dynamic_type c
->
1611 let env_with_assumptions =
1612 Typing_subtype.add_constraint
1614 Ast_defs.Constraint_as
1617 (Errors.unify_error_at pc
)
1620 match Env.get_self_ty
env with
1623 ~coerce
:(Some
Typing_logic.CoerceToDynamic
)
1624 env_with_assumptions
1627 (fun ?code
:_ ?quickfixes
:_ reasons
->
1629 Typing_print.full_strip_ns_decl
env ty
1630 ^
" is subtype of dynamic implies "
1631 ^
Typing_print.full_strip_ns
env self_ty
1632 ^
" is subtype of dynamic"
1634 Errors.bad_conditional_support_dynamic
1650 let check_SupportDynamicType env c
=
1652 TypecheckerOptions.enable_sound_dynamic
1653 (Provider_context.get_tcopt
(Env.get_ctx
env))
1655 let support_dynamic_type =
1656 Naming_attributes.mem
1657 SN.UserAttributes.uaSupportDynamicType
1662 (c
.c_extends
@ c
.c_uses
@ c
.c_implements
)
1664 | (_
, Happly
((_
, name), _
)) -> Some
name
1667 let error_parent_support_dynamic_type parent
f =
1668 Errors.parent_support_dynamic_type
1670 (snd c
.c_name
, c
.c_kind
)
1671 (Cls.name parent
, Cls.kind parent
)
1675 | Ast_defs.(Cenum
| Cenum_class _
) ->
1676 (* Avoid parent SDT check on things that cannot be SDT themselves *)
1679 | Ast_defs.Cinterface
1680 | Ast_defs.Ctrait
->
1681 List.iter
parent_names ~
f:(fun name ->
1682 match Env.get_class_dep
env name with
1683 | Some parent_type
->
1685 match Cls.kind parent_type
with
1687 | Ast_defs.Cinterface
->
1688 (* ensure that we implement dynamic if we are a subclass/subinterface of a class/interface
1689 * that implements dynamic. Upward well-formedness checks are performed in Typing_extends *)
1691 Cls.get_support_dynamic_type parent_type
1692 && not
support_dynamic_type
1694 error_parent_support_dynamic_type
1696 support_dynamic_type
1697 | Ast_defs.(Cenum
| Cenum_class _
| Ctrait
) -> ()
1701 let class_def_ env c tc
=
1702 let (env, user_attributes
) =
1704 if Ast_defs.is_c_enum c
.c_kind
then
1705 SN.AttributeKinds.enum
1706 else if Ast_defs.is_c_enum_class c
.c_kind
then
1707 SN.AttributeKinds.enumcls
1709 SN.AttributeKinds.cls
1711 Typing.attributes_check_def
env kind c
.c_user_attributes
1713 let (env, file_attrs
) = Typing.file_attributes
env c
.c_file_attributes
in
1714 let ctx = Env.get_ctx
env in
1716 (not
(skip_hierarchy_checks ctx))
1717 && (not
Ast_defs.(is_c_trait c
.c_kind
))
1718 && not
(shallow_decl_enabled ctx)
1720 (* These checks are only for eager mode. The same checks are performed
1721 * for shallow mode in Typing_inheritance *)
1722 let method_pos ~is_static class_id meth_id
=
1725 Decl_store.((get
()).get_static_method
)
1727 Decl_store.((get
()).get_method
)
1729 match get_meth (class_id
, meth_id
) with
1730 | Some
{ fe_pos
; _
} -> fe_pos
1731 | None
-> Pos_or_decl.none
1733 let check_override ~is_static
(id, ce
) =
1734 if get_ce_override ce
then
1735 let pos = method_pos ~is_static ce
.ce_origin
id in
1736 (* Method is actually defined in this class *)
1737 if String.equal ce
.ce_origin
(snd c
.c_name
) then
1738 Errors.should_be_override
1742 ~current_decl_and_file
:(Env.get_current_decl_and_file
env)
1744 match Env.get_class
env ce
.ce_origin
with
1746 | Some parent_class
->
1747 (* If it's not defined here, then either it's inherited (so we have emitted an error already)
1748 * or it's in a trait, and so we need to emit the error now *)
1749 if not
Ast_defs.(is_c_trait
(Cls.kind parent_class
)) then
1752 Errors.override_per_trait c
.c_name
id ce
.ce_origin
pos
1755 List.iter
(Cls.methods tc
) ~
f:(check_override ~is_static
:false);
1756 List.iter
(Cls.smethods tc
) ~
f:(check_override ~is_static
:true)
1758 if not
(skip_hierarchy_checks ctx) then check_enum_includes env c
;
1759 let (pc
, c_name
) = c
.c_name
in
1760 let (req_extends
, req_implements
) = split_reqs c
.c_reqs
in
1761 let hints_and_decl_tys hints
=
1762 List.map hints ~
f:(fun hint
-> (hint
, Decl_hint.hint
env.decl_env hint
))
1764 let extends = hints_and_decl_tys c
.c_extends
in
1765 let implements = hints_and_decl_tys c
.c_implements
in
1766 let uses = hints_and_decl_tys c
.c_uses
in
1767 let req_extends = hints_and_decl_tys req_extends in
1768 let req_implements = hints_and_decl_tys req_implements in
1769 let additional_parents =
1770 (* In an abstract class or a trait, we assume the interfaces
1771 will be implemented in the future, so we take them as
1772 part of the class (as requested by dependency injection implementers) *)
1774 | Ast_defs.Cclass k
when Ast_defs.is_abstract k
-> implements
1775 | Ast_defs.Ctrait
-> implements @ req_implements
1776 | Ast_defs.(Cclass _
| Cinterface
| Cenum
| Cenum_class _
) -> []
1778 let check_constructor_dep = check_constructor_dep env in
1779 if not
(skip_hierarchy_checks ctx) then (
1780 check_implements_or_extends_unique implements;
1781 check_implements_or_extends_unique extends
1783 check_constructor_dep extends;
1784 check_constructor_dep uses;
1785 check_constructor_dep req_extends;
1786 check_constructor_dep additional_parents;
1789 | Some e
-> check_constructor_dep (hints_and_decl_tys e
.e_includes
)
1793 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
1795 ~ignore_errors
:false
1797 c
.c_where_constraints
1800 Phase.check_where_constraints
1803 ~definition_pos
:(Pos_or_decl.of_raw_pos pc
)
1805 (empty_expand_env_with_on_error
1806 (Env.unify_error_assert_primary_pos_in_current_decl
env))
1808 (Cls.where_constraints tc
)
1810 Typing_variance.class_def
env c
;
1811 check_no_generic_static_property env tc
;
1812 let impl = extends @ implements @ uses in
1815 TypecheckerOptions.require_extends_implements_ancestors
1818 impl @ req_extends @ req_implements
1822 let env = check_class_parents_where_constraints env pc
impl in
1823 if not
(skip_hierarchy_checks ctx) then (
1824 check_parent env c tc
;
1825 check_parents_sealed env c tc
1827 (if not
(skip_hierarchy_checks ctx) then
1829 TypecheckerOptions.enforce_sealed_subclasses
(Env.get_tcopt
env)
1831 if is_enum_or_enum_class c
.c_kind
then
1832 if TypecheckerOptions.enable_enum_supertyping
(Env.get_tcopt
env) then
1833 sealed_subtype ctx c ~is_enum
:true ~
hard_error
1837 sealed_subtype ctx c ~is_enum
:false ~
hard_error);
1839 check_generic_class_with_SupportDynamicType env c
(extends @ implements)
1841 if not
(skip_hierarchy_checks ctx) then check_extend_abstract (pc
, tc
);
1842 if (not
(skip_hierarchy_checks ctx)) && Cls.const tc
then
1843 List.iter c
.c_uses ~
f:(check_non_const_trait_members pc
env);
1844 let (static_vars
, vars
) = split_vars c
.c_vars
in
1845 let (constructor
, static_methods
, methods
) = split_methods c
.c_methods
in
1846 if not
(skip_hierarchy_checks ctx) then (
1847 List.iter static_vars ~
f:(fun { cv_id
= (p
, id); _
} ->
1848 check_static_class_element (Cls.get_prop tc
) ~elt_type
:`Property
id p
);
1849 List.iter vars ~
f:(fun { cv_id
= (p
, id); _
} ->
1850 check_dynamic_class_element (Cls.get_sprop tc
) ~elt_type
:`Property
id p
);
1851 List.iter static_methods ~
f:(fun { m_name
= (p
, id); _
} ->
1852 check_static_class_element (Cls.get_method tc
) ~elt_type
:`Method
id p
);
1853 List.iter methods ~
f:(fun { m_name
= (p
, id); _
} ->
1854 check_dynamic_class_element (Cls.get_smethod tc
) ~elt_type
:`Method
id p
)
1857 if skip_hierarchy_checks ctx then
1860 Typing_extends.check_implements_extends_uses
1862 ~
implements:(List.map
implements ~
f:snd
)
1863 ~
parents:(List.map
impl ~
f:snd
)
1866 let is_disposable = Typing_disposable.is_disposable_class
env tc
in
1867 if (not
(skip_hierarchy_checks ctx)) && is_disposable then
1869 (c
.c_extends
@ c
.c_uses
)
1870 ~
f:(Typing_disposable.enforce_is_disposable
env);
1871 let (env, typed_vars_and_global_inference_envs
) =
1872 List.map_env
env vars ~
f:(class_var_def ~is_static
:false tc
)
1874 let (typed_vars
, vars_global_inference_envs
) =
1875 List.unzip typed_vars_and_global_inference_envs
1877 let (typed_methods
, methods_global_inference_envs
) =
1878 List.filter_map methods ~
f:(method_def ~
is_disposable env tc
) |> List.unzip
1880 let (env, typed_typeconsts
) =
1881 List.map_env
env c
.c_typeconsts ~
f:(typeconst_def c
)
1883 let in_enum_class = Env.is_enum_class
env c_name
in
1885 List.map_env
env c
.c_consts ~
f:(class_const_def ~
in_enum_class c
)
1887 let (typed_consts
, const_types
) = List.unzip consts
in
1888 let env = Typing_enum.enum_class_check
env tc c
.c_consts const_types
in
1889 let typed_constructor = class_constr_def ~
is_disposable env tc constructor
in
1890 let env = Env.set_static
env in
1891 let (env, typed_static_vars_and_global_inference_envs
) =
1892 List.map_env
env static_vars ~
f:(class_var_def ~is_static
:true tc
)
1894 let (typed_static_vars
, static_vars_global_inference_envs
) =
1895 List.unzip typed_static_vars_and_global_inference_envs
1897 let (typed_static_methods
, static_methods_global_inference_envs
) =
1898 List.filter_map static_methods ~
f:(method_def ~
is_disposable env tc
)
1901 let (methods
, constr_global_inference_env
) =
1902 match typed_constructor with
1903 | None
-> (typed_static_methods
@ typed_methods
, [])
1904 | Some
(m, global_inference_env
) ->
1905 (m :: typed_static_methods
@ typed_methods
, [global_inference_env
])
1907 let (env, tparams
) = class_type_param env c
.c_tparams
in
1908 let env = Typing_solver.solve_all_unsolved_tyvars
env in
1909 check_SupportDynamicType env c
;
1912 Aast.c_span
= c
.c_span
;
1913 Aast.c_annotation
= Env.save
(Env.get_tpenv
env) env;
1914 Aast.c_mode
= c
.c_mode
;
1915 Aast.c_final
= c
.c_final
;
1916 Aast.c_is_xhp
= c
.c_is_xhp
;
1917 Aast.c_has_xhp_keyword
= c
.c_has_xhp_keyword
;
1918 Aast.c_kind
= c
.c_kind
;
1919 Aast.c_name
= c
.c_name
;
1920 Aast.c_tparams
= tparams
;
1921 Aast.c_extends
= c
.c_extends
;
1922 Aast.c_uses
= c
.c_uses
;
1923 (* c_use_as_alias and c_insteadof_alias are PHP features not supported
1924 * in Hack but are required since we have runtime support for it
1926 Aast.c_use_as_alias
= [];
1927 Aast.c_insteadof_alias
= [];
1928 Aast.c_xhp_attr_uses
= c
.c_xhp_attr_uses
;
1929 Aast.c_xhp_category
= c
.c_xhp_category
;
1930 Aast.c_reqs
= c
.c_reqs
;
1931 Aast.c_implements
= c
.c_implements
;
1932 Aast.c_where_constraints
= c
.c_where_constraints
;
1933 Aast.c_consts
= typed_consts
;
1934 Aast.c_typeconsts
= typed_typeconsts
;
1935 Aast.c_vars
= typed_static_vars
@ typed_vars
;
1936 Aast.c_methods
= methods
;
1937 Aast.c_file_attributes
= file_attrs
;
1938 Aast.c_user_attributes
= user_attributes
;
1939 Aast.c_namespace
= c
.c_namespace
;
1940 Aast.c_enum
= c
.c_enum
;
1941 Aast.c_doc_comment
= c
.c_doc_comment
;
1942 Aast.c_attributes
= [];
1943 Aast.c_xhp_children
= c
.c_xhp_children
;
1944 Aast.c_xhp_attrs
= [];
1945 Aast.c_emit_id
= c
.c_emit_id
;
1947 methods_global_inference_envs
1948 @ static_methods_global_inference_envs
1949 @ constr_global_inference_env
1950 @ static_vars_global_inference_envs
1951 @ vars_global_inference_envs
)
1953 let class_def ctx c
=
1954 Counters.count
Counters.Category.Typecheck
@@ fun () ->
1955 Errors.run_with_span c
.c_span
@@ fun () ->
1956 let env = EnvFromDef.class_env ~origin
:Decl_counters.TopLevel
ctx c
in
1957 let (name_pos
, name) = c
.c_name
in
1958 let tc = Env.get_class
env name in
1959 let env = Env.set_env_pessimize
env in
1960 Typing_helpers.add_decl_errors
(Option.bind
tc ~
f:Cls.decl_errors
);
1963 @@ Typing_modules.of_maybe_string
1964 @@ Naming_attributes_params.get_module_attribute c
.c_user_attributes
1969 (Naming_attributes.mem
SN.UserAttributes.uaInternal c
.c_user_attributes
)
1972 Env.set_support_dynamic_type
1974 (Naming_attributes.mem
1975 SN.UserAttributes.uaSupportDynamicType
1976 c
.c_user_attributes
)
1978 Typing_type_wellformedness.class_
env c
;
1979 NastInitCheck.class_
env c
;
1982 (* This can happen if there was an error during the declaration
1986 (* If there are duplicate definitions of the class then we will end up
1987 * checking one AST with respect to the decl corresponding to the other definition.
1988 * Naming has already detected duplicates, so let's just avoid cascading unhelpful
1989 * typing errors, and also avoid triggering the bad position assert
1991 if not
(Pos.equal name_pos
(Cls.pos tc |> Pos_or_decl.unsafe_to_raw_pos
))
1996 if skip_hierarchy_checks ctx then
1999 let env = Typing_requirements.check_class
env name_pos
tc in
2000 if shallow_decl_enabled ctx then
2001 Typing_inheritance.check_class
env name_pos
tc;
2004 Some
(class_def_ env c
tc)
2006 let gconst_def ctx cst
=
2007 Counters.count
Counters.Category.Typecheck
@@ fun () ->
2008 Errors.run_with_span cst
.cst_span
@@ fun () ->
2009 let env = EnvFromDef.gconst_env ~origin
:Decl_counters.TopLevel
ctx cst
in
2010 let env = Env.set_env_pessimize
env in
2011 Typing_type_wellformedness.global_constant
env cst
;
2012 let (typed_cst_value
, env) =
2013 let value = cst
.cst_value
in
2014 match cst
.cst_type
with
2016 let ty = Decl_hint.hint
env.decl_env hint
in
2017 let ty = Typing_enforceability.compute_enforced_ty
env ty in
2019 Phase.localize_possibly_enforced_no_subst
env ~ignore_errors
:false ty
2021 let (env, te, value_type
) =
2023 ExpectedTy.make_and_allow_coercion
(fst hint
) Reason.URhint dty
2025 Typing.expr_with_pure_coeffects
env ~
expected value
2028 Typing_coercion.coerce_type
2039 (not
(is_literal_expr value))
2040 && Partial.should_check_error cst
.cst_mode
2035
2042 Errors.missing_typehint
(fst cst
.cst_name
);
2043 let (env, te, _value_type
) = Typing.expr_with_pure_coeffects
env value in
2047 Aast.cst_annotation
= Env.save
(Env.get_tpenv
env) env;
2048 Aast.cst_mode
= cst
.cst_mode
;
2049 Aast.cst_name
= cst
.cst_name
;
2050 Aast.cst_type
= cst
.cst_type
;
2051 Aast.cst_value
= typed_cst_value
;
2052 Aast.cst_namespace
= cst
.cst_namespace
;
2053 Aast.cst_span
= cst
.cst_span
;
2054 Aast.cst_emit_id
= cst
.cst_emit_id
;
2057 let record_field env f =
2058 let (id, hint
, e
) = f in
2059 let (p
, _
) = hint
in
2060 let (env, cty
) = Phase.localize_hint_no_subst
env ~ignore_errors
:false hint
in
2061 let expected = ExpectedTy.make p
Reason.URhint cty
in
2064 let (env, te, ty) = Typing.expr_with_pure_coeffects
env ~
expected e
in
2066 Typing_coercion.coerce_type
2071 (MakeType.unenforced cty
)
2072 Errors.record_init_value_does_not_match_hint
2074 (env, (id, hint
, Some
te))
2075 | None
-> (env, (id, hint
, None
))
2077 let record_def_parent env rd parent_hint
=
2078 match snd parent_hint
with
2079 | Aast.Happly
((parent_pos, parent_name), []) ->
2080 (match Decl_provider.get_record_def
(Env.get_ctx
env) parent_name with
2082 (* We can only inherit from abstract records. *)
2083 (if not parent_rd
.rdt_abstract
then
2084 let (parent_pos, parent_name) = parent_rd
.rdt_name
in
2085 Errors.extend_non_abstract_record
2090 (* Ensure we aren't defining fields that overlap with
2091 inherited fields. *)
2092 let inherited_fields = Typing_helpers.all_record_fields
env parent_rd
in
2093 List.iter rd
.rd_fields ~
f:(fun ((pos, name), _
, _
) ->
2094 match SMap.find_opt
name inherited_fields with
2095 | Some
((prev_pos
, _
), _
) ->
2096 Errors.repeated_record_field
name pos prev_pos
2099 (* Something exists with this name (naming succeeded), but it's
2101 Errors.unbound_name
parent_pos parent_name Errors.RecordContext
)
2104 "Record parent was not an Happly. This should have been a syntax error."
2106 (* Report an error if we have inheritance cycles in record declarations. *)
2107 let check_record_inheritance_cycle env ((rd_pos
, rd_name
) : Aast.sid
) : unit =
2108 let rec worker name trace seen
=
2109 match Decl_provider.get_record_def
(Env.get_ctx
env) name with
2111 (match rd
.rdt_extends
with
2112 | Some
(_
, parent_name) when String.equal
parent_name rd_name
->
2113 (* This record is in an inheritance cycle.*)
2114 Errors.cyclic_record_def trace rd_pos
2115 | Some
(_
, parent_name) when SSet.mem
parent_name seen
->
2116 (* There's an inheritance cycle higher in the chain. *)
2118 | Some
(_
, parent_name) ->
2119 worker parent_name (parent_name :: trace
) (SSet.add
parent_name seen
)
2123 worker rd_name
[rd_name
] (SSet.singleton rd_name
)
2125 let record_def_def ctx rd
=
2126 Counters.count
Counters.Category.Typecheck
@@ fun () ->
2127 let env = EnvFromDef.record_def_env ~origin
:Decl_counters.TopLevel
ctx rd
in
2128 Typing_type_wellformedness.record_def
env rd
;
2129 (match rd
.rd_extends
with
2130 | Some parent
-> record_def_parent env rd parent
2133 check_record_inheritance_cycle env rd
.rd_name
;
2135 let (env, attributes
) =
2136 Typing.attributes_check_def
env SN.AttributeKinds.cls rd
.rd_user_attributes
2138 let (_env, fields
) = List.map_env
env rd
.rd_fields ~
f:record_field in
2140 Aast.rd_annotation
= Env.save
(Env.get_tpenv
env) env;
2141 Aast.rd_name
= rd
.rd_name
;
2142 Aast.rd_extends
= rd
.rd_extends
;
2143 Aast.rd_abstract
= rd
.rd_abstract
;
2144 Aast.rd_fields
= fields
;
2145 Aast.rd_user_attributes
= attributes
;
2146 Aast.rd_namespace
= rd
.rd_namespace
;
2147 Aast.rd_span
= rd
.rd_span
;
2148 Aast.rd_doc_comment
= rd
.rd_doc_comment
;
2149 Aast.rd_emit_id
= rd
.rd_emit_id
;
2152 let nast_to_tast_gienv ~
(do_tast_checks
: bool) ctx nast
:
2153 _
* Typing_inference_env.t_global_with_pos list
=
2154 let convert_def = function
2155 (* Sometimes typing will just return `None` but that should only be the case
2156 * if an error had already been registered e.g. in naming
2160 match fun_def ctx f with
2161 | Some
(f, env) -> Some
(Aast.Fun
f, [env])
2164 | Constant gc
-> Some
(Aast.Constant
(gconst_def ctx gc
), [])
2165 | Typedef td
-> Some
(Aast.Typedef
(Typing_typedef.typedef_def
ctx td
), [])
2168 match class_def ctx c
with
2169 | Some
(c
, envs
) -> Some
(Aast.Class c
, envs
)
2172 | RecordDef rd
-> Some
(Aast.RecordDef
(record_def_def ctx rd
), [])
2173 (* We don't typecheck top level statements:
2174 * https://docs.hhvm.com/hack/unsupported/top-level
2175 * so just create the minimal env for us to construct a Stmt.
2178 let env = Env.empty
ctx Relative_path.default ~droot
:None
in
2179 Some
(Aast.Stmt
(snd
(Typing.stmt
env s
)), [])
2183 | FileAttributes _
->
2185 "Invalid nodes in NAST. These nodes should be removed during naming."
2187 Nast_check.program
ctx nast
;
2188 let (tast
, envs
) = List.unzip
@@ List.filter_map nast ~
f:convert_def in
2189 let envs = List.concat
envs in
2190 if do_tast_checks
then Tast_check.program
ctx tast
;
2193 let nast_to_tast ~do_tast_checks
ctx nast
=
2194 let (tast
, _gienvs
) = nast_to_tast_gienv ~do_tast_checks
ctx nast
in