1 // Copyright (c) Facebook, Inc. and its affiliates.
3 // This source code is licensed under the MIT license found in the
4 // LICENSE file in the "hack" directory of this source tree.
9 use pos::{ConstName, FunName, MethodName, ModuleName, PropName, TypeName};
12 shallow::Decl, shallow::ModuleDecl, ConstDecl, FunDecl, ShallowClass, Ty, TypedefDecl,
14 use ty::reason::Reason;
16 /// A datastore for shallow declarations (i.e., the information we get from
17 /// decl-parsing a file). The backing datastores are permitted to evict their
18 /// contents at any time.
20 /// Consumers of a `ShallowDeclStore` expect the member-type accessors
21 /// (`get_method_type`, `get_constructor_type`, etc.) to be performant. For
22 /// instance, if our `Store` implementations store data in a serialized format,
23 /// looking up a method type should only deserialize that individual method, not
24 /// the entire `ShallowClass` containing that method declaration.
26 pub struct ShallowDeclStore<R: Reason> {
27 types: Arc<dyn Store<TypeName, TypeDecl<R>>>,
28 funs: Box<dyn Store<FunName, Arc<FunDecl<R>>>>,
29 consts: Box<dyn Store<ConstName, Arc<ConstDecl<R>>>>,
30 modules: Box<dyn Store<ModuleName, Arc<ModuleDecl<R>>>>,
32 // The below tables are intended to be index tables for information stored
33 // in the `types` table (the underlying data is shared via the `Hc` in
34 // `Ty`). When inserting or removing from the `types` table, these
35 // indices must be updated.
36 properties: Box<dyn Store<(TypeName, PropName), Ty<R>>>,
37 static_properties: Box<dyn Store<(TypeName, PropName), Ty<R>>>,
38 methods: Box<dyn Store<(TypeName, MethodName), Ty<R>>>,
39 static_methods: Box<dyn Store<(TypeName, MethodName), Ty<R>>>,
40 constructors: Box<dyn Store<TypeName, Ty<R>>>,
43 impl<R: Reason> ShallowDeclStore<R> {
45 types: Arc<dyn Store<TypeName, TypeDecl<R>>>,
46 funs: Box<dyn Store<FunName, Arc<FunDecl<R>>>>,
47 consts: Box<dyn Store<ConstName, Arc<ConstDecl<R>>>>,
48 modules: Box<dyn Store<ModuleName, Arc<ModuleDecl<R>>>>,
49 properties: Box<dyn Store<(TypeName, PropName), Ty<R>>>,
50 static_properties: Box<dyn Store<(TypeName, PropName), Ty<R>>>,
51 methods: Box<dyn Store<(TypeName, MethodName), Ty<R>>>,
52 static_methods: Box<dyn Store<(TypeName, MethodName), Ty<R>>>,
53 constructors: Box<dyn Store<TypeName, Ty<R>>>,
68 /// Construct a `ShallowDeclStore` which looks up class members from the
69 /// given `types` table rather than maintaining separate member stores.
70 /// Intended to be used with `Store` implementations which hold on to
71 /// hash-consed `Ty`s in memory (rather than storing them in a
72 /// serialized format), so that looking up individual members doesn't
73 /// involve deserializing an entire `ShallowClass`.
74 pub fn with_no_member_stores(
75 types: Arc<dyn Store<TypeName, TypeDecl<R>>>,
76 funs: Box<dyn Store<FunName, Arc<FunDecl<R>>>>,
77 consts: Box<dyn Store<ConstName, Arc<ConstDecl<R>>>>,
78 modules: Box<dyn Store<ModuleName, Arc<ModuleDecl<R>>>>,
81 properties: Box::new(PropFinder {
82 types: Arc::clone(&types),
84 static_properties: Box::new(StaticPropFinder {
85 types: Arc::clone(&types),
87 methods: Box::new(MethodFinder {
88 types: Arc::clone(&types),
90 static_methods: Box::new(StaticMethodFinder {
91 types: Arc::clone(&types),
93 constructors: Box::new(ConstructorFinder {
94 types: Arc::clone(&types),
104 pub fn add_decls(&self, decls: Vec<Decl<R>>) -> Result<()> {
107 Decl::Class(name, decl) => self.add_class(name, Arc::new(decl))?,
108 Decl::Fun(name, decl) => self.funs.insert(name, Arc::new(decl))?,
109 Decl::Typedef(name, decl) => {
110 self.types.insert(name, TypeDecl::Typedef(Arc::new(decl)))?
112 Decl::Const(name, decl) => self.consts.insert(name, Arc::new(decl))?,
113 Decl::Module(name, decl) => self.modules.insert(name, Arc::new(decl))?,
119 pub fn get_type(&self, name: TypeName) -> Result<Option<TypeDecl<R>>> {
123 pub fn get_fun(&self, name: FunName) -> Result<Option<Arc<FunDecl<R>>>> {
127 pub fn get_const(&self, name: ConstName) -> Result<Option<Arc<ConstDecl<R>>>> {
128 self.consts.get(name)
131 pub fn get_class(&self, name: TypeName) -> Result<Option<Arc<ShallowClass<R>>>> {
132 Ok(self.types.get(name)?.and_then(|decl| match decl {
133 TypeDecl::Class(cls) => Some(cls),
134 TypeDecl::Typedef(..) => None,
138 pub fn get_typedef(&self, name: TypeName) -> Result<Option<Arc<TypedefDecl<R>>>> {
139 Ok(self.types.get(name)?.and_then(|decl| match decl {
140 TypeDecl::Typedef(td) => Some(td),
141 TypeDecl::Class(..) => None,
145 pub fn get_property_type(
147 class_name: TypeName,
148 property_name: PropName,
149 ) -> Result<Option<Ty<R>>> {
150 self.properties.get((class_name, property_name))
153 pub fn get_static_property_type(
155 class_name: TypeName,
156 property_name: PropName,
157 ) -> Result<Option<Ty<R>>> {
158 self.static_properties.get((class_name, property_name))
161 pub fn get_method_type(
163 class_name: TypeName,
164 method_name: MethodName,
165 ) -> Result<Option<Ty<R>>> {
166 self.methods.get((class_name, method_name))
169 pub fn get_static_method_type(
171 class_name: TypeName,
172 method_name: MethodName,
173 ) -> Result<Option<Ty<R>>> {
174 self.static_methods.get((class_name, method_name))
177 pub fn get_constructor_type(&self, class_name: TypeName) -> Result<Option<Ty<R>>> {
178 self.constructors.get(class_name)
181 fn add_class(&self, name: TypeName, cls: Arc<ShallowClass<R>>) -> Result<()> {
182 let cid = cls.name.id();
183 for prop in cls.props.iter().rev() {
184 if let Some(ty) = &prop.ty {
185 self.properties.insert((cid, prop.name.id()), ty.clone())?
188 for prop in cls.static_props.iter().rev() {
189 if let Some(ty) = &prop.ty {
190 self.static_properties
191 .insert((cid, prop.name.id()), ty.clone())?
194 for meth in cls.methods.iter().rev() {
196 .insert((cid, meth.name.id()), meth.ty.clone())?
198 for meth in cls.static_methods.iter().rev() {
200 .insert((cid, meth.name.id()), meth.ty.clone())?
202 if let Some(constructor) = &cls.constructor {
203 self.constructors.insert(cid, constructor.ty.clone())?
205 self.types.insert(name, TypeDecl::Class(cls))?;
210 /// Looks up props from the `types` Store instead of storing them separately.
212 struct PropFinder<R: Reason> {
213 types: Arc<dyn Store<TypeName, TypeDecl<R>>>,
216 impl<R: Reason> Store<(TypeName, PropName), Ty<R>> for PropFinder<R> {
217 fn get(&self, (class_name, property_name): (TypeName, PropName)) -> Result<Option<Ty<R>>> {
221 .and_then(|decl| match decl {
222 TypeDecl::Class(cls) => Some(cls),
223 TypeDecl::Typedef(..) => None,
226 cls.props.iter().rev().find_map(|prop| {
227 if prop.name.id() == property_name {
235 fn insert(&self, _: (TypeName, PropName), _: Ty<R>) -> Result<()> {
238 fn remove_batch(&self, _: &mut dyn Iterator<Item = (TypeName, PropName)>) -> Result<()> {
243 /// Looks up props from the `types` Store instead of storing them separately.
245 struct StaticPropFinder<R: Reason> {
246 types: Arc<dyn Store<TypeName, TypeDecl<R>>>,
249 impl<R: Reason> Store<(TypeName, PropName), Ty<R>> for StaticPropFinder<R> {
250 fn get(&self, (class_name, property_name): (TypeName, PropName)) -> Result<Option<Ty<R>>> {
254 .and_then(|decl| match decl {
255 TypeDecl::Class(cls) => Some(cls),
256 TypeDecl::Typedef(..) => None,
259 cls.static_props.iter().rev().find_map(|prop| {
260 if prop.name.id() == property_name {
268 fn insert(&self, _: (TypeName, PropName), _: Ty<R>) -> Result<()> {
271 fn remove_batch(&self, _: &mut dyn Iterator<Item = (TypeName, PropName)>) -> Result<()> {
276 /// Looks up methods from the `types` Store instead of storing them separately.
278 struct MethodFinder<R: Reason> {
279 types: Arc<dyn Store<TypeName, TypeDecl<R>>>,
282 impl<R: Reason> Store<(TypeName, MethodName), Ty<R>> for MethodFinder<R> {
283 fn get(&self, (class_name, method_name): (TypeName, MethodName)) -> Result<Option<Ty<R>>> {
287 .and_then(|decl| match decl {
288 TypeDecl::Class(cls) => Some(cls),
289 TypeDecl::Typedef(..) => None,
292 cls.methods.iter().rev().find_map(|meth| {
293 if meth.name.id() == method_name {
294 Some(meth.ty.clone())
301 fn insert(&self, _: (TypeName, MethodName), _: Ty<R>) -> Result<()> {
304 fn remove_batch(&self, _: &mut dyn Iterator<Item = (TypeName, MethodName)>) -> Result<()> {
309 /// Looks up methods from the `types` Store instead of storing them separately.
311 struct StaticMethodFinder<R: Reason> {
312 types: Arc<dyn Store<TypeName, TypeDecl<R>>>,
315 impl<R: Reason> Store<(TypeName, MethodName), Ty<R>> for StaticMethodFinder<R> {
316 fn get(&self, (class_name, method_name): (TypeName, MethodName)) -> Result<Option<Ty<R>>> {
320 .and_then(|decl| match decl {
321 TypeDecl::Class(cls) => Some(cls),
322 TypeDecl::Typedef(..) => None,
325 cls.static_methods.iter().rev().find_map(|meth| {
326 if meth.name.id() == method_name {
327 Some(meth.ty.clone())
334 fn insert(&self, _: (TypeName, MethodName), _: Ty<R>) -> Result<()> {
337 fn remove_batch(&self, _: &mut dyn Iterator<Item = (TypeName, MethodName)>) -> Result<()> {
342 /// Looks up constructors from the `types` Store instead of storing them separately.
344 struct ConstructorFinder<R: Reason> {
345 types: Arc<dyn Store<TypeName, TypeDecl<R>>>,
348 impl<R: Reason> Store<TypeName, Ty<R>> for ConstructorFinder<R> {
349 fn get(&self, class_name: TypeName) -> Result<Option<Ty<R>>> {
353 .and_then(|decl| match decl {
354 TypeDecl::Class(cls) => Some(cls),
355 TypeDecl::Typedef(..) => None,
357 .and_then(|cls| cls.constructor.as_ref().map(|meth| meth.ty.clone())))
359 fn insert(&self, _: TypeName, _: Ty<R>) -> Result<()> {
362 fn remove_batch(&self, _: &mut dyn Iterator<Item = TypeName>) -> Result<()> {