diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eef1ba6..8fc6f6c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -96,5 +96,6 @@ jobs: timeout-minutes: 45 steps: - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable - uses: dtolnay/install@cargo-outdated - run: cargo outdated --workspace --exit-code 1 diff --git a/Cargo.toml b/Cargo.toml index a1a0339..6a34bdc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-trait" -version = "0.1.77" +version = "0.1.80" authors = ["David Tolnay "] categories = ["asynchronous", "no-std"] description = "Type erasure for async trait methods" diff --git a/build.rs b/build.rs deleted file mode 100644 index db7c5f0..0000000 --- a/build.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::env; -use std::process::Command; -use std::str; - -fn main() { - println!("cargo:rerun-if-env-changed=DOCS_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 { - 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/bound.rs b/src/bound.rs index 50182f6..1210517 100644 --- a/src/bound.rs +++ b/src/bound.rs @@ -1,5 +1,5 @@ use proc_macro2::{Ident, Span, TokenStream}; -use quote::quote_spanned; +use quote::{quote, ToTokens}; use syn::punctuated::Punctuated; use syn::{Token, TypeParamBound}; @@ -34,10 +34,12 @@ impl InferredBound { 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 ToTokens for InferredBound { + fn to_tokens(&self, tokens: &mut TokenStream) { + let ident = Ident::new(self.as_str(), Span::call_site()); + quote!(::core::marker::#ident).to_tokens(tokens); } } diff --git a/src/expand.rs b/src/expand.rs index 2a8b3c2..793e084 100644 --- a/src/expand.rs +++ b/src/expand.rs @@ -166,11 +166,10 @@ fn transform_sig( has_default: bool, is_local: bool, ) { - let default_span = sig.asyncness.take().unwrap().span; - sig.fn_token.span = default_span; + sig.fn_token.span = sig.asyncness.take().unwrap().span; let (ret_arrow, ret) = match &sig.output { - ReturnType::Default => (Token![->](default_span), quote_spanned!(default_span=> ())), + ReturnType::Default => (Token![->](Span::call_site()), quote!(())), ReturnType::Type(arrow, ret) => (*arrow, quote!(#ret)), }; @@ -232,12 +231,12 @@ fn transform_sig( .push(parse_quote_spanned!(elided.span()=> #elided: 'async_trait)); } - sig.generics - .params - .push(parse_quote_spanned!(default_span=> 'async_trait)); + sig.generics.params.push(parse_quote!('async_trait)); if has_self { - let bounds: &[InferredBound] = if let Some(receiver) = sig.receiver() { + let bounds: &[InferredBound] = if is_local { + &[] + } else if let Some(receiver) = sig.receiver() { match receiver.ty.as_ref() { // self: &Self Type::Reference(ty) if ty.mutability.is_none() => &[InferredBound::Sync], @@ -268,21 +267,14 @@ fn transform_sig( &[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)) - } + let bounds = bounds.iter().filter(|bound| match context { + Context::Trait { supertraits, .. } => has_default && !has_bound(supertraits, bound), + Context::Impl { .. } => false, }); where_clause_or_default(&mut sig.generics.where_clause) .predicates - .push(parse_quote_spanned! {default_span=> + .push(parse_quote! { Self: #(#bounds +)* 'async_trait }); } @@ -314,11 +306,11 @@ fn transform_sig( } let bounds = if is_local { - quote_spanned!(default_span=> 'async_trait) + quote!('async_trait) } else { - quote_spanned!(default_span=> ::core::marker::Send + 'async_trait) + quote!(::core::marker::Send + 'async_trait) }; - sig.output = parse_quote_spanned! {default_span=> + sig.output = parse_quote! { #ret_arrow ::core::pin::Pin + #bounds >> @@ -343,7 +335,7 @@ fn transform_sig( // ___ret // }) fn transform_block(context: Context, sig: &mut Signature, block: &mut Block) { - let mut self_span = None; + let mut replace_self = false; let decls = sig .inputs .iter() @@ -354,8 +346,8 @@ fn transform_block(context: Context, sig: &mut Signature, block: &mut Block) { mutability, .. }) => { + replace_self = true; let ident = Ident::new("__self", self_token.span); - self_span = Some(self_token.span); quote!(let #mutability #ident = #self_token;) } FnArg::Typed(arg) => { @@ -397,9 +389,8 @@ fn transform_block(context: Context, sig: &mut Signature, block: &mut Block) { }) .collect::>(); - if let Some(span) = self_span { - let mut replace_self = ReplaceSelf(span); - replace_self.visit_block_mut(block); + if replace_self { + ReplaceSelf.visit_block_mut(block); } let stmts = &block.stmts; @@ -416,8 +407,9 @@ fn transform_block(context: Context, sig: &mut Signature, block: &mut Block) { quote!(#(#decls)* { #(#stmts)* }) } } else { - quote_spanned! {block.brace_token.span=> + quote! { if let ::core::option::Option::Some(__ret) = ::core::option::Option::None::<#ret> { + #[allow(unreachable_code)] return __ret; } #(#decls)* @@ -435,9 +427,7 @@ fn transform_block(context: Context, sig: &mut Signature, block: &mut Block) { } 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()); + let span = syn::spanned::Spanned::span(pat).resolved_at(Span::mixed_site()); format_ident!("__arg{}", i, span = span) } diff --git a/src/lib.rs b/src/lib.rs index 7a48574..cc8b628 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -316,7 +316,7 @@ //! let object = &value as &dyn ObjectSafe; //! ``` -#![doc(html_root_url = "https://docs.rs/async-trait/0.1.77")] +#![doc(html_root_url = "https://docs.rs/async-trait/0.1.80")] #![allow( clippy::default_trait_access, clippy::doc_markdown, diff --git a/src/receiver.rs b/src/receiver.rs index f5791bf..e4627f1 100644 --- a/src/receiver.rs +++ b/src/receiver.rs @@ -1,4 +1,4 @@ -use proc_macro2::{Group, Span, TokenStream, TokenTree}; +use proc_macro2::{Group, TokenStream, TokenTree}; use syn::visit_mut::{self, VisitMut}; use syn::{ Block, ExprPath, Ident, Item, Macro, Pat, PatIdent, Path, Receiver, Signature, Token, TypePath, @@ -78,20 +78,17 @@ impl VisitMut for HasSelf { } } -pub struct ReplaceSelf(pub Span); +pub struct ReplaceSelf; -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 prepend_underscore_to_self(ident: &mut Ident) -> bool { + let modified = ident == "self"; + if modified { + *ident = Ident::new("__self", ident.span()); } + modified +} +impl ReplaceSelf { fn visit_token_stream(&mut self, tokens: &mut TokenStream) -> bool { let mut out = Vec::new(); let mut modified = false; @@ -110,7 +107,7 @@ impl ReplaceSelf { for tt in tokens { match tt { TokenTree::Ident(mut ident) => { - *modified |= visitor.prepend_underscore_to_self(&mut ident); + *modified |= prepend_underscore_to_self(&mut ident); out.push(TokenTree::Ident(ident)); } TokenTree::Group(group) => { @@ -129,7 +126,7 @@ impl ReplaceSelf { impl VisitMut for ReplaceSelf { fn visit_ident_mut(&mut self, i: &mut Ident) { - self.prepend_underscore_to_self(i); + prepend_underscore_to_self(i); } fn visit_path_mut(&mut self, p: &mut Path) { diff --git a/tests/test.rs b/tests/test.rs index b78c9ff..a42b225 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,9 +1,10 @@ #![cfg_attr( async_trait_nightly_testing, - feature(impl_trait_in_assoc_type, min_specialization) + feature(impl_trait_in_assoc_type, min_specialization, never_type) )] -#![deny(rust_2021_compatibility)] +#![deny(rust_2021_compatibility, unused_qualifications)] #![allow( + clippy::incompatible_msrv, // https://github.com/rust-lang/rust-clippy/issues/12257 clippy::let_underscore_untyped, clippy::let_unit_value, clippy::missing_panics_doc, @@ -157,9 +158,11 @@ pub unsafe trait UnsafeTrait {} unsafe impl UnsafeTrait for () {} #[async_trait] +#[allow(dead_code)] pub(crate) unsafe trait UnsafeTraitPubCrate {} #[async_trait] +#[allow(dead_code)] unsafe trait UnsafeTraitPrivate {} pub async fn test_can_destruct() { @@ -177,6 +180,8 @@ pub async fn test_can_destruct() { let _d: u8 = d; } } + + let _ = ::f; } pub async fn test_self_in_macro() { @@ -199,6 +204,10 @@ pub async fn test_self_in_macro() { println!("{}", self); } } + + let _ = ::a; + let _ = ::b; + let _ = ::c; } pub async fn test_inference() { @@ -208,6 +217,10 @@ pub async fn test_inference() { Box::new(std::iter::empty()) } } + + impl Trait for () {} + + let _ = <() as Trait>::f; } pub async fn test_internal_items() { @@ -233,6 +246,10 @@ pub async fn test_unimplemented() { unimplemented!() } } + + impl Trait for () {} + + let _ = <() as Trait>::f; } // https://github.com/dtolnay/async-trait/issues/1 @@ -240,7 +257,7 @@ pub mod issue1 { use async_trait::async_trait; #[async_trait] - trait Issue1 { + pub trait Issue1 { async fn f(&self); } @@ -284,11 +301,11 @@ pub mod issue11 { use std::sync::Arc; #[async_trait] - trait Issue11 { + pub trait Issue11 { async fn example(self: Arc); } - struct Struct; + pub struct Struct; #[async_trait] impl Issue11 for Struct { @@ -301,10 +318,10 @@ pub mod issue15 { use async_trait::async_trait; use std::marker::PhantomData; - trait Trait {} + pub trait Trait {} #[async_trait] - trait Issue15 { + pub trait Issue15 { async fn myfn(&self, _: PhantomData) {} } } @@ -314,11 +331,11 @@ pub mod issue17 { use async_trait::async_trait; #[async_trait] - trait Issue17 { + pub trait Issue17 { async fn f(&self); } - struct Struct { + pub struct Struct { string: String, } @@ -346,6 +363,7 @@ pub mod issue23 { } } + #[allow(dead_code)] struct S {} #[async_trait] @@ -409,10 +427,10 @@ pub mod issue25 { pub mod issue28 { use async_trait::async_trait; - struct Str<'a>(&'a str); + pub struct Str<'a>(&'a str); #[async_trait] - trait Trait1<'a> { + pub trait Trait1<'a> { async fn f(x: Str<'a>) -> &'a str; async fn g(x: Str<'a>) -> &'a str { x.0 @@ -427,7 +445,7 @@ pub mod issue28 { } #[async_trait] - trait Trait2 { + pub trait Trait2 { async fn f(); } @@ -437,7 +455,7 @@ pub mod issue28 { } #[async_trait] - trait Trait3<'a, 'b> { + pub 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 @@ -675,7 +693,7 @@ pub mod issue53 { use async_trait::async_trait; pub struct Unit; - pub struct Tuple(u8); + pub struct Tuple(pub u8); pub struct Struct { pub x: u8, } @@ -715,7 +733,6 @@ pub mod issue53 { } // https://github.com/dtolnay/async-trait/issues/57 -#[cfg(async_trait_nightly_testing)] pub mod issue57 { use crate::executor; use async_trait::async_trait; @@ -867,7 +884,7 @@ pub mod issue89 { use async_trait::async_trait; #[async_trait] - trait Trait { + pub trait Trait { async fn f(&self); } @@ -1003,7 +1020,7 @@ pub mod issue104 { use async_trait::async_trait; #[async_trait] - trait T1 { + pub trait T1 { async fn id(&self) -> i32; } @@ -1018,7 +1035,7 @@ pub mod issue104 { }; } - struct Foo; + pub struct Foo; impl_t1!(Foo, 1); } @@ -1082,7 +1099,7 @@ pub mod issue120 { use async_trait::async_trait; #[async_trait] - trait Trait { + pub trait Trait { async fn f(&self); } @@ -1097,7 +1114,7 @@ pub mod issue123 { use async_trait::async_trait; #[async_trait] - trait Trait { + pub trait Trait { async fn f(&self) -> &str where T: 'async_trait, @@ -1132,12 +1149,11 @@ pub mod issue129 { } // 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 { + pub trait TestTrait { async fn run(self) where Self: Sized, @@ -1284,13 +1300,13 @@ pub mod issue152 { use async_trait::async_trait; #[async_trait] - trait Trait { + pub trait Trait { type Assoc; async fn f(&self) -> Self::Assoc; } - struct Struct; + pub struct Struct; #[async_trait] impl Trait for Struct { @@ -1329,6 +1345,7 @@ pub mod issue158 { fn f() {} #[async_trait] + #[allow(unused_qualifications)] pub trait Trait { async fn f(&self) { self::f(); @@ -1368,6 +1385,7 @@ pub mod issue169 { use async_trait::async_trait; #[async_trait] + #[allow(unused_qualifications)] pub trait Trait: ::core::marker::Sync { async fn f(&self) {} } @@ -1399,7 +1417,7 @@ pub mod issue183 { use async_trait::async_trait; #[async_trait] - trait Foo { + pub trait Foo { async fn foo(_n: i32) {} } } @@ -1474,6 +1492,7 @@ pub mod issue226 { async fn cfg_param_tuple(&self, (left, right): (u8, u8)); } + #[allow(dead_code)] struct Struct; #[async_trait] @@ -1603,3 +1622,23 @@ pub mod issue238 { async fn f() {} } } + +// https://github.com/dtolnay/async-trait/issues/266 +#[cfg(async_trait_nightly_testing)] +pub mod issue266 { + use async_trait::async_trait; + + #[async_trait] + pub trait Trait { + async fn f() -> !; + } + + #[async_trait] + impl Trait for () { + async fn f() -> ! { + loop { + std::thread::sleep(std::time::Duration::from_millis(1)); + } + } + } +} diff --git a/tests/ui/lifetime-span.stderr b/tests/ui/lifetime-span.stderr index fa16ac7..aa7d57e 100644 --- a/tests/ui/lifetime-span.stderr +++ b/tests/ui/lifetime-span.stderr @@ -9,6 +9,15 @@ help: indicate the anonymous lifetime 12 | impl Trait<'_> for A { | ++++ +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[E0107]: trait takes 0 lifetime arguments but 1 lifetime argument was supplied --> tests/ui/lifetime-span.rs:32:10 | @@ -22,3 +31,12 @@ 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: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/send-not-implemented.stderr b/tests/ui/send-not-implemented.stderr index 7152b98..5171b7c 100644 --- a/tests/ui/send-not-implemented.stderr +++ b/tests/ui/send-not-implemented.stderr @@ -9,7 +9,7 @@ error: future cannot be sent between threads safely 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<'_, ()>` + = help: within `{async block@$DIR/tests/ui/send-not-implemented.rs:8:26: 12:6}`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`, which is required by `{async block@$DIR/tests/ui/send-not-implemented.rs:8:26: 12:6}: Send` note: future is not `Send` as this value is used across an await --> tests/ui/send-not-implemented.rs:11:13 | @@ -31,7 +31,7 @@ error: future cannot be sent between threads safely 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<'_, ()>` + = help: within `{async block@$DIR/tests/ui/send-not-implemented.rs:14:38: 19:6}`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`, which is required by `{async block@$DIR/tests/ui/send-not-implemented.rs:14:38: 19:6}: Send` note: future is not `Send` as this value is used across an await --> tests/ui/send-not-implemented.rs:17:13 | pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy