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.
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};
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.
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.
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> {
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>>>,
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()),
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>>>>,
89 properties: Box::new(PropFinder {
90 types: Arc::clone(&types),
92 static_properties: Box::new(StaticPropFinder {
93 types: Arc::clone(&types),
95 methods: Box::new(MethodFinder {
96 types: Arc::clone(&types),
98 static_methods: Box::new(StaticMethodFinder {
99 types: Arc::clone(&types),
101 constructors: Box::new(ConstructorFinder {
102 types: Arc::clone(&types),
111 pub fn add_decls(&self, decls: Vec<shallow::Decl<R>>) {
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)))
119 Decl::Const(name, decl) => self.consts.insert(name, Arc::new(decl)),
124 pub fn get_type(&self, name: TypeName) -> Option<TypeDecl<R>> {
128 pub fn get_fun(&self, name: FunName) -> Option<Arc<FunDecl<R>>> {
132 pub fn get_const(&self, name: ConstName) -> Option<Arc<ConstDecl<R>>> {
133 self.consts.get(name)
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,
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,
150 pub fn get_property_type(
152 class_name: TypeName,
153 property_name: PropName,
154 ) -> Option<DeclTy<R>> {
155 self.properties.get((class_name, property_name))
158 pub fn get_static_property_type(
160 class_name: TypeName,
161 property_name: PropName,
162 ) -> Option<DeclTy<R>> {
163 self.static_properties.get((class_name, property_name))
166 pub fn get_method_type(
168 class_name: TypeName,
169 method_name: MethodName,
170 ) -> Option<DeclTy<R>> {
171 self.methods.get((class_name, method_name))
174 pub fn get_static_method_type(
176 class_name: TypeName,
177 method_name: MethodName,
178 ) -> Option<DeclTy<R>> {
179 self.static_methods.get((class_name, method_name))
182 pub fn get_constructor_type(&self, class_name: TypeName) -> Option<DeclTy<R>> {
183 self.constructors.get(class_name)
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())
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())
199 for meth in &cls.methods {
200 self.methods.insert((cid, meth.name.id()), meth.ty.clone())
202 for meth in &cls.static_methods {
204 .insert((cid, meth.name.id()), meth.ty.clone())
206 if let Some(constructor) = &cls.constructor {
207 self.constructors.insert(cid, constructor.ty.clone())
209 self.types.insert(name, TypeDecl::Class(cls))
213 /// Looks up props from the `types` cache instead of storing them separately.
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>> {
223 .and_then(|decl| match decl {
224 TypeDecl::Class(cls) => Some(cls),
225 TypeDecl::Typedef(..) => None,
228 cls.props.iter().rev().find_map(|prop| {
229 if prop.name.id() == property_name {
237 fn insert(&self, _: (TypeName, PropName), _: DeclTy<R>) {}
240 /// Looks up props from the `types` cache instead of storing them separately.
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>> {
250 .and_then(|decl| match decl {
251 TypeDecl::Class(cls) => Some(cls),
252 TypeDecl::Typedef(..) => None,
255 cls.static_props.iter().rev().find_map(|prop| {
256 if prop.name.id() == property_name {
264 fn insert(&self, _: (TypeName, PropName), _: DeclTy<R>) {}
267 /// Looks up methods from the `types` cache instead of storing them separately.
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>> {
277 .and_then(|decl| match decl {
278 TypeDecl::Class(cls) => Some(cls),
279 TypeDecl::Typedef(..) => None,
282 cls.methods.iter().rev().find_map(|meth| {
283 if meth.name.id() == method_name {
284 Some(meth.ty.clone())
291 fn insert(&self, _: (TypeName, MethodName), _: DeclTy<R>) {}
294 /// Looks up methods from the `types` cache instead of storing them separately.
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>> {
304 .and_then(|decl| match decl {
305 TypeDecl::Class(cls) => Some(cls),
306 TypeDecl::Typedef(..) => None,
309 cls.static_methods.iter().rev().find_map(|meth| {
310 if meth.name.id() == method_name {
311 Some(meth.ty.clone())
318 fn insert(&self, _: (TypeName, MethodName), _: DeclTy<R>) {}
321 /// Looks up constructors from the `types` cache instead of storing them separately.
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>> {
331 .and_then(|decl| match decl {
332 TypeDecl::Class(cls) => Some(cls),
333 TypeDecl::Typedef(..) => None,
335 .and_then(|cls| cls.constructor.as_ref().map(|meth| meth.ty.clone()))
337 fn insert(&self, _: TypeName, _: DeclTy<R>) {}