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