fn visit_async_fn(
&mut self,
id: NodeId,
- async_node_id: NodeId,
- return_impl_trait_id: NodeId,
name: Name,
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
// closure to match their desugared representation.
let fn_def_data = DefPathData::ValueNs(name.as_interned_str());
let fn_def = self.create_def(id, fn_def_data, ITEM_LIKE_SPACE, span);
return self.with_parent(fn_def, |this| {
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,
REGULAR_SPACE,
span);
- this.with_parent(closure_def, visit_fn)
+ this.with_parent(closure_def, |this| {
+ visit::walk_block(this, body);
+ })
})
}
ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
return visit::walk_item(self, i);
}
- ItemKind::Fn(_, FnHeader { asyncness: IsAsync::Async {
- closure_id,
- return_impl_trait_id,
- }, .. }, ..) => {
+ ItemKind::Fn(
+ ref decl,
+ ref header @ FnHeader { asyncness: IsAsync::Async { .. }, .. },
+ ref generics,
+ ref body,
+ ) => {
return self.visit_async_fn(
i.id,
- closure_id,
- return_impl_trait_id,
i.ident.name,
i.span,
- |this| visit::walk_item(this, i)
+ header,
+ generics,
+ decl,
+ body,
)
}
ItemKind::Mod(..) => DefPathData::Module(i.ident.as_interned_str()),
fn visit_impl_item(&mut self, ii: &'a ImplItem) {
let def_data = match ii.node {
ImplItemKind::Method(MethodSig {
- header: FnHeader { asyncness: IsAsync::Async {
- closure_id,
- return_impl_trait_id,
- }, .. }, ..
- }, ..) => {
+ header: ref header @ FnHeader { asyncness: IsAsync::Async { .. }, .. },
+ ref decl,
+ }, ref body) => {
return self.visit_async_fn(
ii.id,
- closure_id,
- return_impl_trait_id,
ii.ident.name,
ii.span,
- |this| visit::walk_impl_item(this, ii)
+ header,
+ &ii.generics,
+ decl,
+ body,
)
}
ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
}
}
}
-}
+}
\ No newline at end of file
}
}
+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> {
async move {
let future = async {
*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> {
async move {
await!(async_fn_with_borrow(&y))
fn main() {
macro_rules! test {
- ($($fn_name:ident,)*) => { $(
+ ($($fn_name:expr,)*) => { $(
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! {
async_block,
async_nonmove_block,
async_closure,
async_fn,
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))
+ }
+ },
}
}