Skip to content

Commit

Permalink
Merge pull request #116 from dtolnay/lifetime
Browse files Browse the repository at this point in the history
Detect non-static lifetime behind reference type parameter
  • Loading branch information
dtolnay authored Dec 27, 2020
2 parents cb3077c + d30890b commit da6ee81
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 17 deletions.
37 changes: 22 additions & 15 deletions impl/src/valid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ fn check_field_attrs(fields: &[Field]) -> Result<()> {
}
}
if let Some(source_field) = source_field.or(from_field) {
if contains_non_static_lifetime(source_field) {
if contains_non_static_lifetime(&source_field.ty) {
return Err(Error::new_spanned(
&source_field.original.ty,
"non-static lifetimes are not allowed in the source of an error, because std::error::Error requires the source is dyn Error + 'static",
Expand All @@ -206,21 +206,28 @@ fn same_member(one: &Field, two: &Field) -> bool {
}
}

fn contains_non_static_lifetime(field: &Field) -> bool {
let ty = match field.ty {
Type::Path(ty) => ty,
_ => return false, // maybe implement later if there are common other cases
};
let bracketed = match &ty.path.segments.last().unwrap().arguments {
PathArguments::AngleBracketed(bracketed) => bracketed,
_ => return false,
};
for arg in &bracketed.args {
if let GenericArgument::Lifetime(lifetime) = arg {
if lifetime.ident != "static" {
return true;
fn contains_non_static_lifetime(ty: &Type) -> bool {
match ty {
Type::Path(ty) => {
let bracketed = match &ty.path.segments.last().unwrap().arguments {
PathArguments::AngleBracketed(bracketed) => bracketed,
_ => return false,
};
for arg in &bracketed.args {
match arg {
GenericArgument::Type(ty) if contains_non_static_lifetime(ty) => return true,
GenericArgument::Lifetime(lifetime) if lifetime.ident != "static" => {
return true
}
_ => {}
}
}
false
}
Type::Reference(ty) => ty
.lifetime
.as_ref()
.map_or(false, |lifetime| lifetime.ident != "static"),
_ => false, // maybe implement later if there are common other cases
}
false
}
11 changes: 11 additions & 0 deletions tests/ui/lifetime.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::fmt::Debug;
use thiserror::Error;

#[derive(Error, Debug)]
Expand All @@ -8,6 +9,16 @@ struct Error<'a>(#[from] Inner<'a>);
#[error("{0}")]
struct Inner<'a>(&'a str);

#[derive(Error, Debug)]
enum Enum<'a> {
#[error("error")]
Foo(#[from] Generic<&'a str>),
}

#[derive(Error, Debug)]
#[error("{0:?}")]
struct Generic<T: Debug>(T);

fn main() -> Result<(), Error<'static>> {
Err(Error(Inner("some text")))
}
10 changes: 8 additions & 2 deletions tests/ui/lifetime.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
error: non-static lifetimes are not allowed in the source of an error, because std::error::Error requires the source is dyn Error + 'static
--> $DIR/lifetime.rs:5:26
--> $DIR/lifetime.rs:6:26
|
5 | struct Error<'a>(#[from] Inner<'a>);
6 | struct Error<'a>(#[from] Inner<'a>);
| ^^^^^^^^^

error: non-static lifetimes are not allowed in the source of an error, because std::error::Error requires the source is dyn Error + 'static
--> $DIR/lifetime.rs:15:17
|
15 | Foo(#[from] Generic<&'a str>),
| ^^^^^^^^^^^^^^^^

0 comments on commit da6ee81

Please sign in to comment.