From 0f1b32ff56f0db0fb0215bdd9a453e429dc7022b Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Thu, 26 Dec 2024 06:14:10 +0900 Subject: [PATCH] Switch to syn 2 --- ambassador/Cargo.toml | 2 +- ambassador/src/delegate_shared.rs | 4 +-- ambassador/src/delegate_to_methods.rs | 48 +++++++++++++++++++-------- ambassador/src/register.rs | 22 ++++++------ ambassador/src/util.rs | 8 ++--- 5 files changed, 53 insertions(+), 31 deletions(-) diff --git a/ambassador/Cargo.toml b/ambassador/Cargo.toml index 1eb9f0f..4d0af9c 100644 --- a/ambassador/Cargo.toml +++ b/ambassador/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" proc-macro = true [dependencies] -syn = { version = "1.0.25", features = ["full", "extra-traits"] } +syn = { version = "2", features = ["full", "extra-traits"] } quote = "1.0.2" proc-macro2 = "1.0.6" itertools = "0.10.3" diff --git a/ambassador/src/delegate_shared.rs b/ambassador/src/delegate_shared.rs index 3742196..9eab959 100644 --- a/ambassador/src/delegate_shared.rs +++ b/ambassador/src/delegate_shared.rs @@ -90,8 +90,8 @@ pub(super) fn delegate_macro( // Parse the input tokens into a syntax tree let mut delegate_attributes = attrs .into_iter() - .filter(|attr| attr.path.is_ident("delegate")) - .map(|attr| attr.tokens) + .filter(|attr| attr.path().is_ident("delegate")) + .map(|attr| attr.meta.to_token_stream().into_iter().skip(1).collect()) .peekable(); if delegate_attributes.peek().is_none() { return error!( diff --git a/ambassador/src/delegate_to_methods.rs b/ambassador/src/delegate_to_methods.rs index b4cc6a5..ea5fe9b 100644 --- a/ambassador/src/delegate_to_methods.rs +++ b/ambassador/src/delegate_to_methods.rs @@ -4,7 +4,7 @@ use super::util; use crate::util::{error, try_option, ReceiverType}; use itertools::Itertools; use proc_macro::TokenStream; -use proc_macro2::{Ident, TokenStream as TokenStream2}; +use proc_macro2::{Ident, TokenStream as TokenStream2, TokenTree}; use quote::{quote, ToTokens}; use std::cell::Cell; use std::convert::{TryFrom, TryInto}; @@ -30,19 +30,18 @@ struct MethodInfo { used: Cell, // modified when a usage is found } -impl TryFrom for MethodInfo { +impl TryFrom for MethodInfo { type Error = (Ident, syn::Error); - fn try_from(method: syn::ImplItemMethod) -> std::result::Result { + fn try_from(method: syn::ImplItemFn) -> std::result::Result { let receiver_or_err = util::receiver_type(&method.sig); let return_span = method.sig.paren_token.span; let mut ident = Some(method.sig.ident); let mut add_ident = |err| (ident.take().unwrap(), err); let receiver = receiver_or_err.map_err(&mut add_ident)?; let ret = match method.sig.output { - ReturnType::Default => { - error!(return_span, "delegated to methods must return").map_err(&mut add_ident)? - } + ReturnType::Default => error!(return_span.open(), "delegated to methods must return") + .map_err(&mut add_ident)?, ReturnType::Type(_, t) => *t, }; let ret = match (ret, receiver) { @@ -188,20 +187,37 @@ impl DelegateTarget { } } +fn replace_semi_with_block(input: TokenStream2) -> TokenStream2 { + input + .into_iter() + .map(|token| match token { + TokenTree::Punct(p) if p.as_char() == ';' => TokenTree::Group(proc_macro2::Group::new( + proc_macro2::Delimiter::Brace, + TokenStream2::new(), + )), + token => token, + }) + .collect() +} + // Checks that: // - all the items in an impl are methods // - all the methods are _empty_ (no body, just the signature) fn check_for_method_impls_and_extras(impl_items: &[syn::ImplItem]) -> Result<()> { let iter = impl_items.iter().filter_map(|i| { + let mut i = i; // We're looking for *only* empty methods (no block). - if let syn::ImplItem::Method(m) = i { + let mut _item: Option = None; + // syn 2 doesn't parse functions with omitted blocks as ImplItemFn. + if let syn::ImplItem::Verbatim(v) = i { + _item = Some(syn::parse2::(replace_semi_with_block(v.clone())).ok()?); + i = _item.as_ref().unwrap(); + } + if let syn::ImplItem::Fn(m) = i { let block = &m.block; - let empty_block = syn::parse2::(quote! { fn foo(); }) - .unwrap() - .block; // We'll accept `{}` blocks and omitted blocks (i.e. `fn foo();`): - if block.stmts.is_empty() || block == &empty_block { + if block.stmts.is_empty() { None } else { Some(syn::Error::new( @@ -257,7 +273,7 @@ pub fn delegate_macro(input: TokenStream, keep_impl_block: bool) -> TokenStream let mut input = parse_macro_input!(input as ItemImpl); let attrs = std::mem::take(&mut input.attrs); assert!( - attrs.iter().all(|attr| attr.path.is_ident("delegate")), + attrs.iter().all(|attr| attr.path().is_ident("delegate")), "All attributes must be \"delegate\"" ); let keep_info = if keep_impl_block { @@ -269,7 +285,13 @@ pub fn delegate_macro(input: TokenStream, keep_impl_block: bool) -> TokenStream .items .into_iter() .filter_map(|item| match item { - syn::ImplItem::Method(method) => Some(method.try_into()), + syn::ImplItem::Fn(method) => Some(method.try_into()), + syn::ImplItem::Verbatim(v) => { + // syn 2 doesn't parse functions with omitted blocks as ImplItemFn. + syn::parse2::(replace_semi_with_block(v.clone())) + .ok() + .map(MethodInfo::try_from) + } _ => None, }) .partition_result(); diff --git a/ambassador/src/register.rs b/ambassador/src/register.rs index 7a44467..e6f74c2 100644 --- a/ambassador/src/register.rs +++ b/ambassador/src/register.rs @@ -1,10 +1,10 @@ use crate::util::{error, process_results, receiver_type, ReceiverType}; use itertools::Itertools; -use proc_macro2::{Delimiter, Ident, TokenStream, TokenTree}; +use proc_macro2::{Ident, TokenStream, TokenTree}; use quote::{quote, ToTokens, TokenStreamExt}; use syn::spanned::Spanned; use syn::{ - AttrStyle, Attribute, ConstParam, GenericParam, ItemTrait, LifetimeDef, TraitItem, + AttrStyle, Attribute, ConstParam, GenericParam, ItemTrait, LifetimeParam, TraitItem, TraitItemConst, TraitItemType, TypeParam, Visibility, }; @@ -116,7 +116,7 @@ pub fn build_register_trait(original_item: &ItemTrait) -> TokenStream { fn param_to_ident(param: &GenericParam) -> &Ident { match param { GenericParam::Type(TypeParam { ident, .. }) => ident, - GenericParam::Lifetime(LifetimeDef { lifetime, .. }) => &lifetime.ident, + GenericParam::Lifetime(LifetimeParam { lifetime, .. }) => &lifetime.ident, GenericParam::Const(ConstParam { ident, .. }) => ident, } } @@ -124,7 +124,7 @@ fn param_to_ident(param: &GenericParam) -> &Ident { fn param_to_matcher(param: &GenericParam) -> TokenStream { match param { GenericParam::Type(TypeParam { ident, .. }) => quote!($ #ident : ty,), - GenericParam::Lifetime(LifetimeDef { lifetime, .. }) => { + GenericParam::Lifetime(LifetimeParam { lifetime, .. }) => { let ident = &lifetime.ident; quote!($ #ident : lifetime,) } @@ -135,7 +135,7 @@ fn param_to_matcher(param: &GenericParam) -> TokenStream { fn param_to_tokens(param: &GenericParam) -> TokenStream { match param { GenericParam::Type(TypeParam { ident, .. }) => quote!(#ident,), - GenericParam::Lifetime(LifetimeDef { lifetime, .. }) => quote!(#lifetime,), + GenericParam::Lifetime(LifetimeParam { lifetime, .. }) => quote!(#lifetime,), GenericParam::Const(ConstParam { ident, .. }) => quote!(#ident,), } } @@ -219,9 +219,9 @@ fn build_method( fn extract_cfg(attrs: &[Attribute]) -> Option { let mut iter = attrs .iter() - .filter(|attr| attr.style == AttrStyle::Outer && attr.path.is_ident("cfg")) - .filter_map(|attr| match attr.tokens.clone().into_iter().next()? { - TokenTree::Group(x) if x.delimiter() == Delimiter::Parenthesis => Some(x.stream()), + .filter(|attr| attr.style == AttrStyle::Outer && attr.path().is_ident("cfg")) + .filter_map(|attr| match &attr.meta { + syn::Meta::List(meta_list) => Some(meta_list.tokens.clone()), _ => None, }); let e0 = iter.next()?; @@ -267,7 +267,7 @@ fn build_trait_items( quote! {compile_error!("trg=\"self\" is not allowed with associated types")}, ) } - TraitItem::Method(original_method) => { + TraitItem::Fn(original_method) => { let method_sig = original_method.sig.to_token_stream(); let method_sig = replace_gen_idents(method_sig, gen_idents); ( @@ -317,7 +317,7 @@ fn build_trait_items( let attrs: &[Attribute] = match original_item { TraitItem::Const(c) => &c.attrs, TraitItem::Type(t) => &t.attrs, - TraitItem::Method(m) => &m.attrs, + TraitItem::Fn(m) => &m.attrs, _ => &[], }; if let Some(pred) = extract_cfg(attrs) { @@ -329,7 +329,7 @@ fn build_trait_items( } fn build_method_invocation( - original_method: &syn::TraitItemMethod, + original_method: &syn::TraitItemFn, field_ident: &TokenStream, ) -> TokenStream { let method_sig = &original_method.sig; diff --git a/ambassador/src/util.rs b/ambassador/src/util.rs index 38eeaab..74c3400 100644 --- a/ambassador/src/util.rs +++ b/ambassador/src/util.rs @@ -122,11 +122,11 @@ fn receiver_type_inner(r: &Receiver) -> ReceiverType { pub(crate) fn receiver_type(sig: &syn::Signature) -> Result { match sig.receiver() { - Some(syn::FnArg::Receiver(r)) => Ok(receiver_type_inner(r)), - Some(syn::FnArg::Typed(t)) => error!( - t.span(), + Some(r) if r.colon_token.is_none() => Ok(receiver_type_inner(r)), + Some(r) => error!( + r.span(), "method's receiver type is not supported (must one of self, &self, or &mut self)" ), - None => error!(sig.paren_token.span, "method must have a receiver"), + None => error!(sig.paren_token.span.open(), "method must have a receiver"), } }