about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs62
-rw-r--r--compiler/rustc_middle/src/ty/util.rs37
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs145
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs22
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs20
6 files changed, 154 insertions, 142 deletions
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 6747da7abd3..e61037e5ea8 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -139,40 +139,6 @@ 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
-            });
-    }
-
-    /// `trait_def_id` MUST BE the `DefId` of a trait.
-    pub fn non_blanket_impls_for_ty(
-        self,
-        trait_def_id: DefId,
-        self_ty: Ty<'tcx>,
-    ) -> impl Iterator<Item = DefId> + 'tcx {
-        let impls = self.trait_impls_of(trait_def_id);
-        if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsCandidateKey) {
-            if let Some(impls) = impls.non_blanket_impls.get(&simp) {
-                return impls.iter().copied();
-            }
-        }
-
-        [].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.
         //
@@ -181,9 +147,7 @@ impl<'tcx> TyCtxt<'tcx> {
         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;
-            }
+            f(impl_def_id);
         }
 
         // Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using
@@ -199,20 +163,30 @@ impl<'tcx> TyCtxt<'tcx> {
         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;
-                    }
+                    f(impl_def_id);
                 }
             }
         } else {
             for &impl_def_id in impls.non_blanket_impls.values().flatten() {
-                if let result @ Some(_) = f(impl_def_id) {
-                    return result;
-                }
+                f(impl_def_id);
             }
         }
+    }
 
-        None
+    /// `trait_def_id` MUST BE the `DefId` of a trait.
+    pub fn non_blanket_impls_for_ty(
+        self,
+        trait_def_id: DefId,
+        self_ty: Ty<'tcx>,
+    ) -> impl Iterator<Item = DefId> + 'tcx {
+        let impls = self.trait_impls_of(trait_def_id);
+        if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsCandidateKey) {
+            if let Some(impls) = impls.non_blanket_impls.get(&simp) {
+                return impls.iter().copied();
+            }
+        }
+
+        [].iter().copied()
     }
 
     /// Returns an iterator containing all impls for `trait_def_id`.
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index dbe2eebe336..9dbd9fbbb5b 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -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 })
     }
 
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 1abcc80d01a..8e7097ce4a7 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -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`.
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index ae21dcd2a36..61e382bbe49 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -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
     }
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index a019d00461b..1db9b8ce92e 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -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 {
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 33e80df9ed7..f2486abaaa7 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -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.