Rollup merge of #91544 - rukai:91492, r=wesleywiser

Fix duplicate derive clone suggestion

closes https://github.com/rust-lang/rust/issues/91492

The addition of:
```rust
derives.sort();
derives.dedup();
```
is what actually solves the problem.
The rest is just cleanup.

I want to improve the diagnostic message to provide the suggestion as a proper diff but ran into some problems, so I'll attempt that again in a follow up PR.
This commit is contained in:
Matthias Krüger 2021-12-23 00:28:51 +01:00 committed by GitHub
commit d8bf974df5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 96 additions and 16 deletions

View File

@ -1195,11 +1195,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn suggest_derive(
&self,
err: &mut DiagnosticBuilder<'_>,
unsatisfied_predicates: &Vec<(
unsatisfied_predicates: &[(
ty::Predicate<'tcx>,
Option<ty::Predicate<'tcx>>,
Option<ObligationCause<'tcx>>,
)>,
)],
) {
let mut derives = Vec::<(String, Span, String)>::new();
let mut traits = Vec::<Span>::new();
@ -1236,23 +1236,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
traits.push(self.tcx.def_span(trait_pred.def_id()));
}
}
derives.sort();
let derives_grouped = derives.into_iter().fold(
Vec::<(String, Span, String)>::new(),
|mut acc, (self_name, self_span, trait_name)| {
if let Some((acc_self_name, _, ref mut traits)) = acc.last_mut() {
if acc_self_name == &self_name {
traits.push_str(format!(", {}", trait_name).as_str());
return acc;
}
}
acc.push((self_name, self_span, trait_name));
acc
},
);
traits.sort();
traits.dedup();
derives.sort();
derives.dedup();
let mut derives_grouped = Vec::<(String, Span, String)>::new();
for (self_name, self_span, trait_name) in derives.into_iter() {
if let Some((last_self_name, _, ref mut last_trait_names)) = derives_grouped.last_mut()
{
if last_self_name == &self_name {
last_trait_names.push_str(format!(", {}", trait_name).as_str());
continue;
}
}
derives_grouped.push((self_name, self_span, trait_name));
}
let len = traits.len();
if len > 0 {
let span: MultiSpan = traits.into();

View File

@ -0,0 +1,25 @@
// Reproduce the issue with vec
pub struct NoDerives;
fn fun1(foo: &mut Vec<NoDerives>, bar: &[NoDerives]) {
foo.extend_from_slice(bar); //~ ERROR
}
// Reproduce the issue with vec
// and demonstrate that other derives are ignored in the suggested output
#[derive(Default, PartialEq)]
pub struct SomeDerives;
fn fun2(foo: &mut Vec<SomeDerives>, bar: &[SomeDerives]) {
foo.extend_from_slice(bar); //~ ERROR
}
// Try and fail to reproduce the issue without vec.
// No idea why it doesnt reproduce the issue but its still a useful test case.
struct Object<T, A>(T, A);
impl<T: Clone, A: Default> Object<T, A> {
fn use_clone(&self) {}
}
fn fun3(foo: Object<NoDerives, SomeDerives>) {
foo.use_clone(); //~ ERROR
}
fn main() {}

View File

@ -0,0 +1,54 @@
error[E0599]: the method `extend_from_slice` exists for mutable reference `&mut Vec<NoDerives>`, but its trait bounds were not satisfied
--> $DIR/issue-91492.rs:4:9
|
LL | pub struct NoDerives;
| --------------------- doesn't satisfy `NoDerives: Clone`
LL | fn fun1(foo: &mut Vec<NoDerives>, bar: &[NoDerives]) {
LL | foo.extend_from_slice(bar);
| ^^^^^^^^^^^^^^^^^
|
= note: the following trait bounds were not satisfied:
`NoDerives: Clone`
help: consider annotating `NoDerives` with `#[derive(Clone)]`
|
LL | #[derive(Clone)]
|
error[E0599]: the method `extend_from_slice` exists for mutable reference `&mut Vec<SomeDerives>`, but its trait bounds were not satisfied
--> $DIR/issue-91492.rs:12:9
|
LL | pub struct SomeDerives;
| ----------------------- doesn't satisfy `SomeDerives: Clone`
LL | fn fun2(foo: &mut Vec<SomeDerives>, bar: &[SomeDerives]) {
LL | foo.extend_from_slice(bar);
| ^^^^^^^^^^^^^^^^^
|
= note: the following trait bounds were not satisfied:
`SomeDerives: Clone`
help: consider annotating `SomeDerives` with `#[derive(Clone)]`
|
LL | #[derive(Clone)]
|
error[E0599]: the method `use_clone` exists for struct `Object<NoDerives, SomeDerives>`, but its trait bounds were not satisfied
--> $DIR/issue-91492.rs:22:9
|
LL | pub struct NoDerives;
| --------------------- doesn't satisfy `NoDerives: Clone`
...
LL | struct Object<T, A>(T, A);
| -------------------------- method `use_clone` not found for this
...
LL | foo.use_clone();
| ^^^^^^^^^ method cannot be called on `Object<NoDerives, SomeDerives>` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`NoDerives: Clone`
help: consider annotating `NoDerives` with `#[derive(Clone)]`
|
LL | #[derive(Clone)]
|
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0599`.