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
22 module FunUtils
= Decl_fun_utils
23 module Reason
= Typing_reason
24 module Env
= Typing_env
25 module EnvFromDef
= Typing_env_from_def
26 module MakeType
= Typing_make_type
28 let param_has_at_most_rx_as_func p
=
29 let module UA
= SN.UserAttributes
in
30 Naming_attributes.mem
UA.uaAtMostRxAsFunc p
.param_user_attributes
32 let fun_reactivity env attrs params
=
33 let r = FunUtils.fun_reactivity env attrs
in
34 let module UA
= Naming_special_names.UserAttributes
in
36 (* if at least one of parameters has <<__AtMostRxAsFunc>> attribute -
37 treat function reactivity as generic that is determined from the reactivity
38 of arguments annotated with __AtMostRxAsFunc. Declared reactivity is used as a
39 upper boundary of the reactivity function can have. *)
40 if List.exists params ~f
:param_has_at_most_rx_as_func then
46 (* if at least one of arguments have <<__OnlyRxIfImpl>> attribute -
47 treat function reactivity as conditional that is determined at the callsite *)
49 List.exists params ~f
:(fun { param_user_attributes
= p
; _
} ->
50 Naming_attributes.mem
UA.uaOnlyRxIfImpl p
)
58 (* The two following functions enable us to retrieve the function (or class)
59 header from the shared mem. Note that they only return a non None value if
60 global inference is on *)
61 let get_decl_function_header env function_id
=
62 let is_global_inference_on = TCO.global_inference
(Env.get_tcopt env
) in
63 if is_global_inference_on then
64 match Decl_provider.get_fun
(Env.get_ctx env
) function_id
with
65 | Some
{ fe_type
; _
} ->
67 match get_node fe_type
with
68 | Tfun fun_type
-> Some fun_type
75 and get_decl_method_header tcopt cls method_id ~is_static
=
76 let is_global_inference_on = TCO.global_inference tcopt
in
77 if is_global_inference_on then
78 match Cls.get_any_method ~is_static cls method_id
with
79 | Some
{ ce_type
= (lazy ty
); _
} ->
81 match get_node ty
with
82 | Tfun fun_type
-> Some fun_type
89 let enforce_param_not_disposable env param ty
=
90 if has_accept_disposable_attribute param
then
93 let p = param
.param_pos
in
94 match Typing_disposable.is_disposable_type env ty
with
95 | Some class_name
-> Errors.invalid_disposable_hint
p (strip_ns class_name
)
98 (* In strict mode, we force you to give a type declaration on a parameter *)
99 (* But the type checker is nice: it makes a suggestion :-) *)
100 let check_param_has_hint env param ty is_code_error
=
102 if is_code_error
4231 then
103 Typing.attributes_check_def
105 SN.AttributeKinds.parameter
106 param
.param_user_attributes
110 match hint_of_type_hint param
.param_type_hint
with
111 | None
when param
.param_is_variadic
&& is_code_error
4033 ->
112 Errors.expecting_type_hint_variadic param
.param_pos
113 | None
when is_code_error
4032 -> Errors.expecting_type_hint param
.param_pos
114 | Some _
when is_code_error
4010 ->
115 (* We do not permit hints to implement IDisposable or IAsyncDisposable *)
116 enforce_param_not_disposable env param ty
119 (* This function is used to determine the type of an argument.
120 * When we want to type-check the body of a function, we need to
121 * introduce the type of the arguments of the function in the environment
122 * Let's take an example, we want to check the code of foo:
124 * function foo(int $x): int {
125 * // CALL TO make_param_type on (int $x)
126 * // Now we know that the type of $x is int
128 * return $x; // in the environment $x is an int, the code is correct
131 * When we localize, we want to resolve to "static" or "$this" depending on
132 * the context. Even though we are passing in CIstatic, resolve_with_class_id
133 * is smart enough to know what to do. Why do this? Consider the following
136 * abstract const type T;
138 * private this::T $val;
140 * final public function __construct(this::T $x) {
144 * public static function create(this::T $x): this {
145 * return new static($x);
149 * class D extends C { const type T = int; }
151 * In __construct() we want to be able to assign $x to $this->val. The type of
152 * $this->val will expand to '$this::T', so we need $x to also be '$this::T'.
153 * We can do this soundly because when we construct a new class such as,
154 * 'new D(0)' we can determine the late static bound type (D) and resolve
155 * 'this::T' to 'D::T' which is int.
157 * A similar line of reasoning is applied for the static method create.
159 let make_param_local_ty env decl_hint param
=
160 let ety_env = Phase.env_with_self
env in
161 let r = Reason.Rwitness param
.param_pos
in
164 | None
-> (env, mk
(r, TUtils.tany
env))
166 let { et_type
= ty
; _
} =
167 Typing_enforceability.compute_enforced_and_pessimize_ty
168 ~explicitly_untrusted
:param
.param_is_variadic
173 FunUtils.condition_type_from_attributes
175 param
.param_user_attributes
178 match condition_type with
179 | Some
condition_type ->
180 let (env, ty
) = Phase.localize ~
ety_env env ty
in
183 TR.try_substitute_type_with_condition
env condition_type ty
189 when Naming_attributes.mem
190 SN.UserAttributes.uaAtMostRxAsFunc
191 param
.param_user_attributes
->
192 let (env, ty
) = Phase.localize ~
ety_env env ty
in
193 (* expand type to track aliased function types *)
194 let (env, expanded_ty
) = Env.expand_type
env ty
in
195 let adjusted_ty = make_function_type_rxvar expanded_ty
in
197 if phys_equal
adjusted_ty expanded_ty
then
201 | _
-> Phase.localize ~
ety_env env ty
205 match get_node
ty with
206 | t
when param
.param_is_variadic
->
207 (* when checking the body of a function with a variadic
208 * argument, "f(C ...$args)", $args is a varray<C> *)
209 let r = Reason.Rvar_param param
.param_pos
in
210 let arr_values = mk
(r, t
) in
211 mk
(r, Tvarray
arr_values)
214 Typing_reactivity.disallow_atmost_rx_as_rxfunc_on_non_functions
env param
ty;
217 let get_callable_variadicity
218 ?
(is_function
= false) ~partial_callback ~pos
env variadicity_decl_ty
=
220 | FVvariadicArg vparam
->
221 let (env, ty) = make_param_local_ty env variadicity_decl_ty vparam
in
222 check_param_has_hint env vparam
ty partial_callback
;
223 let (env, t_variadic
) = Typing.bind_param
env (ty, vparam
) in
224 (env, Aast.FVvariadicArg t_variadic
)
226 if is_function
&& Partial.should_check_error
(Env.get_mode
env) 4223 then
227 Errors.ellipsis_strict_mode ~require
:`Type_and_param_name pos
;
228 (env, Aast.FVellipsis
p)
229 | FVnonVariadic
-> (env, Aast.FVnonVariadic
)
231 let merge_hint_with_decl_hint env type_hint decl_ty
=
232 let contains_tvar decl_ty
=
235 | Some decl_ty
-> TUtils.contains_tvar_decl decl_ty
237 if contains_tvar decl_ty
then
240 Option.map type_hint ~f
:(Decl_hint.hint
env.decl_env
)
242 (* During the decl phase we can, for global inference, add "improved type hints".
243 That is we can say that some missing type hints are in fact global tyvars.
244 In that case to get the real type hint we must merge the type hint present
245 in the ast with the one we created during the decl phase. This function does
246 exactly this for the return type, the parameters and the variadic parameters.
248 let merge_decl_header_with_hints ~params ~ret ~variadic decl_header
env =
250 merge_hint_with_decl_hint
252 (hint_of_type_hint ret
)
254 ~f
:(fun { ft_ret
= { et_type
; _
}; _
} -> et_type
)
258 match decl_header
with
262 merge_hint_with_decl_hint
264 (hint_of_type_hint h
.param_type_hint
)
267 | Some
{ ft_params
; _
} ->
268 List.zip_exn params ft_params
269 |> List.map ~f
:(fun (h
, { fp_type
= { et_type
; _
}; _
}) ->
270 merge_hint_with_decl_hint
272 (hint_of_type_hint h
.param_type_hint
)
275 let variadicity_decl_ty =
276 match (decl_header
, variadic
) with
277 | ( Some
{ ft_arity
= Fvariadic
{ fp_type
= { et_type
; _
}; _
}; _
},
278 FVvariadicArg fp
) ->
279 merge_hint_with_decl_hint
281 (hint_of_type_hint fp
.param_type_hint
)
283 | (_
, FVvariadicArg fp
) ->
284 merge_hint_with_decl_hint env (hint_of_type_hint fp
.param_type_hint
) None
287 (ret_decl_ty, params_decl_ty, variadicity_decl_ty)
289 (* Checking this with List.exists will be a single op in the vast majority of cases (empty) *)
290 let get_ctx_vars ctxs
=
293 List.filter_map cs ~f
:(function
294 | (_
, Haccess
((_
, Hvar n
), _
)) -> Some n
300 (Tast.fun_def * Typing_inference_env.t_global_with_pos
) option =
301 Counters.count
Counters.Category.Typecheck
@@ fun () ->
302 Errors.run_with_span f
.f_span
@@ fun () ->
303 let env = EnvFromDef.fun_env ~origin
:Decl_counters.TopLevel ctx f
in
304 with_timeout
env f
.f_name ~do_
:(fun env ->
305 (* reset the expression dependent display ids for each function body *)
306 Reason.expr_display_id_map
:= IMap.empty
;
307 let pos = fst f
.f_name
in
308 let decl_header = get_decl_function_header env (snd f
.f_name
) in
309 let env = Env.open_tyvars
env (fst f
.f_name
) in
310 let env = Env.set_env_function_pos
env pos in
311 let env = Env.set_env_pessimize
env in
313 Typing.attributes_check_def
env SN.AttributeKinds.fn f
.f_user_attributes
315 let (env, file_attrs
) = Typing.file_attributes
env f
.f_file_attributes
in
316 let (env, cap_ty
, unsafe_cap_ty
) =
317 Typing.type_capability
env f
.f_ctxs f
.f_unsafe_ctxs
(fst f
.f_name
)
320 Typing_coeffects.register_capabilities
env cap_ty unsafe_cap_ty
323 fun_reactivity env.decl_env f
.f_user_attributes f
.f_params
325 let mut = TUtils.fun_mutable f
.f_user_attributes
in
326 let env = Env.set_env_reactive
env reactive in
327 let env = Env.set_fun_mutable
env mut in
328 Typing_check_decls.fun_
env f
;
330 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
334 f
.f_where_constraints
336 let env = Env.set_fn_kind
env f
.f_fun_kind
in
337 let (return_decl_ty
, params_decl_ty, variadicity_decl_ty) =
338 merge_decl_header_with_hints
341 ~variadic
:f
.f_variadic
345 let (env, return_ty
) =
346 match return_decl_ty
with
348 (env, Typing_return.make_default_return ~is_method
:false env f
.f_name
)
350 let localize env ty = Phase.localize_with_self
env ty in
351 Typing_return.make_return_type
localize env ty
354 Typing_return.make_info
358 ~is_explicit
:(Option.is_some
(hint_of_type_hint f
.f_ret
))
362 let (env, param_tys
) =
363 List.zip_exn f
.f_params
params_decl_ty
364 |> List.map_env
env ~f
:(fun env (param
, hint
) ->
365 make_param_local_ty env hint param
)
367 let partial_callback = Partial.should_check_error
(Env.get_mode
env) in
368 let check_has_hint p t
= check_param_has_hint env p t
partial_callback in
369 List.iter2_exn ~f
:check_has_hint f
.f_params param_tys
;
370 Typing_memoize.check_function
env f
;
371 let params_need_immutable = get_ctx_vars f
.f_ctxs
in
372 let (env, typed_params
) =
373 let bind_param_and_check env param
=
374 let name = (snd param
).param_name
in
376 List.exists ~f
:(String.equal
name) params_need_immutable
378 let (env, fun_param
) = Typing.bind_param ~
immutable env param
in
383 (List.zip_exn param_tys f
.f_params
)
386 let (env, t_variadic
) =
387 get_callable_variadicity
396 set_tyvars_variance_in_callable
env return_ty param_tys t_variadic
398 let local_tpenv = Env.get_tpenv
env in
400 Naming_attributes.mem
401 SN.UserAttributes.uaDisableTypecheckerInternal
405 Typing.fun_ ~
disable env return pos f
.f_body f
.f_fun_kind
407 (* restore original reactivity *)
408 let env = Env.set_env_reactive
env reactive in
410 match hint_of_type_hint f
.f_ret
with
412 if partial_callback 4030 then Errors.expecting_return_type_hint
pos
415 let (env, tparams
) = List.map_env
env f
.f_tparams
Typing.type_param
in
416 let (env, user_attributes
) =
417 List.map_env
env f
.f_user_attributes
Typing.user_attribute
420 Typing_solver.close_tyvars_and_solve
env Errors.bad_function_typevar
423 Typing_solver.solve_all_unsolved_tyvars
env Errors.bad_function_typevar
427 Aast.f_annotation
= Env.save
local_tpenv env;
428 Aast.f_span
= f
.f_span
;
429 Aast.f_mode
= f
.f_mode
;
430 Aast.f_readonly_ret
= f
.f_readonly_ret
;
431 Aast.f_ret
= (return_ty
, hint_of_type_hint f
.f_ret
);
432 Aast.f_name
= f
.f_name
;
433 Aast.f_tparams
= tparams
;
434 Aast.f_where_constraints
= f
.f_where_constraints
;
435 Aast.f_variadic
= t_variadic
;
436 Aast.f_params
= typed_params
;
437 Aast.f_ctxs
= f
.f_ctxs
;
438 Aast.f_unsafe_ctxs
= f
.f_unsafe_ctxs
;
439 Aast.f_fun_kind
= f
.f_fun_kind
;
440 Aast.f_file_attributes
= file_attrs
;
441 Aast.f_user_attributes
= user_attributes
;
442 Aast.f_body
= { Aast.fb_ast
= tb
; fb_annotation
= () };
443 Aast.f_external
= f
.f_external
;
444 Aast.f_namespace
= f
.f_namespace
;
445 Aast.f_doc_comment
= f
.f_doc_comment
;
446 Aast.f_static
= f
.f_static
;
449 let (_env
, global_inference_env
) = Env.extract_global_inference_env
env in
450 (fundef, (pos, global_inference_env
)))
452 let method_def env cls m
=
453 Errors.run_with_span m
.m_span
@@ fun () ->
454 with_timeout
env m
.m_name ~do_
:(fun env ->
455 FunUtils.check_params m
.m_params
;
456 let initial_env = env in
457 (* reset the expression dependent display ids for each method body *)
458 Reason.expr_display_id_map
:= IMap.empty
;
460 get_decl_method_header
464 ~is_static
:m
.m_static
466 let pos = fst m
.m_name
in
467 let env = Env.open_tyvars
env (fst m
.m_name
) in
468 let env = Env.reinitialize_locals
env in
469 let env = Env.set_env_function_pos
env pos in
471 Typing.attributes_check_def
473 SN.AttributeKinds.mthd
477 fun_reactivity env.decl_env m
.m_user_attributes m
.m_params
480 match TUtils.fun_mutable m
.m_user_attributes
with
482 (* <<__Mutable>> is implicit on constructors *)
483 if String.equal
(snd m
.m_name
) SN.Members.__construct
then
484 Some Param_borrowed_mutable
489 let (env, cap_ty
, unsafe_cap_ty
) =
490 Typing.type_capability
env m
.m_ctxs m
.m_unsafe_ctxs
(fst m
.m_name
)
493 Typing_coeffects.register_capabilities
env cap_ty unsafe_cap_ty
495 let env = Env.set_env_reactive
env reactive in
496 let env = Env.set_fun_mutable
env mut in
498 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
502 m
.m_where_constraints
505 if Env.is_static
env then
508 Env.set_local
env this
(Env.get_self
env) Pos.none
511 match Env.get_self_class
env with
514 (* Mark $this as a using variable if it has a disposable type *)
515 if Cls.is_disposable c
then
516 Env.set_using_var
env this
520 let env = Env.clear_params
env in
521 let (ret_decl_ty, params_decl_ty, variadicity_decl_ty) =
522 merge_decl_header_with_hints
525 ~variadic
:m
.m_variadic
529 let env = Env.set_fn_kind
env m
.m_fun_kind
in
531 match ret_decl_ty with
533 (env, Typing_return.make_default_return ~is_method
:true env m
.m_name
)
535 (* If a 'this' type appears it needs to be compatible with the
538 let ety_env = Phase.env_with_self
env in
539 Typing_return.make_return_type
(Phase.localize ~
ety_env) env ret
542 Typing_return.make_info
546 ~is_explicit
:(Option.is_some
(hint_of_type_hint m
.m_ret
))
550 let (env, param_tys
) =
551 List.zip_exn m
.m_params
params_decl_ty
552 |> List.map_env
env ~f
:(fun env (param
, hint
) ->
553 make_param_local_ty env hint param
)
555 let partial_callback = Partial.should_check_error
(Env.get_mode
env) in
556 let param_fn p t
= check_param_has_hint env p t
partial_callback in
557 List.iter2_exn ~f
:param_fn m
.m_params param_tys
;
558 Typing_memoize.check_method
env m
;
559 let params_need_immutable = get_ctx_vars m
.m_ctxs
in
560 let (env, typed_params
) =
561 let bind_param_and_check env param
=
562 let name = (snd param
).param_name
in
564 List.exists ~f
:(String.equal
name) params_need_immutable
566 let (env, fun_param
) = Typing.bind_param ~
immutable env param
in
571 (List.zip_exn param_tys m
.m_params
)
574 let (env, t_variadic
) =
575 get_callable_variadicity
583 set_tyvars_variance_in_callable
env locl_ty param_tys t_variadic
585 let nb = Nast.assert_named_body m
.m_body
in
586 let local_tpenv = Env.get_tpenv
env in
588 Naming_attributes.mem
589 SN.UserAttributes.uaDisableTypecheckerInternal
594 ~abstract
:m
.m_abstract
602 (* restore original method reactivity *)
603 let env = Env.set_env_reactive
env reactive in
605 match hint_of_type_hint m
.m_ret
with
606 | None
when String.equal
(snd m
.m_name
) SN.Members.__construct
->
607 Some
(pos, Hprim Tvoid
)
609 if partial_callback 4030 then Errors.expecting_return_type_hint
pos;
611 | Some _
-> hint_of_type_hint m
.m_ret
613 let m = { m with m_ret
= (fst
m.m_ret
, type_hint'
) } in
614 let (env, tparams
) = List.map_env
env m.m_tparams
Typing.type_param
in
615 let (env, user_attributes
) =
616 List.map_env
env m.m_user_attributes
Typing.user_attribute
619 Typing_solver.close_tyvars_and_solve
env Errors.bad_method_typevar
622 Typing_solver.solve_all_unsolved_tyvars
env Errors.bad_method_typevar
624 (* if the class implements dynamic, then check that its methods are dynamically callable *)
626 TypecheckerOptions.enable_sound_dynamic
627 (Provider_context.get_tcopt
(Env.get_ctx
env))
628 && Cls.get_implements_dynamic cls
630 (* 1. check if all the parameters of the method are enforceable *)
631 List.iter
params_decl_ty ~f
:(fun dtyopt
->
634 let te_check = Typing_enforceability.is_enforceable
env dty
in
636 Errors.method_is_not_dynamically_callable
641 (* 2. check if the return type is coercible *)
644 (Typing_subtype.is_sub_type_for_union
645 ~coerce
:(Some
Typing_logic.CoerceToDynamic
)
648 (mk
(Reason.Rnone
, Tdynamic
)))
650 Errors.method_is_not_dynamically_callable
657 Aast.m_annotation
= Env.save
local_tpenv env;
658 Aast.m_span
= m.m_span
;
659 Aast.m_final
= m.m_final
;
660 Aast.m_static
= m.m_static
;
661 Aast.m_abstract
= m.m_abstract
;
662 Aast.m_visibility
= m.m_visibility
;
663 Aast.m_readonly_this
= m.m_readonly_this
;
664 Aast.m_name
= m.m_name
;
665 Aast.m_tparams
= tparams
;
666 Aast.m_where_constraints
= m.m_where_constraints
;
667 Aast.m_variadic
= t_variadic
;
668 Aast.m_params
= typed_params
;
669 Aast.m_ctxs
= m.m_ctxs
;
670 Aast.m_unsafe_ctxs
= m.m_unsafe_ctxs
;
671 Aast.m_fun_kind
= m.m_fun_kind
;
672 Aast.m_user_attributes
= user_attributes
;
673 Aast.m_readonly_ret
= m.m_readonly_ret
;
674 Aast.m_ret
= (locl_ty
, hint_of_type_hint
m.m_ret
);
675 Aast.m_body
= { Aast.fb_ast
= tb
; fb_annotation
= () };
676 Aast.m_external
= m.m_external
;
677 Aast.m_doc_comment
= m.m_doc_comment
;
680 let (env, global_inference_env
) = Env.extract_global_inference_env
env in
681 let _env = Env.log_env_change
"method_def" initial_env env in
682 (method_def, (pos, global_inference_env
)))
684 (** Checks that extending this parent is legal - e.g. it is not final and not const. *)
685 let check_parent env class_def class_type
=
686 match Env.get_parent_class
env with
687 | Some parent_type
->
688 let position = fst class_def
.c_name
in
689 if Cls.const class_type
&& not
(Cls.const parent_type
) then
690 Errors.self_const_parent_not
position;
691 if Cls.final parent_type
then
692 Errors.extend_final
position (Cls.pos parent_type
) (Cls.name parent_type
)
695 let check_parent_sealed ~
(is_enum_class
: bool) child_type parent_type
=
696 match Cls.sealed_whitelist parent_type
with
699 let parent_pos = Cls.pos parent_type
in
700 let parent_name = Cls.name parent_type
in
701 let child_pos = Cls.pos child_type
in
702 let child_name = Cls.name child_type
in
703 let check kind action
=
704 if not
(SSet.mem
child_name whitelist
) then
705 Errors.extend_sealed
child_pos parent_pos parent_name kind action
708 match (Cls.kind parent_type
, Cls.kind child_type
) with
709 | (Ast_defs.Cinterface
, Ast_defs.Cinterface
) -> check "interface" "extend"
710 | (Ast_defs.Cinterface
, _
) -> check "interface" "implement"
711 | (Ast_defs.Ctrait
, _
) -> check "trait" "use"
712 | (Ast_defs.Cabstract
, _
)
713 | (Ast_defs.Cnormal
, _
) ->
714 check "class" "extend"
715 | (Ast_defs.Cenum
, _
) when is_enum_class
-> check "enum class" "extend"
716 | (Ast_defs.Cenum
, _
) -> check "enum" "use"
719 let check_parents_sealed env child_def child_type
=
721 match child_def
.c_enum
with
722 | Some enum
-> enum
.e_includes
723 | None
-> child_def
.c_extends
725 let parents = parents @ child_def
.c_implements
@ child_def
.c_uses
in
726 let is_enum_class = Aast.is_enum_class child_def
in
727 List.iter
parents (function
728 | (_
, Happly
((_
, name), _
)) ->
730 match Env.get_class_dep
env name with
731 | Some parent_type
->
732 check_parent_sealed ~
is_enum_class child_type parent_type
737 (* Reject multiple instantiations of the same generic interface
738 * in extends and implements clauses.
739 * e.g. disallow class C implements I<string>, I<int>
741 * O(n^2) but we don't expect number of instantiated interfaces to be large
743 let rec check_implements_or_extends_unique impl
=
747 (match get_node
ty with
748 | Tapply
((pos, name), _
:: _
) ->
749 let (pos_list
, rest
) =
750 List.partition_map rest
(fun ty ->
751 match get_node
ty with
752 | Tapply
((pos'
, name'
), _
) when String.equal
name name'
->
756 if not
(List.is_empty pos_list
) then
757 Errors.duplicate_interface
pos name pos_list
;
758 check_implements_or_extends_unique rest
759 | _
-> check_implements_or_extends_unique rest
)
761 let check_cstr_dep env deps
=
762 List.iter deps
(fun dep
->
764 | (_
, Tapply
((_
, class_name
), _
)) ->
765 Env.make_depend_on_constructor
env class_name
767 let p = Typing_reason.to_pos
r in
768 Errors.expected_class ~suffix
:" or interface but got a generic" p
770 let p = Typing_reason.to_pos
r in
771 Errors.expected_class ~suffix
:" or interface" p)
773 let check_const_trait_members pos env use_list
=
774 let (_
, trait
, _
) = Decl_utils.unwrap_class_hint use_list
in
775 match Env.get_class
env trait
with
776 | Some c
when Ast_defs.(equal_class_kind
(Cls.kind c
) Ctrait
) ->
777 List.iter
(Cls.props c
) (fun (x
, ce
) ->
778 if not
(get_ce_const ce
) then Errors.trait_prop_const_class
pos x
)
781 let check_consistent_enum_inclusion included_cls
(dest_cls
: Cls.t
) =
782 match (Cls.enum_type included_cls
, Cls.enum_type dest_cls
) with
783 | (Some included_e
, Some dest_e
) ->
784 (* Temporary workaround until D26410129 reaches HHVM *)
785 let pos_included = Cls.pos included_cls
in
786 let pos_dest = Cls.pos dest_cls
in
788 Relative_path.equal
(Pos.filename
pos_dest) (Pos.filename
pos_included)
789 && Pos.line
pos_dest < Pos.line
pos_included
791 Errors.enum_inclusion_unsupported_ordering
794 (Cls.name included_cls
);
795 (* ensure that the base types are identical *)
796 if not
(Typing_defs.equal_decl_ty included_e
.te_base dest_e
.te_base
) then
797 Errors.incompatible_enum_inclusion_base
800 (Cls.name included_cls
);
801 (* ensure that the visibility constraint are compatible *)
802 (match (included_e
.te_constraint
, dest_e
.te_constraint
) with
804 Errors.incompatible_enum_inclusion_constraint
807 (Cls.name included_cls
)
809 (* ensure normal enums can't include enum classes *)
810 if included_e
.te_enum_class
&& not dest_e
.te_enum_class
then
811 Errors.wrong_extend_kind
812 ~
parent_pos:(Cls.pos included_cls
)
813 ~parent_kind
:Ast_defs.Cenum
814 ~
parent_name:(Cls.name included_cls
)
815 ~parent_is_enum_class
:true
816 ~
child_pos:(Cls.pos dest_cls
)
817 ~child_kind
:Ast_defs.Cenum
818 ~
child_name:(Cls.name dest_cls
)
819 ~child_is_enum_class
:false
821 Errors.enum_inclusion_not_enum
824 (Cls.name included_cls
)
827 let check_enum_includes env cls
=
828 (* checks that there are no duplicated enum-constants when folded-decls are enabled *)
829 if Ast_defs.is_c_enum cls
.c_kind
then (
830 let (dest_class_pos
, dest_class_name
) = cls
.c_name
in
831 let enum_constant_map = ref SMap.empty
in
832 (* prepopulate the map with the constants declared in cls *)
833 List.iter cls
.c_consts ~f
:(fun cc
->
837 (fst cc
.cc_id
, dest_class_name
)
839 (* for all included enums *)
841 Aast.enum_includes_map cls
.c_enum ~f
:(fun ce
->
842 List.filter_map ce
.e_includes ~f
:(fun ie
->
845 (match Env.get_class
env (snd sid
) with
847 | Some ie_cls
-> Some
(fst ie
, ie_cls
))
850 List.iter
included_enums ~f
:(fun (ie_pos
, ie_cls
) ->
851 let src_class_name = Cls.name ie_cls
in
852 (* 1. Check for consistency *)
853 (match Env.get_class
env dest_class_name
with
855 | Some cls
-> check_consistent_enum_inclusion ie_cls cls
);
856 (* 2. Check for duplicates *)
857 List.iter
(Cls.consts ie_cls
) ~f
:(fun (const_name
, class_const
) ->
858 ( if String.equal const_name
"class" then
860 else if SMap.mem const_name
!enum_constant_map then
861 (* distinguish between multiple inherit and redeclare *)
862 let (origin_const_pos
, origin_class_name
) =
863 SMap.find const_name
!enum_constant_map
865 if String.equal origin_class_name dest_class_name
then
867 Errors.redeclaring_classish_const
874 (* multiple inherit *)
875 Errors.reinheriting_classish_const
885 (dest_class_pos
, class_const
.cc_origin
)
889 let shallow_decl_enabled (ctx
: Provider_context.t
) : bool =
890 TypecheckerOptions.shallow_class_decl
(Provider_context.get_tcopt ctx
)
892 let class_type_param env ct
=
893 let (env, tparam_list
) = List.map_env
env ct
Typing.type_param
in
896 (* This function sets a temporary coeffect context to check constants
897 * with the right one (either pure / write_props).
898 * We need to carefully restore the locals, otherwise the next continuation
899 * is just reset and the call to register_capabilities is a no-op, no
900 * capability is registered.
902 let expr_with_special_coeffects env ?expected e cap_ty unsafe_cap_ty
=
904 Option.map
(Env.next_cont_opt
env) ~f
:(fun next_cont
->
905 let initial_locals = next_cont
.Typing_per_cont_env.local_types
in
906 let tpenv = Env.get_tpenv
env in
907 (initial_locals, tpenv))
909 let (env, (te
, ty)) =
910 Typing_lenv.stash_and_do
env (Env.all_continuations
env) (fun env ->
914 | Some
(initial_locals, tpenv) ->
915 let env = Env.reinitialize_locals
env in
916 let env = Env.set_locals
env initial_locals in
917 let env = Env.env_with_tpenv
env tpenv in
921 Typing_coeffects.register_capabilities
env cap_ty unsafe_cap_ty
923 let (env, te
, ty) = Typing.expr ?expected
env e
in
928 (* Some (legacy) special functions are allowed as class constant init.,
929 therefore treat them as pure and insert the matching capabilities. *)
930 let expr_with_pure_coeffects env ?expected e
=
931 let pure = MakeType.mixed
(Reason.Rwitness
(fst e
)) in
932 expr_with_special_coeffects env ?expected e
pure pure
934 (* Enum class constant initializers are restricted to be `write_props` *)
935 let expr_with_write_props_coeffects env ?expected e
=
937 let make_hint pos s
= (pos, Aast.Happly
((pos, s
), [])) in
939 Some
(e_pos, [make_hint e_pos SN.Capabilities.writeProperty
])
941 let (env, cap_ty
, unsafe_cap_ty
) =
942 Typing.type_capability
env enum_class_ctx enum_class_ctx e_pos
944 expr_with_special_coeffects env ?expected e cap_ty unsafe_cap_ty
946 (** Checks that a dynamic element is also dynamic in the parents. *)
947 let check_dynamic_class_element get_static_elt element_name dyn_pos ~elt_type
=
948 (* The non-static properties that we get passed do not start with '$', but the
949 static properties we want to look up do, so add it. *)
952 | `Method
-> element_name
953 | `Property
-> "$" ^ element_name
955 match get_static_elt
id with
957 | Some static_element
->
958 let (lazy ty) = static_element
.ce_type
in
959 Errors.static_redeclared_as_dynamic
965 (** Checks that a static element is also static in the parents. *)
966 let check_static_class_element get_dyn_elt element_name static_pos ~elt_type
=
967 (* The static properties that we get passed in start with '$', but the
968 non-static properties we're matching against don't, so we need to detect
969 that and remove it if present. *)
970 let element_name = String_utils.lstrip
element_name "$" in
971 match get_dyn_elt
element_name with
973 | Some dyn_element
->
974 let (lazy ty) = dyn_element
.ce_type
in
975 Errors.dynamic_redeclared_as_static
981 (** Error if there are abstract methods that this class is supposed to provide
982 implementation for. *)
983 let check_extend_abstract_meth ~is_final
p seq
=
984 List.iter seq
(fun (x
, ce
) ->
985 match ce
.ce_type
with
986 | (lazy ty) when get_ce_abstract ce
&& is_fun
ty ->
987 Errors.implement_abstract ~is_final
p (get_pos
ty) "method" x
990 let check_extend_abstract_prop ~is_final
p seq
=
991 List.iter seq
(fun (x
, ce
) ->
992 if get_ce_abstract ce
then
993 let ce_pos = Lazy.force ce
.ce_type
|> get_pos
in
994 Errors.implement_abstract ~is_final
p ce_pos "property" x
)
996 (* Type constants must be bound to a concrete type for non-abstract classes.
998 let check_extend_abstract_typeconst ~is_final
p seq
=
999 List.iter seq
(fun (x
, tc
) ->
1000 if Option.is_none tc
.ttc_type
then
1001 Errors.implement_abstract
1008 let check_extend_abstract_const ~is_final
p seq
=
1009 List.iter seq
(fun (x
, cc
) ->
1010 if cc
.cc_abstract
&& not cc
.cc_synthesized
then
1011 let cc_pos = get_pos cc
.cc_type
in
1012 Errors.implement_abstract ~is_final
p cc_pos "constant" x
)
1014 exception Found
of Pos.t
1016 let contains_generic : Typing_defs.decl_ty
-> Pos.t
option =
1020 inherit [_
] Type_visitor.decl_type_visitor
as super
1022 method! on_type
env ty =
1023 match get_node
ty with
1024 | Tgeneric _
-> raise
(Found
(get_pos
ty))
1025 | _
-> super#on_type
env ty
1029 visitor#on_type
() ty;
1031 with Found
p -> Some
p
1033 let check_no_generic_static_property tc
=
1035 (* Check whether the type of a static property (class variable) contains
1036 * any generic type parameters. Outside of traits, this is illegal as static
1037 * properties are shared across all generic instantiations.
1038 * Although not strictly speaking a variance check, it fits here because
1039 * it concerns the presence of generic type parameters in types.
1041 Ast_defs.(equal_class_kind
(Cls.kind tc
) Ctrait
)
1046 |> List.iter ~f
:(fun (_prop_name
, prop
) ->
1047 let (lazy ty) = prop
.ce_type
in
1048 let var_type_pos = get_pos
ty in
1049 let class_pos = Cls.pos tc
in
1050 match contains_generic ty with
1052 | Some generic_pos
->
1053 Errors.static_property_type_generic_param
1058 let get_decl_prop_ty env cls ~is_static prop_id
=
1059 let is_global_inference_on = TCO.global_inference
(Env.get_tcopt
env) in
1060 if is_global_inference_on then
1063 (* this is very ad-hoc, but this is how we do it in the decl-heap *)
1064 Cls.get_sprop cls
("$" ^ prop_id
)
1066 Cls.get_prop cls prop_id
1069 | None
-> failwith
"error: could not find property in decl heap"
1070 | Some
{ ce_type
; _
} -> Some
(Lazy.force ce_type
)
1079 c_tconst_name
= (pos, _
) as id;
1080 c_tconst_as_constraint
;
1081 c_tconst_type
= hint
;
1082 c_tconst_user_attributes
;
1084 c_tconst_doc_comment
;
1087 if Ast_defs.is_c_enum cls
.c_kind
then
1088 Errors.cannot_declare_constant `enum
pos cls
.c_name
;
1090 opt
Phase.localize_hint_with_self
env c_tconst_as_constraint
1094 | None
-> (env, None
)
1096 let ty = Decl_hint.hint
env.decl_env hint
in
1097 (* We want to report cycles through the definition *)
1098 let name = snd cls
.c_name ^
"::" ^ snd
id in
1100 Phase.localize_with_self
env ~
pos ~report_cycle
:(pos, name) ty
1105 Type.sub_type
pos Reason.URtypeconst_cstr
env t c
Errors.unify_error
1107 let env = Option.value ~default
:env @@ Option.map2
ty cstr ~f
:(check env) in
1110 | Some
(pos, Hshape
{ nsi_field_map
; _
}) ->
1111 let get_name sfi
= sfi
.sfi_name
in
1112 Typing.check_shape_keys_validity
1115 (List.map ~f
:get_name nsi_field_map
)
1119 Typing.attributes_check_def
1121 SN.AttributeKinds.typeconst
1122 c_tconst_user_attributes
1124 let (env, user_attributes
) =
1125 List.map_env
env c_tconst_user_attributes
Typing.user_attribute
1129 Aast.c_tconst_abstract
;
1130 Aast.c_tconst_name
= id;
1131 Aast.c_tconst_as_constraint
;
1132 Aast.c_tconst_type
= hint
;
1133 Aast.c_tconst_user_attributes
= user_attributes
;
1135 Aast.c_tconst_doc_comment
;
1136 Aast.c_tconst_is_ctx
;
1139 (* This should agree with the set of expressions whose type can be inferred in
1140 * Decl_utils.infer_const
1142 let is_literal_expr e
=
1151 | Unop
((Ast_defs.Uminus
| Ast_defs.Uplus
), (_
, (Int _
| Float _
))) -> true
1154 let class_const_def ~in_enum_class c
env cc
=
1155 let { cc_type
= h
; cc_id
= id; cc_expr
= e
; _
} = cc
in
1156 let (env, ty, opt_expected
) =
1164 (not
(is_literal_expr e
))
1165 && Partial.should_check_error c
.c_mode
2035
1166 && not
Ast_defs.(equal_class_kind c
.c_kind Cenum
)
1168 Errors.missing_typehint
(fst
id)
1170 let (env, ty) = Env.fresh_type
env (fst
id) in
1171 (env, MakeType.unenforced
ty, None
)
1173 let ty = Decl_hint.hint
env.decl_env h
in
1174 let ty = Typing_enforceability.compute_enforced_ty
env ty in
1175 let (env, ty) = Phase.localize_possibly_enforced_with_self
env ty in
1176 (* Removing the HH\MemberOf wrapper in case of enum classes so the
1177 * following call to expr_* has the right expected type
1180 if in_enum_class
then
1181 match get_node
ty.et_type
with
1182 | Tnewtype
(memberof
, [_
; et_type
], _
)
1183 when String.equal memberof
SN.Classes.cMemberOf
->
1191 Some
(ExpectedTy.make_and_allow_coercion
(fst
id) Reason.URhint
opt_ty)
1194 let (env, eopt
, ty) =
1197 let (env, te
, ty'
) =
1198 if in_enum_class
then
1199 expr_with_write_props_coeffects env ?expected
:opt_expected e
1201 expr_with_pure_coeffects env ?expected
:opt_expected e
1203 (* If we are checking an enum class, wrap ty' into the right
1204 * HH\MemberOf<class name, ty'> alias
1207 if in_enum_class
then
1208 match deref
ty.et_type
with
1209 | (r, Tnewtype
(memberof
, [enum_name
; _
], _
))
1210 when String.equal memberof
SN.Classes.cMemberOf
->
1211 let lift r ty = mk
(r, Tnewtype
(memberof
, [enum_name
; ty], ty)) in
1212 let ((p, te_ty
), te
) = te
in
1213 let te = ((p, lift (get_reason te_ty
) te_ty
), te) in
1214 let ty'
= lift r ty'
in
1221 Typing_coercion.coerce_type
1227 Errors.class_constant_value_does_not_match_hint
1230 | None
-> (env, None
, ty.et_type
)
1234 Aast.cc_type
= cc
.cc_type
;
1235 Aast.cc_id
= cc
.cc_id
;
1236 Aast.cc_expr
= eopt
;
1237 Aast.cc_doc_comment
= cc
.cc_doc_comment
;
1241 let class_constr_def env cls constructor
=
1242 let env = { env with inside_constructor
= true } in
1243 Option.bind constructor
(method_def env cls
)
1245 let class_implements_type env c1 ctype2
=
1247 List.map c1
.c_tparams
(fun { tp_name
= (p, s
); _
} ->
1248 mk
(Reason.Rwitness
p, Tgeneric
(s
, [])))
1250 let r = Reason.Rwitness
(fst c1
.c_name
) in
1251 let ctype1 = mk
(r, Tapply
(c1
.c_name
, params)) in
1252 Typing_extends.check_implements
env ctype2
ctype1
1254 (** Type-check a property declaration, with optional initializer *)
1255 let class_var_def ~is_static cls
env cv
=
1256 (* First pick up and localize the hint if it exists *)
1258 merge_hint_with_decl_hint
1260 (hint_of_type_hint cv
.cv_type
)
1261 (get_decl_prop_ty env cls ~is_static
(snd cv
.cv_id
))
1263 let (env, expected
) =
1265 | None
-> (env, None
)
1267 let decl_cty = Typing_enforceability.compute_enforced_ty
env decl_cty in
1269 Phase.localize_possibly_enforced_with_self
env decl_cty
1272 Some
(ExpectedTy.make_and_allow_coercion cv
.cv_span
Reason.URhint cty
)
1276 (* Next check the expression, passing in expected type if present *)
1277 let (env, typed_cv_expr
) =
1278 match cv
.cv_expr
with
1279 | None
-> (env, None
)
1281 let (env, te, ty) = expr_with_pure_coeffects env ?
expected e
in
1282 (* Check that the inferred type is a subtype of the expected type.
1283 * Eventually this will be the responsibility of `expr`
1288 | Some
ExpectedTy.{ pos = p; reason
= ur
; ty = cty
} ->
1289 Typing_coercion.coerce_type
1295 Errors.class_property_initializer_type_does_not_match_hint
1302 Typing.attributes_check_def
1304 SN.AttributeKinds.staticProperty
1305 cv
.cv_user_attributes
1307 Typing.attributes_check_def
1309 SN.AttributeKinds.instProperty
1310 cv
.cv_user_attributes
1312 let (env, user_attributes
) =
1313 List.map_env
env cv
.cv_user_attributes
Typing.user_attribute
1316 Option.is_none
(hint_of_type_hint cv
.cv_type
)
1317 && Partial.should_check_error
(Env.get_mode
env) 2001
1319 Errors.prop_without_typehint
1320 (string_of_visibility cv
.cv_visibility
)
1322 let (env, global_inference_env
) = Env.extract_global_inference_env
env in
1326 (expected.ExpectedTy.ty.et_type
, hint_of_type_hint cv
.cv_type)
1327 | None
-> Tast.dummy_type_hint
(hint_of_type_hint cv
.cv_type)
1331 Aast.cv_final
= cv
.cv_final
;
1332 Aast.cv_xhp_attr
= cv
.cv_xhp_attr
;
1333 Aast.cv_abstract
= cv
.cv_abstract
;
1334 Aast.cv_visibility
= cv
.cv_visibility
;
1336 Aast.cv_id
= cv
.cv_id
;
1337 Aast.cv_expr
= typed_cv_expr
;
1338 Aast.cv_user_attributes
= user_attributes
;
1339 Aast.cv_is_promoted_variadic
= cv
.cv_is_promoted_variadic
;
1340 Aast.cv_doc_comment
= cv
.cv_doc_comment
;
1341 (* Can make None to save space *)
1342 Aast.cv_is_static
= is_static
;
1343 Aast.cv_span
= cv
.cv_span
;
1344 Aast.cv_readonly
= cv
.cv_readonly
;
1346 (cv
.cv_span
, global_inference_env
) ) )
1348 let class_def_ env c tc
=
1353 (match c
.c_enum
with
1354 | Some enum
when enum
.e_enum_class
-> SN.AttributeKinds.enumcls
1355 | _
-> SN.AttributeKinds.enum
)
1356 | _
-> SN.AttributeKinds.cls
1358 Typing.attributes_check_def
env kind c
.c_user_attributes
1360 let (env, file_attrs
) = Typing.file_attributes
env c
.c_file_attributes
in
1361 let ctx = Env.get_ctx
env in
1363 ( Ast_defs.(equal_class_kind c
.c_kind Cnormal
)
1364 || Ast_defs.(equal_class_kind c
.c_kind Cabstract
) )
1365 && not
(shallow_decl_enabled ctx)
1367 (* These checks are only for eager mode. The same checks are performed
1368 * for shallow mode in Typing_inheritance *)
1369 let method_pos ~is_static class_id meth_id
=
1372 Decl_heap.StaticMethods.get
1374 Decl_heap.Methods.get
1376 match get_meth (class_id
, meth_id
) with
1377 | Some
{ fe_pos
; _
} -> fe_pos
1380 let check_override ~is_static
(id, ce
) =
1381 if get_ce_override ce
then
1382 let pos = method_pos ~is_static ce
.ce_origin
id in
1383 (* Method is actually defined in this class *)
1384 if String.equal ce
.ce_origin
(snd c
.c_name
) then
1385 Errors.should_be_override
pos (snd c
.c_name
) id
1387 match Env.get_class
env ce
.ce_origin
with
1389 | Some parent_class
->
1390 (* If it's not defined here, then either it's inherited (so we have emitted an error already)
1391 * or it's in a trait, and so we need to emit the error now *)
1392 if not
Ast_defs.(equal_class_kind
(Cls.kind parent_class
) Ctrait
)
1396 Errors.override_per_trait c
.c_name
id ce
.ce_origin
pos
1399 List.iter
(Cls.methods tc
) (check_override ~is_static
:false);
1400 List.iter
(Cls.smethods tc
) (check_override ~is_static
:true)
1402 check_enum_includes env c
;
1403 let (pc
, c_name
) = c
.c_name
in
1404 let (req_extends
, req_implements
) = split_reqs c
in
1405 let extends = List.map c
.c_extends
(Decl_hint.hint
env.decl_env
) in
1406 let implements = List.map c
.c_implements
(Decl_hint.hint
env.decl_env
) in
1407 let uses = List.map c
.c_uses
(Decl_hint.hint
env.decl_env
) in
1408 let req_extends = List.map
req_extends (Decl_hint.hint
env.decl_env
) in
1409 let req_implements = List.map
req_implements (Decl_hint.hint
env.decl_env
) in
1410 let additional_parents =
1411 (* In an abstract class or a trait, we assume the interfaces
1412 will be implemented in the future, so we take them as
1413 part of the class (as requested by dependency injection implementers) *)
1415 | Ast_defs.Cabstract
-> implements
1416 | Ast_defs.Ctrait
-> implements @ req_implements
1419 let check_cstr_dep = check_cstr_dep env in
1420 check_implements_or_extends_unique implements;
1421 check_implements_or_extends_unique extends;
1422 check_cstr_dep extends;
1423 check_cstr_dep uses;
1424 check_cstr_dep req_extends;
1425 check_cstr_dep additional_parents;
1429 check_cstr_dep (List.map e
.e_includes
(Decl_hint.hint
env.decl_env
))
1432 let impl = extends @ implements @ uses in
1434 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
1438 c
.c_where_constraints
1441 Phase.check_where_constraints
1445 ~
ety_env:(Phase.env_with_self
env)
1447 (Cls.where_constraints tc
)
1449 Typing_variance.class_def
env c
;
1450 check_no_generic_static_property tc
;
1451 let check_where_constraints env ht
=
1452 let (_
, (p, _
), _
) = TUtils.unwrap_class_type ht
in
1453 let (env, locl_ty
) = Phase.localize_with_self
env ht
in
1454 match get_node
(TUtils.get_base_type
env locl_ty
) with
1455 | Tclass
(cls
, _
, tyl
) ->
1456 (match Env.get_class
env (snd cls
) with
1457 | Some cls
when not
(List.is_empty
(Cls.where_constraints cls
)) ->
1458 let tc_tparams = Cls.tparams cls
in
1461 (Phase.env_with_self
env) with
1462 substs
= Subst.make_locl
tc_tparams tyl
;
1465 Phase.check_where_constraints
1471 (Cls.where_constraints cls
)
1475 let env = List.fold
impl ~
init:env ~f
:check_where_constraints in
1476 check_parent env c tc
;
1477 check_parents_sealed env c tc
;
1479 let is_final = Cls.final tc
in
1481 (Ast_defs.(equal_class_kind
(Cls.kind tc
) Cnormal
) || is_final)
1482 && Cls.members_fully_known tc
1484 check_extend_abstract_meth ~
is_final pc
(Cls.methods tc
);
1485 (match fst
(Cls.construct tc
) with
1487 check_extend_abstract_meth ~
is_final pc
[(SN.Members.__construct
, constr
)]
1489 check_extend_abstract_meth ~
is_final pc
(Cls.smethods tc
);
1490 check_extend_abstract_prop ~
is_final pc
(Cls.sprops tc
);
1491 check_extend_abstract_const ~
is_final pc
(Cls.consts tc
);
1492 check_extend_abstract_typeconst ~
is_final pc
(Cls.typeconsts tc
)
1494 if Cls.const tc
then List.iter c
.c_uses
(check_const_trait_members pc
env);
1495 let (static_vars
, vars
) = split_vars c
in
1496 List.iter static_vars ~f
:(fun { cv_id
= (p, id); _
} ->
1497 check_static_class_element (Cls.get_prop tc
) ~elt_type
:`Property
id p);
1498 List.iter vars ~f
:(fun { cv_id
= (p, id); _
} ->
1499 check_dynamic_class_element (Cls.get_sprop tc
) ~elt_type
:`Property
id p);
1500 let (constructor
, static_methods
, methods
) = split_methods c
in
1501 List.iter static_methods ~f
:(fun { m_name
= (p, id); _
} ->
1502 check_static_class_element (Cls.get_method tc
) ~elt_type
:`Method
id p);
1503 List.iter methods ~f
:(fun { m_name
= (p, id); _
} ->
1504 check_dynamic_class_element (Cls.get_smethod tc
) ~elt_type
:`Method
id p);
1506 List.fold ~
init:env impl ~f
:(fun env -> class_implements_type env c
)
1508 if Cls.is_disposable tc
then
1510 (c
.c_extends
@ c
.c_uses
)
1511 (Typing_disposable.enforce_is_disposable
env);
1512 let (env, typed_vars_and_global_inference_envs
) =
1513 List.map_env
env vars
(class_var_def ~is_static
:false tc
)
1515 let (typed_vars
, vars_global_inference_envs
) =
1516 List.unzip typed_vars_and_global_inference_envs
1518 let (typed_methods
, methods_global_inference_envs
) =
1519 List.filter_map methods
(method_def env tc
) |> List.unzip
1521 let (env, typed_typeconsts
) =
1522 List.map_env
env c
.c_typeconsts
(typeconst_def c
)
1524 let in_enum_class = Env.is_enum_class env c_name
in
1526 List.map_env
env c
.c_consts
(class_const_def ~
in_enum_class c
)
1528 let (typed_consts
, const_types
) = List.unzip consts
in
1529 let env = Typing_enum.enum_class_check
env tc c
.c_consts const_types
in
1530 let typed_constructor = class_constr_def env tc constructor
in
1531 let env = Env.set_static
env in
1532 let (env, typed_static_vars_and_global_inference_envs
) =
1533 List.map_env
env static_vars
(class_var_def ~is_static
:true tc
)
1535 let (typed_static_vars
, static_vars_global_inference_envs
) =
1536 List.unzip typed_static_vars_and_global_inference_envs
1538 let (typed_static_methods
, static_methods_global_inference_envs
) =
1539 List.filter_map static_methods
(method_def env tc
) |> List.unzip
1541 let (methods
, constr_global_inference_env
) =
1542 match typed_constructor with
1543 | None
-> (typed_static_methods
@ typed_methods
, [])
1544 | Some
(m, global_inference_env
) ->
1545 ((m :: typed_static_methods
) @ typed_methods
, [global_inference_env
])
1547 let (env, tparams
) = class_type_param env c
.c_tparams
in
1548 let (env, user_attributes
) =
1549 List.map_env
env c
.c_user_attributes
Typing.user_attribute
1552 Typing_solver.solve_all_unsolved_tyvars
env Errors.bad_class_typevar
1555 ( if TypecheckerOptions.enable_sound_dynamic
(Provider_context.get_tcopt
ctx)
1559 (c
.c_extends
@ c
.c_uses
@ c
.c_implements
)
1561 | (_
, Happly
((_
, name), _
)) -> Some
name
1564 let error_parent_implements_dynamic parent f
=
1565 Errors.parent_implements_dynamic
1567 (snd c
.c_name
, c
.c_kind
)
1568 (Cls.name parent
, Cls.kind parent
)
1571 List.iter
parent_names (fun name ->
1572 match Env.get_class_dep
env name with
1573 | Some parent_type
->
1575 match Cls.kind parent_type
with
1577 | Ast_defs.Cabstract
->
1581 (Cls.get_implements_dynamic parent_type
)
1582 c
.c_implements_dynamic
)
1584 error_parent_implements_dynamic
1586 c
.c_implements_dynamic
1587 | Ast_defs.Ctrait
->
1589 c
.c_implements_dynamic
1590 && not
(Cls.get_implements_dynamic parent_type
)
1592 error_parent_implements_dynamic parent_type
true
1593 | Ast_defs.Cinterface
->
1595 (not c
.c_implements_dynamic
)
1596 && Cls.get_implements_dynamic parent_type
1598 error_parent_implements_dynamic parent_type
false
1600 Ast_defs.is_c_interface c
.c_kind
1603 (Cls.get_implements_dynamic parent_type
)
1604 c
.c_implements_dynamic
)
1606 error_parent_implements_dynamic
1608 c
.c_implements_dynamic
1614 Aast.c_span
= c
.c_span
;
1615 Aast.c_annotation
= Env.save
(Env.get_tpenv
env) env;
1616 Aast.c_mode
= c
.c_mode
;
1617 Aast.c_final
= c
.c_final
;
1618 Aast.c_is_xhp
= c
.c_is_xhp
;
1619 Aast.c_has_xhp_keyword
= c
.c_has_xhp_keyword
;
1620 Aast.c_kind
= c
.c_kind
;
1621 Aast.c_name
= c
.c_name
;
1622 Aast.c_tparams
= tparams
;
1623 Aast.c_extends
= c
.c_extends
;
1624 Aast.c_uses
= c
.c_uses
;
1625 (* c_use_as_alias and c_insteadof_alias are PHP features not supported
1626 * in Hack but are required since we have runtime support for it
1628 Aast.c_use_as_alias
= [];
1629 Aast.c_insteadof_alias
= [];
1630 Aast.c_xhp_attr_uses
= c
.c_xhp_attr_uses
;
1631 Aast.c_xhp_category
= c
.c_xhp_category
;
1632 Aast.c_reqs
= c
.c_reqs
;
1633 Aast.c_implements
= c
.c_implements
;
1634 Aast.c_implements_dynamic
= c
.c_implements_dynamic
;
1635 Aast.c_where_constraints
= c
.c_where_constraints
;
1636 Aast.c_consts
= typed_consts
;
1637 Aast.c_typeconsts
= typed_typeconsts
;
1638 Aast.c_vars
= typed_static_vars
@ typed_vars
;
1639 Aast.c_methods
= methods
;
1640 Aast.c_file_attributes
= file_attrs
;
1641 Aast.c_user_attributes
= user_attributes
;
1642 Aast.c_namespace
= c
.c_namespace
;
1643 Aast.c_enum
= c
.c_enum
;
1644 Aast.c_doc_comment
= c
.c_doc_comment
;
1645 Aast.c_attributes
= [];
1646 Aast.c_xhp_children
= c
.c_xhp_children
;
1647 Aast.c_xhp_attrs
= [];
1648 Aast.c_emit_id
= c
.c_emit_id
;
1650 methods_global_inference_envs
1651 @ static_methods_global_inference_envs
1652 @ constr_global_inference_env
1653 @ static_vars_global_inference_envs
1654 @ vars_global_inference_envs
)
1656 let class_def ctx c
=
1657 Counters.count
Counters.Category.Typecheck
@@ fun () ->
1658 Errors.run_with_span c
.c_span
@@ fun () ->
1659 let env = EnvFromDef.class_env ~origin
:Decl_counters.TopLevel
ctx c
in
1660 let tc = Env.get_class
env (snd c
.c_name
) in
1661 let env = Env.set_env_pessimize
env in
1662 Typing_helpers.add_decl_errors
(Option.bind
tc Cls.decl_errors
);
1663 Typing_check_decls.class_
env c
;
1664 NastInitCheck.class_
env c
;
1667 (* This can happen if there was an error during the declaration
1671 (* If there are duplicate definitions of the class then we will end up
1672 * checking one AST with respect to the decl corresponding to the other definition.
1673 * Naming has already detected duplicates, so let's just avoid cascading unhelpful
1674 * typing errors, and also avoid triggering the bad position assert
1676 if not
(Pos.equal
(fst c
.c_name
) (Cls.pos tc)) then
1679 let env = Typing_requirements.check_class
env tc in
1680 if shallow_decl_enabled ctx then Typing_inheritance.check_class
env tc;
1681 Some
(class_def_ env c
tc)
1683 let gconst_def ctx cst
=
1684 Counters.count
Counters.Category.Typecheck
@@ fun () ->
1685 Errors.run_with_span cst
.cst_span
@@ fun () ->
1686 let env = EnvFromDef.gconst_env ~origin
:Decl_counters.TopLevel
ctx cst
in
1687 let env = Env.set_env_pessimize
env in
1688 let (typed_cst_value
, env) =
1689 let value = cst
.cst_value
in
1690 match cst
.cst_type
with
1692 let ty = Decl_hint.hint
env.decl_env hint
in
1693 let ty = Typing_enforceability.compute_enforced_ty
env ty in
1694 let (env, dty
) = Phase.localize_possibly_enforced_with_self
env ty in
1695 let (env, te, value_type
) =
1697 ExpectedTy.make_and_allow_coercion
(fst hint
) Reason.URhint dty
1699 expr_with_pure_coeffects env ~
expected value
1702 Typing_coercion.coerce_type
1713 (not
(is_literal_expr value))
1714 && Partial.should_check_error cst
.cst_mode
2035
1716 Errors.missing_typehint
(fst cst
.cst_name
);
1717 let (env, te, _value_type
) = expr_with_pure_coeffects env value in
1721 Aast.cst_annotation
= Env.save
(Env.get_tpenv
env) env;
1722 Aast.cst_mode
= cst
.cst_mode
;
1723 Aast.cst_name
= cst
.cst_name
;
1724 Aast.cst_type
= cst
.cst_type
;
1725 Aast.cst_value
= typed_cst_value
;
1726 Aast.cst_namespace
= cst
.cst_namespace
;
1727 Aast.cst_span
= cst
.cst_span
;
1728 Aast.cst_emit_id
= cst
.cst_emit_id
;
1731 let record_field env f
=
1732 let (id, hint
, e
) = f
in
1733 let ((p, _
) as cty
) = hint
in
1735 let cty = Decl_hint.hint
env.decl_env
cty in
1736 Phase.localize_with_self
env cty
1738 let expected = ExpectedTy.make
p Reason.URhint
cty in
1741 let (env, te, ty) = expr_with_pure_coeffects env ~
expected e
in
1743 Typing_coercion.coerce_type
1748 (MakeType.unenforced
cty)
1749 Errors.record_init_value_does_not_match_hint
1751 (env, (id, hint
, Some
te))
1752 | None
-> (env, (id, hint
, None
))
1754 let record_def_parent env rd parent_hint
=
1755 match snd parent_hint
with
1756 | Aast.Happly
((parent_pos, parent_name), []) ->
1757 (match Decl_provider.get_record_def
(Env.get_ctx
env) parent_name with
1759 (* We can only inherit from abstract records. *)
1760 ( if not parent_rd
.rdt_abstract
then
1761 let (parent_pos, parent_name) = parent_rd
.rdt_name
in
1762 Errors.extend_non_abstract_record
1767 (* Ensure we aren't defining fields that overlap with
1768 inherited fields. *)
1769 let inherited_fields = Typing_helpers.all_record_fields
env parent_rd
in
1770 List.iter rd
.rd_fields ~f
:(fun ((pos, name), _
, _
) ->
1771 match SMap.find_opt
name inherited_fields with
1772 | Some
((prev_pos
, _
), _
) ->
1773 Errors.repeated_record_field
name pos prev_pos
1776 (* Something exists with this name (naming succeeded), but it's
1778 Errors.unbound_name
parent_pos parent_name Errors.RecordContext
)
1781 "Record parent was not an Happly. This should have been a syntax error."
1783 (* Report an error if we have inheritance cycles in record declarations. *)
1784 let check_record_inheritance_cycle env ((rd_pos
, rd_name
) : Aast.sid
) : unit =
1785 let rec worker name trace seen
=
1786 match Decl_provider.get_record_def
(Env.get_ctx
env) name with
1788 (match rd
.rdt_extends
with
1789 | Some
(_
, parent_name) when String.equal
parent_name rd_name
->
1790 (* This record is in an inheritance cycle.*)
1791 Errors.cyclic_record_def trace rd_pos
1792 | Some
(_
, parent_name) when SSet.mem
parent_name seen
->
1793 (* There's an inheritance cycle higher in the chain. *)
1795 | Some
(_
, parent_name) ->
1796 worker parent_name (parent_name :: trace
) (SSet.add
parent_name seen
)
1800 worker rd_name
[rd_name
] (SSet.singleton rd_name
)
1802 let record_def_def ctx rd
=
1803 Counters.count
Counters.Category.Typecheck
@@ fun () ->
1804 let env = EnvFromDef.record_def_env ~origin
:Decl_counters.TopLevel
ctx rd
in
1805 (match rd
.rd_extends
with
1806 | Some parent
-> record_def_parent env rd parent
1809 check_record_inheritance_cycle env rd
.rd_name
;
1811 let (env, attributes
) =
1812 List.map_env
env rd
.rd_user_attributes
Typing.user_attribute
1814 let (_env, fields
) = List.map_env
env rd
.rd_fields
record_field in
1816 Aast.rd_annotation
= Env.save
(Env.get_tpenv
env) env;
1817 Aast.rd_name
= rd
.rd_name
;
1818 Aast.rd_extends
= rd
.rd_extends
;
1819 Aast.rd_abstract
= rd
.rd_abstract
;
1820 Aast.rd_fields
= fields
;
1821 Aast.rd_user_attributes
= attributes
;
1822 Aast.rd_namespace
= rd
.rd_namespace
;
1823 Aast.rd_span
= rd
.rd_span
;
1824 Aast.rd_doc_comment
= rd
.rd_doc_comment
;
1825 Aast.rd_emit_id
= rd
.rd_emit_id
;
1828 let nast_to_tast_gienv ~
(do_tast_checks
: bool) ctx nast
:
1829 _
* Typing_inference_env.t_global_with_pos list
=
1830 let convert_def = function
1831 (* Sometimes typing will just return `None` but that should only be the case
1832 * if an error had already been registered e.g. in naming
1836 match fun_def ctx f
with
1837 | Some
(f
, env) -> Some
(Aast.Fun f
, [env])
1840 | Constant gc
-> Some
(Aast.Constant
(gconst_def ctx gc
), [])
1841 | Typedef td
-> Some
(Aast.Typedef
(Typing.typedef_def
ctx td
), [])
1844 match class_def ctx c
with
1845 | Some
(c
, envs
) -> Some
(Aast.Class c
, envs
)
1848 | RecordDef rd
-> Some
(Aast.RecordDef
(record_def_def ctx rd
), [])
1849 (* We don't typecheck top level statements:
1850 * https://docs.hhvm.com/hack/unsupported/top-level
1851 * so just create the minimal env for us to construct a Stmt.
1854 let env = Env.empty
ctx Relative_path.default None
in
1855 Some
(Aast.Stmt
(snd
(Typing.stmt
env s
)), [])
1859 | FileAttributes _
->
1861 "Invalid nodes in NAST. These nodes should be removed during naming."
1863 Nast_check.program
ctx nast
;
1864 let (tast
, envs
) = List.unzip
@@ List.filter_map nast
convert_def in
1865 let envs = List.concat
envs in
1866 if do_tast_checks
then Tast_check.program
ctx tast
;
1869 let nast_to_tast ~do_tast_checks
ctx nast
=
1870 let (tast
, _gienvs
) = nast_to_tast_gienv ~do_tast_checks
ctx nast
in