From 3691ab8e7adc91f877ded39faba826f5c9f8a5a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 26 Jan 2024 20:07:37 +0000 Subject: [PATCH 1/4] Use only one label for multiple unsatisfied bounds on type (astconv) --- .../rustc_hir_analysis/src/astconv/errors.rs | 39 +++++++++++++------ ...nsatisfied-bounds-in-multiple-impls.stderr | 5 +-- 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 bfe88df4e1a55..b2d5d3885d938 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> = 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)> = 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 650b5946064c2..1613af6b8b152 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`, but its LL | struct S(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::::X; | ^ associated type cannot be referenced on `S` due to unsatisfied trait bounds From 757b726f8689c508dbd3979ea6b547a74d6481b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 26 Jan 2024 20:34:29 +0000 Subject: [PATCH 2/4] Use only one label for multiple unsatisfied bounds on type (typeck) --- .../rustc_hir_typeck/src/method/suggest.rs | 48 ++++++++++++++----- .../box/unit/unique-object-noncopyable.stderr | 15 ++---- tests/ui/box/unit/unique-pinned-nocopy.stderr | 12 ++--- .../deriving-with-repr-packed-2.stderr | 5 +- tests/ui/derives/issue-91550.stderr | 25 ++-------- ...gat-bound-during-assoc-ty-selection.stderr | 3 -- ...method-unsatisfied-assoc-type-predicate.rs | 3 +- ...od-unsatisfied-assoc-type-predicate.stderr | 5 +- .../ui/iterators/vec-on-unimplemented.stderr | 3 -- .../ui/mismatched_types/issue-36053-2.stderr | 6 +-- .../derive-trait-for-method-call.stderr | 16 +------ .../mut-borrow-needed-by-trait.stderr | 3 -- .../ui/suggestions/suggest-change-mut.stderr | 3 -- tests/ui/traits/track-obligations.stderr | 5 +- tests/ui/typeck/derive-sugg-arg-arity.stderr | 3 +- tests/ui/typeck/issue-31173.stderr | 6 --- 16 files changed, 56 insertions(+), 105 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 0b8a25eedafad..d7a0565895d3e 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -9,7 +9,7 @@ use crate::Expectation; use crate::FnCtxt; use rustc_ast::ast::Mutability; use rustc_attr::parse_confusables; -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::unord::UnordSet; use rustc_errors::StashKey; use rustc_errors::{ @@ -547,7 +547,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - let mut bound_spans = vec![]; + let mut bound_spans: FxHashMap> = Default::default(); let mut restrict_type_params = false; let mut unsatisfied_bounds = false; if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) { @@ -642,19 +642,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false }; 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((self.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((self.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(_) => {} @@ -662,8 +664,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } // 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}`"))), + ty::Closure(def_id, _) => { + bound_spans + .entry(tcx.def_span(*def_id)) + .or_default() + .push(format!("`{quiet}`")); + } _ => {} } }; @@ -1170,9 +1176,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.suggest_unwrapping_inner_self(&mut err, source, rcvr_ty, item_name); - bound_spans.sort(); - bound_spans.dedup(); - for (span, msg) in bound_spans.into_iter() { + #[allow(rustc::potential_query_instability)] // We immediately sort the resulting Vec. + let mut bound_spans: Vec<(Span, Vec)> = 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); } diff --git a/tests/ui/box/unit/unique-object-noncopyable.stderr b/tests/ui/box/unit/unique-object-noncopyable.stderr index 1b98d09ccddb0..49547872d1a7b 100644 --- a/tests/ui/box/unit/unique-object-noncopyable.stderr +++ b/tests/ui/box/unit/unique-object-noncopyable.stderr @@ -1,18 +1,11 @@ error[E0599]: the method `clone` exists for struct `Box`, but its trait bounds were not satisfied --> $DIR/unique-object-noncopyable.rs:24:16 | -LL | trait Foo { - | --------- - | | - | doesn't satisfy `dyn Foo: Clone` - | doesn't satisfy `dyn Foo: Sized` +LL | trait Foo { + | --------- doesn't satisfy `dyn Foo: Clone` or `dyn Foo: Sized` ... -LL | let _z = y.clone(); - | ^^^^^ method cannot be called on `Box` due to unsatisfied trait bounds - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL - | - = note: doesn't satisfy `Box: Clone` +LL | let _z = y.clone(); + | ^^^^^ method cannot be called on `Box` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `dyn Foo: Sized` diff --git a/tests/ui/box/unit/unique-pinned-nocopy.stderr b/tests/ui/box/unit/unique-pinned-nocopy.stderr index d662a2d6d0512..d2bf72249c451 100644 --- a/tests/ui/box/unit/unique-pinned-nocopy.stderr +++ b/tests/ui/box/unit/unique-pinned-nocopy.stderr @@ -1,15 +1,11 @@ error[E0599]: the method `clone` exists for struct `Box`, but its trait bounds were not satisfied --> $DIR/unique-pinned-nocopy.rs:12:16 | -LL | struct R { - | -------- doesn't satisfy `R: Clone` +LL | struct R { + | -------- doesn't satisfy `R: Clone` ... -LL | let _j = i.clone(); - | ^^^^^ method cannot be called on `Box` due to unsatisfied trait bounds - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL - | - = note: doesn't satisfy `Box: Clone` +LL | let _j = i.clone(); + | ^^^^^ method cannot be called on `Box` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `R: Clone` diff --git a/tests/ui/derives/deriving-with-repr-packed-2.stderr b/tests/ui/derives/deriving-with-repr-packed-2.stderr index 0eaca7e236098..172dd80fe1d09 100644 --- a/tests/ui/derives/deriving-with-repr-packed-2.stderr +++ b/tests/ui/derives/deriving-with-repr-packed-2.stderr @@ -8,10 +8,7 @@ LL | pub struct Foo(T, T, T); | doesn't satisfy `Foo: Clone` LL | LL | struct NonCopy; - | -------------- - | | - | doesn't satisfy `NonCopy: Clone` - | doesn't satisfy `NonCopy: Copy` + | -------------- doesn't satisfy `NonCopy: Clone` or `NonCopy: Copy` ... LL | _ = x.clone(); | ^^^^^ method cannot be called on `Foo` due to unsatisfied trait bounds diff --git a/tests/ui/derives/issue-91550.stderr b/tests/ui/derives/issue-91550.stderr index 1324b80b5fcdb..9e17189671827 100644 --- a/tests/ui/derives/issue-91550.stderr +++ b/tests/ui/derives/issue-91550.stderr @@ -2,11 +2,7 @@ error[E0599]: the method `insert` exists for struct `HashSet`, but its tr --> $DIR/issue-91550.rs:8:8 | LL | struct Value(u32); - | ------------ - | | - | doesn't satisfy `Value: Eq` - | doesn't satisfy `Value: Hash` - | doesn't satisfy `Value: PartialEq` + | ------------ doesn't satisfy `Value: Eq`, `Value: Hash` or `Value: PartialEq` ... LL | hs.insert(Value(0)); | ^^^^^^ @@ -26,10 +22,7 @@ error[E0599]: the method `use_eq` exists for struct `Object`, but its --> $DIR/issue-91550.rs:26:9 | LL | pub struct NoDerives; - | -------------------- - | | - | doesn't satisfy `NoDerives: Eq` - | doesn't satisfy `NoDerives: PartialEq` + | -------------------- doesn't satisfy `NoDerives: Eq` or `NoDerives: PartialEq` LL | LL | struct Object(T); | ---------------- method `use_eq` not found for this struct @@ -57,12 +50,7 @@ error[E0599]: the method `use_ord` exists for struct `Object`, but it --> $DIR/issue-91550.rs:27:9 | LL | pub struct NoDerives; - | -------------------- - | | - | doesn't satisfy `NoDerives: Eq` - | doesn't satisfy `NoDerives: Ord` - | doesn't satisfy `NoDerives: PartialEq` - | doesn't satisfy `NoDerives: PartialOrd` + | -------------------- doesn't satisfy `NoDerives: Eq`, `NoDerives: Ord`, `NoDerives: PartialEq` or `NoDerives: PartialOrd` LL | LL | struct Object(T); | ---------------- method `use_ord` not found for this struct @@ -94,12 +82,7 @@ error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object $DIR/issue-91550.rs:28:9 | LL | pub struct NoDerives; - | -------------------- - | | - | doesn't satisfy `NoDerives: Eq` - | doesn't satisfy `NoDerives: Ord` - | doesn't satisfy `NoDerives: PartialEq` - | doesn't satisfy `NoDerives: PartialOrd` + | -------------------- doesn't satisfy `NoDerives: Eq`, `NoDerives: Ord`, `NoDerives: PartialEq` or `NoDerives: PartialOrd` LL | LL | struct Object(T); | ---------------- method `use_ord_and_partial_ord` not found for this struct diff --git a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr index 3a973d356dc98..2ce10ce9c1cc0 100644 --- a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr +++ b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr @@ -26,9 +26,6 @@ LL | enum Node { ... LL | let mut list = RcNode::::new(); | ^^^ doesn't have a size known at compile-time - --> $SRC_DIR/core/src/ops/deref.rs:LL:COL - | - = note: doesn't satisfy `_: Sized` | note: trait bound `Node: Sized` was not satisfied --> $DIR/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs:4:18 diff --git a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs index 83655341d6a24..1f9e4f24b161c 100644 --- a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs +++ b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs @@ -17,8 +17,7 @@ impl = i32>> M for T {} struct S; //~^ NOTE method `f` not found for this -//~| NOTE doesn't satisfy `::Y = i32` -//~| NOTE doesn't satisfy `S: M` +//~| NOTE doesn't satisfy `::Y = i32` or `S: M` impl X for S { type Y = bool; diff --git a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr index 7ca0b2912a68a..489b2772ad8c3 100644 --- a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr +++ b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr @@ -1,12 +1,11 @@ error[E0599]: the method `f` exists for struct `S`, but its trait bounds were not satisfied - --> $DIR/method-unsatisfied-assoc-type-predicate.rs:28:7 + --> $DIR/method-unsatisfied-assoc-type-predicate.rs:27:7 | LL | struct S; | -------- | | | method `f` not found for this struct - | doesn't satisfy `::Y = i32` - | doesn't satisfy `S: M` + | doesn't satisfy `::Y = i32` or `S: M` ... LL | a.f(); | ^ method cannot be called on `S` due to unsatisfied trait bounds diff --git a/tests/ui/iterators/vec-on-unimplemented.stderr b/tests/ui/iterators/vec-on-unimplemented.stderr index e2a80dbffdeaa..29b19d5e3b45b 100644 --- a/tests/ui/iterators/vec-on-unimplemented.stderr +++ b/tests/ui/iterators/vec-on-unimplemented.stderr @@ -3,9 +3,6 @@ error[E0599]: `Vec` is not an iterator | LL | vec![true, false].map(|v| !v).collect::>(); | ^^^ `Vec` is not an iterator; try calling `.into_iter()` or `.iter()` - --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL - | - = note: doesn't satisfy `Vec: Iterator` | = note: the following trait bounds were not satisfied: `Vec: Iterator` diff --git a/tests/ui/mismatched_types/issue-36053-2.stderr b/tests/ui/mismatched_types/issue-36053-2.stderr index 292525daa3d6b..6d23319ca7e64 100644 --- a/tests/ui/mismatched_types/issue-36053-2.stderr +++ b/tests/ui/mismatched_types/issue-36053-2.stderr @@ -21,11 +21,7 @@ error[E0599]: the method `count` exists for struct `Filter>, {cl LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); | --------- ^^^^^ method cannot be called due to unsatisfied trait bounds | | - | doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool` - | doesn't satisfy `_: FnMut<(&&str,)>` - --> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL - | - = note: doesn't satisfy `_: Iterator` + | doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool` or `_: FnMut<(&&str,)>` | = note: the following trait bounds were not satisfied: `<{closure@$DIR/issue-36053-2.rs:7:39: 7:48} as FnOnce<(&&str,)>>::Output = bool` diff --git a/tests/ui/suggestions/derive-trait-for-method-call.stderr b/tests/ui/suggestions/derive-trait-for-method-call.stderr index e2db0da74f022..9d6d29ec74eec 100644 --- a/tests/ui/suggestions/derive-trait-for-method-call.stderr +++ b/tests/ui/suggestions/derive-trait-for-method-call.stderr @@ -2,10 +2,7 @@ error[E0599]: the method `test` exists for struct `Foo`, but it --> $DIR/derive-trait-for-method-call.rs:28:15 | LL | enum Enum { - | --------- - | | - | doesn't satisfy `Enum: Clone` - | doesn't satisfy `Enum: Default` + | --------- doesn't satisfy `Enum: Clone` or `Enum: Default` ... LL | enum CloneEnum { | -------------- doesn't satisfy `CloneEnum: Default` @@ -40,10 +37,7 @@ error[E0599]: the method `test` exists for struct `Foo`, bu --> $DIR/derive-trait-for-method-call.rs:34:15 | LL | struct Struct { - | ------------- - | | - | doesn't satisfy `Struct: Clone` - | doesn't satisfy `Struct: Default` + | ------------- doesn't satisfy `Struct: Clone` or `Struct: Default` ... LL | struct CloneStruct { | ------------------ doesn't satisfy `CloneStruct: Default` @@ -85,12 +79,6 @@ LL | struct Foo (X, Y); ... LL | let y = x.test(); | ^^^^ method cannot be called on `Foo, Instant>` due to unsatisfied trait bounds - --> $SRC_DIR/std/src/time.rs:LL:COL - | - = note: doesn't satisfy `Instant: Default` - --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL - | - = note: doesn't satisfy `Vec: Clone` | note: the following trait bounds were not satisfied: `Instant: Default` diff --git a/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr b/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr index 94710f4503f56..09a9b1d3b3482 100644 --- a/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -25,9 +25,6 @@ error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn Write>`, | LL | writeln!(fp, "hello world").unwrap(); | ---------^^---------------- method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds - --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL - | - = note: doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write` | note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method --> $DIR/mut-borrow-needed-by-trait.rs:21:14 diff --git a/tests/ui/suggestions/suggest-change-mut.stderr b/tests/ui/suggestions/suggest-change-mut.stderr index d194afeaf931d..216d1e810fd72 100644 --- a/tests/ui/suggestions/suggest-change-mut.stderr +++ b/tests/ui/suggestions/suggest-change-mut.stderr @@ -27,9 +27,6 @@ error[E0599]: the method `read_until` exists for struct `BufReader<&T>`, but its | LL | stream_reader.read_until(b'\n', &mut buffer).expect("Reading into buffer failed"); | ^^^^^^^^^^ method cannot be called on `BufReader<&T>` due to unsatisfied trait bounds - --> $SRC_DIR/std/src/io/buffered/bufreader.rs:LL:COL - | - = note: doesn't satisfy `BufReader<&T>: BufRead` | = note: the following trait bounds were not satisfied: `&T: std::io::Read` diff --git a/tests/ui/traits/track-obligations.stderr b/tests/ui/traits/track-obligations.stderr index 89477475970f4..822fc91e43fea 100644 --- a/tests/ui/traits/track-obligations.stderr +++ b/tests/ui/traits/track-obligations.stderr @@ -2,10 +2,7 @@ error[E0599]: the method `check` exists for struct `Client<()>`, but its trait b --> $DIR/track-obligations.rs:83:16 | LL | struct ALayer(C); - | ---------------- - | | - | doesn't satisfy `<_ as Layer<()>>::Service = as ParticularServiceLayer<()>>::Service` - | doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>` + | ---------------- doesn't satisfy `<_ as Layer<()>>::Service = as ParticularServiceLayer<()>>::Service` or `ALayer<()>: ParticularServiceLayer<()>` ... LL | struct Client(C); | ---------------- method `check` not found for this struct diff --git a/tests/ui/typeck/derive-sugg-arg-arity.stderr b/tests/ui/typeck/derive-sugg-arg-arity.stderr index 41b16a772ca95..46421ba942c57 100644 --- a/tests/ui/typeck/derive-sugg-arg-arity.stderr +++ b/tests/ui/typeck/derive-sugg-arg-arity.stderr @@ -5,8 +5,7 @@ LL | pub struct A; | ------------ | | | function or associated item `partial_cmp` not found for this struct - | doesn't satisfy `A: Iterator` - | doesn't satisfy `A: PartialOrd<_>` + | doesn't satisfy `A: Iterator` or `A: PartialOrd<_>` ... LL | _ => match A::partial_cmp() {}, | ^^^^^^^^^^^ function or associated item cannot be called on `A` due to unsatisfied trait bounds diff --git a/tests/ui/typeck/issue-31173.stderr b/tests/ui/typeck/issue-31173.stderr index d65c4306a5f28..0983147a5f0c5 100644 --- a/tests/ui/typeck/issue-31173.stderr +++ b/tests/ui/typeck/issue-31173.stderr @@ -35,12 +35,6 @@ LL | | .collect(); | | -^^^^^^^ method cannot be called due to unsatisfied trait bounds | |_________| | - --> $SRC_DIR/core/src/iter/adapters/take_while.rs:LL:COL - | - = note: doesn't satisfy `<_ as Iterator>::Item = &_` - --> $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL - | - = note: doesn't satisfy `_: Iterator` | = note: the following trait bounds were not satisfied: `, {closure@$DIR/issue-31173.rs:7:21: 7:25}> as Iterator>::Item = &_` From 7df4a09fc4e236f854273202e124747d47246ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 26 Jan 2024 20:44:43 +0000 Subject: [PATCH 3/4] Use single label for method not found due to unmet bound --- .../rustc_hir_typeck/src/method/suggest.rs | 35 ++++++++++++------- .../derives/derive-assoc-type-not-impl.stderr | 5 +-- .../deriving-with-repr-packed-2.stderr | 5 +-- ...gat-bound-during-assoc-ty-selection.stderr | 5 +-- ...method-unsatisfied-assoc-type-predicate.rs | 3 +- ...od-unsatisfied-assoc-type-predicate.stderr | 7 ++-- .../trait-bounds/issue-30786.stderr | 10 ++---- tests/ui/methods/method-call-err-msg.stderr | 5 +-- ...pecialization-trait-not-implemented.stderr | 5 +-- ...impl-derived-implicit-sized-bound-2.stderr | 5 +-- .../impl-derived-implicit-sized-bound.stderr | 5 +-- tests/ui/typeck/derive-sugg-arg-arity.stderr | 5 +-- tests/ui/union/union-derive-clone.stderr | 5 +-- 13 files changed, 37 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index d7a0565895d3e..0499a46dbb826 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -459,22 +459,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - let ty_span = match rcvr_ty.kind() { + let mut ty_span = match rcvr_ty.kind() { ty::Param(param_type) => { Some(param_type.span_from_generics(self.tcx, self.body_id.to_def_id())) } ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())), _ => None, }; - if let Some(span) = ty_span { - err.span_label( - span, - format!( - "{item_kind} `{item_name}` not found for this {}", - rcvr_ty.prefix_string(self.tcx) - ), - ); - } if let SelfSource::MethodCall(rcvr_expr) = source { self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| { @@ -1190,13 +1181,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !tcx.sess.source_map().is_span_accessible(span) { continue; } + let pre = if Some(span) == ty_span { + ty_span.take(); + format!( + "{item_kind} `{item_name}` not found for this {} because it ", + rcvr_ty.prefix_string(self.tcx) + ) + } else { + String::new() + }; let msg = match &bounds[..] { - [bound] => format!("doesn't satisfy {bound}"), - [bounds @ .., last] => format!("doesn't satisfy {} or {last}", bounds.join(", ")), + [bound] => format!("{pre}doesn't satisfy {bound}"), + [bounds @ .., last] => { + format!("{pre}doesn't satisfy {} or {last}", bounds.join(", ")) + } [] => unreachable!(), }; err.span_label(span, msg); } + if let Some(span) = ty_span { + err.span_label( + span, + format!( + "{item_kind} `{item_name}` not found for this {}", + rcvr_ty.prefix_string(self.tcx) + ), + ); + } if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params { } else { diff --git a/tests/ui/derives/derive-assoc-type-not-impl.stderr b/tests/ui/derives/derive-assoc-type-not-impl.stderr index 6cbcb455f87e9..61268ffc7f852 100644 --- a/tests/ui/derives/derive-assoc-type-not-impl.stderr +++ b/tests/ui/derives/derive-assoc-type-not-impl.stderr @@ -2,10 +2,7 @@ error[E0599]: the method `clone` exists for struct `Bar`, but its trai --> $DIR/derive-assoc-type-not-impl.rs:18:30 | LL | struct Bar { - | ------------------ - | | - | method `clone` not found for this struct - | doesn't satisfy `Bar: Clone` + | ------------------ method `clone` not found for this struct because it doesn't satisfy `Bar: Clone` ... LL | struct NotClone; | --------------- doesn't satisfy `NotClone: Clone` diff --git a/tests/ui/derives/deriving-with-repr-packed-2.stderr b/tests/ui/derives/deriving-with-repr-packed-2.stderr index 172dd80fe1d09..96f51a4e7a2b4 100644 --- a/tests/ui/derives/deriving-with-repr-packed-2.stderr +++ b/tests/ui/derives/deriving-with-repr-packed-2.stderr @@ -2,10 +2,7 @@ error[E0599]: the method `clone` exists for struct `Foo`, but its trait --> $DIR/deriving-with-repr-packed-2.rs:18:11 | LL | pub struct Foo(T, T, T); - | ----------------- - | | - | method `clone` not found for this struct - | doesn't satisfy `Foo: Clone` + | ----------------- method `clone` not found for this struct because it doesn't satisfy `Foo: Clone` LL | LL | struct NonCopy; | -------------- doesn't satisfy `NonCopy: Clone` or `NonCopy: Copy` diff --git a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr index 2ce10ce9c1cc0..7813370ae63f8 100644 --- a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr +++ b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr @@ -19,10 +19,7 @@ error[E0599]: the size for values of type `Node` cannot be known --> $DIR/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs:31:35 | LL | enum Node { - | ------------------------------ - | | - | variant or associated item `new` not found for this enum - | doesn't satisfy `Node: Sized` + | ------------------------------ variant or associated item `new` not found for this enum because it doesn't satisfy `Node: Sized` ... LL | let mut list = RcNode::::new(); | ^^^ doesn't have a size known at compile-time diff --git a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs index 1f9e4f24b161c..add4d58f86a0d 100644 --- a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs +++ b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs @@ -16,8 +16,7 @@ impl = i32>> M for T {} //~| NOTE struct S; -//~^ NOTE method `f` not found for this -//~| NOTE doesn't satisfy `::Y = i32` or `S: M` +//~^ NOTE method `f` not found for this struct because it doesn't satisfy `::Y = i32` or `S: M` impl X for S { type Y = bool; diff --git a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr index 489b2772ad8c3..1dd463f996ce6 100644 --- a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr +++ b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr @@ -1,11 +1,8 @@ error[E0599]: the method `f` exists for struct `S`, but its trait bounds were not satisfied - --> $DIR/method-unsatisfied-assoc-type-predicate.rs:27:7 + --> $DIR/method-unsatisfied-assoc-type-predicate.rs:26:7 | LL | struct S; - | -------- - | | - | method `f` not found for this struct - | doesn't satisfy `::Y = i32` or `S: M` + | -------- method `f` not found for this struct because it doesn't satisfy `::Y = i32` or `S: M` ... LL | a.f(); | ^ method cannot be called on `S` due to unsatisfied trait bounds diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr index 4f9ceb577c0be..73870703cfbac 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr @@ -2,10 +2,7 @@ error[E0599]: the method `filterx` exists for struct `Map $DIR/issue-30786.rs:120:22 | LL | pub struct Map { - | -------------------- - | | - | method `filterx` not found for this struct - | doesn't satisfy `_: StreamExt` + | -------------------- method `filterx` not found for this struct because it doesn't satisfy `_: StreamExt` ... LL | let filter = map.filterx(|x: &_| true); | ^^^^^^^ method cannot be called on `Map` due to unsatisfied trait bounds @@ -23,10 +20,7 @@ error[E0599]: the method `countx` exists for struct `Filter $DIR/issue-30786.rs:132:24 | LL | pub struct Filter { - | ----------------------- - | | - | method `countx` not found for this struct - | doesn't satisfy `_: StreamExt` + | ----------------------- method `countx` not found for this struct because it doesn't satisfy `_: StreamExt` ... LL | let count = filter.countx(); | ^^^^^^ method cannot be called due to unsatisfied trait bounds diff --git a/tests/ui/methods/method-call-err-msg.stderr b/tests/ui/methods/method-call-err-msg.stderr index bd51378cf1a50..f431085745405 100644 --- a/tests/ui/methods/method-call-err-msg.stderr +++ b/tests/ui/methods/method-call-err-msg.stderr @@ -49,10 +49,7 @@ error[E0599]: `Foo` is not an iterator --> $DIR/method-call-err-msg.rs:19:7 | LL | pub struct Foo; - | -------------- - | | - | method `take` not found for this struct - | doesn't satisfy `Foo: Iterator` + | -------------- method `take` not found for this struct because it doesn't satisfy `Foo: Iterator` ... LL | / y.zero() LL | | .take() diff --git a/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr b/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr index 75c91e4806f77..e9b0845ccf707 100644 --- a/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr +++ b/tests/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr @@ -12,10 +12,7 @@ error[E0599]: the method `foo_one` exists for struct `MyStruct`, but its trait b --> $DIR/specialization-trait-not-implemented.rs:22:29 | LL | struct MyStruct; - | --------------- - | | - | method `foo_one` not found for this struct - | doesn't satisfy `MyStruct: Foo` + | --------------- method `foo_one` not found for this struct because it doesn't satisfy `MyStruct: Foo` ... LL | println!("{}", MyStruct.foo_one()); | ^^^^^^^ method cannot be called on `MyStruct` due to unsatisfied trait bounds diff --git a/tests/ui/trait-bounds/impl-derived-implicit-sized-bound-2.stderr b/tests/ui/trait-bounds/impl-derived-implicit-sized-bound-2.stderr index 84c2ab68da958..397e80197b952 100644 --- a/tests/ui/trait-bounds/impl-derived-implicit-sized-bound-2.stderr +++ b/tests/ui/trait-bounds/impl-derived-implicit-sized-bound-2.stderr @@ -2,10 +2,7 @@ error[E0599]: the method `get` exists for struct `Victim<'_, Self>`, but its tra --> $DIR/impl-derived-implicit-sized-bound-2.rs:28:19 | LL | struct Victim<'a, T: Perpetrator + ?Sized> { - | ------------------------------------------ - | | - | method `get` not found for this struct - | doesn't satisfy `Victim<'_, Self>: VictimTrait` + | ------------------------------------------ method `get` not found for this struct because it doesn't satisfy `Victim<'_, Self>: VictimTrait` ... LL | self.getter().get(); | ^^^ method cannot be called on `Victim<'_, Self>` due to unsatisfied trait bounds diff --git a/tests/ui/trait-bounds/impl-derived-implicit-sized-bound.stderr b/tests/ui/trait-bounds/impl-derived-implicit-sized-bound.stderr index c597ad0b572ee..abcd915c699c4 100644 --- a/tests/ui/trait-bounds/impl-derived-implicit-sized-bound.stderr +++ b/tests/ui/trait-bounds/impl-derived-implicit-sized-bound.stderr @@ -2,10 +2,7 @@ error[E0599]: the method `get` exists for struct `Victim<'_, Self>`, but its tra --> $DIR/impl-derived-implicit-sized-bound.rs:31:19 | LL | struct Victim<'a, T: Perpetrator + ?Sized> - | ------------------------------------------ - | | - | method `get` not found for this struct - | doesn't satisfy `Victim<'_, Self>: VictimTrait` + | ------------------------------------------ method `get` not found for this struct because it doesn't satisfy `Victim<'_, Self>: VictimTrait` ... LL | self.getter().get(); | ^^^ method cannot be called on `Victim<'_, Self>` due to unsatisfied trait bounds diff --git a/tests/ui/typeck/derive-sugg-arg-arity.stderr b/tests/ui/typeck/derive-sugg-arg-arity.stderr index 46421ba942c57..382b324c4cc50 100644 --- a/tests/ui/typeck/derive-sugg-arg-arity.stderr +++ b/tests/ui/typeck/derive-sugg-arg-arity.stderr @@ -2,10 +2,7 @@ error[E0599]: the function or associated item `partial_cmp` exists for struct `A --> $DIR/derive-sugg-arg-arity.rs:5:23 | LL | pub struct A; - | ------------ - | | - | function or associated item `partial_cmp` not found for this struct - | doesn't satisfy `A: Iterator` or `A: PartialOrd<_>` + | ------------ function or associated item `partial_cmp` not found for this struct because it doesn't satisfy `A: Iterator` or `A: PartialOrd<_>` ... LL | _ => match A::partial_cmp() {}, | ^^^^^^^^^^^ function or associated item cannot be called on `A` due to unsatisfied trait bounds diff --git a/tests/ui/union/union-derive-clone.stderr b/tests/ui/union/union-derive-clone.stderr index 39f1e32e6eb71..a2b81f0dba1c3 100644 --- a/tests/ui/union/union-derive-clone.stderr +++ b/tests/ui/union/union-derive-clone.stderr @@ -17,10 +17,7 @@ error[E0599]: the method `clone` exists for union `U5`, but its tra --> $DIR/union-derive-clone.rs:35:15 | LL | union U5 { - | ----------- - | | - | method `clone` not found for this union - | doesn't satisfy `U5: Clone` + | ----------- method `clone` not found for this union because it doesn't satisfy `U5: Clone` ... LL | struct CloneNoCopy; | ------------------ doesn't satisfy `CloneNoCopy: Copy` From fc964fb439473c84a47444f89e5cf4c570b98f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 29 Jan 2024 23:33:02 +0000 Subject: [PATCH 4/4] review comments --- .../rustc_hir_analysis/src/astconv/errors.rs | 25 ++++++----------- .../rustc_hir_typeck/src/method/suggest.rs | 28 +++++++------------ 2 files changed, 19 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index b2d5d3885d938..fa7d9799dbd2e 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -6,6 +6,7 @@ use crate::errors::{ use crate::fluent_generated as fluent; use crate::traits::error_reporting::report_object_safety_error; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; +use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordMap; use rustc_errors::{pluralize, struct_span_code_err, Applicability, Diagnostic, ErrorGuaranteed}; use rustc_hir as hir; @@ -461,14 +462,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { return err.emit(); } - let mut bound_spans: FxHashMap> = Default::default(); + let mut bound_spans: SortedMap> = Default::default(); let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| { 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.entry(tcx.def_span(def.did())).or_default().push(msg) + bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg) } // Point at the trait object that couldn't satisfy the bound. ty::Dynamic(preds, _, _) => { @@ -476,8 +477,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { match pred.skip_binder() { ty::ExistentialPredicate::Trait(tr) => { bound_spans - .entry(tcx.def_span(tr.def_id)) - .or_default() + .get_mut_or_insert_default(tcx.def_span(tr.def_id)) .push(msg.clone()); } ty::ExistentialPredicate::Projection(_) @@ -488,8 +488,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Point at the closure that couldn't satisfy the bound. ty::Closure(def_id, _) => { bound_spans - .entry(tcx.def_span(*def_id)) - .or_default() + .get_mut_or_insert_default(tcx.def_span(*def_id)) .push(format!("`{quiet}`")); } _ => {} @@ -559,21 +558,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { format!("associated type cannot be referenced on `{self_ty}` due to unsatisfied trait bounds") ); - let mut bound_spans: Vec<(Span, Vec)> = 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 { + for (span, mut bounds) in bound_spans { if !tcx.sess.source_map().is_span_accessible(span) { continue; } + bounds.sort(); + bounds.dedup(); let msg = match &bounds[..] { [bound] => format!("doesn't satisfy {bound}"), + bounds if bounds.len() > 4 => format!("doesn't satisfy {} bounds", bounds.len()), [bounds @ .., last] => format!("doesn't satisfy {} or {last}", bounds.join(", ")), [] => unreachable!(), }; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 0499a46dbb826..677d224065195 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -9,7 +9,8 @@ use crate::Expectation; use crate::FnCtxt; use rustc_ast::ast::Mutability; use rustc_attr::parse_confusables; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordSet; use rustc_errors::StashKey; use rustc_errors::{ @@ -538,7 +539,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - let mut bound_spans: FxHashMap> = Default::default(); + let mut bound_spans: SortedMap> = Default::default(); let mut restrict_type_params = false; let mut unsatisfied_bounds = false; if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) { @@ -637,7 +638,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match &self_ty.kind() { // Point at the type that couldn't satisfy the bound. ty::Adt(def, _) => { - bound_spans.entry(tcx.def_span(def.did())).or_default().push(msg) + bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg) } // Point at the trait object that couldn't satisfy the bound. ty::Dynamic(preds, _, _) => { @@ -645,8 +646,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match pred.skip_binder() { ty::ExistentialPredicate::Trait(tr) => { bound_spans - .entry(tcx.def_span(tr.def_id)) - .or_default() + .get_mut_or_insert_default(tcx.def_span(tr.def_id)) .push(msg.clone()); } ty::ExistentialPredicate::Projection(_) @@ -657,8 +657,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Point at the closure that couldn't satisfy the bound. ty::Closure(def_id, _) => { bound_spans - .entry(tcx.def_span(*def_id)) - .or_default() + .get_mut_or_insert_default(tcx.def_span(*def_id)) .push(format!("`{quiet}`")); } _ => {} @@ -1167,20 +1166,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.suggest_unwrapping_inner_self(&mut err, source, rcvr_ty, item_name); - #[allow(rustc::potential_query_instability)] // We immediately sort the resulting Vec. - let mut bound_spans: Vec<(Span, Vec)> = 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 { + for (span, mut bounds) in bound_spans { if !tcx.sess.source_map().is_span_accessible(span) { continue; } + bounds.sort(); + bounds.dedup(); let pre = if Some(span) == ty_span { ty_span.take(); format!( @@ -1192,6 +1183,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let msg = match &bounds[..] { [bound] => format!("{pre}doesn't satisfy {bound}"), + bounds if bounds.len() > 4 => format!("doesn't satisfy {} bounds", bounds.len()), [bounds @ .., last] => { format!("{pre}doesn't satisfy {} or {last}", bounds.join(", ")) }