Check for cyclic class definitions
[hiphop-php.git] / hphp / hack / src / decl / decl_defs.ml
blobf3cb30a0388d707da7d6dfcdd76e58d60d9d0ca4
1 (**
2 * Copyright (c) 2016, 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 open Core_kernel
11 open Typing_defs
12 open Pp_type
14 (* Exception representing not finding a class during decl *)
15 exception Decl_not_found of string
17 (* A substitution context contains all the information necessary for
18 * changing the type of an inherited class element to the class that is
19 * inheriting the class element. It's best illustrated via an example.
21 * class A<Ta1, Ta2> { public function test(Ta1 $x, Ta2 $y): void {} }
23 * class B<Tb> extends A<Tb, int> {}
25 * class C extends B<string> {}
27 * The method `A::test()` has the type (function(Ta1, Ta2): void) in the
28 * context of class A. However in the context of class B, it will have type
29 * (function(Tb, int): void).
31 * The substitution that leads to this change is [Ta1 -> Tb, Ta2 -> int],
32 * which will produce a new type in the context of class B. It's subst_context
33 * would then be:
35 * { sc_subst = [Ta1 -> Tb, Ta2 -> int];
36 * sc_class_context = 'B';
37 * sc_from_req_extends = false;
38 * }
40 * The `sc_from_req_extends` field is set to true if the context was inherited
41 * via a require extends type. This information is relevant when folding
42 * `dc_substs` during inheritance. See Decl_inherit module.
44 type subst_context = {
45 sc_subst : decl ty SMap.t;
46 sc_class_context : string;
47 sc_from_req_extends : bool;
48 } [@@deriving show]
50 type source_type = Child | Parent | Trait | XHPAttr | Interface | ReqImpl | ReqExtends
51 [@@deriving show]
53 type mro_element = {
54 (* The class's name *)
55 mro_name : string;
56 (* The position at which this element was directly included in the hierarchy.
57 If C extends B extends A, the use_pos of A in C's linearization will be the
58 position of the class name A in the line "class B extends A". *)
59 mro_use_pos : Pos.t;
60 (* Like mro_use_pos, but includes type arguments (if any). *)
61 mro_ty_pos : Pos.t;
62 (* The type arguments with which this ancestor class was instantiated. The
63 first class in the linearization (the one which was linearized) will have
64 an empty list here, even when it takes type parameters. *)
65 mro_type_args : decl ty list;
66 (* True if this element referred to a class whose definition could not be
67 found. This is always indicative of an "Unbound name" error (emitted by
68 Naming), so one could imagine omitting elements with this flag set from the
69 linearization (since correct programs will not have them), but keeping
70 track of them helps reduce cascading errors in the event of a typo.
71 Additionally, it's helpful to do this (for now) to keep the behavior of
72 shallow_class_decl equivalent to legacy decl. *)
73 mro_class_not_found : bool;
74 (* When this is [Some], this mro_element represents an attempt to include a
75 linearization within itself. We include these in the linearization for the
76 sake of error reporting (they will not occur in correct programs). The
77 SSet.t is the set of class names known to have been involved in the
78 inclusion of this class in the linearization. *)
79 mro_cyclic : SSet.t option;
80 (* If this element is included in the linearization because it was directly
81 required by some ancestor, this will be [Some], and the position will be
82 the location where this requirement was most recently included into the
83 hierarchy. *)
84 mro_required_at : Pos.t option;
85 (* True if this element is included in the linearization (directly or
86 indirectly) because of a require extends or require implements
87 relationship. *)
88 mro_synthesized : bool;
89 (* True if this element is included in the linearization because of any
90 XHP-attribute-inclusion relationship, and thus, the linearized class
91 inherits only the XHP attributes from this element. *)
92 mro_xhp_attrs_only : bool;
93 (* True if this element is included in the linearization because of a
94 interface-implementation relationship, and thus, the linearized class
95 inherits only the class constants and type constants from this element. *)
96 mro_consts_only : bool;
97 (* True if this element is included in the linearization via an unbroken chain
98 of trait-use relationships, and thus, the linearized class inherits the
99 private members of this element (on account of the runtime behavior where
100 they are effectively copied into the linearized class). *)
101 mro_copy_private_members : bool;
102 (* True if this element is included in the linearization via an unbroken chain
103 of abstract classes, and thus, abstract type constants with default values
104 are inherited unchanged. When this flag is not set, a concrete class was
105 present in the chain. Since we convert abstract type constants with
106 defaults to concrete ones when they are included in a concrete class, any
107 type constant which 1) is abstract, 2) has a default, and 3) was inherited
108 from an ancestor with this flag not set, should be inherited as a concrete
109 type constant instead. *)
110 mro_passthrough_abstract_typeconst : bool;
112 } [@@deriving show]
114 type linearization = mro_element Sequence.t
116 type decl_class_type = {
117 dc_need_init : bool;
118 dc_members_fully_known : bool;
119 dc_abstract : bool;
120 dc_final : bool;
121 dc_is_disposable : bool;
122 dc_const : bool;
123 dc_ppl : bool;
124 dc_deferred_init_members : SSet.t;
125 dc_kind : Ast_defs.class_kind;
126 dc_is_xhp : bool;
127 dc_name : string ;
128 dc_pos : Pos.t ;
129 dc_tparams : decl tparam list ;
130 (* class name to the subst_context that must be applied to that class *)
131 dc_substs : subst_context SMap.t;
132 dc_consts : class_const SMap.t;
133 dc_typeconsts : typeconst_type SMap.t;
134 dc_props : element SMap.t;
135 dc_sprops : element SMap.t;
136 dc_methods : element SMap.t;
137 dc_smethods : element SMap.t;
138 dc_construct : element option * consistent_kind;
139 dc_ancestors : decl ty SMap.t ;
140 dc_req_ancestors : requirement list;
141 dc_req_ancestors_extends : SSet.t;
142 dc_extends : SSet.t;
143 dc_sealed_whitelist : SSet.t option;
144 dc_xhp_attr_deps : SSet.t;
145 dc_enum_type : enum_type option;
146 dc_decl_errors : Errors.t option [@opaque];
147 (* this field is used to prevent condition types being filtered
148 in Decl_redecl_service.is_dependent_class_of_any *)
149 dc_condition_types : SSet.t;
150 } [@@deriving show]
152 (* name of condition type for conditional reactivity of methods.
153 If None - method is unconditionally reactive *)
154 and condition_type_name = string option
156 and method_reactivity =
157 | Method_reactive of condition_type_name
158 | Method_shallow of condition_type_name
159 | Method_local of condition_type_name
161 and element = {
162 elt_final : bool;
163 elt_synthesized : bool;
165 (* Only relevant for methods *)
166 elt_override : bool;
167 elt_memoizelsb : bool;
168 elt_abstract : bool;
169 elt_reactivity : method_reactivity option;
171 (* Only relevant for properties *)
172 elt_xhp_attr : xhp_attr option;
173 elt_const: bool;
174 elt_lateinit: bool;
175 elt_lsb: bool;
177 elt_origin : string;
178 elt_visibility : visibility;