From cbf96694f734e93b5fd2c34444da82cfa7d67317 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 24 Mar 2022 22:15:19 -0700 Subject: [PATCH 1/2] Split context lifetimes from sig params loop --- src/expand.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/expand.rs b/src/expand.rs index fe3f530..85c39c6 100644 --- a/src/expand.rs +++ b/src/expand.rs @@ -8,8 +8,8 @@ use syn::punctuated::Punctuated; use syn::visit_mut::{self, VisitMut}; use syn::{ parse_quote, parse_quote_spanned, Attribute, Block, FnArg, GenericParam, Generics, Ident, - ImplItem, Lifetime, Pat, PatIdent, Receiver, ReturnType, Signature, Stmt, Token, TraitItem, - Type, TypeParamBound, TypePath, WhereClause, + ImplItem, Lifetime, LifetimeDef, Pat, PatIdent, Receiver, ReturnType, Signature, Stmt, Token, + TraitItem, Type, TypeParamBound, TypePath, WhereClause, }; impl ToTokens for Item { @@ -34,17 +34,18 @@ enum Context<'a> { } impl Context<'_> { - fn lifetimes<'a>(&'a self, used: &'a [Lifetime]) -> impl Iterator { + fn lifetimes<'a>(&'a self, used: &'a [Lifetime]) -> impl Iterator { 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(¶m.lifetime) - } else { - false + if used.contains(¶m.lifetime) { + return Some(param); + } } + None }) } } @@ -178,12 +179,7 @@ fn transform_sig( } } - for param in sig - .generics - .params - .iter() - .chain(context.lifetimes(&lifetimes.explicit)) - { + for param in &sig.generics.params { match param { GenericParam::Type(param) => { let param = ¶m.ident; @@ -203,6 +199,14 @@ fn transform_sig( } } + for param in context.lifetimes(&lifetimes.explicit) { + let param = ¶m.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())); } From 46c30234e341c400318f5c68c1f04e0e505b3665 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 24 Mar 2022 22:23:32 -0700 Subject: [PATCH 2/2] Move bounds from generic param list to where-clause after 'async_trait bound --- src/expand.rs | 23 ++++++++++++++++------- tests/ui/consider-restricting.stderr | 4 ++-- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/expand.rs b/src/expand.rs index 85c39c6..ed0818e 100644 --- a/src/expand.rs +++ b/src/expand.rs @@ -4,6 +4,7 @@ use crate::receiver::{has_self_in_block, has_self_in_sig, mut_pat, ReplaceSelf}; use proc_macro2::TokenStream; use quote::{format_ident, quote, quote_spanned, ToTokens}; use std::collections::BTreeSet as Set; +use std::mem; use syn::punctuated::Punctuated; use syn::visit_mut::{self, VisitMut}; use syn::{ @@ -179,21 +180,29 @@ fn transform_sig( } } - for param in &sig.generics.params { + for param in &mut sig.generics.params { match param { GenericParam::Type(param) => { - let param = ¶m.ident; - let span = param.span(); + let param_name = ¶m.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 = ¶m.lifetime; - let span = param.span(); + let param_name = ¶m.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(_) => {} } diff --git a/tests/ui/consider-restricting.stderr b/tests/ui/consider-restricting.stderr index ee14180..86e3894 100644 --- a/tests/ui/consider-restricting.stderr +++ b/tests/ui/consider-restricting.stderr @@ -12,8 +12,8 @@ note: captured value is not `Send` = note: required for the cast to the object type `dyn Future + Send` help: consider further restricting this bound | -16 | async fn publish(&self, url: T) {} - | +++++++++++++++++++ +16 | async fn publish(&self, url: T) {} + | +++++++++++++++++++ error: future cannot be sent between threads safely --> tests/ui/consider-restricting.rs:23:40