aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty/method_resolution.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty/method_resolution.rs')
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs223
1 files changed, 116 insertions, 107 deletions
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index ea6e0dc0f..607e9ba79 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -16,7 +16,7 @@ use crate::{
16 generics::HasGenericParams, 16 generics::HasGenericParams,
17 ty::primitive::{UncertainIntTy, UncertainFloatTy} 17 ty::primitive::{UncertainIntTy, UncertainFloatTy}
18}; 18};
19use super::{TraitRef, Substs}; 19use super::{TraitRef, Canonical};
20 20
21/// This is used as a key for indexing impls. 21/// This is used as a key for indexing impls.
22#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 22#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -130,124 +130,122 @@ fn def_crate(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<Crate>
130 } 130 }
131} 131}
132 132
133impl Ty { 133/// Look up the method with the given name, returning the actual autoderefed
134 /// Look up the method with the given name, returning the actual autoderefed 134/// receiver type (but without autoref applied yet).
135 /// receiver type (but without autoref applied yet). 135pub(crate) fn lookup_method(
136 pub(crate) fn lookup_method( 136 ty: &Canonical<Ty>,
137 self, 137 db: &impl HirDatabase,
138 db: &impl HirDatabase, 138 name: &Name,
139 name: &Name, 139 resolver: &Resolver,
140 resolver: &Resolver, 140) -> Option<(Ty, Function)> {
141 ) -> Option<(Ty, Function)> { 141 iterate_method_candidates(ty, db, resolver, Some(name), |ty, f| Some((ty.clone(), f)))
142 self.iterate_method_candidates(db, resolver, Some(name), |ty, f| Some((ty.clone(), f))) 142}
143 }
144 143
145 // This would be nicer if it just returned an iterator, but that runs into 144// This would be nicer if it just returned an iterator, but that runs into
146 // lifetime problems, because we need to borrow temp `CrateImplBlocks`. 145// lifetime problems, because we need to borrow temp `CrateImplBlocks`.
147 pub(crate) fn iterate_method_candidates<T>( 146pub(crate) fn iterate_method_candidates<T>(
148 self, 147 ty: &Canonical<Ty>,
149 db: &impl HirDatabase, 148 db: &impl HirDatabase,
150 resolver: &Resolver, 149 resolver: &Resolver,
151 name: Option<&Name>, 150 name: Option<&Name>,
152 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 151 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
153 ) -> Option<T> { 152) -> Option<T> {
154 // For method calls, rust first does any number of autoderef, and then one 153 // For method calls, rust first does any number of autoderef, and then one
155 // autoref (i.e. when the method takes &self or &mut self). We just ignore 154 // autoref (i.e. when the method takes &self or &mut self). We just ignore
156 // the autoref currently -- when we find a method matching the given name, 155 // the autoref currently -- when we find a method matching the given name,
157 // we assume it fits. 156 // we assume it fits.
158 157
159 // Also note that when we've got a receiver like &S, even if the method we 158 // Also note that when we've got a receiver like &S, even if the method we
160 // find in the end takes &self, we still do the autoderef step (just as 159 // find in the end takes &self, we still do the autoderef step (just as
161 // rustc does an autoderef and then autoref again). 160 // rustc does an autoderef and then autoref again).
162 161
163 let krate = resolver.krate()?; 162 let krate = resolver.krate()?;
164 for derefed_ty in self.autoderef(db) { 163 for derefed_ty in ty.value.clone().autoderef(db) {
165 if let Some(result) = 164 let derefed_ty = Canonical { value: derefed_ty, num_vars: ty.num_vars };
166 derefed_ty.iterate_inherent_methods(db, name, krate, &mut callback) 165 if let Some(result) = iterate_inherent_methods(&derefed_ty, db, name, krate, &mut callback)
167 { 166 {
168 return Some(result); 167 return Some(result);
169 } 168 }
170 if let Some(result) = 169 if let Some(result) =
171 derefed_ty.iterate_trait_method_candidates(db, resolver, name, &mut callback) 170 iterate_trait_method_candidates(&derefed_ty, db, resolver, name, &mut callback)
172 { 171 {
173 return Some(result); 172 return Some(result);
174 }
175 } 173 }
176 None
177 } 174 }
175 None
176}
178 177
179 fn iterate_trait_method_candidates<T>( 178fn iterate_trait_method_candidates<T>(
180 &self, 179 ty: &Canonical<Ty>,
181 db: &impl HirDatabase, 180 db: &impl HirDatabase,
182 resolver: &Resolver, 181 resolver: &Resolver,
183 name: Option<&Name>, 182 name: Option<&Name>,
184 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 183 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
185 ) -> Option<T> { 184) -> Option<T> {
186 'traits: for t in resolver.traits_in_scope() { 185 let krate = resolver.krate()?;
187 let data = t.trait_data(db); 186 'traits: for t in resolver.traits_in_scope() {
188 // we'll be lazy about checking whether the type implements the 187 let data = t.trait_data(db);
189 // trait, but if we find out it doesn't, we'll skip the rest of the 188 // we'll be lazy about checking whether the type implements the
190 // iteration 189 // trait, but if we find out it doesn't, we'll skip the rest of the
191 let mut known_implemented = false; 190 // iteration
192 for item in data.items() { 191 let mut known_implemented = false;
193 match item { 192 for item in data.items() {
194 &TraitItem::Function(m) => { 193 match item {
195 let sig = m.signature(db); 194 &TraitItem::Function(m) => {
196 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() { 195 let sig = m.signature(db);
197 if !known_implemented { 196 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() {
198 let trait_ref = TraitRef { 197 if !known_implemented {
199 trait_: t, 198 let trait_ref = canonical_trait_ref(db, t, ty.clone());
200 substs: fresh_substs_for_trait(db, t, self.clone()), 199 // FIXME cache this implements check (without solution) in a query?
201 }; 200 if super::traits::implements(db, krate, trait_ref).is_none() {
202 let (trait_ref, _) = super::traits::canonicalize(trait_ref); 201 continue 'traits;
203 if db.implements(trait_ref).is_none() {
204 continue 'traits;
205 }
206 }
207 known_implemented = true;
208 if let Some(result) = callback(self, m) {
209 return Some(result);
210 } 202 }
211 } 203 }
204 known_implemented = true;
205 if let Some(result) = callback(&ty.value, m) {
206 return Some(result);
207 }
212 } 208 }
213 _ => {}
214 } 209 }
210 _ => {}
215 } 211 }
216 } 212 }
217 None
218 } 213 }
214 None
215}
219 216
220 fn iterate_inherent_methods<T>( 217fn iterate_inherent_methods<T>(
221 &self, 218 ty: &Canonical<Ty>,
222 db: &impl HirDatabase, 219 db: &impl HirDatabase,
223 name: Option<&Name>, 220 name: Option<&Name>,
224 krate: Crate, 221 krate: Crate,
225 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 222 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
226 ) -> Option<T> { 223) -> Option<T> {
227 let krate = match def_crate(db, krate, self) { 224 let krate = match def_crate(db, krate, &ty.value) {
228 Some(krate) => krate, 225 Some(krate) => krate,
229 None => return None, 226 None => return None,
230 }; 227 };
231 let impls = db.impls_in_crate(krate); 228 let impls = db.impls_in_crate(krate);
232 229
233 for impl_block in impls.lookup_impl_blocks(self) { 230 for impl_block in impls.lookup_impl_blocks(&ty.value) {
234 for item in impl_block.items(db) { 231 for item in impl_block.items(db) {
235 match item { 232 match item {
236 ImplItem::Method(f) => { 233 ImplItem::Method(f) => {
237 let sig = f.signature(db); 234 let sig = f.signature(db);
238 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() { 235 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() {
239 if let Some(result) = callback(self, f) { 236 if let Some(result) = callback(&ty.value, f) {
240 return Some(result); 237 return Some(result);
241 }
242 } 238 }
243 } 239 }
244 _ => {}
245 } 240 }
241 _ => {}
246 } 242 }
247 } 243 }
248 None
249 } 244 }
245 None
246}
250 247
248impl Ty {
251 // This would be nicer if it just returned an iterator, but that runs into 249 // This would be nicer if it just returned an iterator, but that runs into
252 // lifetime problems, because we need to borrow temp `CrateImplBlocks`. 250 // lifetime problems, because we need to borrow temp `CrateImplBlocks`.
253 pub fn iterate_impl_items<T>( 251 pub fn iterate_impl_items<T>(
@@ -271,15 +269,26 @@ impl Ty {
271} 269}
272 270
273/// This creates Substs for a trait with the given Self type and type variables 271/// This creates Substs for a trait with the given Self type and type variables
274/// for all other parameters. This is kind of a hack since these aren't 'real' 272/// for all other parameters, to query Chalk with it.
275/// type variables; the resulting trait reference is just used for the 273fn canonical_trait_ref(
276/// preliminary method candidate check. 274 db: &impl HirDatabase,
277fn fresh_substs_for_trait(db: &impl HirDatabase, tr: Trait, self_ty: Ty) -> Substs { 275 trait_: Trait,
276 self_ty: Canonical<Ty>,
277) -> Canonical<TraitRef> {
278 let mut substs = Vec::new(); 278 let mut substs = Vec::new();
279 let generics = tr.generic_params(db); 279 let generics = trait_.generic_params(db);
280 substs.push(self_ty); 280 let num_vars = self_ty.num_vars;
281 substs.extend(generics.params_including_parent().into_iter().skip(1).enumerate().map( 281 substs.push(self_ty.value);
282 |(i, _p)| Ty::Infer(super::infer::InferTy::TypeVar(super::infer::TypeVarId(i as u32))), 282 substs.extend(
283 )); 283 generics
284 substs.into() 284 .params_including_parent()
285 .into_iter()
286 .skip(1)
287 .enumerate()
288 .map(|(i, _p)| Ty::Bound((i + num_vars) as u32)),
289 );
290 Canonical {
291 num_vars: substs.len() - 1 + self_ty.num_vars,
292 value: TraitRef { trait_, substs: substs.into() },
293 }
285} 294}