diff --git a/ci/azure-test.yml b/ci/azure-test.yml index f912656..7476ab9 100644 --- a/ci/azure-test.yml +++ b/ci/azure-test.yml @@ -33,6 +33,5 @@ jobs: - script: | cargo update -Zminimal-versions - cat Cargo.lock cargo check --all --all-features displayName: cargo check -Zminimal-versions diff --git a/futures-async-stream-macro/Cargo.toml b/futures-async-stream-macro/Cargo.toml index a71122a..67cddd7 100644 --- a/futures-async-stream-macro/Cargo.toml +++ b/futures-async-stream-macro/Cargo.toml @@ -18,6 +18,6 @@ proc-macro = true [features] [dependencies] -proc-macro2 = "0.4.13" -quote = "0.6.8" -syn = { version = "0.15.41", features = ["full", "visit-mut"] } +proc-macro2 = "1.0" +quote = "1.0" +syn = { version = "1.0", features = ["full", "visit-mut"] } diff --git a/futures-async-stream-macro/src/elision.rs b/futures-async-stream-macro/src/elision.rs index 195628a..a7f01d7 100644 --- a/futures-async-stream-macro/src/elision.rs +++ b/futures-async-stream-macro/src/elision.rs @@ -3,7 +3,7 @@ use syn::{ punctuated::Punctuated, token::Comma, visit_mut::{self, VisitMut}, - ArgSelfRef, FnArg, GenericArgument, GenericParam, Lifetime, LifetimeDef, TypeReference, + FnArg, GenericArgument, GenericParam, Lifetime, LifetimeDef, Receiver, TypeReference, }; pub(super) fn unelide_lifetimes( @@ -54,8 +54,10 @@ impl<'a> UnelideLifetimes<'a> { } impl VisitMut for UnelideLifetimes<'_> { - fn visit_arg_self_ref_mut(&mut self, arg: &mut ArgSelfRef) { - self.visit_opt_lifetime(&mut arg.lifetime); + fn visit_receiver_mut(&mut self, receiver: &mut Receiver) { + if let Some((_, lifetime)) = &mut receiver.reference { + self.visit_opt_lifetime(lifetime); + } } fn visit_type_reference_mut(&mut self, ty: &mut TypeReference) { diff --git a/futures-async-stream-macro/src/lib.rs b/futures-async-stream-macro/src/lib.rs index e19199e..226ba75 100644 --- a/futures-async-stream-macro/src/lib.rs +++ b/futures-async-stream-macro/src/lib.rs @@ -10,7 +10,7 @@ extern crate proc_macro; use proc_macro::{Delimiter, Group, TokenStream, TokenTree}; use quote::ToTokens; -use syn::{Expr, ExprForLoop}; +use syn::{parse::Nothing, Expr, ExprForLoop}; #[macro_use] mod utils; @@ -19,8 +19,6 @@ mod elision; mod stream; mod visitor; -use crate::utils::Nothing; - /// Processes streams using a for loop. #[proc_macro_attribute] pub fn for_await(args: TokenStream, input: TokenStream) -> TokenStream { diff --git a/futures-async-stream-macro/src/stream.rs b/futures-async-stream-macro/src/stream.rs index 75d3082..56ebb05 100644 --- a/futures-async-stream-macro/src/stream.rs +++ b/futures-async-stream-macro/src/stream.rs @@ -1,11 +1,11 @@ -use proc_macro2::{Span, TokenStream}; -use quote::{quote, ToTokens}; +use proc_macro2::TokenStream; +use quote::{format_ident, quote, ToTokens}; use syn::{ parse::{Parse, ParseStream}, token, visit_mut::VisitMut, - ArgCaptured, Attribute, Block, Expr, FnArg, FnDecl, Ident, ItemFn, MethodSig, Pat, PatIdent, - Result, ReturnType, Token, TraitItemMethod, Type, TypeTuple, Visibility, + Attribute, Block, Expr, FnArg, ItemFn, Pat, PatIdent, PatType, Result, ReturnType, Signature, + Token, TraitItemMethod, Type, TypeTuple, Visibility, }; use crate::{ @@ -107,27 +107,14 @@ impl Parse for Args { struct FnSig { attrs: Vec, vis: Visibility, - sig: MethodSig, + sig: Signature, block: Block, semi: Option, } impl From for FnSig { fn from(item: ItemFn) -> Self { - Self { - attrs: item.attrs, - vis: item.vis, - sig: MethodSig { - constness: item.constness, - asyncness: item.asyncness, - unsafety: item.unsafety, - abi: item.abi, - ident: item.ident, - decl: *item.decl, - }, - block: *item.block, - semi: None, - } + Self { attrs: item.attrs, vis: item.vis, sig: item.sig, block: *item.block, semi: None } } } @@ -164,15 +151,15 @@ fn parse_async_stream_fn(args: TokenStream, input: TokenStream) -> Result {} _ => return Err(error!(ty, "async stream must return the unit type")), @@ -184,8 +171,7 @@ fn parse_async_stream_fn(args: TokenStream, input: TokenStream) -> Result TokenStream { let FnSig { attrs, vis, sig, mut block, semi } = item; - let MethodSig { unsafety, abi, ident, decl, .. } = sig; - let FnDecl { inputs, mut generics, fn_token, .. } = decl; + let Signature { unsafety, abi, fn_token, ident, mut generics, inputs, .. } = sig; let where_clause = &generics.where_clause; // Desugar `async fn` @@ -212,29 +198,33 @@ fn expand_async_stream_fn(item: FnSig, args: &Args) -> TokenStream { let mut patterns = Vec::new(); let mut temp_bindings = Vec::new(); for (i, input) in inputs.into_iter().enumerate() { - match input { - FnArg::Captured(ArgCaptured { pat: Pat::Ident(ref pat), .. }) - if pat.ident == "self" => - { + if let FnArg::Typed(PatType { attrs, pat, ty, colon_token }) = input { + let captured_naturally = match &*pat { // `self: Box` will get captured naturally - inputs_no_patterns.push(input); - } - FnArg::Captured(ArgCaptured { - pat: pat @ Pat::Ident(PatIdent { by_ref: Some(_), .. }), - ty, - colon_token, - }) => { + Pat::Ident(pat) if pat.ident == "self" => true, + Pat::Ident(PatIdent { by_ref: Some(_), .. }) => false, + // Other arguments get captured naturally + _ => true, + }; + if captured_naturally { + inputs_no_patterns.push(FnArg::Typed(PatType { attrs, pat, ty, colon_token })); + continue; + } else { // `ref a: B` (or some similar pattern) patterns.push(pat); - let ident = Ident::new(&format!("__arg_{}", i), Span::call_site()); + let ident = format_ident!("__arg_{}", i); temp_bindings.push(ident.clone()); - let pat = PatIdent { by_ref: None, mutability: None, ident, subpat: None }.into(); - inputs_no_patterns.push(ArgCaptured { pat, ty, colon_token }.into()); - } - _ => { - // Other arguments get captured naturally - inputs_no_patterns.push(input); + let pat = Box::new(Pat::Ident(PatIdent { + attrs: Vec::new(), + by_ref: None, + mutability: None, + ident, + subpat: None, + })); + inputs_no_patterns.push(PatType { attrs, pat, ty, colon_token }.into()); } + } else { + inputs_no_patterns.push(input); } } diff --git a/futures-async-stream-macro/src/utils.rs b/futures-async-stream-macro/src/utils.rs index d82c441..527edc0 100644 --- a/futures-async-stream-macro/src/utils.rs +++ b/futures-async-stream-macro/src/utils.rs @@ -2,11 +2,7 @@ use std::mem; use proc_macro2::{Span, TokenStream, TokenTree}; use quote::ToTokens; -use syn::{ - parse::{Parse, ParseStream}, - punctuated::Punctuated, - token, Expr, ExprTuple, ExprVerbatim, Result, -}; +use syn::{punctuated::Punctuated, token, Expr, ExprTuple}; pub(crate) fn first_last(tokens: &T) -> (Span, Span) where @@ -47,7 +43,7 @@ pub(crate) fn replace_expr(this: &mut Expr, f: F) where F: FnOnce(Expr) -> Expr, { - *this = f(mem::replace(this, Expr::Verbatim(ExprVerbatim { tts: TokenStream::new() }))); + *this = f(mem::replace(this, Expr::Verbatim(TokenStream::new()))); } pub(super) fn replace_boxed_expr(expr: &mut Option>, f: F) @@ -63,16 +59,6 @@ where } } -// See https://github.com/dtolnay/syn/commit/82a3aed7ecfd07fc2f7f322b01d2413ffea6c5e7 -/// An empty syntax tree node that consumes no tokens when parsed. -pub(crate) struct Nothing; - -impl Parse for Nothing { - fn parse(_input: ParseStream<'_>) -> Result { - Ok(Nothing) - } -} - macro_rules! error { ($span:expr, $msg:expr) => { syn::Error::new_spanned($span, $msg) diff --git a/futures-async-stream-macro/src/visitor.rs b/futures-async-stream-macro/src/visitor.rs index d569a7c..c78fdbc 100644 --- a/futures-async-stream-macro/src/visitor.rs +++ b/futures-async-stream-macro/src/visitor.rs @@ -1,13 +1,14 @@ use quote::{quote, quote_spanned}; use syn::{ + parse::Nothing, spanned::Spanned, visit_mut::{self, VisitMut}, - Expr, ExprCall, ExprField, ExprForLoop, ExprYield, Item, Member, + Expr, ExprAwait, ExprCall, ExprForLoop, ExprYield, Item, }; use crate::{ async_stream_block, - utils::{expr_compile_error, replace_boxed_expr, replace_expr, Nothing}, + utils::{expr_compile_error, replace_boxed_expr, replace_expr}, }; pub(crate) use Scope::{Closure, Future, Stream}; @@ -56,7 +57,7 @@ impl Visitor { return; } let attr = attrs.pop().unwrap(); - if let Err(e) = syn::parse2::(attr.tts) { + if let Err(e) = syn::parse2::(attr.tokens) { *expr = expr_compile_error(&e); return; } @@ -93,7 +94,7 @@ impl Visitor { } Closure => { *expr = expr_compile_error(&error!( - expr.clone(), + &expr, "for await may not be allowed outside of \ async blocks, functions, closures, async stream blocks, and functions", )); @@ -130,12 +131,12 @@ impl Visitor { } /// Visits `async_stream_block!` macro. - fn visit_macro(&mut self, expr: &mut Expr) { + fn visit_macro(&self, expr: &mut Expr) { replace_expr(expr, |expr| { if let Expr::Macro(mut expr) = expr { if expr.mac.path.is_ident("async_stream_block") { let mut e: ExprCall = - syn::parse(async_stream_block(expr.mac.tts.into())).unwrap(); + syn::parse(async_stream_block(expr.mac.tokens.into())).unwrap(); e.attrs.append(&mut expr.attrs); Expr::Call(e) } else { @@ -152,18 +153,13 @@ impl Visitor { /// It needs to adjust the type yielded by the macro because generators used internally by /// async fn yield `()` type, but generators used internally by `async_stream` yield /// `Poll` type. - fn visit_await(&mut self, expr: &mut Expr) { + fn visit_await(&self, expr: &mut Expr) { if self.scope != Stream { return; } - if let Expr::Field(ExprField { base, member, .. }) = expr { - match &member { - Member::Named(x) if x == "await" => {} - _ => return, - } - - *expr = syn::parse2(quote_spanned! { member.span() => { + if let Expr::Await(ExprAwait { base, await_token, .. }) = expr { + *expr = syn::parse2(quote_spanned! { await_token.span() => { let mut __pinned = #base; loop { if let ::futures_async_stream::core_reexport::task::Poll::Ready(x) = @@ -200,7 +196,7 @@ impl VisitMut for Visitor { visit_mut::visit_expr_mut(self, expr); match expr { Expr::Yield(expr) => self.visit_yield(expr), - Expr::Field(_) => self.visit_await(expr), + Expr::Await(_) => self.visit_await(expr), Expr::ForLoop(_) => self.visit_for_loop(expr), Expr::Macro(_) => self.visit_macro(expr), _ => {} @@ -210,6 +206,7 @@ impl VisitMut for Visitor { self.scope = tmp; } - // Stop at item bounds - fn visit_item_mut(&mut self, _: &mut Item) {} + fn visit_item_mut(&mut self, _: &mut Item) { + // Do not recurse into nested items. + } } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 4cb75a1..3523939 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -13,7 +13,6 @@ fn run_mode(mode: &'static str) { -Z unstable-options \ --extern futures_async_stream \ --extern futures \ - --cfg procmacro2_semver_exempt \ -L {}", me.display() )); diff --git a/tests/ui/invalid-arguments.stderr b/tests/ui/invalid-arguments.stderr index 226ec67..8003e32 100644 --- a/tests/ui/invalid-arguments.stderr +++ b/tests/ui/invalid-arguments.stderr @@ -2,7 +2,7 @@ error: unexpected token --> $DIR/invalid-arguments.rs:11:16 | 11 | #[for_await(bar)] //~ ERROR unexpected token - | ^^^^^ + | ^ error: expected `item` --> $DIR/invalid-arguments.rs:17:16 diff --git a/tests/ui/invalid-function.rs b/tests/ui/invalid-function.rs index 85fb271..70953e1 100644 --- a/tests/ui/invalid-function.rs +++ b/tests/ui/invalid-function.rs @@ -9,7 +9,7 @@ use futures_async_stream::async_stream; const fn constness() {} //~ ERROR async stream may not be const #[async_stream(item = ())] -fn variadic(...) {} //~ ERROR async stream may not be variadic +fn variadic(_: ...) {} //~ ERROR async stream may not be variadic #[async_stream(item = ())] fn asyncness() {} //~ ERROR async stream must be declared as async diff --git a/tests/ui/invalid-function.stderr b/tests/ui/invalid-function.stderr index 178fd91..066355b 100644 --- a/tests/ui/invalid-function.stderr +++ b/tests/ui/invalid-function.stderr @@ -1,8 +1,8 @@ error: only foreign functions are allowed to be C-variadic - --> $DIR/invalid-function.rs:12:13 + --> $DIR/invalid-function.rs:12:16 | -12 | fn variadic(...) {} //~ ERROR async stream may not be variadic - | ^^^ +12 | fn variadic(_: ...) {} //~ ERROR async stream may not be variadic + | ^^^ error: async stream may not be const --> $DIR/invalid-function.rs:9:1 @@ -10,7 +10,11 @@ error: async stream may not be const 9 | const fn constness() {} //~ ERROR async stream may not be const | ^^^^^ -error: async stream must be declared as async +error: expected `:` + --> $DIR/invalid-function.rs:11:1 + | +11 | #[async_stream(item = ())] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: async stream must be declared as async --> $DIR/invalid-function.rs:15:1