aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/method_resolution.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src/method_resolution.rs')
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs225
1 files changed, 186 insertions, 39 deletions
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index 2bded3dbd..21efb196a 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -7,19 +7,20 @@ use std::sync::Arc;
7use arrayvec::ArrayVec; 7use arrayvec::ArrayVec;
8use hir_def::{ 8use hir_def::{
9 lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocItemId, AstItemDef, 9 lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocItemId, AstItemDef,
10 FunctionId, HasModule, ImplId, TraitId, 10 FunctionId, HasModule, ImplId, Lookup, TraitId,
11}; 11};
12use hir_expand::name::Name; 12use hir_expand::name::Name;
13use ra_db::CrateId; 13use ra_db::CrateId;
14use ra_prof::profile; 14use ra_prof::profile;
15use rustc_hash::FxHashMap; 15use rustc_hash::FxHashMap;
16 16
17use super::Substs;
17use crate::{ 18use crate::{
18 autoderef, 19 autoderef,
19 db::HirDatabase, 20 db::HirDatabase,
20 primitive::{FloatBitness, Uncertain}, 21 primitive::{FloatBitness, Uncertain},
21 utils::all_super_traits, 22 utils::all_super_traits,
22 Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, 23 Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
23}; 24};
24 25
25/// This is used as a key for indexing impls. 26/// This is used as a key for indexing impls.
@@ -176,7 +177,6 @@ pub fn iterate_method_candidates<T>(
176 mode: LookupMode, 177 mode: LookupMode,
177 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 178 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
178) -> Option<T> { 179) -> Option<T> {
179 let krate = resolver.krate()?;
180 match mode { 180 match mode {
181 LookupMode::MethodCall => { 181 LookupMode::MethodCall => {
182 // For method calls, rust first does any number of autoderef, and then one 182 // For method calls, rust first does any number of autoderef, and then one
@@ -189,57 +189,159 @@ pub fn iterate_method_candidates<T>(
189 // rustc does an autoderef and then autoref again). 189 // rustc does an autoderef and then autoref again).
190 let environment = TraitEnvironment::lower(db, resolver); 190 let environment = TraitEnvironment::lower(db, resolver);
191 let ty = InEnvironment { value: ty.clone(), environment }; 191 let ty = InEnvironment { value: ty.clone(), environment };
192 for derefed_ty in autoderef::autoderef(db, resolver.krate(), ty) { 192 let krate = resolver.krate()?;
193 if let Some(result) = 193
194 iterate_inherent_methods(&derefed_ty, db, name, mode, krate, &mut callback) 194 // We have to be careful about the order we're looking at candidates
195 { 195 // in here. Consider the case where we're resolving `x.clone()`
196 return Some(result); 196 // where `x: &Vec<_>`. This resolves to the clone method with self
197 } 197 // type `Vec<_>`, *not* `&_`. I.e. we need to consider methods where
198 if let Some(result) = iterate_trait_method_candidates( 198 // the receiver type exactly matches before cases where we have to
199 &derefed_ty, 199 // do autoref. But in the autoderef steps, the `&_` self type comes
200 // up *before* the `Vec<_>` self type.
201 //
202 // On the other hand, we don't want to just pick any by-value method
203 // before any by-autoref method; it's just that we need to consider
204 // the methods by autoderef order of *receiver types*, not *self
205 // types*.
206
207 let deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty.clone()).collect();
208 for i in 0..deref_chain.len() {
209 if let Some(result) = iterate_method_candidates_with_autoref(
210 &deref_chain[i..],
200 db, 211 db,
201 resolver, 212 resolver,
202 name, 213 name,
203 mode,
204 &mut callback, 214 &mut callback,
205 ) { 215 ) {
206 return Some(result); 216 return Some(result);
207 } 217 }
208 } 218 }
219 None
209 } 220 }
210 LookupMode::Path => { 221 LookupMode::Path => {
211 // No autoderef for path lookups 222 // No autoderef for path lookups
212 if let Some(result) = 223 iterate_method_candidates_for_self_ty(&ty, db, resolver, name, &mut callback)
213 iterate_inherent_methods(&ty, db, name, mode, krate.into(), &mut callback) 224 }
214 { 225 }
215 return Some(result); 226}
216 } 227
217 if let Some(result) = 228fn iterate_method_candidates_with_autoref<T>(
218 iterate_trait_method_candidates(&ty, db, resolver, name, mode, &mut callback) 229 deref_chain: &[Canonical<Ty>],
219 { 230 db: &impl HirDatabase,
220 return Some(result); 231 resolver: &Resolver,
221 } 232 name: Option<&Name>,
233 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
234) -> Option<T> {
235 if let Some(result) = iterate_method_candidates_by_receiver(
236 &deref_chain[0],
237 &deref_chain[1..],
238 db,
239 resolver,
240 name,
241 &mut callback,
242 ) {
243 return Some(result);
244 }
245 let refed = Canonical {
246 num_vars: deref_chain[0].num_vars,
247 value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()),
248 };
249 if let Some(result) = iterate_method_candidates_by_receiver(
250 &refed,
251 deref_chain,
252 db,
253 resolver,
254 name,
255 &mut callback,
256 ) {
257 return Some(result);
258 }
259 let ref_muted = Canonical {
260 num_vars: deref_chain[0].num_vars,
261 value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()),
262 };
263 if let Some(result) = iterate_method_candidates_by_receiver(
264 &ref_muted,
265 deref_chain,
266 db,
267 resolver,
268 name,
269 &mut callback,
270 ) {
271 return Some(result);
272 }
273 None
274}
275
276fn iterate_method_candidates_by_receiver<T>(
277 receiver_ty: &Canonical<Ty>,
278 rest_of_deref_chain: &[Canonical<Ty>],
279 db: &impl HirDatabase,
280 resolver: &Resolver,
281 name: Option<&Name>,
282 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
283) -> Option<T> {
284 // We're looking for methods with *receiver* type receiver_ty. These could
285 // be found in any of the derefs of receiver_ty, so we have to go through
286 // that.
287 let krate = resolver.krate()?;
288 for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) {
289 if let Some(result) =
290 iterate_inherent_methods(self_ty, db, name, Some(receiver_ty), krate, &mut callback)
291 {
292 return Some(result);
293 }
294 }
295 for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) {
296 if let Some(result) = iterate_trait_method_candidates(
297 self_ty,
298 db,
299 resolver,
300 name,
301 Some(receiver_ty),
302 &mut callback,
303 ) {
304 return Some(result);
222 } 305 }
223 } 306 }
224 None 307 None
225} 308}
226 309
310fn iterate_method_candidates_for_self_ty<T>(
311 self_ty: &Canonical<Ty>,
312 db: &impl HirDatabase,
313 resolver: &Resolver,
314 name: Option<&Name>,
315 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
316) -> Option<T> {
317 let krate = resolver.krate()?;
318 if let Some(result) = iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) {
319 return Some(result);
320 }
321 if let Some(result) =
322 iterate_trait_method_candidates(self_ty, db, resolver, name, None, &mut callback)
323 {
324 return Some(result);
325 }
326 None
327}
328
227fn iterate_trait_method_candidates<T>( 329fn iterate_trait_method_candidates<T>(
228 ty: &Canonical<Ty>, 330 self_ty: &Canonical<Ty>,
229 db: &impl HirDatabase, 331 db: &impl HirDatabase,
230 resolver: &Resolver, 332 resolver: &Resolver,
231 name: Option<&Name>, 333 name: Option<&Name>,
232 mode: LookupMode, 334 receiver_ty: Option<&Canonical<Ty>>,
233 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 335 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
234) -> Option<T> { 336) -> Option<T> {
235 let krate = resolver.krate()?; 337 let krate = resolver.krate()?;
236 // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) 338 // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that)
237 let env = TraitEnvironment::lower(db, resolver); 339 let env = TraitEnvironment::lower(db, resolver);
238 // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope 340 // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope
239 let inherent_trait = ty.value.inherent_trait().into_iter(); 341 let inherent_trait = self_ty.value.inherent_trait().into_iter();
240 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope 342 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
241 let traits_from_env = env 343 let traits_from_env = env
242 .trait_predicates_for_self_ty(&ty.value) 344 .trait_predicates_for_self_ty(&self_ty.value)
243 .map(|tr| tr.trait_) 345 .map(|tr| tr.trait_)
244 .flat_map(|t| all_super_traits(db, t)); 346 .flat_map(|t| all_super_traits(db, t));
245 let traits = 347 let traits =
@@ -252,17 +354,17 @@ fn iterate_trait_method_candidates<T>(
252 // iteration 354 // iteration
253 let mut known_implemented = false; 355 let mut known_implemented = false;
254 for (_name, item) in data.items.iter() { 356 for (_name, item) in data.items.iter() {
255 if !is_valid_candidate(db, name, mode, (*item).into()) { 357 if !is_valid_candidate(db, name, receiver_ty, (*item).into(), self_ty) {
256 continue; 358 continue;
257 } 359 }
258 if !known_implemented { 360 if !known_implemented {
259 let goal = generic_implements_goal(db, env.clone(), t, ty.clone()); 361 let goal = generic_implements_goal(db, env.clone(), t, self_ty.clone());
260 if db.trait_solve(krate.into(), goal).is_none() { 362 if db.trait_solve(krate.into(), goal).is_none() {
261 continue 'traits; 363 continue 'traits;
262 } 364 }
263 } 365 }
264 known_implemented = true; 366 known_implemented = true;
265 if let Some(result) = callback(&ty.value, (*item).into()) { 367 if let Some(result) = callback(&self_ty.value, (*item).into()) {
266 return Some(result); 368 return Some(result);
267 } 369 }
268 } 370 }
@@ -271,22 +373,22 @@ fn iterate_trait_method_candidates<T>(
271} 373}
272 374
273fn iterate_inherent_methods<T>( 375fn iterate_inherent_methods<T>(
274 ty: &Canonical<Ty>, 376 self_ty: &Canonical<Ty>,
275 db: &impl HirDatabase, 377 db: &impl HirDatabase,
276 name: Option<&Name>, 378 name: Option<&Name>,
277 mode: LookupMode, 379 receiver_ty: Option<&Canonical<Ty>>,
278 krate: CrateId, 380 krate: CrateId,
279 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 381 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
280) -> Option<T> { 382) -> Option<T> {
281 for krate in ty.value.def_crates(db, krate)? { 383 for krate in self_ty.value.def_crates(db, krate)? {
282 let impls = db.impls_in_crate(krate); 384 let impls = db.impls_in_crate(krate);
283 385
284 for impl_block in impls.lookup_impl_blocks(&ty.value) { 386 for impl_block in impls.lookup_impl_blocks(&self_ty.value) {
285 for &item in db.impl_data(impl_block).items.iter() { 387 for &item in db.impl_data(impl_block).items.iter() {
286 if !is_valid_candidate(db, name, mode, item) { 388 if !is_valid_candidate(db, name, receiver_ty, item, self_ty) {
287 continue; 389 continue;
288 } 390 }
289 if let Some(result) = callback(&ty.value, item.into()) { 391 if let Some(result) = callback(&self_ty.value, item) {
290 return Some(result); 392 return Some(result);
291 } 393 }
292 } 394 }
@@ -298,23 +400,68 @@ fn iterate_inherent_methods<T>(
298fn is_valid_candidate( 400fn is_valid_candidate(
299 db: &impl HirDatabase, 401 db: &impl HirDatabase,
300 name: Option<&Name>, 402 name: Option<&Name>,
301 mode: LookupMode, 403 receiver_ty: Option<&Canonical<Ty>>,
302 item: AssocItemId, 404 item: AssocItemId,
405 self_ty: &Canonical<Ty>,
303) -> bool { 406) -> bool {
304 match item { 407 match item {
305 AssocItemId::FunctionId(m) => { 408 AssocItemId::FunctionId(m) => {
306 let data = db.function_data(m); 409 let data = db.function_data(m);
307 name.map_or(true, |name| &data.name == name) 410 if let Some(name) = name {
308 && (data.has_self_param || mode == LookupMode::Path) 411 if &data.name != name {
412 return false;
413 }
414 }
415 if let Some(receiver_ty) = receiver_ty {
416 if !data.has_self_param {
417 return false;
418 }
419 let transformed_receiver_ty = match transform_receiver_ty(db, m, self_ty) {
420 Some(ty) => ty,
421 None => return false,
422 };
423 if transformed_receiver_ty != receiver_ty.value {
424 return false;
425 }
426 }
427 true
309 } 428 }
310 AssocItemId::ConstId(c) => { 429 AssocItemId::ConstId(c) => {
311 let data = db.const_data(c); 430 let data = db.const_data(c);
312 name.map_or(true, |name| data.name.as_ref() == Some(name)) && (mode == LookupMode::Path) 431 name.map_or(true, |name| data.name.as_ref() == Some(name)) && receiver_ty.is_none()
313 } 432 }
314 _ => false, 433 _ => false,
315 } 434 }
316} 435}
317 436
437pub(crate) fn inherent_impl_substs(
438 db: &impl HirDatabase,
439 impl_id: ImplId,
440 self_ty: &Ty,
441) -> Option<Substs> {
442 let vars = Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build();
443 let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars);
444 let self_ty_with_vars = Canonical { num_vars: vars.len(), value: &self_ty_with_vars };
445 super::infer::unify(self_ty_with_vars, self_ty)
446}
447
448fn transform_receiver_ty(
449 db: &impl HirDatabase,
450 function_id: FunctionId,
451 self_ty: &Canonical<Ty>,
452) -> Option<Ty> {
453 let substs = match function_id.lookup(db).container {
454 hir_def::ContainerId::TraitId(_) => Substs::build_for_def(db, function_id)
455 .push(self_ty.value.clone())
456 .fill_with_unknown()
457 .build(),
458 hir_def::ContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty.value)?,
459 hir_def::ContainerId::ModuleId(_) => unreachable!(),
460 };
461 let sig = db.callable_item_signature(function_id.into());
462 Some(sig.params()[0].clone().subst(&substs))
463}
464
318pub fn implements_trait( 465pub fn implements_trait(
319 ty: &Canonical<Ty>, 466 ty: &Canonical<Ty>,
320 db: &impl HirDatabase, 467 db: &impl HirDatabase,