Skip to content

Commit 4b0d375

Browse files
authored
Merge pull request hobofan#70 from glandium/syn2
Switch to syn 2
2 parents 0f76e3a + 49671f1 commit 4b0d375

File tree

10 files changed

+62
-44
lines changed

10 files changed

+62
-44
lines changed

.github/workflows/lint.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
strategy:
99
matrix:
1010
rust:
11-
- 1.53.0
11+
- 1.68.0
1212
steps:
1313
- uses: actions/checkout@v1
1414
- uses: actions-rs/toolchain@v1
@@ -34,7 +34,7 @@ jobs:
3434
strategy:
3535
matrix:
3636
rust:
37-
- 1.53.0
37+
- 1.68.0
3838
steps:
3939
- uses: actions/checkout@v1
4040
- uses: actions-rs/toolchain@v1

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
strategy:
1010
matrix:
1111
rust:
12-
- 1.53.0
12+
- 1.68.0
1313
steps:
1414
- uses: actions/checkout@v1
1515
- uses: actions-rs/toolchain@v1
@@ -34,7 +34,7 @@ jobs:
3434
matrix:
3535
rust:
3636
- 1.79.0
37-
# It's useful to test applications of these macros to newer features so using 1.53 for tests doesn't work
37+
# It's useful to test applications of these macros to newer features so using 1.68 for tests doesn't work
3838
# This needs to be locked to a specific version of Rust since the exact error messages may change
3939
# When switching this Rust version make sure to also update tests to use newer error messages if applicable
4040
steps:

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
Delegating the implementation of traits to enum variants or fields of a struct normally requires a lot of boilerplate code. Ambassador is an attempt to eliminate that boilerplate by deriving the delegating trait implementation via procedural macros.
1818

19-
**The minimum supported Rust version is 1.53.0.**
19+
**The minimum supported Rust version is 1.68.0.**
2020

2121
## Installation
2222

ambassador/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ readme = "README.md"
1313
proc-macro = true
1414

1515
[dependencies]
16-
syn = { version = "1.0.25", features = ["full", "extra-traits"] }
16+
syn = { version = "2", features = ["full", "extra-traits"] }
1717
quote = "1.0.2"
1818
proc-macro2 = "1.0.6"
1919
itertools = "0.10.3"

ambassador/src/delegate_shared.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ pub(super) fn delegate_macro<I>(
9090
// Parse the input tokens into a syntax tree
9191
let mut delegate_attributes = attrs
9292
.into_iter()
93-
.filter(|attr| attr.path.is_ident("delegate"))
94-
.map(|attr| attr.tokens)
93+
.filter(|attr| attr.path().is_ident("delegate"))
94+
.map(|attr| attr.meta.to_token_stream().into_iter().skip(1).collect())
9595
.peekable();
9696
if delegate_attributes.peek().is_none() {
9797
return error!(

ambassador/src/delegate_to_methods.rs

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use super::util;
44
use crate::util::{error, try_option, ReceiverType};
55
use itertools::Itertools;
66
use proc_macro::TokenStream;
7-
use proc_macro2::{Ident, TokenStream as TokenStream2};
7+
use proc_macro2::{Ident, TokenStream as TokenStream2, TokenTree};
88
use quote::{quote, ToTokens};
99
use std::cell::Cell;
1010
use std::convert::{TryFrom, TryInto};
@@ -30,19 +30,18 @@ struct MethodInfo {
3030
used: Cell<bool>, // modified when a usage is found
3131
}
3232

33-
impl TryFrom<syn::ImplItemMethod> for MethodInfo {
33+
impl TryFrom<syn::ImplItemFn> for MethodInfo {
3434
type Error = (Ident, syn::Error);
3535

36-
fn try_from(method: syn::ImplItemMethod) -> std::result::Result<Self, (Ident, syn::Error)> {
36+
fn try_from(method: syn::ImplItemFn) -> std::result::Result<Self, (Ident, syn::Error)> {
3737
let receiver_or_err = util::receiver_type(&method.sig);
3838
let return_span = method.sig.paren_token.span;
3939
let mut ident = Some(method.sig.ident);
4040
let mut add_ident = |err| (ident.take().unwrap(), err);
4141
let receiver = receiver_or_err.map_err(&mut add_ident)?;
4242
let ret = match method.sig.output {
43-
ReturnType::Default => {
44-
error!(return_span, "delegated to methods must return").map_err(&mut add_ident)?
45-
}
43+
ReturnType::Default => error!(return_span.open(), "delegated to methods must return")
44+
.map_err(&mut add_ident)?,
4645
ReturnType::Type(_, t) => *t,
4746
};
4847
let ret = match (ret, receiver) {
@@ -188,20 +187,37 @@ impl DelegateTarget {
188187
}
189188
}
190189

190+
fn replace_semi_with_block(input: TokenStream2) -> TokenStream2 {
191+
input
192+
.into_iter()
193+
.map(|token| match token {
194+
TokenTree::Punct(p) if p.as_char() == ';' => TokenTree::Group(proc_macro2::Group::new(
195+
proc_macro2::Delimiter::Brace,
196+
TokenStream2::new(),
197+
)),
198+
token => token,
199+
})
200+
.collect()
201+
}
202+
191203
// Checks that:
192204
// - all the items in an impl are methods
193205
// - all the methods are _empty_ (no body, just the signature)
194206
fn check_for_method_impls_and_extras(impl_items: &[syn::ImplItem]) -> Result<()> {
195207
let iter = impl_items.iter().filter_map(|i| {
208+
let mut i = i;
196209
// We're looking for *only* empty methods (no block).
197-
if let syn::ImplItem::Method(m) = i {
210+
let mut _item: Option<syn::ImplItem> = None;
211+
// syn 2 doesn't parse functions with omitted blocks as ImplItemFn.
212+
if let syn::ImplItem::Verbatim(v) = i {
213+
_item = Some(syn::parse2::<syn::ImplItem>(replace_semi_with_block(v.clone())).ok()?);
214+
i = _item.as_ref().unwrap();
215+
}
216+
if let syn::ImplItem::Fn(m) = i {
198217
let block = &m.block;
199-
let empty_block = syn::parse2::<syn::ImplItemMethod>(quote! { fn foo(); })
200-
.unwrap()
201-
.block;
202218

203219
// We'll accept `{}` blocks and omitted blocks (i.e. `fn foo();`):
204-
if block.stmts.is_empty() || block == &empty_block {
220+
if block.stmts.is_empty() {
205221
None
206222
} else {
207223
Some(syn::Error::new(
@@ -257,7 +273,7 @@ pub fn delegate_macro(input: TokenStream, keep_impl_block: bool) -> TokenStream
257273
let mut input = parse_macro_input!(input as ItemImpl);
258274
let attrs = std::mem::take(&mut input.attrs);
259275
assert!(
260-
attrs.iter().all(|attr| attr.path.is_ident("delegate")),
276+
attrs.iter().all(|attr| attr.path().is_ident("delegate")),
261277
"All attributes must be \"delegate\""
262278
);
263279
let keep_info = if keep_impl_block {
@@ -269,7 +285,13 @@ pub fn delegate_macro(input: TokenStream, keep_impl_block: bool) -> TokenStream
269285
.items
270286
.into_iter()
271287
.filter_map(|item| match item {
272-
syn::ImplItem::Method(method) => Some(method.try_into()),
288+
syn::ImplItem::Fn(method) => Some(method.try_into()),
289+
syn::ImplItem::Verbatim(v) => {
290+
// syn 2 doesn't parse functions with omitted blocks as ImplItemFn.
291+
syn::parse2::<syn::ImplItemFn>(replace_semi_with_block(v))
292+
.ok()
293+
.map(MethodInfo::try_from)
294+
}
273295
_ => None,
274296
})
275297
.partition_result();

ambassador/src/derive.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,18 +89,14 @@ fn try_info_from_data(span: Span, data: syn::Data) -> Result<DelegateImplementer
8989
Ok(res)
9090
}
9191

92+
#[derive(Default)]
9293
enum DelegateTarget {
9394
Field(syn::Member),
95+
#[default]
9496
TrgNone,
9597
TrgSelf,
9698
}
9799

98-
impl Default for DelegateTarget {
99-
fn default() -> Self {
100-
DelegateTarget::TrgNone
101-
}
102-
}
103-
104100
impl delegate_shared::DelegateTarget for DelegateTarget {
105101
fn try_update(&mut self, key: &str, lit: LitStr) -> Option<Result<()>> {
106102
match key {

ambassador/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
//!
1818
//! Delegating the implementation of traits to enum variants or fields of a struct normally requires a lot of boilerplate code. Ambassador is an attempt to eliminate that boilerplate by deriving the delegating trait implementation via procedural macros.
1919
//!
20-
//! **The minimum supported Rust version is 1.53.0.**
20+
//! **The minimum supported Rust version is 1.68.0.**
2121
//!
2222
//! See individual macro documentation for detailed instructions.
2323
//!

ambassador/src/register.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use crate::util::{error, process_results, receiver_type, ReceiverType};
22
use itertools::Itertools;
3-
use proc_macro2::{Delimiter, Ident, TokenStream, TokenTree};
3+
use proc_macro2::{Ident, TokenStream, TokenTree};
44
use quote::{quote, ToTokens, TokenStreamExt};
55
use syn::spanned::Spanned;
66
use syn::{
7-
AttrStyle, Attribute, ConstParam, GenericParam, ItemTrait, LifetimeDef, ReturnType, TraitItem,
8-
TraitItemConst, TraitItemType, TypeParam, Visibility,
7+
AttrStyle, Attribute, ConstParam, GenericParam, ItemTrait, LifetimeParam, ReturnType,
8+
TraitItem, TraitItemConst, TraitItemType, TypeParam, Visibility,
99
};
1010

1111
pub(crate) fn macro_name(trait_ident: &Ident) -> Ident {
@@ -116,15 +116,15 @@ pub fn build_register_trait(original_item: &ItemTrait) -> TokenStream {
116116
fn param_to_ident(param: &GenericParam) -> &Ident {
117117
match param {
118118
GenericParam::Type(TypeParam { ident, .. }) => ident,
119-
GenericParam::Lifetime(LifetimeDef { lifetime, .. }) => &lifetime.ident,
119+
GenericParam::Lifetime(LifetimeParam { lifetime, .. }) => &lifetime.ident,
120120
GenericParam::Const(ConstParam { ident, .. }) => ident,
121121
}
122122
}
123123

124124
fn param_to_matcher(param: &GenericParam) -> TokenStream {
125125
match param {
126126
GenericParam::Type(TypeParam { ident, .. }) => quote!($ #ident : ty,),
127-
GenericParam::Lifetime(LifetimeDef { lifetime, .. }) => {
127+
GenericParam::Lifetime(LifetimeParam { lifetime, .. }) => {
128128
let ident = &lifetime.ident;
129129
quote!($ #ident : lifetime,)
130130
}
@@ -135,7 +135,7 @@ fn param_to_matcher(param: &GenericParam) -> TokenStream {
135135
fn param_to_tokens(param: &GenericParam) -> TokenStream {
136136
match param {
137137
GenericParam::Type(TypeParam { ident, .. }) => quote!(#ident,),
138-
GenericParam::Lifetime(LifetimeDef { lifetime, .. }) => quote!(#lifetime,),
138+
GenericParam::Lifetime(LifetimeParam { lifetime, .. }) => quote!(#lifetime,),
139139
GenericParam::Const(ConstParam { ident, .. }) => quote!(#ident,),
140140
}
141141
}
@@ -220,9 +220,9 @@ fn build_method(
220220
fn extract_cfg(attrs: &[Attribute]) -> Option<TokenStream> {
221221
let mut iter = attrs
222222
.iter()
223-
.filter(|attr| attr.style == AttrStyle::Outer && attr.path.is_ident("cfg"))
224-
.filter_map(|attr| match attr.tokens.clone().into_iter().next()? {
225-
TokenTree::Group(x) if x.delimiter() == Delimiter::Parenthesis => Some(x.stream()),
223+
.filter(|attr| attr.style == AttrStyle::Outer && attr.path().is_ident("cfg"))
224+
.filter_map(|attr| match &attr.meta {
225+
syn::Meta::List(meta_list) => Some(meta_list.tokens.clone()),
226226
_ => None,
227227
});
228228
let e0 = iter.next()?;
@@ -268,7 +268,7 @@ fn build_trait_items(
268268
quote! {compile_error!("trg=\"self\" is not allowed with associated types")},
269269
)
270270
}
271-
TraitItem::Method(original_method) => {
271+
TraitItem::Fn(original_method) => {
272272
let method_sig = original_method.sig.to_token_stream();
273273
let method_sig = replace_gen_idents(method_sig, gen_idents);
274274
(
@@ -334,7 +334,7 @@ fn build_trait_items(
334334
let attrs: &[Attribute] = match original_item {
335335
TraitItem::Const(c) => &c.attrs,
336336
TraitItem::Type(t) => &t.attrs,
337-
TraitItem::Method(m) => &m.attrs,
337+
TraitItem::Fn(m) => &m.attrs,
338338
_ => &[],
339339
};
340340
if let Some(pred) = extract_cfg(attrs) {
@@ -346,7 +346,7 @@ fn build_trait_items(
346346
}
347347

348348
fn build_method_invocation(
349-
original_method: &syn::TraitItemMethod,
349+
original_method: &syn::TraitItemFn,
350350
field_ident: &TokenStream,
351351
force_add_await: bool,
352352
) -> TokenStream {

ambassador/src/util.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,11 @@ fn receiver_type_inner(r: &Receiver) -> ReceiverType {
122122

123123
pub(crate) fn receiver_type(sig: &syn::Signature) -> Result<ReceiverType> {
124124
match sig.receiver() {
125-
Some(syn::FnArg::Receiver(r)) => Ok(receiver_type_inner(r)),
126-
Some(syn::FnArg::Typed(t)) => error!(
127-
t.span(),
125+
Some(r) if r.colon_token.is_none() => Ok(receiver_type_inner(r)),
126+
Some(r) => error!(
127+
r.span(),
128128
"method's receiver type is not supported (must one of self, &self, or &mut self)"
129129
),
130-
None => error!(sig.paren_token.span, "method must have a receiver"),
130+
None => error!(sig.paren_token.span.open(), "method must have a receiver"),
131131
}
132132
}

0 commit comments

Comments
 (0)