1use proc_macro2::{Span as Span2, TokenStream as TokenStream2};
2use quote::{ToTokens, TokenStreamExt};
3use syn::{
4 punctuated::Punctuated, spanned::Spanned, Attribute, Error, FnArg, GenericParam, Ident,
5 ItemTrait, Lifetime, Pat, PatIdent, PatType, ReturnType, Signature, Token, TraitBound,
6 TraitBoundModifier, TraitItem, TraitItemConst, TraitItemFn, TraitItemType, Type,
7 TypeParamBound, WherePredicate,
8};
9
10use crate::{
11 analyze::find_suitable_param_names,
12 attr::{is_our_attr, parse_our_attr, OurAttr},
13 proxy::ProxyType,
14};
15
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(); params.append_all(&tts);
250
251 let comma = if params.is_empty() || tts.is_empty() {
254 quote! {}
255 } else {
256 quote! { , }
257 };
258 params.append_all(quote! { #comma #proxy_ty_param #ty_bounds });
259
260 params
261 };
262
263 #[rustfmt::skip]
266 let self_ty = match *proxy_type {
267 ProxyType::Ref => quote! { & #proxy_lt_param #proxy_ty_param },
268 ProxyType::RefMut => quote! { & #proxy_lt_param mut #proxy_ty_param },
269 ProxyType::Arc => quote! { alloc::sync::Arc<#proxy_ty_param> },
270 ProxyType::Rc => quote! { alloc::rc::Rc<#proxy_ty_param> },
271 ProxyType::Box => quote! { alloc::boxed::Box<#proxy_ty_param> },
272 ProxyType::Fn => quote! { #proxy_ty_param },
273 ProxyType::FnMut => quote! { #proxy_ty_param },
274 ProxyType::FnOnce => quote! { #proxy_ty_param },
275 };
276
277 let where_clause = if !trait_def.supertraits.is_empty() {
281 let mut out = quote! { where };
282
283 if !trait_def.supertraits.is_empty() {
284 let supertraits = &trait_def.supertraits;
285 out.extend(quote! { #self_ty: #supertraits, });
286 }
287 if let Some(predicates) = where_clause.map(|c| &c.predicates) {
288 out.extend(predicates.into_token_stream());
289 }
290
291 out
292 } else {
293 where_clause.into_token_stream()
294 };
295
296 Ok(quote! {
298 impl<#impl_generics> #trait_path for #self_ty #where_clause
299 })
300}
301
302fn gen_fn_type_for_trait(
308 proxy_type: &ProxyType,
309 trait_def: &ItemTrait,
310) -> syn::Result<TokenStream2> {
311 let method = trait_def.items.first().and_then(|item| {
314 if let TraitItem::Fn(m) = item {
315 Some(m)
316 } else {
317 None
318 }
319 });
320
321 if method.is_none() || trait_def.items.len() > 1 {
323 return Err(Error::new(
324 trait_def.span(),
325 "this trait cannot be auto-implemented for Fn-traits (only traits with exactly \
326 one method and no other items are allowed)",
327 ));
328 }
329
330 let method = method.unwrap();
332 let sig = &method.sig;
333
334 if let Some(const_token) = sig.constness {
336 return Err(Error::new(
337 const_token.span(),
338 format_args!(
339 "the trait '{}' cannot be auto-implemented for Fn-traits: const methods are not \
340 allowed",
341 trait_def.ident
342 ),
343 ));
344 }
345
346 if let Some(unsafe_token) = &sig.unsafety {
347 return Err(Error::new(
348 unsafe_token.span(),
349 format_args!(
350 "the trait '{}' cannot be auto-implemented for Fn-traits: unsafe methods are not \
351 allowed",
352 trait_def.ident
353 ),
354 ));
355 }
356
357 if let Some(abi_token) = &sig.abi {
358 return Err(Error::new(
359 abi_token.span(),
360 format_args!(
361 "the trait '{}' cannot be implemented for Fn-traits: custom ABIs are not allowed",
362 trait_def.ident
363 ),
364 ));
365 }
366
367 let mut r: syn::Result<()> = Ok(());
370 for type_param in sig.generics.type_params() {
371 let err = Error::new(
372 type_param.span(),
373 format_args!("the trait '{}' cannot be implemented for Fn-traits: generic arguments are not allowed",
374 trait_def.ident),
375 );
376
377 if let Err(ref mut current_err) = r {
378 current_err.combine(err);
379 } else {
380 r = Err(err);
381 }
382 }
383
384 for const_param in sig.generics.const_params() {
385 let err = Error::new(
386 const_param.span(),
387 format_args!("the trait '{}' cannot be implemented for Fn-traits: constant arguments are not allowed",
388 trait_def.ident),
389 );
390
391 if let Err(ref mut current_err) = r {
392 current_err.combine(err);
393 } else {
394 r = Err(err);
395 }
396 }
397 r?;
398
399 let self_type = SelfType::from_sig(sig);
402 let err = match (self_type, proxy_type) {
403 (SelfType::None, _) => Some(("Fn-traits", "no", "")),
405
406 (SelfType::Mut, ProxyType::FnOnce) => {
409 Some(("`FnOnce`", "a `&mut self`", " (only `self` is allowed)"))
410 }
411 (SelfType::Ref, ProxyType::FnOnce) => {
412 Some(("`FnOnce`", "a `&self`", " (only `self` is allowed)"))
413 }
414
415 (SelfType::Ref, ProxyType::FnMut) => Some((
417 "`FnMut`",
418 "a `&self`",
419 " (only `self` and `&mut self` are allowed)",
420 )),
421
422 _ => None,
424 };
425
426 if let Some((fn_traits, receiver, allowed)) = err {
427 return Err(Error::new(
428 method.sig.span(),
429 format_args!(
430 "the trait '{}' cannot be auto-implemented for {}, because this method has \
431 {} receiver{}",
432 trait_def.ident, fn_traits, receiver, allowed,
433 ),
434 ));
435 }
436
437 let fn_name = match proxy_type {
442 ProxyType::Fn => quote! { ::core::ops::Fn },
443 ProxyType::FnMut => quote! { ::core::ops::FnMut },
444 ProxyType::FnOnce => quote! { ::core::ops::FnOnce },
445 _ => panic!("internal error in auto_impl (function contract violation)"),
446 };
447
448 let ret = &sig.output;
450
451 let local_lifetimes = sig.generics.lifetimes();
468
469 let mut arg_types = TokenStream2::new();
472 for arg in sig.inputs.iter().skip(1) {
473 match arg {
474 FnArg::Typed(pat) => {
475 let ty = &pat.ty;
476 arg_types.append_all(quote! { #ty , });
477 }
478
479 FnArg::Receiver(r) => {
481 return Err(Error::new(
482 r.span(),
483 "receiver argument that's not the first argument (auto_impl is confused)",
484 ));
485 }
486 }
487 }
488
489 Ok(quote! {
490 for< #(#local_lifetimes),* > #fn_name (#arg_types) #ret
491 })
492}
493
494fn gen_items(
497 proxy_type: &ProxyType,
498 trait_def: &ItemTrait,
499 proxy_ty_param: &Ident,
500) -> syn::Result<Vec<TokenStream2>> {
501 trait_def
502 .items
503 .iter()
504 .map(|item| {
505 match item {
506 TraitItem::Const(c) => gen_const_item(proxy_type, c, trait_def, proxy_ty_param),
507 TraitItem::Fn(method) => {
508 gen_method_item(proxy_type, method, trait_def, proxy_ty_param)
509 }
510 TraitItem::Type(ty) => gen_type_item(proxy_type, ty, trait_def, proxy_ty_param),
511 TraitItem::Macro(mac) => {
512 Err(Error::new(
516 mac.span(),
517 "traits with macro invocations in their bodies are not \
518 supported by auto_impl",
519 ))
520 }
521 TraitItem::Verbatim(v) => {
522 Err(Error::new(
525 v.span(),
526 "unexpected 'verbatim'-item (auto-impl doesn't know how to handle it)",
527 ))
528 }
529 _ => {
530 Err(Error::new(
534 item.span(),
535 "unknown trait item (auto-impl doesn't know how to handle it)",
536 ))
537 }
538 }
539 })
540 .collect()
541}
542
543fn gen_const_item(
549 proxy_type: &ProxyType,
550 item: &TraitItemConst,
551 trait_def: &ItemTrait,
552 proxy_ty_param: &Ident,
553) -> syn::Result<TokenStream2> {
554 if proxy_type.is_fn() {
556 return Err(Error::new(
557 item.span(),
558 format_args!("the trait `{}` cannot be auto-implemented for Fn-traits, because it has \
559 associated consts (only traits with a single method can be implemented for Fn-traits)",
560 trait_def.ident)
561 ));
562 }
563
564 let const_name = &item.ident;
566 let const_ty = &item.ty;
567 let attrs = filter_attrs(&item.attrs);
568
569 Ok(quote! {
570 #(#attrs)* const #const_name: #const_ty = #proxy_ty_param::#const_name;
571 })
572}
573
574fn gen_type_item(
580 proxy_type: &ProxyType,
581 item: &TraitItemType,
582 trait_def: &ItemTrait,
583 proxy_ty_param: &Ident,
584) -> syn::Result<TokenStream2> {
585 if proxy_type.is_fn() {
587 return Err(Error::new(
588 item.span(),
589 format_args!("the trait `{}` cannot be auto-implemented for Fn-traits, because it has \
590 associated types (only traits with a single method can be implemented for Fn-traits)",
591 trait_def.ident)
592 ));
593 }
594
595 let assoc_name = &item.ident;
597 let attrs = filter_attrs(&item.attrs);
598 let generics = &item.generics;
599
600 Ok(quote! {
601 #(#attrs)* type #assoc_name #generics = #proxy_ty_param::#assoc_name #generics;
602 })
603}
604
605fn gen_method_item(
612 proxy_type: &ProxyType,
613 item: &TraitItemFn,
614 trait_def: &ItemTrait,
615 proxy_ty_param: &Ident,
616) -> syn::Result<TokenStream2> {
617 if should_keep_default_for(item, proxy_type)? {
620 return if item.default.is_some() {
621 Ok(TokenStream2::new())
622 } else {
623 Err(Error::new(
624 item.sig.span(),
625 format_args!(
626 "the method `{}` has the attribute `keep_default_for` but is not a default \
627 method (no body is provided)",
628 item.sig.ident
629 ),
630 ))
631 };
632 }
633
634 let sig = &item.sig;
636 let self_arg = SelfType::from_sig(sig);
637 let attrs = filter_attrs(&item.attrs);
638
639 check_receiver_compatible(proxy_type, self_arg, &trait_def.ident, sig.span())?;
641
642 let (inputs, args) = get_arg_list(sig.inputs.iter())?;
644
645 let sig = Signature {
649 constness: item.sig.constness,
650 asyncness: item.sig.asyncness,
651 unsafety: item.sig.unsafety,
652 abi: item.sig.abi.clone(),
653 fn_token: item.sig.fn_token,
654 ident: item.sig.ident.clone(),
655 generics: item.sig.generics.clone(),
656 paren_token: item.sig.paren_token,
657 inputs,
658 variadic: item.sig.variadic.clone(),
659 output: item.sig.output.clone(),
660 };
661
662 let generic_types = sig
684 .generics
685 .params
686 .iter()
687 .filter_map(|param| match param {
688 GenericParam::Type(param) => {
689 let name = ¶m.ident;
690 Some(quote! { #name , })
691 }
692 GenericParam::Const(param) => {
693 let name = ¶m.ident;
694 Some(quote! { #name , })
695 }
696 GenericParam::Lifetime(_) => None,
697 })
698 .collect::<TokenStream2>();
699
700 let generic_types = if generic_types.is_empty() {
701 generic_types
702 } else {
703 quote! { ::<#generic_types> }
704 };
705
706 let fn_name = &sig.ident;
709 let await_token = sig.asyncness.map(|_| quote! { .await });
710
711 let body = match self_arg {
712 _ if proxy_type.is_fn() => {
714 quote! { ({self})(#args) #await_token }
715 }
716
717 SelfType::None => {
719 quote! { #proxy_ty_param::#fn_name #generic_types(#args) #await_token }
721 }
722
723 SelfType::Value => {
725 quote! { #proxy_ty_param::#fn_name #generic_types(*self, #args) #await_token }
727 }
728
729 SelfType::Ref | SelfType::Mut => {
731 quote! { #proxy_ty_param::#fn_name #generic_types(self, #args) #await_token }
734 }
735 };
736
737 Ok(quote! { #(#attrs)* #sig { #body }})
739}
740
741#[derive(Debug, Clone, Copy, PartialEq, Eq)]
742enum SelfType {
743 None,
744 Ref,
745 Mut,
746 Value,
747}
748
749impl SelfType {
750 fn from_sig(sig: &Signature) -> Self {
751 match sig.inputs.iter().next() {
752 Some(FnArg::Receiver(r)) => {
753 if r.reference.is_none() {
754 SelfType::Value
755 } else if r.mutability.is_none() {
756 SelfType::Ref
757 } else {
758 SelfType::Mut
759 }
760 }
761 _ => SelfType::None,
762 }
763 }
764
765 fn as_str(&self) -> Option<&'static str> {
766 match *self {
767 SelfType::None => None,
768 SelfType::Ref => Some("&self"),
769 SelfType::Mut => Some("&mut self"),
770 SelfType::Value => Some("self"),
771 }
772 }
773}
774
775fn check_receiver_compatible(
778 proxy_type: &ProxyType,
779 self_arg: SelfType,
780 trait_name: &Ident,
781 sig_span: Span2,
782) -> syn::Result<()> {
783 match (proxy_type, self_arg) {
784 (ProxyType::Ref, SelfType::Mut) | (ProxyType::Ref, SelfType::Value) => {
785 Err(Error::new(
786 sig_span,
787 format_args!("the trait `{}` cannot be auto-implemented for immutable references, because \
788 this method has a `{}` receiver (only `&self` and no receiver are allowed)",
789 trait_name,
790 self_arg.as_str().unwrap()),
791 ))
792 }
793
794 (ProxyType::RefMut, SelfType::Value) => {
795 Err(Error::new(
796 sig_span,
797 format_args!("the trait `{}` cannot be auto-implemented for mutable references, because \
798 this method has a `self` receiver (only `&self`, `&mut self` and no receiver are allowed)",
799 trait_name,)
800 ))
801 }
802
803 (ProxyType::Rc, SelfType::Mut)
804 | (ProxyType::Rc, SelfType::Value)
805 | (ProxyType::Arc, SelfType::Mut)
806 | (ProxyType::Arc, SelfType::Value) => {
807 let ptr_name = if *proxy_type == ProxyType::Rc {
808 "Rc"
809 } else {
810 "Arc"
811 };
812
813 Err(Error::new(
814 sig_span,
815 format_args!("the trait `{}` cannot be auto-implemented for {}, because \
816 this method has a `{}` receiver (only `&self` and no receiver are allowed)",
817 trait_name,
818 ptr_name,
819 self_arg.as_str().unwrap())
820 ))
821 }
822
823 (ProxyType::Fn, _) | (ProxyType::FnMut, _) | (ProxyType::FnOnce, _) => {
824 Ok(())
827 }
828
829 _ => Ok(()) }
831}
832
833fn get_arg_list<'a>(
837 original_inputs: impl Iterator<Item = &'a FnArg>,
838) -> syn::Result<(Punctuated<FnArg, Token![,]>, TokenStream2)> {
839 let mut args = TokenStream2::new();
840 let mut inputs = Punctuated::new();
841
842 let mut r: Result<(), Error> = Ok(());
843 for arg in original_inputs {
844 match arg {
845 FnArg::Typed(arg) => {
846 if let Pat::Ident(PatIdent {
850 by_ref: _by_ref,
851 mutability: _mutability,
852 ident,
853 subpat: None,
854 attrs,
855 }) = &*arg.pat
856 {
857 args.append_all(quote! { #ident , });
859
860 inputs.push(FnArg::Typed(PatType {
862 attrs: arg.attrs.clone(),
863 pat: Box::new(Pat::Ident(PatIdent {
864 attrs: attrs.clone(),
865 by_ref: None,
866 mutability: None,
867 ident: ident.clone(),
868 subpat: None,
869 })),
870 colon_token: arg.colon_token,
871 ty: arg.ty.clone(),
872 }))
873 } else {
874 let err = Error::new(
875 arg.pat.span(), "argument patterns are not supported by #[auto-impl]; use a simple name like \"foo\" (but not `_`)"
876 );
877
878 if let Err(ref mut current_err) = r {
879 current_err.combine(err);
880 } else {
881 r = Err(err);
882 }
883
884 continue;
885 }
886 }
887
888 FnArg::Receiver(arg) => {
891 inputs.push(FnArg::Receiver(arg.clone()));
892 }
893 }
894 }
895
896 r.map(|_| (inputs, args))
897}
898
899fn should_keep_default_for(m: &TraitItemFn, proxy_type: &ProxyType) -> syn::Result<bool> {
902 let mut it = m
904 .attrs
905 .iter()
906 .filter(|attr| is_our_attr(attr))
907 .map(parse_our_attr);
908
909 let out = match it.next() {
911 Some(attr) => {
912 let OurAttr::KeepDefaultFor(proxy_types) = attr?;
914 proxy_types.contains(proxy_type)
915 }
916
917 None => false,
919 };
920
921 if it.next().is_some() {
923 return Err(Error::new(
924 m.sig.span(),
925 "found two `keep_default_for` attributes on one method",
926 ));
927 }
928
929 Ok(out)
930}
931
932fn filter_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
933 attrs
934 .iter()
935 .filter(|attr| attr.path().is_ident("cfg"))
936 .cloned()
937 .collect()
938}