about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2024-01-26 20:07:37 +0000
committerEsteban Küber <esteban@kuber.com.ar>2024-01-26 20:47:11 +0000
commit3691ab8e7adc91f877ded39faba826f5c9f8a5a1 (patch)
treea6b2bcbfd2ff6cc70527b9f18c9f0733404b86a1
parent0b7730105fb7e008002f6ba29f87a55699f67744 (diff)
downloadrust-3691ab8e7adc91f877ded39faba826f5c9f8a5a1.tar.gz
rust-3691ab8e7adc91f877ded39faba826f5c9f8a5a1.zip
Use only one label for multiple unsatisfied bounds on type (astconv)
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs39
-rw-r--r--tests/ui/associated-inherent-types/not-found-unsatisfied-bounds-in-multiple-impls.stderr5
2 files changed, 29 insertions, 15 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index bfe88df4e1a..b2d5d3885d9 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -461,22 +461,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             return err.emit();
         }
 
-        let mut bound_spans = Vec::new();
+        let mut bound_spans: FxHashMap<Span, Vec<String>> = Default::default();
 
         let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
-            let msg = format!(
-                "doesn't satisfy `{}`",
-                if obligation.len() > 50 { quiet } else { obligation }
-            );
+            let msg = format!("`{}`", if obligation.len() > 50 { quiet } else { obligation });
             match &self_ty.kind() {
                 // Point at the type that couldn't satisfy the bound.
-                ty::Adt(def, _) => bound_spans.push((tcx.def_span(def.did()), msg)),
+                ty::Adt(def, _) => {
+                    bound_spans.entry(tcx.def_span(def.did())).or_default().push(msg)
+                }
                 // Point at the trait object that couldn't satisfy the bound.
                 ty::Dynamic(preds, _, _) => {
                     for pred in preds.iter() {
                         match pred.skip_binder() {
                             ty::ExistentialPredicate::Trait(tr) => {
-                                bound_spans.push((tcx.def_span(tr.def_id), msg.clone()))
+                                bound_spans
+                                    .entry(tcx.def_span(tr.def_id))
+                                    .or_default()
+                                    .push(msg.clone());
                             }
                             ty::ExistentialPredicate::Projection(_)
                             | ty::ExistentialPredicate::AutoTrait(_) => {}
@@ -485,7 +487,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 }
                 // Point at the closure that couldn't satisfy the bound.
                 ty::Closure(def_id, _) => {
-                    bound_spans.push((tcx.def_span(*def_id), format!("doesn't satisfy `{quiet}`")))
+                    bound_spans
+                        .entry(tcx.def_span(*def_id))
+                        .or_default()
+                        .push(format!("`{quiet}`"));
                 }
                 _ => {}
             }
@@ -554,12 +559,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             format!("associated type cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
         );
 
-        bound_spans.sort();
-        bound_spans.dedup();
-        for (span, msg) in bound_spans {
+        let mut bound_spans: Vec<(Span, Vec<String>)> = bound_spans
+            .into_iter()
+            .map(|(span, mut bounds)| {
+                bounds.sort();
+                bounds.dedup();
+                (span, bounds)
+            })
+            .collect();
+        bound_spans.sort_by_key(|(span, _)| *span);
+        for (span, bounds) in bound_spans {
             if !tcx.sess.source_map().is_span_accessible(span) {
                 continue;
             }
+            let msg = match &bounds[..] {
+                [bound] => format!("doesn't satisfy {bound}"),
+                [bounds @ .., last] => format!("doesn't satisfy {} or {last}", bounds.join(", ")),
+                [] => unreachable!(),
+            };
             err.span_label(span, msg);
         }
         add_def_label(&mut err);
diff --git a/tests/ui/associated-inherent-types/not-found-unsatisfied-bounds-in-multiple-impls.stderr b/tests/ui/associated-inherent-types/not-found-unsatisfied-bounds-in-multiple-impls.stderr
index 650b5946064..1613af6b8b1 100644
--- a/tests/ui/associated-inherent-types/not-found-unsatisfied-bounds-in-multiple-impls.stderr
+++ b/tests/ui/associated-inherent-types/not-found-unsatisfied-bounds-in-multiple-impls.stderr
@@ -4,10 +4,7 @@ error: the associated type `X` exists for `S<Featureless, Featureless>`, but its
 LL | struct S<A, B>(A, B);
    | -------------- associated item `X` not found for this struct
 LL | struct Featureless;
-   | ------------------
-   | |
-   | doesn't satisfy `Featureless: One`
-   | doesn't satisfy `Featureless: Two`
+   | ------------------ doesn't satisfy `Featureless: One` or `Featureless: Two`
 ...
 LL |     let _: S::<Featureless, Featureless>::X;
    |                                           ^ associated type cannot be referenced on `S<Featureless, Featureless>` due to unsatisfied trait bounds