Skip to content

Commit 167ae23

Browse files
committed
On E0277 pointing at bound in derive, suggest manual impl
When encountering a bound coming from a derive macro, suggest manual impl of the trait. Use the span for the specific param when adding bounds in builtin derive macros, so the diagnostic will point at them as well as the derive macro itself. ``` error[E0277]: can't compare `SomeNode` with `SomeNode` --> f29.rs:24:15 | 24 | accept_eq(&node); | --------- ^^^^^ no implementation for `SomeNode == SomeNode` | | | required by a bound introduced by this call | = note: -Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs:279:39 = help: the trait `PartialEq` is not implemented for `SomeNode` note: required for `Id<SomeNode>` to implement `PartialEq` --> f29.rs:3:10 | 3 | #[derive(PartialEq, Eq)] | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro 4 | pub struct Id<T>(PhantomData<T>); | - = help: consider manually implementing `PartialEq` to avoid undesired bounds note: required by a bound in `accept_eq` --> f29.rs:15:23 | 15 | fn accept_eq(_: &impl PartialEq) { } | ^^^^^^^^^ required by this bound in `accept_eq` help: consider annotating `SomeNode` with `#[derive(PartialEq)]` | 13 + #[derive(PartialEq)] 14 | struct SomeNode(); | ```
1 parent fbb6fac commit 167ae23

File tree

14 files changed

+140
-26
lines changed

14 files changed

+140
-26
lines changed

compiler/rustc_builtin_macros/src/deriving/generic/mod.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -638,27 +638,27 @@ impl<'a> TraitDef<'a> {
638638
GenericParamKind::Type { .. } => {
639639
// Extra restrictions on the generics parameters to the
640640
// type being derived upon.
641+
let span = param.ident.span.with_ctxt(ctxt);
641642
let bounds: Vec<_> = self
642643
.additional_bounds
643644
.iter()
644645
.map(|p| {
645-
cx.trait_bound(
646-
p.to_path(cx, self.span, type_ident, generics),
647-
self.is_const,
648-
)
646+
cx.trait_bound(p.to_path(cx, span, type_ident, generics), self.is_const)
649647
})
650648
.chain(
651649
// Add a bound for the current trait.
652-
self.skip_path_as_bound
653-
.not()
654-
.then(|| cx.trait_bound(trait_path.clone(), self.is_const)),
650+
self.skip_path_as_bound.not().then(|| {
651+
let mut trait_path = trait_path.clone();
652+
trait_path.span = span;
653+
cx.trait_bound(trait_path, self.is_const)
654+
}),
655655
)
656656
.chain({
657657
// Add a `Copy` bound if required.
658658
if is_packed && self.needs_copy_as_bound_if_packed {
659659
let p = deriving::path_std!(marker::Copy);
660660
Some(cx.trait_bound(
661-
p.to_path(cx, self.span, type_ident, generics),
661+
p.to_path(cx, span, type_ident, generics),
662662
self.is_const,
663663
))
664664
} else {
@@ -671,7 +671,7 @@ impl<'a> TraitDef<'a> {
671671
)
672672
.collect();
673673

674-
cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None)
674+
cx.typaram(span, param.ident, bounds, None)
675675
}
676676
GenericParamKind::Const { ty, span, .. } => {
677677
let const_nodefault_kind = GenericParamKind::Const {

compiler/rustc_hir/src/hir.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// ignore-tidy-filelength
22
use std::borrow::Cow;
33
use std::fmt;
4+
use std::ops::Not;
45

56
use rustc_abi::ExternAbi;
67
use rustc_ast::attr::AttributeExt;
@@ -1012,10 +1013,14 @@ impl<'hir> Generics<'hir> {
10121013

10131014
span_for_parentheses.map_or_else(
10141015
|| {
1015-
// We include bounds that come from a `#[derive(_)]` but point at the user's code,
1016-
// as we use this method to get a span appropriate for suggestions.
1016+
// We include bounds that come from a `#[derive(_)]` but point at the user's
1017+
// code, as we use this method to get a span appropriate for suggestions.
10171018
let bs = bound.span();
1018-
bs.can_be_used_for_suggestions().then(|| (bs.shrink_to_hi(), None))
1019+
// We use `from_expansion` instead of `can_be_used_for_suggestions` becuase
1020+
// the trait bound from imperfect derives do point at the type paramer, but
1021+
// expanded to a where clause, so we want to ignore those. This is only
1022+
// true for derive intrinsics.
1023+
bs.from_expansion().not().then(|| (bs.shrink_to_hi(), None))
10191024
},
10201025
|span| Some((span.shrink_to_hi(), Some(span.shrink_to_lo()))),
10211026
)

compiler/rustc_middle/src/ty/diagnostics.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -526,12 +526,15 @@ pub fn suggest_constraining_type_params<'a>(
526526
//
527527
// fn foo<T>(t: T) { ... }
528528
// - help: consider restricting this type parameter with `T: Foo`
529-
suggestions.push((
530-
param.span.shrink_to_hi(),
531-
post,
532-
format!(": {constraint}"),
533-
SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
534-
));
529+
let span = param.span.shrink_to_hi();
530+
if span.can_be_used_for_suggestions() {
531+
suggestions.push((
532+
span,
533+
post,
534+
format!(": {constraint}"),
535+
SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
536+
));
537+
}
535538
}
536539

537540
// FIXME: remove the suggestions that are from derive, as the span is not correct

compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3586,13 +3586,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
35863586
}
35873587
spans.push(self_ty.span);
35883588
let mut spans: MultiSpan = spans.into();
3589+
let mut derived = false;
35893590
if matches!(
35903591
self_ty.span.ctxt().outer_expn_data().kind,
35913592
ExpnKind::Macro(MacroKind::Derive, _)
35923593
) || matches!(
35933594
of_trait.map(|t| t.trait_ref.path.span.ctxt().outer_expn_data().kind),
35943595
Some(ExpnKind::Macro(MacroKind::Derive, _))
35953596
) {
3597+
derived = true;
35963598
spans.push_span_label(
35973599
data.span,
35983600
"unsatisfied trait bound introduced in this `derive` macro",
@@ -3621,6 +3623,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
36213623
}
36223624
}
36233625
err.span_note(spans, msg);
3626+
if derived {
3627+
err.help(format!(
3628+
"consider manually implementing `{trait_name}` to avoid undesired \
3629+
bounds",
3630+
));
3631+
}
36243632
point_at_assoc_type_restriction(
36253633
tcx,
36263634
err,

tests/ui/associated-types/issue-38821.stderr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ LL | #[derive(Debug, Copy, Clone)]
102102
...
103103
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>,
104104
| ------------------------------------------------ unsatisfied trait bound introduced in this `derive` macro
105+
= help: consider manually implementing `Debug` to avoid undesired bounds
105106
help: consider further restricting the associated type
106107
|
107108
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
@@ -146,6 +147,7 @@ LL | #[derive(Debug, Copy, Clone)]
146147
...
147148
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>,
148149
| ------------------------------------------------ unsatisfied trait bound introduced in this `derive` macro
150+
= help: consider manually implementing `Copy` to avoid undesired bounds
149151
help: consider further restricting the associated type
150152
|
151153
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
@@ -219,6 +221,7 @@ LL | #[derive(Debug, Copy, Clone)]
219221
...
220222
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>,
221223
| ------------------------------------------------ unsatisfied trait bound introduced in this `derive` macro
224+
= help: consider manually implementing `Clone` to avoid undesired bounds
222225
help: consider further restricting the associated type
223226
|
224227
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,

tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)]
6565
| ^^^^^
6666
LL | struct Bar<T>(T);
6767
| - unsatisfied trait bound introduced in this `derive` macro
68+
= help: consider manually implementing `Debug` to avoid undesired bounds
6869
= note: 2 redundant requirements hidden
6970
= note: required for `&&'static Bar<(dyn Debug + 'static)>` to implement `Debug`
7071
= note: required for the cast from `&&&'static Bar<(dyn Debug + 'static)>` to `&dyn Debug`
@@ -96,7 +97,10 @@ note: required for `Bar<dyn Debug>` to implement `Eq`
9697
--> $DIR/unsizing-wfcheck-issue-126272.rs:19:28
9798
|
9899
LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)]
99-
| ^^ unsatisfied trait bound introduced in this `derive` macro
100+
| ^^
101+
LL | struct Bar<T>(T);
102+
| - unsatisfied trait bound introduced in this `derive` macro
103+
= help: consider manually implementing `Eq` to avoid undesired bounds
100104
= note: 1 redundant requirement hidden
101105
= note: required for `&'static Bar<dyn Debug>` to implement `Eq`
102106
note: required by a bound in `AssertParamIsEq`

tests/ui/consts/const-blocks/trait-error.stderr

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ note: required for `Foo<String>` to implement `Copy`
88
--> $DIR/trait-error.rs:1:10
99
|
1010
LL | #[derive(Copy, Clone)]
11-
| ^^^^ unsatisfied trait bound introduced in this `derive` macro
11+
| ^^^^
12+
LL | struct Foo<T>(T);
13+
| - unsatisfied trait bound introduced in this `derive` macro
14+
= help: consider manually implementing `Copy` to avoid undesired bounds
1215
= note: the `Copy` trait is required because this value will be copied for each element of the array
1316
help: create an inline `const` block
1417
|

tests/ui/derives/deriving-copyclone.stderr

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ note: required for `B<C>` to implement `Copy`
1010
--> $DIR/deriving-copyclone.rs:9:10
1111
|
1212
LL | #[derive(Copy, Clone)]
13-
| ^^^^ unsatisfied trait bound introduced in this `derive` macro
13+
| ^^^^
14+
LL | struct B<T> {
15+
| - unsatisfied trait bound introduced in this `derive` macro
16+
= help: consider manually implementing `Copy` to avoid undesired bounds
1417
note: required by a bound in `is_copy`
1518
--> $DIR/deriving-copyclone.rs:18:15
1619
|
@@ -33,7 +36,10 @@ note: required for `B<C>` to implement `Clone`
3336
--> $DIR/deriving-copyclone.rs:9:16
3437
|
3538
LL | #[derive(Copy, Clone)]
36-
| ^^^^^ unsatisfied trait bound introduced in this `derive` macro
39+
| ^^^^^
40+
LL | struct B<T> {
41+
| - unsatisfied trait bound introduced in this `derive` macro
42+
= help: consider manually implementing `Clone` to avoid undesired bounds
3743
note: required by a bound in `is_clone`
3844
--> $DIR/deriving-copyclone.rs:19:16
3945
|
@@ -56,7 +62,10 @@ note: required for `B<D>` to implement `Copy`
5662
--> $DIR/deriving-copyclone.rs:9:10
5763
|
5864
LL | #[derive(Copy, Clone)]
59-
| ^^^^ unsatisfied trait bound introduced in this `derive` macro
65+
| ^^^^
66+
LL | struct B<T> {
67+
| - unsatisfied trait bound introduced in this `derive` macro
68+
= help: consider manually implementing `Copy` to avoid undesired bounds
6069
note: required by a bound in `is_copy`
6170
--> $DIR/deriving-copyclone.rs:18:15
6271
|

tests/ui/generic-associated-types/impl_bounds.stderr

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ note: required for `Fooy<T>` to implement `Copy`
3232
--> $DIR/impl_bounds.rs:10:10
3333
|
3434
LL | #[derive(Copy, Clone)]
35-
| ^^^^ unsatisfied trait bound introduced in this `derive` macro
35+
| ^^^^
36+
LL | struct Fooy<T>(T);
37+
| - unsatisfied trait bound introduced in this `derive` macro
38+
= help: consider manually implementing `Copy` to avoid undesired bounds
3639
note: the requirement `Fooy<T>: Copy` appears on the `impl`'s associated type `C` but not on the corresponding trait's associated type
3740
--> $DIR/impl_bounds.rs:6:10
3841
|
@@ -56,7 +59,10 @@ note: required for `Fooy<T>` to implement `Copy`
5659
--> $DIR/impl_bounds.rs:10:10
5760
|
5861
LL | #[derive(Copy, Clone)]
59-
| ^^^^ unsatisfied trait bound introduced in this `derive` macro
62+
| ^^^^
63+
LL | struct Fooy<T>(T);
64+
| - unsatisfied trait bound introduced in this `derive` macro
65+
= help: consider manually implementing `Copy` to avoid undesired bounds
6066
note: the requirement `Fooy<T>: Copy` appears on the `impl`'s associated function `d` but not on the corresponding trait's associated function
6167
--> $DIR/impl_bounds.rs:7:8
6268
|

tests/ui/proc-macro/issue-104884-trait-impl-sugg-err.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@ note: required for `PriorityQueue<T>` to implement `PartialOrd`
3737
--> $DIR/issue-104884-trait-impl-sugg-err.rs:14:10
3838
|
3939
LL | #[derive(PartialOrd, AddImpl)]
40-
| ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
40+
| ^^^^^^^^^^
41+
...
42+
LL | struct PriorityQueue<T>(BinaryHeap<PriorityQueueEntry<T>>);
43+
| - unsatisfied trait bound introduced in this `derive` macro
44+
= help: consider manually implementing `PartialOrd` to avoid undesired bounds
4145
note: required by a bound in `Ord`
4246
--> $SRC_DIR/core/src/cmp.rs:LL:COL
4347

0 commit comments

Comments
 (0)