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 (*****************************************************************************)
11 (* Module used to declare class types.
12 * For each class we want to build a complete type, that is the type of
13 * the methods defined in the class plus everything that was inherited.
15 (*****************************************************************************)
19 open Shallow_decl_defs
22 module Reason
= Typing_reason
23 module Inst
= Decl_instantiate
24 module Attrs
= Typing_defs.Attributes
25 module SN
= Naming_special_names
27 (*****************************************************************************)
28 (* Checking that the kind of a class is compatible with its parent
29 * For example, a class cannot extend an interface, an interface cannot
30 * extend a trait etc ...
32 (*****************************************************************************)
36 (parent_kind
: Ast_defs.class_kind
)
37 (parent_name
: string)
39 (child_kind
: Ast_defs.class_kind
)
40 (child_name
: string) : unit =
41 match (parent_kind
, child_kind
) with
43 | ( (Ast_defs.Cabstract
| Ast_defs.Cnormal
),
44 (Ast_defs.Cabstract
| Ast_defs.Cnormal
) )
45 | (Ast_defs.Cabstract
, Ast_defs.Cenum
)
46 (* enums extend BuiltinEnum under the hood *)
47 | (Ast_defs.Ctrait
, Ast_defs.Ctrait
)
48 | (Ast_defs.Cinterface
, Ast_defs.Cinterface
) ->
51 (* What is disallowed *)
52 Errors.wrong_extend_kind
60 (*****************************************************************************)
61 (* Functions used retrieve everything implemented in parent classes
63 * env: the new environment
64 * parents: the name of all the parents and grand parents of the class this
66 * is_complete: true if all the parents live in Hack
68 (*****************************************************************************)
70 let disallow_trait_reuse (env
: Decl_env.env
) : bool =
71 TypecheckerOptions.disallow_trait_reuse (Decl_env.tcopt env
)
73 let report_reused_trait
74 (parent_type
: Decl_defs.decl_class_type
)
75 (shallow_class
: Shallow_decl_defs.shallow_class
) : string -> unit =
82 * Verifies that a class never reuses the same trait throughout its hierarchy.
84 * Since Hack only has single inheritance and we already put up a warning for
85 * cyclic class hierarchies, if there is any overlap between our extends and
86 * our parents' extends, that overlap must be a trait.
88 * This does not hold for interfaces because they have multiple inheritance,
89 * but interfaces cannot use traits in the first place.
91 * XHP attribute dependencies don't actually pull the trait into the class,
92 * so we need to track them totally separately.
94 let check_no_duplicate_traits
95 (parent_type
: Decl_defs.decl_class_type
)
96 (shallow_class
: Shallow_decl_defs.shallow_class
)
98 (full_extends
: SSet.t
) : unit =
99 let class_size = SSet.cardinal c_extends
in
100 let parents_size = SSet.cardinal parent_type
.dc_extends
in
101 let full_size = SSet.cardinal full_extends
in
102 if class_size + parents_size > full_size then
103 let duplicates = SSet.inter c_extends parent_type
.dc_extends
in
104 SSet.iter
(report_reused_trait parent_type shallow_class
) duplicates
107 * Adds the traits/classes which are part of a class' hierarchy.
109 * Traits are tracked separately but merged into the parents list when
110 * typechecking so that the class can access the trait members which are
111 * declared as private/protected.
113 let add_grand_parents_or_traits
114 (no_trait_reuse
: bool)
116 (shallow_class
: Shallow_decl_defs.shallow_class
)
117 (acc
: SSet.t
* bool * [> `Extends_pass
| `Xhp_pass
])
118 (parent_type
: Decl_defs.decl_class_type
) : SSet.t
* bool * 'a
=
119 let (extends
, is_complete
, pass
) = acc
in
120 let class_pos = fst shallow_class
.sc_name
in
121 let class_kind = shallow_class
.sc_kind
in
122 let class_name = snd shallow_class
.sc_name
in
123 if phys_equal pass `Extends_pass
then
132 (* If we are crawling the xhp attribute deps, we need to merge their xhp deps
135 if phys_equal pass `Xhp_pass
then
136 SSet.union parent_type
.dc_extends parent_type
.dc_xhp_attr_deps
138 parent_type
.dc_extends
140 let extends'
= SSet.union
extends parent_deps in
141 (* Verify that merging the parent's extends did not introduce trait reuse *)
142 if no_trait_reuse
then
143 check_no_duplicate_traits parent_type shallow_class
extends extends'
;
144 (extends'
, parent_type
.dc_members_fully_known
&& is_complete
, pass
)
146 let get_class_parent_or_trait
148 (shallow_class
: Shallow_decl_defs.shallow_class
)
149 ((parents
, is_complete
, pass
) :
150 SSet.t
* bool * [> `Extends_pass
| `Xhp_pass
])
151 (ty
: Typing_defs.decl_phase
Typing_defs.ty
) : SSet.t
* bool * 'a
=
152 (* See comment on check_no_duplicate_traits for reasoning here *)
154 disallow_trait_reuse env
155 && (not
(phys_equal pass `Xhp_pass
))
156 && not
Ast_defs.(equal_class_kind shallow_class
.sc_kind Cinterface
)
158 let (_
, (parent_pos
, parent
), _
) = Decl_utils.unwrap_class_type ty
in
159 (* If we already had this exact trait, we need to flag trait reuse *)
160 let reused_trait = no_trait_reuse && SSet.mem parent parents
in
161 let parents = SSet.add parent
parents in
162 let parent_type = Decl_env.get_class_dep env parent
in
163 match parent_type with
165 (* The class lives in PHP *)
166 (parents, false, pass
)
167 | Some
parent_type ->
168 (* The parent class lives in Hack, so we can report reused traits *)
169 if reused_trait then report_reused_trait parent_type shallow_class parent
;
170 let acc = (parents, is_complete
, pass
) in
171 add_grand_parents_or_traits
178 let get_class_parents_and_traits
179 (env
: Decl_env.env
) (shallow_class
: Shallow_decl_defs.shallow_class
) :
180 SSet.t
* SSet.t
* bool =
181 let parents = SSet.empty
in
182 let is_complete = true in
183 (* extends parents *)
184 let acc = (parents, is_complete, `Extends_pass
) in
185 let (parents, is_complete, _
) =
187 shallow_class
.sc_extends
188 ~f
:(get_class_parent_or_trait env shallow_class
)
192 let acc = (parents, is_complete, `Traits_pass
) in
193 let (parents, is_complete, _
) =
195 shallow_class
.sc_uses
196 ~f
:(get_class_parent_or_trait env shallow_class
)
199 (* XHP classes whose attributes were imported via "attribute :foo;" syntax *)
200 let acc = (SSet.empty
, is_complete, `Xhp_pass
) in
201 let (xhp_parents
, is_complete, _
) =
203 shallow_class
.sc_xhp_attr_uses
204 ~f
:(get_class_parent_or_trait env shallow_class
)
207 (parents, xhp_parents
, is_complete)
210 ctx
: Provider_context.t
;
214 let check_if_cyclic (class_env
: class_env
) ((pos
, cid
) : Pos.t
* string) : bool
216 let stack = class_env
.stack in
217 let is_cyclic = SSet.mem cid
stack in
218 if is_cyclic then Errors.cyclic_class_def
stack pos
;
221 let shallow_decl_enabled (ctx
: Provider_context.t
) : bool =
222 TypecheckerOptions.shallow_class_decl
(Provider_context.get_tcopt ctx
)
226 (acc : Typing_defs.pu_enum_type
SMap.t
)
227 (spu
: Shallow_decl_defs.shallow_pu_enum
) : Typing_defs.pu_enum_type
SMap.t
229 let spu_name = snd spu
.spu_name in
231 match SMap.find_opt
spu_name acc with
232 | None
-> Decl_to_typing.shallow_pu_enum_to_pu_enum_type origin spu
234 let origin = { pu_class
= origin; pu_enum
= spu_name } in
236 tpu_name
= spu
.spu_name;
237 tpu_is_final
= spu
.spu_is_final
;
241 ~init
:tpu.tpu_case_types
243 let sid = snd tp
.tp_name
in
244 SMap.add
sid (origin, tp
) acc);
248 ~init
:tpu.tpu_case_values
249 ~f
:(fun acc (name
, dty
) ->
250 SMap.add
(snd name
) (origin, name
, dty
) acc);
252 List.fold_left spu
.spu_members ~init
:tpu.tpu_members ~f
:(fun acc sm
->
254 match SMap.find_opt
(snd sm
.spum_atom
) acc with
256 | Some tm
-> tm
.tpum_types
259 match SMap.find_opt
(snd sm
.spum_atom
) acc with
261 | Some tm
-> tm
.tpum_exprs
267 ~f
:(fun acc (sid, declty
) ->
269 SMap.add
k (origin, sid, declty
) acc)
272 List.fold_left sm
.spum_exprs ~init
:tpum_exprs ~f
:(fun acc k ->
273 SMap.add
(snd
k) (origin, k) acc)
278 tpum_atom
= sm
.spum_atom
;
279 tpum_origin
= origin;
286 SMap.add
(snd spu
.spu_name) tpu acc
288 let rec class_decl_if_missing
289 ~
(sh
: SharedMem.uses
) (class_env
: class_env
) (c
: Nast.class_
) :
290 (string * Decl_defs.decl_class_type
) option =
291 let ((_
, cid
) as c_name
) = c
.c_name
in
292 if check_if_cyclic class_env c_name
then
294 else if shallow_decl_enabled class_env
.ctx
then
295 (* This function is often called for its side effect of ensuring that the
296 class is declared. When shallow-decl is enabled, we still want this
297 side effect (for use cases like on-the-fly declaring entire files in
298 Decl_redecl_service for incremental typechecking), but since we are not
299 producing a folded class declaration, there is nothing we can return.
300 This is a code smell--we should use a function with a different
301 signature when we only want this side effect. *)
302 let (_
: shallow_class
) =
303 Shallow_classes_provider.decl class_env
.ctx ~use_cache
:true c
307 match Decl_heap.Classes.get cid
with
308 | Some class_
-> Some
(cid
, class_
)
310 (* Class elements are in memory if and only if the class itself is there.
311 * Exiting before class declaration is ready would break this invariant *)
312 WorkerCancel.with_no_cancellations
@@ fun () ->
313 let class_ = class_naming_and_decl ~sh class_env cid c
in
316 and class_naming_and_decl
317 ~
(sh
: SharedMem.uses
)
318 (class_env
: class_env
)
320 (c
: Nast.class_) : string * Decl_defs.decl_class_type
=
321 let class_env = { class_env with stack = SSet.add cid
class_env.stack } in
323 Shallow_classes_provider.decl
class_env.ctx ~use_cache
:false c
326 Errors.do_
(fun () ->
327 class_parents_decl ~sh
class_env shallow_class;
328 class_decl ~sh
class_env.ctx
shallow_class)
330 let name = snd
shallow_class.sc_name
in
331 let class_ = { tc
with dc_decl_errors
= Some errors
} in
332 Decl_heap.Classes.add
name class_;
335 and class_parents_decl
336 ~
(sh
: SharedMem.uses
)
337 (class_env : class_env)
338 (c
: Shallow_decl_defs.shallow_class) : unit =
339 let class_type class_ =
340 let (_
: Decl_defs.decl_class_type
option) =
341 class_type_decl ~sh
class_env class_
345 List.iter c
.sc_extends
class_type;
346 List.iter c
.sc_implements
class_type;
347 List.iter c
.sc_uses
class_type;
348 List.iter c
.sc_xhp_attr_uses
class_type;
349 List.iter c
.sc_req_extends
class_type;
350 List.iter c
.sc_req_implements
class_type;
352 Aast.enum_includes_map ~f
:(fun et
-> et
.te_includes
) c
.sc_enum_type
354 List.iter
enum_includes class_type;
357 and is_disposable_type
(env
: Decl_env.env
) (hint
: Typing_defs.decl_ty
) : bool
359 match get_node hint
with
360 | Tapply
((_
, c
), _
) ->
362 match Decl_env.get_class_dep env c
with
364 | Some c
-> c
.dc_is_disposable
369 ~
(sh
: SharedMem.uses
) (class_env : class_env) (hint
: Typing_defs.decl_ty
)
370 : Decl_defs.decl_class_type
option =
371 match get_node hint
with
372 | Tapply
((_
, cid
), _
) ->
374 match Naming_provider.get_class_path
class_env.ctx cid
with
375 | Some fn
when not
(Decl_heap.Classes.mem cid
) ->
376 (* We are supposed to redeclare the class *)
377 let class_opt = Ast_provider.find_class_in_file
class_env.ctx fn cid
in
378 Errors.run_in_context fn
Errors.Decl
(fun () ->
380 class_opt >>= class_decl_if_missing ~sh
class_env >>| snd
))
384 (* This class lives in PHP land *)
387 and class_is_abstract
(c
: Shallow_decl_defs.shallow_class) : bool =
390 | Ast_defs.Cinterface
396 (* When all type constants have been inherited and declared, this step synthesizes
397 * the defaults of abstract type constants into concrete type constants. *)
398 and synthesize_defaults
400 (tc
: Typing_defs.typeconst_type
)
401 ((typeconsts
, consts
) :
402 Typing_defs.typeconst_type
SMap.t
* Typing_defs.class_const
SMap.t
) :
403 Typing_defs.typeconst_type
SMap.t
* Typing_defs.class_const
SMap.t
=
404 match tc
.ttc_abstract
with
405 | TCAbstract
(Some default
) ->
409 ttc_abstract
= TCConcrete
;
410 ttc_constraint
= None
;
411 ttc_type
= Some default
;
414 let typeconsts = SMap.add
k concrete typeconsts in
415 (* OCaml 4.06 has an update method that makes this operation much more ergonomic *)
416 let constant = SMap.find_opt
k consts
in
418 Option.value_map
constant ~default
:consts ~f
:(fun c
->
419 SMap.add
k { c
with cc_abstract
= false } consts)
422 | _
-> (typeconsts, consts)
425 ~
(sh
: SharedMem.uses
)
426 (ctx
: Provider_context.t
)
427 (c
: Shallow_decl_defs.shallow_class) : Decl_defs.decl_class_type
=
428 let is_abstract = class_is_abstract c
in
429 let const = Attrs.mem
SN.UserAttributes.uaConst c
.sc_user_attributes
in
430 let (_p
, cls_name
) = c
.sc_name
in
431 let class_dep = Dep.Class cls_name
in
432 let env = { Decl_env.mode
= c
.sc_mode
; droot
= Some
class_dep; ctx
} in
433 let inherited = Decl_inherit.make
env c
in
434 let props = inherited.Decl_inherit.ih_props
in
436 List.fold_left ~f
:(prop_decl ~write_shmem
:true c
) ~init
:props c
.sc_props
438 let m = inherited.Decl_inherit.ih_methods
in
439 let (m, condition_types
) =
441 ~f
:(method_decl_acc ~write_shmem
:true ~is_static
:false c
)
442 ~init
:(m, SSet.empty
)
445 let consts = inherited.Decl_inherit.ih_consts
in
447 List.fold_left ~f
:(class_const_fold c
) ~init
:consts c
.sc_consts
449 let consts = SMap.add
SN.Members.mClass
(class_class_decl c
.sc_name
) consts in
450 let typeconsts = inherited.Decl_inherit.ih_typeconsts
in
451 let (typeconsts, consts) =
454 ~f
:(typeconst_fold c
)
455 ~init
:(typeconsts, consts)
457 let (typeconsts, consts) =
458 if Ast_defs.(equal_class_kind c
.sc_kind Cnormal
) then
459 SMap.fold synthesize_defaults
typeconsts (typeconsts, consts)
463 let pu_enums = inherited.Decl_inherit.ih_pu_enums
in
465 List.fold_left c
.sc_pu_enums ~f
:(pu_enum_fold cls_name
) ~init
:pu_enums
467 let sclass_var = static_prop_decl ~write_shmem
:true c
in
468 let sprops = inherited.Decl_inherit.ih_sprops
in
469 let sprops = List.fold_left c
.sc_sprops ~f
:sclass_var ~init
:sprops in
470 let sm = inherited.Decl_inherit.ih_smethods
in
471 let (sm, condition_types
) =
474 ~f
:(method_decl_acc ~write_shmem
:true ~is_static
:true c
)
475 ~init
:(sm, condition_types
)
477 let parent_cstr = inherited.Decl_inherit.ih_cstr
in
478 let cstr = constructor_decl ~sh
parent_cstr c
in
479 let has_concrete_cstr =
482 | Some elt
when get_elt_abstract elt
-> false
485 let impl = c
.sc_extends
@ c
.sc_implements
@ c
.sc_uses
in
488 List.find c
.sc_methods ~f
:(fun sm ->
489 String.equal
(snd
sm.sm_name
) SN.Members.__toString
)
491 | Some
{ sm_name
= (pos
, _
); _
}
492 when String.( <> ) cls_name
SN.Classes.cStringish
->
493 (* HHVM implicitly adds Stringish interface for every class/iface/trait
494 * with a __toString method; "string" also implements this interface *)
495 (* Declare Stringish and parents if not already declared *)
496 let class_env = { ctx
; stack = SSet.empty
} in
498 mk
(Reason.Rhint pos
, Tapply
((pos
, SN.Classes.cStringish
), []))
500 let (_
: Decl_defs.decl_class_type
option) =
501 class_type_decl ~sh
class_env ty
506 let impl = List.map
impl (get_implements
env) in
507 let impl = List.fold_right
impl ~f
:(SMap.fold
SMap.add
) ~init
:SMap.empty
in
508 let (extends, xhp_attr_deps
, ext_strict
) =
509 get_class_parents_and_traits env c
511 let (req_ancestors
, req_ancestors_extends
) =
512 Decl_requirements.get_class_requirements
env c
514 (* Interfaces IDisposable and IAsyncDisposable are *disposable types*, as
515 * are any classes that implement either of these interfaces, directly or
516 * indirectly. Also treat any trait that *requires* extension or
517 * implementation of a disposable class as disposable itself.
519 let is_disposable_class_name cls_name
=
520 String.equal cls_name
SN.Classes.cIDisposable
521 || String.equal cls_name
SN.Classes.cIAsyncDisposable
524 is_disposable_class_name cls_name
525 || SMap.exists
(fun n _
-> is_disposable_class_name n
) impl
527 (c
.sc_req_extends
@ c
.sc_req_implements
)
528 (is_disposable_type
env)
530 (* If this class is disposable then we require that any extended class or
531 * trait that is used, is also disposable, in order that escape analysis
532 * has been applied on the $this parameter.
535 List.fold_left c
.sc_uses ~f
:(trait_exists
env) ~init
:ext_strict
537 let enum = c
.sc_enum_type
in
538 let enum_inner_ty = SMap.find_opt
SN.FB.tInner
typeconsts in
540 Decl_enum.rewrite_class
543 Option.(enum_inner_ty >>= fun t
-> t
.ttc_type
)
544 (fun x
-> SMap.find_opt x
impl)
547 let has_own_cstr = has_concrete_cstr && Option.is_some c
.sc_constructor
in
548 let deferred_members =
549 if shallow_decl_enabled ctx
then
552 snd
(Decl_init_check.class_ ~
has_own_cstr env c
)
554 let sealed_whitelist = get_sealed_whitelist c
in
557 dc_final
= c
.sc_final
;
559 dc_abstract
= is_abstract;
560 dc_need_init
= has_concrete_cstr;
561 dc_deferred_init_members
= deferred_members;
562 dc_members_fully_known
= ext_strict;
564 dc_is_xhp
= c
.sc_is_xhp
;
565 dc_has_xhp_keyword
= c
.sc_has_xhp_keyword
;
566 dc_is_disposable
= is_disposable;
567 dc_name
= snd c
.sc_name
;
568 dc_pos
= fst c
.sc_name
;
569 dc_tparams
= c
.sc_tparams
;
570 dc_where_constraints
= c
.sc_where_constraints
;
571 dc_substs
= inherited.Decl_inherit.ih_substs
;
573 dc_typeconsts
= typeconsts;
574 dc_pu_enums
= pu_enums;
581 dc_extends
= extends;
582 dc_sealed_whitelist
= sealed_whitelist;
583 dc_xhp_attr_deps
= xhp_attr_deps
;
584 dc_req_ancestors
= req_ancestors
;
585 dc_req_ancestors_extends
= req_ancestors_extends
;
587 dc_decl_errors
= None
;
588 dc_condition_types
= condition_types
;
594 Typing_deps.add_idep
class_dep (Dep.Class x
)
599 and get_sealed_whitelist
(c
: Shallow_decl_defs.shallow_class) : SSet.t
option =
600 match Attributes.find
SN.UserAttributes.uaSealed c
.sc_user_attributes
with
602 | Some
{ ua_classname_params
; _
} -> Some
(SSet.of_list ua_classname_params
)
604 and get_implements
(env : Decl_env.env) (ht
: Typing_defs.decl_ty
) :
605 Typing_defs.decl_ty
SMap.t
=
606 let (_r
, (_p
, c
), paraml
) = Decl_utils.unwrap_class_type ht
in
607 let class_ = Decl_env.get_class_dep
env c
in
610 (* The class lives in PHP land *)
613 let subst = Inst.make_subst
class_.dc_tparams paraml
in
615 SMap.map
(fun ty -> Inst.instantiate
subst ty) class_.dc_ancestors
617 SMap.add c ht
sub_implements
619 and trait_exists
(env : Decl_env.env) (acc : bool) (trait
: Typing_defs.decl_ty
)
621 match get_node trait
with
622 | Tapply
((_
, trait
), _
) ->
623 let class_ = Decl_env.get_class_dep
env trait
in
626 | Some _class
-> acc)
630 ~
(sh
: SharedMem.uses
)
631 ((pcstr
, pconsist
) : Decl_defs.element
option * Typing_defs.consistent_kind
)
632 (class_ : Shallow_decl_defs.shallow_class) :
633 Decl_defs.element
option * Typing_defs.consistent_kind
=
634 let SharedMem.Uses
= sh
in
635 (* constructors in children of class_ must be consistent? *)
637 if class_.sc_final
then
641 SN.UserAttributes.uaConsistentConstruct
642 class_.sc_user_attributes
649 match class_.sc_constructor
with
651 | Some method_
-> build_constructor ~write_shmem
:true class_ method_
653 (cstr, Decl_utils.coalesce_consistent pconsist
cconsist)
655 and build_constructor
656 ~
(write_shmem
: bool)
657 (class_ : Shallow_decl_defs.shallow_class)
658 (method_
: Shallow_decl_defs.shallow_method
) : Decl_defs.element
option =
659 let (_
, class_name) = class_.sc_name
in
660 let vis = visibility
class_name method_
.sm_visibility
in
661 let pos = fst method_
.sm_name
in
667 ~final
:method_
.sm_final
668 ~abstract
:method_
.sm_abstract
675 ~dynamicallycallable
:false;
676 elt_visibility
= vis;
677 elt_origin
= class_name;
678 elt_reactivity
= None
;
679 elt_deprecated
= method_
.sm_deprecated
;
685 fe_deprecated
= method_
.sm_deprecated
;
686 fe_type
= method_
.sm_type
;
687 fe_php_std_lib
= false;
690 if write_shmem
then Decl_heap.Constructors.add
class_name fe;
694 (c
: Shallow_decl_defs.shallow_class)
695 (acc : Typing_defs.class_const
SMap.t
)
696 (scc
: Shallow_decl_defs.shallow_class_const
) :
697 Typing_defs.class_const
SMap.t
=
698 let c_name = snd c
.sc_name
in
701 cc_synthesized
= false;
702 cc_abstract
= scc
.scc_abstract
;
703 cc_pos
= fst scc
.scc_name
;
704 cc_type
= scc
.scc_type
;
708 let acc = SMap.add
(snd scc
.scc_name
) cc acc in
711 (* Every class, interface, and trait implicitly defines a ::class to
712 * allow accessing its fully qualified name as a string *)
713 and class_class_decl
(class_id
: Ast_defs.id
) : Typing_defs.class_const
=
714 let (pos, name) = class_id
in
715 let reason = Reason.Rclass_class
(pos, name) in
717 mk
(reason, Tapply
((pos, SN.Classes.cClassname
), [mk
(reason, Tthis
)]))
722 cc_synthesized
= true;
723 cc_type
= classname_ty;
728 ~
(write_shmem
: bool)
729 (c
: Shallow_decl_defs.shallow_class)
730 (acc : Decl_defs.element
SMap.t
)
731 (sp
: Shallow_decl_defs.shallow_prop
) : Decl_defs.element
SMap.t
=
732 let (sp_pos
, sp_name
) = sp
.sp_name
in
734 match sp
.sp_type
with
735 | None
-> mk
(Reason.Rwitness sp_pos
, Typing_defs.make_tany
())
738 let vis = visibility
(snd c
.sc_name
) sp
.sp_visibility
in
743 ~xhp_attr
:sp
.sp_xhp_attr
750 ~lateinit
:sp
.sp_lateinit
751 ~abstract
:sp
.sp_abstract
752 ~dynamicallycallable
:false;
753 elt_visibility
= vis;
754 elt_origin
= snd c
.sc_name
;
755 elt_reactivity
= None
;
756 elt_deprecated
= None
;
759 if write_shmem
then Decl_heap.Props.add
(elt.elt_origin
, sp_name
) ty;
760 let acc = SMap.add sp_name
elt acc in
764 ~
(write_shmem
: bool)
765 (c
: Shallow_decl_defs.shallow_class)
766 (acc : Decl_defs.element
SMap.t
)
767 (sp
: Shallow_decl_defs.shallow_prop
) : Decl_defs.element
SMap.t
=
768 let (sp_pos
, sp_name
) = sp
.sp_name
in
770 match sp
.sp_type
with
771 | None
-> mk
(Reason.Rwitness sp_pos
, Typing_defs.make_tany
())
774 let vis = visibility
(snd c
.sc_name
) sp
.sp_visibility
in
779 ~xhp_attr
:sp
.sp_xhp_attr
782 ~lateinit
:sp
.sp_lateinit
786 ~abstract
:sp
.sp_abstract
788 ~dynamicallycallable
:false;
789 elt_visibility
= vis;
790 elt_origin
= snd c
.sc_name
;
791 elt_reactivity
= None
;
792 elt_deprecated
= None
;
795 if write_shmem
then Decl_heap.StaticProps.add
(elt.elt_origin
, sp_name
) ty;
796 let acc = SMap.add sp_name
elt acc in
799 and visibility
(cid
: string) (visibility
: Aast_defs.visibility
) :
800 Typing_defs.visibility
=
801 match visibility
with
803 | Protected
-> Vprotected cid
804 | Private
-> Vprivate cid
806 (* each concrete type constant T = <sometype> implicitly defines a
807 class constant with the same name which is TypeStructure<sometype> *)
808 and typeconst_structure
809 (c
: Shallow_decl_defs.shallow_class)
810 (stc
: Shallow_decl_defs.shallow_typeconst
) : Typing_defs.class_const
=
811 let pos = fst stc
.stc_name
in
812 let r = Reason.Rwitness
pos in
813 let tsid = (pos, SN.FB.cTypeStructure
) in
815 mk
(r, Tapply
(tsid, [mk
(r, Taccess
(mk
(r, Tthis
), [stc
.stc_name
]))]))
818 match stc
.stc_abstract
with
819 | TCAbstract _
-> true
823 cc_abstract
= abstract;
825 cc_synthesized
= true;
827 cc_origin
= snd c
.sc_name
;
831 (c
: Shallow_decl_defs.shallow_class)
832 (acc : Typing_defs.typeconst_type
SMap.t
* Typing_defs.class_const
SMap.t
)
833 (stc
: Shallow_decl_defs.shallow_typeconst
) :
834 Typing_defs.typeconst_type
SMap.t
* Typing_defs.class_const
SMap.t
=
835 let (typeconsts, consts) = acc in
840 | Ast_defs.Cinterface
842 | Ast_defs.Cnormal
->
843 let name = snd stc
.stc_name
in
844 let c_name = snd c
.sc_name
in
845 let ts = typeconst_structure c stc
in
846 let consts = SMap.add
name ts consts in
847 let ptc_opt = SMap.find_opt
name typeconsts in
849 (* Without the positions, this is a simple OR, but this way allows us to
850 * report the position of the <<__Enforceable>> attribute to the user *)
851 if snd stc
.stc_enforceable
then
855 | Some ptc
-> ptc
.ttc_enforceable
856 | None
-> (Pos.none
, false)
859 if Option.is_some stc
.stc_reifiable
then
862 Option.bind
ptc_opt (fun ptc
-> ptc
.ttc_reifiable
)
866 ttc_abstract
= stc
.stc_abstract
;
867 ttc_name
= stc
.stc_name
;
868 ttc_constraint
= stc
.stc_constraint
;
869 ttc_type
= stc
.stc_type
;
871 ttc_enforceable
= enforceable;
872 ttc_reifiable
= reifiable;
875 let typeconsts = SMap.add
(snd stc
.stc_name
) tc typeconsts in
879 ~
(write_shmem
: bool)
881 (c
: Shallow_decl_defs.shallow_class)
882 ((acc, condition_types
) : Decl_defs.element
SMap.t
* SSet.t
)
883 (m : Shallow_decl_defs.shallow_method
) : Decl_defs.element
SMap.t
* SSet.t
=
884 (* If method doesn't override anything but has the <<__Override>> attribute, then
885 * set the override flag in ce_flags and let typing emit an appropriate error *)
886 let check_override = m.sm_override
&& not
(SMap.mem
(snd
m.sm_name
) acc) in
887 let (pos, id
) = m.sm_name
in
888 let get_reactivity t
=
889 match get_node t
with
890 | Tfun
{ ft_reactive
; _
} -> ft_reactive
893 let condition_types =
894 match get_reactivity m.sm_type
with
900 match get_node
ty with
901 | Tapply
((_
, cls
), []) -> SSet.add cls
condition_types
902 | _
-> condition_types
904 | _
-> condition_types
907 match (SMap.find_opt id
acc, m.sm_visibility
) with
908 | (Some
{ elt_visibility
= Vprotected _
as parent_vis
; _
}, Protected
) ->
910 | _
-> visibility
(snd c
.sc_name
) m.sm_visibility
918 ~
abstract:m.sm_abstract
919 ~override
:check_override
925 ~dynamicallycallable
:m.sm_dynamicallycallable
;
926 elt_visibility
= vis;
927 elt_origin
= snd c
.sc_name
;
928 elt_reactivity
= m.sm_reactivity
;
929 elt_deprecated
= m.sm_deprecated
;
935 fe_deprecated
= None
;
937 fe_php_std_lib
= false;
942 Decl_heap.StaticMethods.add
(elt.elt_origin
, id
) fe
944 Decl_heap.Methods.add
(elt.elt_origin
, id
) fe;
945 let acc = SMap.add id
elt acc in
946 (acc, condition_types)