Skip to content

Commit

Permalink
Merge pull request #230 from dtolnay/definedhere
Browse files Browse the repository at this point in the history
Improve spans of named lifetimes generated from elided lifetimes
  • Loading branch information
dtolnay committed Jan 20, 2023
2 parents f013652 + b4c19da commit 861b6bc
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 13 deletions.
4 changes: 2 additions & 2 deletions src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ pub fn expand(input: &mut Item, is_local: bool) {
}
}
Item::Impl(input) => {
let mut lifetimes = CollectLifetimes::new("'impl", input.impl_token.span);
let mut lifetimes = CollectLifetimes::new("'impl");
lifetimes.visit_type_mut(&mut *input.self_ty);
lifetimes.visit_path_mut(&mut input.trait_.as_mut().unwrap().1);
let params = &input.generics.params;
Expand Down Expand Up @@ -166,7 +166,7 @@ fn transform_sig(
ReturnType::Type(arrow, ret) => (*arrow, quote!(#ret)),
};

let mut lifetimes = CollectLifetimes::new("'life", default_span);
let mut lifetimes = CollectLifetimes::new("'life");
for arg in sig.inputs.iter_mut() {
match arg {
FnArg::Receiver(arg) => lifetimes.visit_receiver_mut(arg),
Expand Down
19 changes: 8 additions & 11 deletions src/lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,28 @@ use proc_macro2::{Span, TokenStream};
use std::mem;
use syn::visit_mut::{self, VisitMut};
use syn::{
parse_quote_spanned, token, Expr, GenericArgument, Lifetime, Receiver, ReturnType, Type,
parse_quote_spanned, token, Expr, GenericArgument, Lifetime, Receiver, ReturnType, Token, Type,
TypeBareFn, TypeImplTrait, TypeParen, TypePtr, TypeReference,
};

pub struct CollectLifetimes {
pub elided: Vec<Lifetime>,
pub explicit: Vec<Lifetime>,
pub name: &'static str,
pub default_span: Span,
}

impl CollectLifetimes {
pub fn new(name: &'static str, default_span: Span) -> Self {
pub fn new(name: &'static str) -> Self {
CollectLifetimes {
elided: Vec::new(),
explicit: Vec::new(),
name,
default_span,
}
}

fn visit_opt_lifetime(&mut self, lifetime: &mut Option<Lifetime>) {
fn visit_opt_lifetime(&mut self, reference: Token![&], lifetime: &mut Option<Lifetime>) {
match lifetime {
None => *lifetime = Some(self.next_lifetime(None)),
None => *lifetime = Some(self.next_lifetime(reference.span)),
Some(lifetime) => self.visit_lifetime(lifetime),
}
}
Expand All @@ -38,9 +36,8 @@ impl CollectLifetimes {
}
}

fn next_lifetime<S: Into<Option<Span>>>(&mut self, span: S) -> Lifetime {
fn next_lifetime(&mut self, span: Span) -> Lifetime {
let name = format!("{}{}", self.name, self.elided.len());
let span = span.into().unwrap_or(self.default_span);
let life = Lifetime::new(&name, span);
self.elided.push(life.clone());
life
Expand All @@ -49,13 +46,13 @@ impl CollectLifetimes {

impl VisitMut for CollectLifetimes {
fn visit_receiver_mut(&mut self, arg: &mut Receiver) {
if let Some((_, lifetime)) = &mut arg.reference {
self.visit_opt_lifetime(lifetime);
if let Some((reference, lifetime)) = &mut arg.reference {
self.visit_opt_lifetime(*reference, lifetime);
}
}

fn visit_type_reference_mut(&mut self, ty: &mut TypeReference) {
self.visit_opt_lifetime(&mut ty.lifetime);
self.visit_opt_lifetime(ty.and_token, &mut ty.lifetime);
visit_mut::visit_type_reference_mut(self, ty);
}

Expand Down
23 changes: 23 additions & 0 deletions tests/ui/lifetime-defined-here.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use async_trait::async_trait;

#[async_trait]
trait Foo {
async fn bar(&self, x: &str, y: &'_ str) -> &'static str;
}

struct S(String);

#[async_trait]
impl Foo for S {
async fn bar(&self, x: &str, y: &'_ str) -> &'static str {
if false {
&self.0
} else if false {
x
} else {
y
}
}
}

fn main() {}
29 changes: 29 additions & 0 deletions tests/ui/lifetime-defined-here.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
error: lifetime may not live long enough
--> tests/ui/lifetime-defined-here.rs:12:49
|
12 | async fn bar(&self, x: &str, y: &'_ str) -> &'static str {
| - ^^^^^^^^^^^^ type annotation requires that `'life0` must outlive `'static`
| |
| lifetime `'life0` defined here

error: lifetime may not live long enough
--> tests/ui/lifetime-defined-here.rs:12:49
|
12 | async fn bar(&self, x: &str, y: &'_ str) -> &'static str {
| - ^^^^^^^^^^^^ type annotation requires that `'life1` must outlive `'static`
| |
| lifetime `'life1` defined here

error: lifetime may not live long enough
--> tests/ui/lifetime-defined-here.rs:12:49
|
12 | async fn bar(&self, x: &str, y: &'_ str) -> &'static str {
| -- ^^^^^^^^^^^^ type annotation requires that `'life2` must outlive `'static`
| |
| lifetime `'life2` defined here

help: the following changes may resolve your lifetime errors
|
= help: replace `'life0` with `'static`
= help: replace `'life1` with `'static`
= help: replace `'life2` with `'static`

0 comments on commit 861b6bc

Please sign in to comment.