Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir_ty/src/method_resolution.rs')
-rw-r--r--crates/hir_ty/src/method_resolution.rs94
1 files changed, 58 insertions, 36 deletions
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index f917b43ff8..9120f80e2c 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -985,56 +985,78 @@ fn is_valid_candidate(
return false;
}
}
- let snap = table.snapshot();
- let subst = TyBuilder::subst_for_def(db, m).fill_with_inference_vars(table).build();
- let expected_self_ty = match m.lookup(db.upcast()).container {
- ItemContainerId::TraitId(_) => {
- subst.at(Interner, 0).assert_ty_ref(Interner).clone()
+ table.run_in_snapshot(|table| {
+ let subst = TyBuilder::subst_for_def(db, m).fill_with_inference_vars(table).build();
+ let expected_self_ty = match m.lookup(db.upcast()).container {
+ ItemContainerId::TraitId(_) => {
+ subst.at(Interner, 0).assert_ty_ref(Interner).clone()
+ }
+ ItemContainerId::ImplId(impl_id) => {
+ subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner)
+ }
+ // We should only get called for associated items (impl/trait)
+ ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
+ unreachable!()
+ }
+ };
+ if !table.unify(&expected_self_ty, &self_ty) {
+ return false;
}
- ItemContainerId::ImplId(impl_id) => {
- subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner)
+ if let Some(receiver_ty) = receiver_ty {
+ if !data.has_self_param() {
+ return false;
+ }
+
+ let sig = db.callable_item_signature(m.into());
+ let expected_receiver =
+ sig.map(|s| s.params()[0].clone()).substitute(Interner, &subst);
+ let receiver_matches = table.unify(&receiver_ty, &expected_receiver);
+
+ if !receiver_matches {
+ return false;
+ }
}
- // We should only get called for associated items (impl/trait)
- ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => unreachable!(),
- };
- if !table.unify(&expected_self_ty, &self_ty) {
- // FIXME handle rollbacks better
- table.rollback_to(snap);
+ if let Some(from_module) = visible_from_module {
+ if !db.function_visibility(m).is_visible_from(db.upcast(), from_module) {
+ cov_mark::hit!(autoderef_candidate_not_visible);
+ return false;
+ }
+ }
+
+ true
+ })
+ }
+ AssocItemId::ConstId(c) => {
+ let data = db.const_data(c);
+ if receiver_ty.is_some() {
return false;
}
- if let Some(receiver_ty) = receiver_ty {
- if !data.has_self_param() {
- table.rollback_to(snap);
+ if let Some(name) = name {
+ if data.name.as_ref() != Some(name) {
return false;
}
-
- let sig = db.callable_item_signature(m.into());
- let expected_receiver =
- sig.map(|s| s.params()[0].clone()).substitute(Interner, &subst);
- let receiver_matches = table.unify(&receiver_ty, &expected_receiver);
- table.rollback_to(snap);
-
- if !receiver_matches {
+ }
+ if let Some(from_module) = visible_from_module {
+ if !db.const_visibility(c).is_visible_from(db.upcast(), from_module) {
+ cov_mark::hit!(const_candidate_not_visible);
return false;
}
- } else {
- table.rollback_to(snap);
}
- if let Some(from_module) = visible_from_module {
- if !db.function_visibility(m).is_visible_from(db.upcast(), from_module) {
- cov_mark::hit!(autoderef_candidate_not_visible);
+ if let ItemContainerId::ImplId(impl_id) = c.lookup(db.upcast()).container {
+ let self_ty_matches = table.run_in_snapshot(|table| {
+ let subst =
+ TyBuilder::subst_for_def(db, c).fill_with_inference_vars(table).build();
+ let expected_self_ty =
+ subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner);
+ table.unify(&expected_self_ty, &self_ty)
+ });
+ if !self_ty_matches {
+ cov_mark::hit!(const_candidate_self_type_mismatch);
return false;
}
}
-
true
}
- AssocItemId::ConstId(c) => {
- let data = db.const_data(c);
- // TODO check unify self ty
- // TODO check visibility
- name.map_or(true, |name| data.name.as_ref() == Some(name)) && receiver_ty.is_none()
- }
_ => false,
}
}