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 = ¶m.ident;
670 Some(quote! { #name , })
671 }
672 GenericParam::Const(param) => {
673 let name = ¶m.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}