Skip to content

Commit 322ff07

Browse files
committed
support ref mut pattern bindings
1 parent 9ce12d2 commit 322ff07

File tree

2 files changed

+64
-17
lines changed

2 files changed

+64
-17
lines changed

src/gen.rs

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
use proc_macro2::{Span as Span2, TokenStream as TokenStream2};
22
use proc_macro_error::{abort, emit_error};
33
use quote::{ToTokens, TokenStreamExt};
4-
use syn::{
5-
spanned::Spanned, Attribute, FnArg, Ident, ItemTrait, Lifetime, Pat, PatIdent, ReturnType,
6-
Signature, TraitBound, TraitBoundModifier, TraitItem, TraitItemConst, TraitItemMethod,
7-
TraitItemType, Type, TypeParamBound, WherePredicate,
8-
};
4+
use syn::{spanned::Spanned, Attribute, FnArg, Ident, ItemTrait, Lifetime, Pat, PatIdent, ReturnType, Signature, TraitBound, TraitBoundModifier, TraitItem, TraitItemConst, TraitItemMethod, TraitItemType, Type, TypeParamBound, WherePredicate, PatType, Token};
5+
use syn::punctuated::Punctuated;
96

107
use crate::{
118
analyze::find_suitable_param_names,
@@ -577,29 +574,46 @@ fn gen_method_item(
577574
// If this method has a `#[auto_impl(keep_default_for(...))]` attribute for
578575
// the given proxy type, we don't generate anything for this impl block.
579576
if should_keep_default_for(item, proxy_type) {
580-
if item.default.is_some() {
581-
return Ok(TokenStream2::new());
577+
return if item.default.is_some() {
578+
Ok(TokenStream2::new())
582579
} else {
583580
emit_error!(
584581
item.sig.span(),
585582
"the method `{}` has the attribute `keep_default_for` but is not a default \
586583
method (no body is provided)",
587584
item.sig.ident,
588585
);
589-
return Err(());
586+
Err(())
590587
}
591588
}
592589

593590
// Determine the kind of the method, determined by the self type.
594591
let sig = &item.sig;
595-
let self_arg = SelfType::from_sig(sig);
592+
let self_arg = SelfType::from_sig(&sig);
596593
let attrs = filter_attrs(&item.attrs);
597594

598595
// Check self type and proxy type combination
599596
check_receiver_compatible(proxy_type, self_arg, &trait_def.ident, sig.span().into());
600597

601598
// Generate the list of argument used to call the method.
602-
let args = get_arg_list(sig.inputs.iter());
599+
let (inputs, args) = get_arg_list(sig.inputs.iter());
600+
601+
// Construct a signature we'll use to generate the proxy method impl
602+
// This is _almost_ the same as the original, except we use the inputs constructed
603+
// alongside the args. These may be slightly different than the original trait.
604+
let sig = Signature {
605+
constness: item.sig.constness,
606+
asyncness: item.sig.asyncness,
607+
unsafety: item.sig.unsafety,
608+
abi: item.sig.abi.clone(),
609+
fn_token: item.sig.fn_token,
610+
ident: item.sig.ident.clone(),
611+
generics: item.sig.generics.clone(),
612+
paren_token: item.sig.paren_token,
613+
inputs,
614+
variadic: item.sig.variadic.clone(),
615+
output: item.sig.output.clone(),
616+
};
603617

604618
// Build the turbofish type parameters. We need to pass type parameters
605619
// explicitly as they cannot be inferred in all cases (e.g. something like
@@ -769,25 +783,40 @@ fn check_receiver_compatible(
769783
/// Generates a list of comma-separated arguments used to call the function.
770784
/// Currently, only simple names are valid and more complex pattern will lead
771785
/// to an error being emitted. `self` parameters are ignored.
772-
fn get_arg_list<'a>(inputs: impl Iterator<Item = &'a FnArg>) -> TokenStream2 {
786+
fn get_arg_list<'a>(original_inputs: impl Iterator<Item = &'a FnArg>) -> (Punctuated<FnArg, Token![,]>, TokenStream2) {
773787
let mut args = TokenStream2::new();
788+
let mut inputs = Punctuated::new();
774789

775-
for arg in inputs {
790+
for arg in original_inputs {
776791
match arg {
777792
FnArg::Typed(arg) => {
778793
// Make sure the argument pattern is a simple name. In
779794
// principle, we could probably support patterns, but it's
780795
// not that important now.
781796
if let Pat::Ident(PatIdent {
782-
by_ref: None,
783-
mutability: None,
797+
by_ref: _by_ref,
798+
mutability: _mutability,
784799
ident,
785800
subpat: None,
786-
..
801+
attrs,
787802
}) = &*arg.pat
788803
{
789804
// Add name plus trailing comma to tokens
790805
args.append_all(quote! { #ident , });
806+
807+
// Add an input argument that omits the `mut` and `ref` pattern bindings
808+
inputs.push(FnArg::Typed(PatType {
809+
attrs: arg.attrs.clone(),
810+
pat: Box::new(Pat::Ident(PatIdent {
811+
attrs: attrs.clone(),
812+
by_ref: None,
813+
mutability: None,
814+
ident: ident.clone(),
815+
subpat: None,
816+
})),
817+
colon_token: arg.colon_token,
818+
ty: arg.ty.clone(),
819+
}))
791820
} else {
792821
emit_error!(
793822
arg.pat.span(), "argument patterns are not supported by #[auto-impl]";
@@ -799,11 +828,13 @@ fn get_arg_list<'a>(inputs: impl Iterator<Item = &'a FnArg>) -> TokenStream2 {
799828

800829
// There is only one such argument. We handle it elsewhere and
801830
// can ignore it here.
802-
FnArg::Receiver(_) => {}
831+
FnArg::Receiver(arg) => {
832+
inputs.push(FnArg::Receiver(arg.clone()));
833+
}
803834
}
804835
}
805836

806-
args
837+
(inputs, args)
807838
}
808839

809840
/// Checks if the given method has the attribute `#[auto_impl(keep_default_for(...))]`
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use auto_impl::auto_impl;
2+
3+
4+
struct Data {
5+
id: usize,
6+
}
7+
8+
#[auto_impl(Fn)]
9+
trait Foo {
10+
fn foo(&self, ref mut data: Data) {
11+
data.id += 1;
12+
}
13+
}
14+
15+
16+
fn main() {}

0 commit comments

Comments
 (0)