Skip to content

Commit 7bf75ab

Browse files
committed
Restrict suggestion only to built-in derive traits
Address review comments and rebase. Add more tests.
1 parent b0c41eb commit 7bf75ab

4 files changed

+92
-14
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

+20-11
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,7 @@ use rustc_span::symbol::{kw, sym, Ident};
3131
use rustc_span::{
3232
edit_distance, ErrorGuaranteed, ExpnKind, FileName, MacroKind, Span, Symbol, DUMMY_SP,
3333
};
34-
use rustc_trait_selection::error_reporting::traits::on_unimplemented::{
35-
OnUnimplementedNote, TypeErrCtxtExt as _,
36-
};
37-
use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt;
34+
use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedNote;
3835
use rustc_trait_selection::infer::InferCtxtExt;
3936
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
4037
use rustc_trait_selection::traits::{
@@ -1374,16 +1371,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13741371
else {
13751372
continue;
13761373
};
1374+
let lang = tcx.lang_items();
1375+
if ![
1376+
lang.copy_trait(),
1377+
lang.clone_trait(),
1378+
tcx.get_diagnostic_item(sym::Debug),
1379+
tcx.get_diagnostic_item(sym::Eq),
1380+
tcx.get_diagnostic_item(sym::PartialEq),
1381+
tcx.get_diagnostic_item(sym::Default),
1382+
]
1383+
.contains(&Some(trait_pred.def_id()))
1384+
{
1385+
// We restrict ourselves only to built-in `derive`s.
1386+
continue;
1387+
}
13771388
let (adt, params) = match trait_pred.self_ty().kind() {
13781389
ty::Adt(adt, params) if adt.did().is_local() => (*adt, params),
13791390
_ => continue,
13801391
};
1381-
if self
1382-
.tcx
1392+
if tcx
13831393
.all_impls(trait_pred.def_id())
1384-
.filter_map(|imp_did| {
1385-
self.tcx.impl_trait_header(imp_did).map(|h| (imp_did, h))
1386-
})
1394+
.filter_map(|imp_did| tcx.impl_trait_header(imp_did).map(|h| (imp_did, h)))
13871395
.filter(|(did, header)| {
13881396
let imp = header.trait_ref.instantiate_identity();
13891397
let impl_adt = match imp.self_ty().ty_adt_def() {
@@ -1392,7 +1400,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13921400
};
13931401
header.polarity == ty::ImplPolarity::Positive
13941402
&& impl_adt == adt
1395-
&& self.tcx.is_automatically_derived(*did)
1403+
&& tcx.is_automatically_derived(*did)
13961404
})
13971405
.count()
13981406
== 1
@@ -1413,7 +1421,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14131421
// The type param at hand is a local type, try to suggest
14141422
// `derive(Trait)`.
14151423
let trait_ref =
1416-
ty::TraitRef::new(tcx, trait_pred.trait_ref.def_id, [ty]);
1424+
ty::TraitRef::identity(tcx, trait_pred.trait_ref.def_id)
1425+
.with_self_ty(tcx, ty);
14171426
let trait_pred = ty::Binder::dummy(ty::TraitPredicate {
14181427
trait_ref,
14191428
polarity: ty::PredicatePolarity::Positive,

tests/ui/suggestions/type-or-type-param-missing-transitive-trait-contraint.fixed

+10-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ struct Ctx<A> {
77
a_map: HashMap<String, B<A>>,
88
}
99

10-
#[derive(Clone)]
10+
#[derive(Clone, PartialEq, Eq)]
1111
struct B<A> {
1212
a: A,
1313
}
@@ -17,9 +17,18 @@ fn foo<Z: std::clone::Clone>(ctx: &mut Ctx<Z>) {
1717
}
1818

1919
#[derive(Clone)]
20+
#[derive(PartialEq)]
2021
struct S;
2122
fn bar(ctx: &mut Ctx<S>) {
2223
let a_map = ctx.a_map.clone(); //~ ERROR E0599
2324
}
2425

26+
fn qux<Z>(ctx: &mut Ctx<Z>) where Z: PartialEq {
27+
ctx.a_map["a"].eq(&ctx.a_map["a"]); //~ ERROR E0599
28+
}
29+
30+
fn qut(ctx: &mut Ctx<S>) {
31+
ctx.a_map["a"].eq(&ctx.a_map["a"]); //~ ERROR E0599
32+
}
33+
2534
fn main() {}

tests/ui/suggestions/type-or-type-param-missing-transitive-trait-contraint.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ struct Ctx<A> {
77
a_map: HashMap<String, B<A>>,
88
}
99

10-
#[derive(Clone)]
10+
#[derive(Clone, PartialEq, Eq)]
1111
struct B<A> {
1212
a: A,
1313
}
@@ -21,4 +21,12 @@ fn bar(ctx: &mut Ctx<S>) {
2121
let a_map = ctx.a_map.clone(); //~ ERROR E0599
2222
}
2323

24+
fn qux<Z>(ctx: &mut Ctx<Z>) {
25+
ctx.a_map["a"].eq(&ctx.a_map["a"]); //~ ERROR E0599
26+
}
27+
28+
fn qut(ctx: &mut Ctx<S>) {
29+
ctx.a_map["a"].eq(&ctx.a_map["a"]); //~ ERROR E0599
30+
}
31+
2432
fn main() {}

tests/ui/suggestions/type-or-type-param-missing-transitive-trait-contraint.stderr

+53-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,58 @@ LL + #[derive(Clone)]
3333
LL | struct S;
3434
|
3535

36-
error: aborting due to 2 previous errors
36+
error[E0599]: the method `eq` exists for struct `B<Z>`, but its trait bounds were not satisfied
37+
--> $DIR/type-or-type-param-missing-transitive-trait-contraint.rs:25:20
38+
|
39+
LL | struct B<A> {
40+
| ----------- method `eq` not found for this struct because it doesn't satisfy `B<Z>: Iterator` or `B<Z>: PartialEq`
41+
...
42+
LL | ctx.a_map["a"].eq(&ctx.a_map["a"]);
43+
| ^^ method cannot be called on `B<Z>` due to unsatisfied trait bounds
44+
|
45+
note: trait bound `Z: PartialEq` was not satisfied
46+
--> $DIR/type-or-type-param-missing-transitive-trait-contraint.rs:10:17
47+
|
48+
LL | #[derive(Clone, PartialEq, Eq)]
49+
| ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
50+
= note: the following trait bounds were not satisfied:
51+
`B<Z>: Iterator`
52+
which is required by `&mut B<Z>: Iterator`
53+
note: the trait `Iterator` must be implemented
54+
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
55+
help: consider restricting the type parameter to satisfy the trait bound
56+
|
57+
LL | fn qux<Z>(ctx: &mut Ctx<Z>) where Z: PartialEq {
58+
| ++++++++++++++++++
59+
60+
error[E0599]: the method `eq` exists for struct `B<S>`, but its trait bounds were not satisfied
61+
--> $DIR/type-or-type-param-missing-transitive-trait-contraint.rs:29:20
62+
|
63+
LL | struct B<A> {
64+
| ----------- method `eq` not found for this struct because it doesn't satisfy `B<S>: Iterator` or `B<S>: PartialEq`
65+
...
66+
LL | struct S;
67+
| -------- doesn't satisfy `S: PartialEq`
68+
...
69+
LL | ctx.a_map["a"].eq(&ctx.a_map["a"]);
70+
| ^^ method cannot be called on `B<S>` due to unsatisfied trait bounds
71+
|
72+
note: trait bound `S: PartialEq` was not satisfied
73+
--> $DIR/type-or-type-param-missing-transitive-trait-contraint.rs:10:17
74+
|
75+
LL | #[derive(Clone, PartialEq, Eq)]
76+
| ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
77+
= note: the following trait bounds were not satisfied:
78+
`B<S>: Iterator`
79+
which is required by `&mut B<S>: Iterator`
80+
note: the trait `Iterator` must be implemented
81+
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
82+
help: consider annotating `S` with `#[derive(PartialEq)]`
83+
|
84+
LL + #[derive(PartialEq)]
85+
LL | struct S;
86+
|
87+
88+
error: aborting due to 4 previous errors
3789

3890
For more information about this error, try `rustc --explain E0599`.

0 commit comments

Comments
 (0)