Skip to content

Commit a4419a7

Browse files
committed
Use only one label for multiple unsatisfied bounds on type (typeck)
1 parent eae6bd9 commit a4419a7

17 files changed

+60
-118
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::Expectation;
99
use crate::FnCtxt;
1010
use rustc_ast::ast::Mutability;
1111
use rustc_attr::parse_confusables;
12-
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
12+
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
1313
use rustc_data_structures::unord::UnordSet;
1414
use rustc_errors::StashKey;
1515
use rustc_errors::{
@@ -547,7 +547,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
547547
);
548548
}
549549

550-
let mut bound_spans = vec![];
550+
let mut bound_spans: FxHashMap<Span, Vec<String>> = Default::default();
551551
let mut restrict_type_params = false;
552552
let mut unsatisfied_bounds = false;
553553
if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
@@ -653,28 +653,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
653653
false
654654
};
655655
let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
656-
let msg = format!(
657-
"doesn't satisfy `{}`",
658-
if obligation.len() > 50 { quiet } else { obligation }
659-
);
656+
let msg = format!("`{}`", if obligation.len() > 50 { quiet } else { obligation });
660657
match &self_ty.kind() {
661658
// Point at the type that couldn't satisfy the bound.
662-
ty::Adt(def, _) => bound_spans.push((self.tcx.def_span(def.did()), msg)),
659+
ty::Adt(def, _) => {
660+
bound_spans.entry(tcx.def_span(def.did())).or_default().push(msg)
661+
}
663662
// Point at the trait object that couldn't satisfy the bound.
664663
ty::Dynamic(preds, _, _) => {
665664
for pred in preds.iter() {
666665
match pred.skip_binder() {
667666
ty::ExistentialPredicate::Trait(tr) => {
668-
bound_spans.push((self.tcx.def_span(tr.def_id), msg.clone()))
667+
bound_spans
668+
.entry(tcx.def_span(tr.def_id))
669+
.or_default()
670+
.push(msg.clone());
669671
}
670672
ty::ExistentialPredicate::Projection(_)
671673
| ty::ExistentialPredicate::AutoTrait(_) => {}
672674
}
673675
}
674676
}
675677
// Point at the closure that couldn't satisfy the bound.
676-
ty::Closure(def_id, _) => bound_spans
677-
.push((tcx.def_span(*def_id), format!("doesn't satisfy `{quiet}`"))),
678+
ty::Closure(def_id, _) => {
679+
bound_spans
680+
.entry(tcx.def_span(*def_id))
681+
.or_default()
682+
.push(format!("`{quiet}`"));
683+
}
678684
_ => {}
679685
}
680686
};
@@ -1181,9 +1187,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11811187

11821188
self.suggest_unwrapping_inner_self(&mut err, source, rcvr_ty, item_name);
11831189

1184-
bound_spans.sort();
1185-
bound_spans.dedup();
1186-
for (span, msg) in bound_spans.into_iter() {
1190+
#[allow(rustc::potential_query_instability)] // We immediately sort the resulting Vec.
1191+
let mut bound_spans: Vec<(Span, Vec<String>)> = bound_spans
1192+
.into_iter()
1193+
.map(|(span, mut bounds)| {
1194+
bounds.sort();
1195+
bounds.dedup();
1196+
(span, bounds)
1197+
})
1198+
.collect();
1199+
bound_spans.sort_by_key(|(span, _)| *span);
1200+
for (span, bounds) in bound_spans {
1201+
if !tcx.sess.source_map().is_span_accessible(span) {
1202+
continue;
1203+
}
1204+
let msg = match &bounds[..] {
1205+
[bound] => format!("doesn't satisfy {bound}"),
1206+
[bounds @ .., last] => format!("doesn't satisfy {} or {last}", bounds.join(", ")),
1207+
[] => unreachable!(),
1208+
};
11871209
err.span_label(span, msg);
11881210
}
11891211

tests/ui/box/unit/unique-object-noncopyable.stderr

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,11 @@
11
error[E0599]: the method `clone` exists for struct `Box<dyn Foo>`, but its trait bounds were not satisfied
22
--> $DIR/unique-object-noncopyable.rs:24:16
33
|
4-
LL | trait Foo {
5-
| ---------
6-
| |
7-
| doesn't satisfy `dyn Foo: Clone`
8-
| doesn't satisfy `dyn Foo: Sized`
4+
LL | trait Foo {
5+
| --------- doesn't satisfy `dyn Foo: Clone` or `dyn Foo: Sized`
96
...
10-
LL | let _z = y.clone();
11-
| ^^^^^ method cannot be called on `Box<dyn Foo>` due to unsatisfied trait bounds
12-
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
13-
::: $SRC_DIR/alloc/src/boxed.rs:LL:COL
14-
|
15-
= note: doesn't satisfy `Box<dyn Foo>: Clone`
7+
LL | let _z = y.clone();
8+
| ^^^^^ method cannot be called on `Box<dyn Foo>` due to unsatisfied trait bounds
169
|
1710
= note: the following trait bounds were not satisfied:
1811
`dyn Foo: Sized`

tests/ui/box/unit/unique-pinned-nocopy.stderr

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
error[E0599]: the method `clone` exists for struct `Box<R>`, but its trait bounds were not satisfied
22
--> $DIR/unique-pinned-nocopy.rs:12:16
33
|
4-
LL | struct R {
5-
| -------- doesn't satisfy `R: Clone`
4+
LL | struct R {
5+
| -------- doesn't satisfy `R: Clone`
66
...
7-
LL | let _j = i.clone();
8-
| ^^^^^ method cannot be called on `Box<R>` due to unsatisfied trait bounds
9-
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
10-
::: $SRC_DIR/alloc/src/boxed.rs:LL:COL
11-
|
12-
= note: doesn't satisfy `Box<R>: Clone`
7+
LL | let _j = i.clone();
8+
| ^^^^^ method cannot be called on `Box<R>` due to unsatisfied trait bounds
139
|
1410
= note: the following trait bounds were not satisfied:
1511
`R: Clone`

tests/ui/derives/deriving-with-repr-packed-2.stderr

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@ LL | pub struct Foo<T>(T, T, T);
88
| doesn't satisfy `Foo<NonCopy>: Clone`
99
LL |
1010
LL | struct NonCopy;
11-
| --------------
12-
| |
13-
| doesn't satisfy `NonCopy: Clone`
14-
| doesn't satisfy `NonCopy: Copy`
11+
| -------------- doesn't satisfy `NonCopy: Clone` or `NonCopy: Copy`
1512
...
1613
LL | _ = x.clone();
1714
| ^^^^^ method cannot be called on `Foo<NonCopy>` due to unsatisfied trait bounds

tests/ui/derives/issue-91550.stderr

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,7 @@ error[E0599]: the method `insert` exists for struct `HashSet<Value>`, but its tr
22
--> $DIR/issue-91550.rs:8:8
33
|
44
LL | struct Value(u32);
5-
| ------------
6-
| |
7-
| doesn't satisfy `Value: Eq`
8-
| doesn't satisfy `Value: Hash`
9-
| doesn't satisfy `Value: PartialEq`
5+
| ------------ doesn't satisfy `Value: Eq`, `Value: Hash` or `Value: PartialEq`
106
...
117
LL | hs.insert(Value(0));
128
| ^^^^^^
@@ -26,10 +22,7 @@ error[E0599]: the method `use_eq` exists for struct `Object<NoDerives>`, but its
2622
--> $DIR/issue-91550.rs:26:9
2723
|
2824
LL | pub struct NoDerives;
29-
| --------------------
30-
| |
31-
| doesn't satisfy `NoDerives: Eq`
32-
| doesn't satisfy `NoDerives: PartialEq`
25+
| -------------------- doesn't satisfy `NoDerives: Eq` or `NoDerives: PartialEq`
3326
LL |
3427
LL | struct Object<T>(T);
3528
| ---------------- method `use_eq` not found for this struct
@@ -57,12 +50,7 @@ error[E0599]: the method `use_ord` exists for struct `Object<NoDerives>`, but it
5750
--> $DIR/issue-91550.rs:27:9
5851
|
5952
LL | pub struct NoDerives;
60-
| --------------------
61-
| |
62-
| doesn't satisfy `NoDerives: Eq`
63-
| doesn't satisfy `NoDerives: Ord`
64-
| doesn't satisfy `NoDerives: PartialEq`
65-
| doesn't satisfy `NoDerives: PartialOrd`
53+
| -------------------- doesn't satisfy `NoDerives: Eq`, `NoDerives: Ord`, `NoDerives: PartialEq` or `NoDerives: PartialOrd`
6654
LL |
6755
LL | struct Object<T>(T);
6856
| ---------------- 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<NoD
9482
--> $DIR/issue-91550.rs:28:9
9583
|
9684
LL | pub struct NoDerives;
97-
| --------------------
98-
| |
99-
| doesn't satisfy `NoDerives: Eq`
100-
| doesn't satisfy `NoDerives: Ord`
101-
| doesn't satisfy `NoDerives: PartialEq`
102-
| doesn't satisfy `NoDerives: PartialOrd`
85+
| -------------------- doesn't satisfy `NoDerives: Eq`, `NoDerives: Ord`, `NoDerives: PartialEq` or `NoDerives: PartialOrd`
10386
LL |
10487
LL | struct Object<T>(T);
10588
| ---------------- method `use_ord_and_partial_ord` not found for this struct

tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ LL | enum Node<T, P: PointerFamily> {
2626
...
2727
LL | let mut list = RcNode::<i32>::new();
2828
| ^^^ doesn't have a size known at compile-time
29-
--> $SRC_DIR/core/src/ops/deref.rs:LL:COL
30-
|
31-
= note: doesn't satisfy `_: Sized`
3229
|
3330
note: trait bound `Node<i32, RcFamily>: Sized` was not satisfied
3431
--> $DIR/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs:4:18

tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ impl<T: X<Y<i32> = i32>> M for T {}
1717

1818
struct S;
1919
//~^ NOTE method `f` not found for this
20-
//~| NOTE doesn't satisfy `<S as X>::Y<i32> = i32`
21-
//~| NOTE doesn't satisfy `S: M`
20+
//~| NOTE doesn't satisfy `<S as X>::Y<i32> = i32` or `S: M`
2221

2322
impl X for S {
2423
type Y<T> = bool;

tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
error[E0599]: the method `f` exists for struct `S`, but its trait bounds were not satisfied
2-
--> $DIR/method-unsatisfied-assoc-type-predicate.rs:28:7
2+
--> $DIR/method-unsatisfied-assoc-type-predicate.rs:27:7
33
|
44
LL | struct S;
55
| --------
66
| |
77
| method `f` not found for this struct
8-
| doesn't satisfy `<S as X>::Y<i32> = i32`
9-
| doesn't satisfy `S: M`
8+
| doesn't satisfy `<S as X>::Y<i32> = i32` or `S: M`
109
...
1110
LL | a.f();
1211
| ^ method cannot be called on `S` due to unsatisfied trait bounds

tests/ui/iterators/vec-on-unimplemented.stderr

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@ error[E0599]: `Vec<bool>` is not an iterator
33
|
44
LL | vec![true, false].map(|v| !v).collect::<Vec<_>>();
55
| ^^^ `Vec<bool>` is not an iterator; try calling `.into_iter()` or `.iter()`
6-
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
7-
|
8-
= note: doesn't satisfy `Vec<bool>: Iterator`
96
|
107
= note: the following trait bounds were not satisfied:
118
`Vec<bool>: Iterator`

tests/ui/mismatched_types/issue-36053-2.stderr

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,7 @@ error[E0599]: the method `count` exists for struct `Filter<Fuse<Once<&str>>, {cl
2121
LL | once::<&str>("str").fuse().filter(|a: &str| true).count();
2222
| --------- ^^^^^ method cannot be called due to unsatisfied trait bounds
2323
| |
24-
| doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool`
25-
| doesn't satisfy `_: FnMut<(&&str,)>`
26-
--> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL
27-
|
28-
= note: doesn't satisfy `_: Iterator`
24+
| doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool` or `_: FnMut<(&&str,)>`
2925
|
3026
= note: the following trait bounds were not satisfied:
3127
`<{closure@$DIR/issue-36053-2.rs:7:39: 7:48} as FnOnce<(&&str,)>>::Output = bool`

tests/ui/suggestions/derive-trait-for-method-call.stderr

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ error[E0599]: the method `test` exists for struct `Foo<Enum, CloneEnum>`, but it
22
--> $DIR/derive-trait-for-method-call.rs:28:15
33
|
44
LL | enum Enum {
5-
| ---------
6-
| |
7-
| doesn't satisfy `Enum: Clone`
8-
| doesn't satisfy `Enum: Default`
5+
| --------- doesn't satisfy `Enum: Clone` or `Enum: Default`
96
...
107
LL | enum CloneEnum {
118
| -------------- doesn't satisfy `CloneEnum: Default`
@@ -40,10 +37,7 @@ error[E0599]: the method `test` exists for struct `Foo<Struct, CloneStruct>`, bu
4037
--> $DIR/derive-trait-for-method-call.rs:34:15
4138
|
4239
LL | struct Struct {
43-
| -------------
44-
| |
45-
| doesn't satisfy `Struct: Clone`
46-
| doesn't satisfy `Struct: Default`
40+
| ------------- doesn't satisfy `Struct: Clone` or `Struct: Default`
4741
...
4842
LL | struct CloneStruct {
4943
| ------------------ doesn't satisfy `CloneStruct: Default`
@@ -85,12 +79,6 @@ LL | struct Foo<X, Y> (X, Y);
8579
...
8680
LL | let y = x.test();
8781
| ^^^^ method cannot be called on `Foo<Vec<Enum>, Instant>` due to unsatisfied trait bounds
88-
--> $SRC_DIR/std/src/time.rs:LL:COL
89-
|
90-
= note: doesn't satisfy `Instant: Default`
91-
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
92-
|
93-
= note: doesn't satisfy `Vec<Enum>: Clone`
9482
|
9583
note: the following trait bounds were not satisfied:
9684
`Instant: Default`

tests/ui/suggestions/mut-borrow-needed-by-trait.stderr

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn Write>`,
2525
|
2626
LL | writeln!(fp, "hello world").unwrap();
2727
| ---------^^---------------- method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds
28-
--> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
29-
|
30-
= note: doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write`
3128
|
3229
note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method
3330
--> $DIR/mut-borrow-needed-by-trait.rs:21:14

tests/ui/suggestions/suggest-change-mut.stderr

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@ error[E0599]: the method `read_until` exists for struct `BufReader<&T>`, but its
2727
|
2828
LL | stream_reader.read_until(b'\n', &mut buffer).expect("Reading into buffer failed");
2929
| ^^^^^^^^^^ method cannot be called on `BufReader<&T>` due to unsatisfied trait bounds
30-
--> $SRC_DIR/std/src/io/buffered/bufreader.rs:LL:COL
31-
|
32-
= note: doesn't satisfy `BufReader<&T>: BufRead`
3330
|
3431
= note: the following trait bounds were not satisfied:
3532
`&T: std::io::Read`

tests/ui/traits/method-on-unbounded-type-param.stderr

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,11 @@ LL | fn h<T>(a: &T, b: T) -> std::cmp::Ordering where T: Iterator, T: Ord {
5353
error[E0599]: the method `cmp` exists for struct `Box<dyn T>`, but its trait bounds were not satisfied
5454
--> $DIR/method-on-unbounded-type-param.rs:14:7
5555
|
56-
LL | trait T {}
57-
| -------
58-
| |
59-
| doesn't satisfy `dyn T: Iterator`
60-
| doesn't satisfy `dyn T: Ord`
56+
LL | trait T {}
57+
| ------- doesn't satisfy `dyn T: Iterator` or `dyn T: Ord`
6158
...
62-
LL | x.cmp(&x);
63-
| ^^^ method cannot be called on `Box<dyn T>` due to unsatisfied trait bounds
64-
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
65-
::: $SRC_DIR/alloc/src/boxed.rs:LL:COL
66-
|
67-
= note: doesn't satisfy `Box<dyn T>: Iterator`
68-
|
69-
= note: doesn't satisfy `Box<dyn T>: Ord`
59+
LL | x.cmp(&x);
60+
| ^^^ method cannot be called on `Box<dyn T>` due to unsatisfied trait bounds
7061
|
7162
= note: the following trait bounds were not satisfied:
7263
`dyn T: Iterator`

tests/ui/traits/track-obligations.stderr

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ error[E0599]: the method `check` exists for struct `Client<()>`, but its trait b
22
--> $DIR/track-obligations.rs:83:16
33
|
44
LL | struct ALayer<C>(C);
5-
| ----------------
6-
| |
7-
| doesn't satisfy `<_ as Layer<()>>::Service = <ALayer<()> as ParticularServiceLayer<()>>::Service`
8-
| doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>`
5+
| ---------------- doesn't satisfy `<_ as Layer<()>>::Service = <ALayer<()> as ParticularServiceLayer<()>>::Service` or `ALayer<()>: ParticularServiceLayer<()>`
96
...
107
LL | struct Client<C>(C);
118
| ---------------- method `check` not found for this struct

tests/ui/typeck/derive-sugg-arg-arity.stderr

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ LL | pub struct A;
55
| ------------
66
| |
77
| function or associated item `partial_cmp` not found for this struct
8-
| doesn't satisfy `A: Iterator`
9-
| doesn't satisfy `A: PartialOrd<_>`
8+
| doesn't satisfy `A: Iterator` or `A: PartialOrd<_>`
109
...
1110
LL | _ => match A::partial_cmp() {},
1211
| ^^^^^^^^^^^ function or associated item cannot be called on `A` due to unsatisfied trait bounds

tests/ui/typeck/issue-31173.stderr

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,6 @@ LL | | .collect();
3535
| | -^^^^^^^ method cannot be called due to unsatisfied trait bounds
3636
| |_________|
3737
|
38-
--> $SRC_DIR/core/src/iter/adapters/take_while.rs:LL:COL
39-
|
40-
= note: doesn't satisfy `<_ as Iterator>::Item = &_`
41-
--> $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL
42-
|
43-
= note: doesn't satisfy `_: Iterator`
4438
|
4539
= note: the following trait bounds were not satisfied:
4640
`<TakeWhile<&mut std::vec::IntoIter<u8>, {closure@$DIR/issue-31173.rs:7:21: 7:25}> as Iterator>::Item = &_`

0 commit comments

Comments
 (0)