diff --git a/src/expand.rs b/src/expand.rs index fe3f530..bb65381 100644 --- a/src/expand.rs +++ b/src/expand.rs @@ -5,6 +5,7 @@ use proc_macro2::TokenStream; use quote::{format_ident, quote, quote_spanned, ToTokens}; use std::collections::BTreeSet as Set; use syn::punctuated::Punctuated; +use syn::spanned::Spanned; use syn::visit_mut::{self, VisitMut}; use syn::{ parse_quote, parse_quote_spanned, Attribute, Block, FnArg, GenericParam, Generics, Ident, @@ -186,18 +187,30 @@ fn transform_sig( { match param { GenericParam::Type(param) => { + let span = if param.bounds.is_empty() { + // This should use `Span::def_site()`, but that's not stable. + param.ident.span() + } else { + param.bounds.span() + }; let param = ¶m.ident; - let span = param.span(); + let life = quote_spanned!(span=> : 'async_trait); where_clause_or_default(&mut sig.generics.where_clause) .predicates - .push(parse_quote_spanned!(span=> #param: 'async_trait)); + .push(parse_quote!(#param #life)); } GenericParam::Lifetime(param) => { + let span = if param.bounds.is_empty() { + // This should use `Span::def_site()`, but that's not stable. + param.lifetime.span() + } else { + param.bounds.span() + }; let param = ¶m.lifetime; - let span = param.span(); + let life = quote_spanned!(span=> : 'async_trait); where_clause_or_default(&mut sig.generics.where_clause) .predicates - .push(parse_quote_spanned!(span=> #param: 'async_trait)); + .push(parse_quote!(#param #life)); } GenericParam::Const(_) => {} } @@ -385,7 +398,6 @@ 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()) } diff --git a/tests/ui/issue-93828.rs b/tests/ui/issue-93828.rs new file mode 100644 index 0000000..4348652 --- /dev/null +++ b/tests/ui/issue-93828.rs @@ -0,0 +1,31 @@ +use async_trait::async_trait; + +struct Client; +struct Client2; +trait IntoUrl {} + +#[async_trait] +pub trait ClientExt { + async fn publish(&self, url: T) -> String; +} + +// https://github.com/rust-lang/rust/issues/93828 +#[async_trait] +impl ClientExt for Client { + async fn publish(&self, url: T) -> String { + "Foo".to_string() + } +} + +// Variant test case with no bounds at all. +// This doesn't actually work correctly yet. It ought to insert the colon, +// but getting it to do that would require a way to tell rustc that the bounds +// don't actually exist in the source code, and it needs to insert them. +#[async_trait] +impl ClientExt for Client2 { + async fn publish(&self, url: T) -> String { + "Foo".to_string() + } +} + +fn main() {} diff --git a/tests/ui/issue-93828.stderr b/tests/ui/issue-93828.stderr new file mode 100644 index 0000000..6cb607b --- /dev/null +++ b/tests/ui/issue-93828.stderr @@ -0,0 +1,39 @@ +error: future cannot be sent between threads safely + --> tests/ui/issue-93828.rs:15:59 + | +15 | async fn publish(&self, url: T) -> String { + | ___________________________________________________________^ +16 | | "Foo".to_string() +17 | | } + | |_____^ future created by async block is not `Send` + | +note: captured value is not `Send` + --> tests/ui/issue-93828.rs:15:41 + | +15 | async fn publish(&self, url: T) -> String { + | ^^^ has type `T` which is not `Send` + = note: required for the cast to the object type `dyn Future + Send` +help: consider further restricting this bound + | +15 | async fn publish(&self, url: T) -> String { + | +++++++++++++++++++ + +error: future cannot be sent between threads safely + --> tests/ui/issue-93828.rs:26:50 + | +26 | async fn publish(&self, url: T) -> String { + | __________________________________________________^ +27 | | "Foo".to_string() +28 | | } + | |_____^ future created by async block is not `Send` + | +note: captured value is not `Send` + --> tests/ui/issue-93828.rs:26:32 + | +26 | async fn publish(&self, url: T) -> String { + | ^^^ has type `T` which is not `Send` + = note: required for the cast to the object type `dyn Future + Send` +help: consider further restricting this bound + | +26 | async fn publish(&self, url: T) -> String { + | +++++++++++++++++++