-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixed #85845: Added a note in E0369 if the missing trait is PartialEq #85929
Changes from all commits
518f643
01996be
a1d18be
96c4539
bcb49dc
afcef43
38830d2
b58393b
207f9b1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -276,71 +276,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |||||
lhs_expr.span, | ||||||
format!("cannot use `{}=` on type `{}`", op.node.as_str(), lhs_ty), | ||||||
); | ||||||
let missing_trait = match op.node { | ||||||
hir::BinOpKind::Add => Some("std::ops::AddAssign"), | ||||||
hir::BinOpKind::Sub => Some("std::ops::SubAssign"), | ||||||
hir::BinOpKind::Mul => Some("std::ops::MulAssign"), | ||||||
hir::BinOpKind::Div => Some("std::ops::DivAssign"), | ||||||
hir::BinOpKind::Rem => Some("std::ops::RemAssign"), | ||||||
hir::BinOpKind::BitAnd => Some("std::ops::BitAndAssign"), | ||||||
hir::BinOpKind::BitXor => Some("std::ops::BitXorAssign"), | ||||||
hir::BinOpKind::BitOr => Some("std::ops::BitOrAssign"), | ||||||
hir::BinOpKind::Shl => Some("std::ops::ShlAssign"), | ||||||
hir::BinOpKind::Shr => Some("std::ops::ShrAssign"), | ||||||
_ => None, | ||||||
}; | ||||||
(err, missing_trait, false, false) | ||||||
(err, Some(STDImplementationMissing::BinOpAssign(op.node)), false, false) | ||||||
} | ||||||
IsAssign::No => { | ||||||
let (message, missing_trait, use_output) = match op.node { | ||||||
hir::BinOpKind::Add => ( | ||||||
format!("cannot add `{}` to `{}`", rhs_ty, lhs_ty), | ||||||
Some("std::ops::Add"), | ||||||
Some(STDImplementationMissing::BinOp(op.node)), | ||||||
true, | ||||||
), | ||||||
hir::BinOpKind::Sub => ( | ||||||
format!("cannot subtract `{}` from `{}`", rhs_ty, lhs_ty), | ||||||
Some("std::ops::Sub"), | ||||||
Some(STDImplementationMissing::BinOp(op.node)), | ||||||
true, | ||||||
), | ||||||
hir::BinOpKind::Mul => ( | ||||||
format!("cannot multiply `{}` by `{}`", lhs_ty, rhs_ty), | ||||||
Some("std::ops::Mul"), | ||||||
Some(STDImplementationMissing::BinOp(op.node)), | ||||||
true, | ||||||
), | ||||||
hir::BinOpKind::Div => ( | ||||||
format!("cannot divide `{}` by `{}`", lhs_ty, rhs_ty), | ||||||
Some("std::ops::Div"), | ||||||
Some(STDImplementationMissing::BinOp(op.node)), | ||||||
true, | ||||||
), | ||||||
hir::BinOpKind::Rem => ( | ||||||
format!("cannot mod `{}` by `{}`", lhs_ty, rhs_ty), | ||||||
Some("std::ops::Rem"), | ||||||
Some(STDImplementationMissing::BinOp(op.node)), | ||||||
true, | ||||||
), | ||||||
hir::BinOpKind::BitAnd => ( | ||||||
format!("no implementation for `{} & {}`", lhs_ty, rhs_ty), | ||||||
Some("std::ops::BitAnd"), | ||||||
Some(STDImplementationMissing::BinOp(op.node)), | ||||||
true, | ||||||
), | ||||||
hir::BinOpKind::BitXor => ( | ||||||
format!("no implementation for `{} ^ {}`", lhs_ty, rhs_ty), | ||||||
Some("std::ops::BitXor"), | ||||||
Some(STDImplementationMissing::BinOp(op.node)), | ||||||
true, | ||||||
), | ||||||
hir::BinOpKind::BitOr => ( | ||||||
format!("no implementation for `{} | {}`", lhs_ty, rhs_ty), | ||||||
Some("std::ops::BitOr"), | ||||||
Some(STDImplementationMissing::BinOp(op.node)), | ||||||
true, | ||||||
), | ||||||
hir::BinOpKind::Shl => ( | ||||||
format!("no implementation for `{} << {}`", lhs_ty, rhs_ty), | ||||||
Some("std::ops::Shl"), | ||||||
Some(STDImplementationMissing::BinOp(op.node)), | ||||||
true, | ||||||
), | ||||||
hir::BinOpKind::Shr => ( | ||||||
format!("no implementation for `{} >> {}`", lhs_ty, rhs_ty), | ||||||
Some("std::ops::Shr"), | ||||||
Some(STDImplementationMissing::BinOp(op.node)), | ||||||
true, | ||||||
), | ||||||
hir::BinOpKind::Eq | hir::BinOpKind::Ne => ( | ||||||
|
@@ -349,7 +336,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |||||
op.node.as_str(), | ||||||
lhs_ty | ||||||
), | ||||||
Some("std::cmp::PartialEq"), | ||||||
Some(STDImplementationMissing::BinOp(op.node)), | ||||||
false, | ||||||
), | ||||||
hir::BinOpKind::Lt | ||||||
|
@@ -361,7 +348,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |||||
op.node.as_str(), | ||||||
lhs_ty | ||||||
), | ||||||
Some("std::cmp::PartialOrd"), | ||||||
Some(STDImplementationMissing::BinOp(op.node)), | ||||||
false, | ||||||
), | ||||||
_ => ( | ||||||
|
@@ -428,6 +415,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |||||
} | ||||||
} | ||||||
if let Some(missing_trait) = missing_trait { | ||||||
let missing_trait_str = missing_trait.as_std_trait().unwrap_or_default(); | ||||||
let mut visitor = TypeParamVisitor(vec![]); | ||||||
visitor.visit_ty(lhs_ty); | ||||||
|
||||||
|
@@ -459,7 +447,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |||||
&mut err, | ||||||
ty, | ||||||
rhs_ty, | ||||||
missing_trait, | ||||||
missing_trait_str, | ||||||
p, | ||||||
use_output, | ||||||
); | ||||||
|
@@ -468,14 +456,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |||||
// this note as it is redundant. | ||||||
err.note(&format!( | ||||||
"the trait `{}` is not implemented for `{}`", | ||||||
missing_trait, lhs_ty | ||||||
missing_trait_str, lhs_ty | ||||||
)); | ||||||
} | ||||||
} else { | ||||||
bug!("type param visitor stored a non type param: {:?}", ty.kind()); | ||||||
} | ||||||
} else if !suggested_deref && !involves_fn { | ||||||
suggest_impl_missing(&mut err, lhs_ty, &missing_trait); | ||||||
suggest_impl_missing(&mut err, lhs_ty, missing_trait); | ||||||
} | ||||||
} | ||||||
err.emit(); | ||||||
|
@@ -710,12 +698,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |||||
Str | Never | Char | Tuple(_) | Array(_, _) => {} | ||||||
Ref(_, ref lty, _) if *lty.kind() == Str => {} | ||||||
_ => { | ||||||
let missing_trait = match op { | ||||||
hir::UnOp::Neg => "std::ops::Neg", | ||||||
hir::UnOp::Not => "std::ops::Not", | ||||||
hir::UnOp::Deref => "std::ops::UnDerf", | ||||||
}; | ||||||
suggest_impl_missing(&mut err, operand_ty, &missing_trait); | ||||||
suggest_impl_missing( | ||||||
&mut err, | ||||||
operand_ty, | ||||||
STDImplementationMissing::Unop(op), | ||||||
); | ||||||
} | ||||||
} | ||||||
err.emit(); | ||||||
|
@@ -951,14 +938,56 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool | |||||
} | ||||||
} | ||||||
|
||||||
enum STDImplementationMissing { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
nit: capitalisation |
||||||
Unop(hir::UnOp), | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
nit: consistency |
||||||
BinOp(hir::BinOpKind), | ||||||
BinOpAssign(hir::BinOpKind), | ||||||
} | ||||||
|
||||||
impl STDImplementationMissing { | ||||||
fn as_std_trait(&self) -> Option<&'static str> { | ||||||
match self { | ||||||
Self::Unop(e) => Some(e.as_std_trait()), | ||||||
Self::BinOpAssign(e) => e.as_std_trait(true), | ||||||
Self::BinOp(e) => e.as_std_trait(false), | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
/// If applicable, note that an implementation of `trait` for `ty` may fix the error. | ||||||
fn suggest_impl_missing(err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>, missing_trait: &str) { | ||||||
fn suggest_impl_missing( | ||||||
err: &mut DiagnosticBuilder<'_>, | ||||||
ty: Ty<'_>, | ||||||
missing_trait: STDImplementationMissing, | ||||||
) { | ||||||
if let Adt(def, _) = ty.peel_refs().kind() { | ||||||
if def.did.is_local() { | ||||||
err.note(&format!( | ||||||
"an implementation of `{}` might be missing for `{}`", | ||||||
missing_trait, ty | ||||||
)); | ||||||
if let Some(missing_trait_name) = missing_trait.as_std_trait() { | ||||||
err.note(&format!( | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure that a span suggestion is better. A note at the end is clearer. Why do you want a span_suggestion? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because you want to suggest adding a |
||||||
"an implementation of `{}` might be missing for `{}`", | ||||||
missing_trait_name, ty | ||||||
)); | ||||||
} | ||||||
// This checks if the missing trait is PartialEq to suggest adding a derive | ||||||
if let STDImplementationMissing::BinOp(binary_op_trait) = missing_trait { | ||||||
if matches!(binary_op_trait, hir::BinOpKind::Eq | hir::BinOpKind::Ne) { | ||||||
err.note(&format!( | ||||||
"add `#[derive(PartialEq)]` or manually implement `PartialEq` for `{}`", | ||||||
ty | ||||||
)); | ||||||
} else if matches!( | ||||||
binary_op_trait, | ||||||
hir::BinOpKind::Lt | ||||||
| hir::BinOpKind::Le | ||||||
| hir::BinOpKind::Ge | ||||||
| hir::BinOpKind::Gt | ||||||
) { | ||||||
err.note(&format!( | ||||||
"add `#[derive(PartialOrd)]` or manually implement `PartialOrd` for `{}`", | ||||||
ty | ||||||
)); | ||||||
} | ||||||
} | ||||||
} | ||||||
} | ||||||
} | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: newline