Skip to content

Commit 7556236

Browse files
committed
Handle Path<> better in error messages.
`Path<>` needs to be distinguished from `Path<T>`. This commit does that. Also, `maybe_insert_elided_lifetimes_in_path` now does a little more span shrinkage so all the spans it produces are empty and point to the lifetime insertion point. As a result, `suggestion` no longer needs to do any span shrinking. All this improves some error messages. First, on the `Path` case, we have this diff: ``` LL | fn f(_: impl Foo) {} - | ^^^ expected named lifetime parameter + | ^ expected named lifetime parameter ``` The carets now point to where the named lifetime parameter must be inserted, as per the subsequent suggestion: ``` LL | fn f<'a>(_: impl Foo<'a>) {} | ++++ ++++ ``` Similar story on this diff on the `Path<>` case: ``` LL | fn f(_: impl Foo<>) {} - | ^ expected named lifetime parameter + | ^ expected named lifetime parameter ``` Plus we now print the `Path<>` suggestion properly: ``` -LL - fn f(_: impl Foo<>) {} -LL + fn f<'a>(_: impl Foo'a, >) {} - | +LL | fn f<'a>(_: impl Foo<'a, >) {} + | ++++ +++ ```
1 parent cae5ecb commit 7556236

File tree

4 files changed

+58
-42
lines changed

4 files changed

+58
-42
lines changed

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
5454
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
5555
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
5656
use rustc_hir::{
57-
self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, LifetimeSource,
58-
LifetimeSyntax, ParamName, TraitCandidate,
57+
self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem,
58+
LifetimeSource, LifetimeSyntax, ParamName, TraitCandidate,
5959
};
6060
use rustc_index::{Idx, IndexSlice, IndexVec};
6161
use rustc_macros::extension;
@@ -1081,7 +1081,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10811081
match arg {
10821082
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(
10831083
lt,
1084-
LifetimeSource::Path { with_angle_brackets: true },
1084+
LifetimeSource::Path { angle_brackets: hir::AngleBrackets::Full },
10851085
lt.ident.into(),
10861086
)),
10871087
ast::GenericArg::Type(ty) => {
@@ -1773,13 +1773,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
17731773
&mut self,
17741774
id: NodeId,
17751775
span: Span,
1776-
with_angle_brackets: bool,
1776+
angle_brackets: AngleBrackets,
17771777
) -> &'hir hir::Lifetime {
17781778
self.new_named_lifetime(
17791779
id,
17801780
id,
17811781
Ident::new(kw::UnderscoreLifetime, span),
1782-
LifetimeSource::Path { with_angle_brackets },
1782+
LifetimeSource::Path { angle_brackets },
17831783
LifetimeSyntax::Hidden,
17841784
)
17851785
}

compiler/rustc_ast_lowering/src/path.rs

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -432,27 +432,34 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
432432

433433
// Note: these spans are used for diagnostics when they can't be inferred.
434434
// See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label
435-
let (elided_lifetime_span, with_angle_brackets) = if generic_args.span.is_empty() {
436-
// If there are no brackets, use the identifier span.
435+
let (elided_lifetime_span, angle_brackets) = if generic_args.span.is_empty() {
436+
// No brackets, e.g. `Path`: use an empty span just past the end of the identifier.
437437
// HACK: we use find_ancestor_inside to properly suggest elided spans in paths
438438
// originating from macros, since the segment's span might be from a macro arg.
439-
(segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span), false)
440-
} else if generic_args.is_empty() {
441-
// If there are brackets, but not generic arguments, then use the opening bracket
442-
(generic_args.span.with_hi(generic_args.span.lo() + BytePos(1)), true)
439+
(
440+
segment_ident_span
441+
.find_ancestor_inside(path_span)
442+
.unwrap_or(path_span)
443+
.shrink_to_hi(),
444+
hir::AngleBrackets::Missing,
445+
)
443446
} else {
444-
// Else use an empty span right after the opening bracket.
445-
(generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo(), true)
447+
// Brackets, e.g. `Path<>` or `Path<T>`: use an empty span just after the `<`.
448+
(
449+
generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo(),
450+
if generic_args.is_empty() {
451+
hir::AngleBrackets::Empty
452+
} else {
453+
hir::AngleBrackets::Full
454+
},
455+
)
446456
};
447457

448458
generic_args.args.insert_many(
449459
0,
450460
(start..end).map(|id| {
451-
let l = self.lower_lifetime_hidden_in_path(
452-
id,
453-
elided_lifetime_span,
454-
with_angle_brackets,
455-
);
461+
let l =
462+
self.lower_lifetime_hidden_in_path(id, elided_lifetime_span, angle_brackets);
456463
GenericArg::Lifetime(l)
457464
}),
458465
);

compiler/rustc_hir/src/hir.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,24 @@ use crate::def_id::{DefId, LocalDefIdMap};
3535
pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId};
3636
use crate::intravisit::{FnKind, VisitorExt};
3737

38+
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
39+
pub enum AngleBrackets {
40+
/// E.g. `Path`.
41+
Missing,
42+
/// E.g. `Path<>`.
43+
Empty,
44+
/// E.g. `Path<T>`.
45+
Full,
46+
}
47+
3848
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
3949
pub enum LifetimeSource {
4050
/// E.g. `&Type`, `&'_ Type`, `&'a Type`, `&mut Type`, `&'_ mut Type`, `&'a mut Type`
4151
Reference,
4252

43-
/// E.g. `ContainsLifetime`, `ContainsLifetime<'_>`, `ContainsLifetime<'a>`
44-
Path {
45-
/// - true for `ContainsLifetime<'_>`, `ContainsLifetime<'a>`,
46-
/// `ContainsLifetime<'_, T>`, `ContainsLifetime<'a, T>`
47-
/// - false for `ContainsLifetime`
48-
with_angle_brackets: bool,
49-
},
53+
/// E.g. `ContainsLifetime`, `ContainsLifetime<>`, `ContainsLifetime<'_>`,
54+
/// `ContainsLifetime<'a>`
55+
Path { angle_brackets: AngleBrackets },
5056

5157
/// E.g. `impl Trait + '_`, `impl Trait + 'a`
5258
OutlivesBound,
@@ -304,13 +310,18 @@ impl Lifetime {
304310
(Named | Anonymous, _) => (self.ident.span, format!("{new_lifetime}")),
305311

306312
// The user wrote `Path<T>`, and omitted the `'_,`.
307-
(Hidden, Path { with_angle_brackets: true }) => {
313+
(Hidden, Path { angle_brackets: AngleBrackets::Full }) => {
314+
(self.ident.span, format!("{new_lifetime}, "))
315+
}
316+
317+
// The user wrote `Path<>`, and omitted the `'_`..
318+
(Hidden, Path { angle_brackets: AngleBrackets::Empty }) => {
308319
(self.ident.span, format!("{new_lifetime}, "))
309320
}
310321

311322
// The user wrote `Path` and omitted the `<'_>`.
312-
(Hidden, Path { with_angle_brackets: false }) => {
313-
(self.ident.span.shrink_to_hi(), format!("<{new_lifetime}>"))
323+
(Hidden, Path { angle_brackets: AngleBrackets::Missing }) => {
324+
(self.ident.span, format!("<{new_lifetime}>"))
314325
}
315326

316327
// The user wrote `&type` or `&mut type`.

tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,10 @@ LL + fn g<'a>(mut x: impl Iterator<Item = &'a ()>) -> Option<&'_ ()> { x.nex
212212
|
213213

214214
error[E0658]: anonymous lifetimes in `impl Trait` are unstable
215-
--> $DIR/impl-trait-missing-lifetime-gated.rs:44:18
215+
--> $DIR/impl-trait-missing-lifetime-gated.rs:44:21
216216
|
217217
LL | fn f(_: impl Foo) {}
218-
| ^^^ expected named lifetime parameter
218+
| ^ expected named lifetime parameter
219219
|
220220
= help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
221221
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
@@ -225,10 +225,10 @@ LL | fn f<'a>(_: impl Foo<'a>) {}
225225
| ++++ ++++
226226

227227
error[E0658]: anonymous lifetimes in `impl Trait` are unstable
228-
--> $DIR/impl-trait-missing-lifetime-gated.rs:47:22
228+
--> $DIR/impl-trait-missing-lifetime-gated.rs:47:25
229229
|
230230
LL | fn g(mut x: impl Foo) -> Option<&()> { x.next() }
231-
| ^^^ expected named lifetime parameter
231+
| ^ expected named lifetime parameter
232232
|
233233
= help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
234234
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
@@ -238,32 +238,30 @@ LL | fn g<'a>(mut x: impl Foo<'a>) -> Option<&()> { x.next() }
238238
| ++++ ++++
239239

240240
error[E0658]: anonymous lifetimes in `impl Trait` are unstable
241-
--> $DIR/impl-trait-missing-lifetime-gated.rs:55:21
241+
--> $DIR/impl-trait-missing-lifetime-gated.rs:55:22
242242
|
243243
LL | fn f(_: impl Foo<>) {}
244-
| ^ expected named lifetime parameter
244+
| ^ expected named lifetime parameter
245245
|
246246
= help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
247247
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
248248
help: consider introducing a named lifetime parameter
249249
|
250-
LL - fn f(_: impl Foo<>) {}
251-
LL + fn f<'a>(_: impl Foo'a, >) {}
252-
|
250+
LL | fn f<'a>(_: impl Foo<'a, >) {}
251+
| ++++ +++
253252

254253
error[E0658]: anonymous lifetimes in `impl Trait` are unstable
255-
--> $DIR/impl-trait-missing-lifetime-gated.rs:58:25
254+
--> $DIR/impl-trait-missing-lifetime-gated.rs:58:26
256255
|
257256
LL | fn g(mut x: impl Foo<>) -> Option<&()> { x.next() }
258-
| ^ expected named lifetime parameter
257+
| ^ expected named lifetime parameter
259258
|
260259
= help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
261260
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
262261
help: consider introducing a named lifetime parameter
263262
|
264-
LL - fn g(mut x: impl Foo<>) -> Option<&()> { x.next() }
265-
LL + fn g<'a>(mut x: impl Foo'a, >) -> Option<&()> { x.next() }
266-
|
263+
LL | fn g<'a>(mut x: impl Foo<'a, >) -> Option<&()> { x.next() }
264+
| ++++ +++
267265

268266
error[E0658]: anonymous lifetimes in `impl Trait` are unstable
269267
--> $DIR/impl-trait-missing-lifetime-gated.rs:66:22

0 commit comments

Comments
 (0)