Add class-member lookup tables to ShallowDeclCache
[hiphop-php.git] / hphp / hack / src / rupro / lib / shallow_decl_provider / cache.rs
blobd107f9458a3bc1d7c4dba88a634b895204fbccf4
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 crate::cache::Cache;
7 use crate::decl_defs::shallow::{self, ConstDecl, Decl, FunDecl, ShallowClass, TypedefDecl};
8 use crate::decl_defs::DeclTy;
9 use crate::reason::Reason;
10 use pos::{ConstName, FunName, MethodName, PropName, TypeName};
11 use std::sync::Arc;
13 #[derive(Clone, Debug)]
14 pub enum TypeDecl<R: Reason> {
15     Class(Arc<ShallowClass<R>>),
16     Typedef(Arc<TypedefDecl<R>>),
19 /// A cache for shallow declarations (i.e., the information we get from
20 /// decl-parsing a file). The backing caches are permitted to evict their
21 /// contents at any time.
22 ///
23 /// Consumers of a `ShallowDeclCache` expect the member-type accessors
24 /// (`get_method_type`, `get_constructor_type`, etc.) to be performant. For
25 /// instance, if our `Cache` implementations store data in a serialized format,
26 /// looking up a method type should only deserialize that individual method, not
27 /// the entire `ShallowClass` containing that method declaration.
28 #[derive(Debug)]
29 pub struct ShallowDeclCache<R: Reason> {
30     types: Arc<dyn Cache<TypeName, TypeDecl<R>>>,
31     funs: Box<dyn Cache<FunName, Arc<FunDecl<R>>>>,
32     consts: Box<dyn Cache<ConstName, Arc<ConstDecl<R>>>>,
34     // The below tables are intended to be index tables for information stored
35     // in the `types` table (the underlying data is shared via the `Hc` in
36     // `DeclTy`). When inserting or removing from the `types` table, these
37     // indices must be updated.
38     properties: Box<dyn Cache<(TypeName, PropName), DeclTy<R>>>,
39     static_properties: Box<dyn Cache<(TypeName, PropName), DeclTy<R>>>,
40     methods: Box<dyn Cache<(TypeName, MethodName), DeclTy<R>>>,
41     static_methods: Box<dyn Cache<(TypeName, MethodName), DeclTy<R>>>,
42     constructors: Box<dyn Cache<TypeName, DeclTy<R>>>,
45 impl<R: Reason> ShallowDeclCache<R> {
46     pub fn new(
47         types: Arc<dyn Cache<TypeName, TypeDecl<R>>>,
48         funs: Box<dyn Cache<FunName, Arc<FunDecl<R>>>>,
49         consts: Box<dyn Cache<ConstName, Arc<ConstDecl<R>>>>,
50         properties: Box<dyn Cache<(TypeName, PropName), DeclTy<R>>>,
51         static_properties: Box<dyn Cache<(TypeName, PropName), DeclTy<R>>>,
52         methods: Box<dyn Cache<(TypeName, MethodName), DeclTy<R>>>,
53         static_methods: Box<dyn Cache<(TypeName, MethodName), DeclTy<R>>>,
54         constructors: Box<dyn Cache<TypeName, DeclTy<R>>>,
55     ) -> Self {
56         Self {
57             types,
58             funs,
59             consts,
60             properties,
61             static_properties,
62             methods,
63             static_methods,
64             constructors,
65         }
66     }
68     pub fn with_no_eviction() -> Self {
69         use crate::cache::NonEvictingCache;
70         Self::with_no_member_caches(
71             Arc::new(NonEvictingCache::default()),
72             Box::new(NonEvictingCache::default()),
73             Box::new(NonEvictingCache::default()),
74         )
75     }
77     /// Construct a `ShallowDeclCache` which looks up class members from the
78     /// given `types` table rather than maintaining separate member caches.
79     /// Intended to be used with `Cache` implementations which hold on to
80     /// hash-consed `DeclTy`s in memory (rather than storing them in a
81     /// serialized format), so that looking up individual members doesn't
82     /// involve deserializing an entire `ShallowClass`.
83     pub fn with_no_member_caches(
84         types: Arc<dyn Cache<TypeName, TypeDecl<R>>>,
85         funs: Box<dyn Cache<FunName, Arc<FunDecl<R>>>>,
86         consts: Box<dyn Cache<ConstName, Arc<ConstDecl<R>>>>,
87     ) -> Self {
88         Self {
89             properties: Box::new(PropFinder {
90                 types: Arc::clone(&types),
91             }),
92             static_properties: Box::new(StaticPropFinder {
93                 types: Arc::clone(&types),
94             }),
95             methods: Box::new(MethodFinder {
96                 types: Arc::clone(&types),
97             }),
98             static_methods: Box::new(StaticMethodFinder {
99                 types: Arc::clone(&types),
100             }),
101             constructors: Box::new(ConstructorFinder {
102                 types: Arc::clone(&types),
103             }),
105             types,
106             funs,
107             consts,
108         }
109     }
111     pub fn add_decls(&self, decls: Vec<shallow::Decl<R>>) {
112         for decl in decls {
113             match decl {
114                 Decl::Class(name, decl) => self.add_class(name, Arc::new(decl)),
115                 Decl::Fun(name, decl) => self.funs.insert(name, Arc::new(decl)),
116                 Decl::Typedef(name, decl) => {
117                     self.types.insert(name, TypeDecl::Typedef(Arc::new(decl)))
118                 }
119                 Decl::Const(name, decl) => self.consts.insert(name, Arc::new(decl)),
120             }
121         }
122     }
124     pub fn get_type(&self, name: TypeName) -> Option<TypeDecl<R>> {
125         self.types.get(name)
126     }
128     pub fn get_fun(&self, name: FunName) -> Option<Arc<FunDecl<R>>> {
129         self.funs.get(name)
130     }
132     pub fn get_const(&self, name: ConstName) -> Option<Arc<ConstDecl<R>>> {
133         self.consts.get(name)
134     }
136     pub fn get_class(&self, name: TypeName) -> Option<Arc<ShallowClass<R>>> {
137         self.types.get(name).and_then(|decl| match decl {
138             TypeDecl::Class(cls) => Some(cls),
139             TypeDecl::Typedef(..) => None,
140         })
141     }
143     pub fn get_typedef(&self, name: TypeName) -> Option<Arc<TypedefDecl<R>>> {
144         self.types.get(name).and_then(|decl| match decl {
145             TypeDecl::Typedef(td) => Some(td),
146             TypeDecl::Class(..) => None,
147         })
148     }
150     pub fn get_property_type(
151         &self,
152         class_name: TypeName,
153         property_name: PropName,
154     ) -> Option<DeclTy<R>> {
155         self.properties.get((class_name, property_name))
156     }
158     pub fn get_static_property_type(
159         &self,
160         class_name: TypeName,
161         property_name: PropName,
162     ) -> Option<DeclTy<R>> {
163         self.static_properties.get((class_name, property_name))
164     }
166     pub fn get_method_type(
167         &self,
168         class_name: TypeName,
169         method_name: MethodName,
170     ) -> Option<DeclTy<R>> {
171         self.methods.get((class_name, method_name))
172     }
174     pub fn get_static_method_type(
175         &self,
176         class_name: TypeName,
177         method_name: MethodName,
178     ) -> Option<DeclTy<R>> {
179         self.static_methods.get((class_name, method_name))
180     }
182     pub fn get_constructor_type(&self, class_name: TypeName) -> Option<DeclTy<R>> {
183         self.constructors.get(class_name)
184     }
186     fn add_class(&self, name: TypeName, cls: Arc<ShallowClass<R>>) {
187         let cid = cls.name.id();
188         for prop in &cls.props {
189             if let Some(ty) = &prop.ty {
190                 self.properties.insert((cid, prop.name.id()), ty.clone())
191             }
192         }
193         for prop in &cls.static_props {
194             if let Some(ty) = &prop.ty {
195                 self.static_properties
196                     .insert((cid, prop.name.id()), ty.clone())
197             }
198         }
199         for meth in &cls.methods {
200             self.methods.insert((cid, meth.name.id()), meth.ty.clone())
201         }
202         for meth in &cls.static_methods {
203             self.static_methods
204                 .insert((cid, meth.name.id()), meth.ty.clone())
205         }
206         if let Some(constructor) = &cls.constructor {
207             self.constructors.insert(cid, constructor.ty.clone())
208         }
209         self.types.insert(name, TypeDecl::Class(cls))
210     }
213 /// Looks up props from the `types` cache instead of storing them separately.
214 #[derive(Debug)]
215 struct PropFinder<R: Reason> {
216     types: Arc<dyn Cache<TypeName, TypeDecl<R>>>,
219 impl<R: Reason> Cache<(TypeName, PropName), DeclTy<R>> for PropFinder<R> {
220     fn get(&self, (class_name, property_name): (TypeName, PropName)) -> Option<DeclTy<R>> {
221         self.types
222             .get(class_name)
223             .and_then(|decl| match decl {
224                 TypeDecl::Class(cls) => Some(cls),
225                 TypeDecl::Typedef(..) => None,
226             })
227             .and_then(|cls| {
228                 cls.props.iter().rev().find_map(|prop| {
229                     if prop.name.id() == property_name {
230                         prop.ty.clone()
231                     } else {
232                         None
233                     }
234                 })
235             })
236     }
237     fn insert(&self, _: (TypeName, PropName), _: DeclTy<R>) {}
240 /// Looks up props from the `types` cache instead of storing them separately.
241 #[derive(Debug)]
242 struct StaticPropFinder<R: Reason> {
243     types: Arc<dyn Cache<TypeName, TypeDecl<R>>>,
246 impl<R: Reason> Cache<(TypeName, PropName), DeclTy<R>> for StaticPropFinder<R> {
247     fn get(&self, (class_name, property_name): (TypeName, PropName)) -> Option<DeclTy<R>> {
248         self.types
249             .get(class_name)
250             .and_then(|decl| match decl {
251                 TypeDecl::Class(cls) => Some(cls),
252                 TypeDecl::Typedef(..) => None,
253             })
254             .and_then(|cls| {
255                 cls.static_props.iter().rev().find_map(|prop| {
256                     if prop.name.id() == property_name {
257                         prop.ty.clone()
258                     } else {
259                         None
260                     }
261                 })
262             })
263     }
264     fn insert(&self, _: (TypeName, PropName), _: DeclTy<R>) {}
267 /// Looks up methods from the `types` cache instead of storing them separately.
268 #[derive(Debug)]
269 struct MethodFinder<R: Reason> {
270     types: Arc<dyn Cache<TypeName, TypeDecl<R>>>,
273 impl<R: Reason> Cache<(TypeName, MethodName), DeclTy<R>> for MethodFinder<R> {
274     fn get(&self, (class_name, method_name): (TypeName, MethodName)) -> Option<DeclTy<R>> {
275         self.types
276             .get(class_name)
277             .and_then(|decl| match decl {
278                 TypeDecl::Class(cls) => Some(cls),
279                 TypeDecl::Typedef(..) => None,
280             })
281             .and_then(|cls| {
282                 cls.methods.iter().rev().find_map(|meth| {
283                     if meth.name.id() == method_name {
284                         Some(meth.ty.clone())
285                     } else {
286                         None
287                     }
288                 })
289             })
290     }
291     fn insert(&self, _: (TypeName, MethodName), _: DeclTy<R>) {}
294 /// Looks up methods from the `types` cache instead of storing them separately.
295 #[derive(Debug)]
296 struct StaticMethodFinder<R: Reason> {
297     types: Arc<dyn Cache<TypeName, TypeDecl<R>>>,
300 impl<R: Reason> Cache<(TypeName, MethodName), DeclTy<R>> for StaticMethodFinder<R> {
301     fn get(&self, (class_name, method_name): (TypeName, MethodName)) -> Option<DeclTy<R>> {
302         self.types
303             .get(class_name)
304             .and_then(|decl| match decl {
305                 TypeDecl::Class(cls) => Some(cls),
306                 TypeDecl::Typedef(..) => None,
307             })
308             .and_then(|cls| {
309                 cls.static_methods.iter().rev().find_map(|meth| {
310                     if meth.name.id() == method_name {
311                         Some(meth.ty.clone())
312                     } else {
313                         None
314                     }
315                 })
316             })
317     }
318     fn insert(&self, _: (TypeName, MethodName), _: DeclTy<R>) {}
321 /// Looks up constructors from the `types` cache instead of storing them separately.
322 #[derive(Debug)]
323 struct ConstructorFinder<R: Reason> {
324     types: Arc<dyn Cache<TypeName, TypeDecl<R>>>,
327 impl<R: Reason> Cache<TypeName, DeclTy<R>> for ConstructorFinder<R> {
328     fn get(&self, class_name: TypeName) -> Option<DeclTy<R>> {
329         self.types
330             .get(class_name)
331             .and_then(|decl| match decl {
332                 TypeDecl::Class(cls) => Some(cls),
333                 TypeDecl::Typedef(..) => None,
334             })
335             .and_then(|cls| cls.constructor.as_ref().map(|meth| meth.ty.clone()))
336     }
337     fn insert(&self, _: TypeName, _: DeclTy<R>) {}