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 (* The two following functions enable us to retrieve the function (or class)
29 header from the shared mem. Note that they only return a non None value if
30 global inference is on *)
31 let get_decl_function_header env function_id
=
32 let is_global_inference_on = TCO.global_inference
(Env.get_tcopt env
) in
33 if is_global_inference_on then
34 match Decl_provider.get_fun
(Env.get_ctx env
) function_id
with
35 | Some
{ fe_type
; _
} ->
37 match get_node fe_type
with
38 | Tfun fun_type
-> Some fun_type
45 and get_decl_method_header tcopt cls method_id ~is_static
=
46 let is_global_inference_on = TCO.global_inference tcopt
in
47 if is_global_inference_on then
48 match Cls.get_any_method ~is_static cls method_id
with
49 | Some
{ ce_type
= (lazy ty
); _
} ->
51 match get_node ty
with
52 | Tfun fun_type
-> Some fun_type
59 let enforce_param_not_disposable env param ty
=
60 if has_accept_disposable_attribute param
then
63 let p = param
.param_pos
in
64 match Typing_disposable.is_disposable_type env ty
with
65 | Some class_name
-> Errors.invalid_disposable_hint
p (strip_ns class_name
)
68 (* In strict mode, we force you to give a type declaration on a parameter *)
69 (* But the type checker is nice: it makes a suggestion :-) *)
70 let check_param_has_hint env param ty is_code_error
=
72 if is_code_error
4231 then
73 Typing.attributes_check_def
75 SN.AttributeKinds.parameter
76 param
.param_user_attributes
80 match hint_of_type_hint param
.param_type_hint
with
81 | None
when param
.param_is_variadic
&& is_code_error
4033 ->
82 Errors.expecting_type_hint_variadic param
.param_pos
83 | None
when is_code_error
4032 -> Errors.expecting_type_hint param
.param_pos
84 | Some _
when is_code_error
4010 ->
85 (* We do not permit hints to implement IDisposable or IAsyncDisposable *)
86 enforce_param_not_disposable env param ty
89 (* This function is used to determine the type of an argument.
90 * When we want to type-check the body of a function, we need to
91 * introduce the type of the arguments of the function in the environment
92 * Let's take an example, we want to check the code of foo:
94 * function foo(int $x): int {
95 * // CALL TO make_param_type on (int $x)
96 * // Now we know that the type of $x is int
98 * return $x; // in the environment $x is an int, the code is correct
101 * When we localize, we want to resolve to "static" or "$this" depending on
102 * the context. Even though we are passing in CIstatic, resolve_with_class_id
103 * is smart enough to know what to do. Why do this? Consider the following
106 * abstract const type T;
108 * private this::T $val;
110 * final public function __construct(this::T $x) {
114 * public static function create(this::T $x): this {
115 * return new static($x);
119 * class D extends C { const type T = int; }
121 * In __construct() we want to be able to assign $x to $this->val. The type of
122 * $this->val will expand to '$this::T', so we need $x to also be '$this::T'.
123 * We can do this soundly because when we construct a new class such as,
124 * 'new D(0)' we can determine the late static bound type (D) and resolve
125 * 'this::T' to 'D::T' which is int.
127 * A similar line of reasoning is applied for the static method create.
129 let make_param_local_ty env decl_hint param
=
130 let ety_env = Phase.env_with_self
env in
131 let r = Reason.Rwitness param
.param_pos
in
134 | None
-> (env, mk
(r, TUtils.tany
env))
136 let { et_type
= ty
; _
} =
137 Typing_enforceability.compute_enforced_and_pessimize_ty
138 ~explicitly_untrusted
:param
.param_is_variadic
142 Phase.localize ~
ety_env env ty
145 match get_node
ty with
146 | t
when param
.param_is_variadic
->
147 (* when checking the body of a function with a variadic
148 * argument, "f(C ...$args)", $args is a varray<C> *)
149 let r = Reason.Rvar_param param
.param_pos
in
150 let arr_values = mk
(r, t
) in
152 TypecheckerOptions.array_unification
(Env.get_tcopt
env)
154 MakeType.varray ~
unification r arr_values
159 let get_callable_variadicity ~partial_callback ~pos
env variadicity_decl_ty
=
161 | FVvariadicArg vparam
->
162 let (env, ty) = make_param_local_ty env variadicity_decl_ty vparam
in
163 check_param_has_hint env vparam
ty partial_callback
;
164 let (env, t_variadic
) = Typing.bind_param
env (ty, vparam
) in
165 (env, Aast.FVvariadicArg t_variadic
)
167 if Partial.should_check_error
(Env.get_mode
env) 4223 then
168 Errors.ellipsis_strict_mode ~require
:`Type_and_param_name pos
;
169 (env, Aast.FVellipsis
p)
170 | FVnonVariadic
-> (env, Aast.FVnonVariadic
)
172 let merge_hint_with_decl_hint env type_hint decl_ty
=
173 let contains_tvar decl_ty
=
176 | Some decl_ty
-> TUtils.contains_tvar_decl decl_ty
178 if contains_tvar decl_ty
then
181 Option.map type_hint ~f
:(Decl_hint.hint
env.decl_env
)
183 (* During the decl phase we can, for global inference, add "improved type hints".
184 That is we can say that some missing type hints are in fact global tyvars.
185 In that case to get the real type hint we must merge the type hint present
186 in the ast with the one we created during the decl phase. This function does
187 exactly this for the return type, the parameters and the variadic parameters.
189 let merge_decl_header_with_hints ~params ~ret ~variadic decl_header
env =
191 merge_hint_with_decl_hint
193 (hint_of_type_hint ret
)
195 ~f
:(fun { ft_ret
= { et_type
; _
}; _
} -> et_type
)
199 match decl_header
with
203 merge_hint_with_decl_hint
205 (hint_of_type_hint h
.param_type_hint
)
208 | Some
{ ft_params
; _
} ->
209 List.zip_exn params ft_params
210 |> List.map ~f
:(fun (h
, { fp_type
= { et_type
; _
}; _
}) ->
211 merge_hint_with_decl_hint
213 (hint_of_type_hint h
.param_type_hint
)
216 let variadicity_decl_ty =
217 match (decl_header
, variadic
) with
218 | ( Some
{ ft_arity
= Fvariadic
{ fp_type
= { et_type
; _
}; _
}; _
},
219 FVvariadicArg fp
) ->
220 merge_hint_with_decl_hint
222 (hint_of_type_hint fp
.param_type_hint
)
224 | (_
, FVvariadicArg fp
) ->
225 merge_hint_with_decl_hint env (hint_of_type_hint fp
.param_type_hint
) None
228 (ret_decl_ty, params_decl_ty, variadicity_decl_ty)
230 (* Checking this with List.exists will be a single op in the vast majority of cases (empty) *)
231 let get_ctx_vars ctxs
=
234 List.filter_map cs ~f
:(function
235 | (_
, Haccess
((_
, Hvar n
), _
)) -> Some n
241 (Tast.fun_def * Typing_inference_env.t_global_with_pos
) option =
242 Counters.count
Counters.Category.Typecheck
@@ fun () ->
243 Errors.run_with_span f
.f_span
@@ fun () ->
244 let env = EnvFromDef.fun_env ~origin
:Decl_counters.TopLevel ctx f
in
245 with_timeout
env f
.f_name ~do_
:(fun env ->
246 (* reset the expression dependent display ids for each function body *)
247 Reason.expr_display_id_map
:= IMap.empty
;
248 let pos = fst f
.f_name
in
249 let decl_header = get_decl_function_header env (snd f
.f_name
) in
250 let env = Env.open_tyvars
env (fst f
.f_name
) in
251 let env = Env.set_env_function_pos
env pos in
252 let env = Env.set_env_pessimize
env in
254 Typing.attributes_check_def
env SN.AttributeKinds.fn f
.f_user_attributes
256 let (env, file_attrs
) = Typing.file_attributes
env f
.f_file_attributes
in
257 let (env, cap_ty
, unsafe_cap_ty
) =
258 Typing.type_capability
env f
.f_ctxs f
.f_unsafe_ctxs
(fst f
.f_name
)
261 Typing_coeffects.register_capabilities
env cap_ty unsafe_cap_ty
263 Typing_check_decls.fun_
env f
;
265 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
269 f
.f_where_constraints
271 let env = Env.set_fn_kind
env f
.f_fun_kind
in
272 let (return_decl_ty
, params_decl_ty, variadicity_decl_ty) =
273 merge_decl_header_with_hints
276 ~variadic
:f
.f_variadic
280 let (env, return_ty
) =
281 match return_decl_ty
with
283 (env, Typing_return.make_default_return ~is_method
:false env f
.f_name
)
285 let localize env ty = Phase.localize_with_self
env ty in
286 Typing_return.make_return_type
localize env ty
289 Typing_return.make_info
293 ~is_explicit
:(Option.is_some
(hint_of_type_hint f
.f_ret
))
297 let (env, param_tys
) =
298 List.zip_exn f
.f_params
params_decl_ty
299 |> List.map_env
env ~f
:(fun env (param
, hint
) ->
300 make_param_local_ty env hint param
)
302 let partial_callback = Partial.should_check_error
(Env.get_mode
env) in
303 let check_has_hint p t
= check_param_has_hint env p t
partial_callback in
304 List.iter2_exn ~f
:check_has_hint f
.f_params param_tys
;
305 Typing_memoize.check_function
env f
;
306 let params_need_immutable = get_ctx_vars f
.f_ctxs
in
307 let (env, typed_params
) =
308 let bind_param_and_check env param
=
309 let name = (snd param
).param_name
in
311 List.exists ~f
:(String.equal
name) params_need_immutable
313 let (env, fun_param
) = Typing.bind_param ~
immutable env param
in
318 (List.zip_exn param_tys f
.f_params
)
321 let (env, t_variadic
) =
322 get_callable_variadicity
330 set_tyvars_variance_in_callable
env return_ty param_tys t_variadic
332 let local_tpenv = Env.get_tpenv
env in
334 Naming_attributes.mem
335 SN.UserAttributes.uaDisableTypecheckerInternal
339 Typing.fun_ ~
disable env return pos f
.f_body f
.f_fun_kind
342 match hint_of_type_hint f
.f_ret
with
344 if partial_callback 4030 then Errors.expecting_return_type_hint
pos
347 let (env, tparams
) = List.map_env
env f
.f_tparams
Typing.type_param
in
348 let (env, user_attributes
) =
349 List.map_env
env f
.f_user_attributes
Typing.user_attribute
352 Typing_solver.close_tyvars_and_solve
env Errors.bad_function_typevar
355 Typing_solver.solve_all_unsolved_tyvars
env Errors.bad_function_typevar
359 Aast.f_annotation
= Env.save
local_tpenv env;
360 Aast.f_span
= f
.f_span
;
361 Aast.f_mode
= f
.f_mode
;
362 Aast.f_readonly_ret
= f
.f_readonly_ret
;
363 Aast.f_ret
= (return_ty
, hint_of_type_hint f
.f_ret
);
364 Aast.f_name
= f
.f_name
;
365 Aast.f_tparams
= tparams
;
366 Aast.f_where_constraints
= f
.f_where_constraints
;
367 Aast.f_variadic
= t_variadic
;
368 Aast.f_params
= typed_params
;
369 Aast.f_ctxs
= f
.f_ctxs
;
370 Aast.f_unsafe_ctxs
= f
.f_unsafe_ctxs
;
371 Aast.f_fun_kind
= f
.f_fun_kind
;
372 Aast.f_file_attributes
= file_attrs
;
373 Aast.f_user_attributes
= user_attributes
;
374 Aast.f_body
= { Aast.fb_ast
= tb
; fb_annotation
= () };
375 Aast.f_external
= f
.f_external
;
376 Aast.f_namespace
= f
.f_namespace
;
377 Aast.f_doc_comment
= f
.f_doc_comment
;
378 Aast.f_static
= f
.f_static
;
381 let (_env
, global_inference_env
) = Env.extract_global_inference_env
env in
382 (fundef, (pos, global_inference_env
)))
384 let method_def env cls m
=
385 Errors.run_with_span m
.m_span
@@ fun () ->
386 with_timeout
env m
.m_name ~do_
:(fun env ->
387 FunUtils.check_params m
.m_params
;
388 let initial_env = env in
389 (* reset the expression dependent display ids for each method body *)
390 Reason.expr_display_id_map
:= IMap.empty
;
392 get_decl_method_header
396 ~is_static
:m
.m_static
398 let pos = fst m
.m_name
in
399 let env = Env.open_tyvars
env (fst m
.m_name
) in
400 let env = Env.reinitialize_locals
env in
401 let env = Env.set_env_function_pos
env pos in
403 Typing.attributes_check_def
405 SN.AttributeKinds.mthd
408 let (env, cap_ty
, unsafe_cap_ty
) =
409 Typing.type_capability
env m
.m_ctxs m
.m_unsafe_ctxs
(fst m
.m_name
)
412 Typing_coeffects.register_capabilities
env cap_ty unsafe_cap_ty
414 let is_ctor = String.equal
(snd m
.m_name
) SN.Members.__construct
in
415 let env = Env.set_fun_is_constructor
env is_ctor in
417 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
421 m
.m_where_constraints
424 match Env.get_self_ty
env with
425 | Some
ty when not
(Env.is_static
env) ->
426 Env.set_local
env this
ty Pos.none
430 match Env.get_self_class
env with
433 (* Mark $this as a using variable if it has a disposable type *)
434 if Cls.is_disposable c
then
435 Env.set_using_var
env this
439 let env = Env.clear_params
env in
440 let (ret_decl_ty, params_decl_ty, variadicity_decl_ty) =
441 merge_decl_header_with_hints
444 ~variadic
:m
.m_variadic
448 let env = Env.set_fn_kind
env m
.m_fun_kind
in
450 match ret_decl_ty with
452 (env, Typing_return.make_default_return ~is_method
:true env m
.m_name
)
454 (* If a 'this' type appears it needs to be compatible with the
457 let ety_env = Phase.env_with_self
env in
458 Typing_return.make_return_type
(Phase.localize ~
ety_env) env ret
461 Typing_return.make_info
465 ~is_explicit
:(Option.is_some
(hint_of_type_hint m
.m_ret
))
469 let (env, param_tys
) =
470 List.zip_exn m
.m_params
params_decl_ty
471 |> List.map_env
env ~f
:(fun env (param
, hint
) ->
472 make_param_local_ty env hint param
)
474 let partial_callback = Partial.should_check_error
(Env.get_mode
env) in
475 let param_fn p t
= check_param_has_hint env p t
partial_callback in
476 List.iter2_exn ~f
:param_fn m
.m_params param_tys
;
477 Typing_memoize.check_method
env m
;
478 let params_need_immutable = get_ctx_vars m
.m_ctxs
in
479 let (env, typed_params
) =
480 let bind_param_and_check env param
=
481 let name = (snd param
).param_name
in
483 List.exists ~f
:(String.equal
name) params_need_immutable
485 let (env, fun_param
) = Typing.bind_param ~
immutable env param
in
490 (List.zip_exn param_tys m
.m_params
)
493 let (env, t_variadic
) =
494 get_callable_variadicity
502 set_tyvars_variance_in_callable
env locl_ty param_tys t_variadic
504 let nb = Nast.assert_named_body m
.m_body
in
505 let local_tpenv = Env.get_tpenv
env in
507 Naming_attributes.mem
508 SN.UserAttributes.uaDisableTypecheckerInternal
513 ~abstract
:m
.m_abstract
522 match hint_of_type_hint m
.m_ret
with
523 | None
when String.equal
(snd m
.m_name
) SN.Members.__construct
->
524 Some
(pos, Hprim Tvoid
)
526 if partial_callback 4030 then Errors.expecting_return_type_hint
pos;
528 | Some _
-> hint_of_type_hint m
.m_ret
530 let m = { m with m_ret
= (fst
m.m_ret
, type_hint'
) } in
531 let (env, tparams
) = List.map_env
env m.m_tparams
Typing.type_param
in
532 let (env, user_attributes
) =
533 List.map_env
env m.m_user_attributes
Typing.user_attribute
536 Typing_solver.close_tyvars_and_solve
env Errors.bad_method_typevar
539 Typing_solver.solve_all_unsolved_tyvars
env Errors.bad_method_typevar
541 (* if the class implements dynamic, then check that its methods are dynamically callable *)
543 TypecheckerOptions.enable_sound_dynamic
544 (Provider_context.get_tcopt
(Env.get_ctx
env))
545 && Cls.get_implements_dynamic cls
547 (* 1. check if all the parameters of the method are enforceable *)
548 List.iter
params_decl_ty ~f
:(fun dtyopt
->
551 let te_check = Typing_enforceability.is_enforceable
env dty
in
553 Errors.method_is_not_dynamically_callable
558 (* 2. check if the return type is coercible *)
561 (Typing_subtype.is_sub_type_for_union
562 ~coerce
:(Some
Typing_logic.CoerceToDynamic
)
565 (mk
(Reason.Rnone
, Tdynamic
)))
567 Errors.method_is_not_dynamically_callable
574 Aast.m_annotation
= Env.save
local_tpenv env;
575 Aast.m_span
= m.m_span
;
576 Aast.m_final
= m.m_final
;
577 Aast.m_static
= m.m_static
;
578 Aast.m_abstract
= m.m_abstract
;
579 Aast.m_visibility
= m.m_visibility
;
580 Aast.m_readonly_this
= m.m_readonly_this
;
581 Aast.m_name
= m.m_name
;
582 Aast.m_tparams
= tparams
;
583 Aast.m_where_constraints
= m.m_where_constraints
;
584 Aast.m_variadic
= t_variadic
;
585 Aast.m_params
= typed_params
;
586 Aast.m_ctxs
= m.m_ctxs
;
587 Aast.m_unsafe_ctxs
= m.m_unsafe_ctxs
;
588 Aast.m_fun_kind
= m.m_fun_kind
;
589 Aast.m_user_attributes
= user_attributes
;
590 Aast.m_readonly_ret
= m.m_readonly_ret
;
591 Aast.m_ret
= (locl_ty
, hint_of_type_hint
m.m_ret
);
592 Aast.m_body
= { Aast.fb_ast
= tb
; fb_annotation
= () };
593 Aast.m_external
= m.m_external
;
594 Aast.m_doc_comment
= m.m_doc_comment
;
597 let (env, global_inference_env
) = Env.extract_global_inference_env
env in
598 let _env = Env.log_env_change
"method_def" initial_env env in
599 (method_def, (pos, global_inference_env
)))
601 (** Checks that extending this parent is legal - e.g. it is not final and not const. *)
602 let check_parent env class_def class_type
=
603 match Env.get_parent_class
env with
604 | Some parent_type
->
605 let position = fst class_def
.c_name
in
606 if Cls.const class_type
&& not
(Cls.const parent_type
) then
607 Errors.self_const_parent_not
position;
608 if Cls.final parent_type
then
609 Errors.extend_final
position (Cls.pos parent_type
) (Cls.name parent_type
)
612 let check_parent_sealed ~
(is_enum_class
: bool) child_type parent_type
=
613 match Cls.sealed_whitelist parent_type
with
616 let parent_pos = Cls.pos parent_type
in
617 let parent_name = Cls.name parent_type
in
618 let child_pos = Cls.pos child_type
in
619 let child_name = Cls.name child_type
in
620 let check kind action
=
621 if not
(SSet.mem
child_name whitelist
) then
622 Errors.extend_sealed
child_pos parent_pos parent_name kind action
625 match (Cls.kind parent_type
, Cls.kind child_type
) with
626 | (Ast_defs.Cinterface
, Ast_defs.Cinterface
) -> check "interface" "extend"
627 | (Ast_defs.Cinterface
, _
) -> check "interface" "implement"
628 | (Ast_defs.Ctrait
, _
) -> check "trait" "use"
629 | (Ast_defs.Cabstract
, _
)
630 | (Ast_defs.Cnormal
, _
) ->
631 check "class" "extend"
632 | (Ast_defs.Cenum
, _
) when is_enum_class
-> check "enum class" "extend"
633 | (Ast_defs.Cenum
, _
) -> check "enum" "use"
636 let check_parents_sealed env child_def child_type
=
638 match child_def
.c_enum
with
639 | Some enum
-> enum
.e_includes
640 | None
-> child_def
.c_extends
642 let parents = parents @ child_def
.c_implements
@ child_def
.c_uses
in
643 let is_enum_class = Aast.is_enum_class child_def
in
644 List.iter
parents (function
645 | (_
, Happly
((_
, name), _
)) ->
647 match Env.get_class_dep
env name with
648 | Some parent_type
->
649 check_parent_sealed ~
is_enum_class child_type parent_type
654 (* Reject multiple instantiations of the same generic interface
655 * in extends and implements clauses.
656 * e.g. disallow class C implements I<string>, I<int>
658 * O(n^2) but we don't expect number of instantiated interfaces to be large
660 let rec check_implements_or_extends_unique impl
=
664 (match get_node
ty with
665 | Tapply
((pos, name), _
:: _
) ->
666 let (pos_list
, rest
) =
667 List.partition_map rest
(fun ty ->
668 match get_node
ty with
669 | Tapply
((pos'
, name'
), _
) when String.equal
name name'
->
673 if not
(List.is_empty pos_list
) then
674 Errors.duplicate_interface
pos name pos_list
;
675 check_implements_or_extends_unique rest
676 | _
-> check_implements_or_extends_unique rest
)
678 let check_cstr_dep env deps
=
679 List.iter deps
(fun dep
->
681 | (_
, Tapply
((_
, class_name
), _
)) ->
682 Env.make_depend_on_constructor
env class_name
684 let p = Typing_reason.to_pos
r in
685 Errors.expected_class ~suffix
:" or interface but got a generic" p
687 let p = Typing_reason.to_pos
r in
688 Errors.expected_class ~suffix
:" or interface" p)
690 let check_const_trait_members pos env use_list
=
691 let (_
, trait
, _
) = Decl_utils.unwrap_class_hint use_list
in
692 match Env.get_class
env trait
with
693 | Some c
when Ast_defs.(equal_class_kind
(Cls.kind c
) Ctrait
) ->
694 List.iter
(Cls.props c
) (fun (x
, ce
) ->
695 if not
(get_ce_const ce
) then Errors.trait_prop_const_class
pos x
)
698 let check_consistent_enum_inclusion included_cls
(dest_cls
: Cls.t
) =
699 match (Cls.enum_type included_cls
, Cls.enum_type dest_cls
) with
700 | (Some included_e
, Some dest_e
) ->
701 (* ensure that the base types are identical *)
702 if not
(Typing_defs.equal_decl_ty included_e
.te_base dest_e
.te_base
) then
703 Errors.incompatible_enum_inclusion_base
706 (Cls.name included_cls
);
707 (* ensure that the visibility constraint are compatible *)
708 (match (included_e
.te_constraint
, dest_e
.te_constraint
) with
710 Errors.incompatible_enum_inclusion_constraint
713 (Cls.name included_cls
)
715 (* ensure normal enums can't include enum classes *)
716 if included_e
.te_enum_class
&& not dest_e
.te_enum_class
then
717 Errors.wrong_extend_kind
718 ~
parent_pos:(Cls.pos included_cls
)
719 ~parent_kind
:Ast_defs.Cenum
720 ~
parent_name:(Cls.name included_cls
)
721 ~parent_is_enum_class
:true
722 ~
child_pos:(Cls.pos dest_cls
)
723 ~child_kind
:Ast_defs.Cenum
724 ~
child_name:(Cls.name dest_cls
)
725 ~child_is_enum_class
:false
727 Errors.enum_inclusion_not_enum
730 (Cls.name included_cls
)
733 let check_enum_includes env cls
=
734 (* checks that there are no duplicated enum-constants when folded-decls are enabled *)
735 if Ast_defs.is_c_enum cls
.c_kind
then (
736 let (dest_class_pos
, dest_class_name
) = cls
.c_name
in
737 let enum_constant_map = ref SMap.empty
in
738 (* prepopulate the map with the constants declared in cls *)
739 List.iter cls
.c_consts ~f
:(fun cc
->
743 (fst cc
.cc_id
, dest_class_name
)
745 (* for all included enums *)
747 Aast.enum_includes_map cls
.c_enum ~f
:(fun ce
->
748 List.filter_map ce
.e_includes ~f
:(fun ie
->
751 (match Env.get_class
env (snd sid
) with
753 | Some ie_cls
-> Some
(fst ie
, ie_cls
))
756 List.iter
included_enums ~f
:(fun (ie_pos
, ie_cls
) ->
757 let src_class_name = Cls.name ie_cls
in
758 (* 1. Check for consistency *)
759 (match Env.get_class
env dest_class_name
with
761 | Some cls
-> check_consistent_enum_inclusion ie_cls cls
);
762 (* 2. Check for duplicates *)
763 List.iter
(Cls.consts ie_cls
) ~f
:(fun (const_name
, class_const
) ->
764 ( if String.equal const_name
"class" then
766 else if SMap.mem const_name
!enum_constant_map then
767 (* distinguish between multiple inherit and redeclare *)
768 let (origin_const_pos
, origin_class_name
) =
769 SMap.find const_name
!enum_constant_map
771 if String.equal origin_class_name dest_class_name
then
773 Errors.redeclaring_classish_const
780 (* multiple inherit *)
781 Errors.reinheriting_classish_const
791 (dest_class_pos
, class_const
.cc_origin
)
795 let shallow_decl_enabled (ctx
: Provider_context.t
) : bool =
796 TypecheckerOptions.shallow_class_decl
(Provider_context.get_tcopt ctx
)
798 let class_type_param env ct
=
799 let (env, tparam_list
) = List.map_env
env ct
Typing.type_param
in
802 (* This function sets a temporary coeffect context to check constants
803 * with the right one (either pure / write_props).
804 * We need to carefully restore the locals, otherwise the next continuation
805 * is just reset and the call to register_capabilities is a no-op, no
806 * capability is registered.
808 let expr_with_special_coeffects env ?expected e cap_ty unsafe_cap_ty
=
810 Option.map
(Env.next_cont_opt
env) ~f
:(fun next_cont
->
811 let initial_locals = next_cont
.Typing_per_cont_env.local_types
in
812 let tpenv = Env.get_tpenv
env in
813 (initial_locals, tpenv))
815 let (env, (te
, ty)) =
816 Typing_lenv.stash_and_do
env (Env.all_continuations
env) (fun env ->
820 | Some
(initial_locals, tpenv) ->
821 let env = Env.reinitialize_locals
env in
822 let env = Env.set_locals
env initial_locals in
823 let env = Env.env_with_tpenv
env tpenv in
827 Typing_coeffects.register_capabilities
env cap_ty unsafe_cap_ty
829 let (env, te
, ty) = Typing.expr ?expected
env e
in
834 (* Some (legacy) special functions are allowed as class constant init.,
835 therefore treat them as pure and insert the matching capabilities. *)
836 let expr_with_pure_coeffects env ?expected e
=
837 let pure = MakeType.mixed
(Reason.Rwitness
(fst e
)) in
838 expr_with_special_coeffects env ?expected e
pure pure
840 (* Enum class constant initializers are restricted to be `write_props` *)
841 let expr_with_write_props_coeffects env ?expected e
=
843 let make_hint pos s
= (pos, Aast.Happly
((pos, s
), [])) in
845 Some
(e_pos, [make_hint e_pos SN.Capabilities.writeProperty
])
847 let (env, cap_ty
, unsafe_cap_ty
) =
848 Typing.type_capability
env enum_class_ctx enum_class_ctx e_pos
850 expr_with_special_coeffects env ?expected e cap_ty unsafe_cap_ty
852 (** Checks that a dynamic element is also dynamic in the parents. *)
853 let check_dynamic_class_element get_static_elt element_name dyn_pos ~elt_type
=
854 (* The non-static properties that we get passed do not start with '$', but the
855 static properties we want to look up do, so add it. *)
858 | `Method
-> element_name
859 | `Property
-> "$" ^ element_name
861 match get_static_elt
id with
863 | Some static_element
->
864 let (lazy ty) = static_element
.ce_type
in
865 Errors.static_redeclared_as_dynamic
871 (** Checks that a static element is also static in the parents. *)
872 let check_static_class_element get_dyn_elt element_name static_pos ~elt_type
=
873 (* The static properties that we get passed in start with '$', but the
874 non-static properties we're matching against don't, so we need to detect
875 that and remove it if present. *)
876 let element_name = String_utils.lstrip
element_name "$" in
877 match get_dyn_elt
element_name with
879 | Some dyn_element
->
880 let (lazy ty) = dyn_element
.ce_type
in
881 Errors.dynamic_redeclared_as_static
887 (** Error if there are abstract methods that this class is supposed to provide
888 implementation for. *)
889 let check_extend_abstract_meth ~is_final
p seq
=
890 List.iter seq
(fun (x
, ce
) ->
891 match ce
.ce_type
with
892 | (lazy ty) when get_ce_abstract ce
&& is_fun
ty ->
893 Errors.implement_abstract ~is_final
p (get_pos
ty) "method" x
896 let check_extend_abstract_prop ~is_final
p seq
=
897 List.iter seq
(fun (x
, ce
) ->
898 if get_ce_abstract ce
then
899 let ce_pos = Lazy.force ce
.ce_type
|> get_pos
in
900 Errors.implement_abstract ~is_final
p ce_pos "property" x
)
902 (* Type constants must be bound to a concrete type for non-abstract classes.
904 let check_extend_abstract_typeconst ~is_final
p seq
=
905 List.iter seq
(fun (x
, tc
) ->
906 if Option.is_none tc
.ttc_type
then
907 Errors.implement_abstract
914 let check_extend_abstract_const ~is_final
p seq
=
915 List.iter seq
(fun (x
, cc
) ->
916 if cc
.cc_abstract
&& not cc
.cc_synthesized
then
917 let cc_pos = get_pos cc
.cc_type
in
918 Errors.implement_abstract ~is_final
p cc_pos "constant" x
)
920 exception Found
of Pos.t
922 let contains_generic : Typing_defs.decl_ty
-> Pos.t
option =
926 inherit [_
] Type_visitor.decl_type_visitor
as super
928 method! on_type
env ty =
929 match get_node
ty with
930 | Tgeneric _
-> raise
(Found
(get_pos
ty))
931 | _
-> super#on_type
env ty
935 visitor#on_type
() ty;
937 with Found
p -> Some
p
939 let check_no_generic_static_property tc
=
941 (* Check whether the type of a static property (class variable) contains
942 * any generic type parameters. Outside of traits, this is illegal as static
943 * properties are shared across all generic instantiations.
944 * Although not strictly speaking a variance check, it fits here because
945 * it concerns the presence of generic type parameters in types.
947 Ast_defs.(equal_class_kind
(Cls.kind tc
) Ctrait
)
952 |> List.iter ~f
:(fun (_prop_name
, prop
) ->
953 let (lazy ty) = prop
.ce_type
in
954 let var_type_pos = get_pos
ty in
955 let class_pos = Cls.pos tc
in
956 match contains_generic ty with
958 | Some generic_pos
->
959 Errors.static_property_type_generic_param
964 let get_decl_prop_ty env cls ~is_static prop_id
=
965 let is_global_inference_on = TCO.global_inference
(Env.get_tcopt
env) in
966 if is_global_inference_on then
969 (* this is very ad-hoc, but this is how we do it in the decl-heap *)
970 Cls.get_sprop cls
("$" ^ prop_id
)
972 Cls.get_prop cls prop_id
975 | None
-> failwith
"error: could not find property in decl heap"
976 | Some
{ ce_type
; _
} -> Some
(Lazy.force ce_type
)
985 c_tconst_name
= (pos, _
) as id;
986 c_tconst_as_constraint
;
987 c_tconst_type
= hint
;
988 c_tconst_user_attributes
;
990 c_tconst_doc_comment
;
993 if Ast_defs.is_c_enum cls
.c_kind
then
994 Errors.cannot_declare_constant `enum
pos cls
.c_name
;
996 opt
Phase.localize_hint_with_self
env c_tconst_as_constraint
1000 | None
-> (env, None
)
1002 let ty = Decl_hint.hint
env.decl_env hint
in
1003 (* We want to report cycles through the definition *)
1004 let name = snd cls
.c_name ^
"::" ^ snd
id in
1006 Phase.localize_with_self
env ~
pos ~report_cycle
:(pos, name) ty
1011 Type.sub_type
pos Reason.URtypeconst_cstr
env t c
Errors.unify_error
1013 let env = Option.value ~default
:env @@ Option.map2
ty cstr ~f
:(check env) in
1016 | Some
(pos, Hshape
{ nsi_field_map
; _
}) ->
1017 let get_name sfi
= sfi
.sfi_name
in
1018 Typing.check_shape_keys_validity
1021 (List.map ~f
:get_name nsi_field_map
)
1025 Typing.attributes_check_def
1027 SN.AttributeKinds.typeconst
1028 c_tconst_user_attributes
1030 let (env, user_attributes
) =
1031 List.map_env
env c_tconst_user_attributes
Typing.user_attribute
1035 Aast.c_tconst_abstract
;
1036 Aast.c_tconst_name
= id;
1037 Aast.c_tconst_as_constraint
;
1038 Aast.c_tconst_type
= hint
;
1039 Aast.c_tconst_user_attributes
= user_attributes
;
1041 Aast.c_tconst_doc_comment
;
1042 Aast.c_tconst_is_ctx
;
1045 (* This should agree with the set of expressions whose type can be inferred in
1046 * Decl_utils.infer_const
1048 let is_literal_expr e
=
1057 | Unop
((Ast_defs.Uminus
| Ast_defs.Uplus
), (_
, (Int _
| Float _
))) -> true
1060 let class_const_def ~in_enum_class c
env cc
=
1061 let { cc_type
= h
; cc_id
= id; cc_expr
= e
; _
} = cc
in
1062 let (env, ty, opt_expected
) =
1070 (not
(is_literal_expr e
))
1071 && Partial.should_check_error c
.c_mode
2035
1072 && not
Ast_defs.(equal_class_kind c
.c_kind Cenum
)
1074 Errors.missing_typehint
(fst
id)
1076 let (env, ty) = Env.fresh_type
env (fst
id) in
1077 (env, MakeType.unenforced
ty, None
)
1079 let ty = Decl_hint.hint
env.decl_env h
in
1080 let ty = Typing_enforceability.compute_enforced_ty
env ty in
1081 let (env, ty) = Phase.localize_possibly_enforced_with_self
env ty in
1082 (* Removing the HH\MemberOf wrapper in case of enum classes so the
1083 * following call to expr_* has the right expected type
1086 if in_enum_class
then
1087 match get_node
ty.et_type
with
1088 | Tnewtype
(memberof
, [_
; et_type
], _
)
1089 when String.equal memberof
SN.Classes.cMemberOf
->
1097 Some
(ExpectedTy.make_and_allow_coercion
(fst
id) Reason.URhint
opt_ty)
1100 let (env, eopt
, ty) =
1103 let (env, te
, ty'
) =
1104 if in_enum_class
then
1105 expr_with_write_props_coeffects env ?expected
:opt_expected e
1107 expr_with_pure_coeffects env ?expected
:opt_expected e
1109 (* If we are checking an enum class, wrap ty' into the right
1110 * HH\MemberOf<class name, ty'> alias
1113 if in_enum_class
then
1114 match deref
ty.et_type
with
1115 | (r, Tnewtype
(memberof
, [enum_name
; _
], _
))
1116 when String.equal memberof
SN.Classes.cMemberOf
->
1117 let lift r ty = mk
(r, Tnewtype
(memberof
, [enum_name
; ty], ty)) in
1118 let ((p, te_ty
), te
) = te
in
1119 let te = ((p, lift (get_reason te_ty
) te_ty
), te) in
1120 let ty'
= lift r ty'
in
1127 Typing_coercion.coerce_type
1133 Errors.class_constant_value_does_not_match_hint
1136 | None
-> (env, None
, ty.et_type
)
1140 Aast.cc_type
= cc
.cc_type
;
1141 Aast.cc_id
= cc
.cc_id
;
1142 Aast.cc_expr
= eopt
;
1143 Aast.cc_doc_comment
= cc
.cc_doc_comment
;
1147 let class_constr_def env cls constructor
=
1148 let env = { env with inside_constructor
= true } in
1149 Option.bind constructor
(method_def env cls
)
1151 let class_implements_type env implements c1 ctype2
=
1153 List.map c1
.c_tparams
(fun { tp_name
= (p, s
); _
} ->
1154 mk
(Reason.Rwitness_from_decl
p, Tgeneric
(s
, [])))
1156 let r = Reason.Rwitness_from_decl
(fst c1
.c_name
) in
1157 let ctype1 = mk
(r, Tapply
(c1
.c_name
, params)) in
1158 Typing_extends.check_implements
env implements ctype2
ctype1
1160 (** Type-check a property declaration, with optional initializer *)
1161 let class_var_def ~is_static cls
env cv
=
1162 (* First pick up and localize the hint if it exists *)
1164 merge_hint_with_decl_hint
1166 (hint_of_type_hint cv
.cv_type
)
1167 (get_decl_prop_ty env cls ~is_static
(snd cv
.cv_id
))
1169 let (env, expected
) =
1171 | None
-> (env, None
)
1173 let decl_cty = Typing_enforceability.compute_enforced_ty
env decl_cty in
1175 Phase.localize_possibly_enforced_with_self
env decl_cty
1178 Some
(ExpectedTy.make_and_allow_coercion cv
.cv_span
Reason.URhint cty
)
1182 (* Next check the expression, passing in expected type if present *)
1183 let (env, typed_cv_expr
) =
1184 match cv
.cv_expr
with
1185 | None
-> (env, None
)
1187 let (env, te, ty) = expr_with_pure_coeffects env ?
expected e
in
1188 (* Check that the inferred type is a subtype of the expected type.
1189 * Eventually this will be the responsibility of `expr`
1194 | Some
ExpectedTy.{ pos = p; reason
= ur
; ty = cty
} ->
1195 Typing_coercion.coerce_type
1201 Errors.class_property_initializer_type_does_not_match_hint
1208 Typing.attributes_check_def
1210 SN.AttributeKinds.staticProperty
1211 cv
.cv_user_attributes
1213 Typing.attributes_check_def
1215 SN.AttributeKinds.instProperty
1216 cv
.cv_user_attributes
1218 let (env, user_attributes
) =
1219 List.map_env
env cv
.cv_user_attributes
Typing.user_attribute
1222 Option.is_none
(hint_of_type_hint cv
.cv_type
)
1223 && Partial.should_check_error
(Env.get_mode
env) 2001
1225 Errors.prop_without_typehint
1226 (string_of_visibility cv
.cv_visibility
)
1228 let (env, global_inference_env
) = Env.extract_global_inference_env
env in
1232 (expected.ExpectedTy.ty.et_type
, hint_of_type_hint cv
.cv_type)
1233 | None
-> Tast.dummy_type_hint
(hint_of_type_hint cv
.cv_type)
1235 (* if the class implements dynamic, then check that the type of the property
1236 * is enforceable (for writing) and coerces to dynamic (for reading) *)
1238 TypecheckerOptions.enable_sound_dynamic
1239 (Provider_context.get_tcopt
(Env.get_ctx
env))
1240 && Cls.get_implements_dynamic cls
1242 Option.iter
decl_cty (fun ty ->
1243 let te_check = Typing_enforceability.is_enforceable
env ty in
1244 if not
te_check then
1245 Errors.property_is_not_enforceable
1251 (Typing_subtype.is_sub_type_for_union
1252 ~coerce
:(Some
Typing_logic.CoerceToDynamic
)
1255 (mk
(Reason.Rnone
, Tdynamic
)))
1257 Errors.property_is_not_dynamic
1264 Aast.cv_final
= cv
.cv_final
;
1265 Aast.cv_xhp_attr
= cv
.cv_xhp_attr
;
1266 Aast.cv_abstract
= cv
.cv_abstract
;
1267 Aast.cv_visibility
= cv
.cv_visibility
;
1269 Aast.cv_id
= cv
.cv_id
;
1270 Aast.cv_expr
= typed_cv_expr
;
1271 Aast.cv_user_attributes
= user_attributes
;
1272 Aast.cv_is_promoted_variadic
= cv
.cv_is_promoted_variadic
;
1273 Aast.cv_doc_comment
= cv
.cv_doc_comment
;
1274 (* Can make None to save space *)
1275 Aast.cv_is_static
= is_static
;
1276 Aast.cv_span
= cv
.cv_span
;
1277 Aast.cv_readonly
= cv
.cv_readonly
;
1279 (cv
.cv_span
, global_inference_env
) ) )
1281 let class_def_ env c tc
=
1286 (match c
.c_enum
with
1287 | Some enum
when enum
.e_enum_class
-> SN.AttributeKinds.enumcls
1288 | _
-> SN.AttributeKinds.enum
)
1289 | _
-> SN.AttributeKinds.cls
1291 Typing.attributes_check_def
env kind c
.c_user_attributes
1293 let (env, file_attrs
) = Typing.file_attributes
env c
.c_file_attributes
in
1294 let ctx = Env.get_ctx
env in
1296 ( Ast_defs.(equal_class_kind c
.c_kind Cnormal
)
1297 || Ast_defs.(equal_class_kind c
.c_kind Cabstract
) )
1298 && not
(shallow_decl_enabled ctx)
1300 (* These checks are only for eager mode. The same checks are performed
1301 * for shallow mode in Typing_inheritance *)
1302 let method_pos ~is_static class_id meth_id
=
1305 Decl_heap.StaticMethods.get
1307 Decl_heap.Methods.get
1309 match get_meth (class_id
, meth_id
) with
1310 | Some
{ fe_pos
; _
} -> fe_pos
1313 let check_override ~is_static
(id, ce
) =
1314 if get_ce_override ce
then
1315 let pos = method_pos ~is_static ce
.ce_origin
id in
1316 (* Method is actually defined in this class *)
1317 if String.equal ce
.ce_origin
(snd c
.c_name
) then
1318 Errors.should_be_override
pos (snd c
.c_name
) id
1320 match Env.get_class
env ce
.ce_origin
with
1322 | Some parent_class
->
1323 (* If it's not defined here, then either it's inherited (so we have emitted an error already)
1324 * or it's in a trait, and so we need to emit the error now *)
1325 if not
Ast_defs.(equal_class_kind
(Cls.kind parent_class
) Ctrait
)
1329 Errors.override_per_trait c
.c_name
id ce
.ce_origin
pos
1332 List.iter
(Cls.methods tc
) (check_override ~is_static
:false);
1333 List.iter
(Cls.smethods tc
) (check_override ~is_static
:true)
1335 check_enum_includes env c
;
1336 let (pc
, c_name
) = c
.c_name
in
1337 let (req_extends
, req_implements
) = split_reqs c
in
1338 let extends = List.map c
.c_extends
(Decl_hint.hint
env.decl_env
) in
1339 let implements = List.map c
.c_implements
(Decl_hint.hint
env.decl_env
) in
1340 let uses = List.map c
.c_uses
(Decl_hint.hint
env.decl_env
) in
1341 let req_extends = List.map
req_extends (Decl_hint.hint
env.decl_env
) in
1342 let req_implements = List.map
req_implements (Decl_hint.hint
env.decl_env
) in
1343 let additional_parents =
1344 (* In an abstract class or a trait, we assume the interfaces
1345 will be implemented in the future, so we take them as
1346 part of the class (as requested by dependency injection implementers) *)
1348 | Ast_defs.Cabstract
-> implements
1349 | Ast_defs.Ctrait
-> implements @ req_implements
1352 let check_cstr_dep = check_cstr_dep env in
1353 check_implements_or_extends_unique implements;
1354 check_implements_or_extends_unique extends;
1355 check_cstr_dep extends;
1356 check_cstr_dep uses;
1357 check_cstr_dep req_extends;
1358 check_cstr_dep additional_parents;
1362 check_cstr_dep (List.map e
.e_includes
(Decl_hint.hint
env.decl_env
))
1365 let impl = extends @ implements @ uses in
1367 Phase.localize_and_add_ast_generic_parameters_and_where_constraints
1371 c
.c_where_constraints
1374 Phase.check_where_constraints
1378 ~
ety_env:(Phase.env_with_self
env)
1380 (Cls.where_constraints tc
)
1382 Typing_variance.class_def
env c
;
1383 check_no_generic_static_property tc
;
1384 let check_where_constraints env ht
=
1385 let (_
, (p, _
), _
) = TUtils.unwrap_class_type ht
in
1386 let (env, locl_ty
) = Phase.localize_with_self
env ht
in
1387 match get_node
(TUtils.get_base_type
env locl_ty
) with
1388 | Tclass
(cls
, _
, tyl
) ->
1389 (match Env.get_class
env (snd cls
) with
1390 | Some cls
when not
(List.is_empty
(Cls.where_constraints cls
)) ->
1391 let tc_tparams = Cls.tparams cls
in
1394 (Phase.env_with_self
env) with
1395 substs
= Subst.make_locl
tc_tparams tyl
;
1398 Phase.check_where_constraints
1404 (Cls.where_constraints cls
)
1408 let env = List.fold
impl ~
init:env ~f
:check_where_constraints in
1409 check_parent env c tc
;
1410 check_parents_sealed env c tc
;
1412 let is_final = Cls.final tc
in
1414 (Ast_defs.(equal_class_kind
(Cls.kind tc
) Cnormal
) || is_final)
1415 && Cls.members_fully_known tc
1417 check_extend_abstract_meth ~
is_final pc
(Cls.methods tc
);
1418 (match fst
(Cls.construct tc
) with
1420 check_extend_abstract_meth ~
is_final pc
[(SN.Members.__construct
, constr
)]
1422 check_extend_abstract_meth ~
is_final pc
(Cls.smethods tc
);
1423 check_extend_abstract_prop ~
is_final pc
(Cls.sprops tc
);
1424 check_extend_abstract_const ~
is_final pc
(Cls.consts tc
);
1425 check_extend_abstract_typeconst ~
is_final pc
(Cls.typeconsts tc
)
1427 if Cls.const tc
then List.iter c
.c_uses
(check_const_trait_members pc
env);
1428 let (static_vars
, vars
) = split_vars c
in
1429 List.iter static_vars ~f
:(fun { cv_id
= (p, id); _
} ->
1430 check_static_class_element (Cls.get_prop tc
) ~elt_type
:`Property
id p);
1431 List.iter vars ~f
:(fun { cv_id
= (p, id); _
} ->
1432 check_dynamic_class_element (Cls.get_sprop tc
) ~elt_type
:`Property
id p);
1433 let (constructor
, static_methods
, methods
) = split_methods c
in
1434 List.iter static_methods ~f
:(fun { m_name
= (p, id); _
} ->
1435 check_static_class_element (Cls.get_method tc
) ~elt_type
:`Method
id p);
1436 List.iter methods ~f
:(fun { m_name
= (p, id); _
} ->
1437 check_dynamic_class_element (Cls.get_smethod tc
) ~elt_type
:`Method
id p);
1439 List.fold ~
init:env impl ~f
:(fun env ->
1440 class_implements_type env implements c
)
1442 if Cls.is_disposable tc
then
1444 (c
.c_extends
@ c
.c_uses
)
1445 (Typing_disposable.enforce_is_disposable
env);
1446 let (env, typed_vars_and_global_inference_envs
) =
1447 List.map_env
env vars
(class_var_def ~is_static
:false tc
)
1449 let (typed_vars
, vars_global_inference_envs
) =
1450 List.unzip typed_vars_and_global_inference_envs
1452 let (typed_methods
, methods_global_inference_envs
) =
1453 List.filter_map methods
(method_def env tc
) |> List.unzip
1455 let (env, typed_typeconsts
) =
1456 List.map_env
env c
.c_typeconsts
(typeconst_def c
)
1458 let in_enum_class = Env.is_enum_class env c_name
in
1460 List.map_env
env c
.c_consts
(class_const_def ~
in_enum_class c
)
1462 let (typed_consts
, const_types
) = List.unzip consts
in
1463 let env = Typing_enum.enum_class_check
env tc c
.c_consts const_types
in
1464 let typed_constructor = class_constr_def env tc constructor
in
1465 let env = Env.set_static
env in
1466 let (env, typed_static_vars_and_global_inference_envs
) =
1467 List.map_env
env static_vars
(class_var_def ~is_static
:true tc
)
1469 let (typed_static_vars
, static_vars_global_inference_envs
) =
1470 List.unzip typed_static_vars_and_global_inference_envs
1472 let (typed_static_methods
, static_methods_global_inference_envs
) =
1473 List.filter_map static_methods
(method_def env tc
) |> List.unzip
1475 let (methods
, constr_global_inference_env
) =
1476 match typed_constructor with
1477 | None
-> (typed_static_methods
@ typed_methods
, [])
1478 | Some
(m, global_inference_env
) ->
1479 ((m :: typed_static_methods
) @ typed_methods
, [global_inference_env
])
1481 let (env, tparams
) = class_type_param env c
.c_tparams
in
1482 let (env, user_attributes
) =
1483 List.map_env
env c
.c_user_attributes
Typing.user_attribute
1486 Typing_solver.solve_all_unsolved_tyvars
env Errors.bad_class_typevar
1489 ( if TypecheckerOptions.enable_sound_dynamic
(Provider_context.get_tcopt
ctx)
1493 (c
.c_extends
@ c
.c_uses
@ c
.c_implements
)
1495 | (_
, Happly
((_
, name), _
)) -> Some
name
1498 let error_parent_implements_dynamic parent f
=
1499 Errors.parent_implements_dynamic
1501 (snd c
.c_name
, c
.c_kind
)
1502 (Cls.name parent
, Cls.kind parent
)
1505 List.iter
parent_names (fun name ->
1506 match Env.get_class_dep
env name with
1507 | Some parent_type
->
1509 match Cls.kind parent_type
with
1511 | Ast_defs.Cabstract
->
1515 (Cls.get_implements_dynamic parent_type
)
1516 c
.c_implements_dynamic
)
1518 error_parent_implements_dynamic
1520 c
.c_implements_dynamic
1521 | Ast_defs.Ctrait
->
1523 c
.c_implements_dynamic
1524 && not
(Cls.get_implements_dynamic parent_type
)
1526 error_parent_implements_dynamic parent_type
true
1527 | Ast_defs.Cinterface
->
1529 (not c
.c_implements_dynamic
)
1530 && Cls.get_implements_dynamic parent_type
1532 error_parent_implements_dynamic parent_type
false
1534 Ast_defs.is_c_interface c
.c_kind
1537 (Cls.get_implements_dynamic parent_type
)
1538 c
.c_implements_dynamic
)
1540 error_parent_implements_dynamic
1542 c
.c_implements_dynamic
1548 Aast.c_span
= c
.c_span
;
1549 Aast.c_annotation
= Env.save
(Env.get_tpenv
env) env;
1550 Aast.c_mode
= c
.c_mode
;
1551 Aast.c_final
= c
.c_final
;
1552 Aast.c_is_xhp
= c
.c_is_xhp
;
1553 Aast.c_has_xhp_keyword
= c
.c_has_xhp_keyword
;
1554 Aast.c_kind
= c
.c_kind
;
1555 Aast.c_name
= c
.c_name
;
1556 Aast.c_tparams
= tparams
;
1557 Aast.c_extends
= c
.c_extends
;
1558 Aast.c_uses
= c
.c_uses
;
1559 (* c_use_as_alias and c_insteadof_alias are PHP features not supported
1560 * in Hack but are required since we have runtime support for it
1562 Aast.c_use_as_alias
= [];
1563 Aast.c_insteadof_alias
= [];
1564 Aast.c_xhp_attr_uses
= c
.c_xhp_attr_uses
;
1565 Aast.c_xhp_category
= c
.c_xhp_category
;
1566 Aast.c_reqs
= c
.c_reqs
;
1567 Aast.c_implements
= c
.c_implements
;
1568 Aast.c_implements_dynamic
= c
.c_implements_dynamic
;
1569 Aast.c_where_constraints
= c
.c_where_constraints
;
1570 Aast.c_consts
= typed_consts
;
1571 Aast.c_typeconsts
= typed_typeconsts
;
1572 Aast.c_vars
= typed_static_vars
@ typed_vars
;
1573 Aast.c_methods
= methods
;
1574 Aast.c_file_attributes
= file_attrs
;
1575 Aast.c_user_attributes
= user_attributes
;
1576 Aast.c_namespace
= c
.c_namespace
;
1577 Aast.c_enum
= c
.c_enum
;
1578 Aast.c_doc_comment
= c
.c_doc_comment
;
1579 Aast.c_attributes
= [];
1580 Aast.c_xhp_children
= c
.c_xhp_children
;
1581 Aast.c_xhp_attrs
= [];
1582 Aast.c_emit_id
= c
.c_emit_id
;
1584 methods_global_inference_envs
1585 @ static_methods_global_inference_envs
1586 @ constr_global_inference_env
1587 @ static_vars_global_inference_envs
1588 @ vars_global_inference_envs
)
1590 let class_def ctx c
=
1591 Counters.count
Counters.Category.Typecheck
@@ fun () ->
1592 Errors.run_with_span c
.c_span
@@ fun () ->
1593 let env = EnvFromDef.class_env ~origin
:Decl_counters.TopLevel
ctx c
in
1594 let tc = Env.get_class
env (snd c
.c_name
) in
1595 let env = Env.set_env_pessimize
env in
1596 Typing_helpers.add_decl_errors
(Option.bind
tc Cls.decl_errors
);
1597 Typing_check_decls.class_
env c
;
1598 NastInitCheck.class_
env c
;
1601 (* This can happen if there was an error during the declaration
1605 (* If there are duplicate definitions of the class then we will end up
1606 * checking one AST with respect to the decl corresponding to the other definition.
1607 * Naming has already detected duplicates, so let's just avoid cascading unhelpful
1608 * typing errors, and also avoid triggering the bad position assert
1610 if not
(Pos.equal
(fst c
.c_name
) (Cls.pos tc)) then
1613 let env = Typing_requirements.check_class
env tc in
1614 if shallow_decl_enabled ctx then Typing_inheritance.check_class
env tc;
1615 Some
(class_def_ env c
tc)
1617 let gconst_def ctx cst
=
1618 Counters.count
Counters.Category.Typecheck
@@ fun () ->
1619 Errors.run_with_span cst
.cst_span
@@ fun () ->
1620 let env = EnvFromDef.gconst_env ~origin
:Decl_counters.TopLevel
ctx cst
in
1621 let env = Env.set_env_pessimize
env in
1622 let (typed_cst_value
, env) =
1623 let value = cst
.cst_value
in
1624 match cst
.cst_type
with
1626 let ty = Decl_hint.hint
env.decl_env hint
in
1627 let ty = Typing_enforceability.compute_enforced_ty
env ty in
1628 let (env, dty
) = Phase.localize_possibly_enforced_with_self
env ty in
1629 let (env, te, value_type
) =
1631 ExpectedTy.make_and_allow_coercion
(fst hint
) Reason.URhint dty
1633 expr_with_pure_coeffects env ~
expected value
1636 Typing_coercion.coerce_type
1647 (not
(is_literal_expr value))
1648 && Partial.should_check_error cst
.cst_mode
2035
1650 Errors.missing_typehint
(fst cst
.cst_name
);
1651 let (env, te, _value_type
) = expr_with_pure_coeffects env value in
1655 Aast.cst_annotation
= Env.save
(Env.get_tpenv
env) env;
1656 Aast.cst_mode
= cst
.cst_mode
;
1657 Aast.cst_name
= cst
.cst_name
;
1658 Aast.cst_type
= cst
.cst_type
;
1659 Aast.cst_value
= typed_cst_value
;
1660 Aast.cst_namespace
= cst
.cst_namespace
;
1661 Aast.cst_span
= cst
.cst_span
;
1662 Aast.cst_emit_id
= cst
.cst_emit_id
;
1665 let record_field env f
=
1666 let (id, hint
, e
) = f
in
1667 let ((p, _
) as cty
) = hint
in
1669 let cty = Decl_hint.hint
env.decl_env
cty in
1670 Phase.localize_with_self
env cty
1672 let expected = ExpectedTy.make
p Reason.URhint
cty in
1675 let (env, te, ty) = expr_with_pure_coeffects env ~
expected e
in
1677 Typing_coercion.coerce_type
1682 (MakeType.unenforced
cty)
1683 Errors.record_init_value_does_not_match_hint
1685 (env, (id, hint
, Some
te))
1686 | None
-> (env, (id, hint
, None
))
1688 let record_def_parent env rd parent_hint
=
1689 match snd parent_hint
with
1690 | Aast.Happly
((parent_pos, parent_name), []) ->
1691 (match Decl_provider.get_record_def
(Env.get_ctx
env) parent_name with
1693 (* We can only inherit from abstract records. *)
1694 ( if not parent_rd
.rdt_abstract
then
1695 let (parent_pos, parent_name) = parent_rd
.rdt_name
in
1696 Errors.extend_non_abstract_record
1701 (* Ensure we aren't defining fields that overlap with
1702 inherited fields. *)
1703 let inherited_fields = Typing_helpers.all_record_fields
env parent_rd
in
1704 List.iter rd
.rd_fields ~f
:(fun ((pos, name), _
, _
) ->
1705 match SMap.find_opt
name inherited_fields with
1706 | Some
((prev_pos
, _
), _
) ->
1707 Errors.repeated_record_field
name pos prev_pos
1710 (* Something exists with this name (naming succeeded), but it's
1712 Errors.unbound_name
parent_pos parent_name Errors.RecordContext
)
1715 "Record parent was not an Happly. This should have been a syntax error."
1717 (* Report an error if we have inheritance cycles in record declarations. *)
1718 let check_record_inheritance_cycle env ((rd_pos
, rd_name
) : Aast.sid
) : unit =
1719 let rec worker name trace seen
=
1720 match Decl_provider.get_record_def
(Env.get_ctx
env) name with
1722 (match rd
.rdt_extends
with
1723 | Some
(_
, parent_name) when String.equal
parent_name rd_name
->
1724 (* This record is in an inheritance cycle.*)
1725 Errors.cyclic_record_def trace rd_pos
1726 | Some
(_
, parent_name) when SSet.mem
parent_name seen
->
1727 (* There's an inheritance cycle higher in the chain. *)
1729 | Some
(_
, parent_name) ->
1730 worker parent_name (parent_name :: trace
) (SSet.add
parent_name seen
)
1734 worker rd_name
[rd_name
] (SSet.singleton rd_name
)
1736 let record_def_def ctx rd
=
1737 Counters.count
Counters.Category.Typecheck
@@ fun () ->
1738 let env = EnvFromDef.record_def_env ~origin
:Decl_counters.TopLevel
ctx rd
in
1739 (match rd
.rd_extends
with
1740 | Some parent
-> record_def_parent env rd parent
1743 check_record_inheritance_cycle env rd
.rd_name
;
1745 let (env, attributes
) =
1746 List.map_env
env rd
.rd_user_attributes
Typing.user_attribute
1748 let (_env, fields
) = List.map_env
env rd
.rd_fields
record_field in
1750 Aast.rd_annotation
= Env.save
(Env.get_tpenv
env) env;
1751 Aast.rd_name
= rd
.rd_name
;
1752 Aast.rd_extends
= rd
.rd_extends
;
1753 Aast.rd_abstract
= rd
.rd_abstract
;
1754 Aast.rd_fields
= fields
;
1755 Aast.rd_user_attributes
= attributes
;
1756 Aast.rd_namespace
= rd
.rd_namespace
;
1757 Aast.rd_span
= rd
.rd_span
;
1758 Aast.rd_doc_comment
= rd
.rd_doc_comment
;
1759 Aast.rd_emit_id
= rd
.rd_emit_id
;
1762 let nast_to_tast_gienv ~
(do_tast_checks
: bool) ctx nast
:
1763 _
* Typing_inference_env.t_global_with_pos list
=
1764 let convert_def = function
1765 (* Sometimes typing will just return `None` but that should only be the case
1766 * if an error had already been registered e.g. in naming
1770 match fun_def ctx f
with
1771 | Some
(f
, env) -> Some
(Aast.Fun f
, [env])
1774 | Constant gc
-> Some
(Aast.Constant
(gconst_def ctx gc
), [])
1775 | Typedef td
-> Some
(Aast.Typedef
(Typing.typedef_def
ctx td
), [])
1778 match class_def ctx c
with
1779 | Some
(c
, envs
) -> Some
(Aast.Class c
, envs
)
1782 | RecordDef rd
-> Some
(Aast.RecordDef
(record_def_def ctx rd
), [])
1783 (* We don't typecheck top level statements:
1784 * https://docs.hhvm.com/hack/unsupported/top-level
1785 * so just create the minimal env for us to construct a Stmt.
1788 let env = Env.empty
ctx Relative_path.default None
in
1789 Some
(Aast.Stmt
(snd
(Typing.stmt
env s
)), [])
1793 | FileAttributes _
->
1795 "Invalid nodes in NAST. These nodes should be removed during naming."
1797 Nast_check.program
ctx nast
;
1798 let (tast
, envs
) = List.unzip
@@ List.filter_map nast
convert_def in
1799 let envs = List.concat
envs in
1800 if do_tast_checks
then Tast_check.program
ctx tast
;
1803 let nast_to_tast ~do_tast_checks
ctx nast
=
1804 let (tast
, _gienvs
) = nast_to_tast_gienv ~do_tast_checks
ctx nast
in