Skip to content

Commit 6651373

Browse files
authored
Rollup merge of rust-lang#63501 - nikomatsakis:issue-63500-async-anon-impl-lifetime, r=cramertj
use `ParamName` to track in-scope lifetimes instead of Ident Also, clear in-scope lifetimes when visiting nested items. Fixes rust-lang#63500. Fixes rust-lang#63225. Fixes rust-lang#52532. r? @cramertj
2 parents 8243535 + e4756e6 commit 6651373

File tree

5 files changed

+94
-9
lines changed

5 files changed

+94
-9
lines changed

src/librustc/hir/lowering.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,10 @@ pub struct LoweringContext<'a> {
136136
/// When `is_collectin_in_band_lifetimes` is true, each lifetime is checked
137137
/// against this list to see if it is already in-scope, or if a definition
138138
/// needs to be created for it.
139-
in_scope_lifetimes: Vec<Ident>,
139+
///
140+
/// We always store a `modern()` version of the param-name in this
141+
/// vector.
142+
in_scope_lifetimes: Vec<ParamName>,
140143

141144
current_module: NodeId,
142145

@@ -822,7 +825,7 @@ impl<'a> LoweringContext<'a> {
822825
return;
823826
}
824827

825-
if self.in_scope_lifetimes.contains(&ident.modern()) {
828+
if self.in_scope_lifetimes.contains(&ParamName::Plain(ident.modern())) {
826829
return;
827830
}
828831

@@ -856,7 +859,7 @@ impl<'a> LoweringContext<'a> {
856859
{
857860
let old_len = self.in_scope_lifetimes.len();
858861
let lt_def_names = params.iter().filter_map(|param| match param.kind {
859-
GenericParamKind::Lifetime { .. } => Some(param.ident.modern()),
862+
GenericParamKind::Lifetime { .. } => Some(ParamName::Plain(param.ident.modern())),
860863
_ => None,
861864
});
862865
self.in_scope_lifetimes.extend(lt_def_names);
@@ -2271,10 +2274,14 @@ impl<'a> LoweringContext<'a> {
22712274
let lifetime_params: Vec<(Span, ParamName)> =
22722275
this.in_scope_lifetimes
22732276
.iter().cloned()
2274-
.map(|ident| (ident.span, ParamName::Plain(ident)))
2277+
.map(|name| (name.ident().span, name))
22752278
.chain(this.lifetimes_to_define.iter().cloned())
22762279
.collect();
22772280

2281+
debug!("lower_async_fn_ret_ty: in_scope_lifetimes={:#?}", this.in_scope_lifetimes);
2282+
debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", this.lifetimes_to_define);
2283+
debug!("lower_async_fn_ret_ty: lifetime_params={:#?}", lifetime_params);
2284+
22782285
let generic_params =
22792286
lifetime_params
22802287
.iter().cloned()

src/librustc/hir/lowering/item.rs

+29-5
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,12 @@ impl<'tcx, 'interner> Visitor<'tcx> for ItemLowerer<'tcx, 'interner> {
6060
fn visit_item(&mut self, item: &'tcx Item) {
6161
let mut item_hir_id = None;
6262
self.lctx.with_hir_id_owner(item.id, |lctx| {
63-
if let Some(hir_item) = lctx.lower_item(item) {
64-
item_hir_id = Some(hir_item.hir_id);
65-
lctx.insert_item(hir_item);
66-
}
63+
lctx.without_in_scope_lifetime_defs(|lctx| {
64+
if let Some(hir_item) = lctx.lower_item(item) {
65+
item_hir_id = Some(hir_item.hir_id);
66+
lctx.insert_item(hir_item);
67+
}
68+
})
6769
});
6870

6971
if let Some(hir_id) = item_hir_id {
@@ -123,7 +125,7 @@ impl LoweringContext<'_> {
123125
_ => &[],
124126
};
125127
let lt_def_names = parent_generics.iter().filter_map(|param| match param.kind {
126-
hir::GenericParamKind::Lifetime { .. } => Some(param.name.ident().modern()),
128+
hir::GenericParamKind::Lifetime { .. } => Some(param.name.modern()),
127129
_ => None,
128130
});
129131
self.in_scope_lifetimes.extend(lt_def_names);
@@ -134,6 +136,28 @@ impl LoweringContext<'_> {
134136
res
135137
}
136138

139+
// Clears (and restores) the `in_scope_lifetimes` field. Used when
140+
// visiting nested items, which never inherit in-scope lifetimes
141+
// from their surrounding environment.
142+
fn without_in_scope_lifetime_defs<T>(
143+
&mut self,
144+
f: impl FnOnce(&mut LoweringContext<'_>) -> T,
145+
) -> T {
146+
let old_in_scope_lifetimes = std::mem::replace(&mut self.in_scope_lifetimes, vec![]);
147+
148+
// this vector is only used when walking over impl headers,
149+
// input types, and the like, and should not be non-empty in
150+
// between items
151+
assert!(self.lifetimes_to_define.is_empty());
152+
153+
let res = f(self);
154+
155+
assert!(self.in_scope_lifetimes.is_empty());
156+
self.in_scope_lifetimes = old_in_scope_lifetimes;
157+
158+
res
159+
}
160+
137161
pub(super) fn lower_mod(&mut self, m: &Mod) -> hir::Mod {
138162
hir::Mod {
139163
inner: m.inner,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Check that `async fn` inside of an impl with `'_`
2+
// in the header compiles correctly.
3+
//
4+
// Regression test for #63500.
5+
//
6+
// check-pass
7+
// edition:2018
8+
9+
#![feature(async_await)]
10+
11+
struct Foo<'a>(&'a u8);
12+
13+
impl Foo<'_> {
14+
async fn bar() {}
15+
}
16+
17+
fn main() { }
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Test that async fn works when nested inside of
2+
// impls with lifetime parameters.
3+
//
4+
// check-pass
5+
// edition:2018
6+
7+
#![feature(async_await)]
8+
9+
struct Foo<'a>(&'a ());
10+
11+
impl<'a> Foo<'a> {
12+
fn test() {
13+
async fn test() {}
14+
}
15+
}
16+
17+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Test that the `'a` from the impl doesn't
2+
// prevent us from creating a `'a` parameter
3+
// on the `blah` function.
4+
//
5+
// check-pass
6+
7+
#![feature(in_band_lifetimes)]
8+
9+
struct Foo<'a> {
10+
x: &'a u32
11+
12+
}
13+
14+
impl Foo<'a> {
15+
fn method(&self) {
16+
fn blah(f: Foo<'a>) { }
17+
}
18+
}
19+
20+
fn main() { }

0 commit comments

Comments
 (0)