Skip to content

Commit

Permalink
Rollup merge of #91544 - rukai:91492, r=wesleywiser
Browse files Browse the repository at this point in the history
Fix duplicate derive clone suggestion

closes #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.
  • Loading branch information
matthiaskrgr authored Dec 22, 2021
2 parents 60625a6 + 0198ea4 commit d8bf974
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 16 deletions.
33 changes: 17 additions & 16 deletions compiler/rustc_typeck/src/check/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down
25 changes: 25 additions & 0 deletions src/test/ui/derives/issue-91492.rs
Original file line number Diff line number Diff line change
@@ -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() {}
54 changes: 54 additions & 0 deletions src/test/ui/derives/issue-91492.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit d8bf974

Please sign in to comment.