Skip to content

Commit

Permalink
Only chain the traits that are actually used
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e committed Sep 16, 2019
1 parent 513315d commit 1798a69
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 9 deletions.
17 changes: 11 additions & 6 deletions src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ enum Context<'a> {
}

impl Context<'_> {
fn lifetimes<'a>(&'a self) -> impl Iterator<Item = &'a GenericParam> {
fn lifetimes<'a>(&'a self, used: &'a [Ident]) -> impl Iterator<Item = &'a GenericParam> {
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(&param.lifetime.ident)
} else {
false
}
Expand Down Expand Up @@ -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);
Expand All @@ -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 = &param.ident;
Expand Down
6 changes: 5 additions & 1 deletion src/lifetime.rs
Original file line number Diff line number Diff line change
@@ -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);
Expand All @@ -23,12 +23,14 @@ impl VisitMut for HasAsyncLifetime {

pub struct CollectLifetimes {
pub lifetimes: Vec<Lifetime>,
pub unelided: Vec<Ident>,
}

impl CollectLifetimes {
pub fn new() -> Self {
CollectLifetimes {
lifetimes: Vec::new(),
unelided: Vec::new(),
}
}

Expand All @@ -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());
}
}

Expand Down
21 changes: 19 additions & 2 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,17 +313,34 @@ 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
}
}

#[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
}
}

0 comments on commit 1798a69

Please sign in to comment.