aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 04:42:26 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 04:42:26 +0000
commit4f4d1e478c8dd835446cf13e30871147319886ea (patch)
treee0994522f9858cc1bc9c4a96359f1b1eeb7ac1b8
parent6668dafa5e4ceabfc62c076e20f83ebb8ab81b12 (diff)
parent6b971a4de34138562b564ab40528ebf15c005117 (diff)
downloadasync-trait-android14-mainline-art-release.tar.gz
Change-Id: I8c4f004decc4edbd9119ea3de8c65da892cb12fb
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--.github/workflows/ci.yml44
-rw-r--r--Android.bp4
-rw-r--r--Cargo.toml16
-rw-r--r--Cargo.toml.orig14
-rw-r--r--LICENSE-APACHE25
-rw-r--r--METADATA12
-rw-r--r--README.md4
-rw-r--r--TEST_MAPPING66
-rw-r--r--build.rs6
-rw-r--r--src/bound.rs48
-rw-r--r--src/expand.rs229
-rw-r--r--src/lib.rs4
-rw-r--r--src/lifetime.rs72
-rw-r--r--tests/compiletest.rs1
-rw-r--r--tests/test.rs213
-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.stderr14
-rw-r--r--tests/ui/consider-restricting.rs26
-rw-r--r--tests/ui/consider-restricting.stderr33
-rw-r--r--tests/ui/delimiter-span.rs2
-rw-r--r--tests/ui/delimiter-span.stderr16
-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.rs8
-rw-r--r--tests/ui/lifetime-span.stderr33
-rw-r--r--tests/ui/must-use.stderr2
-rw-r--r--tests/ui/self-span.stderr4
-rw-r--r--tests/ui/send-not-implemented.stderr16
30 files changed, 723 insertions, 270 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 71c36c5..4b97a9e 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
{
"git": {
- "sha1": "20bd296e0d646e2b14626b7078e045254bed26ee"
+ "sha1": "6a13fce88235ebd11c0c67f419a3153dcd349eb9"
},
"path_in_vcs": ""
} \ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7c80abc..9443750 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -5,31 +5,46 @@ on:
pull_request:
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: [beta, stable, 1.45.0]
+ rust: [beta, stable, 1.56.0]
include:
- rust: nightly
rustflags: --cfg async_trait_nightly_testing
+ timeout-minutes: 45
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{matrix.rust}}
- run: cargo test
env:
- RUSTFLAGS: ${{matrix.rustflags}}
+ RUSTFLAGS: ${{matrix.rustflags}} ${{env.RUSTFLAGS}}
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@v2
+ - uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@1.39.0
- run: cargo check
@@ -37,16 +52,31 @@ jobs:
name: Clippy
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
+ timeout-minutes: 45
steps:
- - uses: actions/checkout@v2
+ - 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@v2
+ - uses: actions/checkout@v3
- uses: dtolnay/install@cargo-outdated
- - run: cargo outdated --exit-code 1
+ - run: cargo outdated --workspace --exit-code 1
diff --git a/Android.bp b/Android.bp
index 09676ac..c7d70bb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -41,7 +41,7 @@ rust_proc_macro {
name: "libasync_trait",
crate_name: "async_trait",
cargo_env_compat: true,
- cargo_pkg_version: "0.1.52",
+ cargo_pkg_version: "0.1.64",
srcs: ["src/lib.rs"],
edition: "2018",
rustlibs: [
@@ -49,4 +49,6 @@ rust_proc_macro {
"libquote",
"libsyn",
],
+ product_available: true,
+ vendor_available: true,
}
diff --git a/Cargo.toml b/Cargo.toml
index d09788d..5a6efbe 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,19 +13,25 @@
edition = "2018"
rust-version = "1.39"
name = "async-trait"
-version = "0.1.52"
+version = "0.1.64"
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"
@@ -33,8 +39,12 @@ version = "1.0"
version = "1.0"
[dependencies.syn]
-version = "1.0.61"
-features = ["full", "visit-mut"]
+version = "1.0.96"
+features = [
+ "full",
+ "visit-mut",
+]
+
[dev-dependencies.futures]
version = "0.3"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index c340ced..2dd4171 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,15 +1,15 @@
[package]
name = "async-trait"
-version = "0.1.52"
+version = "0.1.64"
authors = ["David Tolnay <dtolnay@gmail.com>"]
-edition = "2018"
-rust-version = "1.39"
-license = "MIT OR Apache-2.0"
+categories = ["asynchronous", "no-std"]
description = "Type erasure for async trait methods"
-repository = "https://github.com/dtolnay/async-trait"
documentation = "https://docs.rs/async-trait"
-readme = "README.md"
+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
@@ -17,7 +17,7 @@ proc-macro = true
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
-syn = { version = "1.0.61", features = ["full", "visit-mut"] }
+syn = { version = "1.0.96", features = ["full", "visit-mut"] }
[dev-dependencies]
futures = "0.3"
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
index 16fe87b..1b5ec8b 100644
--- a/LICENSE-APACHE
+++ b/LICENSE-APACHE
@@ -174,28 +174,3 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
-
-APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
-Copyright [yyyy] [name of copyright owner]
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
diff --git a/METADATA b/METADATA
index 5da1fec..0445905 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update rust/crates/async-trait
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+
name: "async-trait"
description: "Type erasure for async trait methods"
third_party {
@@ -7,13 +11,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/async-trait/async-trait-0.1.52.crate"
+ value: "https://static.crates.io/crates/async-trait/async-trait-0.1.64.crate"
}
- version: "0.1.52"
+ version: "0.1.64"
license_type: NOTICE
last_upgrade_date {
- year: 2022
- month: 3
+ year: 2023
+ month: 2
day: 1
}
}
diff --git a/README.md b/README.md
index 4753f50..39e368b 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,8 @@ 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&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20">](https://docs.rs/async-trait)
-[<img alt="build status" src="https://img.shields.io/github/workflow/status/dtolnay/async-trait/CI/master?style=for-the-badge" height="20">](https://github.com/dtolnay/async-trait/actions?query=branch%3Amaster)
+[<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
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 396e4da..35ab0a7 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,79 +1,35 @@
// Generated by update_crate_tests.py for tests that depend on this crate.
{
- "presubmit": [
+ "imports": [
{
- "name": "ZipFuseTest"
+ "path": "external/uwb/src"
},
{
- "name": "authfs_device_test_src_lib"
+ "path": "packages/modules/Virtualization/authfs"
},
{
- "name": "diced_open_dice_cbor_test"
+ "path": "packages/modules/Virtualization/microdroid_manager"
},
{
- "name": "diced_sample_inputs_test"
+ "path": "packages/modules/Virtualization/virtualizationmanager"
},
{
- "name": "diced_test"
+ "path": "packages/modules/Virtualization/vm"
},
{
- "name": "diced_utils_test"
+ "path": "packages/modules/Virtualization/zipfuse"
},
{
- "name": "diced_vendor_test"
+ "path": "system/keymint/hal"
},
{
- "name": "keystore2_km_compat_test"
+ "path": "system/security/diced"
},
{
- "name": "keystore2_test"
+ "path": "system/security/keystore2"
},
{
- "name": "legacykeystore_test"
- },
- {
- "name": "microdroid_manager_test"
- },
- {
- "name": "virtualizationservice_device_test"
- }
- ],
- "presubmit-rust": [
- {
- "name": "ZipFuseTest"
- },
- {
- "name": "authfs_device_test_src_lib"
- },
- {
- "name": "diced_open_dice_cbor_test"
- },
- {
- "name": "diced_sample_inputs_test"
- },
- {
- "name": "diced_test"
- },
- {
- "name": "diced_utils_test"
- },
- {
- "name": "diced_vendor_test"
- },
- {
- "name": "keystore2_km_compat_test"
- },
- {
- "name": "keystore2_test"
- },
- {
- "name": "legacykeystore_test"
- },
- {
- "name": "microdroid_manager_test"
- },
- {
- "name": "virtualizationservice_device_test"
+ "path": "system/security/keystore2/legacykeystore"
}
]
}
diff --git a/build.rs b/build.rs
index a2b0833..d7f6b15 100644
--- a/build.rs
+++ b/build.rs
@@ -3,11 +3,17 @@ 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");
}
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
index 2f4697a..88338db 100644
--- a/src/expand.rs
+++ b/src/expand.rs
@@ -1,23 +1,19 @@
-use crate::lifetime::CollectLifetimes;
+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::TokenStream;
+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, Attribute, Block, FnArg, GenericParam, Generics, Ident, ImplItem, Lifetime, Pat,
- PatIdent, Receiver, ReturnType, Signature, Stmt, Token, TraitItem, Type, TypeParamBound,
- TypePath, WhereClause,
+ 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,
};
-macro_rules! parse_quote_spanned {
- ($span:expr=> $($t:tt)*) => {
- syn::parse2(quote_spanned!($span=> $($t)*)).unwrap()
- };
-}
-
impl ToTokens for Item {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
@@ -40,23 +36,22 @@ enum Context<'a> {
}
impl Context<'_> {
- fn lifetimes<'a>(&'a self, used: &'a [Lifetime]) -> impl Iterator<Item = &'a GenericParam> {
+ 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(move |param| {
+ generics.params.iter().filter_map(move |param| {
if let GenericParam::Lifetime(param) = param {
- used.contains(&param.lifetime)
- } else {
- false
+ if used.contains(&param.lifetime) {
+ return Some(param);
+ }
}
+ None
})
}
}
-type Supertraits = Punctuated<TypeParamBound, Token![+]>;
-
pub fn expand(input: &mut Item, is_local: bool) {
match input {
Item::Trait(input) => {
@@ -85,7 +80,7 @@ pub fn expand(input: &mut Item, is_local: bool) {
}
}
Item::Impl(input) => {
- let mut lifetimes = CollectLifetimes::new("'impl", input.impl_token.span);
+ let mut lifetimes = CollectLifetimes::new("'impl");
lifetimes.visit_type_mut(&mut *input.self_ty);
lifetimes.visit_path_mut(&mut input.trait_.as_mut().unwrap().1);
let params = &input.generics.params;
@@ -124,6 +119,7 @@ pub fn expand(input: &mut Item, is_local: bool) {
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,
@@ -163,20 +159,15 @@ fn transform_sig(
has_default: bool,
is_local: bool,
) {
- sig.fn_token.span = sig.asyncness.take().unwrap().span;
+ let default_span = sig.asyncness.take().unwrap().span;
+ sig.fn_token.span = default_span;
- let ret = match &sig.output {
- ReturnType::Default => quote!(()),
- ReturnType::Type(_, ret) => quote!(#ret),
+ let (ret_arrow, ret) = match &sig.output {
+ ReturnType::Default => (Token![->](default_span), quote_spanned!(default_span=> ())),
+ ReturnType::Type(arrow, ret) => (*arrow, quote!(#ret)),
};
- let default_span = sig
- .ident
- .span()
- .join(sig.paren_token.span)
- .unwrap_or_else(|| sig.ident.span());
-
- let mut lifetimes = CollectLifetimes::new("'life", default_span);
+ let mut lifetimes = CollectLifetimes::new("'life");
for arg in sig.inputs.iter_mut() {
match arg {
FnArg::Receiver(arg) => lifetimes.visit_receiver_mut(arg),
@@ -184,31 +175,42 @@ fn transform_sig(
}
}
- for param in sig
- .generics
- .params
- .iter()
- .chain(context.lifetimes(&lifetimes.explicit))
- {
+ for param in &mut sig.generics.params {
match param {
GenericParam::Type(param) => {
- let param = &param.ident;
- let span = param.span();
+ 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: 'async_trait));
+ .push(parse_quote_spanned!(span=> #param_name: 'async_trait + #bounds));
}
GenericParam::Lifetime(param) => {
- let param = &param.lifetime;
- let span = param.span();
+ 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));
+ .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()));
}
@@ -228,37 +230,65 @@ fn transform_sig(
.push(parse_quote_spanned!(default_span=> 'async_trait));
if has_self {
- let bound_span = sig.ident.span();
- let bound = match sig.inputs.iter().next() {
+ let bounds: &[InferredBound] = match sig.inputs.iter().next() {
Some(FnArg::Receiver(Receiver {
reference: Some(_),
mutability: None,
..
- })) => Ident::new("Sync", bound_span),
+ })) => &[InferredBound::Sync],
Some(FnArg::Typed(arg))
- if match (arg.pat.as_ref(), arg.ty.as_ref()) {
- (Pat::Ident(pat), Type::Reference(ty)) => {
- pat.ident == "self" && ty.mutability.is_none()
- }
+ if match arg.pat.as_ref() {
+ Pat::Ident(pat) => pat.ident == "self",
_ => false,
} =>
{
- Ident::new("Sync", bound_span)
+ 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],
+ }
}
- _ => Ident::new("Send", bound_span),
- };
-
- let assume_bound = match context {
- Context::Trait { supertraits, .. } => !has_default || has_bound(supertraits, &bound),
- Context::Impl { .. } => true,
+ _ => &[InferredBound::Send],
};
- let where_clause = where_clause_or_default(&mut sig.generics.where_clause);
- where_clause.predicates.push(if assume_bound || is_local {
- parse_quote_spanned!(bound_span=> Self: 'async_trait)
- } else {
- parse_quote_spanned!(bound_span=> Self: ::core::marker::#bound + 'async_trait)
+ 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() {
@@ -268,26 +298,32 @@ fn transform_sig(
}) => {}
FnArg::Receiver(arg) => arg.mutability = None,
FnArg::Typed(arg) => {
- if let Pat::Ident(ident) = &mut *arg.pat {
- ident.by_ref = None;
- ident.mutability = None;
- } else {
+ 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 ret_span = sig.ident.span();
let bounds = if is_local {
- quote_spanned!(ret_span=> 'async_trait)
+ quote_spanned!(default_span=> 'async_trait)
} else {
- quote_spanned!(ret_span=> ::core::marker::Send + 'async_trait)
+ quote_spanned!(default_span=> ::core::marker::Send + 'async_trait)
};
- sig.output = parse_quote_spanned! {ret_span=>
- -> ::core::pin::Pin<Box<
+ sig.output = parse_quote_spanned! {default_span=>
+ #ret_arrow ::core::pin::Pin<Box<
dyn ::core::future::Future<Output = #ret> + #bounds
>>
};
@@ -333,6 +369,12 @@ fn transform_block(context: Context, sig: &mut Signature, block: &mut Block) {
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
@@ -341,13 +383,33 @@ fn transform_block(context: Context, sig: &mut Signature, block: &mut Block) {
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!(let #mutability #ident = #ident;)
+ 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);
- quote!(let #pat = #ident;)
+ if let Pat::Wild(_) = **pat {
+ quote! {
+ #(#attrs)*
+ let #ident = #ident;
+ }
+ } else {
+ quote! {
+ #(#attrs)*
+ let #pat = {
+ let #ident = #ident;
+ #ident
+ };
+ }
+ }
}
}
})
@@ -391,25 +453,10 @@ fn transform_block(context: Context, sig: &mut Signature, block: &mut Block) {
}
fn positional_arg(i: usize, pat: &Pat) -> Ident {
- use syn::spanned::Spanned;
- format_ident!("__arg{}", i, span = pat.span())
-}
-
-fn has_bound(supertraits: &Supertraits, marker: &Ident) -> bool {
- for bound in supertraits {
- if let TypeParamBound::Trait(bound) = bound {
- if bound.path.is_ident(marker)
- || bound.path.segments.len() == 3
- && (bound.path.segments[0].ident == "std"
- || bound.path.segments[0].ident == "core")
- && bound.path.segments[1].ident == "marker"
- && bound.path.segments[2].ident == *marker
- {
- return true;
- }
- }
- }
- false
+ 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 {
diff --git a/src/lib.rs b/src/lib.rs
index 3ae002a..8ca5032 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,7 +2,7 @@
//!
//! [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&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K
+//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
//!
//! <br>
//!
@@ -306,6 +306,7 @@
#![allow(
clippy::default_trait_access,
clippy::doc_markdown,
+ clippy::explicit_auto_deref,
clippy::if_not_else,
clippy::items_after_statements,
clippy::module_name_repetitions,
@@ -317,6 +318,7 @@
extern crate proc_macro;
mod args;
+mod bound;
mod expand;
mod lifetime;
mod parse;
diff --git a/src/lifetime.rs b/src/lifetime.rs
index ff25d32..86eac24 100644
--- a/src/lifetime.rs
+++ b/src/lifetime.rs
@@ -1,27 +1,29 @@
-use proc_macro2::Span;
+use proc_macro2::{Span, TokenStream};
+use std::mem;
use syn::visit_mut::{self, VisitMut};
-use syn::{GenericArgument, Lifetime, Receiver, TypeReference};
+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>,
pub name: &'static str,
- pub default_span: Span,
}
impl CollectLifetimes {
- pub fn new(name: &'static str, default_span: Span) -> Self {
+ pub fn new(name: &'static str) -> Self {
CollectLifetimes {
elided: Vec::new(),
explicit: Vec::new(),
name,
- default_span,
}
}
- fn visit_opt_lifetime(&mut self, lifetime: &mut Option<Lifetime>) {
+ fn visit_opt_lifetime(&mut self, reference: Token![&], lifetime: &mut Option<Lifetime>) {
match lifetime {
- None => *lifetime = Some(self.next_lifetime(None)),
+ None => *lifetime = Some(self.next_lifetime(reference.span)),
Some(lifetime) => self.visit_lifetime(lifetime),
}
}
@@ -34,9 +36,8 @@ impl CollectLifetimes {
}
}
- fn next_lifetime<S: Into<Option<Span>>>(&mut self, span: S) -> Lifetime {
+ fn next_lifetime(&mut self, span: Span) -> Lifetime {
let name = format!("{}{}", self.name, self.elided.len());
- let span = span.into().unwrap_or(self.default_span);
let life = Lifetime::new(&name, span);
self.elided.push(life.clone());
life
@@ -45,13 +46,13 @@ impl CollectLifetimes {
impl VisitMut for CollectLifetimes {
fn visit_receiver_mut(&mut self, arg: &mut Receiver) {
- if let Some((_, lifetime)) = &mut arg.reference {
- self.visit_opt_lifetime(lifetime);
+ 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(&mut ty.lifetime);
+ self.visit_opt_lifetime(ty.and_token, &mut ty.lifetime);
visit_mut::visit_type_reference_mut(self, ty);
}
@@ -62,3 +63,50 @@ impl VisitMut for CollectLifetimes {
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/tests/compiletest.rs b/tests/compiletest.rs
index f9aea23..7974a62 100644
--- a/tests/compiletest.rs
+++ b/tests/compiletest.rs
@@ -1,4 +1,5 @@
#[rustversion::attr(not(nightly), ignore)]
+#[cfg_attr(miri, ignore)]
#[test]
fn ui() {
let t = trybuild::TestCases::new();
diff --git a/tests/test.rs b/tests/test.rs
index 2bca1fc..458904e 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -2,8 +2,8 @@
async_trait_nightly_testing,
feature(min_specialization, type_alias_impl_trait)
)]
+#![deny(rust_2021_compatibility)]
#![allow(
- clippy::let_underscore_drop,
clippy::let_unit_value,
clippy::missing_panics_doc,
clippy::missing_safety_doc,
@@ -618,6 +618,7 @@ pub mod issue45 {
}
#[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.
@@ -913,7 +914,7 @@ pub mod issue92 {
const ASSOCIATED2: &'static str;
type Associated2;
- #[allow(path_statements, clippy::no_effect)]
+ #[allow(path_statements, clippy::let_underscore_future, clippy::no_effect)]
async fn associated2(&self) {
// trait items
mac!(let _: Self::Associated2;);
@@ -936,7 +937,7 @@ pub mod issue92 {
const ASSOCIATED2: &'static str = "2";
type Associated2 = ();
- #[allow(path_statements, clippy::no_effect)]
+ #[allow(path_statements, clippy::let_underscore_future, clippy::no_effect)]
async fn associated2(&self) {
// inherent items
mac!(Self::ASSOCIATED1;);
@@ -1038,9 +1039,9 @@ pub mod issue106 {
}
#[async_trait]
- impl<P: ?Sized> ProcessPool for &P
+ impl<P> ProcessPool for &P
where
- P: ProcessPool,
+ P: ?Sized + ProcessPool,
{
type ThreadPool = P::ThreadPool;
@@ -1056,8 +1057,6 @@ pub mod issue106 {
// https://github.com/dtolnay/async-trait/issues/110
pub mod issue110 {
- #![deny(clippy::all)]
-
use async_trait::async_trait;
use std::marker::PhantomData;
@@ -1113,8 +1112,6 @@ pub mod issue123 {
// https://github.com/dtolnay/async-trait/issues/129
pub mod issue129 {
- #![deny(clippy::pedantic)]
-
use async_trait::async_trait;
#[async_trait]
@@ -1378,6 +1375,23 @@ pub mod issue169 {
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)]
@@ -1389,3 +1403,184 @@ pub mod issue183 {
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(())
+ }
+ }
+}
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.stderr b/tests/ui/bare-trait-object.stderr
index 6670c48..50b2048 100644
--- a/tests/ui/bare-trait-object.stderr
+++ b/tests/ui/bare-trait-object.stderr
@@ -2,12 +2,20 @@ error: trait objects without an explicit `dyn` are deprecated
--> tests/ui/bare-trait-object.rs:11:16
|
11 | impl Trait for Send + Sync {
- | ^^^^^^^^^^^ help: use `dyn`: `dyn 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)]
| ^^^^^^^^^^^^^^^^^^
- = 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>
+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
index d3f67a1..51a44a2 100644
--- a/tests/ui/delimiter-span.rs
+++ b/tests/ui/delimiter-span.rs
@@ -1,3 +1,5 @@
+#![allow(unused_macro_rules)]
+
use async_trait::async_trait;
macro_rules! picky {
diff --git a/tests/ui/delimiter-span.stderr b/tests/ui/delimiter-span.stderr
index a13985d..f03da4c 100644
--- a/tests/ui/delimiter-span.stderr
+++ b/tests/ui/delimiter-span.stderr
@@ -1,17 +1,21 @@
error: no rules expected the token `{`
- --> tests/ui/delimiter-span.rs:17:16
+ --> tests/ui/delimiter-span.rs:19:16
|
-3 | macro_rules! picky {
+5 | macro_rules! picky {
| ------------------ when calling this macro
...
-17 | picky!({ 123, self });
+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:18:16
+ --> tests/ui/delimiter-span.rs:20:16
|
-3 | macro_rules! picky {
+5 | macro_rules! picky {
| ------------------ when calling this macro
...
-18 | picky!({ 123 });
+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
index 4e9e5d9..01981e6 100644
--- a/tests/ui/lifetime-span.rs
+++ b/tests/ui/lifetime-span.rs
@@ -10,12 +10,12 @@ pub trait Trait<'r> {
#[async_trait]
impl Trait for A {
- async fn method(&self) { }
+ async fn method(&self) {}
}
#[async_trait]
impl<'r> Trait<'r> for B {
- async fn method(&self) { }
+ async fn method(&self) {}
}
#[async_trait]
@@ -25,12 +25,12 @@ pub trait Trait2 {
#[async_trait]
impl Trait2 for A {
- async fn method(&self) { }
+ async fn method(&self) {}
}
#[async_trait]
impl<'r> Trait2<'r> for B {
- async fn method(&'r self) { }
+ async fn method(&'r self) {}
}
fn main() {}
diff --git a/tests/ui/lifetime-span.stderr b/tests/ui/lifetime-span.stderr
index aad25a7..999da04 100644
--- a/tests/ui/lifetime-span.stderr
+++ b/tests/ui/lifetime-span.stderr
@@ -2,9 +2,13 @@ error[E0726]: implicit elided lifetime not allowed here
--> tests/ui/lifetime-span.rs:12:6
|
12 | impl Trait for A {
- | ^^^^^- help: indicate the anonymous lifetime: `<'_>`
+ | ^^^^^ expected lifetime parameter
|
= note: assuming a `'static` lifetime...
+help: indicate the anonymous lifetime
+ |
+12 | impl Trait<'_> for A {
+ | ++++
error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
--> tests/ui/lifetime-span.rs:32:10
@@ -19,30 +23,3 @@ note: trait defined here, with 0 lifetime parameters
|
22 | pub trait Trait2 {
| ^^^^^^
-
-error[E0195]: lifetime parameters or bounds on method `method` do not match the trait declaration
- --> tests/ui/lifetime-span.rs:13:14
- |
-8 | async fn method(&'r self);
- | ---------------- lifetimes in impl do not match this method in trait
-...
-13 | async fn method(&self) { }
- | ^^^^^^^^^^^^^ lifetimes do not match method in trait
-
-error[E0195]: lifetime parameters or bounds on method `method` do not match the trait declaration
- --> tests/ui/lifetime-span.rs:18:14
- |
-8 | async fn method(&'r self);
- | ---------------- lifetimes in impl do not match this method in trait
-...
-18 | async fn method(&self) { }
- | ^^^^^^^^^^^^^ lifetimes do not match method in trait
-
-error[E0195]: lifetime parameters or bounds on method `method` do not match the trait declaration
- --> tests/ui/lifetime-span.rs:33:14
- |
-23 | async fn method<'r>(&'r self);
- | ---- lifetimes in impl do not match this method in trait
-...
-33 | async fn method(&'r self) { }
- | ^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
diff --git a/tests/ui/must-use.stderr b/tests/ui/must-use.stderr
index 1b97055..fd6fc31 100644
--- a/tests/ui/must-use.stderr
+++ b/tests/ui/must-use.stderr
@@ -2,7 +2,7 @@ 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
diff --git a/tests/ui/self-span.stderr b/tests/ui/self-span.stderr
index 2690791..8743e57 100644
--- a/tests/ui/self-span.stderr
+++ b/tests/ui/self-span.stderr
@@ -20,8 +20,8 @@ error[E0308]: mismatched types
| |
| expected due to this
-error[E0533]: expected unit struct, unit variant or constant, found struct variant `Self::V`
+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.stderr b/tests/ui/send-not-implemented.stderr
index 8004de6..d68fc43 100644
--- a/tests/ui/send-not-implemented.stderr
+++ b/tests/ui/send-not-implemented.stderr
@@ -9,17 +9,17 @@ error: future cannot be sent between threads safely
12 | | }
| |_____^ future created by async block is not `Send`
|
- = help: within `impl Future<Output = [async output]>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
+ = 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:9
+ --> 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
+ | ^^^^^^ await occurs here, with `_guard` maybe used later
12 | }
| - `_guard` is later dropped here
- = note: required for the cast to the object type `dyn Future<Output = ()> + Send`
+ = 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
@@ -33,15 +33,15 @@ error: future cannot be sent between threads safely
19 | | }
| |_____^ future created by async block is not `Send`
|
- = help: within `impl Future<Output = [async output]>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
+ = 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:9
+ --> 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
+ | ^^^^^^ await occurs here, with `_guard` maybe used later
18 | true
19 | }
| - `_guard` is later dropped here
- = note: required for the cast to the object type `dyn Future<Output = bool> + Send`
+ = 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`