auto_impl/
gen.rs

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