auto_impl/
gen.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
use proc_macro2::{Span as Span2, TokenStream as TokenStream2};
use proc_macro_error::{abort, emit_error};
use quote::{ToTokens, TokenStreamExt};
use syn::{
    punctuated::Punctuated, spanned::Spanned, Attribute, FnArg, GenericParam, Ident, ItemTrait,
    Lifetime, Pat, PatIdent, PatType, ReturnType, Signature, Token, TraitBound, TraitBoundModifier,
    TraitItem, TraitItemConst, TraitItemMethod, TraitItemType, Type, TypeParamBound,
    WherePredicate,
};

use crate::{
    analyze::find_suitable_param_names,
    attr::{is_our_attr, parse_our_attr, OurAttr},
    proxy::ProxyType,
};

/// Generates one complete impl of the given trait for each of the given proxy
/// types. All impls are returned as token stream.
pub(crate) fn gen_impls(proxy_types: &[ProxyType], trait_def: &syn::ItemTrait) -> TokenStream2 {
    let mut tokens = TokenStream2::new();

    let (proxy_ty_param, proxy_lt_param) = find_suitable_param_names(trait_def);

    // One impl for each proxy type
    for proxy_type in proxy_types {
        let header = gen_header(proxy_type, trait_def, &proxy_ty_param, &proxy_lt_param);
        let items = gen_items(proxy_type, trait_def, &proxy_ty_param);

        if let ProxyType::Box | ProxyType::Rc | ProxyType::Arc = proxy_type {
            tokens.append_all(quote! {
                const _: () = {
                    extern crate alloc;
                    #header { #( #items )* }
                };
            });
        } else {
            tokens.append_all(quote! {
                const _: () = {
                    #header { #( #items )* }
                };
            });
        }
    }

    tokens
}

/// Generates the header of the impl of the given trait for the given proxy
/// type.
fn gen_header(
    proxy_type: &ProxyType,
    trait_def: &ItemTrait,
    proxy_ty_param: &Ident,
    proxy_lt_param: &Lifetime,
) -> TokenStream2 {
    // Generate generics for impl positions from trait generics.
    let (impl_generics, trait_generics, where_clause) = trait_def.generics.split_for_impl();

    // The name of the trait with all generic parameters applied.
    let trait_ident = &trait_def.ident;
    let trait_path = quote! { #trait_ident #trait_generics };

    // Here we assemble the parameter list of the impl (the thing in
    // `impl< ... >`). This is simply the parameter list of the trait with
    // one or two parameters added. For a trait `trait Foo<'x, 'y, A, B>`,
    // it will look like this:
    //
    //    '{proxy_lt_param}, 'x, 'y, A, B, {proxy_ty_param}
    //
    // The `'{proxy_lt_param}` in the beginning is only added when the proxy
    // type is `&` or `&mut`.
    let impl_generics = {
        // Determine whether we can add a `?Sized` relaxation to allow trait
        // objects. We can do that as long as there is no method that has a
        // `self` by value receiver and no `where Self: Sized` bound.
        let sized_required = trait_def
            .items
            .iter()
            // Only interested in methods
            .filter_map(|item| {
                if let TraitItem::Method(m) = item {
                    Some(m)
                } else {
                    None
                }
            })
            // We also ignore methods that we will not override. In the case of
            // invalid attributes it is save to assume default behavior.
            .filter(|m| !should_keep_default_for(m, proxy_type))
            .any(|m| {
                // Check if there is a `Self: Sized` bound on the method.
                let self_is_bounded_sized = m
                    .sig
                    .generics
                    .where_clause
                    .iter()
                    .flat_map(|wc| &wc.predicates)
                    .filter_map(|pred| {
                        if let WherePredicate::Type(p) = pred {
                            Some(p)
                        } else {
                            None
                        }
                    })
                    .any(|pred| {
                        // Check if the type is `Self`
                        match &pred.bounded_ty {
                            Type::Path(p) if p.path.is_ident("Self") => {
                                // Check if the bound contains `Sized`
                                pred.bounds.iter().any(|b| match b {
                                    TypeParamBound::Trait(TraitBound {
                                        modifier: TraitBoundModifier::None,
                                        path,
                                        ..
                                    }) => path.is_ident("Sized"),
                                    _ => false,
                                })
                            }
                            _ => false,
                        }
                    });

                // Check if the first parameter is `self` by value. In that
                // case, we might require `Self` to be `Sized`.
                let self_value_param = match m.sig.inputs.first() {
                    Some(FnArg::Receiver(receiver)) => receiver.reference.is_none(),
                    _ => false,
                };

                // Check if return type is `Self`
                let self_value_return = match &m.sig.output {
                    ReturnType::Type(_, t) => {
                        if let Type::Path(p) = &**t {
                            p.path.is_ident("Self")
                        } else {
                            false
                        }
                    }
                    _ => false,
                };

                // TODO: check for `Self` parameter in any other argument.

                // If for this method, `Self` is used in a position that
                // requires `Self: Sized` or this bound is added explicitly, we
                // cannot add the `?Sized` relaxation to the impl body.
                self_value_param || self_value_return || self_is_bounded_sized
            });

        let relaxation = if sized_required {
            quote! {}
        } else {
            quote! { + ?::core::marker::Sized }
        };

        // Check if there are some `Self: Foo` bounds on methods. If so, we
        // need to add those bounds to `T` as well. See issue #11 for more
        // information, but in short: there is no better solution. Method where
        // clauses with `Self: Foo` force us to add `T: Foo` to the impl
        // header, as we otherwise cannot generate a valid impl block.
        let additional_bounds = trait_def
            .items
            .iter()
            // Only interested in methods
            .filter_map(|item| {
                if let TraitItem::Method(m) = item {
                    Some(m)
                } else {
                    None
                }
            })
            // We also ignore methods that we will not override. In the case of
            // invalid attributes it is save to assume default behavior.
            .filter(|m| !should_keep_default_for(m, proxy_type))
            // Exact all relevant bounds
            .flat_map(|m| {
                m.sig
                    .generics
                    .where_clause
                    .iter()
                    .flat_map(|wc| &wc.predicates)
                    .filter_map(|pred| {
                        if let WherePredicate::Type(p) = pred {
                            Some(p)
                        } else {
                            None
                        }
                    })
                    .filter(|p| {
                        // Only `Self:` bounds
                        match &p.bounded_ty {
                            Type::Path(p) => p.path.is_ident("Self"),
                            _ => false,
                        }
                    })
                    .flat_map(|p| &p.bounds)
                    .filter_map(|b| {
                        // We are only interested in trait bounds. That's
                        // because lifetime bounds on `Self` do not need to be
                        // added to the impl header. That's because all values
                        // "derived" from `self` also meet the same lifetime
                        // bound as `self`. In simpler terms: while `self.field`
                        // might not be `Clone` even if `Self: Clone`,
                        // `self.field` is always `: 'a` if `Self: 'a`.
                        match b {
                            TypeParamBound::Trait(t) => Some(t),
                            TypeParamBound::Lifetime(_) => None,
                        }
                    })
            });

        // Determine if our proxy type needs a lifetime parameter
        let (mut params, ty_bounds) = match proxy_type {
            ProxyType::Ref | ProxyType::RefMut => (
                quote! { #proxy_lt_param, },
                quote! { : #proxy_lt_param + #trait_path #relaxation #(+ #additional_bounds)* },
            ),
            ProxyType::Box | ProxyType::Rc | ProxyType::Arc => (
                quote! {},
                quote! { : #trait_path #relaxation #(+ #additional_bounds)* },
            ),
            ProxyType::Fn | ProxyType::FnMut | ProxyType::FnOnce => {
                let fn_bound = gen_fn_type_for_trait(proxy_type, trait_def);
                (quote! {}, quote! { : #fn_bound })
            }
        };

        // Append all parameters from the trait. Sadly, `impl_generics`
        // includes the angle brackets `< >` so we have to remove them like
        // this.
        let mut tts = impl_generics
            .into_token_stream()
            .into_iter()
            .skip(1) // the opening `<`
            .collect::<Vec<_>>();
        tts.pop(); // the closing `>`
        params.append_all(&tts);

        // Append proxy type parameter (if there aren't any parameters so far,
        // we need to add a comma first).
        let comma = if params.is_empty() || tts.is_empty() {
            quote! {}
        } else {
            quote! { , }
        };
        params.append_all(quote! { #comma #proxy_ty_param #ty_bounds });

        params
    };

    // The tokens after `for` in the impl header (the type the trait is
    // implemented for).
    #[rustfmt::skip]
    let self_ty = match *proxy_type {
        ProxyType::Ref      => quote! { & #proxy_lt_param #proxy_ty_param },
        ProxyType::RefMut   => quote! { & #proxy_lt_param mut #proxy_ty_param },
        ProxyType::Arc      => quote! { alloc::sync::Arc<#proxy_ty_param> },
        ProxyType::Rc       => quote! { alloc::rc::Rc<#proxy_ty_param> },
        ProxyType::Box      => quote! { alloc::boxed::Box<#proxy_ty_param> },
        ProxyType::Fn       => quote! { #proxy_ty_param },
        ProxyType::FnMut    => quote! { #proxy_ty_param },
        ProxyType::FnOnce   => quote! { #proxy_ty_param },
    };

    // If the trait has super traits, we need to add the super trait bound to
    // our self type. This can only be done in the where clause, so we need to
    // combine the existing where clauses with our new predicate in that case.
    let where_clause = if !trait_def.supertraits.is_empty() {
        let mut out = quote! { where };

        if !trait_def.supertraits.is_empty() {
            let supertraits = &trait_def.supertraits;
            out.extend(quote! { #self_ty: #supertraits, });
        }
        if let Some(predicates) = where_clause.map(|c| &c.predicates) {
            out.extend(predicates.into_token_stream());
        }

        out
    } else {
        where_clause.into_token_stream()
    };

    // Combine everything
    quote! {
        impl<#impl_generics> #trait_path for #self_ty #where_clause
    }
}

/// Generates the Fn-trait type (e.g. `FnMut(u32) -> String`) for the given
/// trait and proxy type (the latter has to be `Fn`, `FnMut` or `FnOnce`!)
///
/// If the trait is unsuitable to be implemented for the given proxy type, an
/// error is emitted.
fn gen_fn_type_for_trait(proxy_type: &ProxyType, trait_def: &ItemTrait) -> TokenStream2 {
    // Only traits with exactly one method can be implemented for Fn-traits.
    // Associated types and consts are also not allowed.
    let method = trait_def.items.get(0).and_then(|item| {
        if let TraitItem::Method(m) = item {
            Some(m)
        } else {
            None
        }
    });

    // If this requirement is not satisfied, we emit an error.
    if method.is_none() || trait_def.items.len() > 1 {
        emit_error!(
            trait_def.span(),
            "this trait cannot be auto-implemented for Fn-traits (only traits with exactly \
                one method and no other items are allowed)",
        );
        return TokenStream2::new();
    }

    // We checked for `None` above
    let method = method.unwrap();
    let sig = &method.sig;

    // Check for forbidden modifier of the method
    if let Some(const_token) = sig.constness {
        emit_error!(
            const_token.span(),
            "the trait '{}' cannot be auto-implemented for Fn-traits: const methods are not \
                allowed",
            trait_def.ident,
        );
    }

    if let Some(unsafe_token) = &sig.unsafety {
        emit_error!(
            unsafe_token.span(),
            "the trait '{}' cannot be auto-implemented for Fn-traits: unsafe methods are not \
                allowed",
            trait_def.ident,
        );
    }

    if let Some(abi_token) = &sig.abi {
        emit_error!(
            abi_token.span(),
            "the trait '{}' cannot be implemented for Fn-traits: custom ABIs are not allowed",
            trait_def.ident,
        );
    }

    // Function traits cannot support generics in their arguments
    // These would require HRTB for types instead of just lifetimes
    for type_param in sig.generics.type_params() {
        emit_error!(
            type_param.span(),
            "the trait '{}' cannot be implemented for Fn-traits: generic arguments are not allowed",
            trait_def.ident,
        );
    }

    for const_param in sig.generics.const_params() {
        emit_error!(
            const_param.span(),
            "the trait '{}' cannot be implemented for Fn-traits: constant arguments are not allowed",
            trait_def.ident,
        );
    }

    // =======================================================================
    // Check if the trait can be implemented for the given proxy type
    let self_type = SelfType::from_sig(sig);
    let err = match (self_type, proxy_type) {
        // The method needs to have a receiver
        (SelfType::None, _) => Some(("Fn-traits", "no", "")),

        // We can't impl methods with `&mut self` or `&self` receiver for
        // `FnOnce`
        (SelfType::Mut, ProxyType::FnOnce) => {
            Some(("`FnOnce`", "a `&mut self`", " (only `self` is allowed)"))
        }
        (SelfType::Ref, ProxyType::FnOnce) => {
            Some(("`FnOnce`", "a `&self`", " (only `self` is allowed)"))
        }

        // We can't impl methods with `&self` receiver for `FnMut`
        (SelfType::Ref, ProxyType::FnMut) => Some((
            "`FnMut`",
            "a `&self`",
            " (only `self` and `&mut self` are allowed)",
        )),

        // Other combinations are fine
        _ => None,
    };

    if let Some((fn_traits, receiver, allowed)) = err {
        emit_error!(
            method.sig.span(),
            "the trait '{}' cannot be auto-implemented for {}, because this method has \
                {} receiver{}",
            trait_def.ident,
            fn_traits,
            receiver,
            allowed,
        );

        return TokenStream2::new();
    }

    // =======================================================================
    // Generate the full Fn-type

    // The path to the Fn-trait
    let fn_name = match proxy_type {
        ProxyType::Fn => quote! { ::core::ops::Fn },
        ProxyType::FnMut => quote! { ::core::ops::FnMut },
        ProxyType::FnOnce => quote! { ::core::ops::FnOnce },
        _ => panic!("internal error in auto_impl (function contract violation)"),
    };

    // The return type
    let ret = &sig.output;

    // Now it gets a bit complicated. The types of the function signature
    // could contain "local" lifetimes, meaning that they are not declared in
    // the trait definition (or are `'static`). We need to extract all local
    // lifetimes to declare them with HRTB (e.g. `for<'a>`).
    //
    // In Rust 2015 that was easy: we could just take the lifetimes explicitly
    // declared in the function signature. Those were the local lifetimes.
    // Unfortunately, with in-band lifetimes, things get more complicated. We
    // need to take a look at all lifetimes inside the types (arbitrarily deep)
    // and check if they are local or not.
    //
    // In cases where lifetimes are omitted (e.g. `&str`), we don't have a
    // problem. If we just translate that to `for<> Fn(&str)`, it's fine: all
    // omitted lifetimes in an `Fn()` type are automatically declared as HRTB.
    //
    // TODO: Implement this check for in-band lifetimes!
    let local_lifetimes = sig.generics.lifetimes();

    // The input types as comma separated list. We skip the first argument, as
    // this is the receiver argument.
    let mut arg_types = TokenStream2::new();
    for arg in sig.inputs.iter().skip(1) {
        match arg {
            FnArg::Typed(pat) => {
                let ty = &pat.ty;
                arg_types.append_all(quote! { #ty , });
            }

            // We skipped the receiver already.
            FnArg::Receiver(r) => {
                abort!(
                    r.span(),
                    "receiver argument that's not the first argument (auto_impl is confused)",
                );
            }
        }
    }

    quote! {
        for< #(#local_lifetimes),* > #fn_name (#arg_types) #ret
    }
}

/// Generates the implementation of all items of the given trait. These
/// implementations together are the body of the `impl` block.
fn gen_items(
    proxy_type: &ProxyType,
    trait_def: &ItemTrait,
    proxy_ty_param: &Ident,
) -> Vec<TokenStream2> {
    trait_def
        .items
        .iter()
        .filter_map(|item| {
            match item {
                TraitItem::Const(c) => {
                    gen_const_item(proxy_type, c, trait_def, proxy_ty_param).ok()
                }
                TraitItem::Method(method) => {
                    gen_method_item(proxy_type, method, trait_def, proxy_ty_param).ok()
                }
                TraitItem::Type(ty) => {
                    gen_type_item(proxy_type, ty, trait_def, proxy_ty_param).ok()
                }
                TraitItem::Macro(mac) => {
                    // We cannot resolve the macro invocation and thus cannot know
                    // if it adds additional items to the trait. Thus, we have to
                    // give up.
                    emit_error!(
                        mac.span(),
                        "traits with macro invocations in their bodies are not \
                        supported by auto_impl",
                    );
                    None
                }
                TraitItem::Verbatim(v) => {
                    // I don't quite know when this happens, but it's better to
                    // notify the user with a nice error instead of panicking.
                    emit_error!(
                        v.span(),
                        "unexpected 'verbatim'-item (auto-impl doesn't know how to handle it)",
                    );
                    None
                }
                _ => {
                    // `syn` enums are `non_exhaustive` to be future-proof. If a
                    // trait contains a kind of item we don't even know about, we
                    // emit an error.
                    emit_error!(
                        item.span(),
                        "unknown trait item (auto-impl doesn't know how to handle it)",
                    );
                    None
                }
            }
        })
        .collect()
}

/// Generates the implementation of an associated const item described by
/// `item`. The implementation is returned as token stream.
///
/// If the proxy type is an Fn*-trait, an error is emitted and `Err(())` is
/// returned.
fn gen_const_item(
    proxy_type: &ProxyType,
    item: &TraitItemConst,
    trait_def: &ItemTrait,
    proxy_ty_param: &Ident,
) -> Result<TokenStream2, ()> {
    // A trait with associated consts cannot be implemented for Fn* types.
    if proxy_type.is_fn() {
        emit_error!(
            item.span(),
            "the trait `{}` cannot be auto-implemented for Fn-traits, because it has \
                associated consts",
            trait_def.ident;

            note = "only traits with a single method can be implemented for Fn-traits";
        );
        return Err(());
    }

    // We simply use the associated const from our type parameter.
    let const_name = &item.ident;
    let const_ty = &item.ty;
    let attrs = filter_attrs(&item.attrs);

    Ok(quote! {
        #(#attrs)* const #const_name: #const_ty = #proxy_ty_param::#const_name;
    })
}

/// Generates the implementation of an associated type item described by `item`.
/// The implementation is returned as token stream.
///
/// If the proxy type is an Fn*-trait, an error is emitted and `Err(())` is
/// returned.
fn gen_type_item(
    proxy_type: &ProxyType,
    item: &TraitItemType,
    trait_def: &ItemTrait,
    proxy_ty_param: &Ident,
) -> Result<TokenStream2, ()> {
    // A trait with associated types cannot be implemented for Fn* types.
    if proxy_type.is_fn() {
        emit_error!(
            item.span(),
            "the trait `{}` cannot be auto-implemented for Fn-traits, because it has \
                associated types",
                trait_def.ident;

            note = "only traits with a single method can be implemented for Fn-traits";
        );
        return Err(());
    }

    // We simply use the associated type from our type parameter.
    let assoc_name = &item.ident;
    let attrs = filter_attrs(&item.attrs);

    Ok(quote! {
        #(#attrs)* type #assoc_name = #proxy_ty_param::#assoc_name;
    })
}

/// Generates the implementation of a method item described by `item`. The
/// implementation is returned as token stream.
///
/// This function also performs sanity checks, e.g. whether the proxy type can
/// be used to implement the method. If any error occurs, the error is
/// immediately emitted and `Err(())` is returned.
fn gen_method_item(
    proxy_type: &ProxyType,
    item: &TraitItemMethod,
    trait_def: &ItemTrait,
    proxy_ty_param: &Ident,
) -> Result<TokenStream2, ()> {
    // If this method has a `#[auto_impl(keep_default_for(...))]` attribute for
    // the given proxy type, we don't generate anything for this impl block.
    if should_keep_default_for(item, proxy_type) {
        return if item.default.is_some() {
            Ok(TokenStream2::new())
        } else {
            emit_error!(
                item.sig.span(),
                "the method `{}` has the attribute `keep_default_for` but is not a default \
                    method (no body is provided)",
                item.sig.ident,
            );
            Err(())
        };
    }

    // Determine the kind of the method, determined by the self type.
    let sig = &item.sig;
    let self_arg = SelfType::from_sig(sig);
    let attrs = filter_attrs(&item.attrs);

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

    // Generate the list of argument used to call the method.
    let (inputs, args) = get_arg_list(sig.inputs.iter());

    // Construct a signature we'll use to generate the proxy method impl
    // This is _almost_ the same as the original, except we use the inputs constructed
    // alongside the args. These may be slightly different than the original trait.
    let sig = Signature {
        constness: item.sig.constness,
        asyncness: item.sig.asyncness,
        unsafety: item.sig.unsafety,
        abi: item.sig.abi.clone(),
        fn_token: item.sig.fn_token,
        ident: item.sig.ident.clone(),
        generics: item.sig.generics.clone(),
        paren_token: item.sig.paren_token,
        inputs,
        variadic: item.sig.variadic.clone(),
        output: item.sig.output.clone(),
    };

    // Build the turbofish type parameters. We need to pass type parameters
    // explicitly as they cannot be inferred in all cases (e.g. something like
    // `mem::size_of`). However, we don't explicitly specify lifetime
    // parameters. Most lifetime parameters are so called late-bound lifetimes
    // (ones that stick to input parameters) and Rust prohibits us from
    // specifying late-bound lifetimes explicitly (which is not a problem,
    // because those can always be correctly inferred). It would be possible to
    // explicitly specify early-bound lifetimes, but this is hardly useful.
    // Early-bound lifetimes are lifetimes that are only attached to the return
    // type. Something like:
    //
    //     fn foo<'a>() -> &'a i32
    //
    // It's hard to imagine how such a function would even work. So since those
    // functions are really rare and special, we won't support them. In
    // particular, for us to determine if a lifetime parameter is early- or
    // late-bound would be *really* difficult.
    //
    // So we just specify type parameters. In the future, however, we need to
    // add support for const parameters. But those are not remotely stable yet,
    // so we can wait a bit still.
    let generic_types = sig
        .generics
        .params
        .iter()
        .filter_map(|param| match param {
            GenericParam::Type(param) => {
                let name = &param.ident;
                Some(quote! { #name , })
            }
            GenericParam::Const(param) => {
                let name = &param.ident;
                Some(quote! { #name , })
            }
            GenericParam::Lifetime(_) => None,
        })
        .collect::<TokenStream2>();

    let generic_types = if generic_types.is_empty() {
        generic_types
    } else {
        quote! { ::<#generic_types> }
    };

    // Generate the body of the function. This mainly depends on the self type,
    // but also on the proxy type.
    let fn_name = &sig.ident;
    let body = match self_arg {
        // Fn proxy types get a special treatment
        _ if proxy_type.is_fn() => {
            quote! { ({self})(#args) }
        }

        // No receiver
        SelfType::None => {
            // The proxy type is a reference, smart pointer or Box.
            quote! { #proxy_ty_param::#fn_name #generic_types(#args) }
        }

        // Receiver `self` (by value)
        SelfType::Value => {
            // The proxy type is a Box.
            quote! { #proxy_ty_param::#fn_name #generic_types(*self, #args) }
        }

        // `&self` or `&mut self` receiver
        SelfType::Ref | SelfType::Mut => {
            // The proxy type could be anything in the `Ref` case, and `&mut`
            // or Box in the `Mut` case.
            quote! { #proxy_ty_param::#fn_name #generic_types(self, #args) }
        }
    };

    // Combine body with signature
    Ok(quote! { #(#attrs)* #sig { #body }})
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum SelfType {
    None,
    Ref,
    Mut,
    Value,
}

impl SelfType {
    fn from_sig(sig: &Signature) -> Self {
        match sig.inputs.iter().next() {
            Some(FnArg::Receiver(r)) => {
                if r.reference.is_none() {
                    SelfType::Value
                } else if r.mutability.is_none() {
                    SelfType::Ref
                } else {
                    SelfType::Mut
                }
            }
            _ => SelfType::None,
        }
    }

    fn as_str(&self) -> Option<&'static str> {
        match *self {
            SelfType::None => None,
            SelfType::Ref => Some("&self"),
            SelfType::Mut => Some("&mut self"),
            SelfType::Value => Some("self"),
        }
    }
}

/// Checks if this method can be implemented for the given proxy type. If not,
/// we will emit an error pointing to the method signature.
fn check_receiver_compatible(
    proxy_type: &ProxyType,
    self_arg: SelfType,
    trait_name: &Ident,
    sig_span: Span2,
) {
    match (proxy_type, self_arg) {
        (ProxyType::Ref, SelfType::Mut) | (ProxyType::Ref, SelfType::Value) => {
            emit_error!(
                sig_span,
                "the trait `{}` cannot be auto-implemented for immutable references, because \
                    this method has a `{}` receiver",
                    trait_name,
                    self_arg.as_str().unwrap();

                note = "only `&self` and no receiver are allowed";
            );
        }

        (ProxyType::RefMut, SelfType::Value) => {
            emit_error!(
                sig_span,
                "the trait `{}` cannot be auto-implemented for mutable references, because \
                    this method has a `self` receiver",
                trait_name;

                note = "only `&self`, `&mut self` and no receiver are allowed";
            );
        }

        (ProxyType::Rc, SelfType::Mut)
        | (ProxyType::Rc, SelfType::Value)
        | (ProxyType::Arc, SelfType::Mut)
        | (ProxyType::Arc, SelfType::Value) => {
            let ptr_name = if *proxy_type == ProxyType::Rc {
                "Rc"
            } else {
                "Arc"
            };

            emit_error!(
                sig_span,
                "the trait `{}` cannot be auto-implemented for {}, because \
                    this method has a `{}` receiver",
                    trait_name,
                    ptr_name,
                    self_arg.as_str().unwrap();

                note = "only `&self` and no receiver are allowed";
            );
        }

        (ProxyType::Fn, _) | (ProxyType::FnMut, _) | (ProxyType::FnOnce, _) => {
            // The Fn-trait being compatible with the receiver was already
            // checked before (in `gen_fn_type_for_trait()`).
        }

        _ => {} // All other combinations are fine
    }
}

/// Generates a list of comma-separated arguments used to call the function.
/// Currently, only simple names are valid and more complex pattern will lead
/// to an error being emitted. `self` parameters are ignored.
fn get_arg_list<'a>(
    original_inputs: impl Iterator<Item = &'a FnArg>,
) -> (Punctuated<FnArg, Token![,]>, TokenStream2) {
    let mut args = TokenStream2::new();
    let mut inputs = Punctuated::new();

    for arg in original_inputs {
        match arg {
            FnArg::Typed(arg) => {
                // Make sure the argument pattern is a simple name. In
                // principle, we could probably support patterns, but it's
                // not that important now.
                if let Pat::Ident(PatIdent {
                    by_ref: _by_ref,
                    mutability: _mutability,
                    ident,
                    subpat: None,
                    attrs,
                }) = &*arg.pat
                {
                    // Add name plus trailing comma to tokens
                    args.append_all(quote! { #ident , });

                    // Add an input argument that omits the `mut` and `ref` pattern bindings
                    inputs.push(FnArg::Typed(PatType {
                        attrs: arg.attrs.clone(),
                        pat: Box::new(Pat::Ident(PatIdent {
                            attrs: attrs.clone(),
                            by_ref: None,
                            mutability: None,
                            ident: ident.clone(),
                            subpat: None,
                        })),
                        colon_token: arg.colon_token,
                        ty: arg.ty.clone(),
                    }))
                } else {
                    emit_error!(
                        arg.pat.span(), "argument patterns are not supported by #[auto-impl]";
                        help = "please use a simple name like \"foo\" (but not `_`)";
                    );
                    continue;
                }
            }

            // There is only one such argument. We handle it elsewhere and
            // can ignore it here.
            FnArg::Receiver(arg) => {
                inputs.push(FnArg::Receiver(arg.clone()));
            }
        }
    }

    (inputs, args)
}

/// Checks if the given method has the attribute `#[auto_impl(keep_default_for(...))]`
/// and if it contains the given proxy type.
fn should_keep_default_for(m: &TraitItemMethod, proxy_type: &ProxyType) -> bool {
    // Get an iterator of just the attribute we are interested in.
    let mut it = m
        .attrs
        .iter()
        .filter(|attr| is_our_attr(attr))
        .filter_map(|attr| parse_our_attr(attr).ok());

    // Check the first (and hopefully only) `keep_default_for` attribute.
    let out = match it.next() {
        Some(attr) => {
            // Check if the attribute lists the given proxy type.
            let OurAttr::KeepDefaultFor(proxy_types) = attr;
            proxy_types.contains(proxy_type)
        }

        // If there is no such attribute, we return `false`
        None => false,
    };

    // Check if there is another such attribute (which we disallow)
    if it.next().is_some() {
        emit_error!(
            m.sig.span(),
            "found two `keep_default_for` attributes on one method",
        );
    }

    out
}

fn filter_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
    attrs
        .iter()
        .filter(|attr| attr.path.is_ident("cfg"))
        .cloned()
        .collect()
}