diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 81e2b3bc1621f..fc9e14b0000c0 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -9,8 +9,10 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, Node, QPath}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_middle::traits::util::supertraits; use rustc_middle::ty::fast_reject::{simplify_type, SimplifyParams}; use rustc_middle::ty::print::with_crate_prefix; +use rustc_middle::ty::ToPolyTraitRef; use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_span::lev_distance; use rustc_span::symbol::{kw, sym, Ident}; @@ -1196,9 +1198,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(adt) if adt.did.is_local() => adt, _ => continue, }; - let can_derive = match self.tcx.get_diagnostic_name(trait_pred.def_id()) { - Some(sym::Default) => !adt.is_enum(), - Some( + if let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) { + let can_derive = match diagnostic_name { + sym::Default => !adt.is_enum(), sym::Eq | sym::PartialEq | sym::Ord @@ -1206,16 +1208,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | sym::Clone | sym::Copy | sym::Hash - | sym::Debug, - ) => true, - _ => false, - }; - if can_derive { - derives.push(( - format!("{}", trait_pred.self_ty()), - self.tcx.def_span(adt.did), - format!("{}", trait_pred.trait_ref.print_only_trait_name()), - )); + | sym::Debug => true, + _ => false, + }; + if can_derive { + let self_name = trait_pred.self_ty().to_string(); + let self_span = self.tcx.def_span(adt.did); + if let Some(poly_trait_ref) = pred.to_opt_poly_trait_pred() { + for super_trait in supertraits(self.tcx, poly_trait_ref.to_poly_trait_ref()) + { + if let Some(parent_diagnostic_name) = + self.tcx.get_diagnostic_name(super_trait.def_id()) + { + derives.push(( + self_name.clone(), + self_span.clone(), + parent_diagnostic_name.to_string(), + )); + } + } + } + derives.push((self_name, self_span, diagnostic_name.to_string())); + } else { + traits.push(self.tcx.def_span(trait_pred.def_id())); + } } else { traits.push(self.tcx.def_span(trait_pred.def_id())); } diff --git a/src/test/ui/binop/issue-28837.stderr b/src/test/ui/binop/issue-28837.stderr index 10f243bab1586..1875ea06a06d5 100644 --- a/src/test/ui/binop/issue-28837.stderr +++ b/src/test/ui/binop/issue-28837.stderr @@ -272,9 +272,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A` | LL | struct A; | ^^^^^^^^^ must implement `PartialOrd<_>` -help: consider annotating `A` with `#[derive(PartialOrd)]` +help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | -LL | #[derive(PartialOrd)] +LL | #[derive(PartialEq, PartialOrd)] | error[E0369]: binary operation `<=` cannot be applied to type `A` @@ -290,9 +290,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A` | LL | struct A; | ^^^^^^^^^ must implement `PartialOrd<_>` -help: consider annotating `A` with `#[derive(PartialOrd)]` +help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | -LL | #[derive(PartialOrd)] +LL | #[derive(PartialEq, PartialOrd)] | error[E0369]: binary operation `>` cannot be applied to type `A` @@ -308,9 +308,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A` | LL | struct A; | ^^^^^^^^^ must implement `PartialOrd<_>` -help: consider annotating `A` with `#[derive(PartialOrd)]` +help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | -LL | #[derive(PartialOrd)] +LL | #[derive(PartialEq, PartialOrd)] | error[E0369]: binary operation `>=` cannot be applied to type `A` @@ -326,9 +326,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A` | LL | struct A; | ^^^^^^^^^ must implement `PartialOrd<_>` -help: consider annotating `A` with `#[derive(PartialOrd)]` +help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | -LL | #[derive(PartialOrd)] +LL | #[derive(PartialEq, PartialOrd)] | error: aborting due to 15 previous errors diff --git a/src/test/ui/derives/issue-91550.rs b/src/test/ui/derives/issue-91550.rs new file mode 100644 index 0000000000000..56fd5ffa89eea --- /dev/null +++ b/src/test/ui/derives/issue-91550.rs @@ -0,0 +1,29 @@ +use std::collections::HashSet; + +/// natural case from the issue +struct Value(u32); + +fn main() { + let hs = HashSet::::new(); + hs.insert(Value(0)); //~ ERROR +} + +/// synthetic cases +pub struct NoDerives; + +struct Object(T); +impl Object { + fn use_eq(&self) {} +} +impl Object { + fn use_ord(&self) {} +} +impl Object { + fn use_ord_and_partial_ord(&self) {} +} + +fn function(foo: Object) { + foo.use_eq(); //~ ERROR + foo.use_ord(); //~ ERROR + foo.use_ord_and_partial_ord(); //~ ERROR +} diff --git a/src/test/ui/derives/issue-91550.stderr b/src/test/ui/derives/issue-91550.stderr new file mode 100644 index 0000000000000..bf4b7c7da0d50 --- /dev/null +++ b/src/test/ui/derives/issue-91550.stderr @@ -0,0 +1,84 @@ +error[E0599]: the method `insert` exists for struct `HashSet`, but its trait bounds were not satisfied + --> $DIR/issue-91550.rs:8:8 + | +LL | struct Value(u32); + | ------------------ + | | + | doesn't satisfy `Value: Eq` + | doesn't satisfy `Value: Hash` +... +LL | hs.insert(Value(0)); + | ^^^^^^ method cannot be called on `HashSet` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `Value: Eq` + `Value: Hash` +help: consider annotating `Value` with `#[derive(Eq, Hash, PartialEq)]` + | +LL | #[derive(Eq, Hash, PartialEq)] + | + +error[E0599]: the method `use_eq` exists for struct `Object`, but its trait bounds were not satisfied + --> $DIR/issue-91550.rs:26:9 + | +LL | pub struct NoDerives; + | --------------------- doesn't satisfy `NoDerives: Eq` +LL | +LL | struct Object(T); + | -------------------- method `use_eq` not found for this +... +LL | foo.use_eq(); + | ^^^^^^ method cannot be called on `Object` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `NoDerives: Eq` +help: consider annotating `NoDerives` with `#[derive(Eq, PartialEq)]` + | +LL | #[derive(Eq, PartialEq)] + | + +error[E0599]: the method `use_ord` exists for struct `Object`, but its trait bounds were not satisfied + --> $DIR/issue-91550.rs:27:9 + | +LL | pub struct NoDerives; + | --------------------- doesn't satisfy `NoDerives: Ord` +LL | +LL | struct Object(T); + | -------------------- method `use_ord` not found for this +... +LL | foo.use_ord(); + | ^^^^^^^ method cannot be called on `Object` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `NoDerives: Ord` +help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]` + | +LL | #[derive(Eq, Ord, PartialEq, PartialOrd)] + | + +error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object`, but its trait bounds were not satisfied + --> $DIR/issue-91550.rs:28:9 + | +LL | pub struct NoDerives; + | --------------------- + | | + | doesn't satisfy `NoDerives: Ord` + | doesn't satisfy `NoDerives: PartialOrd` +LL | +LL | struct Object(T); + | -------------------- method `use_ord_and_partial_ord` not found for this +... +LL | foo.use_ord_and_partial_ord(); + | ^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `Object` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `NoDerives: Ord` + `NoDerives: PartialOrd` +help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]` + | +LL | #[derive(Eq, Ord, PartialEq, PartialOrd)] + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/union/union-derive-clone.mirunsafeck.stderr b/src/test/ui/union/union-derive-clone.mirunsafeck.stderr index 146a627bcdef7..e8e65fe5d1d1d 100644 --- a/src/test/ui/union/union-derive-clone.mirunsafeck.stderr +++ b/src/test/ui/union/union-derive-clone.mirunsafeck.stderr @@ -16,9 +16,9 @@ LL | let w = u.clone(); = note: the following trait bounds were not satisfied: `CloneNoCopy: Copy` which is required by `U5: Clone` -help: consider annotating `CloneNoCopy` with `#[derive(Copy)]` +help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]` | -LL | #[derive(Copy)] +LL | #[derive(Clone, Copy)] | error[E0277]: the trait bound `U1: Copy` is not satisfied diff --git a/src/test/ui/union/union-derive-clone.thirunsafeck.stderr b/src/test/ui/union/union-derive-clone.thirunsafeck.stderr index 146a627bcdef7..e8e65fe5d1d1d 100644 --- a/src/test/ui/union/union-derive-clone.thirunsafeck.stderr +++ b/src/test/ui/union/union-derive-clone.thirunsafeck.stderr @@ -16,9 +16,9 @@ LL | let w = u.clone(); = note: the following trait bounds were not satisfied: `CloneNoCopy: Copy` which is required by `U5: Clone` -help: consider annotating `CloneNoCopy` with `#[derive(Copy)]` +help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]` | -LL | #[derive(Copy)] +LL | #[derive(Clone, Copy)] | error[E0277]: the trait bound `U1: Copy` is not satisfied