aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/code_model_api.rs14
-rw-r--r--crates/ra_hir/src/code_model_impl/function.rs3
-rw-r--r--crates/ra_hir/src/code_model_impl/module.rs15
-rw-r--r--crates/ra_hir/src/db.rs9
-rw-r--r--crates/ra_hir/src/impl_block.rs36
-rw-r--r--crates/ra_hir/src/mock.rs1
-rw-r--r--crates/ra_hir/src/ty.rs39
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs164
-rw-r--r--crates/ra_hir/src/ty/tests.rs26
-rw-r--r--crates/ra_hir/src/ty/tests/data/inherent_method.txt18
-rw-r--r--crates/ra_ide_api/src/db.rs1
11 files changed, 309 insertions, 17 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index d4244f70c..9c28b62af 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -113,6 +113,11 @@ impl Module {
113 self.child_impl(db, name) 113 self.child_impl(db, name)
114 } 114 }
115 115
116 /// Iterates over all child modules.
117 pub fn children(&self, db: &impl HirDatabase) -> Cancelable<impl Iterator<Item = Module>> {
118 self.children_impl(db)
119 }
120
116 /// Finds a parent module. 121 /// Finds a parent module.
117 pub fn parent(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> { 122 pub fn parent(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
118 self.parent_impl(db) 123 self.parent_impl(db)
@@ -270,6 +275,9 @@ pub struct FnSignature {
270 pub(crate) name: Name, 275 pub(crate) name: Name,
271 pub(crate) args: Vec<TypeRef>, 276 pub(crate) args: Vec<TypeRef>,
272 pub(crate) ret_type: TypeRef, 277 pub(crate) ret_type: TypeRef,
278 /// True if the first arg is `self`. This is relevant to decide whether this
279 /// can be called as a method.
280 pub(crate) has_self_arg: bool,
273} 281}
274 282
275impl FnSignature { 283impl FnSignature {
@@ -284,6 +292,12 @@ impl FnSignature {
284 pub fn ret_type(&self) -> &TypeRef { 292 pub fn ret_type(&self) -> &TypeRef {
285 &self.ret_type 293 &self.ret_type
286 } 294 }
295
296 /// True if the first arg is `self`. This is relevant to decide whether this
297 /// can be called as a method.
298 pub fn has_self_arg(&self) -> bool {
299 self.has_self_arg
300 }
287} 301}
288 302
289impl Function { 303impl Function {
diff --git a/crates/ra_hir/src/code_model_impl/function.rs b/crates/ra_hir/src/code_model_impl/function.rs
index 1ce939e05..77dddff79 100644
--- a/crates/ra_hir/src/code_model_impl/function.rs
+++ b/crates/ra_hir/src/code_model_impl/function.rs
@@ -43,6 +43,7 @@ impl FnSignature {
43 .map(|n| n.as_name()) 43 .map(|n| n.as_name())
44 .unwrap_or_else(Name::missing); 44 .unwrap_or_else(Name::missing);
45 let mut args = Vec::new(); 45 let mut args = Vec::new();
46 let mut has_self_arg = false;
46 if let Some(param_list) = node.param_list() { 47 if let Some(param_list) = node.param_list() {
47 if let Some(self_param) = param_list.self_param() { 48 if let Some(self_param) = param_list.self_param() {
48 let self_type = if let Some(type_ref) = self_param.type_ref() { 49 let self_type = if let Some(type_ref) = self_param.type_ref() {
@@ -60,6 +61,7 @@ impl FnSignature {
60 } 61 }
61 }; 62 };
62 args.push(self_type); 63 args.push(self_type);
64 has_self_arg = true;
63 } 65 }
64 for param in param_list.params() { 66 for param in param_list.params() {
65 let type_ref = TypeRef::from_ast_opt(param.type_ref()); 67 let type_ref = TypeRef::from_ast_opt(param.type_ref());
@@ -75,6 +77,7 @@ impl FnSignature {
75 name, 77 name,
76 args, 78 args,
77 ret_type, 79 ret_type,
80 has_self_arg,
78 }; 81 };
79 Arc::new(sig) 82 Arc::new(sig)
80 } 83 }
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs
index e9ff06dc8..775dd6709 100644
--- a/crates/ra_hir/src/code_model_impl/module.rs
+++ b/crates/ra_hir/src/code_model_impl/module.rs
@@ -95,6 +95,21 @@ impl Module {
95 Module::from_module_id(db, loc.source_root_id, child_id).map(Some) 95 Module::from_module_id(db, loc.source_root_id, child_id).map(Some)
96 } 96 }
97 97
98 /// Iterates over all child modules.
99 pub fn children_impl(&self, db: &impl HirDatabase) -> Cancelable<impl Iterator<Item = Module>> {
100 // FIXME this should be implementable without collecting into a vec, but
101 // it's kind of hard since the iterator needs to keep a reference to the
102 // module tree.
103 let loc = self.def_id.loc(db);
104 let module_tree = db.module_tree(loc.source_root_id)?;
105 let children = loc
106 .module_id
107 .children(&module_tree)
108 .map(|(_, module_id)| Module::from_module_id(db, loc.source_root_id, module_id))
109 .collect::<Cancelable<Vec<_>>>()?;
110 Ok(children.into_iter())
111 }
112
98 pub fn parent_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> { 113 pub fn parent_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
99 let loc = self.def_id.loc(db); 114 let loc = self.def_id.loc(db);
100 let module_tree = db.module_tree(loc.source_root_id)?; 115 let module_tree = db.module_tree(loc.source_root_id)?;
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index a11c73db0..842f54f11 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -5,13 +5,13 @@ use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, Cancelable};
5 5
6use crate::{ 6use crate::{
7 DefLoc, DefId, MacroCallLoc, MacroCallId, Name, HirFileId, 7 DefLoc, DefId, MacroCallLoc, MacroCallId, Name, HirFileId,
8 SourceFileItems, SourceItemId, 8 SourceFileItems, SourceItemId, Crate,
9 query_definitions, 9 query_definitions,
10 FnSignature, FnScopes, 10 FnSignature, FnScopes,
11 macros::MacroExpansion, 11 macros::MacroExpansion,
12 module_tree::{ModuleId, ModuleTree}, 12 module_tree::{ModuleId, ModuleTree},
13 nameres::{ItemMap, InputModuleItems}, 13 nameres::{ItemMap, InputModuleItems},
14 ty::{InferenceResult, Ty}, 14 ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks},
15 adt::{StructData, EnumData, EnumVariantData}, 15 adt::{StructData, EnumData, EnumVariantData},
16 impl_block::ModuleImplBlocks, 16 impl_block::ModuleImplBlocks,
17}; 17};
@@ -102,6 +102,11 @@ pub trait HirDatabase: SyntaxDatabase
102 use fn crate::impl_block::impls_in_module; 102 use fn crate::impl_block::impls_in_module;
103 } 103 }
104 104
105 fn impls_in_crate(krate: Crate) -> Cancelable<Arc<CrateImplBlocks>> {
106 type ImplsInCrateQuery;
107 use fn crate::ty::method_resolution::impls_in_crate;
108 }
109
105 fn body_hir(def_id: DefId) -> Cancelable<Arc<crate::expr::Body>> { 110 fn body_hir(def_id: DefId) -> Cancelable<Arc<crate::expr::Body>> {
106 type BodyHirQuery; 111 type BodyHirQuery;
107 use fn crate::expr::body_hir; 112 use fn crate::expr::body_hir;
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
index 4acda9af3..23c1d98d5 100644
--- a/crates/ra_hir/src/impl_block.rs
+++ b/crates/ra_hir/src/impl_block.rs
@@ -33,20 +33,27 @@ impl ImplBlock {
33 }) 33 })
34 } 34 }
35 35
36 pub(crate) fn from_id(module_impl_blocks: Arc<ModuleImplBlocks>, impl_id: ImplId) -> ImplBlock {
37 ImplBlock {
38 module_impl_blocks,
39 impl_id,
40 }
41 }
42
36 fn impl_data(&self) -> &ImplData { 43 fn impl_data(&self) -> &ImplData {
37 &self.module_impl_blocks.impls[self.impl_id] 44 &self.module_impl_blocks.impls[self.impl_id]
38 } 45 }
39 46
40 pub fn target_trait(&self) -> Option<&TypeRef> { 47 pub fn target_trait(&self) -> Option<&TypeRef> {
41 self.impl_data().target_trait.as_ref() 48 self.impl_data().target_trait()
42 } 49 }
43 50
44 pub fn target_type(&self) -> &TypeRef { 51 pub fn target_type(&self) -> &TypeRef {
45 &self.impl_data().target_type 52 self.impl_data().target_type()
46 } 53 }
47 54
48 pub fn items(&self) -> &[ImplItem] { 55 pub fn items(&self) -> &[ImplItem] {
49 &self.impl_data().items 56 self.impl_data().items()
50 } 57 }
51} 58}
52 59
@@ -64,7 +71,7 @@ impl ImplData {
64 module: &Module, 71 module: &Module,
65 node: &ast::ImplBlock, 72 node: &ast::ImplBlock,
66 ) -> Self { 73 ) -> Self {
67 let target_trait = node.target_type().map(TypeRef::from_ast); 74 let target_trait = node.target_trait().map(TypeRef::from_ast);
68 let target_type = TypeRef::from_ast_opt(node.target_type()); 75 let target_type = TypeRef::from_ast_opt(node.target_type());
69 let module_loc = module.def_id.loc(db); 76 let module_loc = module.def_id.loc(db);
70 let items = if let Some(item_list) = node.item_list() { 77 let items = if let Some(item_list) = node.item_list() {
@@ -103,6 +110,18 @@ impl ImplData {
103 items, 110 items,
104 } 111 }
105 } 112 }
113
114 pub fn target_trait(&self) -> Option<&TypeRef> {
115 self.target_trait.as_ref()
116 }
117
118 pub fn target_type(&self) -> &TypeRef {
119 &self.target_type
120 }
121
122 pub fn items(&self) -> &[ImplItem] {
123 &self.items
124 }
106} 125}
107 126
108#[derive(Debug, Clone, PartialEq, Eq)] 127#[derive(Debug, Clone, PartialEq, Eq)]
@@ -133,11 +152,9 @@ impl_arena_id!(ImplId);
133/// This way, we avoid having to do this process for the whole crate whenever 152/// This way, we avoid having to do this process for the whole crate whenever
134/// a file is changed; as long as the impl blocks in the file don't change, 153/// a file is changed; as long as the impl blocks in the file don't change,
135/// we don't need to do the second step again. 154/// we don't need to do the second step again.
136///
137/// (The second step does not yet exist.)
138#[derive(Debug, PartialEq, Eq)] 155#[derive(Debug, PartialEq, Eq)]
139pub struct ModuleImplBlocks { 156pub struct ModuleImplBlocks {
140 impls: Arena<ImplId, ImplData>, 157 pub(crate) impls: Arena<ImplId, ImplData>,
141 impls_by_def: FxHashMap<DefId, ImplId>, 158 impls_by_def: FxHashMap<DefId, ImplId>,
142} 159}
143 160
@@ -153,7 +170,10 @@ impl ModuleImplBlocks {
153 let (file_id, module_source) = module.definition_source(db)?; 170 let (file_id, module_source) = module.definition_source(db)?;
154 let node = match &module_source { 171 let node = match &module_source {
155 ModuleSource::SourceFile(node) => node.syntax(), 172 ModuleSource::SourceFile(node) => node.syntax(),
156 ModuleSource::Module(node) => node.syntax(), 173 ModuleSource::Module(node) => match node.item_list() {
174 Some(item_list) => item_list.syntax(),
175 None => return Ok(()),
176 },
157 }; 177 };
158 178
159 let source_file_items = db.file_items(file_id.into()); 179 let source_file_items = db.file_items(file_id.into());
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 6f93bb59d..9371c5a0d 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -235,6 +235,7 @@ salsa::database_storage! {
235 fn enum_data() for db::EnumDataQuery; 235 fn enum_data() for db::EnumDataQuery;
236 fn enum_variant_data() for db::EnumVariantDataQuery; 236 fn enum_variant_data() for db::EnumVariantDataQuery;
237 fn impls_in_module() for db::ImplsInModuleQuery; 237 fn impls_in_module() for db::ImplsInModuleQuery;
238 fn impls_in_crate() for db::ImplsInCrateQuery;
238 fn body_hir() for db::BodyHirQuery; 239 fn body_hir() for db::BodyHirQuery;
239 fn body_syntax_mapping() for db::BodySyntaxMappingQuery; 240 fn body_syntax_mapping() for db::BodySyntaxMappingQuery;
240 fn fn_signature() for db::FnSignatureQuery; 241 fn fn_signature() for db::FnSignatureQuery;
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 2d533eb6a..2dcba5283 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -17,6 +17,7 @@ mod autoderef;
17mod primitive; 17mod primitive;
18#[cfg(test)] 18#[cfg(test)]
19mod tests; 19mod tests;
20pub(crate) mod method_resolution;
20 21
21use std::borrow::Cow; 22use std::borrow::Cow;
22use std::ops::Index; 23use std::ops::Index;
@@ -891,14 +892,38 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
891 } 892 }
892 ret_ty 893 ret_ty
893 } 894 }
894 Expr::MethodCall { receiver, args, .. } => { 895 Expr::MethodCall {
895 let _receiver_ty = self.infer_expr(*receiver, &Expectation::none())?; 896 receiver,
896 // TODO resolve method... 897 args,
897 for (_i, arg) in args.iter().enumerate() { 898 method_name,
898 // TODO unify / expect argument type 899 } => {
899 self.infer_expr(*arg, &Expectation::none())?; 900 let receiver_ty = self.infer_expr(*receiver, &Expectation::none())?;
901 let resolved = receiver_ty.clone().lookup_method(self.db, method_name)?;
902 let method_ty = match resolved {
903 Some(def_id) => self.db.type_for_def(def_id)?,
904 None => Ty::Unknown,
905 };
906 let method_ty = self.insert_type_vars(method_ty);
907 let (expected_receiver_ty, arg_tys, ret_ty) = match &method_ty {
908 Ty::FnPtr(sig) => {
909 if sig.input.len() > 0 {
910 (&sig.input[0], &sig.input[1..], sig.output.clone())
911 } else {
912 (&Ty::Unknown, &[][..], sig.output.clone())
913 }
914 }
915 _ => (&Ty::Unknown, &[][..], Ty::Unknown),
916 };
917 // TODO we would have to apply the autoderef/autoref steps here
918 // to get the correct receiver type to unify...
919 self.unify(expected_receiver_ty, &receiver_ty);
920 for (i, arg) in args.iter().enumerate() {
921 self.infer_expr(
922 *arg,
923 &Expectation::has_type(arg_tys.get(i).cloned().unwrap_or(Ty::Unknown)),
924 )?;
900 } 925 }
901 Ty::Unknown 926 ret_ty
902 } 927 }
903 Expr::Match { expr, arms } => { 928 Expr::Match { expr, arms } => {
904 let _ty = self.infer_expr(*expr, &Expectation::none())?; 929 let _ty = self.infer_expr(*expr, &Expectation::none())?;
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
new file mode 100644
index 000000000..ad80aa8b6
--- /dev/null
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -0,0 +1,164 @@
1//! This module is concerned with finding methods that a given type provides.
2//! For details about how this works in rustc, see the method lookup page in the
3//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
4//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs.
5use std::sync::Arc;
6
7use rustc_hash::FxHashMap;
8
9use ra_db::{Cancelable, SourceRootId};
10
11use crate::{HirDatabase, DefId, module_tree::ModuleId, Module, Crate, Name, Function, impl_block::{ImplId, ImplBlock, ImplItem}};
12use super::Ty;
13
14/// This is used as a key for indexing impls.
15#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
16pub enum TyFingerprint {
17 Adt(DefId),
18 // we'll also want to index impls for primitive types etc.
19}
20
21impl TyFingerprint {
22 /// Creates a TyFingerprint for looking up an impl. Only certain types can
23 /// have impls: if we have some `struct S`, we can have an `impl S`, but not
24 /// `impl &S`. Hence, this will return `None` for reference types and such.
25 fn for_impl(ty: &Ty) -> Option<TyFingerprint> {
26 match ty {
27 Ty::Adt { def_id, .. } => Some(TyFingerprint::Adt(*def_id)),
28 _ => None,
29 }
30 }
31}
32
33#[derive(Debug, PartialEq, Eq)]
34pub struct CrateImplBlocks {
35 /// To make sense of the ModuleIds, we need the source root.
36 source_root_id: SourceRootId,
37 impls: FxHashMap<TyFingerprint, Vec<(ModuleId, ImplId)>>,
38}
39
40impl CrateImplBlocks {
41 pub fn lookup_impl_blocks<'a>(
42 &'a self,
43 db: &'a impl HirDatabase,
44 ty: &Ty,
45 ) -> impl Iterator<Item = Cancelable<ImplBlock>> + 'a {
46 let fingerprint = TyFingerprint::for_impl(ty);
47 fingerprint
48 .and_then(|f| self.impls.get(&f))
49 .into_iter()
50 .flat_map(|i| i.iter())
51 .map(move |(module_id, impl_id)| {
52 let module_impl_blocks = db.impls_in_module(self.source_root_id, *module_id)?;
53 Ok(ImplBlock::from_id(module_impl_blocks, *impl_id))
54 })
55 }
56
57 fn collect_recursive(&mut self, db: &impl HirDatabase, module: Module) -> Cancelable<()> {
58 let module_id = module.def_id.loc(db).module_id;
59 let module_impl_blocks = db.impls_in_module(self.source_root_id, module_id)?;
60
61 for (impl_id, impl_data) in module_impl_blocks.impls.iter() {
62 let impl_block = ImplBlock::from_id(Arc::clone(&module_impl_blocks), impl_id);
63
64 if let Some(_target_trait) = impl_data.target_trait() {
65 // ignore for now
66 } else {
67 let target_ty =
68 Ty::from_hir(db, &module, Some(&impl_block), impl_data.target_type())?;
69 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
70 self.impls
71 .entry(target_ty_fp)
72 .or_insert_with(Vec::new)
73 .push((module_id, impl_id));
74 }
75 }
76 }
77
78 for child in module.children(db)? {
79 self.collect_recursive(db, child)?;
80 }
81
82 Ok(())
83 }
84}
85
86pub(crate) fn impls_in_crate(
87 db: &impl HirDatabase,
88 krate: Crate,
89) -> Cancelable<Arc<CrateImplBlocks>> {
90 let crate_graph = db.crate_graph();
91 let file_id = crate_graph.crate_root(krate.crate_id);
92 let source_root_id = db.file_source_root(file_id);
93 let mut crate_impl_blocks = CrateImplBlocks {
94 source_root_id,
95 impls: FxHashMap::default(),
96 };
97 if let Some(module) = krate.root_module(db)? {
98 crate_impl_blocks.collect_recursive(db, module)?;
99 }
100 Ok(Arc::new(crate_impl_blocks))
101}
102
103fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Cancelable<Option<Crate>> {
104 match ty {
105 Ty::Adt { def_id, .. } => def_id.krate(db),
106 _ => Ok(None),
107 }
108}
109
110impl Ty {
111 // TODO: cache this as a query?
112 // - if so, what signature? (TyFingerprint, Name)?
113 // - or maybe cache all names and def_ids of methods per fingerprint?
114 pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<DefId>> {
115 self.iterate_methods(db, |f| {
116 let sig = f.signature(db);
117 if sig.name() == name && sig.has_self_arg() {
118 Ok(Some(f.def_id()))
119 } else {
120 Ok(None)
121 }
122 })
123 }
124
125 // This would be nicer if it just returned an iterator, but that's really
126 // complicated with all the cancelable operations
127 pub fn iterate_methods<T>(
128 self,
129 db: &impl HirDatabase,
130 mut callback: impl FnMut(Function) -> Cancelable<Option<T>>,
131 ) -> Cancelable<Option<T>> {
132 // For method calls, rust first does any number of autoderef, and then one
133 // autoref (i.e. when the method takes &self or &mut self). We just ignore
134 // the autoref currently -- when we find a method matching the given name,
135 // we assume it fits.
136
137 // Also note that when we've got a receiver like &S, even if the method we
138 // find in the end takes &self, we still do the autoderef step (just as
139 // rustc does an autoderef and then autoref again).
140
141 for derefed_ty in self.autoderef(db) {
142 let krate = match def_crate(db, &derefed_ty)? {
143 Some(krate) => krate,
144 None => continue,
145 };
146 let impls = db.impls_in_crate(krate)?;
147
148 for impl_block in impls.lookup_impl_blocks(db, &derefed_ty) {
149 let impl_block = impl_block?;
150 for item in impl_block.items() {
151 match item {
152 ImplItem::Method(f) => {
153 if let Some(result) = callback(f.clone())? {
154 return Ok(Some(result));
155 }
156 }
157 _ => {}
158 }
159 }
160 }
161 }
162 Ok(None)
163 }
164}
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 815aecda7..1c3129441 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -242,6 +242,32 @@ fn test() {
242 ); 242 );
243} 243}
244 244
245#[test]
246fn infer_inherent_method() {
247 check_inference(
248 r#"
249struct A;
250
251impl A {
252 fn foo(self, x: u32) -> i32 {}
253}
254
255mod b {
256 impl super::A {
257 fn bar(&self, x: u64) -> i64 {}
258 }
259}
260
261fn test(a: A) {
262 a.foo(1);
263 (&a).bar(1);
264 a.bar(1);
265}
266"#,
267 "inherent_method.txt",
268 );
269}
270
245fn infer(content: &str) -> String { 271fn infer(content: &str) -> String {
246 let (db, _, file_id) = MockDatabase::with_single_file(content); 272 let (db, _, file_id) = MockDatabase::with_single_file(content);
247 let source_file = db.source_file(file_id); 273 let source_file = db.source_file(file_id);
diff --git a/crates/ra_hir/src/ty/tests/data/inherent_method.txt b/crates/ra_hir/src/ty/tests/data/inherent_method.txt
new file mode 100644
index 000000000..6e6f70357
--- /dev/null
+++ b/crates/ra_hir/src/ty/tests/data/inherent_method.txt
@@ -0,0 +1,18 @@
1[32; 36) 'self': A
2[38; 39) 'x': u32
3[53; 55) '{}': ()
4[103; 107) 'self': &A
5[109; 110) 'x': u64
6[124; 126) '{}': ()
7[144; 145) 'a': A
8[150; 198) '{ ...(1); }': ()
9[156; 157) 'a': A
10[156; 164) 'a.foo(1)': i32
11[162; 163) '1': u32
12[170; 181) '(&a).bar(1)': i64
13[171; 173) '&a': &A
14[172; 173) 'a': A
15[179; 180) '1': u64
16[187; 188) 'a': A
17[187; 195) 'a.bar(1)': i64
18[193; 194) '1': u64
diff --git a/crates/ra_ide_api/src/db.rs b/crates/ra_ide_api/src/db.rs
index efdf261be..60f84675d 100644
--- a/crates/ra_ide_api/src/db.rs
+++ b/crates/ra_ide_api/src/db.rs
@@ -124,6 +124,7 @@ salsa::database_storage! {
124 fn enum_data() for hir::db::EnumDataQuery; 124 fn enum_data() for hir::db::EnumDataQuery;
125 fn enum_variant_data() for hir::db::EnumVariantDataQuery; 125 fn enum_variant_data() for hir::db::EnumVariantDataQuery;
126 fn impls_in_module() for hir::db::ImplsInModuleQuery; 126 fn impls_in_module() for hir::db::ImplsInModuleQuery;
127 fn impls_in_crate() for hir::db::ImplsInCrateQuery;
127 fn body_hir() for hir::db::BodyHirQuery; 128 fn body_hir() for hir::db::BodyHirQuery;
128 fn body_syntax_mapping() for hir::db::BodySyntaxMappingQuery; 129 fn body_syntax_mapping() for hir::db::BodySyntaxMappingQuery;
129 fn fn_signature() for hir::db::FnSignatureQuery; 130 fn fn_signature() for hir::db::FnSignatureQuery;