Rollup merge of #110514 - compiler-errors:remove-find_map_relevant_impl, r=b-naber
Remove `find_map_relevant_impl` Fixes #108895
This commit is contained in:
commit
d60c64a0c5
6 changed files with 168 additions and 156 deletions
|
@ -139,11 +139,38 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
treat_projections: TreatProjections,
|
||||
mut f: impl FnMut(DefId),
|
||||
) {
|
||||
let _: Option<()> =
|
||||
self.find_map_relevant_impl(trait_def_id, self_ty, treat_projections, |did| {
|
||||
f(did);
|
||||
None
|
||||
});
|
||||
// FIXME: This depends on the set of all impls for the trait. That is
|
||||
// unfortunate wrt. incremental compilation.
|
||||
//
|
||||
// If we want to be faster, we could have separate queries for
|
||||
// blanket and non-blanket impls, and compare them separately.
|
||||
let impls = self.trait_impls_of(trait_def_id);
|
||||
|
||||
for &impl_def_id in impls.blanket_impls.iter() {
|
||||
f(impl_def_id);
|
||||
}
|
||||
|
||||
// Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using
|
||||
// `TreatParams::AsCandidateKey` while actually adding them.
|
||||
let treat_params = match treat_projections {
|
||||
TreatProjections::NextSolverLookup => TreatParams::NextSolverLookup,
|
||||
TreatProjections::ForLookup => TreatParams::ForLookup,
|
||||
};
|
||||
// This way, when searching for some impl for `T: Trait`, we do not look at any impls
|
||||
// whose outer level is not a parameter or projection. Especially for things like
|
||||
// `T: Clone` this is incredibly useful as we would otherwise look at all the impls
|
||||
// of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
|
||||
if let Some(simp) = fast_reject::simplify_type(self, self_ty, treat_params) {
|
||||
if let Some(impls) = impls.non_blanket_impls.get(&simp) {
|
||||
for &impl_def_id in impls {
|
||||
f(impl_def_id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for &impl_def_id in impls.non_blanket_impls.values().flatten() {
|
||||
f(impl_def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `trait_def_id` MUST BE the `DefId` of a trait.
|
||||
|
@ -162,59 +189,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
[].iter().copied()
|
||||
}
|
||||
|
||||
/// Applies function to every impl that could possibly match the self type `self_ty` and returns
|
||||
/// the first non-none value.
|
||||
///
|
||||
/// `trait_def_id` MUST BE the `DefId` of a trait.
|
||||
pub fn find_map_relevant_impl<T>(
|
||||
self,
|
||||
trait_def_id: DefId,
|
||||
self_ty: Ty<'tcx>,
|
||||
treat_projections: TreatProjections,
|
||||
mut f: impl FnMut(DefId) -> Option<T>,
|
||||
) -> Option<T> {
|
||||
// FIXME: This depends on the set of all impls for the trait. That is
|
||||
// unfortunate wrt. incremental compilation.
|
||||
//
|
||||
// If we want to be faster, we could have separate queries for
|
||||
// blanket and non-blanket impls, and compare them separately.
|
||||
let impls = self.trait_impls_of(trait_def_id);
|
||||
|
||||
for &impl_def_id in impls.blanket_impls.iter() {
|
||||
if let result @ Some(_) = f(impl_def_id) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using
|
||||
// `TreatParams::AsCandidateKey` while actually adding them.
|
||||
let treat_params = match treat_projections {
|
||||
TreatProjections::NextSolverLookup => TreatParams::NextSolverLookup,
|
||||
TreatProjections::ForLookup => TreatParams::ForLookup,
|
||||
};
|
||||
// This way, when searching for some impl for `T: Trait`, we do not look at any impls
|
||||
// whose outer level is not a parameter or projection. Especially for things like
|
||||
// `T: Clone` this is incredibly useful as we would otherwise look at all the impls
|
||||
// of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
|
||||
if let Some(simp) = fast_reject::simplify_type(self, self_ty, treat_params) {
|
||||
if let Some(impls) = impls.non_blanket_impls.get(&simp) {
|
||||
for &impl_def_id in impls {
|
||||
if let result @ Some(_) = f(impl_def_id) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for &impl_def_id in impls.non_blanket_impls.values().flatten() {
|
||||
if let result @ Some(_) = f(impl_def_id) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns an iterator containing all impls for `trait_def_id`.
|
||||
///
|
||||
/// `trait_def_id` MUST BE the `DefId` of a trait.
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use crate::mir;
|
||||
use crate::ty::fast_reject::TreatProjections;
|
||||
use crate::ty::layout::IntegerExt;
|
||||
use crate::ty::{
|
||||
self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
|
||||
|
@ -359,21 +358,29 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self.ensure().coherent_trait(drop_trait);
|
||||
|
||||
let ty = self.type_of(adt_did).subst_identity();
|
||||
let (did, constness) = self.find_map_relevant_impl(
|
||||
drop_trait,
|
||||
ty,
|
||||
// FIXME: This could also be some other mode, like "unexpected"
|
||||
TreatProjections::ForLookup,
|
||||
|impl_did| {
|
||||
if let Some(item_id) = self.associated_item_def_ids(impl_did).first() {
|
||||
if validate(self, impl_did).is_ok() {
|
||||
return Some((*item_id, self.constness(impl_did)));
|
||||
}
|
||||
}
|
||||
None
|
||||
},
|
||||
)?;
|
||||
let mut dtor_candidate = None;
|
||||
self.for_each_relevant_impl(drop_trait, ty, |impl_did| {
|
||||
let Some(item_id) = self.associated_item_def_ids(impl_did).first() else {
|
||||
self.sess.delay_span_bug(self.def_span(impl_did), "Drop impl without drop function");
|
||||
return;
|
||||
};
|
||||
|
||||
if validate(self, impl_did).is_err() {
|
||||
// Already `ErrorGuaranteed`, no need to delay a span bug here.
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some((old_item_id, _)) = dtor_candidate {
|
||||
self.sess
|
||||
.struct_span_err(self.def_span(item_id), "multiple drop impls found")
|
||||
.span_note(self.def_span(old_item_id), "other impl here")
|
||||
.delay_as_bug();
|
||||
}
|
||||
|
||||
dtor_candidate = Some((*item_id, self.constness(impl_did)));
|
||||
});
|
||||
|
||||
let (did, constness) = dtor_candidate?;
|
||||
Some(ty::Destructor { did, constness })
|
||||
}
|
||||
|
||||
|
|
|
@ -645,12 +645,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
// FIXME: Handling opaques here is kinda sus. Especially because we
|
||||
// simplify them to PlaceholderSimplifiedType.
|
||||
| ty::Alias(ty::Opaque, _) => {
|
||||
if let Some(def_id) = self.tcx().find_map_relevant_impl(
|
||||
let mut disqualifying_impl = None;
|
||||
self.tcx().for_each_relevant_impl_treating_projections(
|
||||
goal.predicate.def_id(),
|
||||
goal.predicate.self_ty(),
|
||||
TreatProjections::NextSolverLookup,
|
||||
Some,
|
||||
) {
|
||||
|impl_def_id| {
|
||||
disqualifying_impl = Some(impl_def_id);
|
||||
},
|
||||
);
|
||||
if let Some(def_id) = disqualifying_impl {
|
||||
debug!(?def_id, ?goal, "disqualified auto-trait implementation");
|
||||
// No need to actually consider the candidate here,
|
||||
// since we do that in `consider_impl_candidate`.
|
||||
|
|
|
@ -32,7 +32,6 @@ use rustc_infer::infer::{InferOk, TypeTrace};
|
|||
use rustc_middle::traits::select::OverflowError;
|
||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::fast_reject::TreatProjections;
|
||||
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
|
||||
use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
|
||||
use rustc_middle::ty::{
|
||||
|
@ -1836,57 +1835,61 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
});
|
||||
let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
|
||||
|
||||
let secondary_span = match predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => self
|
||||
.tcx
|
||||
.opt_associated_item(proj.projection_ty.def_id)
|
||||
.and_then(|trait_assoc_item| {
|
||||
self.tcx
|
||||
.trait_of_item(proj.projection_ty.def_id)
|
||||
.map(|id| (trait_assoc_item, id))
|
||||
})
|
||||
.and_then(|(trait_assoc_item, id)| {
|
||||
let trait_assoc_ident = trait_assoc_item.ident(self.tcx);
|
||||
self.tcx.find_map_relevant_impl(
|
||||
id,
|
||||
proj.projection_ty.self_ty(),
|
||||
TreatProjections::ForLookup,
|
||||
|did| {
|
||||
self.tcx
|
||||
.associated_items(did)
|
||||
.in_definition_order()
|
||||
.find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident)
|
||||
},
|
||||
)
|
||||
})
|
||||
.and_then(|item| match self.tcx.hir().get_if_local(item.def_id) {
|
||||
Some(
|
||||
hir::Node::TraitItem(hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Type(_, Some(ty)),
|
||||
..
|
||||
})
|
||||
| hir::Node::ImplItem(hir::ImplItem {
|
||||
kind: hir::ImplItemKind::Type(ty),
|
||||
..
|
||||
}),
|
||||
) => Some((
|
||||
ty.span,
|
||||
with_forced_trimmed_paths!(format!(
|
||||
"type mismatch resolving `{}`",
|
||||
self.resolve_vars_if_possible(predicate)
|
||||
.print(FmtPrinter::new_with_limit(
|
||||
self.tcx,
|
||||
Namespace::TypeNS,
|
||||
rustc_session::Limit(5),
|
||||
))
|
||||
.unwrap()
|
||||
.into_buffer()
|
||||
)),
|
||||
let secondary_span = (|| {
|
||||
let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) =
|
||||
predicate.kind().skip_binder()
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let trait_assoc_item = self.tcx.opt_associated_item(proj.projection_ty.def_id)?;
|
||||
let trait_assoc_ident = trait_assoc_item.ident(self.tcx);
|
||||
|
||||
let mut associated_items = vec![];
|
||||
self.tcx.for_each_relevant_impl(
|
||||
self.tcx.trait_of_item(proj.projection_ty.def_id)?,
|
||||
proj.projection_ty.self_ty(),
|
||||
|impl_def_id| {
|
||||
associated_items.extend(
|
||||
self.tcx
|
||||
.associated_items(impl_def_id)
|
||||
.in_definition_order()
|
||||
.find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
let [associated_item]: &[ty::AssocItem] = &associated_items[..] else {
|
||||
return None;
|
||||
};
|
||||
match self.tcx.hir().get_if_local(associated_item.def_id) {
|
||||
Some(
|
||||
hir::Node::TraitItem(hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Type(_, Some(ty)),
|
||||
..
|
||||
})
|
||||
| hir::Node::ImplItem(hir::ImplItem {
|
||||
kind: hir::ImplItemKind::Type(ty),
|
||||
..
|
||||
}),
|
||||
) => Some((
|
||||
ty.span,
|
||||
with_forced_trimmed_paths!(format!(
|
||||
"type mismatch resolving `{}`",
|
||||
self.resolve_vars_if_possible(predicate)
|
||||
.print(FmtPrinter::new_with_limit(
|
||||
self.tcx,
|
||||
Namespace::TypeNS,
|
||||
rustc_session::Limit(5),
|
||||
))
|
||||
.unwrap()
|
||||
.into_buffer()
|
||||
)),
|
||||
_ => None,
|
||||
}),
|
||||
_ => None,
|
||||
};
|
||||
)),
|
||||
_ => None,
|
||||
}
|
||||
})();
|
||||
|
||||
self.note_type_err(
|
||||
&mut diag,
|
||||
&obligation.cause,
|
||||
|
@ -2228,14 +2231,18 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
err: &mut Diagnostic,
|
||||
trait_ref: &ty::PolyTraitRef<'tcx>,
|
||||
) -> bool {
|
||||
let get_trait_impl = |trait_def_id| {
|
||||
self.tcx.find_map_relevant_impl(
|
||||
let get_trait_impls = |trait_def_id| {
|
||||
let mut trait_impls = vec![];
|
||||
self.tcx.for_each_relevant_impl(
|
||||
trait_def_id,
|
||||
trait_ref.skip_binder().self_ty(),
|
||||
TreatProjections::ForLookup,
|
||||
Some,
|
||||
)
|
||||
|impl_def_id| {
|
||||
trait_impls.push(impl_def_id);
|
||||
},
|
||||
);
|
||||
trait_impls
|
||||
};
|
||||
|
||||
let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
|
||||
let traits_with_same_path: std::collections::BTreeSet<_> = self
|
||||
.tcx
|
||||
|
@ -2245,17 +2252,23 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
.collect();
|
||||
let mut suggested = false;
|
||||
for trait_with_same_path in traits_with_same_path {
|
||||
if let Some(impl_def_id) = get_trait_impl(trait_with_same_path) {
|
||||
let impl_span = self.tcx.def_span(impl_def_id);
|
||||
err.span_help(impl_span, "trait impl with same name found");
|
||||
let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
|
||||
let crate_msg = format!(
|
||||
"perhaps two different versions of crate `{}` are being used?",
|
||||
trait_crate
|
||||
);
|
||||
err.note(&crate_msg);
|
||||
suggested = true;
|
||||
let trait_impls = get_trait_impls(trait_with_same_path);
|
||||
if trait_impls.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let impl_spans: Vec<_> =
|
||||
trait_impls.iter().map(|impl_def_id| self.tcx.def_span(*impl_def_id)).collect();
|
||||
err.span_help(
|
||||
impl_spans,
|
||||
format!("trait impl{} with same name found", pluralize!(trait_impls.len())),
|
||||
);
|
||||
let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
|
||||
let crate_msg = format!(
|
||||
"perhaps two different versions of crate `{}` are being used?",
|
||||
trait_crate
|
||||
);
|
||||
err.note(&crate_msg);
|
||||
suggested = true;
|
||||
}
|
||||
suggested
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use hir::LangItem;
|
|||
use rustc_hir as hir;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
|
||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
|
||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
||||
|
||||
use crate::traits;
|
||||
|
@ -875,12 +875,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
ty::Adt(..) => {
|
||||
// Find a custom `impl Drop` impl, if it exists
|
||||
let relevant_impl = self.tcx().find_map_relevant_impl(
|
||||
let mut relevant_impl = None;
|
||||
self.tcx().for_each_relevant_impl(
|
||||
self.tcx().require_lang_item(LangItem::Drop, None),
|
||||
obligation.predicate.skip_binder().trait_ref.self_ty(),
|
||||
TreatProjections::ForLookup,
|
||||
Some,
|
||||
|impl_def_id| {
|
||||
if let Some(old_impl_def_id) = relevant_impl {
|
||||
self.tcx()
|
||||
.sess
|
||||
.struct_span_err(
|
||||
self.tcx().def_span(impl_def_id),
|
||||
"multiple drop impls found",
|
||||
)
|
||||
.span_note(self.tcx().def_span(old_impl_def_id), "other impl here")
|
||||
.delay_as_bug();
|
||||
}
|
||||
|
||||
relevant_impl = Some(impl_def_id);
|
||||
},
|
||||
);
|
||||
|
||||
if let Some(impl_def_id) = relevant_impl {
|
||||
|
|
|
@ -13,7 +13,7 @@ use rustc_hir::def::Namespace::*;
|
|||
use rustc_hir::def::{DefKind, Namespace, PerNS};
|
||||
use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
|
||||
use rustc_hir::Mutability;
|
||||
use rustc_middle::ty::{fast_reject::TreatProjections, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{Ty, TyCtxt};
|
||||
use rustc_middle::{bug, ty};
|
||||
use rustc_resolve::rustdoc::{has_primitive_or_keyword_docs, prepare_to_doc_link_resolution};
|
||||
use rustc_resolve::rustdoc::{strip_generics_from_path, MalformedGenerics};
|
||||
|
@ -772,11 +772,10 @@ fn trait_impls_for<'a>(
|
|||
module: DefId,
|
||||
) -> FxHashSet<(DefId, DefId)> {
|
||||
let tcx = cx.tcx;
|
||||
let iter = tcx.doc_link_traits_in_scope(module).iter().flat_map(|&trait_| {
|
||||
trace!("considering explicit impl for trait {:?}", trait_);
|
||||
let mut impls = FxHashSet::default();
|
||||
|
||||
// Look at each trait implementation to see if it's an impl for `did`
|
||||
tcx.find_map_relevant_impl(trait_, ty, TreatProjections::ForLookup, |impl_| {
|
||||
for &trait_ in tcx.doc_link_traits_in_scope(module) {
|
||||
tcx.for_each_relevant_impl(trait_, ty, |impl_| {
|
||||
let trait_ref = tcx.impl_trait_ref(impl_).expect("this is not an inherent impl");
|
||||
// Check if these are the same type.
|
||||
let impl_type = trait_ref.skip_binder().self_ty();
|
||||
|
@ -800,10 +799,13 @@ fn trait_impls_for<'a>(
|
|||
_ => false,
|
||||
};
|
||||
|
||||
if saw_impl { Some((impl_, trait_)) } else { None }
|
||||
})
|
||||
});
|
||||
iter.collect()
|
||||
if saw_impl {
|
||||
impls.insert((impl_, trait_));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
impls
|
||||
}
|
||||
|
||||
/// Check for resolve collisions between a trait and its derive.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue