summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWoohyun Jung <wh0705.jung@samsung.com>2023-03-14 10:46:40 +0900
committerWoohyun Jung <wh0705.jung@samsung.com>2023-03-14 10:46:40 +0900
commit8994bb8673920be4a5422bc3310a5e3dcd5c9d27 (patch)
tree1611c1828e24df435fdf718aa349c8af9d1dac2a
downloadrust-async-trait-8994bb8673920be4a5422bc3310a5e3dcd5c9d27.tar.gz
rust-async-trait-8994bb8673920be4a5422bc3310a5e3dcd5c9d27.tar.bz2
rust-async-trait-8994bb8673920be4a5422bc3310a5e3dcd5c9d27.zip
Import async-trait 0.1.66upstream/0.1.66upstream
-rw-r--r--.cargo_vcs_info.json6
-rw-r--r--.clippy.toml1
-rw-r--r--.github/workflows/ci.yml84
-rw-r--r--.gitignore3
-rw-r--r--Cargo.toml62
-rw-r--r--Cargo.toml.orig30
-rw-r--r--LICENSE-APACHE176
-rw-r--r--LICENSE-MIT23
-rw-r--r--README.md262
-rw-r--r--build.rs31
-rw-r--r--src/args.rs36
-rw-r--r--src/bound.rs48
-rw-r--r--src/expand.rs495
-rw-r--r--src/lib.rs341
-rw-r--r--src/lifetime.rs110
-rw-r--r--src/parse.rs34
-rw-r--r--src/receiver.rs179
-rw-r--r--tests/compiletest.rs7
-rw-r--r--tests/executor/mod.rs36
-rw-r--r--tests/test.rs1606
-rw-r--r--tests/ui/arg-implementation-detail.rs22
-rw-r--r--tests/ui/arg-implementation-detail.stderr5
-rw-r--r--tests/ui/bare-trait-object.rs15
-rw-r--r--tests/ui/bare-trait-object.stderr21
-rw-r--r--tests/ui/consider-restricting.rs26
-rw-r--r--tests/ui/consider-restricting.stderr33
-rw-r--r--tests/ui/delimiter-span.rs24
-rw-r--r--tests/ui/delimiter-span.stderr21
-rw-r--r--tests/ui/lifetime-defined-here.rs23
-rw-r--r--tests/ui/lifetime-defined-here.stderr29
-rw-r--r--tests/ui/lifetime-span.rs36
-rw-r--r--tests/ui/lifetime-span.stderr24
-rw-r--r--tests/ui/missing-async-in-impl.rs15
-rw-r--r--tests/ui/missing-async-in-impl.stderr8
-rw-r--r--tests/ui/missing-async-in-trait.rs15
-rw-r--r--tests/ui/missing-async-in-trait.stderr8
-rw-r--r--tests/ui/missing-body.rs15
-rw-r--r--tests/ui/missing-body.stderr7
-rw-r--r--tests/ui/must-use.rs21
-rw-r--r--tests/ui/must-use.stderr11
-rw-r--r--tests/ui/self-span.rs30
-rw-r--r--tests/ui/self-span.stderr27
-rw-r--r--tests/ui/send-not-implemented.rs22
-rw-r--r--tests/ui/send-not-implemented.stderr47
-rw-r--r--tests/ui/unreachable.rs20
-rw-r--r--tests/ui/unreachable.stderr14
-rw-r--r--tests/ui/unsupported-self.rs15
-rw-r--r--tests/ui/unsupported-self.stderr5
48 files changed, 4129 insertions, 0 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..df0cdd6
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+ "git": {
+ "sha1": "9a9b32228707aded43b07a50e8f69f92d15ca7a3"
+ },
+ "path_in_vcs": ""
+} \ No newline at end of file
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
new file mode 100644
index 0000000..51fdd49
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,84 @@
+name: CI
+
+on:
+ push:
+ pull_request:
+ workflow_dispatch:
+ schedule: [cron: "40 1 * * *"]
+
+permissions:
+ contents: read
+
+env:
+ RUSTFLAGS: -Dwarnings
+
+jobs:
+ pre_ci:
+ uses: dtolnay/.github/.github/workflows/pre_ci.yml@master
+
+ test:
+ name: Rust ${{matrix.rust}}
+ needs: pre_ci
+ if: needs.pre_ci.outputs.continue
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ rust: [nightly, beta, stable, 1.56.0]
+ timeout-minutes: 45
+ steps:
+ - uses: actions/checkout@v3
+ - uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: ${{matrix.rust}}
+ - name: Enable type layout randomization
+ run: echo RUSTFLAGS=${RUSTFLAGS}\ -Zrandomize-layout >> $GITHUB_ENV
+ if: matrix.rust == 'nightly'
+ - name: Enable nightly-only tests
+ run: echo RUSTFLAGS=${RUSTFLAGS}\ --cfg=async_trait_nightly_testing >> $GITHUB_ENV
+ if: matrix.rust == 'nightly'
+ - run: cargo test
+
+ msrv:
+ name: Rust 1.39.0
+ needs: pre_ci
+ if: needs.pre_ci.outputs.continue
+ runs-on: ubuntu-latest
+ timeout-minutes: 45
+ steps:
+ - uses: actions/checkout@v3
+ - uses: dtolnay/rust-toolchain@1.39.0
+ - run: cargo check
+
+ clippy:
+ name: Clippy
+ runs-on: ubuntu-latest
+ if: github.event_name != 'pull_request'
+ timeout-minutes: 45
+ steps:
+ - uses: actions/checkout@v3
+ - uses: dtolnay/rust-toolchain@clippy
+ - run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic
+
+ miri:
+ name: Miri
+ needs: pre_ci
+ if: needs.pre_ci.outputs.continue
+ runs-on: ubuntu-latest
+ timeout-minutes: 45
+ steps:
+ - uses: actions/checkout@v3
+ - uses: dtolnay/rust-toolchain@miri
+ - run: cargo miri test
+ env:
+ MIRIFLAGS: -Zmiri-strict-provenance
+
+ outdated:
+ name: Outdated
+ runs-on: ubuntu-latest
+ if: github.event_name != 'pull_request'
+ timeout-minutes: 45
+ steps:
+ - uses: actions/checkout@v3
+ - uses: dtolnay/install@cargo-outdated
+ - run: cargo outdated --workspace --exit-code 1
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6936990
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+/target
+**/*.rs.bk
+Cargo.lock
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..c29ebe2
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,62 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+rust-version = "1.39"
+name = "async-trait"
+version = "0.1.66"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+description = "Type erasure for async trait methods"
+documentation = "https://docs.rs/async-trait"
+readme = "README.md"
+keywords = ["async"]
+categories = [
+ "asynchronous",
+ "no-std",
+]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/dtolnay/async-trait"
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+
+[lib]
+proc-macro = true
+
+[dependencies.proc-macro2]
+version = "1.0"
+
+[dependencies.quote]
+version = "1.0"
+
+[dependencies.syn]
+version = "1.0.96"
+features = [
+ "full",
+ "visit-mut",
+]
+
+[dev-dependencies.futures]
+version = "0.3"
+
+[dev-dependencies.rustversion]
+version = "1.0"
+
+[dev-dependencies.tracing]
+version = "0.1.14"
+
+[dev-dependencies.tracing-attributes]
+version = "0.1.14"
+
+[dev-dependencies.trybuild]
+version = "1.0.49"
+features = ["diff"]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..152ec78
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,30 @@
+[package]
+name = "async-trait"
+version = "0.1.66"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+categories = ["asynchronous", "no-std"]
+description = "Type erasure for async trait methods"
+documentation = "https://docs.rs/async-trait"
+edition = "2018"
+keywords = ["async"]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/dtolnay/async-trait"
+rust-version = "1.39"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+proc-macro2 = "1.0"
+quote = "1.0"
+syn = { version = "1.0.96", features = ["full", "visit-mut"] }
+
+[dev-dependencies]
+futures = "0.3"
+rustversion = "1.0"
+tracing = "0.1.14"
+tracing-attributes = "0.1.14"
+trybuild = { version = "1.0.49", features = ["diff"] }
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
new file mode 100644
index 0000000..1b5ec8b
--- /dev/null
+++ b/LICENSE-APACHE
@@ -0,0 +1,176 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..31aa793
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,23 @@
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..39e368b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,262 @@
+Async trait methods
+===================
+
+[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/async--trait-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/async-trait)
+[<img alt="crates.io" src="https://img.shields.io/crates/v/async-trait.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/async-trait)
+[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-async--trait-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/async-trait)
+[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/async-trait/ci.yml?branch=master&style=for-the-badge" height="20">](https://github.com/dtolnay/async-trait/actions?query=branch%3Amaster)
+
+The initial round of stabilizations for the async/await language feature in Rust
+1.39 did not include support for async fn in traits. Trying to include an async
+fn in a trait produces the following error:
+
+```rust
+trait MyTrait {
+ async fn f() {}
+}
+```
+
+```console
+error[E0706]: trait fns cannot be declared `async`
+ --> src/main.rs:4:5
+ |
+4 | async fn f() {}
+ | ^^^^^^^^^^^^^^^
+```
+
+This crate provides an attribute macro to make async fn in traits work.
+
+Please refer to [*why async fn in traits are hard*][hard] for a deeper analysis
+of how this implementation differs from what the compiler and language hope to
+deliver in the future.
+
+[hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/
+
+<br>
+
+## Example
+
+This example implements the core of a highly effective advertising platform
+using async fn in a trait.
+
+The only thing to notice here is that we write an `#[async_trait]` macro on top
+of traits and trait impls that contain async fn, and then they work.
+
+```rust
+use async_trait::async_trait;
+
+#[async_trait]
+trait Advertisement {
+ async fn run(&self);
+}
+
+struct Modal;
+
+#[async_trait]
+impl Advertisement for Modal {
+ async fn run(&self) {
+ self.render_fullscreen().await;
+ for _ in 0..4u16 {
+ remind_user_to_join_mailing_list().await;
+ }
+ self.hide_for_now().await;
+ }
+}
+
+struct AutoplayingVideo {
+ media_url: String,
+}
+
+#[async_trait]
+impl Advertisement for AutoplayingVideo {
+ async fn run(&self) {
+ let stream = connect(&self.media_url).await;
+ stream.play().await;
+
+ // Video probably persuaded user to join our mailing list!
+ Modal.run().await;
+ }
+}
+```
+
+<br>
+
+## Supported features
+
+It is the intention that all features of Rust traits should work nicely with
+\#\[async_trait\], but the edge cases are numerous. *Please file an issue if you
+see unexpected borrow checker errors, type errors, or warnings.* There is no use
+of `unsafe` in the expanded code, so rest assured that if your code compiles it
+can't be that badly broken.
+
+- &#128077;&ensp;Self by value, by reference, by mut reference, or no self;
+- &#128077;&ensp;Any number of arguments, any return value;
+- &#128077;&ensp;Generic type parameters and lifetime parameters;
+- &#128077;&ensp;Associated types;
+- &#128077;&ensp;Having async and non-async functions in the same trait;
+- &#128077;&ensp;Default implementations provided by the trait;
+- &#128077;&ensp;Elided lifetimes;
+- &#128077;&ensp;Dyn-capable traits.
+
+<br>
+
+## Explanation
+
+Async fns get transformed into methods that return `Pin<Box<dyn Future + Send +
+'async_trait>>` and delegate to a private async freestanding function.
+
+For example the `impl Advertisement for AutoplayingVideo` above would be
+expanded as:
+
+```rust
+impl Advertisement for AutoplayingVideo {
+ fn run<'async_trait>(
+ &'async_trait self,
+ ) -> Pin<Box<dyn std::future::Future<Output = ()> + Send + 'async_trait>>
+ where
+ Self: Sync + 'async_trait,
+ {
+ async fn run(_self: &AutoplayingVideo) {
+ /* the original method body */
+ }
+
+ Box::pin(run(self))
+ }
+}
+```
+
+<br>
+
+## Non-threadsafe futures
+
+Not all async traits need futures that are `dyn Future + Send`. To avoid having
+Send and Sync bounds placed on the async trait methods, invoke the async trait
+macro as `#[async_trait(?Send)]` on both the trait and the impl blocks.
+
+<br>
+
+## Elided lifetimes
+
+Be aware that async fn syntax does not allow lifetime elision outside of `&` and
+`&mut` references. (This is true even when not using #\[async_trait\].)
+Lifetimes must be named or marked by the placeholder `'_`.
+
+Fortunately the compiler is able to diagnose missing lifetimes with a good error
+message.
+
+```rust
+type Elided<'a> = &'a usize;
+
+#[async_trait]
+trait Test {
+ async fn test(not_okay: Elided, okay: &usize) {}
+}
+```
+
+```console
+error[E0726]: implicit elided lifetime not allowed here
+ --> src/main.rs:9:29
+ |
+9 | async fn test(not_okay: Elided, okay: &usize) {}
+ | ^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+```
+
+The fix is to name the lifetime or use `'_`.
+
+```rust
+#[async_trait]
+trait Test {
+ // either
+ async fn test<'e>(elided: Elided<'e>) {}
+ // or
+ async fn test(elided: Elided<'_>) {}
+}
+```
+
+<br>
+
+## Dyn traits
+
+Traits with async methods can be used as trait objects as long as they meet the
+usual requirements for dyn -- no methods with type parameters, no self by value,
+no associated types, etc.
+
+```rust
+#[async_trait]
+pub trait ObjectSafe {
+ async fn f(&self);
+ async fn g(&mut self);
+}
+
+impl ObjectSafe for MyType {...}
+
+let value: MyType = ...;
+let object = &value as &dyn ObjectSafe; // make trait object
+```
+
+The one wrinkle is in traits that provide default implementations of async
+methods. In order for the default implementation to produce a future that is
+Send, the async\_trait macro must emit a bound of `Self: Sync` on trait methods
+that take `&self` and a bound `Self: Send` on trait methods that take `&mut
+self`. An example of the former is visible in the expanded code in the
+explanation section above.
+
+If you make a trait with async methods that have default implementations,
+everything will work except that the trait cannot be used as a trait object.
+Creating a value of type `&dyn Trait` will produce an error that looks like
+this:
+
+```console
+error: the trait `Test` cannot be made into an object
+ --> src/main.rs:8:5
+ |
+8 | async fn cannot_dyn(&self) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+```
+
+For traits that need to be object safe and need to have default implementations
+for some async methods, there are two resolutions. Either you can add Send
+and/or Sync as supertraits (Send if there are `&mut self` methods with default
+implementations, Sync if there are `&self` methods with default implementations)
+to constrain all implementors of the trait such that the default implementations
+are applicable to them:
+
+```rust
+#[async_trait]
+pub trait ObjectSafe: Sync { // added supertrait
+ async fn can_dyn(&self) {}
+}
+
+let object = &value as &dyn ObjectSafe;
+```
+
+or you can strike the problematic methods from your trait object by bounding
+them with `Self: Sized`:
+
+```rust
+#[async_trait]
+pub trait ObjectSafe {
+ async fn cannot_dyn(&self) where Self: Sized {}
+
+ // presumably other methods
+}
+
+let object = &value as &dyn ObjectSafe;
+```
+
+<br>
+
+#### License
+
+<sup>
+Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
+2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
+</sup>
+
+<br>
+
+<sub>
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
+be dual licensed as above, without any additional terms or conditions.
+</sub>
diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000..d7f6b15
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,31 @@
+use std::env;
+use std::process::Command;
+use std::str;
+
+fn main() {
+ println!("cargo:rerun-if-changed=build.rs");
+
+ let compiler = match rustc_minor_version() {
+ Some(compiler) => compiler,
+ None => return,
+ };
+
+ if compiler < 45 {
+ println!("cargo:rustc-cfg=no_span_mixed_site");
+ }
+
+ 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/args.rs b/src/args.rs
new file mode 100644
index 0000000..72d97e9
--- /dev/null
+++ b/src/args.rs
@@ -0,0 +1,36 @@
+use proc_macro2::Span;
+use syn::parse::{Error, Parse, ParseStream, Result};
+use syn::Token;
+
+#[derive(Copy, Clone)]
+pub struct Args {
+ pub local: bool,
+}
+
+mod kw {
+ syn::custom_keyword!(Send);
+}
+
+impl Parse for Args {
+ fn parse(input: ParseStream) -> Result<Self> {
+ match try_parse(input) {
+ Ok(args) if input.is_empty() => Ok(args),
+ _ => Err(error()),
+ }
+ }
+}
+
+fn try_parse(input: ParseStream) -> Result<Args> {
+ if input.peek(Token![?]) {
+ input.parse::<Token![?]>()?;
+ input.parse::<kw::Send>()?;
+ Ok(Args { local: true })
+ } else {
+ Ok(Args { local: false })
+ }
+}
+
+fn error() -> Error {
+ let msg = "expected #[async_trait] or #[async_trait(?Send)]";
+ Error::new(Span::call_site(), msg)
+}
diff --git a/src/bound.rs b/src/bound.rs
new file mode 100644
index 0000000..50182f6
--- /dev/null
+++ b/src/bound.rs
@@ -0,0 +1,48 @@
+use proc_macro2::{Ident, Span, TokenStream};
+use quote::quote_spanned;
+use syn::punctuated::Punctuated;
+use syn::{Token, TypeParamBound};
+
+pub type Supertraits = Punctuated<TypeParamBound, Token![+]>;
+
+pub enum InferredBound {
+ Send,
+ Sync,
+}
+
+pub fn has_bound(supertraits: &Supertraits, bound: &InferredBound) -> bool {
+ for supertrait in supertraits {
+ if let TypeParamBound::Trait(supertrait) = supertrait {
+ if supertrait.path.is_ident(bound)
+ || supertrait.path.segments.len() == 3
+ && (supertrait.path.segments[0].ident == "std"
+ || supertrait.path.segments[0].ident == "core")
+ && supertrait.path.segments[1].ident == "marker"
+ && supertrait.path.segments[2].ident == *bound
+ {
+ return true;
+ }
+ }
+ }
+ false
+}
+
+impl InferredBound {
+ fn as_str(&self) -> &str {
+ match self {
+ InferredBound::Send => "Send",
+ InferredBound::Sync => "Sync",
+ }
+ }
+
+ pub fn spanned_path(&self, span: Span) -> TokenStream {
+ let ident = Ident::new(self.as_str(), span);
+ quote_spanned!(span=> ::core::marker::#ident)
+ }
+}
+
+impl PartialEq<InferredBound> for Ident {
+ fn eq(&self, bound: &InferredBound) -> bool {
+ self == bound.as_str()
+ }
+}
diff --git a/src/expand.rs b/src/expand.rs
new file mode 100644
index 0000000..2499177
--- /dev/null
+++ b/src/expand.rs
@@ -0,0 +1,495 @@
+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 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, LifetimeDef, Pat, PatIdent, PathArguments, Receiver,
+ ReturnType, Signature, Stmt, 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 LifetimeDef> {
+ 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(&param.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::Method(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 {
+ if let ImplItem::Method(method) = inner {
+ let sig = &mut method.sig;
+ 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);
+ transform_sig(context, sig, has_self, false, is_local);
+ method.attrs.push(lint_suppress_with_body());
+ }
+ }
+ }
+ }
+ }
+}
+
+fn lint_suppress_with_body() -> Attribute {
+ parse_quote! {
+ #[allow(
+ clippy::async_yields_async,
+ clippy::let_unit_value,
+ 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(
+ 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,
+) {
+ let default_span = sig.asyncness.take().unwrap().span;
+ sig.fn_token.span = default_span;
+
+ let (ret_arrow, ret) = match &sig.output {
+ ReturnType::Default => (Token![->](default_span), quote_spanned!(default_span=> ())),
+ ReturnType::Type(arrow, ret) => (*arrow, quote!(#ret)),
+ };
+
+ let mut lifetimes = CollectLifetimes::new();
+ for arg in sig.inputs.iter_mut() {
+ 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 = &param.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 = &param.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 = &param.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![<](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_or_default(&mut sig.generics.where_clause)
+ .predicates
+ .push(parse_quote_spanned!(elided.span()=> #elided: 'async_trait));
+ }
+
+ sig.generics
+ .params
+ .push(parse_quote_spanned!(default_span=> 'async_trait));
+
+ if has_self {
+ let bounds: &[InferredBound] = match sig.inputs.iter().next() {
+ Some(FnArg::Receiver(Receiver {
+ reference: Some(_),
+ mutability: None,
+ ..
+ })) => &[InferredBound::Sync],
+ Some(FnArg::Typed(arg))
+ if match arg.pat.as_ref() {
+ Pat::Ident(pat) => pat.ident == "self",
+ _ => false,
+ } =>
+ {
+ match arg.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],
+ }
+ }
+ _ => &[InferredBound::Send],
+ };
+
+ let bounds = bounds.iter().filter_map(|bound| {
+ let assume_bound = match context {
+ Context::Trait { supertraits, .. } => !has_default || has_bound(supertraits, bound),
+ Context::Impl { .. } => true,
+ };
+ if assume_bound || is_local {
+ None
+ } else {
+ Some(bound.spanned_path(default_span))
+ }
+ });
+
+ where_clause_or_default(&mut sig.generics.where_clause)
+ .predicates
+ .push(parse_quote_spanned! {default_span=>
+ Self: #(#bounds +)* 'async_trait
+ });
+ }
+
+ for (i, arg) in sig.inputs.iter_mut().enumerate() {
+ match arg {
+ FnArg::Receiver(Receiver {
+ reference: Some(_), ..
+ }) => {}
+ FnArg::Receiver(arg) => arg.mutability = None,
+ FnArg::Typed(arg) => {
+ let type_is_reference = match *arg.ty {
+ Type::Reference(_) => true,
+ _ => false,
+ };
+ if let Pat::Ident(pat) = &mut *arg.pat {
+ if pat.ident == "self" || !type_is_reference {
+ pat.by_ref = None;
+ pat.mutability = None;
+ }
+ } else if !type_is_reference {
+ 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_spanned!(default_span=> 'async_trait)
+ } else {
+ quote_spanned!(default_span=> ::core::marker::Send + 'async_trait)
+ };
+ sig.output = parse_quote_spanned! {default_span=>
+ #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) {
+ if let Some(Stmt::Item(syn::Item::Verbatim(item))) = block.stmts.first() {
+ if block.stmts.len() == 1 && item.to_string() == ";" {
+ return;
+ }
+ }
+
+ 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;)
+ }
+ 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 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 if let Type::Reference(_) = *arg.ty {
+ quote!()
+ } else {
+ quote! {
+ #(#attrs)*
+ let #mutability #ident = #ident;
+ }
+ }
+ } else if let Type::Reference(_) = *arg.ty {
+ quote!()
+ } 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 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)* })
+ }
+ } else {
+ quote_spanned! {block.brace_token.span=>
+ if let ::core::option::Option::Some(__ret) = ::core::option::Option::None::<#ret> {
+ 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: Span = syn::spanned::Spanned::span(pat);
+ #[cfg(not(no_span_mixed_site))]
+ let span = span.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(),
+ })
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..b973640
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,341 @@
+//! [![github]](https://github.com/dtolnay/async-trait)&ensp;[![crates-io]](https://crates.io/crates/async-trait)&ensp;[![docs-rs]](https://docs.rs/async-trait)
+//!
+//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
+//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
+//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
+//!
+//! <br>
+//!
+//! <h5>Type erasure for async trait methods</h5>
+//!
+//! The initial round of stabilizations for the async/await language feature in
+//! Rust 1.39 did not include support for async fn in traits. Trying to include
+//! an async fn in a trait produces the following error:
+//!
+//! ```compile_fail
+//! trait MyTrait {
+//! async fn f() {}
+//! }
+//! ```
+//!
+//! ```text
+//! error[E0706]: trait fns cannot be declared `async`
+//! --> src/main.rs:4:5
+//! |
+//! 4 | async fn f() {}
+//! | ^^^^^^^^^^^^^^^
+//! ```
+//!
+//! This crate provides an attribute macro to make async fn in traits work.
+//!
+//! Please refer to [*why async fn in traits are hard*][hard] for a deeper
+//! analysis of how this implementation differs from what the compiler and
+//! language hope to deliver in the future.
+//!
+//! [hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/
+//!
+//! <br>
+//!
+//! # Example
+//!
+//! This example implements the core of a highly effective advertising platform
+//! using async fn in a trait.
+//!
+//! The only thing to notice here is that we write an `#[async_trait]` macro on
+//! top of traits and trait impls that contain async fn, and then they work.
+//!
+//! ```
+//! use async_trait::async_trait;
+//!
+//! #[async_trait]
+//! trait Advertisement {
+//! async fn run(&self);
+//! }
+//!
+//! struct Modal;
+//!
+//! #[async_trait]
+//! impl Advertisement for Modal {
+//! async fn run(&self) {
+//! self.render_fullscreen().await;
+//! for _ in 0..4u16 {
+//! remind_user_to_join_mailing_list().await;
+//! }
+//! self.hide_for_now().await;
+//! }
+//! }
+//!
+//! struct AutoplayingVideo {
+//! media_url: String,
+//! }
+//!
+//! #[async_trait]
+//! impl Advertisement for AutoplayingVideo {
+//! async fn run(&self) {
+//! let stream = connect(&self.media_url).await;
+//! stream.play().await;
+//!
+//! // Video probably persuaded user to join our mailing list!
+//! Modal.run().await;
+//! }
+//! }
+//! #
+//! # impl Modal {
+//! # async fn render_fullscreen(&self) {}
+//! # async fn hide_for_now(&self) {}
+//! # }
+//! #
+//! # async fn remind_user_to_join_mailing_list() {}
+//! #
+//! # struct Stream;
+//! # async fn connect(_media_url: &str) -> Stream { Stream }
+//! # impl Stream {
+//! # async fn play(&self) {}
+//! # }
+//! ```
+//!
+//! <br><br>
+//!
+//! # Supported features
+//!
+//! It is the intention that all features of Rust traits should work nicely with
+//! #\[async_trait\], but the edge cases are numerous. Please file an issue if
+//! you see unexpected borrow checker errors, type errors, or warnings. There is
+//! no use of `unsafe` in the expanded code, so rest assured that if your code
+//! compiles it can't be that badly broken.
+//!
+//! > &#9745;&emsp;Self by value, by reference, by mut reference, or no self;<br>
+//! > &#9745;&emsp;Any number of arguments, any return value;<br>
+//! > &#9745;&emsp;Generic type parameters and lifetime parameters;<br>
+//! > &#9745;&emsp;Associated types;<br>
+//! > &#9745;&emsp;Having async and non-async functions in the same trait;<br>
+//! > &#9745;&emsp;Default implementations provided by the trait;<br>
+//! > &#9745;&emsp;Elided lifetimes;<br>
+//! > &#9745;&emsp;Dyn-capable traits.<br>
+//!
+//! <br>
+//!
+//! # Explanation
+//!
+//! Async fns get transformed into methods that return `Pin<Box<dyn Future +
+//! Send + 'async>>` and delegate to a private async freestanding function.
+//!
+//! For example the `impl Advertisement for AutoplayingVideo` above would be
+//! expanded as:
+//!
+//! ```
+//! # const IGNORE: &str = stringify! {
+//! impl Advertisement for AutoplayingVideo {
+//! fn run<'async>(
+//! &'async self,
+//! ) -> Pin<Box<dyn core::future::Future<Output = ()> + Send + 'async>>
+//! where
+//! Self: Sync + 'async,
+//! {
+//! async fn run(_self: &AutoplayingVideo) {
+//! /* the original method body */
+//! }
+//!
+//! Box::pin(run(self))
+//! }
+//! }
+//! # };
+//! ```
+//!
+//! <br><br>
+//!
+//! # Non-threadsafe futures
+//!
+//! Not all async traits need futures that are `dyn Future + Send`. To avoid
+//! having Send and Sync bounds placed on the async trait methods, invoke the
+//! async trait macro as `#[async_trait(?Send)]` on both the trait and the impl
+//! blocks.
+//!
+//! <br>
+//!
+//! # Elided lifetimes
+//!
+//! Be aware that async fn syntax does not allow lifetime elision outside of `&`
+//! and `&mut` references. (This is true even when not using #\[async_trait\].)
+//! Lifetimes must be named or marked by the placeholder `'_`.
+//!
+//! Fortunately the compiler is able to diagnose missing lifetimes with a good
+//! error message.
+//!
+//! ```compile_fail
+//! # use async_trait::async_trait;
+//! #
+//! type Elided<'a> = &'a usize;
+//!
+//! #[async_trait]
+//! trait Test {
+//! async fn test(not_okay: Elided, okay: &usize) {}
+//! }
+//! ```
+//!
+//! ```text
+//! error[E0726]: implicit elided lifetime not allowed here
+//! --> src/main.rs:9:29
+//! |
+//! 9 | async fn test(not_okay: Elided, okay: &usize) {}
+//! | ^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+//! ```
+//!
+//! The fix is to name the lifetime or use `'_`.
+//!
+//! ```
+//! # use async_trait::async_trait;
+//! #
+//! # type Elided<'a> = &'a usize;
+//! #
+//! #[async_trait]
+//! trait Test {
+//! // either
+//! async fn test<'e>(elided: Elided<'e>) {}
+//! # }
+//! # #[async_trait]
+//! # trait Test2 {
+//! // or
+//! async fn test(elided: Elided<'_>) {}
+//! }
+//! ```
+//!
+//! <br><br>
+//!
+//! # Dyn traits
+//!
+//! Traits with async methods can be used as trait objects as long as they meet
+//! the usual requirements for dyn -- no methods with type parameters, no self
+//! by value, no associated types, etc.
+//!
+//! ```
+//! # use async_trait::async_trait;
+//! #
+//! #[async_trait]
+//! pub trait ObjectSafe {
+//! async fn f(&self);
+//! async fn g(&mut self);
+//! }
+//!
+//! # const IGNORE: &str = stringify! {
+//! impl ObjectSafe for MyType {...}
+//!
+//! let value: MyType = ...;
+//! # };
+//! #
+//! # struct MyType;
+//! #
+//! # #[async_trait]
+//! # impl ObjectSafe for MyType {
+//! # async fn f(&self) {}
+//! # async fn g(&mut self) {}
+//! # }
+//! #
+//! # let value: MyType = MyType;
+//! let object = &value as &dyn ObjectSafe; // make trait object
+//! ```
+//!
+//! The one wrinkle is in traits that provide default implementations of async
+//! methods. In order for the default implementation to produce a future that is
+//! Send, the async_trait macro must emit a bound of `Self: Sync` on trait
+//! methods that take `&self` and a bound `Self: Send` on trait methods that
+//! take `&mut self`. An example of the former is visible in the expanded code
+//! in the explanation section above.
+//!
+//! If you make a trait with async methods that have default implementations,
+//! everything will work except that the trait cannot be used as a trait object.
+//! Creating a value of type `&dyn Trait` will produce an error that looks like
+//! this:
+//!
+//! ```text
+//! error: the trait `Test` cannot be made into an object
+//! --> src/main.rs:8:5
+//! |
+//! 8 | async fn cannot_dyn(&self) {}
+//! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//! ```
+//!
+//! For traits that need to be object safe and need to have default
+//! implementations for some async methods, there are two resolutions. Either
+//! you can add Send and/or Sync as supertraits (Send if there are `&mut self`
+//! methods with default implementations, Sync if there are `&self` methods with
+//! default implementations) to constrain all implementors of the trait such that
+//! the default implementations are applicable to them:
+//!
+//! ```
+//! # use async_trait::async_trait;
+//! #
+//! #[async_trait]
+//! pub trait ObjectSafe: Sync { // added supertrait
+//! async fn can_dyn(&self) {}
+//! }
+//! #
+//! # struct MyType;
+//! #
+//! # #[async_trait]
+//! # impl ObjectSafe for MyType {}
+//! #
+//! # let value = MyType;
+//!
+//! let object = &value as &dyn ObjectSafe;
+//! ```
+//!
+//! or you can strike the problematic methods from your trait object by
+//! bounding them with `Self: Sized`:
+//!
+//! ```
+//! # use async_trait::async_trait;
+//! #
+//! #[async_trait]
+//! pub trait ObjectSafe {
+//! async fn cannot_dyn(&self) where Self: Sized {}
+//!
+//! // presumably other methods
+//! }
+//! #
+//! # struct MyType;
+//! #
+//! # #[async_trait]
+//! # impl ObjectSafe for MyType {}
+//! #
+//! # let value = MyType;
+//!
+//! let object = &value as &dyn ObjectSafe;
+//! ```
+
+#![doc(html_root_url = "https://docs.rs/async-trait/0.1.66")]
+#![allow(
+ clippy::default_trait_access,
+ clippy::doc_markdown,
+ clippy::explicit_auto_deref,
+ 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;
+
+mod args;
+mod bound;
+mod expand;
+mod lifetime;
+mod parse;
+mod receiver;
+
+use crate::args::Args;
+use crate::expand::expand;
+use crate::parse::Item;
+use proc_macro::TokenStream;
+use quote::quote;
+use syn::parse_macro_input;
+
+#[proc_macro_attribute]
+pub fn async_trait(args: TokenStream, input: TokenStream) -> TokenStream {
+ let args = parse_macro_input!(args as Args);
+ let mut item = parse_macro_input!(input as Item);
+ expand(&mut item, args.local);
+ TokenStream::from(quote!(#item))
+}
diff --git a/src/lifetime.rs b/src/lifetime.rs
new file mode 100644
index 0000000..1e5a658
--- /dev/null
+++ b/src/lifetime.rs
@@ -0,0 +1,110 @@
+use proc_macro2::{Span, TokenStream};
+use std::mem;
+use syn::visit_mut::{self, VisitMut};
+use syn::{
+ parse_quote_spanned, token, Expr, GenericArgument, Lifetime, Receiver, ReturnType, Token, Type,
+ TypeBareFn, TypeImplTrait, TypeParen, TypePtr, TypeReference,
+};
+
+pub struct CollectLifetimes {
+ pub elided: Vec<Lifetime>,
+ pub explicit: Vec<Lifetime>,
+}
+
+impl CollectLifetimes {
+ pub fn new() -> Self {
+ CollectLifetimes {
+ elided: Vec::new(),
+ explicit: Vec::new(),
+ }
+ }
+
+ fn visit_opt_lifetime(&mut self, reference: Token![&], lifetime: &mut Option<Lifetime>) {
+ match lifetime {
+ None => *lifetime = Some(self.next_lifetime(reference.span)),
+ Some(lifetime) => self.visit_lifetime(lifetime),
+ }
+ }
+
+ fn visit_lifetime(&mut self, lifetime: &mut Lifetime) {
+ if lifetime.ident == "_" {
+ *lifetime = self.next_lifetime(lifetime.span());
+ } else {
+ self.explicit.push(lifetime.clone());
+ }
+ }
+
+ fn next_lifetime(&mut self, span: Span) -> Lifetime {
+ let name = format!("'life{}", self.elided.len());
+ let life = Lifetime::new(&name, span);
+ self.elided.push(life.clone());
+ life
+ }
+}
+
+impl VisitMut for CollectLifetimes {
+ fn visit_receiver_mut(&mut self, arg: &mut Receiver) {
+ if let Some((reference, lifetime)) = &mut arg.reference {
+ self.visit_opt_lifetime(*reference, lifetime);
+ }
+ }
+
+ fn visit_type_reference_mut(&mut self, ty: &mut TypeReference) {
+ self.visit_opt_lifetime(ty.and_token, &mut ty.lifetime);
+ visit_mut::visit_type_reference_mut(self, ty);
+ }
+
+ fn visit_generic_argument_mut(&mut self, gen: &mut GenericArgument) {
+ if let GenericArgument::Lifetime(lifetime) = gen {
+ self.visit_lifetime(lifetime);
+ }
+ visit_mut::visit_generic_argument_mut(self, gen);
+ }
+}
+
+pub struct AddLifetimeToImplTrait;
+
+impl VisitMut for AddLifetimeToImplTrait {
+ fn visit_type_impl_trait_mut(&mut self, ty: &mut TypeImplTrait) {
+ let span = ty.impl_token.span;
+ let lifetime = parse_quote_spanned!(span=> 'async_trait);
+ ty.bounds.insert(0, lifetime);
+ if let Some(punct) = ty.bounds.pairs_mut().next().unwrap().punct_mut() {
+ punct.span = span;
+ }
+ visit_mut::visit_type_impl_trait_mut(self, ty);
+ }
+
+ fn visit_type_reference_mut(&mut self, ty: &mut TypeReference) {
+ parenthesize_impl_trait(&mut ty.elem, ty.and_token.span);
+ visit_mut::visit_type_reference_mut(self, ty);
+ }
+
+ fn visit_type_ptr_mut(&mut self, ty: &mut TypePtr) {
+ parenthesize_impl_trait(&mut ty.elem, ty.star_token.span);
+ visit_mut::visit_type_ptr_mut(self, ty);
+ }
+
+ fn visit_type_bare_fn_mut(&mut self, ty: &mut TypeBareFn) {
+ if let ReturnType::Type(arrow, return_type) = &mut ty.output {
+ parenthesize_impl_trait(return_type, arrow.spans[0]);
+ }
+ visit_mut::visit_type_bare_fn_mut(self, ty);
+ }
+
+ fn visit_expr_mut(&mut self, _e: &mut Expr) {
+ // Do not recurse into impl Traits inside of an array length expression.
+ //
+ // fn outer(arg: [u8; { fn inner(_: impl Trait) {}; 0 }]);
+ }
+}
+
+fn parenthesize_impl_trait(elem: &mut Type, paren_span: Span) {
+ if let Type::ImplTrait(_) = *elem {
+ let placeholder = Type::Verbatim(TokenStream::new());
+ *elem = Type::Paren(TypeParen {
+ paren_token: token::Paren(paren_span),
+ elem: Box::new(mem::replace(elem, placeholder)),
+ });
+ }
+}
diff --git a/src/parse.rs b/src/parse.rs
new file mode 100644
index 0000000..ebd2535
--- /dev/null
+++ b/src/parse.rs
@@ -0,0 +1,34 @@
+use proc_macro2::Span;
+use syn::parse::{Error, Parse, ParseStream, Result};
+use syn::{Attribute, ItemImpl, ItemTrait, Token};
+
+pub enum Item {
+ Trait(ItemTrait),
+ Impl(ItemImpl),
+}
+
+impl Parse for Item {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let mut lookahead = input.lookahead1();
+ if lookahead.peek(Token![unsafe]) {
+ let ahead = input.fork();
+ ahead.parse::<Token![unsafe]>()?;
+ lookahead = ahead.lookahead1();
+ }
+ if lookahead.peek(Token![pub]) || lookahead.peek(Token![trait]) {
+ let mut item: ItemTrait = input.parse()?;
+ item.attrs = attrs;
+ Ok(Item::Trait(item))
+ } else if lookahead.peek(Token![impl]) {
+ let mut item: ItemImpl = input.parse()?;
+ if item.trait_.is_none() {
+ return Err(Error::new(Span::call_site(), "expected a trait impl"));
+ }
+ item.attrs = attrs;
+ Ok(Item::Impl(item))
+ } else {
+ Err(lookahead.error())
+ }
+ }
+}
diff --git a/src/receiver.rs b/src/receiver.rs
new file mode 100644
index 0000000..2230db6
--- /dev/null
+++ b/src/receiver.rs
@@ -0,0 +1,179 @@
+use proc_macro2::{Group, Span, TokenStream, TokenTree};
+use std::iter::FromIterator;
+use syn::visit_mut::{self, VisitMut};
+use syn::{
+ Block, ExprPath, Ident, Item, Macro, Pat, PatIdent, PatPath, Path, Receiver, Signature, Token,
+ TypePath,
+};
+
+pub fn has_self_in_sig(sig: &mut Signature) -> bool {
+ let mut visitor = HasSelf(false);
+ visitor.visit_signature_mut(sig);
+ visitor.0
+}
+
+pub fn has_self_in_block(block: &mut Block) -> bool {
+ let mut visitor = HasSelf(false);
+ visitor.visit_block_mut(block);
+ visitor.0
+}
+
+fn has_self_in_token_stream(tokens: TokenStream) -> bool {
+ tokens.into_iter().any(|tt| match tt {
+ TokenTree::Ident(ident) => ident == "Self",
+ TokenTree::Group(group) => has_self_in_token_stream(group.stream()),
+ _ => false,
+ })
+}
+
+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 {
+ fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) {
+ self.0 |= expr.path.segments[0].ident == "Self";
+ visit_mut::visit_expr_path_mut(self, expr);
+ }
+
+ fn visit_pat_path_mut(&mut self, pat: &mut PatPath) {
+ self.0 |= pat.path.segments[0].ident == "Self";
+ visit_mut::visit_pat_path_mut(self, pat);
+ }
+
+ fn visit_type_path_mut(&mut self, ty: &mut TypePath) {
+ self.0 |= ty.path.segments[0].ident == "Self";
+ visit_mut::visit_type_path_mut(self, ty);
+ }
+
+ fn visit_receiver_mut(&mut self, _arg: &mut Receiver) {
+ self.0 = true;
+ }
+
+ fn visit_item_mut(&mut self, _: &mut Item) {
+ // Do not recurse into nested items.
+ }
+
+ fn visit_macro_mut(&mut self, mac: &mut Macro) {
+ if !contains_fn(mac.tokens.clone()) {
+ self.0 |= has_self_in_token_stream(mac.tokens.clone());
+ }
+ }
+}
+
+pub struct ReplaceSelf(pub Span);
+
+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 {
+ *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 ReplaceSelf {
+ fn visit_ident_mut(&mut self, i: &mut Ident) {
+ self.prepend_underscore_to_self(i);
+ }
+
+ fn visit_path_mut(&mut self, p: &mut Path) {
+ if p.segments.len() == 1 {
+ // Replace `self`, but not `self::function`.
+ self.visit_ident_mut(&mut p.segments[0].ident);
+ }
+ for segment in &mut p.segments {
+ self.visit_path_arguments_mut(&mut segment.arguments);
+ }
+ }
+
+ fn visit_item_mut(&mut self, i: &mut Item) {
+ // Visit `macro_rules!` because locally defined macros can refer to
+ // `self`.
+ //
+ // Visit `futures::select` and similar select macros, which commonly
+ // appear syntactically like an item despite expanding to an expression.
+ //
+ // Otherwise, do not recurse into nested items.
+ if let Item::Macro(i) = i {
+ if i.mac.path.is_ident("macro_rules")
+ || i.mac.path.segments.last().unwrap().ident == "select"
+ {
+ self.visit_macro_mut(&mut i.mac);
+ }
+ }
+ }
+
+ fn visit_macro_mut(&mut self, mac: &mut Macro) {
+ // We can't tell in general whether `self` inside a macro invocation
+ // refers to the self in the argument list or a different self
+ // introduced within the macro. Heuristic: if the macro input contains
+ // `fn`, then `self` is more likely to refer to something other than the
+ // outer function's self argument.
+ if !contains_fn(mac.tokens.clone()) {
+ self.visit_token_stream(&mut mac.tokens);
+ }
+ }
+}
diff --git a/tests/compiletest.rs b/tests/compiletest.rs
new file mode 100644
index 0000000..7974a62
--- /dev/null
+++ b/tests/compiletest.rs
@@ -0,0 +1,7 @@
+#[rustversion::attr(not(nightly), ignore)]
+#[cfg_attr(miri, ignore)]
+#[test]
+fn ui() {
+ let t = trybuild::TestCases::new();
+ t.compile_fail("tests/ui/*.rs");
+}
diff --git a/tests/executor/mod.rs b/tests/executor/mod.rs
new file mode 100644
index 0000000..912fb79
--- /dev/null
+++ b/tests/executor/mod.rs
@@ -0,0 +1,36 @@
+use std::future::Future;
+use std::pin::Pin;
+use std::ptr;
+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!()
+ }
+
+ unsafe fn wake(_null: *const ()) {
+ unimplemented!()
+ }
+
+ unsafe fn wake_by_ref(_null: *const ()) {
+ unimplemented!()
+ }
+
+ unsafe fn drop(_null: *const ()) {}
+
+ let data = ptr::null();
+ let vtable = &RawWakerVTable::new(clone, wake, wake_by_ref, drop);
+ let raw_waker = RawWaker::new(data, vtable);
+ let waker = unsafe { Waker::from_raw(raw_waker) };
+ let mut cx = Context::from_waker(&waker);
+
+ // fut does not move until it gets dropped.
+ let fut = unsafe { Pin::new_unchecked(&mut fut) };
+
+ match fut.poll(&mut cx) {
+ Poll::Ready(output) => output,
+ Poll::Pending => panic!("future did not resolve immediately"),
+ }
+}
diff --git a/tests/test.rs b/tests/test.rs
new file mode 100644
index 0000000..4fc46f0
--- /dev/null
+++ b/tests/test.rs
@@ -0,0 +1,1606 @@
+#![cfg_attr(
+ async_trait_nightly_testing,
+ feature(min_specialization, type_alias_impl_trait)
+)]
+#![deny(rust_2021_compatibility)]
+#![allow(
+ clippy::let_underscore_untyped,
+ clippy::let_unit_value,
+ clippy::missing_panics_doc,
+ clippy::missing_safety_doc,
+ clippy::needless_return,
+ clippy::trivially_copy_pass_by_ref,
+ clippy::unused_async
+)]
+
+use async_trait::async_trait;
+
+pub mod executor;
+
+// Dummy module to check that the expansion refer to rust's core crate
+mod core {}
+
+#[async_trait]
+trait Trait {
+ type Assoc;
+
+ async fn selfvalue(self)
+ where
+ Self: Sized,
+ {
+ }
+
+ async fn selfref(&self) {}
+
+ async fn selfmut(&mut self) {}
+
+ async fn required() -> Self::Assoc;
+
+ async fn elided_lifetime(_x: &str) {}
+
+ async fn explicit_lifetime<'a>(_x: &'a str) {}
+
+ async fn generic_type_param<T: Send>(x: Box<T>) -> T {
+ *x
+ }
+
+ async fn calls(&self) {
+ self.selfref().await;
+ Self::elided_lifetime("").await;
+ <Self>::elided_lifetime("").await;
+ }
+
+ async fn calls_mut(&mut self) {
+ self.selfmut().await;
+ }
+}
+
+struct Struct;
+
+#[async_trait]
+impl Trait for Struct {
+ type Assoc = ();
+
+ async fn selfvalue(self) {}
+
+ async fn selfref(&self) {}
+
+ async fn selfmut(&mut self) {}
+
+ async fn required() -> Self::Assoc {}
+
+ async fn elided_lifetime(_x: &str) {}
+
+ async fn explicit_lifetime<'a>(_x: &'a str) {}
+
+ async fn generic_type_param<T: Send>(x: Box<T>) -> T {
+ *x
+ }
+
+ async fn calls(&self) {
+ self.selfref().await;
+ Self::elided_lifetime("").await;
+ <Self>::elided_lifetime("").await;
+ }
+
+ async fn calls_mut(&mut self) {
+ self.selfmut().await;
+ }
+}
+
+pub async fn test() {
+ let mut s = Struct;
+ s.selfref().await;
+ s.selfmut().await;
+ s.selfvalue().await;
+
+ Struct::required().await;
+ Struct::elided_lifetime("").await;
+ Struct::explicit_lifetime("").await;
+ Struct::generic_type_param(Box::new("")).await;
+
+ let mut s = Struct;
+ s.calls().await;
+ s.calls_mut().await;
+}
+
+pub async fn test_object_safe_without_default() {
+ #[async_trait]
+ trait ObjectSafe {
+ async fn f(&self);
+ }
+
+ #[async_trait]
+ impl ObjectSafe for Struct {
+ async fn f(&self) {}
+ }
+
+ let object = &Struct as &dyn ObjectSafe;
+ object.f().await;
+}
+
+pub async fn test_object_safe_with_default() {
+ #[async_trait]
+ trait ObjectSafe: Sync {
+ async fn f(&self) {}
+ }
+
+ #[async_trait]
+ impl ObjectSafe for Struct {
+ async fn f(&self) {}
+ }
+
+ let object = &Struct as &dyn ObjectSafe;
+ object.f().await;
+}
+
+pub async fn test_object_no_send() {
+ #[async_trait(?Send)]
+ trait ObjectSafe: Sync {
+ async fn f(&self) {}
+ }
+
+ #[async_trait(?Send)]
+ impl ObjectSafe for Struct {
+ async fn f(&self) {}
+ }
+
+ let object = &Struct as &dyn ObjectSafe;
+ object.f().await;
+}
+
+#[async_trait]
+pub unsafe trait UnsafeTrait {}
+
+#[async_trait]
+unsafe impl UnsafeTrait for () {}
+
+#[async_trait]
+pub(crate) unsafe trait UnsafeTraitPubCrate {}
+
+#[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;
+
+ #[async_trait]
+ trait Issue1 {
+ async fn f<U>(&self);
+ }
+
+ #[async_trait]
+ impl<T: Sync> Issue1 for Vec<T> {
+ async fn f<U>(&self) {}
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/2
+pub mod issue2 {
+ use async_trait::async_trait;
+ use std::future::Future;
+
+ #[async_trait]
+ pub trait Issue2: Future {
+ async fn flatten(self) -> <Self::Output as Future>::Output
+ where
+ Self::Output: Future + Send,
+ Self: Sized,
+ {
+ let nested_future = self.await;
+ nested_future.await
+ }
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/9
+pub mod issue9 {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait Issue9: Sized + Send {
+ async fn f(_x: Self) {}
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/11
+pub mod issue11 {
+ use async_trait::async_trait;
+ use std::sync::Arc;
+
+ #[async_trait]
+ trait Issue11 {
+ async fn example(self: Arc<Self>);
+ }
+
+ struct Struct;
+
+ #[async_trait]
+ impl Issue11 for Struct {
+ async fn example(self: Arc<Self>) {}
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/15
+pub mod issue15 {
+ use async_trait::async_trait;
+ use std::marker::PhantomData;
+
+ trait Trait {}
+
+ #[async_trait]
+ trait Issue15 {
+ async fn myfn(&self, _: PhantomData<dyn Trait + Send>) {}
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/17
+pub mod issue17 {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ trait Issue17 {
+ async fn f(&self);
+ }
+
+ struct Struct {
+ string: String,
+ }
+
+ #[async_trait]
+ impl Issue17 for Struct {
+ async fn f(&self) {
+ println!("{}", self.string);
+ }
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/23
+pub mod issue23 {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait Issue23 {
+ async fn f(self);
+
+ async fn g(mut self)
+ where
+ Self: Sized,
+ {
+ do_something(&mut self);
+ }
+ }
+
+ struct S {}
+
+ #[async_trait]
+ impl Issue23 for S {
+ async fn f(mut self) {
+ do_something(&mut self);
+ }
+ }
+
+ fn do_something<T>(_: &mut T) {}
+}
+
+// https://github.com/dtolnay/async-trait/issues/25
+#[cfg(async_trait_nightly_testing)]
+pub mod issue25 {
+ use crate::executor;
+ use async_trait::async_trait;
+ use std::fmt::{Display, Write};
+
+ #[async_trait]
+ trait AsyncToString {
+ async fn async_to_string(&self) -> String;
+ }
+
+ #[async_trait]
+ impl AsyncToString for String {
+ async fn async_to_string(&self) -> String {
+ "special".to_owned()
+ }
+ }
+
+ macro_rules! hide_from_stable_parser {
+ ($($tt:tt)*) => {
+ $($tt)*
+ };
+ }
+
+ hide_from_stable_parser! {
+ #[async_trait]
+ impl<T: ?Sized + Display + Sync> AsyncToString for T {
+ default async fn async_to_string(&self) -> String {
+ let mut buf = String::new();
+ buf.write_fmt(format_args!("{}", self)).unwrap();
+ buf
+ }
+ }
+ }
+
+ #[test]
+ fn test() {
+ let fut = true.async_to_string();
+ assert_eq!(executor::block_on_simple(fut), "true");
+
+ let string = String::new();
+ let fut = string.async_to_string();
+ assert_eq!(executor::block_on_simple(fut), "special");
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/28
+pub mod issue28 {
+ use async_trait::async_trait;
+
+ struct Str<'a>(&'a str);
+
+ #[async_trait]
+ trait Trait1<'a> {
+ async fn f(x: Str<'a>) -> &'a str;
+ async fn g(x: Str<'a>) -> &'a str {
+ x.0
+ }
+ }
+
+ #[async_trait]
+ impl<'a> Trait1<'a> for str {
+ async fn f(x: Str<'a>) -> &'a str {
+ x.0
+ }
+ }
+
+ #[async_trait]
+ trait Trait2 {
+ async fn f();
+ }
+
+ #[async_trait]
+ impl<'a> Trait2 for &'a () {
+ async fn f() {}
+ }
+
+ #[async_trait]
+ trait Trait3<'a, 'b> {
+ async fn f(_: &'a &'b ()); // chain 'a and 'b
+ async fn g(_: &'b ()); // chain 'b only
+ async fn h(); // do not chain
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/31
+pub mod issue31 {
+ use async_trait::async_trait;
+
+ pub struct Struct<'a> {
+ pub name: &'a str,
+ }
+
+ #[async_trait]
+ pub trait Trait<'a> {
+ async fn hello(thing: Struct<'a>) -> String;
+ async fn hello_twice(one: Struct<'a>, two: Struct<'a>) -> String {
+ let str1 = Self::hello(one).await;
+ let str2 = Self::hello(two).await;
+ str1 + &str2
+ }
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/42
+pub mod issue42 {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait Context: Sized {
+ async fn from_parts() -> Self;
+ }
+
+ pub struct TokenContext;
+
+ #[async_trait]
+ impl Context for TokenContext {
+ async fn from_parts() -> TokenContext {
+ TokenContext
+ }
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/44
+pub mod issue44 {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait StaticWithWhereSelf
+ where
+ Box<Self>: Sized,
+ Self: Sized + Send,
+ {
+ async fn get_one() -> u8 {
+ 1
+ }
+ }
+
+ pub struct Struct;
+
+ #[async_trait]
+ impl StaticWithWhereSelf for Struct {}
+}
+
+// https://github.com/dtolnay/async-trait/issues/45
+pub mod issue45 {
+ use crate::executor;
+ use async_trait::async_trait;
+ use std::fmt::Debug;
+ use std::sync::atomic::{AtomicU64, Ordering};
+ use std::sync::{Arc, Mutex};
+ use tracing::event::Event;
+ use tracing::field::{Field, Visit};
+ use tracing::span::{Attributes, Id, Record};
+ use tracing::{info, instrument, subscriber, Metadata, Subscriber};
+
+ #[async_trait]
+ pub trait Parent {
+ async fn foo(&mut self, v: usize);
+ }
+
+ #[async_trait]
+ pub trait Child {
+ async fn bar(&self);
+ }
+
+ #[derive(Debug)]
+ struct Impl(usize);
+
+ #[async_trait]
+ impl Parent for Impl {
+ #[instrument]
+ async fn foo(&mut self, v: usize) {
+ self.0 = v;
+ self.bar().await;
+ }
+ }
+
+ #[async_trait]
+ impl Child for Impl {
+ // Let's check that tracing detects the renaming of the `self` variable
+ // too, as tracing::instrument is not going to be able to skip the
+ // `self` argument if it can't find it in the function signature.
+ #[instrument(skip(self))]
+ async fn bar(&self) {
+ info!(val = self.0);
+ }
+ }
+
+ // A simple subscriber implementation to test the behavior of async-trait
+ // with tokio-rs/tracing. This implementation is not robust against race
+ // conditions, but it's not an issue here as we are only polling on a single
+ // future at a time.
+ #[derive(Debug)]
+ struct SubscriberInner {
+ current_depth: AtomicU64,
+ // We assert that nested functions work. If the fix were to break, we
+ // would see two top-level functions instead of `bar` nested in `foo`.
+ max_depth: AtomicU64,
+ max_span_id: AtomicU64,
+ // Name of the variable / value / depth when the event was recorded.
+ value: Mutex<Option<(&'static str, u64, u64)>>,
+ }
+
+ #[derive(Debug, Clone)]
+ struct TestSubscriber {
+ inner: Arc<SubscriberInner>,
+ }
+
+ impl TestSubscriber {
+ fn new() -> Self {
+ TestSubscriber {
+ inner: Arc::new(SubscriberInner {
+ current_depth: AtomicU64::new(0),
+ max_depth: AtomicU64::new(0),
+ max_span_id: AtomicU64::new(1),
+ value: Mutex::new(None),
+ }),
+ }
+ }
+ }
+
+ struct U64Visitor(Option<(&'static str, u64)>);
+
+ impl Visit for U64Visitor {
+ fn record_debug(&mut self, _field: &Field, _value: &dyn Debug) {}
+
+ fn record_u64(&mut self, field: &Field, value: u64) {
+ self.0 = Some((field.name(), value));
+ }
+ }
+
+ impl Subscriber for TestSubscriber {
+ fn enabled(&self, _metadata: &Metadata) -> bool {
+ true
+ }
+ fn new_span(&self, _span: &Attributes) -> Id {
+ Id::from_u64(self.inner.max_span_id.fetch_add(1, Ordering::AcqRel))
+ }
+ fn record(&self, _span: &Id, _values: &Record) {}
+ fn record_follows_from(&self, _span: &Id, _follows: &Id) {}
+ fn event(&self, event: &Event) {
+ let mut visitor = U64Visitor(None);
+ event.record(&mut visitor);
+ if let Some((s, v)) = visitor.0 {
+ let current_depth = self.inner.current_depth.load(Ordering::Acquire);
+ *self.inner.value.lock().unwrap() = Some((s, v, current_depth));
+ }
+ }
+ fn enter(&self, _span: &Id) {
+ let old_depth = self.inner.current_depth.fetch_add(1, Ordering::AcqRel);
+ if old_depth + 1 > self.inner.max_depth.load(Ordering::Acquire) {
+ self.inner.max_depth.fetch_add(1, Ordering::AcqRel);
+ }
+ }
+ fn exit(&self, _span: &Id) {
+ self.inner.current_depth.fetch_sub(1, Ordering::AcqRel);
+ }
+ }
+
+ #[test]
+ #[cfg_attr(miri, ignore)] // https://github.com/matklad/once_cell/pull/185
+ fn tracing() {
+ // Create the future outside of the subscriber, as no call to tracing
+ // should be made until the future is polled.
+ let mut struct_impl = Impl(0);
+ let fut = struct_impl.foo(5);
+ let subscriber = TestSubscriber::new();
+ subscriber::with_default(subscriber.clone(), || executor::block_on_simple(fut));
+ // Did we enter bar inside of foo?
+ assert_eq!(subscriber.inner.max_depth.load(Ordering::Acquire), 2);
+ // Have we exited all spans?
+ assert_eq!(subscriber.inner.current_depth.load(Ordering::Acquire), 0);
+ // Did we create only two spans? Note: spans start at 1, hence the -1.
+ assert_eq!(subscriber.inner.max_span_id.load(Ordering::Acquire) - 1, 2);
+ // Was the value recorded at the right depth i.e. in the right function?
+ // If so, was it the expected value?
+ assert_eq!(*subscriber.inner.value.lock().unwrap(), Some(("val", 5, 2)));
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/46
+pub mod issue46 {
+ use async_trait::async_trait;
+
+ macro_rules! implement_commands_workaround {
+ ($tyargs:tt : $ty:tt) => {
+ #[async_trait]
+ pub trait AsyncCommands1: Sized {
+ async fn f<$tyargs: $ty>(&mut self, x: $tyargs) {
+ self.f(x).await
+ }
+ }
+ };
+ }
+
+ implement_commands_workaround!(K: Send);
+
+ macro_rules! implement_commands {
+ ($tyargs:ident : $ty:ident) => {
+ #[async_trait]
+ pub trait AsyncCommands2: Sized {
+ async fn f<$tyargs: $ty>(&mut self, x: $tyargs) {
+ self.f(x).await
+ }
+ }
+ };
+ }
+
+ implement_commands!(K: Send);
+}
+
+// https://github.com/dtolnay/async-trait/issues/53
+pub mod issue53 {
+ use async_trait::async_trait;
+
+ pub struct Unit;
+ pub struct Tuple(u8);
+ pub struct Struct {
+ pub x: u8,
+ }
+
+ #[async_trait]
+ pub trait Trait {
+ async fn method();
+ }
+
+ #[async_trait]
+ impl Trait for Unit {
+ async fn method() {
+ let _ = Self;
+ }
+ }
+
+ #[async_trait]
+ impl Trait for Tuple {
+ async fn method() {
+ let _ = Self(0);
+ }
+ }
+
+ #[async_trait]
+ impl Trait for Struct {
+ async fn method() {
+ let _ = Self { x: 0 };
+ }
+ }
+
+ #[async_trait]
+ impl Trait for std::marker::PhantomData<Struct> {
+ async fn method() {
+ let _ = Self;
+ }
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/57
+#[cfg(async_trait_nightly_testing)]
+pub mod issue57 {
+ use crate::executor;
+ use async_trait::async_trait;
+
+ #[async_trait]
+ trait Trait {
+ async fn const_generic<T: Send, const C: usize>(_: [T; C]) {}
+ }
+
+ struct Struct;
+
+ #[async_trait]
+ impl Trait for Struct {
+ async fn const_generic<T: Send, const C: usize>(_: [T; C]) {}
+ }
+
+ #[test]
+ fn test() {
+ let fut = Struct::const_generic([0; 10]);
+ executor::block_on_simple(fut);
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/68
+pub mod issue68 {
+ #[rustversion::since(1.40)] // procedural macros cannot expand to macro definitions in 1.39.
+ #[async_trait::async_trait]
+ pub trait Example {
+ async fn method(&self) {
+ macro_rules! t {
+ () => {{
+ let _: &Self = self;
+ }};
+ }
+ t!();
+ }
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/73
+pub mod issue73 {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait Example {
+ const ASSOCIATED: &'static str;
+
+ async fn associated(&self) {
+ println!("Associated:{}", Self::ASSOCIATED);
+ }
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/81
+pub mod issue81 {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait Trait {
+ async fn handle(&self);
+ }
+
+ pub enum Enum {
+ Variant,
+ }
+
+ #[async_trait]
+ impl Trait for Enum {
+ async fn handle(&self) {
+ let Enum::Variant = self;
+ let Self::Variant = self;
+ }
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/83
+pub mod issue83 {
+ #![allow(clippy::needless_arbitrary_self_type)]
+
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait Trait {
+ async fn f(&self) {}
+ async fn g(self: &Self) {}
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/85
+pub mod issue85 {
+ #![deny(non_snake_case)]
+
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait Trait {
+ #[allow(non_snake_case)]
+ async fn camelCase();
+ }
+
+ pub struct Struct;
+
+ #[async_trait]
+ impl Trait for Struct {
+ async fn camelCase() {}
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/87
+pub mod issue87 {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait Trait {
+ async fn f(&self);
+ }
+
+ pub enum Tuple {
+ V(),
+ }
+
+ pub enum Struct {
+ V {},
+ }
+
+ #[async_trait]
+ impl Trait for Tuple {
+ async fn f(&self) {
+ let Tuple::V() = self;
+ let Self::V() = self;
+ let _ = Self::V;
+ let _ = Self::V();
+ }
+ }
+
+ #[async_trait]
+ impl Trait for Struct {
+ async fn f(&self) {
+ let Struct::V {} = self;
+ let Self::V {} = self;
+ let _ = Self::V {};
+ }
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/89
+pub mod issue89 {
+ #![allow(bare_trait_objects)]
+
+ use async_trait::async_trait;
+
+ #[async_trait]
+ trait Trait {
+ async fn f(&self);
+ }
+
+ #[async_trait]
+ impl Trait for Send + Sync {
+ async fn f(&self) {}
+ }
+
+ #[async_trait]
+ impl Trait for dyn Fn(i8) + Send + Sync {
+ async fn f(&self) {}
+ }
+
+ #[async_trait]
+ impl Trait for (dyn Fn(u8) + Send + Sync) {
+ async fn f(&self) {}
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/92
+pub mod issue92 {
+ use async_trait::async_trait;
+
+ macro_rules! mac {
+ ($($tt:tt)*) => {
+ $($tt)*
+ };
+ }
+
+ pub struct Struct<T> {
+ _x: T,
+ }
+
+ impl<T> Struct<T> {
+ const ASSOCIATED1: &'static str = "1";
+ async fn associated1() {}
+ }
+
+ #[async_trait]
+ pub trait Trait
+ where
+ mac!(Self): Send,
+ {
+ const ASSOCIATED2: &'static str;
+ type Associated2;
+
+ #[allow(path_statements, clippy::let_underscore_future, clippy::no_effect)]
+ async fn associated2(&self) {
+ // trait items
+ mac!(let _: Self::Associated2;);
+ mac!(let _: <Self>::Associated2;);
+ mac!(let _: <Self as Trait>::Associated2;);
+ mac!(Self::ASSOCIATED2;);
+ mac!(<Self>::ASSOCIATED2;);
+ mac!(<Self as Trait>::ASSOCIATED2;);
+ mac!(let _ = Self::associated2(self););
+ mac!(let _ = <Self>::associated2(self););
+ mac!(let _ = <Self as Trait>::associated2(self););
+ }
+ }
+
+ #[async_trait]
+ impl<T: Send + Sync> Trait for Struct<T>
+ where
+ mac!(Self): Send,
+ {
+ const ASSOCIATED2: &'static str = "2";
+ type Associated2 = ();
+
+ #[allow(path_statements, clippy::let_underscore_future, clippy::no_effect)]
+ async fn associated2(&self) {
+ // inherent items
+ mac!(Self::ASSOCIATED1;);
+ mac!(<Self>::ASSOCIATED1;);
+ mac!(let _ = Self::associated1(););
+ mac!(let _ = <Self>::associated1(););
+
+ // trait items
+ mac!(let _: <Self as Trait>::Associated2;);
+ mac!(Self::ASSOCIATED2;);
+ mac!(<Self>::ASSOCIATED2;);
+ mac!(<Self as Trait>::ASSOCIATED2;);
+ mac!(let _ = Self::associated2(self););
+ mac!(let _ = <Self>::associated2(self););
+ mac!(let _ = <Self as Trait>::associated2(self););
+ }
+ }
+
+ pub struct Unit;
+
+ #[async_trait]
+ impl Trait for Unit {
+ const ASSOCIATED2: &'static str = "2";
+ type Associated2 = ();
+
+ async fn associated2(&self) {
+ mac!(let Self: Self = *self;);
+ }
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/92#issuecomment-683370136
+pub mod issue92_2 {
+ use async_trait::async_trait;
+
+ macro_rules! mac {
+ ($($tt:tt)*) => {
+ $($tt)*
+ };
+ }
+
+ pub trait Trait1 {
+ fn func1();
+ }
+
+ #[async_trait]
+ pub trait Trait2: Trait1 {
+ async fn func2() {
+ mac!(Self::func1());
+
+ macro_rules! mac2 {
+ ($($tt:tt)*) => {
+ Self::func1();
+ };
+ }
+ mac2!();
+ }
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/104
+pub mod issue104 {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ trait T1 {
+ async fn id(&self) -> i32;
+ }
+
+ macro_rules! impl_t1 {
+ ($ty:ty, $id:expr) => {
+ #[async_trait]
+ impl T1 for $ty {
+ async fn id(&self) -> i32 {
+ $id
+ }
+ }
+ };
+ }
+
+ struct Foo;
+
+ impl_t1!(Foo, 1);
+}
+
+// https://github.com/dtolnay/async-trait/issues/106
+pub mod issue106 {
+ use async_trait::async_trait;
+ use std::future::Future;
+
+ #[async_trait]
+ pub trait ProcessPool: Send + Sync {
+ type ThreadPool;
+
+ async fn spawn<F, Fut, T>(&self, work: F) -> T
+ where
+ F: FnOnce(&Self::ThreadPool) -> Fut + Send,
+ Fut: Future<Output = T> + 'static;
+ }
+
+ #[async_trait]
+ impl<P> ProcessPool for &P
+ where
+ P: ?Sized + ProcessPool,
+ {
+ type ThreadPool = P::ThreadPool;
+
+ async fn spawn<F, Fut, T>(&self, work: F) -> T
+ where
+ F: FnOnce(&Self::ThreadPool) -> Fut + Send,
+ Fut: Future<Output = T> + 'static,
+ {
+ (**self).spawn(work).await
+ }
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/110
+pub mod issue110 {
+ use async_trait::async_trait;
+ use std::marker::PhantomData;
+
+ #[async_trait]
+ pub trait Loader {
+ async fn load(&self, key: &str);
+ }
+
+ pub struct AwsEc2MetadataLoader<'a> {
+ marker: PhantomData<&'a ()>,
+ }
+
+ #[async_trait]
+ impl Loader for AwsEc2MetadataLoader<'_> {
+ async fn load(&self, _key: &str) {}
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/120
+pub mod issue120 {
+ #![deny(clippy::trivially_copy_pass_by_ref)]
+
+ use async_trait::async_trait;
+
+ #[async_trait]
+ trait Trait {
+ async fn f(&self);
+ }
+
+ #[async_trait]
+ impl Trait for () {
+ async fn f(&self) {}
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/123
+pub mod issue123 {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ trait Trait<T = ()> {
+ async fn f(&self) -> &str
+ where
+ T: 'async_trait,
+ {
+ "default"
+ }
+ }
+
+ #[async_trait]
+ impl<T> Trait<T> for () {}
+}
+
+// https://github.com/dtolnay/async-trait/issues/129
+pub mod issue129 {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait TestTrait {
+ async fn a(_b: u8, c: u8) -> u8 {
+ c
+ }
+ }
+
+ pub struct TestStruct;
+
+ #[async_trait]
+ impl TestTrait for TestStruct {
+ async fn a(_b: u8, c: u8) -> u8 {
+ c
+ }
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/134
+#[cfg(async_trait_nightly_testing)]
+pub mod issue134 {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ trait TestTrait {
+ async fn run<const DUMMY: bool>(self)
+ where
+ Self: Sized,
+ {
+ }
+ }
+
+ pub struct TestStruct;
+
+ #[async_trait]
+ impl TestTrait for TestStruct {
+ async fn run<const DUMMY: bool>(self)
+ where
+ Self: Sized,
+ {
+ }
+ }
+}
+
+// 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);
+ }
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/158
+pub mod issue158 {
+ use async_trait::async_trait;
+
+ fn f() {}
+
+ #[async_trait]
+ pub trait Trait {
+ async fn f(&self) {
+ self::f();
+ }
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/161
+#[allow(clippy::mut_mut)]
+pub mod issue161 {
+ use async_trait::async_trait;
+ use futures::future::FutureExt;
+ use std::sync::Arc;
+
+ #[async_trait]
+ pub trait Trait {
+ async fn f(self: Arc<Self>);
+ }
+
+ pub struct MyStruct(bool);
+
+ #[async_trait]
+ impl Trait for MyStruct {
+ async fn f(self: Arc<Self>) {
+ futures::select! {
+ _ = async {
+ println!("{}", self.0);
+ }.fuse() => {}
+ }
+ }
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/169
+#[deny(where_clauses_object_safety)]
+pub mod issue169 {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait Trait: ::core::marker::Sync {
+ async fn f(&self) {}
+ }
+
+ pub fn test(_t: &dyn Trait) {}
+}
+
+// https://github.com/dtolnay/async-trait/issues/177
+pub mod issue177 {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait Trait {
+ async fn foo(&self, _callback: impl FnMut(&str) + Send) {}
+ }
+
+ pub struct Struct;
+
+ #[async_trait]
+ impl Trait for Struct {
+ async fn foo(&self, _callback: impl FnMut(&str) + Send) {}
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/183
+pub mod issue183 {
+ #![deny(clippy::shadow_same)]
+
+ use async_trait::async_trait;
+
+ #[async_trait]
+ trait Foo {
+ async fn foo(_n: i32) {}
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/199
+pub mod issue199 {
+ use async_trait::async_trait;
+ use std::cell::Cell;
+
+ struct IncrementOnDrop<'a>(&'a Cell<usize>);
+
+ impl<'a> Drop for IncrementOnDrop<'a> {
+ fn drop(&mut self) {
+ self.0.set(self.0.get() + 1);
+ }
+ }
+
+ #[async_trait(?Send)]
+ trait Trait {
+ async fn f(counter: &Cell<usize>, arg: IncrementOnDrop<'_>);
+ }
+
+ struct Struct;
+
+ #[async_trait(?Send)]
+ impl Trait for Struct {
+ async fn f(counter: &Cell<usize>, _: IncrementOnDrop<'_>) {
+ assert_eq!(counter.get(), 0); // second arg not dropped yet
+ }
+ }
+
+ #[test]
+ fn test() {
+ let counter = Cell::new(0);
+ let future = Struct::f(&counter, IncrementOnDrop(&counter));
+ assert_eq!(counter.get(), 0);
+ drop(future);
+ assert_eq!(counter.get(), 1);
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/204
+pub mod issue204 {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait Trait {
+ async fn f(arg: &impl Trait);
+ async fn g(arg: *const impl Trait);
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/210
+pub mod issue210 {
+ use async_trait::async_trait;
+ use std::sync::Arc;
+
+ #[async_trait]
+ pub trait Trait {
+ async fn f(self: Arc<Self>) {}
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/226
+pub mod issue226 {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait Trait {
+ async fn cfg_param(&self, param: u8);
+ async fn cfg_param_wildcard(&self, _: u8);
+ async fn cfg_param_tuple(&self, (left, right): (u8, u8));
+ }
+
+ struct Struct;
+
+ #[async_trait]
+ impl Trait for Struct {
+ async fn cfg_param(&self, #[cfg(any())] param: u8, #[cfg(all())] _unused: u8) {}
+
+ async fn cfg_param_wildcard(&self, #[cfg(any())] _: u8, #[cfg(all())] _: u8) {}
+
+ async fn cfg_param_tuple(
+ &self,
+ #[cfg(any())] (left, right): (u8, u8),
+ #[cfg(all())] (_left, _right): (u8, u8),
+ ) {
+ }
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/232
+pub mod issue232 {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait Generic<T> {
+ async fn take_ref(&self, thing: &T);
+ }
+
+ pub struct One;
+
+ #[async_trait]
+ impl<T> Generic<T> for One {
+ async fn take_ref(&self, _: &T) {}
+ }
+
+ pub struct Two;
+
+ #[async_trait]
+ impl<T: Sync> Generic<(T, T)> for Two {
+ async fn take_ref(&self, (a, b): &(T, T)) {
+ let _ = a;
+ let _ = b;
+ }
+ }
+
+ pub struct Three;
+
+ #[async_trait]
+ impl<T> Generic<(T, T, T)> for Three {
+ async fn take_ref(&self, (_a, _b, _c): &(T, T, T)) {}
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/234
+pub mod issue234 {
+ use async_trait::async_trait;
+
+ pub struct Droppable;
+
+ impl Drop for Droppable {
+ fn drop(&mut self) {}
+ }
+
+ pub struct Tuple<T, U>(T, U);
+
+ #[async_trait]
+ pub trait Trait {
+ async fn f(arg: Tuple<Droppable, i32>);
+ }
+
+ pub struct UnderscorePattern;
+
+ #[async_trait]
+ impl Trait for UnderscorePattern {
+ async fn f(Tuple(_, _int): Tuple<Droppable, i32>) {}
+ }
+
+ pub struct DotDotPattern;
+
+ #[async_trait]
+ impl Trait for DotDotPattern {
+ async fn f(Tuple { 1: _int, .. }: Tuple<Droppable, i32>) {}
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/236
+pub mod issue236 {
+ #![deny(clippy::async_yields_async)]
+ #![allow(clippy::manual_async_fn)]
+
+ use async_trait::async_trait;
+ use std::future::{self, Future, Ready};
+
+ // Does not trigger the lint.
+ pub async fn async_fn() -> Ready<()> {
+ future::ready(())
+ }
+
+ #[allow(clippy::async_yields_async)]
+ pub fn impl_future_fn() -> impl Future<Output = Ready<()>> {
+ async { future::ready(()) }
+ }
+
+ // The async_trait attribute turns the former into the latter, so we make it
+ // put its own allow(async_yeilds_async) to remain consistent with async fn.
+ #[async_trait]
+ pub trait Trait {
+ async fn f() -> Ready<()> {
+ future::ready(())
+ }
+ }
+}
+
+// https://github.com/dtolnay/async-trait/issues/238
+pub mod issue238 {
+ #![deny(single_use_lifetimes)]
+
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait Trait {
+ async fn f();
+ }
+
+ pub struct Struct;
+
+ #[async_trait]
+ impl Trait for &Struct {
+ async fn f() {}
+ }
+}
diff --git a/tests/ui/arg-implementation-detail.rs b/tests/ui/arg-implementation-detail.rs
new file mode 100644
index 0000000..b83aa72
--- /dev/null
+++ b/tests/ui/arg-implementation-detail.rs
@@ -0,0 +1,22 @@
+use async_trait::async_trait;
+
+pub struct Struct;
+
+#[async_trait]
+pub trait Trait {
+ async fn f((_a, _b): (Struct, Struct)) {
+ // Expands to something like:
+ //
+ // fn f(__arg0: (Struct, Struct)) -> … {
+ // Box::pin(async move {
+ // let (_a, _b) = __arg0;
+ // …
+ // })
+ // }
+ //
+ // but user's code must not be allowed to name that temporary argument:
+ let _ = __arg0;
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/arg-implementation-detail.stderr b/tests/ui/arg-implementation-detail.stderr
new file mode 100644
index 0000000..e742688
--- /dev/null
+++ b/tests/ui/arg-implementation-detail.stderr
@@ -0,0 +1,5 @@
+error[E0425]: cannot find value `__arg0` in this scope
+ --> tests/ui/arg-implementation-detail.rs:18:17
+ |
+18 | let _ = __arg0;
+ | ^^^^^^ not found in this scope
diff --git a/tests/ui/bare-trait-object.rs b/tests/ui/bare-trait-object.rs
new file mode 100644
index 0000000..afcd6b4
--- /dev/null
+++ b/tests/ui/bare-trait-object.rs
@@ -0,0 +1,15 @@
+#![deny(bare_trait_objects)]
+
+use async_trait::async_trait;
+
+#[async_trait]
+trait Trait {
+ async fn f(&self);
+}
+
+#[async_trait]
+impl Trait for Send + Sync {
+ async fn f(&self) {}
+}
+
+fn main() {}
diff --git a/tests/ui/bare-trait-object.stderr b/tests/ui/bare-trait-object.stderr
new file mode 100644
index 0000000..50b2048
--- /dev/null
+++ b/tests/ui/bare-trait-object.stderr
@@ -0,0 +1,21 @@
+error: trait objects without an explicit `dyn` are deprecated
+ --> tests/ui/bare-trait-object.rs:11:16
+ |
+11 | impl Trait for Send + Sync {
+ | ^^^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+note: the lint level is defined here
+ --> tests/ui/bare-trait-object.rs:1:9
+ |
+1 | #![deny(bare_trait_objects)]
+ | ^^^^^^^^^^^^^^^^^^
+help: use `dyn`
+ |
+11 | impl Trait for dyn Send + Sync {
+ | +++
+help: alternatively use a blanket implementation to implement `Trait` for all types that also implement `Send + Sync`
+ |
+11 | impl<T: Send + Sync> Trait for T {
+ | ++++++++++++++++ ~
diff --git a/tests/ui/consider-restricting.rs b/tests/ui/consider-restricting.rs
new file mode 100644
index 0000000..e23c8b1
--- /dev/null
+++ b/tests/ui/consider-restricting.rs
@@ -0,0 +1,26 @@
+// https://github.com/rust-lang/rust/issues/93828
+
+use async_trait::async_trait;
+
+pub trait IntoUrl {}
+
+#[async_trait]
+pub trait ClientExt {
+ async fn publish<T: IntoUrl>(&self, url: T);
+}
+
+struct Client;
+
+#[async_trait]
+impl ClientExt for Client {
+ async fn publish<T: IntoUrl>(&self, url: T) {}
+}
+
+struct Client2;
+
+#[async_trait]
+impl ClientExt for Client2 {
+ async fn publish<T>(&self, url: T) {}
+}
+
+fn main() {}
diff --git a/tests/ui/consider-restricting.stderr b/tests/ui/consider-restricting.stderr
new file mode 100644
index 0000000..62ff894
--- /dev/null
+++ b/tests/ui/consider-restricting.stderr
@@ -0,0 +1,33 @@
+error: future cannot be sent between threads safely
+ --> tests/ui/consider-restricting.rs:16:49
+ |
+16 | async fn publish<T: IntoUrl>(&self, url: T) {}
+ | ^^ future created by async block is not `Send`
+ |
+note: captured value is not `Send`
+ --> tests/ui/consider-restricting.rs:16:41
+ |
+16 | async fn publish<T: IntoUrl>(&self, url: T) {}
+ | ^^^ has type `T` which is not `Send`
+ = note: required for the cast from `[async block@$DIR/tests/ui/consider-restricting.rs:16:49: 16:51]` to the object type `dyn Future<Output = ()> + Send`
+help: consider further restricting this bound
+ |
+16 | async fn publish<T: IntoUrl + std::marker::Send>(&self, url: T) {}
+ | +++++++++++++++++++
+
+error: future cannot be sent between threads safely
+ --> tests/ui/consider-restricting.rs:23:40
+ |
+23 | async fn publish<T>(&self, url: T) {}
+ | ^^ future created by async block is not `Send`
+ |
+note: captured value is not `Send`
+ --> tests/ui/consider-restricting.rs:23:32
+ |
+23 | async fn publish<T>(&self, url: T) {}
+ | ^^^ has type `T` which is not `Send`
+ = note: required for the cast from `[async block@$DIR/tests/ui/consider-restricting.rs:23:40: 23:42]` to the object type `dyn Future<Output = ()> + Send`
+help: consider further restricting this bound
+ |
+23 | async fn publish<T + std::marker::Send>(&self, url: T) {}
+ | +++++++++++++++++++
diff --git a/tests/ui/delimiter-span.rs b/tests/ui/delimiter-span.rs
new file mode 100644
index 0000000..51a44a2
--- /dev/null
+++ b/tests/ui/delimiter-span.rs
@@ -0,0 +1,24 @@
+#![allow(unused_macro_rules)]
+
+use async_trait::async_trait;
+
+macro_rules! picky {
+ ($(t:tt)*) => {};
+}
+
+#[async_trait]
+trait Trait {
+ async fn method();
+}
+
+struct Struct;
+
+#[async_trait]
+impl Trait for Struct {
+ async fn method() {
+ picky!({ 123, self });
+ picky!({ 123 });
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/delimiter-span.stderr b/tests/ui/delimiter-span.stderr
new file mode 100644
index 0000000..f03da4c
--- /dev/null
+++ b/tests/ui/delimiter-span.stderr
@@ -0,0 +1,21 @@
+error: no rules expected the token `{`
+ --> tests/ui/delimiter-span.rs:19:16
+ |
+5 | macro_rules! picky {
+ | ------------------ when calling this macro
+...
+19 | picky!({ 123, self });
+ | ^ no rules expected this token in macro call
+ |
+ = note: while trying to match sequence start
+
+error: no rules expected the token `{`
+ --> tests/ui/delimiter-span.rs:20:16
+ |
+5 | macro_rules! picky {
+ | ------------------ when calling this macro
+...
+20 | picky!({ 123 });
+ | ^ no rules expected this token in macro call
+ |
+ = note: while trying to match sequence start
diff --git a/tests/ui/lifetime-defined-here.rs b/tests/ui/lifetime-defined-here.rs
new file mode 100644
index 0000000..237cf66
--- /dev/null
+++ b/tests/ui/lifetime-defined-here.rs
@@ -0,0 +1,23 @@
+use async_trait::async_trait;
+
+#[async_trait]
+trait Foo {
+ async fn bar(&self, x: &str, y: &'_ str) -> &'static str;
+}
+
+struct S(String);
+
+#[async_trait]
+impl Foo for S {
+ async fn bar(&self, x: &str, y: &'_ str) -> &'static str {
+ if false {
+ &self.0
+ } else if false {
+ x
+ } else {
+ y
+ }
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/lifetime-defined-here.stderr b/tests/ui/lifetime-defined-here.stderr
new file mode 100644
index 0000000..9ffef5b
--- /dev/null
+++ b/tests/ui/lifetime-defined-here.stderr
@@ -0,0 +1,29 @@
+error: lifetime may not live long enough
+ --> tests/ui/lifetime-defined-here.rs:12:49
+ |
+12 | async fn bar(&self, x: &str, y: &'_ str) -> &'static str {
+ | - ^^^^^^^^^^^^ type annotation requires that `'life0` must outlive `'static`
+ | |
+ | lifetime `'life0` defined here
+
+error: lifetime may not live long enough
+ --> tests/ui/lifetime-defined-here.rs:12:49
+ |
+12 | async fn bar(&self, x: &str, y: &'_ str) -> &'static str {
+ | - ^^^^^^^^^^^^ type annotation requires that `'life1` must outlive `'static`
+ | |
+ | lifetime `'life1` defined here
+
+error: lifetime may not live long enough
+ --> tests/ui/lifetime-defined-here.rs:12:49
+ |
+12 | async fn bar(&self, x: &str, y: &'_ str) -> &'static str {
+ | -- ^^^^^^^^^^^^ type annotation requires that `'life2` must outlive `'static`
+ | |
+ | lifetime `'life2` defined here
+
+help: the following changes may resolve your lifetime errors
+ |
+ = help: replace `'life0` with `'static`
+ = help: replace `'life1` with `'static`
+ = help: replace `'life2` with `'static`
diff --git a/tests/ui/lifetime-span.rs b/tests/ui/lifetime-span.rs
new file mode 100644
index 0000000..01981e6
--- /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..fa16ac7
--- /dev/null
+++ b/tests/ui/lifetime-span.stderr
@@ -0,0 +1,24 @@
+error[E0726]: implicit elided lifetime not allowed here
+ --> tests/ui/lifetime-span.rs:12:6
+ |
+12 | impl Trait for A {
+ | ^^^^^ expected lifetime parameter
+ |
+help: indicate the anonymous lifetime
+ |
+12 | impl Trait<'_> for A {
+ | ++++
+
+error[E0107]: trait takes 0 lifetime arguments but 1 lifetime argument was supplied
+ --> tests/ui/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
+ --> tests/ui/lifetime-span.rs:22:11
+ |
+22 | pub trait Trait2 {
+ | ^^^^^^
diff --git a/tests/ui/missing-async-in-impl.rs b/tests/ui/missing-async-in-impl.rs
new file mode 100644
index 0000000..3a5f58c
--- /dev/null
+++ b/tests/ui/missing-async-in-impl.rs
@@ -0,0 +1,15 @@
+use async_trait::async_trait;
+
+#[async_trait]
+pub trait Trait {
+ async fn method();
+}
+
+pub struct Struct;
+
+#[async_trait]
+impl Trait for Struct {
+ fn method() {}
+}
+
+fn main() {}
diff --git a/tests/ui/missing-async-in-impl.stderr b/tests/ui/missing-async-in-impl.stderr
new file mode 100644
index 0000000..e461c85
--- /dev/null
+++ b/tests/ui/missing-async-in-impl.stderr
@@ -0,0 +1,8 @@
+error[E0195]: lifetime parameters or bounds on method `method` do not match the trait declaration
+ --> tests/ui/missing-async-in-impl.rs:12:14
+ |
+5 | async fn method();
+ | -------- lifetimes in impl do not match this method in trait
+...
+12 | fn method() {}
+ | ^ lifetimes do not match method in trait
diff --git a/tests/ui/missing-async-in-trait.rs b/tests/ui/missing-async-in-trait.rs
new file mode 100644
index 0000000..56fea7a
--- /dev/null
+++ b/tests/ui/missing-async-in-trait.rs
@@ -0,0 +1,15 @@
+use async_trait::async_trait;
+
+#[async_trait]
+pub trait Trait {
+ fn method();
+}
+
+pub struct Struct;
+
+#[async_trait]
+impl Trait for Struct {
+ async fn method() {}
+}
+
+fn main() {}
diff --git a/tests/ui/missing-async-in-trait.stderr b/tests/ui/missing-async-in-trait.stderr
new file mode 100644
index 0000000..c92c38d
--- /dev/null
+++ b/tests/ui/missing-async-in-trait.stderr
@@ -0,0 +1,8 @@
+error[E0195]: lifetime parameters or bounds on method `method` do not match the trait declaration
+ --> tests/ui/missing-async-in-trait.rs:12:14
+ |
+5 | fn method();
+ | - lifetimes in impl do not match this method in trait
+...
+12 | async fn method() {}
+ | ^^^^^^^^ lifetimes do not match method in trait
diff --git a/tests/ui/missing-body.rs b/tests/ui/missing-body.rs
new file mode 100644
index 0000000..f3e1126
--- /dev/null
+++ b/tests/ui/missing-body.rs
@@ -0,0 +1,15 @@
+use async_trait::async_trait;
+
+#[async_trait]
+trait Trait {
+ async fn f(&self);
+}
+
+struct Thing;
+
+#[async_trait]
+impl Trait for Thing {
+ async fn f(&self);
+}
+
+fn main() {}
diff --git a/tests/ui/missing-body.stderr b/tests/ui/missing-body.stderr
new file mode 100644
index 0000000..e6ddb42
--- /dev/null
+++ b/tests/ui/missing-body.stderr
@@ -0,0 +1,7 @@
+error: associated function in `impl` without body
+ --> tests/ui/missing-body.rs:12:5
+ |
+12 | async fn f(&self);
+ | ^^^^^^^^^^^^^^^^^-
+ | |
+ | help: provide a definition for the function: `{ <body> }`
diff --git a/tests/ui/must-use.rs b/tests/ui/must-use.rs
new file mode 100644
index 0000000..7ad0d9b
--- /dev/null
+++ b/tests/ui/must-use.rs
@@ -0,0 +1,21 @@
+#![deny(unused_must_use)]
+
+use async_trait::async_trait;
+
+#[async_trait]
+trait Interface {
+ async fn f(&self);
+}
+
+struct Thing;
+
+#[async_trait]
+impl Interface for Thing {
+ async fn f(&self) {}
+}
+
+pub async fn f() {
+ Thing.f();
+}
+
+fn main() {}
diff --git a/tests/ui/must-use.stderr b/tests/ui/must-use.stderr
new file mode 100644
index 0000000..fd6fc31
--- /dev/null
+++ b/tests/ui/must-use.stderr
@@ -0,0 +1,11 @@
+error: unused return value of `Interface::f` that must be used
+ --> tests/ui/must-use.rs:18:5
+ |
+18 | Thing.f();
+ | ^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> tests/ui/must-use.rs:1:9
+ |
+1 | #![deny(unused_must_use)]
+ | ^^^^^^^^^^^^^^^
diff --git a/tests/ui/self-span.rs b/tests/ui/self-span.rs
new file mode 100644
index 0000000..b01f247
--- /dev/null
+++ b/tests/ui/self-span.rs
@@ -0,0 +1,30 @@
+use async_trait::async_trait;
+
+pub struct S {}
+
+pub enum E {
+ V {},
+}
+
+#[async_trait]
+pub trait Trait {
+ async fn method(self);
+}
+
+#[async_trait]
+impl Trait for S {
+ async fn method(self) {
+ let _: () = self;
+ let _: Self = Self;
+ }
+}
+
+#[async_trait]
+impl Trait for E {
+ async fn method(self) {
+ let _: () = self;
+ let _: Self = Self::V;
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/self-span.stderr b/tests/ui/self-span.stderr
new file mode 100644
index 0000000..04493f8
--- /dev/null
+++ b/tests/ui/self-span.stderr
@@ -0,0 +1,27 @@
+error[E0308]: mismatched types
+ --> tests/ui/self-span.rs:17:21
+ |
+17 | let _: () = self;
+ | -- ^^^^ expected `()`, found `S`
+ | |
+ | expected due to this
+
+error: the `Self` constructor can only be used with tuple or unit structs
+ --> tests/ui/self-span.rs:18:23
+ |
+18 | let _: Self = Self;
+ | ^^^^ help: use curly brackets: `Self { /* fields */ }`
+
+error[E0308]: mismatched types
+ --> tests/ui/self-span.rs:25:21
+ |
+25 | let _: () = self;
+ | -- ^^^^ expected `()`, found `E`
+ | |
+ | expected due to this
+
+error[E0533]: expected value, found struct variant `Self::V`
+ --> tests/ui/self-span.rs:26:23
+ |
+26 | let _: Self = Self::V;
+ | ^^^^^^^ not a value
diff --git a/tests/ui/send-not-implemented.rs b/tests/ui/send-not-implemented.rs
new file mode 100644
index 0000000..d8883fb
--- /dev/null
+++ b/tests/ui/send-not-implemented.rs
@@ -0,0 +1,22 @@
+use async_trait::async_trait;
+use std::sync::Mutex;
+
+async fn f() {}
+
+#[async_trait]
+trait Test {
+ async fn test(&self) {
+ let mutex = Mutex::new(());
+ 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
new file mode 100644
index 0000000..d68fc43
--- /dev/null
+++ b/tests/ui/send-not-implemented.stderr
@@ -0,0 +1,47 @@
+error: future cannot be sent between threads safely
+ --> tests/ui/send-not-implemented.rs:8:26
+ |
+8 | async fn test(&self) {
+ | __________________________^
+9 | | let mutex = Mutex::new(());
+10 | | let _guard = mutex.lock().unwrap();
+11 | | f().await;
+12 | | }
+ | |_____^ future created by async block is not `Send`
+ |
+ = help: within `[async block@$DIR/tests/ui/send-not-implemented.rs:8:26: 12:6]`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
+note: future is not `Send` as this value is used across an await
+ --> tests/ui/send-not-implemented.rs:11:12
+ |
+10 | let _guard = mutex.lock().unwrap();
+ | ------ has type `MutexGuard<'_, ()>` which is not `Send`
+11 | f().await;
+ | ^^^^^^ await occurs here, with `_guard` maybe used later
+12 | }
+ | - `_guard` is later dropped here
+ = note: required for the cast from `[async block@$DIR/tests/ui/send-not-implemented.rs:8:26: 12:6]` to the object type `dyn Future<Output = ()> + Send`
+
+error: future cannot be sent between threads safely
+ --> tests/ui/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 `[async block@$DIR/tests/ui/send-not-implemented.rs:14:38: 19:6]`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
+note: future is not `Send` as this value is used across an await
+ --> tests/ui/send-not-implemented.rs:17:12
+ |
+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 from `[async block@$DIR/tests/ui/send-not-implemented.rs:14:38: 19:6]` 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..cac2826
--- /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..08595e5
--- /dev/null
+++ b/tests/ui/unreachable.stderr
@@ -0,0 +1,14 @@
+error: unreachable statement
+ --> tests/ui/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
+ --> tests/ui/unreachable.rs:1:9
+ |
+1 | #![deny(warnings)]
+ | ^^^^^^^^
+ = note: `#[deny(unreachable_code)]` implied by `#[deny(warnings)]`
diff --git a/tests/ui/unsupported-self.rs b/tests/ui/unsupported-self.rs
new file mode 100644
index 0000000..5868c61
--- /dev/null
+++ b/tests/ui/unsupported-self.rs
@@ -0,0 +1,15 @@
+use async_trait::async_trait;
+
+#[async_trait]
+pub trait Trait {
+ async fn method();
+}
+
+#[async_trait]
+impl Trait for &'static str {
+ async fn method() {
+ let _ = Self;
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/unsupported-self.stderr b/tests/ui/unsupported-self.stderr
new file mode 100644
index 0000000..1493945
--- /dev/null
+++ b/tests/ui/unsupported-self.stderr
@@ -0,0 +1,5 @@
+error: the `Self` constructor can only be used with tuple or unit structs
+ --> tests/ui/unsupported-self.rs:11:17
+ |
+11 | let _ = Self;
+ | ^^^^