Skip to content

Commit 8a830f1

Browse files
authored
Merge pull request #81 from auto-impl-rs/fix/ref-mut-pats
support ref mut pattern bindings
2 parents 11fffab + 094b085 commit 8a830f1

File tree

2 files changed

+65
-17
lines changed

2 files changed

+65
-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,
@@ -595,29 +592,46 @@ fn gen_method_item(
595592
// If this method has a `#[auto_impl(keep_default_for(...))]` attribute for
596593
// the given proxy type, we don't generate anything for this impl block.
597594
if should_keep_default_for(item, proxy_type) {
598-
if item.default.is_some() {
599-
return Ok(TokenStream2::new());
595+
return if item.default.is_some() {
596+
Ok(TokenStream2::new())
600597
} else {
601598
emit_error!(
602599
item.sig.span(),
603600
"the method `{}` has the attribute `keep_default_for` but is not a default \
604601
method (no body is provided)",
605602
item.sig.ident,
606603
);
607-
return Err(());
604+
Err(())
608605
}
609606
}
610607

611608
// Determine the kind of the method, determined by the self type.
612609
let sig = &item.sig;
613-
let self_arg = SelfType::from_sig(sig);
610+
let self_arg = SelfType::from_sig(&sig);
614611
let attrs = filter_attrs(&item.attrs);
615612

616613
// Check self type and proxy type combination
617614
check_receiver_compatible(proxy_type, self_arg, &trait_def.ident, sig.span().into());
618615

619616
// Generate the list of argument used to call the method.
620-
let args = get_arg_list(sig.inputs.iter());
617+
let (inputs, args) = get_arg_list(sig.inputs.iter());
618+
619+
// Construct a signature we'll use to generate the proxy method impl
620+
// This is _almost_ the same as the original, except we use the inputs constructed
621+
// alongside the args. These may be slightly different than the original trait.
622+
let sig = Signature {
623+
constness: item.sig.constness,
624+
asyncness: item.sig.asyncness,
625+
unsafety: item.sig.unsafety,
626+
abi: item.sig.abi.clone(),
627+
fn_token: item.sig.fn_token,
628+
ident: item.sig.ident.clone(),
629+
generics: item.sig.generics.clone(),
630+
paren_token: item.sig.paren_token,
631+
inputs,
632+
variadic: item.sig.variadic.clone(),
633+
output: item.sig.output.clone(),
634+
};
621635

622636
// Build the turbofish type parameters. We need to pass type parameters
623637
// explicitly as they cannot be inferred in all cases (e.g. something like
@@ -787,25 +801,40 @@ fn check_receiver_compatible(
787801
/// Generates a list of comma-separated arguments used to call the function.
788802
/// Currently, only simple names are valid and more complex pattern will lead
789803
/// to an error being emitted. `self` parameters are ignored.
790-
fn get_arg_list<'a>(inputs: impl Iterator<Item = &'a FnArg>) -> TokenStream2 {
804+
fn get_arg_list<'a>(original_inputs: impl Iterator<Item = &'a FnArg>) -> (Punctuated<FnArg, Token![,]>, TokenStream2) {
791805
let mut args = TokenStream2::new();
806+
let mut inputs = Punctuated::new();
792807

793-
for arg in inputs {
808+
for arg in original_inputs {
794809
match arg {
795810
FnArg::Typed(arg) => {
796811
// Make sure the argument pattern is a simple name. In
797812
// principle, we could probably support patterns, but it's
798813
// not that important now.
799814
if let Pat::Ident(PatIdent {
800-
by_ref: None,
801-
mutability: None,
815+
by_ref: _by_ref,
816+
mutability: _mutability,
802817
ident,
803818
subpat: None,
804-
..
819+
attrs,
805820
}) = &*arg.pat
806821
{
807822
// Add name plus trailing comma to tokens
808823
args.append_all(quote! { #ident , });
824+
825+
// Add an input argument that omits the `mut` and `ref` pattern bindings
826+
inputs.push(FnArg::Typed(PatType {
827+
attrs: arg.attrs.clone(),
828+
pat: Box::new(Pat::Ident(PatIdent {
829+
attrs: attrs.clone(),
830+
by_ref: None,
831+
mutability: None,
832+
ident: ident.clone(),
833+
subpat: None,
834+
})),
835+
colon_token: arg.colon_token,
836+
ty: arg.ty.clone(),
837+
}))
809838
} else {
810839
emit_error!(
811840
arg.pat.span(), "argument patterns are not supported by #[auto-impl]";
@@ -817,11 +846,13 @@ fn get_arg_list<'a>(inputs: impl Iterator<Item = &'a FnArg>) -> TokenStream2 {
817846

818847
// There is only one such argument. We handle it elsewhere and
819848
// can ignore it here.
820-
FnArg::Receiver(_) => {}
849+
FnArg::Receiver(arg) => {
850+
inputs.push(FnArg::Receiver(arg.clone()));
851+
}
821852
}
822853
}
823854

824-
args
855+
(inputs, args)
825856
}
826857

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

0 commit comments

Comments
 (0)