* executor-macros: don't parse function bodies. * executor-macros: refactor for better recovery and ide-friendliness on errors. * executor-macros: disallow `impl Trait` in task arguments. Fixes #3420 * Fix example using `impl Trait` in tasks.
		
			
				
	
	
		
			75 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			75 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
use std::fmt::Display;
 | 
						|
 | 
						|
use proc_macro2::{TokenStream, TokenTree};
 | 
						|
use quote::{ToTokens, TokenStreamExt};
 | 
						|
use syn::parse::{Parse, ParseStream};
 | 
						|
use syn::{braced, bracketed, token, AttrStyle, Attribute, Signature, Token, Visibility};
 | 
						|
 | 
						|
pub fn token_stream_with_error(mut tokens: TokenStream, error: syn::Error) -> TokenStream {
 | 
						|
    tokens.extend(error.into_compile_error());
 | 
						|
    tokens
 | 
						|
}
 | 
						|
 | 
						|
pub fn error<A: ToTokens, T: Display>(s: &mut TokenStream, obj: A, msg: T) {
 | 
						|
    s.extend(syn::Error::new_spanned(obj.into_token_stream(), msg).into_compile_error())
 | 
						|
}
 | 
						|
 | 
						|
/// Function signature and body.
 | 
						|
///
 | 
						|
/// Same as `syn`'s `ItemFn` except we keep the body as a TokenStream instead of
 | 
						|
/// parsing it. This makes the macro not error if there's a syntax error in the body,
 | 
						|
/// which helps IDE autocomplete work better.
 | 
						|
#[derive(Debug, Clone)]
 | 
						|
pub struct ItemFn {
 | 
						|
    pub attrs: Vec<Attribute>,
 | 
						|
    pub vis: Visibility,
 | 
						|
    pub sig: Signature,
 | 
						|
    pub brace_token: token::Brace,
 | 
						|
    pub body: TokenStream,
 | 
						|
}
 | 
						|
 | 
						|
impl Parse for ItemFn {
 | 
						|
    fn parse(input: ParseStream) -> syn::Result<Self> {
 | 
						|
        let mut attrs = input.call(Attribute::parse_outer)?;
 | 
						|
        let vis: Visibility = input.parse()?;
 | 
						|
        let sig: Signature = input.parse()?;
 | 
						|
 | 
						|
        let content;
 | 
						|
        let brace_token = braced!(content in input);
 | 
						|
        while content.peek(Token![#]) && content.peek2(Token![!]) {
 | 
						|
            let content2;
 | 
						|
            attrs.push(Attribute {
 | 
						|
                pound_token: content.parse()?,
 | 
						|
                style: AttrStyle::Inner(content.parse()?),
 | 
						|
                bracket_token: bracketed!(content2 in content),
 | 
						|
                meta: content2.parse()?,
 | 
						|
            });
 | 
						|
        }
 | 
						|
 | 
						|
        let mut body = Vec::new();
 | 
						|
        while !content.is_empty() {
 | 
						|
            body.push(content.parse::<TokenTree>()?);
 | 
						|
        }
 | 
						|
        let body = body.into_iter().collect();
 | 
						|
 | 
						|
        Ok(ItemFn {
 | 
						|
            attrs,
 | 
						|
            vis,
 | 
						|
            sig,
 | 
						|
            brace_token,
 | 
						|
            body,
 | 
						|
        })
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl ToTokens for ItemFn {
 | 
						|
    fn to_tokens(&self, tokens: &mut TokenStream) {
 | 
						|
        tokens.append_all(self.attrs.iter().filter(|a| matches!(a.style, AttrStyle::Outer)));
 | 
						|
        self.vis.to_tokens(tokens);
 | 
						|
        self.sig.to_tokens(tokens);
 | 
						|
        self.brace_token.surround(tokens, |tokens| {
 | 
						|
            tokens.append_all(self.body.clone());
 | 
						|
        });
 | 
						|
    }
 | 
						|
}
 |