Auto merge of #54000 - jkozlowski:fix-53174, r=cramertj

Allow named lifetimes in async functions.

- Fixes #53174

Code by @eddyb; @cramertj suggested I lift it off another change so we can fix #53174.

r? @cramertj
This commit is contained in:
bors 2018-09-10 12:58:04 +00:00
commit 3c3e372e18
2 changed files with 89 additions and 21 deletions

View file

@ -76,23 +76,38 @@ impl<'a> DefCollector<'a> {
fn visit_async_fn( fn visit_async_fn(
&mut self, &mut self,
id: NodeId, id: NodeId,
async_node_id: NodeId,
return_impl_trait_id: NodeId,
name: Name, name: Name,
span: Span, span: Span,
visit_fn: impl FnOnce(&mut DefCollector<'a>) header: &FnHeader,
generics: &'a Generics,
decl: &'a FnDecl,
body: &'a Block,
) { ) {
let (closure_id, return_impl_trait_id) = match header.asyncness {
IsAsync::Async {
closure_id,
return_impl_trait_id,
} => (closure_id, return_impl_trait_id),
_ => unreachable!(),
};
// For async functions, we need to create their inner defs inside of a // For async functions, we need to create their inner defs inside of a
// closure to match their desugared representation. // closure to match their desugared representation.
let fn_def_data = DefPathData::ValueNs(name.as_interned_str()); let fn_def_data = DefPathData::ValueNs(name.as_interned_str());
let fn_def = self.create_def(id, fn_def_data, ITEM_LIKE_SPACE, span); let fn_def = self.create_def(id, fn_def_data, ITEM_LIKE_SPACE, span);
return self.with_parent(fn_def, |this| { return self.with_parent(fn_def, |this| {
this.create_def(return_impl_trait_id, DefPathData::ImplTrait, REGULAR_SPACE, span); this.create_def(return_impl_trait_id, DefPathData::ImplTrait, REGULAR_SPACE, span);
let closure_def = this.create_def(async_node_id,
visit::walk_generics(this, generics);
visit::walk_fn_decl(this, decl);
let closure_def = this.create_def(closure_id,
DefPathData::ClosureExpr, DefPathData::ClosureExpr,
REGULAR_SPACE, REGULAR_SPACE,
span); span);
this.with_parent(closure_def, visit_fn) this.with_parent(closure_def, |this| {
visit::walk_block(this, body);
})
}) })
} }
@ -122,17 +137,20 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => { ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
return visit::walk_item(self, i); return visit::walk_item(self, i);
} }
ItemKind::Fn(_, FnHeader { asyncness: IsAsync::Async { ItemKind::Fn(
closure_id, ref decl,
return_impl_trait_id, ref header @ FnHeader { asyncness: IsAsync::Async { .. }, .. },
}, .. }, ..) => { ref generics,
ref body,
) => {
return self.visit_async_fn( return self.visit_async_fn(
i.id, i.id,
closure_id,
return_impl_trait_id,
i.ident.name, i.ident.name,
i.span, i.span,
|this| visit::walk_item(this, i) header,
generics,
decl,
body,
) )
} }
ItemKind::Mod(..) => DefPathData::Module(i.ident.as_interned_str()), ItemKind::Mod(..) => DefPathData::Module(i.ident.as_interned_str()),
@ -233,18 +251,17 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
fn visit_impl_item(&mut self, ii: &'a ImplItem) { fn visit_impl_item(&mut self, ii: &'a ImplItem) {
let def_data = match ii.node { let def_data = match ii.node {
ImplItemKind::Method(MethodSig { ImplItemKind::Method(MethodSig {
header: FnHeader { asyncness: IsAsync::Async { header: ref header @ FnHeader { asyncness: IsAsync::Async { .. }, .. },
closure_id, ref decl,
return_impl_trait_id, }, ref body) => {
}, .. }, ..
}, ..) => {
return self.visit_async_fn( return self.visit_async_fn(
ii.id, ii.id,
closure_id,
return_impl_trait_id,
ii.ident.name, ii.ident.name,
ii.span, ii.span,
|this| visit::walk_impl_item(this, ii) header,
&ii.generics,
decl,
body,
) )
} }
ImplItemKind::Method(..) | ImplItemKind::Const(..) => ImplItemKind::Method(..) | ImplItemKind::Const(..) =>

View file

@ -67,6 +67,13 @@ fn async_block(x: u8) -> impl Future<Output = u8> {
} }
} }
fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
async move {
await!(wake_and_yield_once());
*x
}
}
fn async_nonmove_block(x: u8) -> impl Future<Output = u8> { fn async_nonmove_block(x: u8) -> impl Future<Output = u8> {
async move { async move {
let future = async { let future = async {
@ -94,6 +101,23 @@ async fn async_fn_with_borrow(x: &u8) -> u8 {
*x *x
} }
async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 {
await!(wake_and_yield_once());
*x
}
fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
async move {
await!(wake_and_yield_once());
*x
}
}
async fn async_fn_with_named_lifetime_multiple_args<'a>(x: &'a u8, _y: &'a u8) -> u8 {
await!(wake_and_yield_once());
*x
}
fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> { fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
async move { async move {
await!(async_fn_with_borrow(&y)) await!(async_fn_with_borrow(&y))
@ -138,16 +162,43 @@ where
fn main() { fn main() {
macro_rules! test { macro_rules! test {
($($fn_name:ident,)*) => { $( ($($fn_name:expr,)*) => { $(
test_future_yields_once_then_returns($fn_name); test_future_yields_once_then_returns($fn_name);
)* } )* }
} }
macro_rules! test_with_borrow {
($($fn_name:expr,)*) => { $(
test_future_yields_once_then_returns(|x| {
async move {
await!($fn_name(&x))
}
});
)* }
}
test! { test! {
async_block, async_block,
async_nonmove_block, async_nonmove_block,
async_closure, async_closure,
async_fn, async_fn,
async_fn_with_internal_borrow, async_fn_with_internal_borrow,
|x| {
async move {
unsafe { await!(unsafe_async_fn(x)) }
}
},
}
test_with_borrow! {
async_block_with_borrow_named_lifetime,
async_fn_with_borrow,
async_fn_with_borrow_named_lifetime,
async_fn_with_impl_future_named_lifetime,
|x| {
async move {
await!(async_fn_with_named_lifetime_multiple_args(x, x))
}
},
} }
} }