From 1798a69b3d98897e12aa79785e324919b24b20aa Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Mon, 16 Sep 2019 12:40:32 +0900 Subject: [PATCH] Only chain the traits that are actually used --- src/expand.rs | 17 +++++++++++------ src/lifetime.rs | 6 +++++- tests/test.rs | 21 +++++++++++++++++++-- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/expand.rs b/src/expand.rs index 7daf9a1..58a58e8 100644 --- a/src/expand.rs +++ b/src/expand.rs @@ -36,14 +36,14 @@ enum Context<'a> { } impl Context<'_> { - fn lifetimes<'a>(&'a self) -> impl Iterator { + fn lifetimes<'a>(&'a self, used: &'a [Ident]) -> impl Iterator { let generics = match self { Context::Trait { generics, .. } => generics, Context::Impl { impl_generics, .. } => impl_generics, }; - generics.params.iter().filter(|param| { - if let GenericParam::Lifetime(_) = param { - true + generics.params.iter().filter(move |param| { + if let GenericParam::Lifetime(param) = param { + used.contains(¶m.lifetime.ident) } else { false } @@ -135,8 +135,8 @@ fn transform_sig( let lifetime: Lifetime; if !sig.generics.params.is_empty() - || context.lifetimes().count() != 0 || !elided.lifetimes.is_empty() + || !elided.unelided.is_empty() || has_self { lifetime = parse_quote!('async_trait); @@ -147,7 +147,12 @@ fn transform_sig( where_token: Default::default(), predicates: Punctuated::new(), }); - for param in sig.generics.params.iter().chain(context.lifetimes()) { + for param in sig + .generics + .params + .iter() + .chain(context.lifetimes(&elided.unelided)) + { match param { GenericParam::Type(param) => { let param = ¶m.ident; diff --git a/src/lifetime.rs b/src/lifetime.rs index b11cec0..aa44762 100644 --- a/src/lifetime.rs +++ b/src/lifetime.rs @@ -1,6 +1,6 @@ use proc_macro2::Span; use syn::visit_mut::{self, VisitMut}; -use syn::{Block, GenericArgument, Item, Lifetime, Receiver, Signature, TypeReference}; +use syn::{Block, GenericArgument, Ident, Item, Lifetime, Receiver, Signature, TypeReference}; pub fn has_async_lifetime(sig: &mut Signature, block: &mut Block) -> bool { let mut visitor = HasAsyncLifetime(false); @@ -23,12 +23,14 @@ impl VisitMut for HasAsyncLifetime { pub struct CollectLifetimes { pub lifetimes: Vec, + pub unelided: Vec, } impl CollectLifetimes { pub fn new() -> Self { CollectLifetimes { lifetimes: Vec::new(), + unelided: Vec::new(), } } @@ -42,6 +44,8 @@ impl CollectLifetimes { fn visit_lifetime(&mut self, lifetime: &mut Lifetime) { if lifetime.ident == "_" { *lifetime = self.next_lifetime(); + } else { + self.unelided.push(lifetime.ident.clone()); } } diff --git a/tests/test.rs b/tests/test.rs index f6f08d2..18a9c5a 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -313,7 +313,7 @@ mod issue28 { struct Struct {} #[async_trait] - trait Lifetime<'a> { + trait Trait1<'a> { async fn f(x: Str<'a>) -> &'a str; async fn g(x: Str<'a>) -> &'a str { x.0 @@ -321,9 +321,26 @@ mod issue28 { } #[async_trait] - impl<'a> Lifetime<'a> for Struct { + impl<'a> Trait1<'a> for Struct { 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 + } }