Reverse order in which class elements are added to ShallowDeclStore
[hiphop-php.git] / hphp / hack / src / rupro / hackrs / shallow_decl_provider / store.rs
bloba5bac2611b566ee7abb32b1e1b466cb358f51229
1 // Copyright (c) Facebook, Inc. and its affiliates.
2 //
3 // This source code is licensed under the MIT license found in the
4 // LICENSE file in the "hack" directory of this source tree.
6 use super::TypeDecl;
7 use anyhow::Result;
8 use datastore::Store;
9 use pos::{ConstName, FunName, MethodName, ModuleName, PropName, TypeName};
10 use std::sync::Arc;
11 use ty::decl::{
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.
19 ///
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.
25 #[derive(Debug)]
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> {
44     pub fn new(
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>>>,
54     ) -> Self {
55         Self {
56             types,
57             funs,
58             consts,
59             modules,
60             properties,
61             static_properties,
62             methods,
63             static_methods,
64             constructors,
65         }
66     }
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>>>>,
79     ) -> Self {
80         Self {
81             properties: Box::new(PropFinder {
82                 types: Arc::clone(&types),
83             }),
84             static_properties: Box::new(StaticPropFinder {
85                 types: Arc::clone(&types),
86             }),
87             methods: Box::new(MethodFinder {
88                 types: Arc::clone(&types),
89             }),
90             static_methods: Box::new(StaticMethodFinder {
91                 types: Arc::clone(&types),
92             }),
93             constructors: Box::new(ConstructorFinder {
94                 types: Arc::clone(&types),
95             }),
97             types,
98             funs,
99             consts,
100             modules,
101         }
102     }
104     pub fn add_decls(&self, decls: Vec<Decl<R>>) -> Result<()> {
105         for decl in decls {
106             match decl {
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)))?
111                 }
112                 Decl::Const(name, decl) => self.consts.insert(name, Arc::new(decl))?,
113                 Decl::Module(name, decl) => self.modules.insert(name, Arc::new(decl))?,
114             }
115         }
116         Ok(())
117     }
119     pub fn get_type(&self, name: TypeName) -> Result<Option<TypeDecl<R>>> {
120         self.types.get(name)
121     }
123     pub fn get_fun(&self, name: FunName) -> Result<Option<Arc<FunDecl<R>>>> {
124         self.funs.get(name)
125     }
127     pub fn get_const(&self, name: ConstName) -> Result<Option<Arc<ConstDecl<R>>>> {
128         self.consts.get(name)
129     }
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,
135         }))
136     }
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,
142         }))
143     }
145     pub fn get_property_type(
146         &self,
147         class_name: TypeName,
148         property_name: PropName,
149     ) -> Result<Option<Ty<R>>> {
150         self.properties.get((class_name, property_name))
151     }
153     pub fn get_static_property_type(
154         &self,
155         class_name: TypeName,
156         property_name: PropName,
157     ) -> Result<Option<Ty<R>>> {
158         self.static_properties.get((class_name, property_name))
159     }
161     pub fn get_method_type(
162         &self,
163         class_name: TypeName,
164         method_name: MethodName,
165     ) -> Result<Option<Ty<R>>> {
166         self.methods.get((class_name, method_name))
167     }
169     pub fn get_static_method_type(
170         &self,
171         class_name: TypeName,
172         method_name: MethodName,
173     ) -> Result<Option<Ty<R>>> {
174         self.static_methods.get((class_name, method_name))
175     }
177     pub fn get_constructor_type(&self, class_name: TypeName) -> Result<Option<Ty<R>>> {
178         self.constructors.get(class_name)
179     }
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())?
186             }
187         }
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())?
192             }
193         }
194         for meth in cls.methods.iter().rev() {
195             self.methods
196                 .insert((cid, meth.name.id()), meth.ty.clone())?
197         }
198         for meth in cls.static_methods.iter().rev() {
199             self.static_methods
200                 .insert((cid, meth.name.id()), meth.ty.clone())?
201         }
202         if let Some(constructor) = &cls.constructor {
203             self.constructors.insert(cid, constructor.ty.clone())?
204         }
205         self.types.insert(name, TypeDecl::Class(cls))?;
206         Ok(())
207     }
210 /// Looks up props from the `types` Store instead of storing them separately.
211 #[derive(Debug)]
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>>> {
218         Ok(self
219             .types
220             .get(class_name)?
221             .and_then(|decl| match decl {
222                 TypeDecl::Class(cls) => Some(cls),
223                 TypeDecl::Typedef(..) => None,
224             })
225             .and_then(|cls| {
226                 cls.props.iter().rev().find_map(|prop| {
227                     if prop.name.id() == property_name {
228                         prop.ty.clone()
229                     } else {
230                         None
231                     }
232                 })
233             }))
234     }
235     fn insert(&self, _: (TypeName, PropName), _: Ty<R>) -> Result<()> {
236         Ok(())
237     }
238     fn remove_batch(&self, _: &mut dyn Iterator<Item = (TypeName, PropName)>) -> Result<()> {
239         Ok(())
240     }
243 /// Looks up props from the `types` Store instead of storing them separately.
244 #[derive(Debug)]
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>>> {
251         Ok(self
252             .types
253             .get(class_name)?
254             .and_then(|decl| match decl {
255                 TypeDecl::Class(cls) => Some(cls),
256                 TypeDecl::Typedef(..) => None,
257             })
258             .and_then(|cls| {
259                 cls.static_props.iter().rev().find_map(|prop| {
260                     if prop.name.id() == property_name {
261                         prop.ty.clone()
262                     } else {
263                         None
264                     }
265                 })
266             }))
267     }
268     fn insert(&self, _: (TypeName, PropName), _: Ty<R>) -> Result<()> {
269         Ok(())
270     }
271     fn remove_batch(&self, _: &mut dyn Iterator<Item = (TypeName, PropName)>) -> Result<()> {
272         Ok(())
273     }
276 /// Looks up methods from the `types` Store instead of storing them separately.
277 #[derive(Debug)]
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>>> {
284         Ok(self
285             .types
286             .get(class_name)?
287             .and_then(|decl| match decl {
288                 TypeDecl::Class(cls) => Some(cls),
289                 TypeDecl::Typedef(..) => None,
290             })
291             .and_then(|cls| {
292                 cls.methods.iter().rev().find_map(|meth| {
293                     if meth.name.id() == method_name {
294                         Some(meth.ty.clone())
295                     } else {
296                         None
297                     }
298                 })
299             }))
300     }
301     fn insert(&self, _: (TypeName, MethodName), _: Ty<R>) -> Result<()> {
302         Ok(())
303     }
304     fn remove_batch(&self, _: &mut dyn Iterator<Item = (TypeName, MethodName)>) -> Result<()> {
305         Ok(())
306     }
309 /// Looks up methods from the `types` Store instead of storing them separately.
310 #[derive(Debug)]
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>>> {
317         Ok(self
318             .types
319             .get(class_name)?
320             .and_then(|decl| match decl {
321                 TypeDecl::Class(cls) => Some(cls),
322                 TypeDecl::Typedef(..) => None,
323             })
324             .and_then(|cls| {
325                 cls.static_methods.iter().rev().find_map(|meth| {
326                     if meth.name.id() == method_name {
327                         Some(meth.ty.clone())
328                     } else {
329                         None
330                     }
331                 })
332             }))
333     }
334     fn insert(&self, _: (TypeName, MethodName), _: Ty<R>) -> Result<()> {
335         Ok(())
336     }
337     fn remove_batch(&self, _: &mut dyn Iterator<Item = (TypeName, MethodName)>) -> Result<()> {
338         Ok(())
339     }
342 /// Looks up constructors from the `types` Store instead of storing them separately.
343 #[derive(Debug)]
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>>> {
350         Ok(self
351             .types
352             .get(class_name)?
353             .and_then(|decl| match decl {
354                 TypeDecl::Class(cls) => Some(cls),
355                 TypeDecl::Typedef(..) => None,
356             })
357             .and_then(|cls| cls.constructor.as_ref().map(|meth| meth.ty.clone())))
358     }
359     fn insert(&self, _: TypeName, _: Ty<R>) -> Result<()> {
360         Ok(())
361     }
362     fn remove_batch(&self, _: &mut dyn Iterator<Item = TypeName>) -> Result<()> {
363         Ok(())
364     }