Skip to content

Commit f4d3048

Browse files
committed
Migrate to await syntax
1 parent 5ebe086 commit f4d3048

File tree

5 files changed

+82
-84
lines changed

5 files changed

+82
-84
lines changed

futures-async-macro/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Processes streams using a for loop.
1717
This is a reimplement of [futures-await]'s `#[async]` for loops for futures 0.3 and is an experimental implementation of [the idea listed as the next step of async/await](https://github.com/rust-lang/rfcs/blob/master/text/2394-async_await.md#for-await-and-processing-streams).
1818

1919
```rust
20-
#![feature(async_await, generators, stmt_expr_attributes, proc_macro_hygiene)]
20+
#![feature(async_await, stmt_expr_attributes, proc_macro_hygiene)]
2121
use futures::for_await;
2222
use futures::prelude::*;
2323

futures-async-macro/src/lib.rs

+67-46
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
#![recursion_limit = "128"]
44
#![warn(rust_2018_idioms)]
5+
#![warn(clippy::all)]
56

67
extern crate proc_macro;
78

@@ -10,8 +11,8 @@ use proc_macro2::{Span, TokenStream as TokenStream2, TokenTree as TokenTree2};
1011
use quote::{quote, ToTokens};
1112
use syn::{
1213
fold::{self, Fold},
13-
token, ArgCaptured, Error, Expr, ExprCall, ExprForLoop, ExprMacro, ExprYield, FnArg, FnDecl,
14-
Ident, Item, ItemFn, Pat, PatIdent, ReturnType, TypeTuple,
14+
token, ArgCaptured, Error, Expr, ExprCall, ExprField, ExprForLoop, ExprMacro, ExprYield, FnArg,
15+
FnDecl, Ident, Item, ItemFn, Member, Pat, PatIdent, ReturnType, TypeTuple,
1516
};
1617

1718
#[macro_use]
@@ -210,7 +211,7 @@ pub fn async_stream_block(input: TokenStream) -> TokenStream {
210211
tokens.into()
211212
}
212213

213-
/// The scope in which `#[for_await]`, `await!` was called.
214+
/// The scope in which `#[for_await]`, `.await` was called.
214215
///
215216
/// The type of generator depends on which scope is called.
216217
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -221,7 +222,7 @@ enum Scope {
221222
Stream,
222223
/// `static move ||`, `||`
223224
///
224-
/// It cannot call `#[for_await]`, `await!` in this scope.
225+
/// It cannot call `#[for_await]`, `.await` in this scope.
225226
Closure,
226227
}
227228

@@ -241,49 +242,66 @@ impl Expand {
241242
));
242243
}
243244

245+
let ExprForLoop { label, pat, expr, body, .. } = &expr;
244246
// It needs to adjust the type yielded by the macro because generators used internally by
245247
// async fn yield `()` type, but generators used internally by `async_stream` yield
246248
// `Poll<U>` type.
247-
let yield_ = match self.0 {
248-
Future => TokenStream2::new(),
249-
Stream => quote! { ::futures::core_reexport::task::Poll::Pending },
250-
Closure => return outside_of_async_error!(expr, "#[for_await]"),
251-
};
252-
let ExprForLoop { label, pat, expr, body, .. } = expr;
253-
254-
// Basically just expand to a `poll` loop
255-
syn::parse_quote! {{
256-
let mut __pinned = #expr;
257-
#label
258-
loop {
259-
let #pat = {
260-
match ::futures::async_stream::poll_next_with_tls_context(unsafe {
261-
::futures::core_reexport::pin::Pin::new_unchecked(&mut __pinned)
262-
})
263-
{
264-
::futures::core_reexport::task::Poll::Ready(e) => {
265-
match e {
249+
match self.0 {
250+
Future => {
251+
// Basically just expand to a `poll` loop
252+
syn::parse_quote! {{
253+
let mut __pinned = #expr;
254+
let mut __pinned = unsafe {
255+
::futures::core_reexport::pin::Pin::new_unchecked(&mut __pinned)
256+
};
257+
#label
258+
loop {
259+
let #pat = {
260+
match ::futures::stream::StreamExt::next(&mut __pinned).await {
266261
::futures::core_reexport::option::Option::Some(e) => e,
267262
::futures::core_reexport::option::Option::None => break,
268263
}
269-
}
270-
::futures::core_reexport::task::Poll::Pending => {
271-
yield #yield_;
272-
continue
273-
}
264+
};
265+
266+
#body
274267
}
275-
};
268+
}}
269+
}
270+
Stream => {
271+
// Basically just expand to a `poll` loop
272+
syn::parse_quote! {{
273+
let mut __pinned = #expr;
274+
#label
275+
loop {
276+
let #pat = {
277+
match ::futures::async_stream::poll_next_with_tls_context(unsafe {
278+
::futures::core_reexport::pin::Pin::new_unchecked(&mut __pinned)
279+
})
280+
{
281+
::futures::core_reexport::task::Poll::Ready(e) => {
282+
match e {
283+
::futures::core_reexport::option::Option::Some(e) => e,
284+
::futures::core_reexport::option::Option::None => break,
285+
}
286+
}
287+
::futures::core_reexport::task::Poll::Pending => {
288+
yield ::futures::core_reexport::task::Poll::Pending;
289+
continue
290+
}
291+
}
292+
};
276293

277-
#body
294+
#body
295+
}
296+
}}
278297
}
279-
}}
298+
Closure => return outside_of_async_error!(expr, "#[for_await]"),
299+
}
280300
}
281301

282302
/// Expands `yield expr` in `async_stream` scope.
283303
fn expand_yield(&self, expr: ExprYield) -> ExprYield {
284-
if self.0 != Stream {
285-
return expr;
286-
}
304+
if self.0 != Stream { return expr }
287305

288306
let ExprYield { attrs, yield_token, expr } = expr;
289307
let expr = expr.map_or_else(|| quote!(()), ToTokens::into_token_stream);
@@ -293,28 +311,30 @@ impl Expand {
293311
ExprYield { attrs, yield_token, expr: Some(Box::new(expr)) }
294312
}
295313

296-
/// Expands a macro.
314+
/// Expands `async_stream_block!` macro.
297315
fn expand_macro(&mut self, mut expr: ExprMacro) -> Expr {
298-
if self.0 == Stream && expr.mac.path.is_ident("await") {
299-
return self.expand_await_macros(expr);
300-
} else if expr.mac.path.is_ident("async_stream_block") {
316+
if expr.mac.path.is_ident("async_stream_block") {
301317
let mut e: ExprCall = syn::parse(async_stream_block(expr.mac.tts.into())).unwrap();
302318
e.attrs.append(&mut expr.attrs);
303-
return Expr::Call(e);
319+
Expr::Call(e)
320+
} else {
321+
Expr::Macro(expr)
304322
}
305-
306-
Expr::Macro(expr)
307323
}
308324

309-
/// Expands `await!(expr)` in `async_stream` scope.
325+
/// Expands `expr.await` in `async_stream` scope.
310326
///
311327
/// It needs to adjust the type yielded by the macro because generators used internally by
312328
/// async fn yield `()` type, but generators used internally by `async_stream` yield
313329
/// `Poll<U>` type.
314-
fn expand_await_macros(&mut self, expr: ExprMacro) -> Expr {
315-
assert_eq!(self.0, Stream);
330+
fn expand_await(&mut self, expr: ExprField) -> Expr {
331+
if self.0 != Stream { return Expr::Field(expr) }
316332

317-
let expr = expr.mac.tts;
333+
match &expr.member {
334+
Member::Named(x) if x == "await" => {}
335+
_ => return Expr::Field(expr),
336+
}
337+
let expr = expr.base;
318338

319339
// Because macro input (`#expr`) is untrusted, use `syn::parse2` + `expr_compile_error`
320340
// instead of `syn::parse_quote!` to generate better error messages (`syn::parse_quote!`
@@ -349,8 +369,9 @@ impl Fold for Expand {
349369
}
350370

351371
let expr = match fold::fold_expr(self, expr) {
352-
Expr::ForLoop(expr) => self.expand_for_await(expr),
353372
Expr::Yield(expr) => Expr::Yield(self.expand_yield(expr)),
373+
Expr::Field(expr) => self.expand_await(expr),
374+
Expr::ForLoop(expr) => self.expand_for_await(expr),
354375
Expr::Macro(expr) => self.expand_macro(expr),
355376
expr => expr,
356377
};

futures/testcrate/ui/nested.stderr

+11-34
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,14 @@
1-
error[E0308]: mismatched types
2-
--> $DIR/nested.rs:10:19
1+
error[E0727]: `async` generators are not yet supported
2+
--> $DIR/nested.rs:7:19
33
|
4-
10 | yield i * i;
5-
| ^^^^^ expected (), found integer
6-
|
7-
= note: expected type `()`
8-
found type `{integer}`
9-
10-
error[E0698]: type inside generator must be known in this context
11-
--> $DIR/nested.rs:10:13
12-
|
13-
10 | yield i * i;
14-
| ^^^^^^^^^^^ cannot infer type for `{integer}`
15-
|
16-
note: the type is part of the generator because of this `yield`
17-
--> $DIR/nested.rs:10:13
18-
|
19-
10 | yield i * i;
20-
| ^^^^^^^^^^^
21-
22-
error[E0698]: type inside generator must be known in this context
23-
--> $DIR/nested.rs:5:1
24-
|
25-
5 | #[async_stream]
26-
| ^^^^^^^^^^^^^^^ cannot infer type for `{integer}`
27-
|
28-
note: the type is part of the generator because of this `yield`
29-
--> $DIR/nested.rs:5:1
30-
|
31-
5 | #[async_stream]
32-
| ^^^^^^^^^^^^^^^
4+
7 | let _ = async {
5+
| ___________________^
6+
8 | | #[for_await]
7+
9 | | for i in stream::iter(vec![1, 2]) {
8+
10 | | yield i * i;
9+
11 | | }
10+
12 | | };
11+
| |_____^
3312

34-
error: aborting due to 3 previous errors
13+
error: aborting due to previous error
3514

36-
Some errors have detailed explanations: E0308, E0698.
37-
For more information about an error, try `rustc --explain E0308`.

futures/tests/async_stream/nested.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ fn _stream1() -> i32 {
66
let _ = async { // impl Generator<Yield = (), Return = U>
77
#[for_await]
88
for i in stream::iter(vec![1, 2]) {
9-
await!(future::lazy(|_| i * i));
9+
future::lazy(|_| i * i).await;
1010
}
1111
};
12-
await!(future::lazy(|_| ()));
12+
future::lazy(|_| ()).await;
1313
}

futures/tests/async_stream_tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![feature(async_await, await_macro)]
1+
#![feature(async_await)]
22
#![cfg_attr(all(feature = "async-stream", feature = "nightly"), feature(generators, stmt_expr_attributes, proc_macro_hygiene))]
33

44
#[cfg(all(feature = "async-stream", feature = "nightly"))]

0 commit comments

Comments
 (0)