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
16pub(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 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
50fn 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 let (impl_generics, trait_generics, where_clause) = trait_def.generics.split_for_impl();
60
61 let trait_ident = &trait_def.ident;
63 let trait_path = quote! { #trait_ident #trait_generics };
64
65 let impl_generics = {
75 let methods = trait_def
79 .items
80 .iter()
81 .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 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 match &pred.bounded_ty {
113 Type::Path(p) if p.path.is_ident("Self") => {
114 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 let self_value_param = match m.sig.inputs.first() {
131 Some(FnArg::Receiver(receiver)) => receiver.reference.is_none(),
132 _ => false,
133 };
134
135 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 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 let methods = trait_def
170 .items
171 .iter()
172 .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 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 match b {
217 TypeParamBound::Trait(t) => Some(t),
218 _ => None,
219 }
220 }),
221 );
222 }
223
224 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 let mut tts = impl_generics
244 .into_token_stream()
245 .into_iter()
246 .skip(1) .collect::<Vec<_>>();
248 tts.pop(); 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 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 #[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 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 Ok(quote! {
312 impl<#impl_generics> #trait_path for #self_ty #where_clause
313 })
314}
315
316fn gen_fn_type_for_trait(
322 proxy_type: &ProxyType,
323 trait_def: &ItemTrait,
324) -> syn::Result<TokenStream2> {
325 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 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 let method = method.unwrap();
346 let sig = &method.sig;
347
348 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 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 let self_type = SelfType::from_sig(sig);
416 let err = match (self_type, proxy_type) {
417 (SelfType::None, _) => Some(("Fn-traits", "no", "")),
419
420 (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 (SelfType::Ref, ProxyType::FnMut) => Some((
431 "`FnMut`",
432 "a `&self`",
433 " (only `self` and `&mut self` are allowed)",
434 )),
435
436 _ => 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 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 let ret = &sig.output;
464
465 let local_lifetimes = sig.generics.lifetimes();
482
483 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 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
508fn 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 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 Err(Error::new(
539 v.span(),
540 "unexpected 'verbatim'-item (auto-impl doesn't know how to handle it)",
541 ))
542 }
543 _ => {
544 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
557fn gen_const_item(
563 proxy_type: &ProxyType,
564 item: &TraitItemConst,
565 trait_def: &ItemTrait,
566 proxy_ty_param: &Ident,
567) -> syn::Result<TokenStream2> {
568 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 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
588fn gen_type_item(
594 proxy_type: &ProxyType,
595 item: &TraitItemType,
596 trait_def: &ItemTrait,
597 proxy_ty_param: &Ident,
598) -> syn::Result<TokenStream2> {
599 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 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
619fn 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 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 let sig = &item.sig;
650 let self_arg = SelfType::from_sig(sig);
651 let attrs = filter_attrs(&item.attrs);
652
653 check_receiver_compatible(proxy_type, self_arg, &trait_def.ident, sig.span())?;
655
656 let (inputs, args) = get_arg_list(sig.inputs.iter())?;
658
659 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 let generic_types = sig
698 .generics
699 .params
700 .iter()
701 .filter_map(|param| match param {
702 GenericParam::Type(param) => {
703 let name = ¶m.ident;
704 Some(quote! { #name , })
705 }
706 GenericParam::Const(param) => {
707 let name = ¶m.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 let fn_name = &sig.ident;
723 let await_token = sig.asyncness.map(|_| quote! { .await });
724
725 let body = match self_arg {
726 _ if proxy_type.is_fn() => {
728 quote! { ({self})(#args) #await_token }
729 }
730
731 SelfType::None => {
733 quote! { #proxy_ty_param::#fn_name #generic_types(#args) #await_token }
735 }
736
737 SelfType::Value => {
739 quote! { #proxy_ty_param::#fn_name #generic_types(*self, #args) #await_token }
741 }
742
743 SelfType::Ref | SelfType::Mut => {
745 quote! { #proxy_ty_param::#fn_name #generic_types(self, #args) #await_token }
748 }
749 };
750
751 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
789fn 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 Ok(())
841 }
842
843 _ => Ok(()) }
845}
846
847fn 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 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 args.append_all(quote! { #ident , });
873
874 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 FnArg::Receiver(arg) => {
905 inputs.push(FnArg::Receiver(arg.clone()));
906 }
907 }
908 }
909
910 r.map(|_| (inputs, args))
911}
912
913fn should_keep_default_for(m: &TraitItemFn, proxy_type: &ProxyType) -> syn::Result<bool> {
916 let mut it = m
918 .attrs
919 .iter()
920 .filter(|attr| is_our_attr(attr))
921 .map(parse_our_attr);
922
923 let out = match it.next() {
925 Some(attr) => {
926 let OurAttr::KeepDefaultFor(proxy_types) = attr?;
928 proxy_types.contains(proxy_type)
929 }
930
931 None => false,
933 };
934
935 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}