internal: Remove dead branches in method_resolutiopn::is_valid_candidate
This commit is contained in:
parent
cc7fe32ba3
commit
3a1b4c29b3
@ -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
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user