Skip to content

Commit 0311cfa

Browse files
authored
Rollup merge of rust-lang#90519 - estebank:issue-84003, r=petrochenkov
Keep spans for generics in `#[derive(_)]` desugaring Keep the spans for generics coming from a `derive`d Item, so that errors and suggestions have better detail. Fix rust-lang#84003.
2 parents 9f8e822 + b0c3968 commit 0311cfa

File tree

14 files changed

+409
-135
lines changed

14 files changed

+409
-135
lines changed

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

+76-78
Large diffs are not rendered by default.

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

+6-10
Original file line numberDiff line numberDiff line change
@@ -211,14 +211,6 @@ fn mk_ty_param(
211211
cx.typaram(span, Ident::new(name, span), attrs.to_owned(), bounds, None)
212212
}
213213

214-
fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
215-
Generics {
216-
params,
217-
where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span },
218-
span,
219-
}
220-
}
221-
222214
/// Bounds on type parameters.
223215
#[derive(Clone)]
224216
pub struct Bounds {
@@ -236,7 +228,7 @@ impl Bounds {
236228
self_ty: Ident,
237229
self_generics: &Generics,
238230
) -> Generics {
239-
let generic_params = self
231+
let params = self
240232
.bounds
241233
.iter()
242234
.map(|t| {
@@ -245,7 +237,11 @@ impl Bounds {
245237
})
246238
.collect();
247239

248-
mk_generics(generic_params, span)
240+
Generics {
241+
params,
242+
where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span },
243+
span,
244+
}
249245
}
250246
}
251247

compiler/rustc_hir/src/hir.rs

+15-8
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ use rustc_index::vec::IndexVec;
1717
use rustc_macros::HashStable_Generic;
1818
use rustc_span::source_map::Spanned;
1919
use rustc_span::symbol::{kw, sym, Ident, Symbol};
20-
use rustc_span::{def_id::LocalDefId, BytePos};
21-
use rustc_span::{MultiSpan, Span, DUMMY_SP};
20+
use rustc_span::{def_id::LocalDefId, BytePos, MultiSpan, Span, DUMMY_SP};
2221
use rustc_target::asm::InlineAsmRegOrRegClass;
2322
use rustc_target::spec::abi::Abi;
2423

@@ -526,12 +525,20 @@ pub struct GenericParam<'hir> {
526525
}
527526

528527
impl GenericParam<'hir> {
529-
pub fn bounds_span(&self) -> Option<Span> {
530-
self.bounds.iter().fold(None, |span, bound| {
531-
let span = span.map(|s| s.to(bound.span())).unwrap_or_else(|| bound.span());
532-
533-
Some(span)
534-
})
528+
pub fn bounds_span_for_suggestions(&self) -> Option<Span> {
529+
self.bounds
530+
.iter()
531+
.fold(None, |span: Option<Span>, bound| {
532+
// We include bounds that come from a `#[derive(_)]` but point at the user's code,
533+
// as we use this method to get a span appropriate for suggestions.
534+
if !bound.span().can_be_used_for_suggestions() {
535+
None
536+
} else {
537+
let span = span.map(|s| s.to(bound.span())).unwrap_or_else(|| bound.span());
538+
Some(span)
539+
}
540+
})
541+
.map(|sp| sp.shrink_to_hi())
535542
}
536543
}
537544

compiler/rustc_middle/src/ty/diagnostics.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ pub fn suggest_constraining_type_param(
270270
// `where` clause instead of `trait Base<T: Copy = String>: Super<T>`.
271271
&& !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
272272
{
273-
if let Some(bounds_span) = param.bounds_span() {
273+
if let Some(span) = param.bounds_span_for_suggestions() {
274274
// If user has provided some bounds, suggest restricting them:
275275
//
276276
// fn foo<T: Foo>(t: T) { ... }
@@ -284,7 +284,7 @@ pub fn suggest_constraining_type_param(
284284
// --
285285
// |
286286
// replace with: `T: Bar +`
287-
suggest_restrict(bounds_span.shrink_to_hi());
287+
suggest_restrict(span);
288288
} else {
289289
// If user hasn't provided any bounds, suggest adding a new one:
290290
//

compiler/rustc_resolve/src/late/diagnostics.rs

+7-13
Original file line numberDiff line numberDiff line change
@@ -1735,7 +1735,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
17351735
(generics.span, format!("<{}>", ident))
17361736
};
17371737
// Do not suggest if this is coming from macro expansion.
1738-
if !span.from_expansion() {
1738+
if span.can_be_used_for_suggestions() {
17391739
return Some((
17401740
span.shrink_to_hi(),
17411741
msg,
@@ -1803,7 +1803,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
18031803
);
18041804
err.span_label(lifetime_ref.span, "undeclared lifetime");
18051805
let mut suggests_in_band = false;
1806-
let mut suggest_note = true;
1806+
let mut suggested_spans = vec![];
18071807
for missing in &self.missing_named_lifetime_spots {
18081808
match missing {
18091809
MissingLifetimeSpot::Generics(generics) => {
@@ -1821,23 +1821,17 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
18211821
suggests_in_band = true;
18221822
(generics.span, format!("<{}>", lifetime_ref))
18231823
};
1824-
if !span.from_expansion() {
1824+
if suggested_spans.contains(&span) {
1825+
continue;
1826+
}
1827+
suggested_spans.push(span);
1828+
if span.can_be_used_for_suggestions() {
18251829
err.span_suggestion(
18261830
span,
18271831
&format!("consider introducing lifetime `{}` here", lifetime_ref),
18281832
sugg,
18291833
Applicability::MaybeIncorrect,
18301834
);
1831-
} else if suggest_note {
1832-
suggest_note = false; // Avoid displaying the same help multiple times.
1833-
err.span_label(
1834-
span,
1835-
&format!(
1836-
"lifetime `{}` is missing in item created through this procedural \
1837-
macro",
1838-
lifetime_ref,
1839-
),
1840-
);
18411835
}
18421836
}
18431837
MissingLifetimeSpot::HigherRanked { span, span_type } => {

compiler/rustc_span/src/lib.rs

+10
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,16 @@ impl Span {
551551
matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
552552
}
553553

554+
/// Gate suggestions that would not be appropriate in a context the user didn't write.
555+
pub fn can_be_used_for_suggestions(self) -> bool {
556+
!self.from_expansion()
557+
// FIXME: If this span comes from a `derive` macro but it points at code the user wrote,
558+
// the callsite span and the span will be pointing at different places. It also means that
559+
// we can safely provide suggestions on this span.
560+
|| (matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
561+
&& self.parent_callsite().map(|p| (p.lo(), p.hi())) != Some((self.lo(), self.hi())))
562+
}
563+
554564
#[inline]
555565
pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span {
556566
Span::new(lo, hi, SyntaxContext::root(), None)

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -262,16 +262,16 @@ fn suggest_restriction(
262262
match generics
263263
.params
264264
.iter()
265-
.map(|p| p.bounds_span().unwrap_or(p.span))
266-
.filter(|&span| generics.span.contains(span) && span.desugaring_kind().is_none())
265+
.map(|p| p.bounds_span_for_suggestions().unwrap_or(p.span.shrink_to_hi()))
266+
.filter(|&span| generics.span.contains(span) && span.can_be_used_for_suggestions())
267267
.max_by_key(|span| span.hi())
268268
{
269269
// `fn foo(t: impl Trait)`
270270
// ^ suggest `<T: Trait>` here
271271
None => (generics.span, format!("<{}>", type_param)),
272272
// `fn foo<A>(t: impl Trait)`
273273
// ^^^ suggest `<A, T: Trait>` here
274-
Some(span) => (span.shrink_to_hi(), format!(", {}", type_param)),
274+
Some(span) => (span, format!(", {}", type_param)),
275275
},
276276
// `fn foo(t: impl Trait)`
277277
// ^ suggest `where <T as Trait>::A: Bound`

compiler/rustc_typeck/src/collect.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,9 @@ crate fn placeholder_type_error(
177177
sugg.push((arg.span, (*type_name).to_string()));
178178
} else {
179179
let last = generics.iter().last().unwrap();
180-
sugg.push((
181-
// Account for bounds, we want `fn foo<T: E, K>(_: K)` not `fn foo<T, K: E>(_: K)`.
182-
last.bounds_span().unwrap_or(last.span).shrink_to_hi(),
183-
format!(", {}", type_name),
184-
));
180+
// Account for bounds, we want `fn foo<T: E, K>(_: K)` not `fn foo<T, K: E>(_: K)`.
181+
let span = last.bounds_span_for_suggestions().unwrap_or(last.span.shrink_to_hi());
182+
sugg.push((span, format!(", {}", type_name)));
185183
}
186184

187185
let mut err = bad_placeholder_type(tcx, placeholder_types, kind);

src/test/ui/issues/issue-38821.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ note: required because of the requirements on the impl of `IntoNullable` for `<C
1010
LL | impl<T: NotNull> IntoNullable for T {
1111
| ^^^^^^^^^^^^ ^
1212
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
13+
help: consider further restricting the associated type
14+
|
15+
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
16+
| +++++++++++++++++++++++++++++++++++++++
1317

1418
error: aborting due to previous error
1519

src/test/ui/issues/issue-50480.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
#[derive(Clone, Copy)]
22
//~^ ERROR the trait `Copy` may not be implemented for this type
3-
struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
3+
struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
44
//~^ ERROR cannot find type `NotDefined` in this scope
55
//~| ERROR cannot find type `NotDefined` in this scope
6+
//~| ERROR cannot find type `N` in this scope
7+
//~| ERROR cannot find type `N` in this scope
8+
//~| ERROR `i32` is not an iterator
9+
10+
#[derive(Clone, Copy)]
11+
//~^ ERROR the trait `Copy` may not be implemented for this type
12+
struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
13+
//~^ ERROR cannot find type `NotDefined` in this scope
14+
//~| ERROR cannot find type `N` in this scope
615
//~| ERROR `i32` is not an iterator
716

817
fn main() {}

src/test/ui/issues/issue-50480.stderr

+76-13
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,61 @@
1-
error[E0412]: cannot find type `NotDefined` in this scope
1+
error[E0412]: cannot find type `N` in this scope
22
--> $DIR/issue-50480.rs:3:12
33
|
4-
LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
5-
| ^^^^^^^^^^ not found in this scope
4+
LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
5+
| -^ not found in this scope
6+
| |
7+
| help: you might be missing a type parameter: `<N>`
68

79
error[E0412]: cannot find type `NotDefined` in this scope
10+
--> $DIR/issue-50480.rs:3:15
11+
|
12+
LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
13+
| ^^^^^^^^^^ not found in this scope
14+
15+
error[E0412]: cannot find type `N` in this scope
816
--> $DIR/issue-50480.rs:3:12
917
|
10-
LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
11-
| ^^^^^^^^^^ not found in this scope
18+
LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
19+
| -^ not found in this scope
20+
| |
21+
| help: you might be missing a type parameter: `<N>`
22+
23+
error[E0412]: cannot find type `NotDefined` in this scope
24+
--> $DIR/issue-50480.rs:3:15
25+
|
26+
LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
27+
| - ^^^^^^^^^^ not found in this scope
28+
| |
29+
| help: you might be missing a type parameter: `<NotDefined>`
30+
31+
error[E0412]: cannot find type `N` in this scope
32+
--> $DIR/issue-50480.rs:12:18
33+
|
34+
LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
35+
| - ^
36+
| |
37+
| similarly named type parameter `T` defined here
38+
|
39+
help: a type parameter with a similar name exists
40+
|
41+
LL | struct Bar<T>(T, T, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
42+
| ~
43+
help: you might be missing a type parameter
44+
|
45+
LL | struct Bar<T, N>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
46+
| +++
47+
48+
error[E0412]: cannot find type `NotDefined` in this scope
49+
--> $DIR/issue-50480.rs:12:21
50+
|
51+
LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
52+
| ^^^^^^^^^^ not found in this scope
1253

1354
error[E0277]: `i32` is not an iterator
14-
--> $DIR/issue-50480.rs:3:24
55+
--> $DIR/issue-50480.rs:3:27
1556
|
16-
LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
17-
| ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
57+
LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
58+
| ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
1859
|
1960
= help: the trait `Iterator` is not implemented for `i32`
2061
= note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
@@ -25,14 +66,36 @@ error[E0204]: the trait `Copy` may not be implemented for this type
2566
LL | #[derive(Clone, Copy)]
2667
| ^^^^
2768
LL |
28-
LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
29-
| -------- ------ this field does not implement `Copy`
30-
| |
31-
| this field does not implement `Copy`
69+
LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
70+
| -------- ------ this field does not implement `Copy`
71+
| |
72+
| this field does not implement `Copy`
73+
|
74+
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
75+
76+
error[E0277]: `i32` is not an iterator
77+
--> $DIR/issue-50480.rs:12:33
78+
|
79+
LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
80+
| ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
81+
|
82+
= help: the trait `Iterator` is not implemented for `i32`
83+
= note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
84+
85+
error[E0204]: the trait `Copy` may not be implemented for this type
86+
--> $DIR/issue-50480.rs:10:17
87+
|
88+
LL | #[derive(Clone, Copy)]
89+
| ^^^^
90+
LL |
91+
LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
92+
| -------- ------ this field does not implement `Copy`
93+
| |
94+
| this field does not implement `Copy`
3295
|
3396
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
3497

35-
error: aborting due to 4 previous errors
98+
error: aborting due to 10 previous errors
3699

37100
Some errors have detailed explanations: E0204, E0277, E0412.
38101
For more information about an error, try `rustc --explain E0204`.

src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ LL | a: &'b str,
1111
error[E0261]: use of undeclared lifetime name `'b`
1212
--> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9
1313
|
14-
LL | #[derive(Eq, PartialEq)]
15-
| -- lifetime `'b` is missing in item created through this procedural macro
1614
LL | struct Test {
15+
| - help: consider introducing lifetime `'b` here: `<'b>`
1716
LL | a: &'b str,
1817
| ^^ undeclared lifetime
1918
|

0 commit comments

Comments
 (0)