mirror of
https://github.com/dtolnay/thiserror.git
synced 2025-04-07 06:47:38 +03:00
Change span of as_dyn_error()
to point compile error at attribute.
This commit is contained in:
parent
f4eac7ef7b
commit
a49f7c603d
14 changed files with 209 additions and 8 deletions
|
@ -23,14 +23,14 @@ fn impl_struct(input: Struct) -> TokenStream {
|
||||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||||
let mut error_inferred_bounds = InferredBounds::new();
|
let mut error_inferred_bounds = InferredBounds::new();
|
||||||
|
|
||||||
let source_body = if input.attrs.transparent.is_some() {
|
let source_body = if let Some(transparent_attr) = &input.attrs.transparent {
|
||||||
let only_field = &input.fields[0];
|
let only_field = &input.fields[0];
|
||||||
if only_field.contains_generic {
|
if only_field.contains_generic {
|
||||||
error_inferred_bounds.insert(only_field.ty, quote!(std::error::Error));
|
error_inferred_bounds.insert(only_field.ty, quote!(std::error::Error));
|
||||||
}
|
}
|
||||||
let member = &only_field.member;
|
let member = &only_field.member;
|
||||||
Some(quote! {
|
Some(quote_spanned! {
|
||||||
std::error::Error::source(self.#member.as_dyn_error())
|
transparent_attr.span => std::error::Error::source(self.#member.as_dyn_error())
|
||||||
})
|
})
|
||||||
} else if let Some(source_field) = input.source_field() {
|
} else if let Some(source_field) = input.source_field() {
|
||||||
let source = &source_field.member;
|
let source = &source_field.member;
|
||||||
|
@ -43,7 +43,8 @@ fn impl_struct(input: Struct) -> TokenStream {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let dyn_error = quote_spanned!(source.span()=> self.#source #asref.as_dyn_error());
|
let dyn_error =
|
||||||
|
quote_spanned!(source_field.source_span() => self.#source #asref.as_dyn_error());
|
||||||
Some(quote! {
|
Some(quote! {
|
||||||
::core::option::Option::Some(#dyn_error)
|
::core::option::Option::Some(#dyn_error)
|
||||||
})
|
})
|
||||||
|
@ -193,13 +194,13 @@ fn impl_enum(input: Enum) -> TokenStream {
|
||||||
let source_method = if input.has_source() {
|
let source_method = if input.has_source() {
|
||||||
let arms = input.variants.iter().map(|variant| {
|
let arms = input.variants.iter().map(|variant| {
|
||||||
let ident = &variant.ident;
|
let ident = &variant.ident;
|
||||||
if variant.attrs.transparent.is_some() {
|
if let Some(transparent_attr) = &variant.attrs.transparent {
|
||||||
let only_field = &variant.fields[0];
|
let only_field = &variant.fields[0];
|
||||||
if only_field.contains_generic {
|
if only_field.contains_generic {
|
||||||
error_inferred_bounds.insert(only_field.ty, quote!(std::error::Error));
|
error_inferred_bounds.insert(only_field.ty, quote!(std::error::Error));
|
||||||
}
|
}
|
||||||
let member = &only_field.member;
|
let member = &only_field.member;
|
||||||
let source = quote!(std::error::Error::source(transparent.as_dyn_error()));
|
let source = quote_spanned!(transparent_attr.span => std::error::Error::source(transparent.as_dyn_error()));
|
||||||
quote! {
|
quote! {
|
||||||
#ty::#ident {#member: transparent} => #source,
|
#ty::#ident {#member: transparent} => #source,
|
||||||
}
|
}
|
||||||
|
@ -215,7 +216,7 @@ fn impl_enum(input: Enum) -> TokenStream {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let varsource = quote!(source);
|
let varsource = quote!(source);
|
||||||
let dyn_error = quote_spanned!(source.span()=> #varsource #asref.as_dyn_error());
|
let dyn_error = quote_spanned!(source_field.source_span()=> #varsource #asref.as_dyn_error());
|
||||||
quote! {
|
quote! {
|
||||||
#ty::#ident {#source: #varsource, ..} => ::core::option::Option::Some(#dyn_error),
|
#ty::#ident {#source: #varsource, ..} => ::core::option::Option::Some(#dyn_error),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ast::{Enum, Field, Struct, Variant};
|
use crate::ast::{Enum, Field, Struct, Variant};
|
||||||
use syn::{Member, Type};
|
use proc_macro2::Span;
|
||||||
|
use syn::{spanned::Spanned, Member, Type};
|
||||||
|
|
||||||
impl Struct<'_> {
|
impl Struct<'_> {
|
||||||
pub(crate) fn from_field(&self) -> Option<&Field> {
|
pub(crate) fn from_field(&self) -> Option<&Field> {
|
||||||
|
@ -70,6 +71,16 @@ impl Field<'_> {
|
||||||
pub(crate) fn is_backtrace(&self) -> bool {
|
pub(crate) fn is_backtrace(&self) -> bool {
|
||||||
type_is_backtrace(self.ty)
|
type_is_backtrace(self.ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn source_span(&self) -> Span {
|
||||||
|
if let Some(source_attr) = &self.attrs.source {
|
||||||
|
source_attr.path().span()
|
||||||
|
} else if let Some(from_attr) = &self.attrs.from {
|
||||||
|
from_attr.path().span()
|
||||||
|
} else {
|
||||||
|
self.member.span()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> {
|
fn from_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> {
|
||||||
|
|
12
tests/ui/source-enum-unnamed-field-not-error.rs
Normal file
12
tests/ui/source-enum-unnamed-field-not-error.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NotError;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
#[error("...")]
|
||||||
|
pub enum ErrorEnum {
|
||||||
|
Broken(#[source] NotError),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
22
tests/ui/source-enum-unnamed-field-not-error.stderr
Normal file
22
tests/ui/source-enum-unnamed-field-not-error.stderr
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
error[E0599]: the method `as_dyn_error` exists for reference `&NotError`, but its trait bounds were not satisfied
|
||||||
|
--> tests/ui/source-enum-unnamed-field-not-error.rs:9:14
|
||||||
|
|
|
||||||
|
4 | pub struct NotError;
|
||||||
|
| -------------------
|
||||||
|
| |
|
||||||
|
| doesn't satisfy `NotError: AsDynError<'_>`
|
||||||
|
| doesn't satisfy `NotError: std::error::Error`
|
||||||
|
...
|
||||||
|
9 | Broken(#[source] NotError),
|
||||||
|
| ^^^^^^ method cannot be called on `&NotError` due to unsatisfied trait bounds
|
||||||
|
|
|
||||||
|
= note: the following trait bounds were not satisfied:
|
||||||
|
`NotError: std::error::Error`
|
||||||
|
which is required by `NotError: AsDynError<'_>`
|
||||||
|
`&NotError: std::error::Error`
|
||||||
|
which is required by `&NotError: AsDynError<'_>`
|
||||||
|
note: the trait `std::error::Error` must be implemented
|
||||||
|
--> $RUST/core/src/error.rs
|
||||||
|
|
|
||||||
|
| pub trait Error: Debug + Display {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
10
tests/ui/source-struct-unnamed-field-not-error.rs
Normal file
10
tests/ui/source-struct-unnamed-field-not-error.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct NotError;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
#[error("...")]
|
||||||
|
pub struct ErrorStruct(#[source] NotError);
|
||||||
|
|
||||||
|
fn main() {}
|
21
tests/ui/source-struct-unnamed-field-not-error.stderr
Normal file
21
tests/ui/source-struct-unnamed-field-not-error.stderr
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
error[E0599]: the method `as_dyn_error` exists for struct `NotError`, but its trait bounds were not satisfied
|
||||||
|
--> tests/ui/source-struct-unnamed-field-not-error.rs:8:26
|
||||||
|
|
|
||||||
|
4 | struct NotError;
|
||||||
|
| ---------------
|
||||||
|
| |
|
||||||
|
| method `as_dyn_error` not found for this struct
|
||||||
|
| doesn't satisfy `NotError: AsDynError<'_>`
|
||||||
|
| doesn't satisfy `NotError: std::error::Error`
|
||||||
|
...
|
||||||
|
8 | pub struct ErrorStruct(#[source] NotError);
|
||||||
|
| ^^^^^^ method cannot be called on `NotError` due to unsatisfied trait bounds
|
||||||
|
|
|
||||||
|
= note: the following trait bounds were not satisfied:
|
||||||
|
`NotError: std::error::Error`
|
||||||
|
which is required by `NotError: AsDynError<'_>`
|
||||||
|
note: the trait `std::error::Error` must be implemented
|
||||||
|
--> $RUST/core/src/error.rs
|
||||||
|
|
|
||||||
|
| pub trait Error: Debug + Display {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
11
tests/ui/transparent-enum-not-error.rs
Normal file
11
tests/ui/transparent-enum-not-error.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
Other {
|
||||||
|
message: String,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
23
tests/ui/transparent-enum-not-error.stderr
Normal file
23
tests/ui/transparent-enum-not-error.stderr
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
error[E0599]: the method `as_dyn_error` exists for reference `&String`, but its trait bounds were not satisfied
|
||||||
|
--> tests/ui/transparent-enum-not-error.rs:5:13
|
||||||
|
|
|
||||||
|
5 | #[error(transparent)]
|
||||||
|
| ^^^^^^^^^^^ method cannot be called on `&String` due to unsatisfied trait bounds
|
||||||
|
|
|
||||||
|
::: $RUST/alloc/src/string.rs
|
||||||
|
|
|
||||||
|
| pub struct String {
|
||||||
|
| -----------------
|
||||||
|
| |
|
||||||
|
| doesn't satisfy `String: AsDynError<'_>`
|
||||||
|
| doesn't satisfy `String: std::error::Error`
|
||||||
|
|
|
||||||
|
= note: the following trait bounds were not satisfied:
|
||||||
|
`String: std::error::Error`
|
||||||
|
which is required by `String: AsDynError<'_>`
|
||||||
|
`&String: std::error::Error`
|
||||||
|
which is required by `&String: AsDynError<'_>`
|
||||||
|
`str: Sized`
|
||||||
|
which is required by `str: AsDynError<'_>`
|
||||||
|
`str: std::error::Error`
|
||||||
|
which is required by `str: AsDynError<'_>`
|
9
tests/ui/transparent-enum-unnamed-field-not-error.rs
Normal file
9
tests/ui/transparent-enum-unnamed-field-not-error.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
Other(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
23
tests/ui/transparent-enum-unnamed-field-not-error.stderr
Normal file
23
tests/ui/transparent-enum-unnamed-field-not-error.stderr
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
error[E0599]: the method `as_dyn_error` exists for reference `&String`, but its trait bounds were not satisfied
|
||||||
|
--> tests/ui/transparent-enum-unnamed-field-not-error.rs:5:13
|
||||||
|
|
|
||||||
|
5 | #[error(transparent)]
|
||||||
|
| ^^^^^^^^^^^ method cannot be called on `&String` due to unsatisfied trait bounds
|
||||||
|
|
|
||||||
|
::: $RUST/alloc/src/string.rs
|
||||||
|
|
|
||||||
|
| pub struct String {
|
||||||
|
| -----------------
|
||||||
|
| |
|
||||||
|
| doesn't satisfy `String: AsDynError<'_>`
|
||||||
|
| doesn't satisfy `String: std::error::Error`
|
||||||
|
|
|
||||||
|
= note: the following trait bounds were not satisfied:
|
||||||
|
`String: std::error::Error`
|
||||||
|
which is required by `String: AsDynError<'_>`
|
||||||
|
`&String: std::error::Error`
|
||||||
|
which is required by `&String: AsDynError<'_>`
|
||||||
|
`str: Sized`
|
||||||
|
which is required by `str: AsDynError<'_>`
|
||||||
|
`str: std::error::Error`
|
||||||
|
which is required by `str: AsDynError<'_>`
|
9
tests/ui/transparent-struct-not-error.rs
Normal file
9
tests/ui/transparent-struct-not-error.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
#[error(transparent)]
|
||||||
|
pub struct Error {
|
||||||
|
message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
21
tests/ui/transparent-struct-not-error.stderr
Normal file
21
tests/ui/transparent-struct-not-error.stderr
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
error[E0599]: the method `as_dyn_error` exists for struct `String`, but its trait bounds were not satisfied
|
||||||
|
--> tests/ui/transparent-struct-not-error.rs:4:9
|
||||||
|
|
|
||||||
|
4 | #[error(transparent)]
|
||||||
|
| ^^^^^^^^^^^ method cannot be called on `String` due to unsatisfied trait bounds
|
||||||
|
|
|
||||||
|
::: $RUST/alloc/src/string.rs
|
||||||
|
|
|
||||||
|
| pub struct String {
|
||||||
|
| -----------------
|
||||||
|
| |
|
||||||
|
| doesn't satisfy `String: AsDynError<'_>`
|
||||||
|
| doesn't satisfy `String: std::error::Error`
|
||||||
|
|
|
||||||
|
= note: the following trait bounds were not satisfied:
|
||||||
|
`String: std::error::Error`
|
||||||
|
which is required by `String: AsDynError<'_>`
|
||||||
|
`str: Sized`
|
||||||
|
which is required by `str: AsDynError<'_>`
|
||||||
|
`str: std::error::Error`
|
||||||
|
which is required by `str: AsDynError<'_>`
|
7
tests/ui/transparent-struct-unnamed-field-not-error.rs
Normal file
7
tests/ui/transparent-struct-unnamed-field-not-error.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
#[error(transparent)]
|
||||||
|
pub struct Error(String);
|
||||||
|
|
||||||
|
fn main() {}
|
21
tests/ui/transparent-struct-unnamed-field-not-error.stderr
Normal file
21
tests/ui/transparent-struct-unnamed-field-not-error.stderr
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
error[E0599]: the method `as_dyn_error` exists for struct `String`, but its trait bounds were not satisfied
|
||||||
|
--> tests/ui/transparent-struct-unnamed-field-not-error.rs:4:9
|
||||||
|
|
|
||||||
|
4 | #[error(transparent)]
|
||||||
|
| ^^^^^^^^^^^ method cannot be called on `String` due to unsatisfied trait bounds
|
||||||
|
|
|
||||||
|
::: $RUST/alloc/src/string.rs
|
||||||
|
|
|
||||||
|
| pub struct String {
|
||||||
|
| -----------------
|
||||||
|
| |
|
||||||
|
| doesn't satisfy `String: AsDynError<'_>`
|
||||||
|
| doesn't satisfy `String: std::error::Error`
|
||||||
|
|
|
||||||
|
= note: the following trait bounds were not satisfied:
|
||||||
|
`String: std::error::Error`
|
||||||
|
which is required by `String: AsDynError<'_>`
|
||||||
|
`str: Sized`
|
||||||
|
which is required by `str: AsDynError<'_>`
|
||||||
|
`str: std::error::Error`
|
||||||
|
which is required by `str: AsDynError<'_>`
|
Loading…
Add table
Add a link
Reference in a new issue