auto_impl/
gen.rs

1use proc_macro2::{Span as Span2, TokenStream as TokenStream2, TokenTree as TokenTree2};
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
250        // Pop a trailing comma if there is one
251        // We'll end up conditionally putting one back in shortly
252        if tts.last().and_then(|tt| {
253            if let TokenTree2::Punct(p) = tt {
254                Some(p.as_char())
255            } else {
256                None
257            }
258        }) == Some(',')
259        {
260            tts.pop();
261        }
262
263        params.append_all(&tts);
264
265        // Append proxy type parameter (if there aren't any parameters so far,
266        // we need to add a comma first).
267        let comma = if params.is_empty() || tts.is_empty() {
268            quote! {}
269        } else {
270            quote! { , }
271        };
272        params.append_all(quote! { #comma #proxy_ty_param #ty_bounds });
273
274        params
275    };
276
277    // The tokens after `for` in the impl header (the type the trait is
278    // implemented for).
279    #[rustfmt::skip]
280    let self_ty = match *proxy_type {
281        ProxyType::Ref      => quote! { & #proxy_lt_param #proxy_ty_param },
282        ProxyType::RefMut   => quote! { & #proxy_lt_param mut #proxy_ty_param },
283        ProxyType::Arc      => quote! { alloc::sync::Arc<#proxy_ty_param> },
284        ProxyType::Rc       => quote! { alloc::rc::Rc<#proxy_ty_param> },
285        ProxyType::Box      => quote! { alloc::boxed::Box<#proxy_ty_param> },
286        ProxyType::Fn       => quote! { #proxy_ty_param },
287        ProxyType::FnMut    => quote! { #proxy_ty_param },
288        ProxyType::FnOnce   => quote! { #proxy_ty_param },
289    };
290
291    // If the trait has super traits, we need to add the super trait bound to
292    // our self type. This can only be done in the where clause, so we need to
293    // combine the existing where clauses with our new predicate in that case.
294    let where_clause = if !trait_def.supertraits.is_empty() {
295        let mut out = quote! { where };
296
297        if !trait_def.supertraits.is_empty() {
298            let supertraits = &trait_def.supertraits;
299            out.extend(quote! { #self_ty: #supertraits, });
300        }
301        if let Some(predicates) = where_clause.map(|c| &c.predicates) {
302            out.extend(predicates.into_token_stream());
303        }
304
305        out
306    } else {
307        where_clause.into_token_stream()
308    };
309
310    // Combine everything
311    Ok(quote! {
312        impl<#impl_generics> #trait_path for #self_ty #where_clause
313    })
314}
315
316/// Generates the Fn-trait type (e.g. `FnMut(u32) -> String`) for the given
317/// trait and proxy type (the latter has to be `Fn`, `FnMut` or `FnOnce`!)
318///
319/// If the trait is unsuitable to be implemented for the given proxy type, an
320/// error is emitted.
321fn gen_fn_type_for_trait(
322    proxy_type: &ProxyType,
323    trait_def: &ItemTrait,
324) -> syn::Result<TokenStream2> {
325    // Only traits with exactly one method can be implemented for Fn-traits.
326    // Associated types and consts are also not allowed.
327    let method = trait_def.items.first().and_then(|item| {
328        if let TraitItem::Fn(m) = item {
329            Some(m)
330        } else {
331            None
332        }
333    });
334
335    // If this requirement is not satisfied, we emit an error.
336    if method.is_none() || trait_def.items.len() > 1 {
337        return Err(Error::new(
338            trait_def.span(),
339            "this trait cannot be auto-implemented for Fn-traits (only traits with exactly \
340                one method and no other items are allowed)",
341        ));
342    }
343
344    // We checked for `None` above
345    let method = method.unwrap();
346    let sig = &method.sig;
347
348    // Check for forbidden modifier of the method
349    if let Some(const_token) = sig.constness {
350        return Err(Error::new(
351            const_token.span(),
352            format_args!(
353                "the trait '{}' cannot be auto-implemented for Fn-traits: const methods are not \
354                allowed",
355                trait_def.ident
356            ),
357        ));
358    }
359
360    if let Some(unsafe_token) = &sig.unsafety {
361        return Err(Error::new(
362            unsafe_token.span(),
363            format_args!(
364                "the trait '{}' cannot be auto-implemented for Fn-traits: unsafe methods are not \
365                allowed",
366                trait_def.ident
367            ),
368        ));
369    }
370
371    if let Some(abi_token) = &sig.abi {
372        return Err(Error::new(
373            abi_token.span(),
374            format_args!(
375                "the trait '{}' cannot be implemented for Fn-traits: custom ABIs are not allowed",
376                trait_def.ident
377            ),
378        ));
379    }
380
381    // Function traits cannot support generics in their arguments
382    // These would require HRTB for types instead of just lifetimes
383    let mut r: syn::Result<()> = Ok(());
384    for type_param in sig.generics.type_params() {
385        let err = Error::new(
386            type_param.span(),
387            format_args!("the trait '{}' cannot be implemented for Fn-traits: generic 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
398    for const_param in sig.generics.const_params() {
399        let err = Error::new(
400            const_param.span(),
401            format_args!("the trait '{}' cannot be implemented for Fn-traits: constant arguments are not allowed",
402            trait_def.ident),
403        );
404
405        if let Err(ref mut current_err) = r {
406            current_err.combine(err);
407        } else {
408            r = Err(err);
409        }
410    }
411    r?;
412
413    // =======================================================================
414    // Check if the trait can be implemented for the given proxy type
415    let self_type = SelfType::from_sig(sig);
416    let err = match (self_type, proxy_type) {
417        // The method needs to have a receiver
418        (SelfType::None, _) => Some(("Fn-traits", "no", "")),
419
420        // We can't impl methods with `&mut self` or `&self` receiver for
421        // `FnOnce`
422        (SelfType::Mut, ProxyType::FnOnce) => {
423            Some(("`FnOnce`", "a `&mut self`", " (only `self` is allowed)"))
424        }
425        (SelfType::Ref, ProxyType::FnOnce) => {
426            Some(("`FnOnce`", "a `&self`", " (only `self` is allowed)"))
427        }
428
429        // We can't impl methods with `&self` receiver for `FnMut`
430        (SelfType::Ref, ProxyType::FnMut) => Some((
431            "`FnMut`",
432            "a `&self`",
433            " (only `self` and `&mut self` are allowed)",
434        )),
435
436        // Other combinations are fine
437        _ => None,
438    };
439
440    if let Some((fn_traits, receiver, allowed)) = err {
441        return Err(Error::new(
442            method.sig.span(),
443            format_args!(
444                "the trait '{}' cannot be auto-implemented for {}, because this method has \
445                {} receiver{}",
446                trait_def.ident, fn_traits, receiver, allowed,
447            ),
448        ));
449    }
450
451    // =======================================================================
452    // Generate the full Fn-type
453
454    // The path to the Fn-trait
455    let fn_name = match proxy_type {
456        ProxyType::Fn => quote! { ::core::ops::Fn },
457        ProxyType::FnMut => quote! { ::core::ops::FnMut },
458        ProxyType::FnOnce => quote! { ::core::ops::FnOnce },
459        _ => panic!("internal error in auto_impl (function contract violation)"),
460    };
461
462    // The return type
463    let ret = &sig.output;
464
465    // Now it gets a bit complicated. The types of the function signature
466    // could contain "local" lifetimes, meaning that they are not declared in
467    // the trait definition (or are `'static`). We need to extract all local
468    // lifetimes to declare them with HRTB (e.g. `for<'a>`).
469    //
470    // In Rust 2015 that was easy: we could just take the lifetimes explicitly
471    // declared in the function signature. Those were the local lifetimes.
472    // Unfortunately, with in-band lifetimes, things get more complicated. We
473    // need to take a look at all lifetimes inside the types (arbitrarily deep)
474    // and check if they are local or not.
475    //
476    // In cases where lifetimes are omitted (e.g. `&str`), we don't have a
477    // problem. If we just translate that to `for<> Fn(&str)`, it's fine: all
478    // omitted lifetimes in an `Fn()` type are automatically declared as HRTB.
479    //
480    // TODO: Implement this check for in-band lifetimes!
481    let local_lifetimes = sig.generics.lifetimes();
482
483    // The input types as comma separated list. We skip the first argument, as
484    // this is the receiver argument.
485    let mut arg_types = TokenStream2::new();
486    for arg in sig.inputs.iter().skip(1) {
487        match arg {
488            FnArg::Typed(pat) => {
489                let ty = &pat.ty;
490                arg_types.append_all(quote! { #ty , });
491            }
492
493            // We skipped the receiver already.
494            FnArg::Receiver(r) => {
495                return Err(Error::new(
496                    r.span(),
497                    "receiver argument that's not the first argument (auto_impl is confused)",
498                ));
499            }
500        }
501    }
502
503    Ok(quote! {
504        for< #(#local_lifetimes),* > #fn_name (#arg_types) #ret
505    })
506}
507
508/// Generates the implementation of all items of the given trait. These
509/// implementations together are the body of the `impl` block.
510fn gen_items(
511    proxy_type: &ProxyType,
512    trait_def: &ItemTrait,
513    proxy_ty_param: &Ident,
514) -> syn::Result<Vec<TokenStream2>> {
515    trait_def
516        .items
517        .iter()
518        .map(|item| {
519            match item {
520                TraitItem::Const(c) => gen_const_item(proxy_type, c, trait_def, proxy_ty_param),
521                TraitItem::Fn(method) => {
522                    gen_method_item(proxy_type, method, trait_def, proxy_ty_param)
523                }
524                TraitItem::Type(ty) => gen_type_item(proxy_type, ty, trait_def, proxy_ty_param),
525                TraitItem::Macro(mac) => {
526                    // We cannot resolve the macro invocation and thus cannot know
527                    // if it adds additional items to the trait. Thus, we have to
528                    // give up.
529                    Err(Error::new(
530                        mac.span(),
531                        "traits with macro invocations in their bodies are not \
532                        supported by auto_impl",
533                    ))
534                }
535                TraitItem::Verbatim(v) => {
536                    // I don't quite know when this happens, but it's better to
537                    // notify the user with a nice error instead of panicking.
538                    Err(Error::new(
539                        v.span(),
540                        "unexpected 'verbatim'-item (auto-impl doesn't know how to handle it)",
541                    ))
542                }
543                _ => {
544                    // `syn` enums are `non_exhaustive` to be future-proof. If a
545                    // trait contains a kind of item we don't even know about, we
546                    // emit an error.
547                    Err(Error::new(
548                        item.span(),
549                        "unknown trait item (auto-impl doesn't know how to handle it)",
550                    ))
551                }
552            }
553        })
554        .collect()
555}
556
557/// Generates the implementation of an associated const item described by
558/// `item`. The implementation is returned as token stream.
559///
560/// If the proxy type is an Fn*-trait, an error is emitted and `Err(())` is
561/// returned.
562fn gen_const_item(
563    proxy_type: &ProxyType,
564    item: &TraitItemConst,
565    trait_def: &ItemTrait,
566    proxy_ty_param: &Ident,
567) -> syn::Result<TokenStream2> {
568    // A trait with associated consts cannot be implemented for Fn* types.
569    if proxy_type.is_fn() {
570        return Err(Error::new(
571            item.span(),
572            format_args!("the trait `{}` cannot be auto-implemented for Fn-traits, because it has \
573                associated consts (only traits with a single method can be implemented for Fn-traits)",
574            trait_def.ident)
575        ));
576    }
577
578    // We simply use the associated const from our type parameter.
579    let const_name = &item.ident;
580    let const_ty = &item.ty;
581    let attrs = filter_attrs(&item.attrs);
582
583    Ok(quote! {
584        #(#attrs)* const #const_name: #const_ty = #proxy_ty_param::#const_name;
585    })
586}
587
588/// Generates the implementation of an associated type item described by `item`.
589/// The implementation is returned as token stream.
590///
591/// If the proxy type is an Fn*-trait, an error is emitted and `Err(())` is
592/// returned.
593fn gen_type_item(
594    proxy_type: &ProxyType,
595    item: &TraitItemType,
596    trait_def: &ItemTrait,
597    proxy_ty_param: &Ident,
598) -> syn::Result<TokenStream2> {
599    // A trait with associated types cannot be implemented for Fn* types.
600    if proxy_type.is_fn() {
601        return Err(Error::new(
602            item.span(),
603            format_args!("the trait `{}` cannot be auto-implemented for Fn-traits, because it has \
604                associated types (only traits with a single method can be implemented for Fn-traits)",
605                trait_def.ident)
606        ));
607    }
608
609    // We simply use the associated type from our type parameter.
610    let assoc_name = &item.ident;
611    let attrs = filter_attrs(&item.attrs);
612    let generics = &item.generics;
613
614    Ok(quote! {
615        #(#attrs)* type #assoc_name #generics = #proxy_ty_param::#assoc_name #generics;
616    })
617}
618
619/// Generates the implementation of a method item described by `item`. The
620/// implementation is returned as token stream.
621///
622/// This function also performs sanity checks, e.g. whether the proxy type can
623/// be used to implement the method. If any error occurs, the error is
624/// immediately emitted and `Err(())` is returned.
625fn gen_method_item(
626    proxy_type: &ProxyType,
627    item: &TraitItemFn,
628    trait_def: &ItemTrait,
629    proxy_ty_param: &Ident,
630) -> syn::Result<TokenStream2> {
631    // If this method has a `#[auto_impl(keep_default_for(...))]` attribute for
632    // the given proxy type, we don't generate anything for this impl block.
633    if should_keep_default_for(item, proxy_type)? {
634        return if item.default.is_some() {
635            Ok(TokenStream2::new())
636        } else {
637            Err(Error::new(
638                item.sig.span(),
639                format_args!(
640                    "the method `{}` has the attribute `keep_default_for` but is not a default \
641                    method (no body is provided)",
642                    item.sig.ident
643                ),
644            ))
645        };
646    }
647
648    // Determine the kind of the method, determined by the self type.
649    let sig = &item.sig;
650    let self_arg = SelfType::from_sig(sig);
651    let attrs = filter_attrs(&item.attrs);
652
653    // Check self type and proxy type combination
654    check_receiver_compatible(proxy_type, self_arg, &trait_def.ident, sig.span())?;
655
656    // Generate the list of argument used to call the method.
657    let (inputs, args) = get_arg_list(sig.inputs.iter())?;
658
659    // Construct a signature we'll use to generate the proxy method impl
660    // This is _almost_ the same as the original, except we use the inputs constructed
661    // alongside the args. These may be slightly different than the original trait.
662    let sig = Signature {
663        constness: item.sig.constness,
664        asyncness: item.sig.asyncness,
665        unsafety: item.sig.unsafety,
666        abi: item.sig.abi.clone(),
667        fn_token: item.sig.fn_token,
668        ident: item.sig.ident.clone(),
669        generics: item.sig.generics.clone(),
670        paren_token: item.sig.paren_token,
671        inputs,
672        variadic: item.sig.variadic.clone(),
673        output: item.sig.output.clone(),
674    };
675
676    // Build the turbofish type parameters. We need to pass type parameters
677    // explicitly as they cannot be inferred in all cases (e.g. something like
678    // `mem::size_of`). However, we don't explicitly specify lifetime
679    // parameters. Most lifetime parameters are so called late-bound lifetimes
680    // (ones that stick to input parameters) and Rust prohibits us from
681    // specifying late-bound lifetimes explicitly (which is not a problem,
682    // because those can always be correctly inferred). It would be possible to
683    // explicitly specify early-bound lifetimes, but this is hardly useful.
684    // Early-bound lifetimes are lifetimes that are only attached to the return
685    // type. Something like:
686    //
687    //     fn foo<'a>() -> &'a i32
688    //
689    // It's hard to imagine how such a function would even work. So since those
690    // functions are really rare and special, we won't support them. In
691    // particular, for us to determine if a lifetime parameter is early- or
692    // late-bound would be *really* difficult.
693    //
694    // So we just specify type parameters. In the future, however, we need to
695    // add support for const parameters. But those are not remotely stable yet,
696    // so we can wait a bit still.
697    let generic_types = sig
698        .generics
699        .params
700        .iter()
701        .filter_map(|param| match param {
702            GenericParam::Type(param) => {
703                let name = &param.ident;
704                Some(quote! { #name , })
705            }
706            GenericParam::Const(param) => {
707                let name = &param.ident;
708                Some(quote! { #name , })
709            }
710            GenericParam::Lifetime(_) => None,
711        })
712        .collect::<TokenStream2>();
713
714    let generic_types = if generic_types.is_empty() {
715        generic_types
716    } else {
717        quote! { ::<#generic_types> }
718    };
719
720    // Generate the body of the function. This mainly depends on the self type,
721    // but also on the proxy type.
722    let fn_name = &sig.ident;
723    let await_token = sig.asyncness.map(|_| quote! { .await });
724
725    let body = match self_arg {
726        // Fn proxy types get a special treatment
727        _ if proxy_type.is_fn() => {
728            quote! { ({self})(#args) #await_token }
729        }
730
731        // No receiver
732        SelfType::None => {
733            // The proxy type is a reference, smart pointer or Box.
734            quote! { #proxy_ty_param::#fn_name #generic_types(#args) #await_token }
735        }
736
737        // Receiver `self` (by value)
738        SelfType::Value => {
739            // The proxy type is a Box.
740            quote! { #proxy_ty_param::#fn_name #generic_types(*self, #args) #await_token }
741        }
742
743        // `&self` or `&mut self` receiver
744        SelfType::Ref | SelfType::Mut => {
745            // The proxy type could be anything in the `Ref` case, and `&mut`
746            // or Box in the `Mut` case.
747            quote! { #proxy_ty_param::#fn_name #generic_types(self, #args) #await_token }
748        }
749    };
750
751    // Combine body with signature
752    Ok(quote! { #(#attrs)* #sig { #body }})
753}
754
755#[derive(Debug, Clone, Copy, PartialEq, Eq)]
756enum SelfType {
757    None,
758    Ref,
759    Mut,
760    Value,
761}
762
763impl SelfType {
764    fn from_sig(sig: &Signature) -> Self {
765        match sig.inputs.iter().next() {
766            Some(FnArg::Receiver(r)) => {
767                if r.reference.is_none() {
768                    SelfType::Value
769                } else if r.mutability.is_none() {
770                    SelfType::Ref
771                } else {
772                    SelfType::Mut
773                }
774            }
775            _ => SelfType::None,
776        }
777    }
778
779    fn as_str(&self) -> Option<&'static str> {
780        match *self {
781            SelfType::None => None,
782            SelfType::Ref => Some("&self"),
783            SelfType::Mut => Some("&mut self"),
784            SelfType::Value => Some("self"),
785        }
786    }
787}
788
789/// Checks if this method can be implemented for the given proxy type. If not,
790/// we will emit an error pointing to the method signature.
791fn check_receiver_compatible(
792    proxy_type: &ProxyType,
793    self_arg: SelfType,
794    trait_name: &Ident,
795    sig_span: Span2,
796) -> syn::Result<()> {
797    match (proxy_type, self_arg) {
798        (ProxyType::Ref, SelfType::Mut) | (ProxyType::Ref, SelfType::Value) => {
799            Err(Error::new(
800                sig_span,
801                format_args!("the trait `{}` cannot be auto-implemented for immutable references, because \
802                    this method has a `{}` receiver (only `&self` and no receiver are allowed)",
803                    trait_name,
804                    self_arg.as_str().unwrap()),
805            ))
806        }
807
808        (ProxyType::RefMut, SelfType::Value) => {
809            Err(Error::new(
810                sig_span,
811                format_args!("the trait `{}` cannot be auto-implemented for mutable references, because \
812                    this method has a `self` receiver (only `&self`, `&mut self` and no receiver are allowed)",
813                trait_name,)
814            ))
815        }
816
817        (ProxyType::Rc, SelfType::Mut)
818        | (ProxyType::Rc, SelfType::Value)
819        | (ProxyType::Arc, SelfType::Mut)
820        | (ProxyType::Arc, SelfType::Value) => {
821            let ptr_name = if *proxy_type == ProxyType::Rc {
822                "Rc"
823            } else {
824                "Arc"
825            };
826
827            Err(Error::new(
828                sig_span,
829                format_args!("the trait `{}` cannot be auto-implemented for {}, because \
830                    this method has a `{}` receiver (only `&self` and no receiver are allowed)",
831                    trait_name,
832                    ptr_name,
833                    self_arg.as_str().unwrap())
834            ))
835        }
836
837        (ProxyType::Fn, _) | (ProxyType::FnMut, _) | (ProxyType::FnOnce, _) => {
838            // The Fn-trait being compatible with the receiver was already
839            // checked before (in `gen_fn_type_for_trait()`).
840            Ok(())
841        }
842
843        _ => Ok(()) // All other combinations are fine
844    }
845}
846
847/// Generates a list of comma-separated arguments used to call the function.
848/// Currently, only simple names are valid and more complex pattern will lead
849/// to an error being emitted. `self` parameters are ignored.
850fn get_arg_list<'a>(
851    original_inputs: impl Iterator<Item = &'a FnArg>,
852) -> syn::Result<(Punctuated<FnArg, Token![,]>, TokenStream2)> {
853    let mut args = TokenStream2::new();
854    let mut inputs = Punctuated::new();
855
856    let mut r: Result<(), Error> = Ok(());
857    for arg in original_inputs {
858        match arg {
859            FnArg::Typed(arg) => {
860                // Make sure the argument pattern is a simple name. In
861                // principle, we could probably support patterns, but it's
862                // not that important now.
863                if let Pat::Ident(PatIdent {
864                    by_ref: _by_ref,
865                    mutability: _mutability,
866                    ident,
867                    subpat: None,
868                    attrs,
869                }) = &*arg.pat
870                {
871                    // Add name plus trailing comma to tokens
872                    args.append_all(quote! { #ident , });
873
874                    // Add an input argument that omits the `mut` and `ref` pattern bindings
875                    inputs.push(FnArg::Typed(PatType {
876                        attrs: arg.attrs.clone(),
877                        pat: Box::new(Pat::Ident(PatIdent {
878                            attrs: attrs.clone(),
879                            by_ref: None,
880                            mutability: None,
881                            ident: ident.clone(),
882                            subpat: None,
883                        })),
884                        colon_token: arg.colon_token,
885                        ty: arg.ty.clone(),
886                    }))
887                } else {
888                    let err = Error::new(
889                        arg.pat.span(), "argument patterns are not supported by #[auto-impl]; use a simple name like \"foo\" (but not `_`)"
890                    );
891
892                    if let Err(ref mut current_err) = r {
893                        current_err.combine(err);
894                    } else {
895                        r = Err(err);
896                    }
897
898                    continue;
899                }
900            }
901
902            // There is only one such argument. We handle it elsewhere and
903            // can ignore it here.
904            FnArg::Receiver(arg) => {
905                inputs.push(FnArg::Receiver(arg.clone()));
906            }
907        }
908    }
909
910    r.map(|_| (inputs, args))
911}
912
913/// Checks if the given method has the attribute `#[auto_impl(keep_default_for(...))]`
914/// and if it contains the given proxy type.
915fn should_keep_default_for(m: &TraitItemFn, proxy_type: &ProxyType) -> syn::Result<bool> {
916    // Get an iterator of just the attribute we are interested in.
917    let mut it = m
918        .attrs
919        .iter()
920        .filter(|attr| is_our_attr(attr))
921        .map(parse_our_attr);
922
923    // Check the first (and hopefully only) `keep_default_for` attribute.
924    let out = match it.next() {
925        Some(attr) => {
926            // Check if the attribute lists the given proxy type.
927            let OurAttr::KeepDefaultFor(proxy_types) = attr?;
928            proxy_types.contains(proxy_type)
929        }
930
931        // If there is no such attribute, we return `false`
932        None => false,
933    };
934
935    // Check if there is another such attribute (which we disallow)
936    if it.next().is_some() {
937        return Err(Error::new(
938            m.sig.span(),
939            "found two `keep_default_for` attributes on one method",
940        ));
941    }
942
943    Ok(out)
944}
945
946fn filter_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
947    attrs
948        .iter()
949        .filter(|attr| attr.path().is_ident("cfg"))
950        .cloned()
951        .collect()
952}