internal: Remove dead branches in method_resolutiopn::is_valid_candidate

This commit is contained in:
Lukas Wirth 2024-02-27 10:00:45 +01:00
parent cc7fe32ba3
commit 3a1b4c29b3

View File

@ -1176,11 +1176,12 @@ fn iterate_trait_method_candidates(
for &(_, item) in data.items.iter() { for &(_, item) in data.items.iter() {
// Don't pass a `visible_from_module` down to `is_valid_candidate`, // Don't pass a `visible_from_module` down to `is_valid_candidate`,
// since only inherent methods should be included into visibility checking. // since only inherent methods should be included into visibility checking.
let visible = match is_valid_method_candidate(table, name, receiver_ty, item, self_ty) { let visible =
IsValidCandidate::Yes => true, match is_valid_trait_method_candidate(table, t, name, receiver_ty, item, self_ty) {
IsValidCandidate::NotVisible => false, IsValidCandidate::Yes => true,
IsValidCandidate::No => continue, IsValidCandidate::NotVisible => false,
}; IsValidCandidate::No => continue,
};
if !known_implemented { if !known_implemented {
let goal = generic_implements_goal(db, env.clone(), t, &canonical_self_ty); let goal = generic_implements_goal(db, env.clone(), t, &canonical_self_ty);
if db.trait_solve(env.krate, env.block, goal.cast(Interner)).is_none() { if db.trait_solve(env.krate, env.block, goal.cast(Interner)).is_none() {
@ -1302,12 +1303,18 @@ fn iterate_inherent_trait_methods(
let data = db.trait_data(t); let data = db.trait_data(t);
for &(_, item) in data.items.iter() { for &(_, item) in data.items.iter() {
// We don't pass `visible_from_module` as all trait items should be visible. // We don't pass `visible_from_module` as all trait items should be visible.
let visible = let visible = match is_valid_trait_method_candidate(
match is_valid_candidate(table, name, receiver_ty, item, self_ty, None) { table,
IsValidCandidate::Yes => true, t,
IsValidCandidate::NotVisible => false, name,
IsValidCandidate::No => continue, receiver_ty,
}; item,
self_ty,
) {
IsValidCandidate::Yes => true,
IsValidCandidate::NotVisible => false,
IsValidCandidate::No => continue,
};
callback(receiver_adjustments.clone().unwrap_or_default(), item, visible)?; callback(receiver_adjustments.clone().unwrap_or_default(), item, visible)?;
} }
} }
@ -1325,17 +1332,16 @@ fn impls_for_self_ty(
visible_from_module: Option<ModuleId>, visible_from_module: Option<ModuleId>,
callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>, callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> { ) -> ControlFlow<()> {
let db = table.db; for &impl_id in impls.for_self_ty(self_ty) {
let impls_for_self_ty = impls.for_self_ty(self_ty); for &item in &table.db.impl_data(impl_id).items {
for &impl_def in impls_for_self_ty { let visible = match is_valid_impl_method_candidate(
for &item in &db.impl_data(impl_def).items {
let visible = match is_valid_candidate(
table, table,
name,
receiver_ty,
item,
self_ty, self_ty,
receiver_ty,
visible_from_module, visible_from_module,
name,
impl_id,
item,
) { ) {
IsValidCandidate::Yes => true, IsValidCandidate::Yes => true,
IsValidCandidate::NotVisible => false, IsValidCandidate::NotVisible => false,
@ -1378,21 +1384,34 @@ macro_rules! check_that {
}; };
} }
enum IsValidCandidate {
Yes,
No,
NotVisible,
}
#[tracing::instrument(skip_all, fields(name))] #[tracing::instrument(skip_all, fields(name))]
fn is_valid_candidate( fn is_valid_impl_method_candidate(
table: &mut InferenceTable<'_>, table: &mut InferenceTable<'_>,
name: Option<&Name>,
receiver_ty: Option<&Ty>,
item: AssocItemId,
self_ty: &Ty, self_ty: &Ty,
receiver_ty: Option<&Ty>,
visible_from_module: Option<ModuleId>, visible_from_module: Option<ModuleId>,
name: Option<&Name>,
impl_id: ImplId,
item: AssocItemId,
) -> IsValidCandidate { ) -> IsValidCandidate {
let db = table.db;
match item { match item {
AssocItemId::FunctionId(f) => { AssocItemId::FunctionId(f) => is_valid_impl_fn_candidate(
is_valid_fn_candidate(table, f, name, receiver_ty, self_ty, visible_from_module) table,
} impl_id,
f,
name,
receiver_ty,
self_ty,
visible_from_module,
),
AssocItemId::ConstId(c) => { AssocItemId::ConstId(c) => {
let db = table.db;
check_that!(receiver_ty.is_none()); check_that!(receiver_ty.is_none());
check_that!(name.map_or(true, |n| db.const_data(c).name.as_ref() == Some(n))); check_that!(name.map_or(true, |n| db.const_data(c).name.as_ref() == Some(n)));
@ -1402,17 +1421,14 @@ fn is_valid_candidate(
return IsValidCandidate::NotVisible; return IsValidCandidate::NotVisible;
} }
} }
if let ItemContainerId::ImplId(impl_id) = c.lookup(db.upcast()).container { let self_ty_matches = table.run_in_snapshot(|table| {
let self_ty_matches = table.run_in_snapshot(|table| { let expected_self_ty =
let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id) TyBuilder::impl_self_ty(db, impl_id).fill_with_inference_vars(table).build();
.fill_with_inference_vars(table) table.unify(&expected_self_ty, self_ty)
.build(); });
table.unify(&expected_self_ty, self_ty) if !self_ty_matches {
}); cov_mark::hit!(const_candidate_self_type_mismatch);
if !self_ty_matches { return IsValidCandidate::No;
cov_mark::hit!(const_candidate_self_type_mismatch);
return IsValidCandidate::No;
}
} }
IsValidCandidate::Yes IsValidCandidate::Yes
} }
@ -1421,12 +1437,10 @@ fn is_valid_candidate(
} }
/// Checks whether a given `AssocItemId` is applicable for `receiver_ty`. /// Checks whether a given `AssocItemId` is applicable for `receiver_ty`.
///
/// This method should *only* be called by [`iterate_trait_method_candidates`],
/// as it is responsible for determining applicability in completions.
#[tracing::instrument(skip_all, fields(name))] #[tracing::instrument(skip_all, fields(name))]
fn is_valid_method_candidate( fn is_valid_trait_method_candidate(
table: &mut InferenceTable<'_>, table: &mut InferenceTable<'_>,
trait_id: TraitId,
name: Option<&Name>, name: Option<&Name>,
receiver_ty: Option<&Ty>, receiver_ty: Option<&Ty>,
item: AssocItemId, item: AssocItemId,
@ -1440,24 +1454,10 @@ fn is_valid_method_candidate(
check_that!(name.map_or(true, |n| n == &data.name)); check_that!(name.map_or(true, |n| n == &data.name));
table.run_in_snapshot(|table| { table.run_in_snapshot(|table| {
let container = fn_id.lookup(db.upcast()).container; let impl_subst = TyBuilder::subst_for_def(db, trait_id, None)
let (impl_subst, expect_self_ty) = match container { .fill_with_inference_vars(table)
ItemContainerId::ImplId(it) => { .build();
let subst = TyBuilder::subst_for_def(db, it, None) let expect_self_ty = impl_subst.at(Interner, 0).assert_ty_ref(Interner).clone();
.fill_with_inference_vars(table)
.build();
let self_ty = db.impl_self_ty(it).substitute(Interner, &subst);
(subst, self_ty)
}
ItemContainerId::TraitId(it) => {
let subst = TyBuilder::subst_for_def(db, it, None)
.fill_with_inference_vars(table)
.build();
let self_ty = subst.at(Interner, 0).assert_ty_ref(Interner).clone();
(subst, self_ty)
}
_ => unreachable!(),
};
check_that!(table.unify(&expect_self_ty, self_ty)); check_that!(table.unify(&expect_self_ty, self_ty));
@ -1488,15 +1488,10 @@ fn is_valid_method_candidate(
} }
} }
enum IsValidCandidate {
Yes,
No,
NotVisible,
}
#[tracing::instrument(skip_all, fields(name))] #[tracing::instrument(skip_all, fields(name))]
fn is_valid_fn_candidate( fn is_valid_impl_fn_candidate(
table: &mut InferenceTable<'_>, table: &mut InferenceTable<'_>,
impl_id: ImplId,
fn_id: FunctionId, fn_id: FunctionId,
name: Option<&Name>, name: Option<&Name>,
receiver_ty: Option<&Ty>, receiver_ty: Option<&Ty>,
@ -1514,24 +1509,10 @@ fn is_valid_fn_candidate(
} }
} }
table.run_in_snapshot(|table| { table.run_in_snapshot(|table| {
let container = fn_id.lookup(db.upcast()).container;
let _p = tracing::span!(tracing::Level::INFO, "subst_for_def").entered(); let _p = tracing::span!(tracing::Level::INFO, "subst_for_def").entered();
let (impl_subst, expect_self_ty) = match container { let impl_subst =
ItemContainerId::ImplId(it) => { TyBuilder::subst_for_def(db, impl_id, None).fill_with_inference_vars(table).build();
let subst = let expect_self_ty = db.impl_self_ty(impl_id).substitute(Interner, &impl_subst);
TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
let self_ty = db.impl_self_ty(it).substitute(Interner, &subst);
(subst, self_ty)
}
ItemContainerId::TraitId(it) => {
let subst =
TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
let self_ty = subst.at(Interner, 0).assert_ty_ref(Interner).clone();
(subst, self_ty)
}
_ => unreachable!(),
};
check_that!(table.unify(&expect_self_ty, self_ty)); check_that!(table.unify(&expect_self_ty, self_ty));
@ -1550,63 +1531,55 @@ fn is_valid_fn_candidate(
check_that!(table.unify(receiver_ty, &expected_receiver)); check_that!(table.unify(receiver_ty, &expected_receiver));
} }
if let ItemContainerId::ImplId(impl_id) = container { // We need to consider the bounds on the impl to distinguish functions of the same name
let _p = tracing::span!(tracing::Level::INFO, "check_item_container").entered(); // for a type.
// We need to consider the bounds on the impl to distinguish functions of the same name let predicates = db.generic_predicates(impl_id.into());
// for a type. let goals = predicates.iter().map(|p| {
let predicates = db.generic_predicates(impl_id.into()); let (p, b) = p
let goals = predicates.iter().map(|p| { .clone()
let (p, b) = p .substitute(Interner, &impl_subst)
.clone() // Skipping the inner binders is ok, as we don't handle quantified where
.substitute(Interner, &impl_subst) // clauses yet.
// Skipping the inner binders is ok, as we don't handle quantified where .into_value_and_skipped_binders();
// clauses yet. stdx::always!(b.len(Interner) == 0);
.into_value_and_skipped_binders();
stdx::always!(b.len(Interner) == 0);
p.cast::<Goal>(Interner) p.cast::<Goal>(Interner)
}); });
for goal in goals.clone() { for goal in goals.clone() {
let in_env = InEnvironment::new(&table.trait_env.env, goal); let in_env = InEnvironment::new(&table.trait_env.env, goal);
let canonicalized = table.canonicalize(in_env); let canonicalized = table.canonicalize(in_env);
let solution = table.db.trait_solve( let solution = table.db.trait_solve(
table.trait_env.krate, table.trait_env.krate,
table.trait_env.block, table.trait_env.block,
canonicalized.value.clone(), canonicalized.value.clone(),
); );
match solution { match solution {
Some(Solution::Unique(canonical_subst)) => { Some(Solution::Unique(canonical_subst)) => {
canonicalized.apply_solution( canonicalized.apply_solution(
table, table,
Canonical { Canonical {
binders: canonical_subst.binders, binders: canonical_subst.binders,
value: canonical_subst.value.subst, value: canonical_subst.value.subst,
}, },
); );
}
Some(Solution::Ambig(Guidance::Definite(substs))) => {
canonicalized.apply_solution(table, substs);
}
Some(_) => (),
None => return IsValidCandidate::No,
} }
} Some(Solution::Ambig(Guidance::Definite(substs))) => {
canonicalized.apply_solution(table, substs);
for goal in goals {
if table.try_obligation(goal).is_none() {
return IsValidCandidate::No;
} }
Some(_) => (),
None => return IsValidCandidate::No,
} }
IsValidCandidate::Yes
} else {
// For `ItemContainerId::TraitId`, we check if `self_ty` implements the trait in
// `iterate_trait_method_candidates()`.
// For others, this function shouldn't be called.
IsValidCandidate::Yes
} }
for goal in goals {
if table.try_obligation(goal).is_none() {
return IsValidCandidate::No;
}
}
IsValidCandidate::Yes
}) })
} }