Skip to content

Commit 39aef92

Browse files
authored
Rollup merge of rust-lang#93693 - rukai:91550, r=davidtwco
Suggest deriving required supertraits closes rust-lang#91550 I chose to just hardcode handling for PartialOrd and PartialEq because that should be robust enough and I dont know how to go about doing it generically r? rust-lang/diagnostics
2 parents cae0433 + 1973f27 commit 39aef92

File tree

6 files changed

+154
-25
lines changed

6 files changed

+154
-25
lines changed

compiler/rustc_typeck/src/check/method/suggest.rs

+29-13
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ use rustc_hir::def_id::{DefId, LocalDefId};
99
use rustc_hir::lang_items::LangItem;
1010
use rustc_hir::{ExprKind, Node, QPath};
1111
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
12+
use rustc_middle::traits::util::supertraits;
1213
use rustc_middle::ty::fast_reject::{simplify_type, SimplifyParams};
1314
use rustc_middle::ty::print::with_crate_prefix;
15+
use rustc_middle::ty::ToPolyTraitRef;
1416
use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
1517
use rustc_span::lev_distance;
1618
use rustc_span::symbol::{kw, sym, Ident};
@@ -1196,26 +1198,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11961198
Some(adt) if adt.did.is_local() => adt,
11971199
_ => continue,
11981200
};
1199-
let can_derive = match self.tcx.get_diagnostic_name(trait_pred.def_id()) {
1200-
Some(sym::Default) => !adt.is_enum(),
1201-
Some(
1201+
if let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) {
1202+
let can_derive = match diagnostic_name {
1203+
sym::Default => !adt.is_enum(),
12021204
sym::Eq
12031205
| sym::PartialEq
12041206
| sym::Ord
12051207
| sym::PartialOrd
12061208
| sym::Clone
12071209
| sym::Copy
12081210
| sym::Hash
1209-
| sym::Debug,
1210-
) => true,
1211-
_ => false,
1212-
};
1213-
if can_derive {
1214-
derives.push((
1215-
format!("{}", trait_pred.self_ty()),
1216-
self.tcx.def_span(adt.did),
1217-
format!("{}", trait_pred.trait_ref.print_only_trait_name()),
1218-
));
1211+
| sym::Debug => true,
1212+
_ => false,
1213+
};
1214+
if can_derive {
1215+
let self_name = trait_pred.self_ty().to_string();
1216+
let self_span = self.tcx.def_span(adt.did);
1217+
if let Some(poly_trait_ref) = pred.to_opt_poly_trait_pred() {
1218+
for super_trait in supertraits(self.tcx, poly_trait_ref.to_poly_trait_ref())
1219+
{
1220+
if let Some(parent_diagnostic_name) =
1221+
self.tcx.get_diagnostic_name(super_trait.def_id())
1222+
{
1223+
derives.push((
1224+
self_name.clone(),
1225+
self_span.clone(),
1226+
parent_diagnostic_name.to_string(),
1227+
));
1228+
}
1229+
}
1230+
}
1231+
derives.push((self_name, self_span, diagnostic_name.to_string()));
1232+
} else {
1233+
traits.push(self.tcx.def_span(trait_pred.def_id()));
1234+
}
12191235
} else {
12201236
traits.push(self.tcx.def_span(trait_pred.def_id()));
12211237
}

src/test/ui/binop/issue-28837.stderr

+8-8
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A`
272272
|
273273
LL | struct A;
274274
| ^^^^^^^^^ must implement `PartialOrd<_>`
275-
help: consider annotating `A` with `#[derive(PartialOrd)]`
275+
help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]`
276276
|
277-
LL | #[derive(PartialOrd)]
277+
LL | #[derive(PartialEq, PartialOrd)]
278278
|
279279

280280
error[E0369]: binary operation `<=` cannot be applied to type `A`
@@ -290,9 +290,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A`
290290
|
291291
LL | struct A;
292292
| ^^^^^^^^^ must implement `PartialOrd<_>`
293-
help: consider annotating `A` with `#[derive(PartialOrd)]`
293+
help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]`
294294
|
295-
LL | #[derive(PartialOrd)]
295+
LL | #[derive(PartialEq, PartialOrd)]
296296
|
297297

298298
error[E0369]: binary operation `>` cannot be applied to type `A`
@@ -308,9 +308,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A`
308308
|
309309
LL | struct A;
310310
| ^^^^^^^^^ must implement `PartialOrd<_>`
311-
help: consider annotating `A` with `#[derive(PartialOrd)]`
311+
help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]`
312312
|
313-
LL | #[derive(PartialOrd)]
313+
LL | #[derive(PartialEq, PartialOrd)]
314314
|
315315

316316
error[E0369]: binary operation `>=` cannot be applied to type `A`
@@ -326,9 +326,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A`
326326
|
327327
LL | struct A;
328328
| ^^^^^^^^^ must implement `PartialOrd<_>`
329-
help: consider annotating `A` with `#[derive(PartialOrd)]`
329+
help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]`
330330
|
331-
LL | #[derive(PartialOrd)]
331+
LL | #[derive(PartialEq, PartialOrd)]
332332
|
333333

334334
error: aborting due to 15 previous errors

src/test/ui/derives/issue-91550.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use std::collections::HashSet;
2+
3+
/// natural case from the issue
4+
struct Value(u32);
5+
6+
fn main() {
7+
let hs = HashSet::<Value>::new();
8+
hs.insert(Value(0)); //~ ERROR
9+
}
10+
11+
/// synthetic cases
12+
pub struct NoDerives;
13+
14+
struct Object<T>(T);
15+
impl<T: Eq> Object<T> {
16+
fn use_eq(&self) {}
17+
}
18+
impl<T: Ord> Object<T> {
19+
fn use_ord(&self) {}
20+
}
21+
impl<T: Ord + PartialOrd> Object<T> {
22+
fn use_ord_and_partial_ord(&self) {}
23+
}
24+
25+
fn function(foo: Object<NoDerives>) {
26+
foo.use_eq(); //~ ERROR
27+
foo.use_ord(); //~ ERROR
28+
foo.use_ord_and_partial_ord(); //~ ERROR
29+
}
+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
error[E0599]: the method `insert` exists for struct `HashSet<Value>`, but its trait bounds were not satisfied
2+
--> $DIR/issue-91550.rs:8:8
3+
|
4+
LL | struct Value(u32);
5+
| ------------------
6+
| |
7+
| doesn't satisfy `Value: Eq`
8+
| doesn't satisfy `Value: Hash`
9+
...
10+
LL | hs.insert(Value(0));
11+
| ^^^^^^ method cannot be called on `HashSet<Value>` due to unsatisfied trait bounds
12+
|
13+
= note: the following trait bounds were not satisfied:
14+
`Value: Eq`
15+
`Value: Hash`
16+
help: consider annotating `Value` with `#[derive(Eq, Hash, PartialEq)]`
17+
|
18+
LL | #[derive(Eq, Hash, PartialEq)]
19+
|
20+
21+
error[E0599]: the method `use_eq` exists for struct `Object<NoDerives>`, but its trait bounds were not satisfied
22+
--> $DIR/issue-91550.rs:26:9
23+
|
24+
LL | pub struct NoDerives;
25+
| --------------------- doesn't satisfy `NoDerives: Eq`
26+
LL |
27+
LL | struct Object<T>(T);
28+
| -------------------- method `use_eq` not found for this
29+
...
30+
LL | foo.use_eq();
31+
| ^^^^^^ method cannot be called on `Object<NoDerives>` due to unsatisfied trait bounds
32+
|
33+
= note: the following trait bounds were not satisfied:
34+
`NoDerives: Eq`
35+
help: consider annotating `NoDerives` with `#[derive(Eq, PartialEq)]`
36+
|
37+
LL | #[derive(Eq, PartialEq)]
38+
|
39+
40+
error[E0599]: the method `use_ord` exists for struct `Object<NoDerives>`, but its trait bounds were not satisfied
41+
--> $DIR/issue-91550.rs:27:9
42+
|
43+
LL | pub struct NoDerives;
44+
| --------------------- doesn't satisfy `NoDerives: Ord`
45+
LL |
46+
LL | struct Object<T>(T);
47+
| -------------------- method `use_ord` not found for this
48+
...
49+
LL | foo.use_ord();
50+
| ^^^^^^^ method cannot be called on `Object<NoDerives>` due to unsatisfied trait bounds
51+
|
52+
= note: the following trait bounds were not satisfied:
53+
`NoDerives: Ord`
54+
help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
55+
|
56+
LL | #[derive(Eq, Ord, PartialEq, PartialOrd)]
57+
|
58+
59+
error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object<NoDerives>`, but its trait bounds were not satisfied
60+
--> $DIR/issue-91550.rs:28:9
61+
|
62+
LL | pub struct NoDerives;
63+
| ---------------------
64+
| |
65+
| doesn't satisfy `NoDerives: Ord`
66+
| doesn't satisfy `NoDerives: PartialOrd`
67+
LL |
68+
LL | struct Object<T>(T);
69+
| -------------------- method `use_ord_and_partial_ord` not found for this
70+
...
71+
LL | foo.use_ord_and_partial_ord();
72+
| ^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `Object<NoDerives>` due to unsatisfied trait bounds
73+
|
74+
= note: the following trait bounds were not satisfied:
75+
`NoDerives: Ord`
76+
`NoDerives: PartialOrd`
77+
help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
78+
|
79+
LL | #[derive(Eq, Ord, PartialEq, PartialOrd)]
80+
|
81+
82+
error: aborting due to 4 previous errors
83+
84+
For more information about this error, try `rustc --explain E0599`.

src/test/ui/union/union-derive-clone.mirunsafeck.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ LL | let w = u.clone();
1616
= note: the following trait bounds were not satisfied:
1717
`CloneNoCopy: Copy`
1818
which is required by `U5<CloneNoCopy>: Clone`
19-
help: consider annotating `CloneNoCopy` with `#[derive(Copy)]`
19+
help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]`
2020
|
21-
LL | #[derive(Copy)]
21+
LL | #[derive(Clone, Copy)]
2222
|
2323

2424
error[E0277]: the trait bound `U1: Copy` is not satisfied

src/test/ui/union/union-derive-clone.thirunsafeck.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ LL | let w = u.clone();
1616
= note: the following trait bounds were not satisfied:
1717
`CloneNoCopy: Copy`
1818
which is required by `U5<CloneNoCopy>: Clone`
19-
help: consider annotating `CloneNoCopy` with `#[derive(Copy)]`
19+
help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]`
2020
|
21-
LL | #[derive(Copy)]
21+
LL | #[derive(Clone, Copy)]
2222
|
2323

2424
error[E0277]: the trait bound `U1: Copy` is not satisfied

0 commit comments

Comments
 (0)