| use crate::bound::{has_bound, InferredBound, Supertraits}; | 
 | use crate::lifetime::{AddLifetimeToImplTrait, CollectLifetimes}; | 
 | use crate::parse::Item; | 
 | use crate::receiver::{has_self_in_block, has_self_in_sig, mut_pat, ReplaceSelf}; | 
 | use crate::verbatim::VerbatimFn; | 
 | use proc_macro2::{Span, TokenStream}; | 
 | use quote::{format_ident, quote, quote_spanned, ToTokens}; | 
 | use std::collections::BTreeSet as Set; | 
 | use std::mem; | 
 | use syn::punctuated::Punctuated; | 
 | use syn::visit_mut::{self, VisitMut}; | 
 | use syn::{ | 
 |     parse_quote, parse_quote_spanned, Attribute, Block, FnArg, GenericArgument, GenericParam, | 
 |     Generics, Ident, ImplItem, Lifetime, LifetimeParam, Pat, PatIdent, PathArguments, Receiver, | 
 |     ReturnType, Signature, Token, TraitItem, Type, TypePath, WhereClause, | 
 | }; | 
 |  | 
 | impl ToTokens for Item { | 
 |     fn to_tokens(&self, tokens: &mut TokenStream) { | 
 |         match self { | 
 |             Item::Trait(item) => item.to_tokens(tokens), | 
 |             Item::Impl(item) => item.to_tokens(tokens), | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | #[derive(Clone, Copy)] | 
 | enum Context<'a> { | 
 |     Trait { | 
 |         generics: &'a Generics, | 
 |         supertraits: &'a Supertraits, | 
 |     }, | 
 |     Impl { | 
 |         impl_generics: &'a Generics, | 
 |         associated_type_impl_traits: &'a Set<Ident>, | 
 |     }, | 
 | } | 
 |  | 
 | impl Context<'_> { | 
 |     fn lifetimes<'a>(&'a self, used: &'a [Lifetime]) -> impl Iterator<Item = &'a LifetimeParam> { | 
 |         let generics = match self { | 
 |             Context::Trait { generics, .. } => generics, | 
 |             Context::Impl { impl_generics, .. } => impl_generics, | 
 |         }; | 
 |         generics.params.iter().filter_map(move |param| { | 
 |             if let GenericParam::Lifetime(param) = param { | 
 |                 if used.contains(¶m.lifetime) { | 
 |                     return Some(param); | 
 |                 } | 
 |             } | 
 |             None | 
 |         }) | 
 |     } | 
 | } | 
 |  | 
 | pub fn expand(input: &mut Item, is_local: bool) { | 
 |     match input { | 
 |         Item::Trait(input) => { | 
 |             let context = Context::Trait { | 
 |                 generics: &input.generics, | 
 |                 supertraits: &input.supertraits, | 
 |             }; | 
 |             for inner in &mut input.items { | 
 |                 if let TraitItem::Fn(method) = inner { | 
 |                     let sig = &mut method.sig; | 
 |                     if sig.asyncness.is_some() { | 
 |                         let block = &mut method.default; | 
 |                         let mut has_self = has_self_in_sig(sig); | 
 |                         method.attrs.push(parse_quote!(#[must_use])); | 
 |                         if let Some(block) = block { | 
 |                             has_self |= has_self_in_block(block); | 
 |                             transform_block(context, sig, block); | 
 |                             method.attrs.push(lint_suppress_with_body()); | 
 |                         } else { | 
 |                             method.attrs.push(lint_suppress_without_body()); | 
 |                         } | 
 |                         let has_default = method.default.is_some(); | 
 |                         transform_sig(context, sig, has_self, has_default, is_local); | 
 |                     } | 
 |                 } | 
 |             } | 
 |         } | 
 |         Item::Impl(input) => { | 
 |             let mut associated_type_impl_traits = Set::new(); | 
 |             for inner in &input.items { | 
 |                 if let ImplItem::Type(assoc) = inner { | 
 |                     if let Type::ImplTrait(_) = assoc.ty { | 
 |                         associated_type_impl_traits.insert(assoc.ident.clone()); | 
 |                     } | 
 |                 } | 
 |             } | 
 |  | 
 |             let context = Context::Impl { | 
 |                 impl_generics: &input.generics, | 
 |                 associated_type_impl_traits: &associated_type_impl_traits, | 
 |             }; | 
 |             for inner in &mut input.items { | 
 |                 match inner { | 
 |                     ImplItem::Fn(method) if method.sig.asyncness.is_some() => { | 
 |                         let sig = &mut method.sig; | 
 |                         let block = &mut method.block; | 
 |                         let has_self = has_self_in_sig(sig) || has_self_in_block(block); | 
 |                         transform_block(context, sig, block); | 
 |                         transform_sig(context, sig, has_self, false, is_local); | 
 |                         method.attrs.push(lint_suppress_with_body()); | 
 |                     } | 
 |                     ImplItem::Verbatim(tokens) => { | 
 |                         let mut method = match syn::parse2::<VerbatimFn>(tokens.clone()) { | 
 |                             Ok(method) if method.sig.asyncness.is_some() => method, | 
 |                             _ => continue, | 
 |                         }; | 
 |                         let sig = &mut method.sig; | 
 |                         let has_self = has_self_in_sig(sig); | 
 |                         transform_sig(context, sig, has_self, false, is_local); | 
 |                         method.attrs.push(lint_suppress_with_body()); | 
 |                         *tokens = quote!(#method); | 
 |                     } | 
 |                     _ => {} | 
 |                 } | 
 |             } | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | fn lint_suppress_with_body() -> Attribute { | 
 |     parse_quote! { | 
 |         #[allow( | 
 |             elided_named_lifetimes, | 
 |             clippy::async_yields_async, | 
 |             clippy::diverging_sub_expression, | 
 |             clippy::let_unit_value, | 
 |             clippy::needless_arbitrary_self_type, | 
 |             clippy::no_effect_underscore_binding, | 
 |             clippy::shadow_same, | 
 |             clippy::type_complexity, | 
 |             clippy::type_repetition_in_bounds, | 
 |             clippy::used_underscore_binding | 
 |         )] | 
 |     } | 
 | } | 
 |  | 
 | fn lint_suppress_without_body() -> Attribute { | 
 |     parse_quote! { | 
 |         #[allow( | 
 |             elided_named_lifetimes, | 
 |             clippy::type_complexity, | 
 |             clippy::type_repetition_in_bounds | 
 |         )] | 
 |     } | 
 | } | 
 |  | 
 | // Input: | 
 | //     async fn f<T>(&self, x: &T) -> Ret; | 
 | // | 
 | // Output: | 
 | //     fn f<'life0, 'life1, 'async_trait, T>( | 
 | //         &'life0 self, | 
 | //         x: &'life1 T, | 
 | //     ) -> Pin<Box<dyn Future<Output = Ret> + Send + 'async_trait>> | 
 | //     where | 
 | //         'life0: 'async_trait, | 
 | //         'life1: 'async_trait, | 
 | //         T: 'async_trait, | 
 | //         Self: Sync + 'async_trait; | 
 | fn transform_sig( | 
 |     context: Context, | 
 |     sig: &mut Signature, | 
 |     has_self: bool, | 
 |     has_default: bool, | 
 |     is_local: bool, | 
 | ) { | 
 |     sig.fn_token.span = sig.asyncness.take().unwrap().span; | 
 |  | 
 |     let (ret_arrow, ret) = match &sig.output { | 
 |         ReturnType::Default => (quote!(->), quote!(())), | 
 |         ReturnType::Type(arrow, ret) => (quote!(#arrow), quote!(#ret)), | 
 |     }; | 
 |  | 
 |     let mut lifetimes = CollectLifetimes::new(); | 
 |     for arg in &mut sig.inputs { | 
 |         match arg { | 
 |             FnArg::Receiver(arg) => lifetimes.visit_receiver_mut(arg), | 
 |             FnArg::Typed(arg) => lifetimes.visit_type_mut(&mut arg.ty), | 
 |         } | 
 |     } | 
 |  | 
 |     for param in &mut sig.generics.params { | 
 |         match param { | 
 |             GenericParam::Type(param) => { | 
 |                 let param_name = ¶m.ident; | 
 |                 let span = match param.colon_token.take() { | 
 |                     Some(colon_token) => colon_token.span, | 
 |                     None => param_name.span(), | 
 |                 }; | 
 |                 let bounds = mem::replace(&mut param.bounds, Punctuated::new()); | 
 |                 where_clause_or_default(&mut sig.generics.where_clause) | 
 |                     .predicates | 
 |                     .push(parse_quote_spanned!(span=> #param_name: 'async_trait + #bounds)); | 
 |             } | 
 |             GenericParam::Lifetime(param) => { | 
 |                 let param_name = ¶m.lifetime; | 
 |                 let span = match param.colon_token.take() { | 
 |                     Some(colon_token) => colon_token.span, | 
 |                     None => param_name.span(), | 
 |                 }; | 
 |                 let bounds = mem::replace(&mut param.bounds, Punctuated::new()); | 
 |                 where_clause_or_default(&mut sig.generics.where_clause) | 
 |                     .predicates | 
 |                     .push(parse_quote_spanned!(span=> #param: 'async_trait + #bounds)); | 
 |             } | 
 |             GenericParam::Const(_) => {} | 
 |         } | 
 |     } | 
 |  | 
 |     for param in context.lifetimes(&lifetimes.explicit) { | 
 |         let param = ¶m.lifetime; | 
 |         let span = param.span(); | 
 |         where_clause_or_default(&mut sig.generics.where_clause) | 
 |             .predicates | 
 |             .push(parse_quote_spanned!(span=> #param: 'async_trait)); | 
 |     } | 
 |  | 
 |     if sig.generics.lt_token.is_none() { | 
 |         sig.generics.lt_token = Some(Token)); | 
 |     } | 
 |     if sig.generics.gt_token.is_none() { | 
 |         sig.generics.gt_token = Some(Token)); | 
 |     } | 
 |  | 
 |     for elided in lifetimes.elided { | 
 |         sig.generics.params.push(parse_quote!(#elided)); | 
 |         where_clause_or_default(&mut sig.generics.where_clause) | 
 |             .predicates | 
 |             .push(parse_quote_spanned!(elided.span()=> #elided: 'async_trait)); | 
 |     } | 
 |  | 
 |     sig.generics.params.push(parse_quote!('async_trait)); | 
 |  | 
 |     if has_self { | 
 |         let bounds: &[InferredBound] = if is_local { | 
 |             &[] | 
 |         } else if let Some(receiver) = sig.receiver() { | 
 |             match receiver.ty.as_ref() { | 
 |                 // self: &Self | 
 |                 Type::Reference(ty) if ty.mutability.is_none() => &[InferredBound::Sync], | 
 |                 // self: Arc<Self> | 
 |                 Type::Path(ty) | 
 |                     if { | 
 |                         let segment = ty.path.segments.last().unwrap(); | 
 |                         segment.ident == "Arc" | 
 |                             && match &segment.arguments { | 
 |                                 PathArguments::AngleBracketed(arguments) => { | 
 |                                     arguments.args.len() == 1 | 
 |                                         && match &arguments.args[0] { | 
 |                                             GenericArgument::Type(Type::Path(arg)) => { | 
 |                                                 arg.path.is_ident("Self") | 
 |                                             } | 
 |                                             _ => false, | 
 |                                         } | 
 |                                 } | 
 |                                 _ => false, | 
 |                             } | 
 |                     } => | 
 |                 { | 
 |                     &[InferredBound::Sync, InferredBound::Send] | 
 |                 } | 
 |                 _ => &[InferredBound::Send], | 
 |             } | 
 |         } else { | 
 |             &[InferredBound::Send] | 
 |         }; | 
 |  | 
 |         let bounds = bounds.iter().filter(|bound| match context { | 
 |             Context::Trait { supertraits, .. } => has_default && !has_bound(supertraits, bound), | 
 |             Context::Impl { .. } => false, | 
 |         }); | 
 |  | 
 |         where_clause_or_default(&mut sig.generics.where_clause) | 
 |             .predicates | 
 |             .push(parse_quote! { | 
 |                 Self: #(#bounds +)* 'async_trait | 
 |             }); | 
 |     } | 
 |  | 
 |     for (i, arg) in sig.inputs.iter_mut().enumerate() { | 
 |         match arg { | 
 |             FnArg::Receiver(receiver) => { | 
 |                 if receiver.reference.is_none() { | 
 |                     receiver.mutability = None; | 
 |                 } | 
 |             } | 
 |             FnArg::Typed(arg) => { | 
 |                 if match *arg.ty { | 
 |                     Type::Reference(_) => false, | 
 |                     _ => true, | 
 |                 } { | 
 |                     if let Pat::Ident(pat) = &mut *arg.pat { | 
 |                         pat.by_ref = None; | 
 |                         pat.mutability = None; | 
 |                     } else { | 
 |                         let positional = positional_arg(i, &arg.pat); | 
 |                         let m = mut_pat(&mut arg.pat); | 
 |                         arg.pat = parse_quote!(#m #positional); | 
 |                     } | 
 |                 } | 
 |                 AddLifetimeToImplTrait.visit_type_mut(&mut arg.ty); | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     let bounds = if is_local { | 
 |         quote!('async_trait) | 
 |     } else { | 
 |         quote!(::core::marker::Send + 'async_trait) | 
 |     }; | 
 |     sig.output = parse_quote! { | 
 |         #ret_arrow ::core::pin::Pin<Box< | 
 |             dyn ::core::future::Future<Output = #ret> + #bounds | 
 |         >> | 
 |     }; | 
 | } | 
 |  | 
 | // Input: | 
 | //     async fn f<T>(&self, x: &T, (a, b): (A, B)) -> Ret { | 
 | //         self + x + a + b | 
 | //     } | 
 | // | 
 | // Output: | 
 | //     Box::pin(async move { | 
 | //         let ___ret: Ret = { | 
 | //             let __self = self; | 
 | //             let x = x; | 
 | //             let (a, b) = __arg1; | 
 | // | 
 | //             __self + x + a + b | 
 | //         }; | 
 | // | 
 | //         ___ret | 
 | //     }) | 
 | fn transform_block(context: Context, sig: &mut Signature, block: &mut Block) { | 
 |     let mut replace_self = false; | 
 |     let decls = sig | 
 |         .inputs | 
 |         .iter() | 
 |         .enumerate() | 
 |         .map(|(i, arg)| match arg { | 
 |             FnArg::Receiver(Receiver { | 
 |                 self_token, | 
 |                 mutability, | 
 |                 .. | 
 |             }) => { | 
 |                 replace_self = true; | 
 |                 let ident = Ident::new("__self", self_token.span); | 
 |                 quote!(let #mutability #ident = #self_token;) | 
 |             } | 
 |             FnArg::Typed(arg) => { | 
 |                 // If there is a #[cfg(...)] attribute that selectively enables | 
 |                 // the parameter, forward it to the variable. | 
 |                 // | 
 |                 // This is currently not applied to the `self` parameter. | 
 |                 let attrs = arg.attrs.iter().filter(|attr| attr.path().is_ident("cfg")); | 
 |  | 
 |                 if let Type::Reference(_) = *arg.ty { | 
 |                     quote!() | 
 |                 } else if let Pat::Ident(PatIdent { | 
 |                     ident, mutability, .. | 
 |                 }) = &*arg.pat | 
 |                 { | 
 |                     quote! { | 
 |                         #(#attrs)* | 
 |                         let #mutability #ident = #ident; | 
 |                     } | 
 |                 } else { | 
 |                     let pat = &arg.pat; | 
 |                     let ident = positional_arg(i, pat); | 
 |                     if let Pat::Wild(_) = **pat { | 
 |                         quote! { | 
 |                             #(#attrs)* | 
 |                             let #ident = #ident; | 
 |                         } | 
 |                     } else { | 
 |                         quote! { | 
 |                             #(#attrs)* | 
 |                             let #pat = { | 
 |                                 let #ident = #ident; | 
 |                                 #ident | 
 |                             }; | 
 |                         } | 
 |                     } | 
 |                 } | 
 |             } | 
 |         }) | 
 |         .collect::<Vec<_>>(); | 
 |  | 
 |     if replace_self { | 
 |         ReplaceSelf.visit_block_mut(block); | 
 |     } | 
 |  | 
 |     let stmts = &block.stmts; | 
 |     let let_ret = match &mut sig.output { | 
 |         ReturnType::Default => quote_spanned! {block.brace_token.span=> | 
 |             #(#decls)* | 
 |             let () = { #(#stmts)* }; | 
 |         }, | 
 |         ReturnType::Type(_, ret) => { | 
 |             if contains_associated_type_impl_trait(context, ret) { | 
 |                 if decls.is_empty() { | 
 |                     quote!(#(#stmts)*) | 
 |                 } else { | 
 |                     quote!(#(#decls)* { #(#stmts)* }) | 
 |                 } | 
 |             } else { | 
 |                 quote! { | 
 |                     if let ::core::option::Option::Some(__ret) = ::core::option::Option::None::<#ret> { | 
 |                         #[allow(unreachable_code)] | 
 |                         return __ret; | 
 |                     } | 
 |                     #(#decls)* | 
 |                     let __ret: #ret = { #(#stmts)* }; | 
 |                     #[allow(unreachable_code)] | 
 |                     __ret | 
 |                 } | 
 |             } | 
 |         } | 
 |     }; | 
 |     let box_pin = quote_spanned!(block.brace_token.span=> | 
 |         Box::pin(async move { #let_ret }) | 
 |     ); | 
 |     block.stmts = parse_quote!(#box_pin); | 
 | } | 
 |  | 
 | fn positional_arg(i: usize, pat: &Pat) -> Ident { | 
 |     let span = syn::spanned::Spanned::span(pat).resolved_at(Span::mixed_site()); | 
 |     format_ident!("__arg{}", i, span = span) | 
 | } | 
 |  | 
 | fn contains_associated_type_impl_trait(context: Context, ret: &mut Type) -> bool { | 
 |     struct AssociatedTypeImplTraits<'a> { | 
 |         set: &'a Set<Ident>, | 
 |         contains: bool, | 
 |     } | 
 |  | 
 |     impl<'a> VisitMut for AssociatedTypeImplTraits<'a> { | 
 |         fn visit_type_path_mut(&mut self, ty: &mut TypePath) { | 
 |             if ty.qself.is_none() | 
 |                 && ty.path.segments.len() == 2 | 
 |                 && ty.path.segments[0].ident == "Self" | 
 |                 && self.set.contains(&ty.path.segments[1].ident) | 
 |             { | 
 |                 self.contains = true; | 
 |             } | 
 |             visit_mut::visit_type_path_mut(self, ty); | 
 |         } | 
 |     } | 
 |  | 
 |     match context { | 
 |         Context::Trait { .. } => false, | 
 |         Context::Impl { | 
 |             associated_type_impl_traits, | 
 |             .. | 
 |         } => { | 
 |             let mut visit = AssociatedTypeImplTraits { | 
 |                 set: associated_type_impl_traits, | 
 |                 contains: false, | 
 |             }; | 
 |             visit.visit_type_mut(ret); | 
 |             visit.contains | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | fn where_clause_or_default(clause: &mut Option<WhereClause>) -> &mut WhereClause { | 
 |     clause.get_or_insert_with(|| WhereClause { | 
 |         where_token: Default::default(), | 
 |         predicates: Punctuated::new(), | 
 |     }) | 
 | } |