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
23 module FunUtils
= Decl_fun_utils
24 module Reason
= Typing_reason
25 module Env
= Typing_env
26 module MakeType
= Typing_make_type
27 module Type
= Typing_ops
28 module Phase
= Typing_phase
29 module Subst
= Decl_subst
30 module EnvFromDef
= Typing_env_from_def
31 module Partial
= Partial_provider
32 module TUtils
= Typing_utils
33 module TCO
= TypecheckerOptions
34 module Cls
= Decl_provider.Class
35 module SN
= Naming_special_names
37 (* The two following functions enable us to retrieve the function (or class)
38 header from the shared mem. Note that they only return a non None value if
39 global inference is on *)
40 let get_decl_function_header env function_id
=
41 let is_global_inference_on = TCO.global_inference
(Env.get_tcopt env
) in
42 if is_global_inference_on then
43 match Decl_provider.get_fun
(Env.get_ctx env
) function_id
with
44 | Some
{ fe_type
; _
} ->
46 match get_node fe_type
with
47 | Tfun fun_type
-> Some fun_type
54 and get_decl_method_header tcopt cls method_id ~is_static
=
55 let is_global_inference_on = TCO.global_inference tcopt
in
56 if is_global_inference_on then
57 match Cls.get_any_method ~is_static cls method_id
with
58 | Some
{ ce_type
= (lazy ty
); _
} ->
60 match get_node ty
with
61 | Tfun fun_type
-> Some fun_type
68 let enforce_param_not_disposable env param ty
=
69 if has_accept_disposable_attribute param
then
72 let p = param
.param_pos
in
73 match Typing_disposable.is_disposable_type env ty
with
74 | Some class_name
-> Errors.invalid_disposable_hint
p (strip_ns class_name
)
77 (* In strict mode, we force you to give a type declaration on a parameter *)
78 (* But the type checker is nice: it makes a suggestion :-) *)
79 let check_param_has_hint env param ty is_code_error
=
81 if is_code_error
4231 then
82 Typing.attributes_check_def
84 SN.AttributeKinds.parameter
85 param
.param_user_attributes
89 match hint_of_type_hint param
.param_type_hint
with
90 | None
when param
.param_is_variadic
&& is_code_error
4033 ->
91 Errors.expecting_type_hint_variadic param
.param_pos
92 | None
when is_code_error
4032 -> Errors.expecting_type_hint param
.param_pos
93 | Some _
when is_code_error
4010 ->
94 (* We do not permit hints to implement IDisposable or IAsyncDisposable *)
95 enforce_param_not_disposable env param ty
98 (* This function is used to determine the type of an argument.
99 * When we want to type-check the body of a function, we need to
100 * introduce the type of the arguments of the function in the environment
101 * Let's take an example, we want to check the code of foo:
103 * function foo(int $x): int {
104 * // CALL TO make_param_type on (int $x)
105 * // Now we know that the type of $x is int
107 * return $x; // in the environment $x is an int, the code is correct
110 * When we localize, we want to resolve to "static" or "$this" depending on
111 * the context. Even though we are passing in CIstatic, resolve_with_class_id
112 * is smart enough to know what to do. Why do this? Consider the following
115 * abstract const type T;
117 * private this::T $val;
119 * final public function __construct(this::T $x) {
123 * public static function create(this::T $x): this {
124 * return new static($x);
128 * class D extends C { const type T = int; }
130 * In __construct() we want to be able to assign $x to $this->val. The type of
131 * $this->val will expand to '$this::T', so we need $x to also be '$this::T'.
132 * We can do this soundly because when we construct a new class such as,
133 * 'new D(0)' we can determine the late static bound type (D) and resolve
134 * 'this::T' to 'D::T' which is int.
136 * A similar line of reasoning is applied for the static method create.
138 let make_param_local_ty env decl_hint param
=
139 let r = Reason.Rwitness param
.param_pos
in
142 | None
-> (env, mk
(r, TUtils.tany
env))
144 let { et_type
= ty
; _
} =
145 Typing_enforceability.compute_enforced_and_pessimize_ty
146 ~explicitly_untrusted
:param
.param_is_variadic
150 Phase.localize_no_subst
env ~ignore_errors
:false ty
153 match get_node
ty with
154 | t
when param
.param_is_variadic
->
155 (* when checking the body of a function with a variadic
156 * argument, "f(C ...$args)", $args is a varray<C> *)
157 let r = Reason.Rvar_param param
.param_pos
in
158 let arr_values = mk
(r, t
) in
159 MakeType.varray
r arr_values
164 let get_callable_variadicity ~partial_callback ~pos
env variadicity_decl_ty
=
166 | FVvariadicArg vparam
->
167 let (env, ty) = make_param_local_ty env variadicity_decl_ty vparam
in
168 check_param_has_hint env vparam
ty partial_callback
;
169 let (env, t_variadic
) = Typing.bind_param
env (ty, vparam
) in
170 (env, Aast.FVvariadicArg t_variadic
)
172 if Partial.should_check_error
(Env.get_mode
env) 4223 then
173 Errors.ellipsis_strict_mode ~require
:`Type_and_param_name pos
;
174 (env, Aast.FVellipsis
p)
175 | FVnonVariadic
-> (env, Aast.FVnonVariadic
)
177 let merge_hint_with_decl_hint env type_hint decl_ty
=
178 let contains_tvar decl_ty
=
181 | Some decl_ty
-> TUtils.contains_tvar_decl decl_ty
183 if contains_tvar decl_ty
then
186 Option.map type_hint ~f
:(Decl_hint.hint
env.decl_env
)
188 (* During the decl phase we can, for global inference, add "improved type hints".
189 That is we can say that some missing type hints are in fact global tyvars.
190 In that case to get the real type hint we must merge the type hint present
191 in the ast with the one we created during the decl phase. This function does
192 exactly this for the return type, the parameters and the variadic parameters.
194 let merge_decl_header_with_hints ~params ~ret ~variadic decl_header
env =
196 merge_hint_with_decl_hint
198 (hint_of_type_hint ret
)
200 ~f
:(fun { ft_ret
= { et_type
; _
}; _
} -> et_type
)
204 match decl_header
with
208 merge_hint_with_decl_hint
210 (hint_of_type_hint h
.param_type_hint
)
213 | Some
{ ft_params
; _
} ->
214 List.zip_exn params ft_params
215 |> List.map ~f
:(fun (h
, { fp_type
= { et_type
; _
}; _
}) ->
216 merge_hint_with_decl_hint
218 (hint_of_type_hint h
.param_type_hint
)
221 let variadicity_decl_ty =
222 match (decl_header
, variadic
) with
223 | ( Some
{ ft_arity
= Fvariadic
{ fp_type
= { et_type
; _
}; _
}; _
},
224 FVvariadicArg fp
) ->
225 merge_hint_with_decl_hint
227 (hint_of_type_hint fp
.param_type_hint
)
229 | (_
, FVvariadicArg fp
) ->
230 merge_hint_with_decl_hint env (hint_of_type_hint fp
.param_type_hint
) None
233 (ret_decl_ty, params_decl_ty, variadicity_decl_ty)
235 (* Checking this with List.exists will be a single op in the vast majority of cases (empty) *)
236 let get_ctx_vars ctxs
=
239 List.filter_map cs ~f
:(function
240 | (_
, Haccess
((_
, Hvar n
), _
)) -> Some n
245 let function_dynamically_callable
246 env f
params_decl_ty variadicity_decl_ty ret_locl_ty
=
247 let env = { env with in_support_dynamic_type_method_check
= true } in
248 let interface_check =
249 Typing_dynamic.sound_dynamic_interface_check
251 (variadicity_decl_ty :: params_decl_ty)
254 let function_body_check () =
255 (* Here the body of the function is typechecked again to ensure it is safe
256 * to call it from a dynamic context (eg. under dyn..dyn->dyn assumptions).
257 * The code below must be kept in sync with with the fun_def checks.
259 let make_dynamic pos
=
260 Typing_make_type.dynamic
(Reason.Rsupport_dynamic_type pos
)
262 let dynamic_return_ty = make_dynamic (get_pos ret_locl_ty
) in
263 let dynamic_return_info =
264 Typing_env_return_info.
266 return_type
= MakeType.unenforced
dynamic_return_ty;
267 return_disposable
= false;
268 return_explicit
= true;
269 return_dynamically_callable
= true;
272 let (env, param_tys
) =
273 List.zip_exn f
.f_params
params_decl_ty
274 |> List.map_env
env ~f
:(fun env (param
, hint
) ->
276 make_dynamic @@ Pos_or_decl.of_raw_pos param
.param_pos
280 | Some
ty when Typing_enforceability.is_enforceable
env ty ->
281 Typing_make_type.intersection
282 (Reason.Rsupport_dynamic_type
Pos_or_decl.none
)
286 make_param_local_ty env (Some
ty) param
)
288 let params_need_immutable = get_ctx_vars f
.f_ctxs
in
290 (* In this pass, bind_param_and_check receives a pair where the lhs is
291 * either Tdynamic or TInstersection of the original type and TDynamic,
292 * but the fun_param is still referencing the source hint. We amend
293 * the source hint to keep in in sync before calling bind_param
294 * so the right enforcement is computed.
296 let bind_param_and_check env lty_and_param
=
297 let (ty, param
) = lty_and_param
in
298 let name = param
.param_name
in
299 let (hi
, hopt
) = param
.param_type_hint
in
301 Option.map
hopt ~f
:(fun (p, h
) ->
302 if Typing_utils.is_tintersection
env ty then
303 (p, Hintersection
[(p, h
); (p, Hdynamic
)])
307 let param_type_hint = (hi
, hopt) in
308 let param = (ty, { param with param_type_hint }) in
310 List.exists ~f
:(String.equal
name) params_need_immutable
312 let (env, fun_param
) = Typing.bind_param ~
immutable env param in
317 (List.zip_exn param_tys f
.f_params
)
318 ~f
:bind_param_and_check
321 let pos = fst f
.f_name
in
322 let (env, t_variadic
) =
323 get_callable_variadicity
324 ~partial_callback
:(Partial.should_check_error
(Env.get_mode
env))
327 (Some
(make_dynamic @@ Pos_or_decl.of_raw_pos
pos))
331 set_tyvars_variance_in_callable
env dynamic_return_ty param_tys t_variadic
334 Naming_attributes.mem
335 SN.UserAttributes.uaDisableTypecheckerInternal
341 let (_
: env * Tast.stmt list
) =
342 Typing.fun_ ~
disable env dynamic_return_info pos f
.f_body f
.f_fun_kind
346 Errors.function_is_not_dynamically_callable
pos (snd f
.f_name
) error
)
348 if not
interface_check then function_body_check ()
351 (Tast.fun_def * Typing_inference_env.t_global_with_pos
) option =
353 Counters.count
Counters.Category.Typecheck
@@ fun () ->
354 Errors.run_with_span
f.f_span
@@ fun () ->
355 let env = EnvFromDef.fun_env ~origin
:Decl_counters.TopLevel ctx fd
in
356 with_timeout
env f.f_name
@@ fun env ->
357 (* reset the expression dependent display ids for each function body *)
358 Reason.expr_display_id_map
:= IMap.empty
;
359 let pos = fst
f.f_name
in
360 let decl_header = get_decl_function_header env (snd
f.f_name
) in
361 let env = Env.open_tyvars
env (fst
f.f_name
) in
362 let env = Env.set_env_callable_pos
env pos in
363 let env = Env.set_env_pessimize
env in
365 Typing.attributes_check_def
env SN.AttributeKinds.fn
f.f_user_attributes
367 let (env, file_attrs
) = Typing.file_attributes
env fd
.fd_file_attributes
in
368 let (env, cap_ty
, unsafe_cap_ty
) =
369 Typing.type_capability
env f.f_ctxs
f.f_unsafe_ctxs
(fst
f.f_name
)
374 (Naming_attributes_params.get_module_attribute
f.f_user_attributes
)
379 (Naming_attributes.mem
SN.UserAttributes.uaInternal
f.f_user_attributes
)
381 Typing_type_wellformedness.fun_
env f;
383 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
387 f.f_where_constraints
389 let env = Env.set_fn_kind
env f.f_fun_kind
in
390 let (return_decl_ty
, params_decl_ty, variadicity_decl_ty) =
391 merge_decl_header_with_hints
394 ~variadic
:f.f_variadic
398 let (env, return_ty
) =
399 match return_decl_ty
with
401 (env, Typing_return.make_default_return ~is_method
:false env f.f_name
)
403 let localize env ty =
404 Phase.localize_no_subst
env ~ignore_errors
:false ty
406 Typing_return.make_return_type
localize env ty
409 match snd
f.f_ret
with
410 | Some
(ret_pos, _
) -> ret_pos
411 | None
-> fst
f.f_name
413 let (env, return_ty
) =
414 Typing_return.force_return_kind
env ret_pos return_ty
417 Typing_return.make_info
422 ~is_explicit
:(Option.is_some
(hint_of_type_hint
f.f_ret
))
426 let sound_dynamic_check_saved_env = env in
427 let (env, param_tys
) =
428 List.zip_exn
f.f_params
params_decl_ty
429 |> List.map_env
env ~
f:(fun env (param, hint
) ->
430 make_param_local_ty env hint
param)
432 let partial_callback = Partial.should_check_error
(Env.get_mode
env) in
433 let check_has_hint p t
= check_param_has_hint env p t
partial_callback in
434 List.iter2_exn ~
f:check_has_hint f.f_params param_tys
;
435 let params_need_immutable = get_ctx_vars f.f_ctxs
in
436 let (env, typed_params
) =
437 let bind_param_and_check env param =
438 let name = (snd
param).param_name
in
440 List.exists ~
f:(String.equal
name) params_need_immutable
442 let (env, fun_param
) = Typing.bind_param ~
immutable env param in
445 List.map_env
env (List.zip_exn param_tys
f.f_params
) ~
f:bind_param_and_check
447 let (env, t_variadic
) =
448 get_callable_variadicity
456 set_tyvars_variance_in_callable
env return_ty param_tys t_variadic
458 let local_tpenv = Env.get_tpenv
env in
460 Naming_attributes.mem
461 SN.UserAttributes.uaDisableTypecheckerInternal
465 Typing_coeffects.register_capabilities
env cap_ty unsafe_cap_ty
467 Typing_memoize.check_function
env f;
468 let (env, tb
) = Typing.fun_ ~
disable env return pos f.f_body
f.f_fun_kind
in
470 match hint_of_type_hint
f.f_ret
with
472 if partial_callback 4030 then Errors.expecting_return_type_hint
pos
475 let (env, tparams
) = List.map_env
env f.f_tparams ~
f:Typing.type_param
in
476 let (env, user_attributes
) =
477 List.map_env
env f.f_user_attributes ~
f:Typing.user_attribute
479 let env = Typing_solver.close_tyvars_and_solve
env in
480 let env = Typing_solver.solve_all_unsolved_tyvars
env in
482 let check_support_dynamic_type =
483 Naming_attributes.mem
484 SN.UserAttributes.uaSupportDynamicType
488 TypecheckerOptions.enable_sound_dynamic
489 (Provider_context.get_tcopt
(Env.get_ctx
env))
490 && check_support_dynamic_type
492 function_dynamically_callable
493 sound_dynamic_check_saved_env
501 Aast.f_annotation
= Env.save
local_tpenv env;
502 Aast.f_readonly_this
= f.f_readonly_this
;
503 Aast.f_span
= f.f_span
;
504 Aast.f_readonly_ret
= f.f_readonly_ret
;
505 Aast.f_ret
= (return_ty
, hint_of_type_hint
f.f_ret
);
506 Aast.f_name
= f.f_name
;
507 Aast.f_tparams
= tparams
;
508 Aast.f_where_constraints
= f.f_where_constraints
;
509 Aast.f_variadic
= t_variadic
;
510 Aast.f_params
= typed_params
;
511 Aast.f_ctxs
= f.f_ctxs
;
512 Aast.f_unsafe_ctxs
= f.f_unsafe_ctxs
;
513 Aast.f_fun_kind
= f.f_fun_kind
;
514 Aast.f_user_attributes
= user_attributes
;
515 Aast.f_body
= { Aast.fb_ast
= tb
};
516 Aast.f_external
= f.f_external
;
517 Aast.f_doc_comment
= f.f_doc_comment
;
522 Aast.fd_mode
= fd
.fd_mode
;
524 Aast.fd_file_attributes
= file_attrs
;
525 Aast.fd_namespace
= fd
.fd_namespace
;
528 let (_env
, global_inference_env
) = Env.extract_global_inference_env
env in
529 (fundef, (pos, global_inference_env
))
531 let method_dynamically_callable
532 env cls m
params_decl_ty variadicity_decl_ty ret_locl_ty
=
533 let env = { env with in_support_dynamic_type_method_check
= true } in
534 (* Add `dynamic` lower and upper bound to any type parameters that are not marked <<__NoRequireDynamic>> *)
535 let env_with_require_dynamic =
536 Typing_dynamic.add_require_dynamic_bounds
env cls
538 let interface_check =
539 Typing_dynamic.sound_dynamic_interface_check
540 env_with_require_dynamic
541 (variadicity_decl_ty :: params_decl_ty)
544 let method_body_check () =
545 (* Here the body of the method is typechecked again to ensure it is safe
546 * to call it from a dynamic context (eg. under dyn..dyn->dyn assumptions).
547 * The code below must be kept in sync with with the method_def checks.
549 let make_dynamic pos =
550 Typing_make_type.dynamic
(Reason.Rsupport_dynamic_type
pos)
552 let dynamic_return_ty = make_dynamic (get_pos ret_locl_ty
) in
553 let dynamic_return_info =
554 Typing_env_return_info.
556 return_type
= MakeType.unenforced
dynamic_return_ty;
557 return_disposable
= false;
558 return_explicit
= true;
559 return_dynamically_callable
= true;
562 let (env, param_tys
) =
563 List.zip_exn m
.m_params
params_decl_ty
564 |> List.map_env
env ~
f:(fun env (param, hint
) ->
566 make_dynamic @@ Pos_or_decl.of_raw_pos
param.param_pos
570 | Some
ty when Typing_enforceability.is_enforceable
env ty ->
571 Typing_make_type.intersection
572 (Reason.Rsupport_dynamic_type
Pos_or_decl.none
)
576 make_param_local_ty env (Some
ty) param)
578 let params_need_immutable = get_ctx_vars m
.m_ctxs
in
580 (* In this pass, bind_param_and_check receives a pair where the lhs is
581 * either Tdynamic or TInstersection of the original type and TDynamic,
582 * but the fun_param is still referencing the source hint. We amend
583 * the source hint to keep in in sync before calling bind_param
584 * so the right enforcement is computed.
586 let bind_param_and_check env lty_and_param
=
587 let (ty, param) = lty_and_param
in
588 let name = param.param_name
in
589 let (hi
, hopt) = param.param_type_hint in
591 Option.map
hopt ~
f:(fun (p, h
) ->
592 if Typing_utils.is_tintersection
env ty then
593 (p, Hintersection
[(p, h
); (p, Hdynamic
)])
597 let param_type_hint = (hi
, hopt) in
598 let param = (ty, { param with param_type_hint }) in
600 List.exists ~
f:(String.equal
name) params_need_immutable
602 let (env, fun_param
) = Typing.bind_param ~
immutable env param in
607 (List.zip_exn param_tys m
.m_params
)
608 ~
f:bind_param_and_check
611 let pos = fst m
.m_name
in
612 let (env, t_variadic
) =
613 get_callable_variadicity
614 ~
partial_callback:(Partial.should_check_error
(Env.get_mode
env))
617 (Some
(make_dynamic @@ Pos_or_decl.of_raw_pos
pos))
621 set_tyvars_variance_in_callable
env dynamic_return_ty param_tys t_variadic
625 if Cls.get_support_dynamic_type cls
then
627 Typing_make_type.intersection
628 (Reason.Rsupport_dynamic_type
Pos_or_decl.none
)
629 [Env.get_local
env this
; make_dynamic Pos_or_decl.none
]
631 Env.set_local
env this
this_ty Pos.none
637 Naming_attributes.mem
638 SN.UserAttributes.uaDisableTypecheckerInternal
644 let (_
: env * Tast.stmt list
) =
646 ~abstract
:m
.m_abstract
656 Errors.method_is_not_dynamically_callable
660 (Naming_attributes.mem
661 SN.UserAttributes.uaSupportDynamicType
663 || Cls.get_support_dynamic_type cls
)
667 if not
interface_check then method_body_check ()
669 let method_def env cls m
=
670 Errors.run_with_span m
.m_span
@@ fun () ->
671 with_timeout
env m
.m_name
@@ fun env ->
672 FunUtils.check_params m
.m_params
;
673 let initial_env = env in
674 (* reset the expression dependent display ids for each method body *)
675 Reason.expr_display_id_map
:= IMap.empty
;
677 get_decl_method_header
681 ~is_static
:m
.m_static
683 let pos = fst m
.m_name
in
684 let env = Env.open_tyvars
env (fst m
.m_name
) in
685 let env = Env.reinitialize_locals
env in
686 let env = Env.set_env_callable_pos
env pos in
688 Typing.attributes_check_def
env SN.AttributeKinds.mthd m
.m_user_attributes
690 let (env, cap_ty
, unsafe_cap_ty
) =
691 Typing.type_capability
env m
.m_ctxs m
.m_unsafe_ctxs
(fst m
.m_name
)
694 Typing_coeffects.register_capabilities
env cap_ty unsafe_cap_ty
696 let is_ctor = String.equal
(snd m
.m_name
) SN.Members.__construct
in
697 let env = Env.set_fun_is_constructor
env is_ctor in
699 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
703 m
.m_where_constraints
706 match Env.get_self_ty
env with
707 | Some
ty when not
(Env.is_static
env) ->
708 Env.set_local
env this
(MakeType.this
(get_reason
ty)) Pos.none
712 match Env.get_self_class
env with
715 (* Mark $this as a using variable if it has a disposable type *)
716 if Cls.is_disposable c
then
717 Env.set_using_var
env this
721 let env = Env.clear_params
env in
722 let (ret_decl_ty, params_decl_ty, variadicity_decl_ty) =
723 merge_decl_header_with_hints
726 ~variadic
:m
.m_variadic
730 let env = Env.set_fn_kind
env m
.m_fun_kind
in
732 match ret_decl_ty with
734 (env, Typing_return.make_default_return ~is_method
:true env m
.m_name
)
736 (* If a 'this' type appears it needs to be compatible with the
740 empty_expand_env_with_on_error
741 (Env.invalid_type_hint_assert_primary_pos_in_current_decl
env)
743 Typing_return.make_return_type
(Phase.localize ~
ety_env) env ret
746 match snd m
.m_ret
with
747 | Some
(ret_pos, _
) -> ret_pos
748 | None
-> fst m
.m_name
750 let (env, locl_ty
) = Typing_return.force_return_kind
env ret_pos locl_ty
in
752 Typing_return.make_info
757 ~is_explicit
:(Option.is_some
(hint_of_type_hint m
.m_ret
))
761 let sound_dynamic_check_saved_env = env in
762 let (env, param_tys
) =
763 List.zip_exn m
.m_params
params_decl_ty
764 |> List.map_env
env ~
f:(fun env (param, hint
) ->
765 make_param_local_ty env hint
param)
767 let partial_callback = Partial.should_check_error
(Env.get_mode
env) in
768 let param_fn p t
= check_param_has_hint env p t
partial_callback in
769 List.iter2_exn ~
f:param_fn m
.m_params param_tys
;
770 Typing_memoize.check_method
env m
;
771 let params_need_immutable = get_ctx_vars m
.m_ctxs
in
772 let (env, typed_params
) =
773 let bind_param_and_check env param =
774 let name = (snd
param).param_name
in
776 List.exists ~
f:(String.equal
name) params_need_immutable
778 let (env, fun_param
) = Typing.bind_param ~
immutable env param in
781 List.map_env
env (List.zip_exn param_tys m
.m_params
) ~
f:bind_param_and_check
783 let (env, t_variadic
) =
784 get_callable_variadicity
791 let env = set_tyvars_variance_in_callable
env locl_ty param_tys t_variadic
in
793 let local_tpenv = Env.get_tpenv
env in
795 Naming_attributes.mem
796 SN.UserAttributes.uaDisableTypecheckerInternal
800 Typing.fun_ ~abstract
:m
.m_abstract ~
disable env return pos nb m
.m_fun_kind
803 match hint_of_type_hint m
.m_ret
with
804 | None
when String.equal
(snd m
.m_name
) SN.Members.__construct
->
805 Some
(pos, Hprim Tvoid
)
807 if partial_callback 4030 then Errors.expecting_return_type_hint
pos;
809 | Some _
-> hint_of_type_hint m
.m_ret
811 let m = { m with m_ret
= (fst
m.m_ret
, type_hint'
) } in
812 let (env, tparams
) = List.map_env
env m.m_tparams ~
f:Typing.type_param
in
813 let (env, user_attributes
) =
814 List.map_env
env m.m_user_attributes ~
f:Typing.user_attribute
816 let env = Typing_solver.close_tyvars_and_solve
env in
817 let env = Typing_solver.solve_all_unsolved_tyvars
env in
819 (* if the enclosing class implements dynamic, or the method is annotated with
820 * <<__SupportDynamicType>>, check that the method is dynamically callable *)
821 let check_support_dynamic_type =
822 (not
env.inside_constructor
)
823 && (Cls.get_support_dynamic_type cls
824 && not
(Aast.equal_visibility
m.m_visibility Private
)
825 || Naming_attributes.mem
826 SN.UserAttributes.uaSupportDynamicType
830 TypecheckerOptions.enable_sound_dynamic
831 (Provider_context.get_tcopt
(Env.get_ctx
env))
832 && check_support_dynamic_type
834 method_dynamically_callable
835 sound_dynamic_check_saved_env
843 Aast.m_annotation
= Env.save
local_tpenv env;
844 Aast.m_span
= m.m_span
;
845 Aast.m_final
= m.m_final
;
846 Aast.m_static
= m.m_static
;
847 Aast.m_abstract
= m.m_abstract
;
848 Aast.m_visibility
= m.m_visibility
;
849 Aast.m_readonly_this
= m.m_readonly_this
;
850 Aast.m_name
= m.m_name
;
851 Aast.m_tparams
= tparams
;
852 Aast.m_where_constraints
= m.m_where_constraints
;
853 Aast.m_variadic
= t_variadic
;
854 Aast.m_params
= typed_params
;
855 Aast.m_ctxs
= m.m_ctxs
;
856 Aast.m_unsafe_ctxs
= m.m_unsafe_ctxs
;
857 Aast.m_fun_kind
= m.m_fun_kind
;
858 Aast.m_user_attributes
= user_attributes
;
859 Aast.m_readonly_ret
= m.m_readonly_ret
;
860 Aast.m_ret
= (locl_ty
, hint_of_type_hint
m.m_ret
);
861 Aast.m_body
= { Aast.fb_ast
= tb
};
862 Aast.m_external
= m.m_external
;
863 Aast.m_doc_comment
= m.m_doc_comment
;
866 let (env, global_inference_env
) = Env.extract_global_inference_env
env in
867 let _env = Env.log_env_change
"method_def" initial_env env in
868 (method_def, (pos, global_inference_env
))
870 (** Checks that extending this parent is legal - e.g. it is not final and not const. *)
871 let check_parent env class_def class_type
=
872 match Env.get_parent_class
env with
873 | Some parent_type
->
874 let position = fst class_def
.c_name
in
875 if Cls.const class_type
&& not
(Cls.const parent_type
) then
876 Errors.self_const_parent_not
position;
877 if Cls.final parent_type
then
878 Errors.extend_final
position (Cls.pos parent_type
) (Cls.name parent_type
)
881 let sealed_subtype ctx
(c
: Nast.class_
) ~is_enum
=
882 let parent_name = snd c
.c_name
in
883 let is_sealed (attr
: Nast.user_attribute
) =
884 String.equal
(snd attr
.ua_name
) SN.UserAttributes.uaSealed
886 match List.find c
.c_user_attributes ~
f:is_sealed with
888 | Some sealed_attr
->
889 let iter_item ((_
, pos, expr_
) : Nast.expr
) =
891 | Class_const
((_
, _
, cid
), _
) ->
892 let klass_name = Nast.class_id_to_str cid
in
893 let klass = Decl_provider.get_class ctx
klass_name in
897 let includes_ancestor =
899 match Cls.enum_type decl
with
903 match get_node x
with
904 | Tapply
((_
, name), _
) -> String.equal
name parent_name
907 List.exists enum_ty
.te_includes ~
f:check
909 Cls.has_ancestor decl
parent_name
911 if not
includes_ancestor then
912 let parent_pos = pos in
913 let child_pos = Cls.pos decl
in
914 let child_name = Cls.name decl
in
915 let (child_kind
, verb
) =
916 match Cls.kind decl
with
917 | Ast_defs.Cclass _
-> ("Class", "extend")
918 | Ast_defs.Cinterface
-> ("Interface", "implement")
919 | Ast_defs.Ctrait
-> ("Trait", "use")
920 | Ast_defs.Cenum
-> ("Enum", "use")
921 | Ast_defs.Cenum_class _
-> ("Enum Class", "extend")
923 Errors.sealed_not_subtype
930 (* unit below is fine because error cases are handled as Parsing[1002] *)
933 List.iter sealed_attr
.ua_params ~
f:iter_item
935 let check_parent_sealed (child_pos, child_type
) parent_type
=
936 match Cls.sealed_whitelist parent_type
with
939 let parent_pos = Cls.pos parent_type
in
940 let parent_name = Cls.name parent_type
in
941 let child_name = Cls.name child_type
in
942 let check kind action
=
943 if not
(SSet.mem
child_name whitelist
) then
944 Errors.extend_sealed
child_pos parent_pos parent_name kind action
947 match (Cls.kind parent_type
, Cls.kind child_type
) with
948 | (Ast_defs.Cinterface
, Ast_defs.Cinterface
) -> check "interface" "extend"
949 | (Ast_defs.Cinterface
, _
) -> check "interface" "implement"
950 | (Ast_defs.Ctrait
, _
) -> check "trait" "use"
951 | (Ast_defs.Cclass _
, _
) -> check "class" "extend"
952 | (Ast_defs.Cenum_class _
, _
) -> check "enum class" "extend"
953 | (Ast_defs.Cenum
, _
) -> check "enum" "use"
956 let check_parents_sealed env child_def child_type
=
958 match child_def
.c_enum
with
959 | Some enum
-> enum
.e_includes
960 | None
-> child_def
.c_extends
962 let parents = parents @ child_def
.c_implements
@ child_def
.c_uses
in
963 List.iter
parents ~
f:(function
964 | (_
, Happly
((_
, name), _
)) ->
966 match Env.get_class_dep
env name with
967 | Some parent_type
->
968 check_parent_sealed (fst child_def
.c_name
, child_type
) parent_type
973 (* Reject multiple instantiations of the same generic interface
974 * in extends and implements clauses.
975 * e.g. disallow class C implements I<string>, I<int>
977 * O(n^2) but we don't expect number of instantiated interfaces to be large
979 let rec check_implements_or_extends_unique impl
=
982 | (hint
, ty) :: rest
->
983 (match get_node
ty with
984 | Tapply
((_
, name), _
:: _
) ->
985 let (pos_list
, rest
) =
986 List.partition_map rest ~
f:(fun (h
, ty) ->
987 match get_node
ty with
988 | Tapply
((pos'
, name'
), _
) when String.equal
name name'
->
990 | _
-> Second
(h
, ty))
992 if not
(List.is_empty pos_list
) then
993 Errors.duplicate_interface
(fst hint
) name pos_list
;
994 check_implements_or_extends_unique rest
995 | _
-> check_implements_or_extends_unique rest
)
997 let check_constructor_dep env deps
=
998 List.iter deps ~
f:(fun ((p, _dep_hint
), dep
) ->
999 match get_node dep
with
1000 | Tapply
((_
, class_name
), _
) ->
1001 Env.make_depend_on_constructor
env class_name
1003 Errors.expected_class ~suffix
:" or interface but got a generic" p
1004 | _
-> Errors.expected_class ~suffix
:" or interface" p)
1006 (** For const classes, check that members from traits are all constant. *)
1007 let check_non_const_trait_members pos env use_list
=
1008 let (_
, trait
, _
) = Decl_utils.unwrap_class_hint use_list
in
1009 match Env.get_class
env trait
with
1010 | Some c
when Ast_defs.is_c_trait
(Cls.kind c
) ->
1011 List.iter
(Cls.props c
) ~
f:(fun (x
, ce
) ->
1012 if not
(get_ce_const ce
) then Errors.trait_prop_const_class
pos x
)
1015 let check_consistent_enum_inclusion
1016 included_cls
((dest_cls_pos
, dest_cls
) : Pos.t
* Cls.t
) =
1017 let included_kind = Cls.kind included_cls
in
1018 let dest_kind = Cls.kind dest_cls
in
1019 match (Cls.enum_type included_cls
, Cls.enum_type dest_cls
) with
1020 | (Some included_e
, Some dest_e
) ->
1021 (* ensure that the base types are identical *)
1022 if not
(Typing_defs.equal_decl_ty included_e
.te_base dest_e
.te_base
) then
1023 Errors.incompatible_enum_inclusion_base
1026 (Cls.name included_cls
);
1027 (* ensure that the visibility constraint are compatible *)
1028 (match (included_e
.te_constraint
, dest_e
.te_constraint
) with
1030 Errors.incompatible_enum_inclusion_constraint
1033 (Cls.name included_cls
)
1035 (* ensure normal enums can't include enum classes *)
1037 Ast_defs.is_c_enum_class
included_kind
1038 && not
(Ast_defs.is_c_enum_class
dest_kind)
1040 Errors.wrong_extend_kind
1041 ~
parent_pos:(Cls.pos included_cls
)
1042 ~parent_kind
:included_kind
1043 ~
parent_name:(Cls.name included_cls
)
1044 ~
child_pos:dest_cls_pos
1045 ~child_kind
:dest_kind
1046 ~
child_name:(Cls.name dest_cls
)
1048 Errors.enum_inclusion_not_enum
1051 (Cls.name included_cls
)
1054 let is_enum_or_enum_class k
= Ast_defs.is_c_enum k
|| Ast_defs.is_c_enum_class k
1056 let check_enum_includes env cls
=
1057 let is_abstract = function
1058 | CCAbstract has_default
-> not has_default
1059 | CCConcrete
-> false
1061 (* checks that there are no duplicated enum-constants when folded-decls are enabled *)
1062 if is_enum_or_enum_class cls
.c_kind
then (
1063 let (dest_class_pos
, dest_class_name
) = cls
.c_name
in
1064 let enum_constant_map = ref SMap.empty
in
1065 (* prepopulate the map with the constants declared in cls *)
1066 List.iter cls
.c_consts ~
f:(fun cc
->
1067 enum_constant_map :=
1070 (fst cc
.cc_id
, dest_class_name
)
1071 !enum_constant_map);
1072 (* for all included enums *)
1073 let included_enums =
1074 Aast.enum_includes_map cls
.c_enum ~
f:(fun ce
->
1075 List.filter_map ce
.e_includes ~
f:(fun ie
->
1077 | Happly
(sid
, _
) ->
1078 (match Env.get_class
env (snd sid
) with
1080 | Some ie_cls
-> Some
(fst ie
, ie_cls
))
1083 List.iter
included_enums ~
f:(fun (ie_pos
, ie_cls
) ->
1084 let src_class_name = Cls.name ie_cls
in
1085 (* 1. Check for consistency *)
1086 (match Env.get_class
env dest_class_name
with
1088 | Some cls
-> check_consistent_enum_inclusion ie_cls
(ie_pos
, cls
));
1089 (* 2. Check for duplicates *)
1090 List.iter
(Cls.consts ie_cls
) ~
f:(fun (const_name
, class_const
) ->
1091 (if String.equal const_name
"class" then
1093 (* TODO: Check with @fzn *)
1094 else if is_abstract class_const
.cc_abstract
then
1096 else if SMap.mem const_name
!enum_constant_map then
1097 (* distinguish between multiple inherit and redeclare *)
1098 let (origin_const_pos
, origin_class_name
) =
1099 SMap.find const_name
!enum_constant_map
1101 if String.equal origin_class_name dest_class_name
then
1103 Errors.redeclaring_classish_const
1109 else if String.( <> ) origin_class_name class_const
.cc_origin
then
1110 (* check for diamond inclusion, if not raise an error about multiple inherit *)
1111 Errors.reinheriting_classish_const
1118 enum_constant_map :=
1121 (dest_class_pos
, class_const
.cc_origin
)
1122 !enum_constant_map))
1125 let shallow_decl_enabled (ctx
: Provider_context.t
) : bool =
1126 TypecheckerOptions.shallow_class_decl
(Provider_context.get_tcopt ctx
)
1128 let skip_hierarchy_checks (ctx
: Provider_context.t
) : bool =
1129 TypecheckerOptions.skip_hierarchy_checks (Provider_context.get_tcopt ctx
)
1131 let class_type_param env ct
=
1132 let (env, tparam_list
) = List.map_env
env ct ~
f:Typing.type_param
in
1135 (** Checks that a dynamic element is also dynamic in the parents. *)
1136 let check_dynamic_class_element get_static_elt element_name dyn_pos ~elt_type
=
1137 (* The non-static properties that we get passed do not start with '$', but the
1138 static properties we want to look up do, so add it. *)
1141 | `Method
-> element_name
1142 | `Property
-> "$" ^ element_name
1144 match get_static_elt
id with
1146 | Some static_element
->
1147 let (lazy ty) = static_element
.ce_type
in
1148 Errors.static_redeclared_as_dynamic
1154 (** Checks that a static element is also static in the parents. *)
1155 let check_static_class_element get_dyn_elt element_name static_pos ~elt_type
=
1156 (* The static properties that we get passed in start with '$', but the
1157 non-static properties we're matching against don't, so we need to detect
1158 that and remove it if present. *)
1159 let element_name = String_utils.lstrip
element_name "$" in
1160 match get_dyn_elt
element_name with
1162 | Some dyn_element
->
1163 let (lazy ty) = dyn_element
.ce_type
in
1164 Errors.dynamic_redeclared_as_static
1170 (** Error if there are abstract methods that this class is supposed to provide
1171 implementation for. *)
1172 let check_extend_abstract_meth ~is_final
p seq
=
1173 List.iter seq ~
f:(fun (x
, ce
) ->
1174 match ce
.ce_type
with
1175 | (lazy ty) when get_ce_abstract ce
&& is_fun
ty ->
1176 Errors.implement_abstract ~is_final
p (get_pos
ty) "method" x
1179 let check_extend_abstract_prop ~is_final
p seq
=
1180 List.iter seq ~
f:(fun (x
, ce
) ->
1181 if get_ce_abstract ce
then
1182 let ce_pos = Lazy.force ce
.ce_type
|> get_pos
in
1183 Errors.implement_abstract ~is_final
p ce_pos "property" x
)
1185 (* Type constants must be bound to a concrete type for non-abstract classes.
1187 let check_extend_abstract_typeconst ~is_final
p seq
=
1188 List.iter seq ~
f:(fun (x
, tc
) ->
1189 match tc
.ttc_kind
with
1191 Errors.implement_abstract
1199 let check_extend_abstract_const ~is_final
p seq
=
1200 List.iter seq ~
f:(fun (x
, cc
) ->
1201 match cc
.cc_abstract
with
1202 | CCAbstract _
when not cc
.cc_synthesized
->
1203 let cc_pos = get_pos cc
.cc_type
in
1204 Errors.implement_abstract ~is_final
p cc_pos "constant" x
1207 (** Error if there are abstract members that this class is supposed to provide
1208 implementation for. *)
1209 let check_extend_abstract (pc
, tc
) =
1211 let open Ast_defs
in
1212 match Cls.kind tc
with
1221 let is_final = Cls.final tc
in
1222 if (is_concrete || is_final) && Cls.members_fully_known tc
then (
1223 let constructor_as_list cstr
=
1225 >>| (fun cstr
-> (SN.Members.__construct
, cstr
))
1228 check_extend_abstract_meth ~
is_final pc
(Cls.methods tc
);
1229 check_extend_abstract_meth
1232 (Cls.construct tc
|> constructor_as_list);
1233 check_extend_abstract_meth ~
is_final pc
(Cls.smethods tc
);
1234 check_extend_abstract_prop ~
is_final pc
(Cls.sprops tc
);
1235 check_extend_abstract_const ~
is_final pc
(Cls.consts tc
);
1236 check_extend_abstract_typeconst ~
is_final pc
(Cls.typeconsts tc
)
1239 exception Found
of Pos_or_decl.t
1241 let contains_generic : Typing_defs.decl_ty
-> Pos_or_decl.t
option =
1245 inherit [_
] Type_visitor.decl_type_visitor
as super
1247 method! on_type
env ty =
1248 match get_node
ty with
1249 | Tgeneric _
-> raise
(Found
(get_pos
ty))
1250 | _
-> super#on_type
env ty
1254 visitor#on_type
() ty;
1259 (** Check whether the type of a static property (class variable) contains
1260 any generic type parameters. Outside of traits, this is illegal as static
1261 * properties are shared across all generic instantiations. *)
1262 let check_no_generic_static_property env tc
=
1263 if Ast_defs.is_c_trait
(Cls.kind tc
) then
1267 |> List.iter ~
f:(fun (_prop_name
, prop
) ->
1268 let (lazy ty) = prop
.ce_type
in
1269 let var_type_pos = get_pos
ty in
1270 let class_pos = Cls.pos tc
in
1271 match contains_generic ty with
1273 | Some generic_pos
->
1275 (* If the static property is inherited from another trait, the position may be
1276 * in a different file. *)
1277 (Env.fill_in_pos_filename_if_in_current_decl
env generic_pos
)
1278 ~
f:(fun generic_pos
->
1279 Errors.static_property_type_generic_param
1284 let get_decl_prop_ty env cls ~is_static prop_id
=
1285 let is_global_inference_on = TCO.global_inference
(Env.get_tcopt
env) in
1286 if is_global_inference_on then
1289 (* this is very ad-hoc, but this is how we do it in the decl-heap *)
1290 Cls.get_sprop cls
("$" ^ prop_id
)
1292 Cls.get_prop cls prop_id
1295 | None
-> failwith
"error: could not find property in decl heap"
1296 | Some
{ ce_type
; _
} -> Some
(Lazy.force ce_type
)
1304 c_tconst_name
= (pos, _
) as id;
1306 c_tconst_user_attributes
;
1308 c_tconst_doc_comment
;
1311 if is_enum_or_enum_class cls
.c_kind
then
1312 Errors.cannot_declare_constant `enum
pos cls
.c_name
;
1314 let name = snd cls
.c_name ^
"::" ^ snd
id in
1315 (* Check constraints and report cycles through the definition *)
1317 match c_tconst_kind
with
1319 { c_atc_as_constraint
; c_atc_super_constraint
; c_atc_default
= Some
ty }
1322 Phase.localize_hint_no_subst
1323 ~ignore_errors
:false
1324 ~report_cycle
:(pos, name)
1329 match c_atc_as_constraint
with
1332 Phase.localize_hint_no_subst ~ignore_errors
:false env as_
1336 Reason.URtypeconst_cstr
1344 match c_atc_super_constraint
with
1347 Phase.localize_hint_no_subst ~ignore_errors
:false env super
1351 Reason.URtypeconst_cstr
1359 | TCPartiallyAbstract
{ c_patc_constraint
= cstr
; c_patc_type
= ty } ->
1361 Phase.localize_hint_no_subst ~ignore_errors
:false env cstr
1364 Phase.localize_hint_no_subst
1365 ~ignore_errors
:false
1366 ~report_cycle
:(pos, name)
1370 Type.sub_type
pos Reason.URtypeconst_cstr
env ty cstr
Errors.unify_error
1371 | TCConcrete
{ c_tc_type
= ty } ->
1373 Phase.localize_hint_no_subst
1374 ~ignore_errors
:false
1375 ~report_cycle
:(pos, name)
1383 (* TODO(T88552052): should this check be happening for defaults
1384 * Does this belong here at all? *)
1386 match c_tconst_kind
with
1387 | TCConcrete
{ c_tc_type
= (pos, Hshape
{ nsi_field_map
; _
}) }
1388 | TCPartiallyAbstract
1389 { c_patc_type
= (pos, Hshape
{ nsi_field_map
; _
}); _
}
1390 | TCAbstract
{ c_atc_default
= Some
(pos, Hshape
{ nsi_field_map
; _
}); _
}
1392 let get_name sfi
= sfi
.sfi_name
in
1393 Typing.check_shape_keys_validity
1396 (List.map ~
f:get_name nsi_field_map
)
1401 Typing.attributes_check_def
1403 SN.AttributeKinds.typeconst
1404 c_tconst_user_attributes
1406 let (env, user_attributes
) =
1407 List.map_env
env c_tconst_user_attributes ~
f:Typing.user_attribute
1411 Aast.c_tconst_name
= id;
1413 Aast.c_tconst_user_attributes
= user_attributes
;
1415 Aast.c_tconst_doc_comment
;
1416 Aast.c_tconst_is_ctx
;
1419 (* This should agree with the set of expressions whose type can be inferred in
1420 * Decl_utils.infer_const
1422 let is_literal_expr (_
, _
, e
) =
1431 | Unop
((Ast_defs.Uminus
| Ast_defs.Uplus
), (_
, _
, (Int _
| Float _
))) -> true
1434 let class_const_def ~in_enum_class c
env cc
=
1435 let { cc_type
= h
; cc_id
= id; cc_kind
= k
; _
} = cc
in
1436 let (env, hint_ty
, opt_expected
) =
1441 | CCAbstract None
-> ()
1442 | CCAbstract
(Some e
(* default *))
1445 (not
(is_literal_expr e
))
1446 && Partial.should_check_error c
.c_mode
2035
1447 && not
(is_enum_or_enum_class c
.c_kind
)
1449 Errors.missing_typehint
(fst
id)
1451 let (env, ty) = Env.fresh_type
env (fst
id) in
1452 (env, MakeType.unenforced
ty, None
)
1454 let ty = Decl_hint.hint
env.decl_env h
in
1455 let ty = Typing_enforceability.compute_enforced_ty
env ty in
1457 Phase.localize_possibly_enforced_no_subst
env ~ignore_errors
:false ty
1459 (* Removing the HH\MemberOf wrapper in case of enum classes so the
1460 * following call to expr_* has the right expected type
1463 if in_enum_class
then
1464 match get_node
ty.et_type
with
1465 | Tnewtype
(memberof
, [_
; et_type
], _
)
1466 when String.equal memberof
SN.Classes.cMemberOf
->
1474 Some
(ExpectedTy.make_and_allow_coercion
(fst
id) Reason.URhint
opt_ty)
1478 (* Lifted out to closure to illustrate which variables are captured *)
1479 Typing_coercion.coerce_type
1485 Errors.class_constant_value_does_not_match_hint
1487 let type_and_check env e
=
1488 let (env, (te
, ty'
)) =
1490 expr_with_pure_coeffects ?expected
:opt_expected
env e
|> triple_to_pair
)
1492 let env = check env ty'
in
1495 let (env, kind
, ty) =
1497 | CCConcrete
((_
, e_pos
, _
) as e
) when in_enum_class
->
1498 let (env, cap
, unsafe_cap
) =
1499 (* Enum class constant initializers are restricted to be `write_props` *)
1500 let make_hint pos s
= (pos, Aast.Happly
((pos, s
), [])) in
1501 let enum_class_ctx =
1502 Some
(e_pos
, [make_hint e_pos
SN.Capabilities.writeProperty
])
1504 Typing.type_capability
env enum_class_ctx enum_class_ctx e_pos
1506 let (env, (te
, ty'
)) =
1508 with_special_coeffects
env cap unsafe_cap
@@ fun env ->
1509 expr
env ?expected
:opt_expected e
|> triple_to_pair
)
1512 match deref hint_ty
.et_type
with
1513 | (r, Tnewtype
(memberof
, [enum_name
; _
], _
))
1514 when String.equal memberof
SN.Classes.cMemberOf
->
1515 let lift r ty = mk
(r, Tnewtype
(memberof
, [enum_name
; ty], ty)) in
1516 let (te_ty
, p, te
) = te
in
1517 let te = (lift (get_reason te_ty
) te_ty
, p, te) in
1518 let ty'
= lift r ty'
in
1522 let env = check env ty'
in
1523 (env, Aast.CCConcrete
te, ty'
)
1525 let (env, te, ty'
) = type_and_check env e
in
1526 (env, Aast.CCConcrete
te, ty'
)
1527 | CCAbstract
(Some default
) ->
1528 let (env, tdefault
, ty'
) = type_and_check env default
in
1529 (env, CCAbstract
(Some tdefault
), ty'
)
1530 | CCAbstract None
-> (env, CCAbstract None
, hint_ty
.et_type
)
1534 Aast.cc_type
= cc
.cc_type
;
1535 Aast.cc_id
= cc
.cc_id
;
1536 Aast.cc_kind
= kind
;
1537 Aast.cc_doc_comment
= cc
.cc_doc_comment
;
1541 let class_constr_def env cls constructor
=
1542 let env = { env with inside_constructor
= true } in
1543 Option.bind constructor ~
f:(method_def env cls
)
1545 (** Type-check a property declaration, with optional initializer *)
1546 let class_var_def ~is_static cls
env cv
=
1547 (* First pick up and localize the hint if it exists *)
1549 merge_hint_with_decl_hint
1551 (hint_of_type_hint cv
.cv_type
)
1552 (get_decl_prop_ty env cls ~is_static
(snd cv
.cv_id
))
1554 let (env, expected
) =
1556 | None
-> (env, None
)
1558 let decl_cty = Typing_enforceability.compute_enforced_ty
env decl_cty in
1560 Phase.localize_possibly_enforced_no_subst
1562 ~ignore_errors
:false
1566 Some
(ExpectedTy.make_and_allow_coercion cv
.cv_span
Reason.URhint cty
)
1570 (* Next check the expression, passing in expected type if present *)
1571 let (env, typed_cv_expr
) =
1572 match cv
.cv_expr
with
1573 | None
-> (env, None
)
1575 let (env, te, ty) = Typing.expr_with_pure_coeffects
env ?
expected e
in
1576 (* Check that the inferred type is a subtype of the expected type.
1577 * Eventually this will be the responsibility of `expr`
1582 | Some
ExpectedTy.{ pos = p; reason
= ur
; ty = cty
} ->
1583 Typing_coercion.coerce_type
1589 Errors.class_property_initializer_type_does_not_match_hint
1596 Typing.attributes_check_def
1598 SN.AttributeKinds.staticProperty
1599 cv
.cv_user_attributes
1601 Typing.attributes_check_def
1603 SN.AttributeKinds.instProperty
1604 cv
.cv_user_attributes
1606 let (env, user_attributes
) =
1607 List.map_env
env cv
.cv_user_attributes ~
f:Typing.user_attribute
1610 Option.is_none
(hint_of_type_hint cv
.cv_type
)
1611 && Partial.should_check_error
(Env.get_mode
env) 2001
1613 Errors.prop_without_typehint
1614 (string_of_visibility cv
.cv_visibility
)
1616 let (env, global_inference_env
) = Env.extract_global_inference_env
env in
1617 let ((cv_type_ty
, _
) as cv_type
) =
1620 (expected.ExpectedTy.ty.et_type
, hint_of_type_hint cv
.cv_type
)
1621 | None
-> Tast.dummy_type_hint
(hint_of_type_hint cv
.cv_type
)
1623 (* if the class implements dynamic, then check that the type of the property
1624 * is enforceable (for writing) and coerces to dynamic (for reading) *)
1626 TypecheckerOptions.enable_sound_dynamic
1627 (Provider_context.get_tcopt
(Env.get_ctx
env))
1628 && Cls.get_support_dynamic_type cls
1629 && not
(Aast.equal_visibility cv
.cv_visibility Private
)
1631 let env_with_require_dynamic =
1632 Typing_dynamic.add_require_dynamic_bounds
env cls
1634 Option.iter
decl_cty ~
f:(fun ty ->
1635 Typing_dynamic.check_property_sound_for_dynamic_write
1636 ~on_error
:Errors.property_is_not_enforceable
1637 env_with_require_dynamic
1641 Typing_dynamic.check_property_sound_for_dynamic_read
1642 ~on_error
:Errors.property_is_not_dynamic
1643 env_with_require_dynamic
1650 Aast.cv_final
= cv
.cv_final
;
1651 Aast.cv_xhp_attr
= cv
.cv_xhp_attr
;
1652 Aast.cv_abstract
= cv
.cv_abstract
;
1653 Aast.cv_visibility
= cv
.cv_visibility
;
1655 Aast.cv_id
= cv
.cv_id
;
1656 Aast.cv_expr
= typed_cv_expr
;
1657 Aast.cv_user_attributes
= user_attributes
;
1658 Aast.cv_is_promoted_variadic
= cv
.cv_is_promoted_variadic
;
1659 Aast.cv_doc_comment
= cv
.cv_doc_comment
;
1660 (* Can make None to save space *)
1661 Aast.cv_is_static
= is_static
;
1662 Aast.cv_span
= cv
.cv_span
;
1663 Aast.cv_readonly
= cv
.cv_readonly
;
1665 (cv
.cv_span
, global_inference_env
) ) )
1667 (** Check the where constraints of the parents of a class *)
1668 let check_class_parents_where_constraints env pc impl
=
1669 let check_where_constraints env ((p, _hint
), decl_ty
) =
1670 let (env, locl_ty
) =
1671 Phase.localize_no_subst
env ~ignore_errors
:false decl_ty
1673 match get_node
(TUtils.get_base_type
env locl_ty
) with
1674 | Tclass
(cls
, _
, tyl
) ->
1675 (match Env.get_class
env (snd cls
) with
1676 | Some cls
when not
(List.is_empty
(Cls.where_constraints cls
)) ->
1677 let tc_tparams = Cls.tparams cls
in
1680 (empty_expand_env_with_on_error
1681 (Env.unify_error_assert_primary_pos_in_current_decl
env))
1683 substs
= Subst.make_locl
tc_tparams tyl
;
1686 Phase.check_where_constraints
1689 ~definition_pos
:(Pos_or_decl.of_raw_pos
p)
1692 (Cls.where_constraints cls
)
1696 List.fold impl ~init
:env ~
f:check_where_constraints
1698 let check_generic_class_with_SupportDynamicType env c
parents =
1699 let (pc
, c_name
) = c
.c_name
in
1700 if c
.c_support_dynamic_type
then
1701 (* Any class that extends a class or implements an interface
1702 * that declares <<__SupportDynamicType>> must itself declare
1703 * <<__SupportDynamicType>>. This is checked elsewhere. But if any generic
1704 * parameters are not marked <<__NoRequireDynamic>> then we must check that the
1705 * conditional support for dynamic is sound.
1708 * and C<T1,..,Tn> extends t
1709 * then C<T1,...,Tn> <: dynamic
1712 MakeType.dynamic
(Reason.Rdynamic_coercion
(Reason.Rwitness pc
))
1715 List.fold
parents ~init
:env ~
f:(fun env (_
, ty) ->
1716 let (env, lty
) = Phase.localize_no_subst
env ~ignore_errors
:true ty in
1717 match get_node lty
with
1718 | Tclass
((_
, name), _
, _
) ->
1720 match Env.get_class
env name with
1721 | Some c
when Cls.get_support_dynamic_type c
->
1722 let env_with_assumptions =
1723 Typing_subtype.add_constraint
1725 Ast_defs.Constraint_as
1728 (Errors.unify_error_at pc
)
1731 match Env.get_self_ty
env with
1734 ~coerce
:(Some
Typing_logic.CoerceToDynamic
)
1735 env_with_assumptions
1738 (fun ?code
:_ ?quickfixes
:_ reasons
->
1740 Typing_print.full_strip_ns_decl
env ty
1741 ^
" is subtype of dynamic implies "
1742 ^
Typing_print.full_strip_ns
env self_ty
1743 ^
" is subtype of dynamic"
1745 Errors.bad_conditional_support_dynamic
1761 let check_SupportDynamicType env c
=
1763 TypecheckerOptions.enable_sound_dynamic
1764 (Provider_context.get_tcopt
(Env.get_ctx
env))
1768 (c
.c_extends
@ c
.c_uses
@ c
.c_implements
)
1770 | (_
, Happly
((_
, name), _
)) -> Some
name
1773 let error_parent_support_dynamic_type parent
f =
1774 Errors.parent_support_dynamic_type
1776 (snd c
.c_name
, c
.c_kind
)
1777 (Cls.name parent
, Cls.kind parent
)
1780 List.iter
parent_names ~
f:(fun name ->
1781 match Env.get_class_dep
env name with
1782 | Some parent_type
->
1784 match Cls.kind parent_type
with
1786 | Ast_defs.Cinterface
->
1787 (* ensure that we implement dynamic if we are a subclass/subinterface of a class/interface
1788 * that implements dynamic. Upward well-formedness checks are performed in Typing_extends *)
1790 Cls.get_support_dynamic_type parent_type
1791 && not c
.c_support_dynamic_type
1793 error_parent_support_dynamic_type
1795 c
.c_support_dynamic_type
1796 | Ast_defs.(Cenum
| Cenum_class _
| Ctrait
) -> ()
1800 let class_def_ env c tc
=
1803 if Ast_defs.is_c_enum c
.c_kind
then
1804 SN.AttributeKinds.enum
1805 else if Ast_defs.is_c_enum_class c
.c_kind
then
1806 SN.AttributeKinds.enumcls
1808 SN.AttributeKinds.cls
1810 Typing.attributes_check_def
env kind c
.c_user_attributes
1812 let (env, file_attrs
) = Typing.file_attributes
env c
.c_file_attributes
in
1813 let ctx = Env.get_ctx
env in
1814 if (not
Ast_defs.(is_c_trait c
.c_kind
)) && not
(shallow_decl_enabled ctx) then (
1815 (* These checks are only for eager mode. The same checks are performed
1816 * for shallow mode in Typing_inheritance *)
1817 let method_pos ~is_static class_id meth_id
=
1820 Decl_store.((get
()).get_static_method
)
1822 Decl_store.((get
()).get_method
)
1824 match get_meth (class_id
, meth_id
) with
1825 | Some
{ fe_pos
; _
} -> fe_pos
1826 | None
-> Pos_or_decl.none
1828 let check_override ~is_static
(id, ce
) =
1829 if get_ce_override ce
then
1830 let pos = method_pos ~is_static ce
.ce_origin
id in
1831 (* Method is actually defined in this class *)
1832 if String.equal ce
.ce_origin
(snd c
.c_name
) then
1833 Errors.should_be_override
1837 ~current_decl_and_file
:(Env.get_current_decl_and_file
env)
1839 match Env.get_class
env ce
.ce_origin
with
1841 | Some parent_class
->
1842 (* If it's not defined here, then either it's inherited (so we have emitted an error already)
1843 * or it's in a trait, and so we need to emit the error now *)
1844 if not
Ast_defs.(is_c_trait
(Cls.kind parent_class
)) then
1847 Errors.override_per_trait c
.c_name
id ce
.ce_origin
pos
1850 List.iter
(Cls.methods tc
) ~
f:(check_override ~is_static
:false);
1851 List.iter
(Cls.smethods tc
) ~
f:(check_override ~is_static
:true)
1853 check_enum_includes env c
;
1854 let (pc
, c_name
) = c
.c_name
in
1855 let (req_extends
, req_implements
) = split_reqs c
.c_reqs
in
1856 let hints_and_decl_tys hints
=
1857 List.map hints ~
f:(fun hint
-> (hint
, Decl_hint.hint
env.decl_env hint
))
1859 let extends = hints_and_decl_tys c
.c_extends
in
1860 let implements = hints_and_decl_tys c
.c_implements
in
1861 let uses = hints_and_decl_tys c
.c_uses
in
1862 let req_extends = hints_and_decl_tys req_extends in
1863 let req_implements = hints_and_decl_tys req_implements in
1864 let additional_parents =
1865 (* In an abstract class or a trait, we assume the interfaces
1866 will be implemented in the future, so we take them as
1867 part of the class (as requested by dependency injection implementers) *)
1869 | Ast_defs.Cclass k
when Ast_defs.is_abstract k
-> implements
1870 | Ast_defs.Ctrait
-> implements @ req_implements
1871 | Ast_defs.(Cclass _
| Cinterface
| Cenum
| Cenum_class _
) -> []
1873 let check_constructor_dep = check_constructor_dep env in
1874 check_implements_or_extends_unique implements;
1875 check_implements_or_extends_unique extends;
1876 check_constructor_dep extends;
1877 check_constructor_dep uses;
1878 check_constructor_dep req_extends;
1879 check_constructor_dep additional_parents;
1882 | Some e
-> check_constructor_dep (hints_and_decl_tys e
.e_includes
)
1886 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
1888 ~ignore_errors
:false
1890 c
.c_where_constraints
1893 Phase.check_where_constraints
1896 ~definition_pos
:(Pos_or_decl.of_raw_pos pc
)
1898 (empty_expand_env_with_on_error
1899 (Env.unify_error_assert_primary_pos_in_current_decl
env))
1901 (Cls.where_constraints tc
)
1903 Typing_variance.class_def
env c
;
1904 check_no_generic_static_property env tc
;
1905 let impl = extends @ implements @ uses in
1908 TypecheckerOptions.require_extends_implements_ancestors
1911 impl @ req_extends @ req_implements
1915 let env = check_class_parents_where_constraints env pc
impl in
1916 check_parent env c tc
;
1917 check_parents_sealed env c tc
;
1918 if TypecheckerOptions.enforce_sealed_subclasses
(Env.get_tcopt
env) then
1919 if is_enum_or_enum_class c
.c_kind
then
1920 if TypecheckerOptions.enable_enum_supertyping
(Env.get_tcopt
env) then
1921 sealed_subtype ctx c ~is_enum
:true
1925 sealed_subtype ctx c ~is_enum
:false;
1927 check_generic_class_with_SupportDynamicType env c
(extends @ implements)
1929 check_extend_abstract (pc
, tc
);
1930 if Cls.const tc
then
1931 List.iter c
.c_uses ~
f:(check_non_const_trait_members pc
env);
1932 let (static_vars
, vars
) = split_vars c
.c_vars
in
1933 List.iter static_vars ~
f:(fun { cv_id
= (p, id); _
} ->
1934 check_static_class_element (Cls.get_prop tc
) ~elt_type
:`Property
id p);
1935 List.iter vars ~
f:(fun { cv_id
= (p, id); _
} ->
1936 check_dynamic_class_element (Cls.get_sprop tc
) ~elt_type
:`Property
id p);
1937 let (constructor
, static_methods
, methods
) = split_methods c
.c_methods
in
1938 List.iter static_methods ~
f:(fun { m_name
= (p, id); _
} ->
1939 check_static_class_element (Cls.get_method tc
) ~elt_type
:`Method
id p);
1940 List.iter methods ~
f:(fun { m_name
= (p, id); _
} ->
1941 check_dynamic_class_element (Cls.get_smethod tc
) ~elt_type
:`Method
id p);
1943 if skip_hierarchy_checks ctx then
1946 Typing_extends.check_implements_extends_uses
1948 ~
implements:(List.map
implements ~
f:snd
)
1949 ~
parents:(List.map
impl ~
f:snd
)
1952 if Cls.is_disposable tc
then
1954 (c
.c_extends
@ c
.c_uses
)
1955 ~
f:(Typing_disposable.enforce_is_disposable
env);
1956 let (env, typed_vars_and_global_inference_envs
) =
1957 List.map_env
env vars ~
f:(class_var_def ~is_static
:false tc
)
1959 let (typed_vars
, vars_global_inference_envs
) =
1960 List.unzip typed_vars_and_global_inference_envs
1962 let (typed_methods
, methods_global_inference_envs
) =
1963 List.filter_map methods ~
f:(method_def env tc
) |> List.unzip
1965 let (env, typed_typeconsts
) =
1966 List.map_env
env c
.c_typeconsts ~
f:(typeconst_def c
)
1968 let in_enum_class = Env.is_enum_class
env c_name
in
1970 List.map_env
env c
.c_consts ~
f:(class_const_def ~
in_enum_class c
)
1972 let (typed_consts
, const_types
) = List.unzip consts
in
1973 let env = Typing_enum.enum_class_check
env tc c
.c_consts const_types
in
1974 let typed_constructor = class_constr_def env tc constructor
in
1975 let env = Env.set_static
env in
1976 let (env, typed_static_vars_and_global_inference_envs
) =
1977 List.map_env
env static_vars ~
f:(class_var_def ~is_static
:true tc
)
1979 let (typed_static_vars
, static_vars_global_inference_envs
) =
1980 List.unzip typed_static_vars_and_global_inference_envs
1982 let (typed_static_methods
, static_methods_global_inference_envs
) =
1983 List.filter_map static_methods ~
f:(method_def env tc
) |> List.unzip
1985 let (methods
, constr_global_inference_env
) =
1986 match typed_constructor with
1987 | None
-> (typed_static_methods
@ typed_methods
, [])
1988 | Some
(m, global_inference_env
) ->
1989 (m :: typed_static_methods
@ typed_methods
, [global_inference_env
])
1991 let (env, tparams
) = class_type_param env c
.c_tparams
in
1992 let (env, user_attributes
) =
1993 List.map_env
env c
.c_user_attributes ~
f:Typing.user_attribute
1995 let env = Typing_solver.solve_all_unsolved_tyvars
env in
1996 check_SupportDynamicType env c
;
1999 Aast.c_span
= c
.c_span
;
2000 Aast.c_annotation
= Env.save
(Env.get_tpenv
env) env;
2001 Aast.c_mode
= c
.c_mode
;
2002 Aast.c_final
= c
.c_final
;
2003 Aast.c_is_xhp
= c
.c_is_xhp
;
2004 Aast.c_has_xhp_keyword
= c
.c_has_xhp_keyword
;
2005 Aast.c_kind
= c
.c_kind
;
2006 Aast.c_name
= c
.c_name
;
2007 Aast.c_tparams
= tparams
;
2008 Aast.c_extends
= c
.c_extends
;
2009 Aast.c_uses
= c
.c_uses
;
2010 (* c_use_as_alias and c_insteadof_alias are PHP features not supported
2011 * in Hack but are required since we have runtime support for it
2013 Aast.c_use_as_alias
= [];
2014 Aast.c_insteadof_alias
= [];
2015 Aast.c_xhp_attr_uses
= c
.c_xhp_attr_uses
;
2016 Aast.c_xhp_category
= c
.c_xhp_category
;
2017 Aast.c_reqs
= c
.c_reqs
;
2018 Aast.c_implements
= c
.c_implements
;
2019 Aast.c_support_dynamic_type
= c
.c_support_dynamic_type
;
2020 Aast.c_where_constraints
= c
.c_where_constraints
;
2021 Aast.c_consts
= typed_consts
;
2022 Aast.c_typeconsts
= typed_typeconsts
;
2023 Aast.c_vars
= typed_static_vars
@ typed_vars
;
2024 Aast.c_methods
= methods
;
2025 Aast.c_file_attributes
= file_attrs
;
2026 Aast.c_user_attributes
= user_attributes
;
2027 Aast.c_namespace
= c
.c_namespace
;
2028 Aast.c_enum
= c
.c_enum
;
2029 Aast.c_doc_comment
= c
.c_doc_comment
;
2030 Aast.c_attributes
= [];
2031 Aast.c_xhp_children
= c
.c_xhp_children
;
2032 Aast.c_xhp_attrs
= [];
2033 Aast.c_emit_id
= c
.c_emit_id
;
2035 methods_global_inference_envs
2036 @ static_methods_global_inference_envs
2037 @ constr_global_inference_env
2038 @ static_vars_global_inference_envs
2039 @ vars_global_inference_envs
)
2041 let class_def ctx c
=
2042 Counters.count
Counters.Category.Typecheck
@@ fun () ->
2043 Errors.run_with_span c
.c_span
@@ fun () ->
2044 let env = EnvFromDef.class_env ~origin
:Decl_counters.TopLevel
ctx c
in
2045 let (name_pos
, name) = c
.c_name
in
2046 let tc = Env.get_class
env name in
2047 let env = Env.set_env_pessimize
env in
2048 Typing_helpers.add_decl_errors
(Option.bind
tc ~
f:Cls.decl_errors
);
2052 (Naming_attributes_params.get_module_attribute c
.c_user_attributes
)
2057 (Naming_attributes.mem
SN.UserAttributes.uaInternal c
.c_user_attributes
)
2059 Typing_type_wellformedness.class_
env c
;
2060 NastInitCheck.class_
env c
;
2063 (* This can happen if there was an error during the declaration
2067 (* If there are duplicate definitions of the class then we will end up
2068 * checking one AST with respect to the decl corresponding to the other definition.
2069 * Naming has already detected duplicates, so let's just avoid cascading unhelpful
2070 * typing errors, and also avoid triggering the bad position assert
2072 if not
(Pos.equal name_pos
(Cls.pos tc |> Pos_or_decl.unsafe_to_raw_pos
))
2077 if skip_hierarchy_checks ctx then
2080 let env = Typing_requirements.check_class
env name_pos
tc in
2081 if shallow_decl_enabled ctx then
2082 Typing_inheritance.check_class
env name_pos
tc;
2085 Some
(class_def_ env c
tc)
2087 let gconst_def ctx cst
=
2088 Counters.count
Counters.Category.Typecheck
@@ fun () ->
2089 Errors.run_with_span cst
.cst_span
@@ fun () ->
2090 let env = EnvFromDef.gconst_env ~origin
:Decl_counters.TopLevel
ctx cst
in
2091 let env = Env.set_env_pessimize
env in
2092 Typing_type_wellformedness.global_constant
env cst
;
2093 let (typed_cst_value
, env) =
2094 let value = cst
.cst_value
in
2095 match cst
.cst_type
with
2097 let ty = Decl_hint.hint
env.decl_env hint
in
2098 let ty = Typing_enforceability.compute_enforced_ty
env ty in
2100 Phase.localize_possibly_enforced_no_subst
env ~ignore_errors
:false ty
2102 let (env, te, value_type
) =
2104 ExpectedTy.make_and_allow_coercion
(fst hint
) Reason.URhint dty
2106 Typing.expr_with_pure_coeffects
env ~
expected value
2109 Typing_coercion.coerce_type
2120 (not
(is_literal_expr value))
2121 && Partial.should_check_error cst
.cst_mode
2035
2123 Errors.missing_typehint
(fst cst
.cst_name
);
2124 let (env, te, _value_type
) = Typing.expr_with_pure_coeffects
env value in
2128 Aast.cst_annotation
= Env.save
(Env.get_tpenv
env) env;
2129 Aast.cst_mode
= cst
.cst_mode
;
2130 Aast.cst_name
= cst
.cst_name
;
2131 Aast.cst_type
= cst
.cst_type
;
2132 Aast.cst_value
= typed_cst_value
;
2133 Aast.cst_namespace
= cst
.cst_namespace
;
2134 Aast.cst_span
= cst
.cst_span
;
2135 Aast.cst_emit_id
= cst
.cst_emit_id
;
2138 let record_field env f =
2139 let (id, hint
, e
) = f in
2140 let (p, _
) = hint
in
2141 let (env, cty
) = Phase.localize_hint_no_subst
env ~ignore_errors
:false hint
in
2142 let expected = ExpectedTy.make
p Reason.URhint cty
in
2145 let (env, te, ty) = Typing.expr_with_pure_coeffects
env ~
expected e
in
2147 Typing_coercion.coerce_type
2152 (MakeType.unenforced cty
)
2153 Errors.record_init_value_does_not_match_hint
2155 (env, (id, hint
, Some
te))
2156 | None
-> (env, (id, hint
, None
))
2158 let record_def_parent env rd parent_hint
=
2159 match snd parent_hint
with
2160 | Aast.Happly
((parent_pos, parent_name), []) ->
2161 (match Decl_provider.get_record_def
(Env.get_ctx
env) parent_name with
2163 (* We can only inherit from abstract records. *)
2164 (if not parent_rd
.rdt_abstract
then
2165 let (parent_pos, parent_name) = parent_rd
.rdt_name
in
2166 Errors.extend_non_abstract_record
2171 (* Ensure we aren't defining fields that overlap with
2172 inherited fields. *)
2173 let inherited_fields = Typing_helpers.all_record_fields
env parent_rd
in
2174 List.iter rd
.rd_fields ~
f:(fun ((pos, name), _
, _
) ->
2175 match SMap.find_opt
name inherited_fields with
2176 | Some
((prev_pos
, _
), _
) ->
2177 Errors.repeated_record_field
name pos prev_pos
2180 (* Something exists with this name (naming succeeded), but it's
2182 Errors.unbound_name
parent_pos parent_name Errors.RecordContext
)
2185 "Record parent was not an Happly. This should have been a syntax error."
2187 (* Report an error if we have inheritance cycles in record declarations. *)
2188 let check_record_inheritance_cycle env ((rd_pos
, rd_name
) : Aast.sid
) : unit =
2189 let rec worker name trace seen
=
2190 match Decl_provider.get_record_def
(Env.get_ctx
env) name with
2192 (match rd
.rdt_extends
with
2193 | Some
(_
, parent_name) when String.equal
parent_name rd_name
->
2194 (* This record is in an inheritance cycle.*)
2195 Errors.cyclic_record_def trace rd_pos
2196 | Some
(_
, parent_name) when SSet.mem
parent_name seen
->
2197 (* There's an inheritance cycle higher in the chain. *)
2199 | Some
(_
, parent_name) ->
2200 worker parent_name (parent_name :: trace
) (SSet.add
parent_name seen
)
2204 worker rd_name
[rd_name
] (SSet.singleton rd_name
)
2206 let record_def_def ctx rd
=
2207 Counters.count
Counters.Category.Typecheck
@@ fun () ->
2208 let env = EnvFromDef.record_def_env ~origin
:Decl_counters.TopLevel
ctx rd
in
2209 Typing_type_wellformedness.record_def
env rd
;
2210 (match rd
.rd_extends
with
2211 | Some parent
-> record_def_parent env rd parent
2214 check_record_inheritance_cycle env rd
.rd_name
;
2216 let (env, attributes
) =
2217 List.map_env
env rd
.rd_user_attributes ~
f:Typing.user_attribute
2219 let (_env, fields
) = List.map_env
env rd
.rd_fields ~
f:record_field in
2221 Aast.rd_annotation
= Env.save
(Env.get_tpenv
env) env;
2222 Aast.rd_name
= rd
.rd_name
;
2223 Aast.rd_extends
= rd
.rd_extends
;
2224 Aast.rd_abstract
= rd
.rd_abstract
;
2225 Aast.rd_fields
= fields
;
2226 Aast.rd_user_attributes
= attributes
;
2227 Aast.rd_namespace
= rd
.rd_namespace
;
2228 Aast.rd_span
= rd
.rd_span
;
2229 Aast.rd_doc_comment
= rd
.rd_doc_comment
;
2230 Aast.rd_emit_id
= rd
.rd_emit_id
;
2233 let nast_to_tast_gienv ~
(do_tast_checks
: bool) ctx nast
:
2234 _
* Typing_inference_env.t_global_with_pos list
=
2235 let convert_def = function
2236 (* Sometimes typing will just return `None` but that should only be the case
2237 * if an error had already been registered e.g. in naming
2241 match fun_def ctx f with
2242 | Some
(f, env) -> Some
(Aast.Fun
f, [env])
2245 | Constant gc
-> Some
(Aast.Constant
(gconst_def ctx gc
), [])
2246 | Typedef td
-> Some
(Aast.Typedef
(Typing.typedef_def
ctx td
), [])
2249 match class_def ctx c
with
2250 | Some
(c
, envs
) -> Some
(Aast.Class c
, envs
)
2253 | RecordDef rd
-> Some
(Aast.RecordDef
(record_def_def ctx rd
), [])
2254 (* We don't typecheck top level statements:
2255 * https://docs.hhvm.com/hack/unsupported/top-level
2256 * so just create the minimal env for us to construct a Stmt.
2259 let env = Env.empty
ctx Relative_path.default ~droot
:None
in
2260 Some
(Aast.Stmt
(snd
(Typing.stmt
env s
)), [])
2264 | FileAttributes _
->
2266 "Invalid nodes in NAST. These nodes should be removed during naming."
2268 Nast_check.program
ctx nast
;
2269 let (tast
, envs
) = List.unzip
@@ List.filter_map nast ~
f:convert_def in
2270 let envs = List.concat
envs in
2271 if do_tast_checks
then Tast_check.program
ctx tast
;
2274 let nast_to_tast ~do_tast_checks
ctx nast
=
2275 let (tast
, _gienvs
) = nast_to_tast_gienv ~do_tast_checks
ctx nast
in