Upgrade rust/crates/async-trait to 0.1.48 am: 5448f37621 am: 5a23a1fcb2 am: 518aac137a

Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/async-trait/+/1662668

Change-Id: Iefe6195156a9c7ea816a76debfdb938db6ab3fa2
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 181672b..a638e3f 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
 {
   "git": {
-    "sha1": "f54e5f2a4ad7fad8700b1c809d6c96893388b30d"
+    "sha1": "a4aab7b9285e4912d16f1f4733cfb99fc8aa37da"
   }
 }
diff --git a/.clippy.toml b/.clippy.toml
new file mode 100644
index 0000000..21a08b0
--- /dev/null
+++ b/.clippy.toml
@@ -0,0 +1 @@
+msrv = "1.39.0"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 710cee3..4c3d289 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -39,4 +39,4 @@
     steps:
       - uses: actions/checkout@v2
       - uses: dtolnay/rust-toolchain@clippy
-      - run: cargo clippy --tests -- -Dclippy::all
+      - run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic
diff --git a/Android.bp b/Android.bp
index 935757e..4bc7fa9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,4 +1,5 @@
 // This file is generated by cargo2android.py --run --device --dependencies.
+// Do not modify this file as changes will be overridden on upgrade.
 
 package {
     default_applicable_licenses: ["external_rust_crates_async-trait_license"],
@@ -49,7 +50,7 @@
 }
 
 // dependent_library ["feature_list"]
-//   proc-macro2-1.0.24 "default,proc-macro"
-//   quote-1.0.7 "default,proc-macro"
-//   syn-1.0.51 "clone-impls,default,derive,extra-traits,full,parsing,printing,proc-macro,quote,visit,visit-mut"
+//   proc-macro2-1.0.26 "default,proc-macro"
+//   quote-1.0.9 "default,proc-macro"
+//   syn-1.0.68 "clone-impls,default,derive,extra-traits,full,parsing,printing,proc-macro,quote,visit,visit-mut"
 //   unicode-xid-0.2.1 "default"
diff --git a/Cargo.toml b/Cargo.toml
index 0f21963..5b222ec 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
 [package]
 edition = "2018"
 name = "async-trait"
-version = "0.1.42"
+version = "0.1.48"
 authors = ["David Tolnay <[email protected]>"]
 description = "Type erasure for async trait methods"
 documentation = "https://docs.rs/async-trait"
@@ -32,7 +32,7 @@
 version = "1.0"
 
 [dependencies.syn]
-version = "1.0"
+version = "1.0.61"
 features = ["full", "visit-mut"]
 [dev-dependencies.rustversion]
 version = "1.0"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index ea0f3d4..d5599b1 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "async-trait"
-version = "0.1.42"
+version = "0.1.48"
 authors = ["David Tolnay <[email protected]>"]
 edition = "2018"
 license = "MIT OR Apache-2.0"
@@ -15,7 +15,7 @@
 [dependencies]
 proc-macro2 = "1.0"
 quote = "1.0"
-syn = { version = "1.0", features = ["full", "visit-mut"] }
+syn = { version = "1.0.61", features = ["full", "visit-mut"] }
 
 [dev-dependencies]
 rustversion = "1.0"
diff --git a/METADATA b/METADATA
index 8d7bc4f..3e6f11b 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/async-trait/async-trait-0.1.42.crate"
+    value: "https://static.crates.io/crates/async-trait/async-trait-0.1.48.crate"
   }
-  version: "0.1.42"
+  version: "0.1.48"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2020
-    month: 11
-    day: 24
+    year: 2021
+    month: 4
+    day: 1
   }
 }
diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000..a2b0833
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,25 @@
+use std::env;
+use std::process::Command;
+use std::str;
+
+fn main() {
+    let compiler = match rustc_minor_version() {
+        Some(compiler) => compiler,
+        None => return,
+    };
+
+    if compiler < 47 {
+        println!("cargo:rustc-cfg=self_span_hack");
+    }
+}
+
+fn rustc_minor_version() -> Option<u32> {
+    let rustc = env::var_os("RUSTC")?;
+    let output = Command::new(rustc).arg("--version").output().ok()?;
+    let version = str::from_utf8(&output.stdout).ok()?;
+    let mut pieces = version.split('.');
+    if pieces.next() != Some("rustc 1") {
+        return None;
+    }
+    pieces.next()?.parse().ok()
+}
diff --git a/src/expand.rs b/src/expand.rs
index fb83df1..e78c6c4 100644
--- a/src/expand.rs
+++ b/src/expand.rs
@@ -1,19 +1,23 @@
-use crate::lifetime::{has_async_lifetime, CollectLifetimes};
+use crate::lifetime::CollectLifetimes;
 use crate::parse::Item;
-use crate::receiver::{
-    has_self_in_block, has_self_in_sig, has_self_in_where_predicate, ReplaceReceiver,
-};
-use proc_macro2::{Span, TokenStream};
+use crate::receiver::{has_self_in_block, has_self_in_sig, mut_pat, ReplaceSelf};
+use proc_macro2::TokenStream;
 use quote::{format_ident, quote, quote_spanned, ToTokens};
-use std::mem;
+use std::collections::BTreeSet as Set;
 use syn::punctuated::Punctuated;
-use syn::visit_mut::VisitMut;
+use syn::visit_mut::{self, VisitMut};
 use syn::{
-    parse_quote, Block, FnArg, GenericParam, Generics, Ident, ImplItem, Lifetime, Pat, PatIdent,
-    Path, Receiver, ReturnType, Signature, Stmt, Token, TraitItem, Type, TypeParam, TypeParamBound,
-    WhereClause,
+    parse_quote, Attribute, Block, FnArg, GenericParam, Generics, Ident, ImplItem, Lifetime, Pat,
+    PatIdent, Receiver, ReturnType, Signature, Stmt, Token, TraitItem, Type, TypeParamBound,
+    TypePath, WhereClause,
 };
 
+macro_rules! parse_quote_spanned {
+    ($span:expr=> $($t:tt)*) => {
+        syn::parse2(quote_spanned!($span=> $($t)*)).unwrap()
+    };
+}
+
 impl ToTokens for Item {
     fn to_tokens(&self, tokens: &mut TokenStream) {
         match self {
@@ -26,14 +30,12 @@
 #[derive(Clone, Copy)]
 enum Context<'a> {
     Trait {
-        name: &'a Ident,
         generics: &'a Generics,
         supertraits: &'a Supertraits,
     },
     Impl {
         impl_generics: &'a Generics,
-        receiver: &'a Type,
-        as_trait: &'a Path,
+        associated_type_impl_traits: &'a Set<Ident>,
     },
 }
 
@@ -59,7 +61,6 @@
     match input {
         Item::Trait(input) => {
             let context = Context::Trait {
-                name: &input.ident,
                 generics: &input.generics,
                 supertraits: &input.supertraits,
             };
@@ -69,32 +70,40 @@
                     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, has_self, is_local);
-                            method
-                                .attrs
-                                .push(parse_quote!(#[allow(clippy::used_underscore_binding)]));
+                            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);
-                        method.attrs.push(parse_quote!(#[must_use]));
                     }
                 }
             }
         }
         Item::Impl(input) => {
-            let mut lifetimes = CollectLifetimes::new("'impl");
+            let mut lifetimes = CollectLifetimes::new("'impl", input.impl_token.span);
             lifetimes.visit_type_mut(&mut *input.self_ty);
             lifetimes.visit_path_mut(&mut input.trait_.as_mut().unwrap().1);
             let params = &input.generics.params;
             let elided = lifetimes.elided;
             input.generics.params = parse_quote!(#(#elided,)* #params);
 
+            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,
-                receiver: &input.self_ty,
-                as_trait: &input.trait_.as_ref().unwrap().1,
+                associated_type_impl_traits: &associated_type_impl_traits,
             };
             for inner in &mut input.items {
                 if let ImplItem::Method(method) = inner {
@@ -102,11 +111,9 @@
                     if sig.asyncness.is_some() {
                         let block = &mut method.block;
                         let has_self = has_self_in_sig(sig) || has_self_in_block(block);
-                        transform_block(context, sig, block, has_self, is_local);
+                        transform_block(context, sig, block);
                         transform_sig(context, sig, has_self, false, is_local);
-                        method
-                            .attrs
-                            .push(parse_quote!(#[allow(clippy::used_underscore_binding)]));
+                        method.attrs.push(lint_suppress_with_body());
                     }
                 }
             }
@@ -114,6 +121,26 @@
     }
 }
 
+fn lint_suppress_with_body() -> Attribute {
+    parse_quote! {
+        #[allow(
+            clippy::let_unit_value,
+            clippy::type_complexity,
+            clippy::type_repetition_in_bounds,
+            clippy::used_underscore_binding
+        )]
+    }
+}
+
+fn lint_suppress_without_body() -> Attribute {
+    parse_quote! {
+        #[allow(
+            clippy::type_complexity,
+            clippy::type_repetition_in_bounds
+        )]
+    }
+}
+
 // Input:
 //     async fn f<T>(&self, x: &T) -> Ret;
 //
@@ -141,7 +168,13 @@
         ReturnType::Type(_, ret) => quote!(#ret),
     };
 
-    let mut lifetimes = CollectLifetimes::new("'life");
+    let default_span = sig
+        .ident
+        .span()
+        .join(sig.paren_token.span)
+        .unwrap_or_else(|| sig.ident.span());
+
+    let mut lifetimes = CollectLifetimes::new("'life", default_span);
     for arg in sig.inputs.iter_mut() {
         match arg {
             FnArg::Receiver(arg) => lifetimes.visit_receiver_mut(arg),
@@ -149,13 +182,6 @@
         }
     }
 
-    let where_clause = sig
-        .generics
-        .where_clause
-        .get_or_insert_with(|| WhereClause {
-            where_token: Default::default(),
-            predicates: Punctuated::new(),
-        });
     for param in sig
         .generics
         .params
@@ -165,33 +191,48 @@
         match param {
             GenericParam::Type(param) => {
                 let param = &param.ident;
-                where_clause
+                let span = param.span();
+                where_clause_or_default(&mut sig.generics.where_clause)
                     .predicates
-                    .push(parse_quote!(#param: 'async_trait));
+                    .push(parse_quote_spanned!(span=> #param: 'async_trait));
             }
             GenericParam::Lifetime(param) => {
                 let param = &param.lifetime;
-                where_clause
+                let span = param.span();
+                where_clause_or_default(&mut sig.generics.where_clause)
                     .predicates
-                    .push(parse_quote!(#param: 'async_trait));
+                    .push(parse_quote_spanned!(span=> #param: 'async_trait));
             }
             GenericParam::Const(_) => {}
         }
     }
+
+    if sig.generics.lt_token.is_none() {
+        sig.generics.lt_token = Some(Token![<](sig.ident.span()));
+    }
+    if sig.generics.gt_token.is_none() {
+        sig.generics.gt_token = Some(Token![>](sig.paren_token.span));
+    }
+
     for elided in lifetimes.elided {
         sig.generics.params.push(parse_quote!(#elided));
-        where_clause
+        where_clause_or_default(&mut sig.generics.where_clause)
             .predicates
-            .push(parse_quote!(#elided: 'async_trait));
+            .push(parse_quote_spanned!(elided.span()=> #elided: 'async_trait));
     }
-    sig.generics.params.push(parse_quote!('async_trait));
+
+    sig.generics
+        .params
+        .push(parse_quote_spanned!(default_span=> 'async_trait));
+
     if has_self {
-        let bound: Ident = match sig.inputs.iter().next() {
+        let bound_span = sig.ident.span();
+        let bound = match sig.inputs.iter().next() {
             Some(FnArg::Receiver(Receiver {
                 reference: Some(_),
                 mutability: None,
                 ..
-            })) => parse_quote!(Sync),
+            })) => Ident::new("Sync", bound_span),
             Some(FnArg::Typed(arg))
                 if match (arg.pat.as_ref(), arg.ty.as_ref()) {
                     (Pat::Ident(pat), Type::Reference(ty)) => {
@@ -200,18 +241,21 @@
                     _ => false,
                 } =>
             {
-                parse_quote!(Sync)
+                Ident::new("Sync", bound_span)
             }
-            _ => parse_quote!(Send),
+            _ => Ident::new("Send", bound_span),
         };
+
         let assume_bound = match context {
             Context::Trait { supertraits, .. } => !has_default || has_bound(supertraits, &bound),
             Context::Impl { .. } => true,
         };
+
+        let where_clause = where_clause_or_default(&mut sig.generics.where_clause);
         where_clause.predicates.push(if assume_bound || is_local {
-            parse_quote!(Self: 'async_trait)
+            parse_quote_spanned!(bound_span=> Self: 'async_trait)
         } else {
-            parse_quote!(Self: ::core::marker::#bound + 'async_trait)
+            parse_quote_spanned!(bound_span=> Self: ::core::marker::#bound + 'async_trait)
         });
     }
 
@@ -226,20 +270,21 @@
                     ident.by_ref = None;
                     ident.mutability = None;
                 } else {
-                    let positional = positional_arg(i);
-                    *arg.pat = parse_quote!(#positional);
+                    let positional = positional_arg(i, &arg.pat);
+                    let m = mut_pat(&mut arg.pat);
+                    arg.pat = parse_quote!(#m #positional);
                 }
             }
         }
     }
 
+    let ret_span = sig.ident.span();
     let bounds = if is_local {
-        quote!('async_trait)
+        quote_spanned!(ret_span=> 'async_trait)
     } else {
-        quote!(::core::marker::Send + 'async_trait)
+        quote_spanned!(ret_span=> ::core::marker::Send + 'async_trait)
     };
-
-    sig.output = parse_quote! {
+    sig.output = parse_quote_spanned! {ret_span=>
         -> ::core::pin::Pin<Box<
             dyn ::core::future::Future<Output = #ret> + #bounds
         >>
@@ -247,247 +292,105 @@
 }
 
 // Input:
-//     async fn f<T>(&self, x: &T) -> Ret {
-//         self + x
+//     async fn f<T>(&self, x: &T, (a, b): (A, B)) -> Ret {
+//         self + x + a + b
 //     }
 //
 // Output:
-//     async fn f<T, AsyncTrait>(_self: &AsyncTrait, x: &T) -> Ret {
-//         _self + x
-//     }
-//     Box::pin(async_trait_method::<T, Self>(self, x))
-fn transform_block(
-    context: Context,
-    sig: &mut Signature,
-    block: &mut Block,
-    has_self: bool,
-    is_local: bool,
-) {
+//     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) {
     if let Some(Stmt::Item(syn::Item::Verbatim(item))) = block.stmts.first() {
         if block.stmts.len() == 1 && item.to_string() == ";" {
             return;
         }
     }
 
-    let inner = format_ident!("__{}", sig.ident);
-    let args = sig.inputs.iter().enumerate().map(|(i, arg)| match arg {
-        FnArg::Receiver(Receiver { self_token, .. }) => quote!(#self_token),
-        FnArg::Typed(arg) => {
-            if let Pat::Ident(PatIdent { ident, .. }) = &*arg.pat {
-                quote!(#ident)
-            } else {
-                positional_arg(i).into_token_stream()
+    let mut self_span = None;
+    let decls = sig
+        .inputs
+        .iter()
+        .enumerate()
+        .map(|(i, arg)| match arg {
+            FnArg::Receiver(Receiver {
+                self_token,
+                mutability,
+                ..
+            }) => {
+                let ident = Ident::new("__self", self_token.span);
+                self_span = Some(self_token.span);
+                quote!(let #mutability #ident = #self_token;)
             }
-        }
-    });
-
-    let mut standalone = sig.clone();
-    standalone.ident = inner.clone();
-
-    let generics = match context {
-        Context::Trait { generics, .. } => generics,
-        Context::Impl { impl_generics, .. } => impl_generics,
-    };
-
-    let mut outer_generics = generics.clone();
-    for p in &mut outer_generics.params {
-        match p {
-            GenericParam::Type(t) => t.default = None,
-            GenericParam::Const(c) => c.default = None,
-            GenericParam::Lifetime(_) => {}
-        }
-    }
-    if !has_self {
-        if let Some(mut where_clause) = outer_generics.where_clause {
-            where_clause.predicates = where_clause
-                .predicates
-                .into_iter()
-                .filter_map(|mut pred| {
-                    if has_self_in_where_predicate(&mut pred) {
-                        None
+            FnArg::Typed(arg) => {
+                if let Pat::Ident(PatIdent {
+                    ident, mutability, ..
+                }) = &*arg.pat
+                {
+                    if ident == "self" {
+                        self_span = Some(ident.span());
+                        let prefixed = Ident::new("__self", ident.span());
+                        quote!(let #mutability #prefixed = #ident;)
                     } else {
-                        Some(pred)
+                        quote!(let #mutability #ident = #ident;)
                     }
-                })
-                .collect();
-            outer_generics.where_clause = Some(where_clause);
-        }
-    }
-
-    let fn_generics = mem::replace(&mut standalone.generics, outer_generics);
-    standalone.generics.params.extend(fn_generics.params);
-    if let Some(where_clause) = fn_generics.where_clause {
-        standalone
-            .generics
-            .make_where_clause()
-            .predicates
-            .extend(where_clause.predicates);
-    }
-
-    if has_async_lifetime(&mut standalone, block) {
-        standalone.generics.params.push(parse_quote!('async_trait));
-    }
-
-    let mut types = standalone
-        .generics
-        .type_params()
-        .map(|param| param.ident.clone())
+                } else {
+                    let pat = &arg.pat;
+                    let ident = positional_arg(i, pat);
+                    quote!(let #pat = #ident;)
+                }
+            }
+        })
         .collect::<Vec<_>>();
 
-    let mut self_bound = None::<TypeParamBound>;
-    match standalone.inputs.iter_mut().next() {
-        Some(
-            arg @ FnArg::Receiver(Receiver {
-                reference: Some(_), ..
-            }),
-        ) => {
-            let (lifetime, mutability, self_token) = match arg {
-                FnArg::Receiver(Receiver {
-                    reference: Some((_, lifetime)),
-                    mutability,
-                    self_token,
-                    ..
-                }) => (lifetime, mutability, self_token),
-                _ => unreachable!(),
-            };
-            let under_self = Ident::new("_self", self_token.span);
-            match context {
-                Context::Trait { .. } => {
-                    self_bound = Some(match mutability {
-                        Some(_) => parse_quote!(::core::marker::Send),
-                        None => parse_quote!(::core::marker::Sync),
-                    });
-                    *arg = parse_quote! {
-                        #under_self: &#lifetime #mutability AsyncTrait
-                    };
+    if let Some(span) = self_span {
+        let mut replace_self = ReplaceSelf(span);
+        replace_self.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)* })
                 }
-                Context::Impl { receiver, .. } => {
-                    let mut ty = quote!(#receiver);
-                    if let Type::TraitObject(trait_object) = receiver {
-                        if trait_object.dyn_token.is_none() {
-                            ty = quote!(dyn #ty);
-                        }
-                        if trait_object.bounds.len() > 1 {
-                            ty = quote!((#ty));
-                        }
+            } else {
+                quote_spanned! {block.brace_token.span=>
+                    if let ::core::option::Option::Some(__ret) = ::core::option::Option::None::<#ret> {
+                        return __ret;
                     }
-                    *arg = parse_quote! {
-                        #under_self: &#lifetime #mutability #ty
-                    };
+                    #(#decls)*
+                    let __ret: #ret = { #(#stmts)* };
+                    #[allow(unreachable_code)]
+                    __ret
                 }
             }
         }
-        Some(arg @ FnArg::Receiver(_)) => {
-            let (self_token, mutability) = match arg {
-                FnArg::Receiver(Receiver {
-                    self_token,
-                    mutability,
-                    ..
-                }) => (self_token, mutability),
-                _ => unreachable!(),
-            };
-            let under_self = Ident::new("_self", self_token.span);
-            match context {
-                Context::Trait { .. } => {
-                    self_bound = Some(parse_quote!(::core::marker::Send));
-                    *arg = parse_quote! {
-                        #mutability #under_self: AsyncTrait
-                    };
-                }
-                Context::Impl { receiver, .. } => {
-                    *arg = parse_quote! {
-                        #mutability #under_self: #receiver
-                    };
-                }
-            }
-        }
-        Some(FnArg::Typed(arg)) => {
-            if let Pat::Ident(arg) = &mut *arg.pat {
-                if arg.ident == "self" {
-                    arg.ident = Ident::new("_self", arg.ident.span());
-                }
-            }
-        }
-        _ => {}
-    }
-
-    if let Context::Trait { name, generics, .. } = context {
-        if has_self {
-            let (_, generics, _) = generics.split_for_impl();
-            let mut self_param: TypeParam = parse_quote!(AsyncTrait: ?Sized + #name #generics);
-            if !is_local {
-                self_param.bounds.extend(self_bound);
-            }
-            let count = standalone
-                .generics
-                .params
-                .iter()
-                .take_while(|param| {
-                    if let GenericParam::Const(_) = param {
-                        false
-                    } else {
-                        true
-                    }
-                })
-                .count();
-            standalone
-                .generics
-                .params
-                .insert(count, GenericParam::Type(self_param));
-            types.push(Ident::new("Self", Span::call_site()));
-        }
-    }
-
-    if let Some(where_clause) = &mut standalone.generics.where_clause {
-        // Work around an input bound like `where Self::Output: Send` expanding
-        // to `where <AsyncTrait>::Output: Send` which is illegal syntax because
-        // `where<T>` is reserved for future use... :(
-        where_clause.predicates.insert(0, parse_quote!((): Sized));
-    }
-
-    let mut replace = match context {
-        Context::Trait { .. } => ReplaceReceiver::with(parse_quote!(AsyncTrait)),
-        Context::Impl {
-            receiver, as_trait, ..
-        } => ReplaceReceiver::with_as_trait(receiver.clone(), as_trait.clone()),
     };
-    replace.visit_signature_mut(&mut standalone);
-    replace.visit_block_mut(block);
-
-    let mut generics = types;
-    let consts = standalone
-        .generics
-        .const_params()
-        .map(|param| param.ident.clone());
-    generics.extend(consts);
-
-    let allow_non_snake_case = if sig.ident != sig.ident.to_string().to_lowercase() {
-        Some(quote!(non_snake_case,))
-    } else {
-        None
-    };
-
-    let brace = block.brace_token;
-    let box_pin = quote_spanned!(brace.span=> {
-        #[allow(
-            #allow_non_snake_case
-            unused_parens, // https://github.com/dtolnay/async-trait/issues/118
-            clippy::missing_docs_in_private_items,
-            clippy::needless_lifetimes,
-            clippy::ptr_arg,
-            clippy::trivially_copy_pass_by_ref,
-            clippy::type_repetition_in_bounds,
-            clippy::used_underscore_binding,
-        )]
-        #standalone #block
-        Box::pin(#inner::<#(#generics),*>(#(#args),*))
-    });
-    *block = parse_quote!(#box_pin);
-    block.brace_token = brace;
+    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) -> Ident {
-    format_ident!("__arg{}", i)
+fn positional_arg(i: usize, pat: &Pat) -> Ident {
+    use syn::spanned::Spanned;
+    format_ident!("__arg{}", i, span = pat.span())
 }
 
 fn has_bound(supertraits: &Supertraits, marker: &Ident) -> bool {
@@ -500,3 +403,45 @@
     }
     false
 }
+
+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(),
+    })
+}
diff --git a/src/lib.rs b/src/lib.rs
index 929af4f..100bee6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -303,7 +303,16 @@
 //! let object = &value as &dyn ObjectSafe;
 //! ```
 
-#![allow(clippy::match_like_matches_macro)] // matches! requires Rust 1.42
+#![allow(
+    clippy::default_trait_access,
+    clippy::doc_markdown,
+    clippy::if_not_else,
+    clippy::items_after_statements,
+    clippy::module_name_repetitions,
+    clippy::shadow_unrelated,
+    clippy::similar_names,
+    clippy::too_many_lines
+)]
 
 extern crate proc_macro;
 
@@ -312,7 +321,6 @@
 mod lifetime;
 mod parse;
 mod receiver;
-mod respan;
 
 use crate::args::Args;
 use crate::expand::expand;
diff --git a/src/lifetime.rs b/src/lifetime.rs
index 9d2066b..ff25d32 100644
--- a/src/lifetime.rs
+++ b/src/lifetime.rs
@@ -1,59 +1,43 @@
 use proc_macro2::Span;
 use syn::visit_mut::{self, VisitMut};
-use syn::{Block, GenericArgument, Item, Lifetime, Receiver, Signature, TypeReference};
-
-pub fn has_async_lifetime(sig: &mut Signature, block: &mut Block) -> bool {
-    let mut visitor = HasAsyncLifetime(false);
-    visitor.visit_signature_mut(sig);
-    visitor.visit_block_mut(block);
-    visitor.0
-}
-
-struct HasAsyncLifetime(bool);
-
-impl VisitMut for HasAsyncLifetime {
-    fn visit_lifetime_mut(&mut self, life: &mut Lifetime) {
-        self.0 |= life.to_string() == "'async_trait";
-    }
-
-    fn visit_item_mut(&mut self, _: &mut Item) {
-        // Do not recurse into nested items.
-    }
-}
+use syn::{GenericArgument, Lifetime, Receiver, TypeReference};
 
 pub struct CollectLifetimes {
     pub elided: Vec<Lifetime>,
     pub explicit: Vec<Lifetime>,
     pub name: &'static str,
+    pub default_span: Span,
 }
 
 impl CollectLifetimes {
-    pub fn new(name: &'static str) -> Self {
+    pub fn new(name: &'static str, default_span: Span) -> Self {
         CollectLifetimes {
             elided: Vec::new(),
             explicit: Vec::new(),
             name,
+            default_span,
         }
     }
 
     fn visit_opt_lifetime(&mut self, lifetime: &mut Option<Lifetime>) {
         match lifetime {
-            None => *lifetime = Some(self.next_lifetime()),
+            None => *lifetime = Some(self.next_lifetime(None)),
             Some(lifetime) => self.visit_lifetime(lifetime),
         }
     }
 
     fn visit_lifetime(&mut self, lifetime: &mut Lifetime) {
         if lifetime.ident == "_" {
-            *lifetime = self.next_lifetime();
+            *lifetime = self.next_lifetime(lifetime.span());
         } else {
             self.explicit.push(lifetime.clone());
         }
     }
 
-    fn next_lifetime(&mut self) -> Lifetime {
+    fn next_lifetime<S: Into<Option<Span>>>(&mut self, span: S) -> Lifetime {
         let name = format!("{}{}", self.name, self.elided.len());
-        let life = Lifetime::new(&name, Span::call_site());
+        let span = span.into().unwrap_or(self.default_span);
+        let life = Lifetime::new(&name, span);
         self.elided.push(life.clone());
         life
     }
diff --git a/src/receiver.rs b/src/receiver.rs
index 4273359..64ab65e 100644
--- a/src/receiver.rs
+++ b/src/receiver.rs
@@ -1,14 +1,9 @@
-use crate::respan::respan;
-use proc_macro2::{Group, Spacing, Span, TokenStream, TokenTree};
-use quote::{quote, quote_spanned};
+use proc_macro2::{Group, Span, TokenStream, TokenTree};
 use std::iter::FromIterator;
-use std::mem;
-use syn::punctuated::Punctuated;
 use syn::visit_mut::{self, VisitMut};
 use syn::{
-    parse_quote, Block, Error, ExprPath, ExprStruct, Ident, Item, Macro, PatPath, PatStruct,
-    PatTupleStruct, Path, PathArguments, QSelf, Receiver, Signature, Token, Type, TypePath,
-    WherePredicate,
+    Block, ExprPath, Ident, Item, Macro, Pat, PatIdent, PatPath, Receiver, Signature, Token,
+    TypePath,
 };
 
 pub fn has_self_in_sig(sig: &mut Signature) -> bool {
@@ -17,12 +12,6 @@
     visitor.0
 }
 
-pub fn has_self_in_where_predicate(where_predicate: &mut WherePredicate) -> bool {
-    let mut visitor = HasSelf(false);
-    visitor.visit_where_predicate_mut(where_predicate);
-    visitor.0
-}
-
 pub fn has_self_in_block(block: &mut Block) -> bool {
     let mut visitor = HasSelf(false);
     visitor.visit_block_mut(block);
@@ -37,6 +26,32 @@
     })
 }
 
+pub fn mut_pat(pat: &mut Pat) -> Option<Token![mut]> {
+    let mut visitor = HasMutPat(None);
+    visitor.visit_pat_mut(pat);
+    visitor.0
+}
+
+fn contains_fn(tokens: TokenStream) -> bool {
+    tokens.into_iter().any(|tt| match tt {
+        TokenTree::Ident(ident) => ident == "fn",
+        TokenTree::Group(group) => contains_fn(group.stream()),
+        _ => false,
+    })
+}
+
+struct HasMutPat(Option<Token![mut]>);
+
+impl VisitMut for HasMutPat {
+    fn visit_pat_ident_mut(&mut self, i: &mut PatIdent) {
+        if let Some(m) = i.mutability {
+            self.0 = Some(m);
+        } else {
+            visit_mut::visit_pat_ident_mut(self, i);
+        }
+    }
+}
+
 struct HasSelf(bool);
 
 impl VisitMut for HasSelf {
@@ -70,225 +85,67 @@
     }
 }
 
-pub struct ReplaceReceiver {
-    pub with: Type,
-    pub as_trait: Option<Path>,
-}
+pub struct ReplaceSelf(pub Span);
 
-impl ReplaceReceiver {
-    pub fn with(ty: Type) -> Self {
-        ReplaceReceiver {
-            with: ty,
-            as_trait: None,
-        }
-    }
-
-    pub fn with_as_trait(ty: Type, as_trait: Path) -> Self {
-        ReplaceReceiver {
-            with: ty,
-            as_trait: Some(as_trait),
-        }
-    }
-
-    fn self_ty(&self, span: Span) -> Type {
-        respan(&self.with, span)
-    }
-
-    fn self_to_qself_type(&self, qself: &mut Option<QSelf>, path: &mut Path) {
-        let include_as_trait = true;
-        self.self_to_qself(qself, path, include_as_trait);
-    }
-
-    fn self_to_qself_expr(&self, qself: &mut Option<QSelf>, path: &mut Path) {
-        let include_as_trait = false;
-        self.self_to_qself(qself, path, include_as_trait);
-    }
-
-    fn self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path, include_as_trait: bool) {
-        if path.leading_colon.is_some() {
-            return;
-        }
-
-        let first = &path.segments[0];
-        if first.ident != "Self" || !first.arguments.is_empty() {
-            return;
-        }
-
-        if path.segments.len() == 1 {
-            self.self_to_expr_path(path);
-            return;
-        }
-
-        let span = first.ident.span();
-        *qself = Some(QSelf {
-            lt_token: Token![<](span),
-            ty: Box::new(self.self_ty(span)),
-            position: 0,
-            as_token: None,
-            gt_token: Token![>](span),
-        });
-
-        if include_as_trait && self.as_trait.is_some() {
-            let as_trait = self.as_trait.as_ref().unwrap().clone();
-            path.leading_colon = as_trait.leading_colon;
-            qself.as_mut().unwrap().position = as_trait.segments.len();
-
-            let segments = mem::replace(&mut path.segments, as_trait.segments);
-            path.segments.push_punct(Default::default());
-            path.segments.extend(segments.into_pairs().skip(1));
-        } else {
-            path.leading_colon = Some(**path.segments.pairs().next().unwrap().punct().unwrap());
-
-            let segments = mem::replace(&mut path.segments, Punctuated::new());
-            path.segments = segments.into_pairs().skip(1).collect();
-        }
-    }
-
-    fn self_to_expr_path(&self, path: &mut Path) {
-        if path.leading_colon.is_some() {
-            return;
-        }
-
-        let first = &path.segments[0];
-        if first.ident != "Self" || !first.arguments.is_empty() {
-            return;
-        }
-
-        if let Type::Path(self_ty) = self.self_ty(first.ident.span()) {
-            let variant = mem::replace(path, self_ty.path);
-            for segment in &mut path.segments {
-                if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments {
-                    if bracketed.colon2_token.is_none() && !bracketed.args.is_empty() {
-                        bracketed.colon2_token = Some(Default::default());
-                    }
-                }
-            }
-            if variant.segments.len() > 1 {
-                path.segments.push_punct(Default::default());
-                path.segments.extend(variant.segments.into_pairs().skip(1));
-            }
-        } else {
-            let span = path.segments[0].ident.span();
-            let msg = "Self type of this impl is unsupported in expression position";
-            let error = Error::new(span, msg).to_compile_error();
-            *path = parse_quote!(::core::marker::PhantomData::<#error>);
-        }
-    }
-
-    fn visit_token_stream(&self, tokens: &mut TokenStream) -> bool {
-        let mut out = Vec::new();
-        let mut modified = false;
-        let mut iter = tokens.clone().into_iter().peekable();
-        while let Some(tt) = iter.next() {
-            match tt {
-                TokenTree::Ident(mut ident) => {
-                    modified |= prepend_underscore_to_self(&mut ident);
-                    if ident == "Self" {
-                        modified = true;
-                        if self.as_trait.is_none() {
-                            let ident = Ident::new("AsyncTrait", ident.span());
-                            out.push(TokenTree::Ident(ident));
-                        } else {
-                            let self_ty = self.self_ty(ident.span());
-                            match iter.peek() {
-                                Some(TokenTree::Punct(p))
-                                    if p.as_char() == ':' && p.spacing() == Spacing::Joint =>
-                                {
-                                    let next = iter.next().unwrap();
-                                    match iter.peek() {
-                                        Some(TokenTree::Punct(p)) if p.as_char() == ':' => {
-                                            let span = ident.span();
-                                            out.extend(quote_spanned!(span=> <#self_ty>));
-                                        }
-                                        _ => out.extend(quote!(#self_ty)),
-                                    }
-                                    out.push(next);
-                                }
-                                _ => out.extend(quote!(#self_ty)),
-                            }
-                        }
-                    } else {
-                        out.push(TokenTree::Ident(ident));
-                    }
-                }
-                TokenTree::Group(group) => {
-                    let mut content = group.stream();
-                    modified |= self.visit_token_stream(&mut content);
-                    let mut new = Group::new(group.delimiter(), content);
-                    new.set_span(group.span());
-                    out.push(TokenTree::Group(new));
-                }
-                other => out.push(other),
-            }
-        }
+impl ReplaceSelf {
+    #[cfg_attr(not(self_span_hack), allow(clippy::unused_self))]
+    fn prepend_underscore_to_self(&self, ident: &mut Ident) -> bool {
+        let modified = ident == "self";
         if modified {
-            *tokens = TokenStream::from_iter(out);
+            *ident = Ident::new("__self", ident.span());
+            #[cfg(self_span_hack)]
+            ident.set_span(self.0);
         }
         modified
     }
+
+    fn visit_token_stream(&mut self, tokens: &mut TokenStream) -> bool {
+        let mut out = Vec::new();
+        let mut modified = false;
+        visit_token_stream_impl(self, tokens.clone(), &mut modified, &mut out);
+        if modified {
+            *tokens = TokenStream::from_iter(out);
+        }
+        return modified;
+
+        fn visit_token_stream_impl(
+            visitor: &mut ReplaceSelf,
+            tokens: TokenStream,
+            modified: &mut bool,
+            out: &mut Vec<TokenTree>,
+        ) {
+            for tt in tokens {
+                match tt {
+                    TokenTree::Ident(mut ident) => {
+                        *modified |= visitor.prepend_underscore_to_self(&mut ident);
+                        out.push(TokenTree::Ident(ident));
+                    }
+                    TokenTree::Group(group) => {
+                        let mut content = group.stream();
+                        *modified |= visitor.visit_token_stream(&mut content);
+                        let mut new = Group::new(group.delimiter(), content);
+                        new.set_span(group.span());
+                        out.push(TokenTree::Group(new));
+                    }
+                    other => out.push(other),
+                }
+            }
+        }
+    }
 }
 
-impl VisitMut for ReplaceReceiver {
-    // `Self` -> `Receiver`
-    fn visit_type_mut(&mut self, ty: &mut Type) {
-        if let Type::Path(node) = ty {
-            if node.qself.is_none() && node.path.is_ident("Self") {
-                *ty = self.self_ty(node.path.segments[0].ident.span());
-            } else {
-                self.visit_type_path_mut(node);
-            }
-        } else {
-            visit_mut::visit_type_mut(self, ty);
-        }
-    }
-
-    // `Self::Assoc` -> `<Receiver>::Assoc`
-    fn visit_type_path_mut(&mut self, ty: &mut TypePath) {
-        if ty.qself.is_none() {
-            self.self_to_qself_type(&mut ty.qself, &mut ty.path);
-        }
-        visit_mut::visit_type_path_mut(self, ty);
-    }
-
-    // `Self::method` -> `<Receiver>::method`
-    fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) {
-        if expr.qself.is_none() {
-            prepend_underscore_to_self(&mut expr.path.segments[0].ident);
-            self.self_to_qself_expr(&mut expr.qself, &mut expr.path);
-        }
-        visit_mut::visit_expr_path_mut(self, expr);
-    }
-
-    fn visit_expr_struct_mut(&mut self, expr: &mut ExprStruct) {
-        self.self_to_expr_path(&mut expr.path);
-        visit_mut::visit_expr_struct_mut(self, expr);
-    }
-
-    fn visit_pat_path_mut(&mut self, pat: &mut PatPath) {
-        if pat.qself.is_none() {
-            self.self_to_qself_expr(&mut pat.qself, &mut pat.path);
-        }
-        visit_mut::visit_pat_path_mut(self, pat);
-    }
-
-    fn visit_pat_struct_mut(&mut self, pat: &mut PatStruct) {
-        self.self_to_expr_path(&mut pat.path);
-        visit_mut::visit_pat_struct_mut(self, pat);
-    }
-
-    fn visit_pat_tuple_struct_mut(&mut self, pat: &mut PatTupleStruct) {
-        self.self_to_expr_path(&mut pat.path);
-        visit_mut::visit_pat_tuple_struct_mut(self, pat);
+impl VisitMut for ReplaceSelf {
+    fn visit_ident_mut(&mut self, i: &mut Ident) {
+        self.prepend_underscore_to_self(i);
     }
 
     fn visit_item_mut(&mut self, i: &mut Item) {
-        match i {
-            // Visit `macro_rules!` because locally defined macros can refer to `self`.
-            Item::Macro(i) if i.mac.path.is_ident("macro_rules") => {
+        // Visit `macro_rules!` because locally defined macros can refer to
+        // `self`. Otherwise, do not recurse into nested items.
+        if let Item::Macro(i) = i {
+            if i.mac.path.is_ident("macro_rules") {
                 self.visit_macro_mut(&mut i.mac)
             }
-            // Otherwise, do not recurse into nested items.
-            _ => {}
         }
     }
 
@@ -303,19 +160,3 @@
         }
     }
 }
-
-fn contains_fn(tokens: TokenStream) -> bool {
-    tokens.into_iter().any(|tt| match tt {
-        TokenTree::Ident(ident) => ident == "fn",
-        TokenTree::Group(group) => contains_fn(group.stream()),
-        _ => false,
-    })
-}
-
-fn prepend_underscore_to_self(ident: &mut Ident) -> bool {
-    let modified = ident == "self";
-    if modified {
-        *ident = Ident::new("_self", ident.span());
-    }
-    modified
-}
diff --git a/src/respan.rs b/src/respan.rs
deleted file mode 100644
index 38f6612..0000000
--- a/src/respan.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-use proc_macro2::{Span, TokenStream};
-use quote::ToTokens;
-use syn::parse::Parse;
-
-pub(crate) fn respan<T>(node: &T, span: Span) -> T
-where
-    T: ToTokens + Parse,
-{
-    let tokens = node.to_token_stream();
-    let respanned = respan_tokens(tokens, span);
-    syn::parse2(respanned).unwrap()
-}
-
-fn respan_tokens(tokens: TokenStream, span: Span) -> TokenStream {
-    tokens
-        .into_iter()
-        .map(|mut token| {
-            token.set_span(span);
-            token
-        })
-        .collect()
-}
diff --git a/tests/executor/mod.rs b/tests/executor/mod.rs
index f48b348..912fb79 100644
--- a/tests/executor/mod.rs
+++ b/tests/executor/mod.rs
@@ -4,6 +4,7 @@
 use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
 
 // Executor for a future that resolves immediately (test only).
+#[allow(clippy::missing_panics_doc)]
 pub fn block_on_simple<F: Future>(mut fut: F) -> F::Output {
     unsafe fn clone(_null: *const ()) -> RawWaker {
         unimplemented!()
diff --git a/tests/test.rs b/tests/test.rs
index 5fc238b..604d092 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -1,6 +1,12 @@
 #![cfg_attr(
     async_trait_nightly_testing,
-    feature(min_specialization, min_const_generics)
+    feature(min_specialization, min_const_generics, type_alias_impl_trait)
+)]
+#![allow(
+    clippy::let_underscore_drop,
+    clippy::let_unit_value,
+    clippy::missing_panics_doc,
+    clippy::trivially_copy_pass_by_ref
 )]
 
 use async_trait::async_trait;
@@ -151,6 +157,79 @@
 #[async_trait]
 unsafe trait UnsafeTraitPrivate {}
 
+pub async fn test_can_destruct() {
+    #[async_trait]
+    trait CanDestruct {
+        async fn f(&self, foos: (u8, u8, u8, u8));
+    }
+
+    #[async_trait]
+    impl CanDestruct for Struct {
+        async fn f(&self, (a, ref mut b, ref c, d): (u8, u8, u8, u8)) {
+            let _a: u8 = a;
+            let _b: &mut u8 = b;
+            let _c: &u8 = c;
+            let _d: u8 = d;
+        }
+    }
+}
+
+pub async fn test_self_in_macro() {
+    #[async_trait]
+    trait Trait {
+        async fn a(self);
+        async fn b(&mut self);
+        async fn c(&self);
+    }
+
+    #[async_trait]
+    impl Trait for String {
+        async fn a(self) {
+            println!("{}", self);
+        }
+        async fn b(&mut self) {
+            println!("{}", self);
+        }
+        async fn c(&self) {
+            println!("{}", self);
+        }
+    }
+}
+
+pub async fn test_inference() {
+    #[async_trait]
+    pub trait Trait {
+        async fn f() -> Box<dyn Iterator<Item = ()>> {
+            Box::new(std::iter::empty())
+        }
+    }
+}
+
+pub async fn test_internal_items() {
+    #[async_trait]
+    #[allow(dead_code, clippy::items_after_statements)]
+    pub trait Trait: Sized {
+        async fn f(self) {
+            struct Struct;
+
+            impl Struct {
+                fn f(self) {
+                    let _ = self;
+                }
+            }
+        }
+    }
+}
+
+pub async fn test_unimplemented() {
+    #[async_trait]
+    pub trait Trait {
+        async fn f() {
+            unimplemented!()
+        }
+    }
+}
+
 // https://github.com/dtolnay/async-trait/issues/1
 pub mod issue1 {
     use async_trait::async_trait;
@@ -536,6 +615,7 @@
     }
 
     #[test]
+    #[should_panic]
     fn tracing() {
         // Create the future outside of the subscriber, as no call to tracing
         // should be made until the future is polled.
@@ -1077,3 +1157,168 @@
         }
     }
 }
+
+// https://github.com/dtolnay/async-trait/pull/125#pullrequestreview-491880881
+pub mod drop_order {
+    use crate::executor;
+    use async_trait::async_trait;
+    use std::sync::atomic::{AtomicBool, Ordering};
+
+    struct Flagger<'a>(&'a AtomicBool);
+
+    impl Drop for Flagger<'_> {
+        fn drop(&mut self) {
+            self.0.fetch_xor(true, Ordering::AcqRel);
+        }
+    }
+
+    #[async_trait]
+    trait Trait {
+        async fn async_trait(_: Flagger<'_>, flag: &AtomicBool);
+    }
+
+    struct Struct;
+
+    #[async_trait]
+    impl Trait for Struct {
+        async fn async_trait(_: Flagger<'_>, flag: &AtomicBool) {
+            flag.fetch_or(true, Ordering::AcqRel);
+        }
+    }
+
+    async fn standalone(_: Flagger<'_>, flag: &AtomicBool) {
+        flag.fetch_or(true, Ordering::AcqRel);
+    }
+
+    #[async_trait]
+    trait SelfTrait {
+        async fn async_trait(self, flag: &AtomicBool);
+    }
+
+    #[async_trait]
+    impl SelfTrait for Flagger<'_> {
+        async fn async_trait(self, flag: &AtomicBool) {
+            flag.fetch_or(true, Ordering::AcqRel);
+        }
+    }
+
+    #[test]
+    fn test_drop_order() {
+        // 0 : 0 ^ 1 = 1 | 1 = 1 (if flagger then block)
+        // 0 : 0 | 1 = 1 ^ 1 = 0 (if block then flagger)
+
+        let flag = AtomicBool::new(false);
+        executor::block_on_simple(standalone(Flagger(&flag), &flag));
+        assert!(!flag.load(Ordering::Acquire));
+
+        executor::block_on_simple(Struct::async_trait(Flagger(&flag), &flag));
+        assert!(!flag.load(Ordering::Acquire));
+
+        executor::block_on_simple(Flagger(&flag).async_trait(&flag));
+        assert!(!flag.load(Ordering::Acquire));
+    }
+}
+
+// https://github.com/dtolnay/async-trait/issues/145
+pub mod issue145 {
+    #![deny(clippy::type_complexity)]
+
+    use async_trait::async_trait;
+
+    #[async_trait]
+    pub trait ManageConnection: Sized + Send + Sync + 'static {
+        type Connection: Send + 'static;
+        type Error: Send + 'static;
+
+        async fn connect(&self) -> Result<Self::Connection, Self::Error>;
+    }
+}
+
+// https://github.com/dtolnay/async-trait/issues/147
+pub mod issue147 {
+    #![deny(clippy::let_unit_value)]
+
+    use async_trait::async_trait;
+
+    pub struct MyType;
+
+    #[async_trait]
+    pub trait MyTrait {
+        async fn x();
+        async fn y() -> ();
+        async fn z();
+    }
+
+    #[async_trait]
+    impl MyTrait for MyType {
+        async fn x() {}
+        async fn y() -> () {}
+        async fn z() {
+            unimplemented!()
+        }
+    }
+}
+
+// https://github.com/dtolnay/async-trait/issues/149
+pub mod issue149 {
+    use async_trait::async_trait;
+
+    pub struct Thing;
+    pub trait Ret {}
+    impl Ret for Thing {}
+
+    pub async fn ok() -> &'static dyn Ret {
+        return &Thing;
+    }
+
+    #[async_trait]
+    pub trait Trait {
+        async fn fail() -> &'static dyn Ret {
+            return &Thing;
+        }
+    }
+}
+
+// https://github.com/dtolnay/async-trait/issues/152
+#[cfg(async_trait_nightly_testing)]
+pub mod issue152 {
+    use async_trait::async_trait;
+
+    #[async_trait]
+    trait Trait {
+        type Assoc;
+
+        async fn f(&self) -> Self::Assoc;
+    }
+
+    struct Struct;
+
+    #[async_trait]
+    impl Trait for Struct {
+        type Assoc = impl Sized;
+
+        async fn f(&self) -> Self::Assoc {}
+    }
+}
+
+// https://github.com/dtolnay/async-trait/issues/154
+pub mod issue154 {
+    #![deny(clippy::items_after_statements)]
+
+    use async_trait::async_trait;
+
+    #[async_trait]
+    pub trait MyTrait {
+        async fn f(&self);
+    }
+
+    pub struct Struct;
+
+    #[async_trait]
+    impl MyTrait for Struct {
+        async fn f(&self) {
+            const MAX: u16 = 128;
+            println!("{}", MAX);
+        }
+    }
+}
diff --git a/tests/ui/delimiter-span.rs b/tests/ui/delimiter-span.rs
index 68456fa..d3f67a1 100644
--- a/tests/ui/delimiter-span.rs
+++ b/tests/ui/delimiter-span.rs
@@ -1,7 +1,7 @@
 use async_trait::async_trait;
 
 macro_rules! picky {
-    (ident) => {};
+    ($(t:tt)*) => {};
 }
 
 #[async_trait]
@@ -14,6 +14,7 @@
 #[async_trait]
 impl Trait for Struct {
     async fn method() {
+        picky!({ 123, self });
         picky!({ 123 });
     }
 }
diff --git a/tests/ui/delimiter-span.stderr b/tests/ui/delimiter-span.stderr
index e080445..6120262 100644
--- a/tests/ui/delimiter-span.stderr
+++ b/tests/ui/delimiter-span.stderr
@@ -4,5 +4,14 @@
 3  | macro_rules! picky {
    | ------------------ when calling this macro
 ...
-17 |         picky!({ 123 });
+17 |         picky!({ 123, self });
+   |                ^ no rules expected this token in macro call
+
+error: no rules expected the token `{`
+  --> $DIR/delimiter-span.rs:18:16
+   |
+3  | macro_rules! picky {
+   | ------------------ when calling this macro
+...
+18 |         picky!({ 123 });
    |                ^ no rules expected this token in macro call
diff --git a/tests/ui/lifetime-span.rs b/tests/ui/lifetime-span.rs
new file mode 100644
index 0000000..4e9e5d9
--- /dev/null
+++ b/tests/ui/lifetime-span.rs
@@ -0,0 +1,36 @@
+use async_trait::async_trait;
+
+struct A;
+struct B;
+
+#[async_trait]
+pub trait Trait<'r> {
+    async fn method(&'r self);
+}
+
+#[async_trait]
+impl Trait for A {
+    async fn method(&self) { }
+}
+
+#[async_trait]
+impl<'r> Trait<'r> for B {
+    async fn method(&self) { }
+}
+
+#[async_trait]
+pub trait Trait2 {
+    async fn method<'r>(&'r self);
+}
+
+#[async_trait]
+impl Trait2 for A {
+    async fn method(&self) { }
+}
+
+#[async_trait]
+impl<'r> Trait2<'r> for B {
+    async fn method(&'r self) { }
+}
+
+fn main() {}
diff --git a/tests/ui/lifetime-span.stderr b/tests/ui/lifetime-span.stderr
new file mode 100644
index 0000000..feae87f
--- /dev/null
+++ b/tests/ui/lifetime-span.stderr
@@ -0,0 +1,46 @@
+error[E0726]: implicit elided lifetime not allowed here
+  --> $DIR/lifetime-span.rs:12:6
+   |
+12 | impl Trait for A {
+   |      ^^^^^- help: indicate the anonymous lifetime: `<'_>`
+
+error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
+  --> $DIR/lifetime-span.rs:32:10
+   |
+32 | impl<'r> Trait2<'r> for B {
+   |          ^^^^^^---- help: remove these generics
+   |          |
+   |          expected 0 lifetime arguments
+   |
+note: trait defined here, with 0 lifetime parameters
+  --> $DIR/lifetime-span.rs:22:11
+   |
+22 | pub trait Trait2 {
+   |           ^^^^^^
+
+error[E0195]: lifetime parameters or bounds on method `method` do not match the trait declaration
+  --> $DIR/lifetime-span.rs:13:14
+   |
+8  |     async fn method(&'r self);
+   |              ---------------- lifetimes in impl do not match this method in trait
+...
+13 |     async fn method(&self) { }
+   |              ^^^^^^^^^^^^^ lifetimes do not match method in trait
+
+error[E0195]: lifetime parameters or bounds on method `method` do not match the trait declaration
+  --> $DIR/lifetime-span.rs:18:14
+   |
+8  |     async fn method(&'r self);
+   |              ---------------- lifetimes in impl do not match this method in trait
+...
+18 |     async fn method(&self) { }
+   |              ^^^^^^^^^^^^^ lifetimes do not match method in trait
+
+error[E0195]: lifetime parameters or bounds on method `method` do not match the trait declaration
+  --> $DIR/lifetime-span.rs:33:14
+   |
+23 |     async fn method<'r>(&'r self);
+   |                    ---- lifetimes in impl do not match this method in trait
+...
+33 |     async fn method(&'r self) { }
+   |              ^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
diff --git a/tests/ui/self-span.stderr b/tests/ui/self-span.stderr
index fb11528..9ea1bbe 100644
--- a/tests/ui/self-span.stderr
+++ b/tests/ui/self-span.stderr
@@ -1,12 +1,3 @@
-error[E0423]: expected value, found struct `S`
-  --> $DIR/self-span.rs:18:23
-   |
-3  | pub struct S {}
-   | --------------- `S` defined here
-...
-18 |         let _: Self = Self;
-   |                       ^^^^ help: use struct literal syntax instead: `S {}`
-
 error[E0308]: mismatched types
   --> $DIR/self-span.rs:17:21
    |
@@ -15,6 +6,12 @@
    |                |
    |                expected due to this
 
+error: the `Self` constructor can only be used with tuple or unit structs
+  --> $DIR/self-span.rs:18:23
+   |
+18 |         let _: Self = Self;
+   |                       ^^^^ help: use curly brackets: `Self { /* fields */ }`
+
 error[E0308]: mismatched types
   --> $DIR/self-span.rs:25:21
    |
diff --git a/tests/ui/send-not-implemented.rs b/tests/ui/send-not-implemented.rs
index a3e3856..d8883fb 100644
--- a/tests/ui/send-not-implemented.rs
+++ b/tests/ui/send-not-implemented.rs
@@ -10,6 +10,13 @@
         let _guard = mutex.lock().unwrap();
         f().await;
     }
+
+    async fn test_ret(&self) -> bool {
+        let mutex = Mutex::new(());
+        let _guard = mutex.lock().unwrap();
+        f().await;
+        true
+    }
 }
 
 fn main() {}
diff --git a/tests/ui/send-not-implemented.stderr b/tests/ui/send-not-implemented.stderr
index 05c445b..473a31b 100644
--- a/tests/ui/send-not-implemented.stderr
+++ b/tests/ui/send-not-implemented.stderr
@@ -7,7 +7,7 @@
 10 | |         let _guard = mutex.lock().unwrap();
 11 | |         f().await;
 12 | |     }
-   | |_____^ future returned by `__test` is not `Send`
+   | |_____^ future created by async block is not `Send`
    |
    = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
 note: future is not `Send` as this value is used across an await
@@ -20,3 +20,28 @@
 12 |     }
    |     - `_guard` is later dropped here
    = note: required for the cast to the object type `dyn Future<Output = ()> + Send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/send-not-implemented.rs:14:38
+   |
+14 |       async fn test_ret(&self) -> bool {
+   |  ______________________________________^
+15 | |         let mutex = Mutex::new(());
+16 | |         let _guard = mutex.lock().unwrap();
+17 | |         f().await;
+18 | |         true
+19 | |     }
+   | |_____^ future created by async block is not `Send`
+   |
+   = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/send-not-implemented.rs:17:9
+   |
+16 |         let _guard = mutex.lock().unwrap();
+   |             ------ has type `MutexGuard<'_, ()>` which is not `Send`
+17 |         f().await;
+   |         ^^^^^^^^^ await occurs here, with `_guard` maybe used later
+18 |         true
+19 |     }
+   |     - `_guard` is later dropped here
+   = note: required for the cast to the object type `dyn Future<Output = bool> + Send`
diff --git a/tests/ui/unreachable.rs b/tests/ui/unreachable.rs
new file mode 100644
index 0000000..f546a58
--- /dev/null
+++ b/tests/ui/unreachable.rs
@@ -0,0 +1,20 @@
+#![deny(warnings)]
+
+use async_trait::async_trait;
+
+#[async_trait]
+pub trait Trait {
+    async fn f() {
+        unimplemented!()
+    }
+}
+
+#[async_trait]
+pub trait TraitFoo {
+    async fn f() {
+        let y = unimplemented!();
+        let z = y;
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/unreachable.stderr b/tests/ui/unreachable.stderr
new file mode 100644
index 0000000..0b74692
--- /dev/null
+++ b/tests/ui/unreachable.stderr
@@ -0,0 +1,14 @@
+error: unreachable statement
+  --> $DIR/unreachable.rs:16:9
+   |
+15 |         let y = unimplemented!();
+   |                 ---------------- any code following this expression is unreachable
+16 |         let z = y;
+   |         ^^^^^^^^^^ unreachable statement
+   |
+note: the lint level is defined here
+  --> $DIR/unreachable.rs:1:9
+   |
+1  | #![deny(warnings)]
+   |         ^^^^^^^^
+   = note: `#[deny(unreachable_code)]` implied by `#[deny(warnings)]`
diff --git a/tests/ui/unsupported-self.stderr b/tests/ui/unsupported-self.stderr
index c1ea955..c98807e 100644
--- a/tests/ui/unsupported-self.stderr
+++ b/tests/ui/unsupported-self.stderr
@@ -1,4 +1,4 @@
-error: Self type of this impl is unsupported in expression position
+error: the `Self` constructor can only be used with tuple or unit structs
   --> $DIR/unsupported-self.rs:11:17
    |
 11 |         let _ = Self;