Rollup merge of #119362 - estebank:restrict-derive-suggestion, r=fmease

Make `derive(Trait)` suggestion more accurate

Only suggest `derive(PartialEq)` when both LHS and RHS types are the same, otherwise the suggestion is not useful.
This commit is contained in:
Matthias Krüger 2024-01-04 08:33:24 +01:00 committed by GitHub
commit 6526b164a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 41 additions and 31 deletions

View File

@ -2252,6 +2252,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self, &self,
err: &mut Diagnostic, err: &mut Diagnostic,
errors: Vec<FulfillmentError<'tcx>>, errors: Vec<FulfillmentError<'tcx>>,
suggest_derive: bool,
) { ) {
let all_local_types_needing_impls = let all_local_types_needing_impls =
errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() { errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() {
@ -2322,10 +2323,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.iter() .iter()
.map(|e| (e.obligation.predicate, None, Some(e.obligation.cause.clone()))) .map(|e| (e.obligation.predicate, None, Some(e.obligation.cause.clone())))
.collect(); .collect();
if suggest_derive {
self.suggest_derive(err, &preds); self.suggest_derive(err, &preds);
} else {
// The predicate comes from a binop where the lhs and rhs have different types.
let _ = self.note_predicate_source_and_get_derives(err, &preds);
}
} }
pub fn suggest_derive( fn note_predicate_source_and_get_derives(
&self, &self,
err: &mut Diagnostic, err: &mut Diagnostic,
unsatisfied_predicates: &[( unsatisfied_predicates: &[(
@ -2333,7 +2339,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Option<ty::Predicate<'tcx>>, Option<ty::Predicate<'tcx>>,
Option<ObligationCause<'tcx>>, Option<ObligationCause<'tcx>>,
)], )],
) { ) -> Vec<(String, Span, Symbol)> {
let mut derives = Vec::<(String, Span, Symbol)>::new(); let mut derives = Vec::<(String, Span, Symbol)>::new();
let mut traits = Vec::new(); let mut traits = Vec::new();
for (pred, _, _) in unsatisfied_predicates { for (pred, _, _) in unsatisfied_predicates {
@ -2382,21 +2388,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
traits.sort(); traits.sort();
traits.dedup(); 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.to_string()));
}
let len = traits.len(); let len = traits.len();
if len > 0 { if len > 0 {
let span = let span =
@ -2419,6 +2410,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
); );
} }
derives
}
pub(crate) fn suggest_derive(
&self,
err: &mut Diagnostic,
unsatisfied_predicates: &[(
ty::Predicate<'tcx>,
Option<ty::Predicate<'tcx>>,
Option<ObligationCause<'tcx>>,
)],
) {
let mut derives = self.note_predicate_source_and_get_derives(err, unsatisfied_predicates);
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.to_string()));
}
for (self_name, self_span, traits) in &derives_grouped { for (self_name, self_span, traits) in &derives_grouped {
err.span_suggestion_verbose( err.span_suggestion_verbose(
self_span.shrink_to_lo(), self_span.shrink_to_lo(),

View File

@ -318,7 +318,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lhs_expr.span, lhs_expr.span,
format!("cannot use `{}=` on type `{}`", op.node.as_str(), lhs_ty), format!("cannot use `{}=` on type `{}`", op.node.as_str(), lhs_ty),
); );
self.note_unmet_impls_on_type(&mut err, errors); self.note_unmet_impls_on_type(&mut err, errors, false);
(err, None) (err, None)
} }
IsAssign::No => { IsAssign::No => {
@ -375,7 +375,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_label(lhs_expr.span, lhs_ty.to_string()); err.span_label(lhs_expr.span, lhs_ty.to_string());
err.span_label(rhs_expr.span, rhs_ty.to_string()); err.span_label(rhs_expr.span, rhs_ty.to_string());
} }
self.note_unmet_impls_on_type(&mut err, errors); let suggest_derive = self.can_eq(self.param_env, lhs_ty, rhs_ty);
self.note_unmet_impls_on_type(&mut err, errors, suggest_derive);
(err, output_def_id) (err, output_def_id)
} }
}; };
@ -852,7 +853,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Str | Never | Char | Tuple(_) | Array(_, _) => {} Str | Never | Char | Tuple(_) | Array(_, _) => {}
Ref(_, lty, _) if *lty.kind() == Str => {} Ref(_, lty, _) if *lty.kind() == Str => {}
_ => { _ => {
self.note_unmet_impls_on_type(&mut err, errors); self.note_unmet_impls_on_type(&mut err, errors, true);
} }
} }
} }

View File

@ -270,11 +270,6 @@ note: an implementation of `PartialEq<&&{integer}>` might be missing for `Foo`
| |
LL | struct Foo; LL | struct Foo;
| ^^^^^^^^^^ must implement `PartialEq<&&{integer}>` | ^^^^^^^^^^ must implement `PartialEq<&&{integer}>`
help: consider annotating `Foo` with `#[derive(PartialEq)]`
|
LL + #[derive(PartialEq)]
LL | struct Foo;
|
error[E0277]: can't compare `&String` with `str` error[E0277]: can't compare `&String` with `str`
--> $DIR/binary-op-suggest-deref.rs:69:20 --> $DIR/binary-op-suggest-deref.rs:69:20

View File

@ -11,11 +11,6 @@ note: an implementation of `PartialEq<fn(()) -> A {A::Value}>` might be missing
| |
LL | enum A { LL | enum A {
| ^^^^^^ must implement `PartialEq<fn(()) -> A {A::Value}>` | ^^^^^^ must implement `PartialEq<fn(()) -> A {A::Value}>`
help: consider annotating `A` with `#[derive(PartialEq)]`
|
LL + #[derive(PartialEq)]
LL | enum A {
|
help: use parentheses to construct this tuple variant help: use parentheses to construct this tuple variant
| |
LL | a == A::Value(/* () */); LL | a == A::Value(/* () */);