auto_impl/
gen.rs

1use proc_macro2::{Span as Span2, TokenStream as TokenStream2};
2use quote::{ToTokens, TokenStreamExt};
3use syn::{
4    punctuated::Punctuated, spanned::Spanned, Attribute, Error, FnArg, GenericParam, Ident,
5    ItemTrait, Lifetime, Pat, PatIdent, PatType, ReturnType, Signature, Token, TraitBound,
6    TraitBoundModifier, TraitItem, TraitItemConst, TraitItemFn, TraitItemType, Type,
7    TypeParamBound, WherePredicate,
8};
9
10use crate::{
11    analyze::find_suitable_param_names,
12    attr::{is_our_attr, parse_our_attr, OurAttr},
13    proxy::ProxyType,
14};
15
16/// Generates one complete impl of the given trait for each of the given proxy
17/// types. All impls are returned as token stream.
18pub(crate) fn gen_impls(
19    proxy_types: &[ProxyType],
20    trait_def: &syn::ItemTrait,
21) -> syn::Result<TokenStream2> {
22    let mut tokens = TokenStream2::new();
23
24    let (proxy_ty_param, proxy_lt_param) = find_suitable_param_names(trait_def);
25
26    // One impl for each proxy type
27    for proxy_type in proxy_types {
28        let header = gen_header(proxy_type, trait_def, &proxy_ty_param, &proxy_lt_param)?;
29        let items = gen_items(proxy_type, trait_def, &proxy_ty_param)?;
30
31        if let ProxyType::Box | ProxyType::Rc | ProxyType::Arc = proxy_type {
32            tokens.append_all(quote! {
33                const _: () = {
34                    extern crate alloc;
35                    #header { #( #items )* }
36                };
37            });
38        } else {
39            tokens.append_all(quote! {
40                const _: () = {
41                    #header { #( #items )* }
42                };
43            });
44        }
45    }
46
47    Ok(tokens)
48}
49
50/// Generates the header of the impl of the given trait for the given proxy
51/// type.
52fn gen_header(
53    proxy_type: &ProxyType,
54    trait_def: &ItemTrait,
55    proxy_ty_param: &Ident,
56    proxy_lt_param: &Lifetime,
57) -> syn::Result<TokenStream2> {
58    // Generate generics for impl positions from trait generics.
59    let (impl_generics, trait_generics, where_clause) = trait_def.generics.split_for_impl();
60
61    // The name of the trait with all generic parameters applied.
62    let trait_ident = &trait_def.ident;
63    let trait_path = quote! { #trait_ident #trait_generics };
64
65    // Here we assemble the parameter list of the impl (the thing in
66    // `impl< ... >`). This is simply the parameter list of the trait with
67    // one or two parameters added. For a trait `trait Foo<'x, 'y, A, B>`,
68    // it will look like this:
69    //
70    //    '{proxy_lt_param}, 'x, 'y, A, B, {proxy_ty_param}
71    //
72    // The `'{proxy_lt_param}` in the beginning is only added when the proxy
73    // type is `&` or `&mut`.
74    let impl_generics = {
75        // Determine whether we can add a `?Sized` relaxation to allow trait
76        // objects. We can do that as long as there is no method that has a
77        // `self` by value receiver and no `where Self: Sized` bound.
78        let methods = trait_def
79            .items
80            .iter()
81            // Only interested in methods
82            .filter_map(|item| {
83                if let TraitItem::Fn(m) = item {
84                    Some(m)
85                } else {
86                    None
87                }
88            });
89
90        let mut sized_required = false;
91        for m in methods {
92            if should_keep_default_for(m, proxy_type)? {
93                continue;
94            }
95
96            // Check if there is a `Self: Sized` bound on the method.
97            let self_is_bounded_sized = m
98                .sig
99                .generics
100                .where_clause
101                .iter()
102                .flat_map(|wc| &wc.predicates)
103                .filter_map(|pred| {
104                    if let WherePredicate::Type(p) = pred {
105                        Some(p)
106                    } else {
107                        None
108                    }
109                })
110                .any(|pred| {
111                    // Check if the type is `Self`
112                    match &pred.bounded_ty {
113                        Type::Path(p) if p.path.is_ident("Self") => {
114                            // Check if the bound contains `Sized`
115                            pred.bounds.iter().any(|b| match b {
116                                TypeParamBound::Trait(TraitBound {
117                                    modifier: TraitBoundModifier::None,
118                                    path,
119                                    ..
120                                }) => path.is_ident("Sized"),
121                                _ => false,
122                            })
123                        }
124                        _ => false,
125                    }
126                });
127
128            // Check if the first parameter is `self` by value. In that
129            // case, we might require `Self` to be `Sized`.
130            let self_value_param = match m.sig.inputs.first() {
131                Some(FnArg::Receiver(receiver)) => receiver.reference.is_none(),
132                _ => false,
133            };
134
135            // Check if return type is `Self`
136            let self_value_return = match &m.sig.output {
137                ReturnType::Type(_, t) => {
138                    if let Type::Path(p) = &**t {
139                        p.path.is_ident("Self")
140                    } else {
141                        false
142                    }
143                }
144                _ => false,
145            };
146
147            // TODO: check for `Self` parameter in any other argument.
148
149            // If for this method, `Self` is used in a position that
150            // requires `Self: Sized` or this bound is added explicitly, we
151            // cannot add the `?Sized` relaxation to the impl body.
152            if self_value_param || self_value_return || self_is_bounded_sized {
153                sized_required = true;
154                break;
155            }
156        }
157
158        let relaxation = if sized_required {
159            quote! {}
160        } else {
161            quote! { + ?::core::marker::Sized }
162        };
163
164        // Check if there are some `Self: Foo` bounds on methods. If so, we
165        // need to add those bounds to `T` as well. See issue #11 for more
166        // information, but in short: there is no better solution. Method where
167        // clauses with `Self: Foo` force us to add `T: Foo` to the impl
168        // header, as we otherwise cannot generate a valid impl block.
169        let methods = trait_def
170            .items
171            .iter()
172            // Only interested in methods
173            .filter_map(|item| {
174                if let TraitItem::Fn(m) = item {
175                    Some(m)
176                } else {
177                    None
178                }
179            });
180
181        let mut additional_bounds = Vec::new();
182        for m in methods {
183            if should_keep_default_for(m, proxy_type)? {
184                continue;
185            }
186
187            additional_bounds.extend(
188                m.sig
189                    .generics
190                    .where_clause
191                    .iter()
192                    .flat_map(|wc| &wc.predicates)
193                    .filter_map(|pred| {
194                        if let WherePredicate::Type(p) = pred {
195                            Some(p)
196                        } else {
197                            None
198                        }
199                    })
200                    .filter(|p| {
201                        // Only `Self:` bounds
202                        match &p.bounded_ty {
203                            Type::Path(p) => p.path.is_ident("Self"),
204                            _ => false,
205                        }
206                    })
207                    .flat_map(|p| &p.bounds)
208                    .filter_map(|b| {
209                        // We are only interested in trait bounds. That's
210                        // because lifetime bounds on `Self` do not need to be
211                        // added to the impl header. That's because all values
212                        // "derived" from `self` also meet the same lifetime
213                        // bound as `self`. In simpler terms: while `self.field`
214                        // might not be `Clone` even if `Self: Clone`,
215                        // `self.field` is always `: 'a` if `Self: 'a`.
216                        match b {
217                            TypeParamBound::Trait(t) => Some(t),
218                            _ => None,
219                        }
220                    }),
221            );
222        }
223
224        // Determine if our proxy type needs a lifetime parameter
225        let (mut params, ty_bounds) = match proxy_type {
226            ProxyType::Ref | ProxyType::RefMut => (
227                quote! { #proxy_lt_param, },
228                quote! { : #proxy_lt_param + #trait_path #relaxation #(+ #additional_bounds)* },
229            ),
230            ProxyType::Box | ProxyType::Rc | ProxyType::Arc => (
231                quote! {},
232                quote! { : #trait_path #relaxation #(+ #additional_bounds)* },
233            ),
234            ProxyType::Fn | ProxyType::FnMut | ProxyType::FnOnce => {
235                let fn_bound = gen_fn_type_for_trait(proxy_type, trait_def)?;
236                (quote! {}, quote! { : #fn_bound })
237            }
238        };
239
240        // Append all parameters from the trait. Sadly, `impl_generics`
241        // includes the angle brackets `< >` so we have to remove them like
242        // this.
243        let mut tts = impl_generics
244            .into_token_stream()
245            .into_iter()
246            .skip(1) // the opening `<`
247            .collect::<Vec<_>>();
248        tts.pop(); // the closing `>`
249        params.append_all(&tts);
250
251        // Append proxy type parameter (if there aren't any parameters so far,
252        // we need to add a comma first).
253        let comma = if params.is_empty() || tts.is_empty() {
254            quote! {}
255        } else {
256            quote! { , }
257        };
258        params.append_all(quote! { #comma #proxy_ty_param #ty_bounds });
259
260        params
261    };
262
263    // The tokens after `for` in the impl header (the type the trait is
264    // implemented for).
265    #[rustfmt::skip]
266    let self_ty = match *proxy_type {
267        ProxyType::Ref      => quote! { & #proxy_lt_param #proxy_ty_param },
268        ProxyType::RefMut   => quote! { & #proxy_lt_param mut #proxy_ty_param },
269        ProxyType::Arc      => quote! { alloc::sync::Arc<#proxy_ty_param> },
270        ProxyType::Rc       => quote! { alloc::rc::Rc<#proxy_ty_param> },
271        ProxyType::Box      => quote! { alloc::boxed::Box<#proxy_ty_param> },
272        ProxyType::Fn       => quote! { #proxy_ty_param },
273        ProxyType::FnMut    => quote! { #proxy_ty_param },
274        ProxyType::FnOnce   => quote! { #proxy_ty_param },
275    };
276
277    // If the trait has super traits, we need to add the super trait bound to
278    // our self type. This can only be done in the where clause, so we need to
279    // combine the existing where clauses with our new predicate in that case.
280    let where_clause = if !trait_def.supertraits.is_empty() {
281        let mut out = quote! { where };
282
283        if !trait_def.supertraits.is_empty() {
284            let supertraits = &trait_def.supertraits;
285            out.extend(quote! { #self_ty: #supertraits, });
286        }
287        if let Some(predicates) = where_clause.map(|c| &c.predicates) {
288            out.extend(predicates.into_token_stream());
289        }
290
291        out
292    } else {
293        where_clause.into_token_stream()
294    };
295
296    // Combine everything
297    Ok(quote! {
298        impl<#impl_generics> #trait_path for #self_ty #where_clause
299    })
300}
301
302/// Generates the Fn-trait type (e.g. `FnMut(u32) -> String`) for the given
303/// trait and proxy type (the latter has to be `Fn`, `FnMut` or `FnOnce`!)
304///
305/// If the trait is unsuitable to be implemented for the given proxy type, an
306/// error is emitted.
307fn gen_fn_type_for_trait(
308    proxy_type: &ProxyType,
309    trait_def: &ItemTrait,
310) -> syn::Result<TokenStream2> {
311    // Only traits with exactly one method can be implemented for Fn-traits.
312    // Associated types and consts are also not allowed.
313    let method = trait_def.items.first().and_then(|item| {
314        if let TraitItem::Fn(m) = item {
315            Some(m)
316        } else {
317            None
318        }
319    });
320
321    // If this requirement is not satisfied, we emit an error.
322    if method.is_none() || trait_def.items.len() > 1 {
323        return Err(Error::new(
324            trait_def.span(),
325            "this trait cannot be auto-implemented for Fn-traits (only traits with exactly \
326                one method and no other items are allowed)",
327        ));
328    }
329
330    // We checked for `None` above
331    let method = method.unwrap();
332    let sig = &method.sig;
333
334    // Check for forbidden modifier of the method
335    if let Some(const_token) = sig.constness {
336        return Err(Error::new(
337            const_token.span(),
338            format_args!(
339                "the trait '{}' cannot be auto-implemented for Fn-traits: const methods are not \
340                allowed",
341                trait_def.ident
342            ),
343        ));
344    }
345
346    if let Some(unsafe_token) = &sig.unsafety {
347        return Err(Error::new(
348            unsafe_token.span(),
349            format_args!(
350                "the trait '{}' cannot be auto-implemented for Fn-traits: unsafe methods are not \
351                allowed",
352                trait_def.ident
353            ),
354        ));
355    }
356
357    if let Some(abi_token) = &sig.abi {
358        return Err(Error::new(
359            abi_token.span(),
360            format_args!(
361                "the trait '{}' cannot be implemented for Fn-traits: custom ABIs are not allowed",
362                trait_def.ident
363            ),
364        ));
365    }
366
367    // Function traits cannot support generics in their arguments
368    // These would require HRTB for types instead of just lifetimes
369    let mut r: syn::Result<()> = Ok(());
370    for type_param in sig.generics.type_params() {
371        let err = Error::new(
372            type_param.span(),
373            format_args!("the trait '{}' cannot be implemented for Fn-traits: generic arguments are not allowed",
374            trait_def.ident),
375        );
376
377        if let Err(ref mut current_err) = r {
378            current_err.combine(err);
379        } else {
380            r = Err(err);
381        }
382    }
383
384    for const_param in sig.generics.const_params() {
385        let err = Error::new(
386            const_param.span(),
387            format_args!("the trait '{}' cannot be implemented for Fn-traits: constant arguments are not allowed",
388            trait_def.ident),
389        );
390
391        if let Err(ref mut current_err) = r {
392            current_err.combine(err);
393        } else {
394            r = Err(err);
395        }
396    }
397    r?;
398
399    // =======================================================================
400    // Check if the trait can be implemented for the given proxy type
401    let self_type = SelfType::from_sig(sig);
402    let err = match (self_type, proxy_type) {
403        // The method needs to have a receiver
404        (SelfType::None, _) => Some(("Fn-traits", "no", "")),
405
406        // We can't impl methods with `&mut self` or `&self` receiver for
407        // `FnOnce`
408        (SelfType::Mut, ProxyType::FnOnce) => {
409            Some(("`FnOnce`", "a `&mut self`", " (only `self` is allowed)"))
410        }
411        (SelfType::Ref, ProxyType::FnOnce) => {
412            Some(("`FnOnce`", "a `&self`", " (only `self` is allowed)"))
413        }
414
415        // We can't impl methods with `&self` receiver for `FnMut`
416        (SelfType::Ref, ProxyType::FnMut) => Some((
417            "`FnMut`",
418            "a `&self`",
419            " (only `self` and `&mut self` are allowed)",
420        )),
421
422        // Other combinations are fine
423        _ => None,
424    };
425
426    if let Some((fn_traits, receiver, allowed)) = err {
427        return Err(Error::new(
428            method.sig.span(),
429            format_args!(
430                "the trait '{}' cannot be auto-implemented for {}, because this method has \
431                {} receiver{}",
432                trait_def.ident, fn_traits, receiver, allowed,
433            ),
434        ));
435    }
436
437    // =======================================================================
438    // Generate the full Fn-type
439
440    // The path to the Fn-trait
441    let fn_name = match proxy_type {
442        ProxyType::Fn => quote! { ::core::ops::Fn },
443        ProxyType::FnMut => quote! { ::core::ops::FnMut },
444        ProxyType::FnOnce => quote! { ::core::ops::FnOnce },
445        _ => panic!("internal error in auto_impl (function contract violation)"),
446    };
447
448    // The return type
449    let ret = &sig.output;
450
451    // Now it gets a bit complicated. The types of the function signature
452    // could contain "local" lifetimes, meaning that they are not declared in
453    // the trait definition (or are `'static`). We need to extract all local
454    // lifetimes to declare them with HRTB (e.g. `for<'a>`).
455    //
456    // In Rust 2015 that was easy: we could just take the lifetimes explicitly
457    // declared in the function signature. Those were the local lifetimes.
458    // Unfortunately, with in-band lifetimes, things get more complicated. We
459    // need to take a look at all lifetimes inside the types (arbitrarily deep)
460    // and check if they are local or not.
461    //
462    // In cases where lifetimes are omitted (e.g. `&str`), we don't have a
463    // problem. If we just translate that to `for<> Fn(&str)`, it's fine: all
464    // omitted lifetimes in an `Fn()` type are automatically declared as HRTB.
465    //
466    // TODO: Implement this check for in-band lifetimes!
467    let local_lifetimes = sig.generics.lifetimes();
468
469    // The input types as comma separated list. We skip the first argument, as
470    // this is the receiver argument.
471    let mut arg_types = TokenStream2::new();
472    for arg in sig.inputs.iter().skip(1) {
473        match arg {
474            FnArg::Typed(pat) => {
475                let ty = &pat.ty;
476                arg_types.append_all(quote! { #ty , });
477            }
478
479            // We skipped the receiver already.
480            FnArg::Receiver(r) => {
481                return Err(Error::new(
482                    r.span(),
483                    "receiver argument that's not the first argument (auto_impl is confused)",
484                ));
485            }
486        }
487    }
488
489    Ok(quote! {
490        for< #(#local_lifetimes),* > #fn_name (#arg_types) #ret
491    })
492}
493
494/// Generates the implementation of all items of the given trait. These
495/// implementations together are the body of the `impl` block.
496fn gen_items(
497    proxy_type: &ProxyType,
498    trait_def: &ItemTrait,
499    proxy_ty_param: &Ident,
500) -> syn::Result<Vec<TokenStream2>> {
501    trait_def
502        .items
503        .iter()
504        .map(|item| {
505            match item {
506                TraitItem::Const(c) => gen_const_item(proxy_type, c, trait_def, proxy_ty_param),
507                TraitItem::Fn(method) => {
508                    gen_method_item(proxy_type, method, trait_def, proxy_ty_param)
509                }
510                TraitItem::Type(ty) => gen_type_item(proxy_type, ty, trait_def, proxy_ty_param),
511                TraitItem::Macro(mac) => {
512                    // We cannot resolve the macro invocation and thus cannot know
513                    // if it adds additional items to the trait. Thus, we have to
514                    // give up.
515                    Err(Error::new(
516                        mac.span(),
517                        "traits with macro invocations in their bodies are not \
518                        supported by auto_impl",
519                    ))
520                }
521                TraitItem::Verbatim(v) => {
522                    // I don't quite know when this happens, but it's better to
523                    // notify the user with a nice error instead of panicking.
524                    Err(Error::new(
525                        v.span(),
526                        "unexpected 'verbatim'-item (auto-impl doesn't know how to handle it)",
527                    ))
528                }
529                _ => {
530                    // `syn` enums are `non_exhaustive` to be future-proof. If a
531                    // trait contains a kind of item we don't even know about, we
532                    // emit an error.
533                    Err(Error::new(
534                        item.span(),
535                        "unknown trait item (auto-impl doesn't know how to handle it)",
536                    ))
537                }
538            }
539        })
540        .collect()
541}
542
543/// Generates the implementation of an associated const item described by
544/// `item`. The implementation is returned as token stream.
545///
546/// If the proxy type is an Fn*-trait, an error is emitted and `Err(())` is
547/// returned.
548fn gen_const_item(
549    proxy_type: &ProxyType,
550    item: &TraitItemConst,
551    trait_def: &ItemTrait,
552    proxy_ty_param: &Ident,
553) -> syn::Result<TokenStream2> {
554    // A trait with associated consts cannot be implemented for Fn* types.
555    if proxy_type.is_fn() {
556        return Err(Error::new(
557            item.span(),
558            format_args!("the trait `{}` cannot be auto-implemented for Fn-traits, because it has \
559                associated consts (only traits with a single method can be implemented for Fn-traits)",
560            trait_def.ident)
561        ));
562    }
563
564    // We simply use the associated const from our type parameter.
565    let const_name = &item.ident;
566    let const_ty = &item.ty;
567    let attrs = filter_attrs(&item.attrs);
568
569    Ok(quote! {
570        #(#attrs)* const #const_name: #const_ty = #proxy_ty_param::#const_name;
571    })
572}
573
574/// Generates the implementation of an associated type item described by `item`.
575/// The implementation is returned as token stream.
576///
577/// If the proxy type is an Fn*-trait, an error is emitted and `Err(())` is
578/// returned.
579fn gen_type_item(
580    proxy_type: &ProxyType,
581    item: &TraitItemType,
582    trait_def: &ItemTrait,
583    proxy_ty_param: &Ident,
584) -> syn::Result<TokenStream2> {
585    // A trait with associated types cannot be implemented for Fn* types.
586    if proxy_type.is_fn() {
587        return Err(Error::new(
588            item.span(),
589            format_args!("the trait `{}` cannot be auto-implemented for Fn-traits, because it has \
590                associated types (only traits with a single method can be implemented for Fn-traits)",
591                trait_def.ident)
592        ));
593    }
594
595    // We simply use the associated type from our type parameter.
596    let assoc_name = &item.ident;
597    let attrs = filter_attrs(&item.attrs);
598    let generics = &item.generics;
599
600    Ok(quote! {
601        #(#attrs)* type #assoc_name #generics = #proxy_ty_param::#assoc_name #generics;
602    })
603}
604
605/// Generates the implementation of a method item described by `item`. The
606/// implementation is returned as token stream.
607///
608/// This function also performs sanity checks, e.g. whether the proxy type can
609/// be used to implement the method. If any error occurs, the error is
610/// immediately emitted and `Err(())` is returned.
611fn gen_method_item(
612    proxy_type: &ProxyType,
613    item: &TraitItemFn,
614    trait_def: &ItemTrait,
615    proxy_ty_param: &Ident,
616) -> syn::Result<TokenStream2> {
617    // If this method has a `#[auto_impl(keep_default_for(...))]` attribute for
618    // the given proxy type, we don't generate anything for this impl block.
619    if should_keep_default_for(item, proxy_type)? {
620        return if item.default.is_some() {
621            Ok(TokenStream2::new())
622        } else {
623            Err(Error::new(
624                item.sig.span(),
625                format_args!(
626                    "the method `{}` has the attribute `keep_default_for` but is not a default \
627                    method (no body is provided)",
628                    item.sig.ident
629                ),
630            ))
631        };
632    }
633
634    // Determine the kind of the method, determined by the self type.
635    let sig = &item.sig;
636    let self_arg = SelfType::from_sig(sig);
637    let attrs = filter_attrs(&item.attrs);
638
639    // Check self type and proxy type combination
640    check_receiver_compatible(proxy_type, self_arg, &trait_def.ident, sig.span())?;
641
642    // Generate the list of argument used to call the method.
643    let (inputs, args) = get_arg_list(sig.inputs.iter())?;
644
645    // Construct a signature we'll use to generate the proxy method impl
646    // This is _almost_ the same as the original, except we use the inputs constructed
647    // alongside the args. These may be slightly different than the original trait.
648    let sig = Signature {
649        constness: item.sig.constness,
650        asyncness: item.sig.asyncness,
651        unsafety: item.sig.unsafety,
652        abi: item.sig.abi.clone(),
653        fn_token: item.sig.fn_token,
654        ident: item.sig.ident.clone(),
655        generics: item.sig.generics.clone(),
656        paren_token: item.sig.paren_token,
657        inputs,
658        variadic: item.sig.variadic.clone(),
659        output: item.sig.output.clone(),
660    };
661
662    // Build the turbofish type parameters. We need to pass type parameters
663    // explicitly as they cannot be inferred in all cases (e.g. something like
664    // `mem::size_of`). However, we don't explicitly specify lifetime
665    // parameters. Most lifetime parameters are so called late-bound lifetimes
666    // (ones that stick to input parameters) and Rust prohibits us from
667    // specifying late-bound lifetimes explicitly (which is not a problem,
668    // because those can always be correctly inferred). It would be possible to
669    // explicitly specify early-bound lifetimes, but this is hardly useful.
670    // Early-bound lifetimes are lifetimes that are only attached to the return
671    // type. Something like:
672    //
673    //     fn foo<'a>() -> &'a i32
674    //
675    // It's hard to imagine how such a function would even work. So since those
676    // functions are really rare and special, we won't support them. In
677    // particular, for us to determine if a lifetime parameter is early- or
678    // late-bound would be *really* difficult.
679    //
680    // So we just specify type parameters. In the future, however, we need to
681    // add support for const parameters. But those are not remotely stable yet,
682    // so we can wait a bit still.
683    let generic_types = sig
684        .generics
685        .params
686        .iter()
687        .filter_map(|param| match param {
688            GenericParam::Type(param) => {
689                let name = &param.ident;
690                Some(quote! { #name , })
691            }
692            GenericParam::Const(param) => {
693                let name = &param.ident;
694                Some(quote! { #name , })
695            }
696            GenericParam::Lifetime(_) => None,
697        })
698        .collect::<TokenStream2>();
699
700    let generic_types = if generic_types.is_empty() {
701        generic_types
702    } else {
703        quote! { ::<#generic_types> }
704    };
705
706    // Generate the body of the function. This mainly depends on the self type,
707    // but also on the proxy type.
708    let fn_name = &sig.ident;
709    let await_token = sig.asyncness.map(|_| quote! { .await });
710
711    let body = match self_arg {
712        // Fn proxy types get a special treatment
713        _ if proxy_type.is_fn() => {
714            quote! { ({self})(#args) #await_token }
715        }
716
717        // No receiver
718        SelfType::None => {
719            // The proxy type is a reference, smart pointer or Box.
720            quote! { #proxy_ty_param::#fn_name #generic_types(#args) #await_token }
721        }
722
723        // Receiver `self` (by value)
724        SelfType::Value => {
725            // The proxy type is a Box.
726            quote! { #proxy_ty_param::#fn_name #generic_types(*self, #args) #await_token }
727        }
728
729        // `&self` or `&mut self` receiver
730        SelfType::Ref | SelfType::Mut => {
731            // The proxy type could be anything in the `Ref` case, and `&mut`
732            // or Box in the `Mut` case.
733            quote! { #proxy_ty_param::#fn_name #generic_types(self, #args) #await_token }
734        }
735    };
736
737    // Combine body with signature
738    Ok(quote! { #(#attrs)* #sig { #body }})
739}
740
741#[derive(Debug, Clone, Copy, PartialEq, Eq)]
742enum SelfType {
743    None,
744    Ref,
745    Mut,
746    Value,
747}
748
749impl SelfType {
750    fn from_sig(sig: &Signature) -> Self {
751        match sig.inputs.iter().next() {
752            Some(FnArg::Receiver(r)) => {
753                if r.reference.is_none() {
754                    SelfType::Value
755                } else if r.mutability.is_none() {
756                    SelfType::Ref
757                } else {
758                    SelfType::Mut
759                }
760            }
761            _ => SelfType::None,
762        }
763    }
764
765    fn as_str(&self) -> Option<&'static str> {
766        match *self {
767            SelfType::None => None,
768            SelfType::Ref => Some("&self"),
769            SelfType::Mut => Some("&mut self"),
770            SelfType::Value => Some("self"),
771        }
772    }
773}
774
775/// Checks if this method can be implemented for the given proxy type. If not,
776/// we will emit an error pointing to the method signature.
777fn check_receiver_compatible(
778    proxy_type: &ProxyType,
779    self_arg: SelfType,
780    trait_name: &Ident,
781    sig_span: Span2,
782) -> syn::Result<()> {
783    match (proxy_type, self_arg) {
784        (ProxyType::Ref, SelfType::Mut) | (ProxyType::Ref, SelfType::Value) => {
785            Err(Error::new(
786                sig_span,
787                format_args!("the trait `{}` cannot be auto-implemented for immutable references, because \
788                    this method has a `{}` receiver (only `&self` and no receiver are allowed)",
789                    trait_name,
790                    self_arg.as_str().unwrap()),
791            ))
792        }
793
794        (ProxyType::RefMut, SelfType::Value) => {
795            Err(Error::new(
796                sig_span,
797                format_args!("the trait `{}` cannot be auto-implemented for mutable references, because \
798                    this method has a `self` receiver (only `&self`, `&mut self` and no receiver are allowed)",
799                trait_name,)
800            ))
801        }
802
803        (ProxyType::Rc, SelfType::Mut)
804        | (ProxyType::Rc, SelfType::Value)
805        | (ProxyType::Arc, SelfType::Mut)
806        | (ProxyType::Arc, SelfType::Value) => {
807            let ptr_name = if *proxy_type == ProxyType::Rc {
808                "Rc"
809            } else {
810                "Arc"
811            };
812
813            Err(Error::new(
814                sig_span,
815                format_args!("the trait `{}` cannot be auto-implemented for {}, because \
816                    this method has a `{}` receiver (only `&self` and no receiver are allowed)",
817                    trait_name,
818                    ptr_name,
819                    self_arg.as_str().unwrap())
820            ))
821        }
822
823        (ProxyType::Fn, _) | (ProxyType::FnMut, _) | (ProxyType::FnOnce, _) => {
824            // The Fn-trait being compatible with the receiver was already
825            // checked before (in `gen_fn_type_for_trait()`).
826            Ok(())
827        }
828
829        _ => Ok(()) // All other combinations are fine
830    }
831}
832
833/// Generates a list of comma-separated arguments used to call the function.
834/// Currently, only simple names are valid and more complex pattern will lead
835/// to an error being emitted. `self` parameters are ignored.
836fn get_arg_list<'a>(
837    original_inputs: impl Iterator<Item = &'a FnArg>,
838) -> syn::Result<(Punctuated<FnArg, Token![,]>, TokenStream2)> {
839    let mut args = TokenStream2::new();
840    let mut inputs = Punctuated::new();
841
842    let mut r: Result<(), Error> = Ok(());
843    for arg in original_inputs {
844        match arg {
845            FnArg::Typed(arg) => {
846                // Make sure the argument pattern is a simple name. In
847                // principle, we could probably support patterns, but it's
848                // not that important now.
849                if let Pat::Ident(PatIdent {
850                    by_ref: _by_ref,
851                    mutability: _mutability,
852                    ident,
853                    subpat: None,
854                    attrs,
855                }) = &*arg.pat
856                {
857                    // Add name plus trailing comma to tokens
858                    args.append_all(quote! { #ident , });
859
860                    // Add an input argument that omits the `mut` and `ref` pattern bindings
861                    inputs.push(FnArg::Typed(PatType {
862                        attrs: arg.attrs.clone(),
863                        pat: Box::new(Pat::Ident(PatIdent {
864                            attrs: attrs.clone(),
865                            by_ref: None,
866                            mutability: None,
867                            ident: ident.clone(),
868                            subpat: None,
869                        })),
870                        colon_token: arg.colon_token,
871                        ty: arg.ty.clone(),
872                    }))
873                } else {
874                    let err = Error::new(
875                        arg.pat.span(), "argument patterns are not supported by #[auto-impl]; use a simple name like \"foo\" (but not `_`)"
876                    );
877
878                    if let Err(ref mut current_err) = r {
879                        current_err.combine(err);
880                    } else {
881                        r = Err(err);
882                    }
883
884                    continue;
885                }
886            }
887
888            // There is only one such argument. We handle it elsewhere and
889            // can ignore it here.
890            FnArg::Receiver(arg) => {
891                inputs.push(FnArg::Receiver(arg.clone()));
892            }
893        }
894    }
895
896    r.map(|_| (inputs, args))
897}
898
899/// Checks if the given method has the attribute `#[auto_impl(keep_default_for(...))]`
900/// and if it contains the given proxy type.
901fn should_keep_default_for(m: &TraitItemFn, proxy_type: &ProxyType) -> syn::Result<bool> {
902    // Get an iterator of just the attribute we are interested in.
903    let mut it = m
904        .attrs
905        .iter()
906        .filter(|attr| is_our_attr(attr))
907        .map(parse_our_attr);
908
909    // Check the first (and hopefully only) `keep_default_for` attribute.
910    let out = match it.next() {
911        Some(attr) => {
912            // Check if the attribute lists the given proxy type.
913            let OurAttr::KeepDefaultFor(proxy_types) = attr?;
914            proxy_types.contains(proxy_type)
915        }
916
917        // If there is no such attribute, we return `false`
918        None => false,
919    };
920
921    // Check if there is another such attribute (which we disallow)
922    if it.next().is_some() {
923        return Err(Error::new(
924            m.sig.span(),
925            "found two `keep_default_for` attributes on one method",
926        ));
927    }
928
929    Ok(out)
930}
931
932fn filter_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
933    attrs
934        .iter()
935        .filter(|attr| attr.path().is_ident("cfg"))
936        .cloned()
937        .collect()
938}