Skip to content

Commit 1c737d6

Browse files
committed
Use kw::Empty for elided lifetimes in path.
1 parent 4109034 commit 1c737d6

File tree

12 files changed

+281
-83
lines changed

12 files changed

+281
-83
lines changed

compiler/rustc_ast_lowering/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -2101,7 +2101,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
21012101
hir::LifetimeName::Param(param)
21022102
}
21032103
LifetimeRes::Fresh { param, .. } => {
2104-
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
21052104
let param = self.local_def_id(param);
21062105
hir::LifetimeName::Param(param)
21072106
}

compiler/rustc_ast_lowering/src/path.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
309309
let id = NodeId::from_u32(i);
310310
let l = self.lower_lifetime(&Lifetime {
311311
id,
312-
ident: Ident::new(kw::UnderscoreLifetime, elided_lifetime_span),
312+
ident: Ident::new(kw::Empty, elided_lifetime_span),
313313
});
314314
GenericArg::Lifetime(l)
315315
}),

compiler/rustc_hir/src/hir.rs

+35-5
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,15 @@ use std::fmt;
2929
#[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)]
3030
pub struct Lifetime {
3131
pub hir_id: HirId,
32-
pub ident: Ident,
3332

3433
/// Either "`'a`", referring to a named lifetime definition,
35-
/// or "``" (i.e., `kw::Empty`), for elision placeholders.
34+
/// `'_` referring to an anonymous lifetime (either explicitly `'_` or `&type`),
35+
/// or "``" (i.e., `kw::Empty`) when appearing in path.
3636
///
37-
/// HIR lowering inserts these placeholders in type paths that
38-
/// refer to type definitions needing lifetime parameters,
39-
/// `&T` and `&mut T`, and trait objects without `... + 'a`.
37+
/// See `Lifetime::suggestion_position` for practical use.
38+
pub ident: Ident,
39+
40+
/// Semantics of this lifetime.
4041
pub res: LifetimeName,
4142
}
4243

@@ -135,6 +136,19 @@ impl fmt::Display for Lifetime {
135136
}
136137
}
137138

139+
pub enum LifetimeSuggestionPosition {
140+
/// The user wrote `'a` or `'_`.
141+
Normal,
142+
/// The user wrote `&type` or `&mut type`.
143+
Ampersand,
144+
/// The user wrote `Path` and omitted the `<'_>`.
145+
ElidedPath,
146+
/// The user wrote `Path<T>`, and omitted the `'_,`.
147+
ElidedPathArgument,
148+
/// The user wrote `dyn Trait` and omitted the `+ '_`.
149+
ObjectDefault,
150+
}
151+
138152
impl Lifetime {
139153
pub fn is_elided(&self) -> bool {
140154
self.res.is_elided()
@@ -144,6 +158,22 @@ impl Lifetime {
144158
self.ident.name == kw::Empty || self.ident.name == kw::UnderscoreLifetime
145159
}
146160

161+
pub fn suggestion_position(&self) -> (LifetimeSuggestionPosition, Span) {
162+
if self.ident.name == kw::Empty {
163+
if self.ident.span.is_empty() {
164+
(LifetimeSuggestionPosition::ElidedPathArgument, self.ident.span)
165+
} else {
166+
(LifetimeSuggestionPosition::ElidedPath, self.ident.span.shrink_to_hi())
167+
}
168+
} else if self.res == LifetimeName::ImplicitObjectLifetimeDefault {
169+
(LifetimeSuggestionPosition::ObjectDefault, self.ident.span)
170+
} else if self.ident.span.is_empty() {
171+
(LifetimeSuggestionPosition::Ampersand, self.ident.span)
172+
} else {
173+
(LifetimeSuggestionPosition::Normal, self.ident.span)
174+
}
175+
}
176+
147177
pub fn is_static(&self) -> bool {
148178
self.res == LifetimeName::Static
149179
}

compiler/rustc_hir_analysis/src/collect/lifetimes.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use rustc_middle::hir::nested_filter;
1919
use rustc_middle::middle::resolve_lifetime::*;
2020
use rustc_middle::ty::{self, DefIdTree, TyCtxt, TypeSuperVisitable, TypeVisitor};
2121
use rustc_span::def_id::DefId;
22-
use rustc_span::symbol::{kw, sym, Ident};
22+
use rustc_span::symbol::{sym, Ident};
2323
use rustc_span::Span;
2424
use std::fmt;
2525

@@ -1218,13 +1218,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
12181218
(generics.span, "<'a>".to_owned())
12191219
};
12201220

1221-
let lifetime_sugg = match lifetime_ref.ident.name {
1222-
kw::Empty => "'a, ".to_owned(),
1223-
kw::UnderscoreLifetime => "'a ".to_owned(),
1224-
_ => "'a ".to_owned(),
1221+
let lifetime_sugg = match lifetime_ref.suggestion_position() {
1222+
(hir::LifetimeSuggestionPosition::Normal, span) => (span, "'a".to_owned()),
1223+
(hir::LifetimeSuggestionPosition::Ampersand, span) => (span, "'a ".to_owned()),
1224+
(hir::LifetimeSuggestionPosition::ElidedPath, span) => (span, "<'a>".to_owned()),
1225+
(hir::LifetimeSuggestionPosition::ElidedPathArgument, span) => (span, "'a, ".to_owned()),
1226+
(hir::LifetimeSuggestionPosition::ObjectDefault, span) => (span, "+ 'a".to_owned()),
12251227
};
12261228
let suggestions = vec![
1227-
(lifetime_ref.ident.span.shrink_to_hi(), lifetime_sugg),
1229+
lifetime_sugg,
12281230
new_param_sugg,
12291231
];
12301232

compiler/rustc_middle/src/ty/generics.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::ty::{EarlyBinder, SubstsRef};
33
use rustc_ast as ast;
44
use rustc_data_structures::fx::FxHashMap;
55
use rustc_hir::def_id::DefId;
6-
use rustc_span::symbol::Symbol;
6+
use rustc_span::symbol::{kw, Symbol};
77
use rustc_span::Span;
88

99
use super::{EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Predicate, TyCtxt};
@@ -78,6 +78,15 @@ impl GenericParamDef {
7878
}
7979
}
8080

81+
pub fn is_anonymous_lifetime(&self) -> bool {
82+
match self.kind {
83+
GenericParamDefKind::Lifetime => {
84+
self.name == kw::UnderscoreLifetime || self.name == kw::Empty
85+
}
86+
_ => false,
87+
}
88+
}
89+
8190
pub fn default_value<'tcx>(
8291
&self,
8392
tcx: TyCtxt<'tcx>,

compiler/rustc_middle/src/ty/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ impl ty::EarlyBoundRegion {
530530
/// Does this early bound region have a name? Early bound regions normally
531531
/// always have names except when using anonymous lifetimes (`'_`).
532532
pub fn has_name(&self) -> bool {
533-
self.name != kw::UnderscoreLifetime
533+
self.name != kw::UnderscoreLifetime && self.name != kw::Empty
534534
}
535535
}
536536

compiler/rustc_middle/src/ty/print/pretty.rs

+7-13
Original file line numberDiff line numberDiff line change
@@ -1963,17 +1963,13 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
19631963
let identify_regions = self.tcx.sess.opts.unstable_opts.identify_regions;
19641964

19651965
match *region {
1966-
ty::ReEarlyBound(ref data) => {
1967-
data.name != kw::Empty && data.name != kw::UnderscoreLifetime
1968-
}
1966+
ty::ReEarlyBound(ref data) => data.has_name(),
19691967

19701968
ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
19711969
| ty::ReFree(ty::FreeRegion { bound_region: br, .. })
19721970
| ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
1973-
if let ty::BrNamed(_, name) = br {
1974-
if name != kw::Empty && name != kw::UnderscoreLifetime {
1975-
return true;
1976-
}
1971+
if br.is_named() {
1972+
return true;
19771973
}
19781974

19791975
if let Some((region, _)) = highlight.highlight_bound_region {
@@ -2049,11 +2045,9 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
20492045
ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
20502046
| ty::ReFree(ty::FreeRegion { bound_region: br, .. })
20512047
| ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
2052-
if let ty::BrNamed(_, name) = br {
2053-
if name != kw::Empty && name != kw::UnderscoreLifetime {
2054-
p!(write("{}", name));
2055-
return Ok(self);
2056-
}
2048+
if let ty::BrNamed(_, name) = br && br.is_named() {
2049+
p!(write("{}", name));
2050+
return Ok(self);
20572051
}
20582052

20592053
if let Some((region, counter)) = highlight.highlight_bound_region {
@@ -2266,7 +2260,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
22662260

22672261
(name, ty::BrNamed(CRATE_DEF_ID.to_def_id(), name))
22682262
}
2269-
ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
2263+
ty::BrNamed(def_id, kw::UnderscoreLifetime | kw::Empty) => {
22702264
let name = next_name(&self);
22712265

22722266
if let Some(lt_idx) = lifetime_idx {

compiler/rustc_middle/src/ty/sty.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ pub struct BoundRegion {
8383
impl BoundRegionKind {
8484
pub fn is_named(&self) -> bool {
8585
match *self {
86-
BoundRegionKind::BrNamed(_, name) => name != kw::UnderscoreLifetime,
86+
BoundRegionKind::BrNamed(_, name) => {
87+
name != kw::UnderscoreLifetime && name != kw::Empty
88+
}
8789
_ => false,
8890
}
8991
}

src/librustdoc/clean/mod.rs

+12-16
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,7 @@ fn clean_poly_trait_ref_with_bindings<'tcx>(
182182
.collect_referenced_late_bound_regions(&poly_trait_ref)
183183
.into_iter()
184184
.filter_map(|br| match br {
185-
ty::BrNamed(_, name) if name != kw::UnderscoreLifetime => {
186-
Some(GenericParamDef::lifetime(name))
187-
}
185+
ty::BrNamed(_, name) if br.is_named() => Some(GenericParamDef::lifetime(name)),
188186
_ => None,
189187
})
190188
.collect();
@@ -233,16 +231,11 @@ pub(crate) fn clean_middle_const<'tcx>(
233231
pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option<Lifetime> {
234232
match *region {
235233
ty::ReStatic => Some(Lifetime::statik()),
234+
_ if !region.has_name() => None,
236235
ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => {
237-
if name != kw::UnderscoreLifetime { Some(Lifetime(name)) } else { None }
238-
}
239-
ty::ReEarlyBound(ref data) => {
240-
if data.name != kw::UnderscoreLifetime {
241-
Some(Lifetime(data.name))
242-
} else {
243-
None
244-
}
236+
Some(Lifetime(name))
245237
}
238+
ty::ReEarlyBound(ref data) => Some(Lifetime(data.name)),
246239
ty::ReLateBound(..)
247240
| ty::ReFree(..)
248241
| ty::ReVar(..)
@@ -396,7 +389,7 @@ fn clean_projection_predicate<'tcx>(
396389
.collect_referenced_late_bound_regions(&pred)
397390
.into_iter()
398391
.filter_map(|br| match br {
399-
ty::BrNamed(_, name) if name != kw::UnderscoreLifetime => Some(Lifetime(name)),
392+
ty::BrNamed(_, name) if br.is_named() => Some(Lifetime(name)),
400393
_ => None,
401394
})
402395
.collect();
@@ -660,7 +653,7 @@ fn clean_ty_generics<'tcx>(
660653
.params
661654
.iter()
662655
.filter_map(|param| match param.kind {
663-
ty::GenericParamDefKind::Lifetime if param.name == kw::UnderscoreLifetime => None,
656+
ty::GenericParamDefKind::Lifetime if param.is_anonymous_lifetime() => None,
664657
ty::GenericParamDefKind::Lifetime => Some(clean_generic_param_def(param, cx)),
665658
ty::GenericParamDefKind::Type { synthetic, .. } => {
666659
if param.name == kw::SelfUpper {
@@ -1460,8 +1453,11 @@ fn maybe_expand_private_type_alias<'tcx>(
14601453
});
14611454
if let Some(lt) = lifetime {
14621455
let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
1463-
let cleaned =
1464-
if !lt.is_elided() { clean_lifetime(lt, cx) } else { Lifetime::elided() };
1456+
let cleaned = if !lt.is_anonymous() {
1457+
clean_lifetime(lt, cx)
1458+
} else {
1459+
Lifetime::elided()
1460+
};
14651461
substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(cleaned));
14661462
}
14671463
indices.lifetimes += 1;
@@ -1892,7 +1888,7 @@ fn clean_generic_args<'tcx>(
18921888
.args
18931889
.iter()
18941890
.map(|arg| match arg {
1895-
hir::GenericArg::Lifetime(lt) if !lt.is_elided() => {
1891+
hir::GenericArg::Lifetime(lt) if !lt.is_anonymous() => {
18961892
GenericArg::Lifetime(clean_lifetime(*lt, cx))
18971893
}
18981894
hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),

src/test/ui/suggestions/impl-trait-missing-lifetime-gated.rs

+54-12
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,62 @@
22
// gate-test-anonymous_lifetime_in_impl_trait
33
// Verify the behaviour of `feature(anonymous_lifetime_in_impl_trait)`.
44

5-
fn f(_: impl Iterator<Item = &'_ ()>) {}
6-
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
5+
mod elided {
6+
fn f(_: impl Iterator<Item = &()>) {}
7+
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
78

8-
fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
9-
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
10-
//~| ERROR missing lifetime specifier
9+
fn g(mut x: impl Iterator<Item = &()>) -> Option<&()> { x.next() }
10+
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
11+
//~| ERROR missing lifetime specifier
1112

12-
// Anonymous lifetimes in async fn are already allowed.
13-
// This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`.
14-
async fn h(_: impl Iterator<Item = &'_ ()>) {}
13+
// Anonymous lifetimes in async fn are already allowed.
14+
// This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`.
15+
async fn h(_: impl Iterator<Item = &()>) {}
1516

16-
// Anonymous lifetimes in async fn are already allowed.
17-
// But that lifetime does not participate in resolution.
18-
async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
19-
//~^ ERROR missing lifetime specifier
17+
// Anonymous lifetimes in async fn are already allowed.
18+
// But that lifetime does not participate in resolution.
19+
async fn i(mut x: impl Iterator<Item = &()>) -> Option<&()> { x.next() }
20+
//~^ ERROR missing lifetime specifier
21+
}
22+
23+
mod underscore {
24+
fn f(_: impl Iterator<Item = &'_ ()>) {}
25+
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
26+
27+
fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
28+
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
29+
//~| ERROR missing lifetime specifier
30+
31+
// Anonymous lifetimes in async fn are already allowed.
32+
// This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`.
33+
async fn h(_: impl Iterator<Item = &'_ ()>) {}
34+
35+
// Anonymous lifetimes in async fn are already allowed.
36+
// But that lifetime does not participate in resolution.
37+
async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
38+
//~^ ERROR missing lifetime specifier
39+
}
40+
41+
mod alone_in_path {
42+
trait Foo<'a> { fn next(&mut self) -> Option<&'a ()>; }
43+
44+
fn f(_: impl Foo) {}
45+
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
46+
47+
fn g(mut x: impl Foo) -> Option<&()> { x.next() }
48+
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
49+
//~| ERROR missing lifetime specifier
50+
}
51+
52+
mod in_path {
53+
trait Foo<'a, T> { fn next(&mut self) -> Option<&'a T>; }
54+
55+
fn f(_: impl Foo<()>) {}
56+
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
57+
58+
fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() }
59+
//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
60+
//~| ERROR missing lifetime specifier
61+
}
2062

2163
fn main() {}

0 commit comments

Comments
 (0)