Add support for source forwarding in Error derive#293
Add support for source forwarding in Error derive#293MegaBluejay wants to merge 11 commits intoJelteF:masterfrom
Conversation
8552a14 to
9250cca
Compare
This comment was marked as resolved.
This comment was marked as resolved.
|
@MegaBluejay no, let's postpone refactoring here as a minor priority task. |
| called `Backtrace`. Then it would return that field as the `backtrace`. | ||
| 3. One of the fields is annotated with `#[error(backtrace)]`. Then it would | ||
| return that field as the `backtrace`. | ||
| 4. The source field is annotated with `#[error(backtrace)]`. Then it would |
There was a problem hiding this comment.
copy paste error?
| 4. The source field is annotated with `#[error(backtrace)]`. Then it would | |
| 4. The source field is annotated with `#[error(forward)]`. Then it would |
There was a problem hiding this comment.
No that's correct, provide is forwarded only when the source is annotated with #[error(backtrace)].
That behaviour is unchanged in this PR.
The reasoning for keeping a separate attribute is to make source forwarding work on stable, since there's no good way of generating feature-gated code.
I also think this is somewhat unintuitive, but I haven't come up with a better idea.
Perhaps it could make sense to disallow #[error(backtrace)] on the source field if there's no #[error(forward)]?
|
I'm having a hard time understanding the usecase for such forwarding. Could you share a concrete example for when this is useful? |
The main use case I can see is transparent error variants Something like #[derive(Debug, Display, Error)
enum Error {
...
#[error(forward)]
#[display("{_0}")]
#[debug("{_0:?}")]
Other(anyhow::Error),
}Where there's no new information added by the wrapper, so adding it to the source stack is unnecessary. |
|
@MegaBluejay yes, I start thinking that maybe |
|
Example use case: e.g. #[derive(Debug, Display, Error)]
#[display("`{rust_name}` should work but {kind}")]
struct Error {
rust_name: &'static str,
#[error(forward)]
kind: ErrorKind
}
#[derive(Debug, Display, Error)]
enum ErrorKind {
#[display("foo was encountered")]
Foo,
#[display("bar errored")]
Bar {
#[error(source)]
external: ExternalError
}
}We have data common to all variants, so moving it into a struct makes sense. But we also have source information only relevant to specific variants, so we need some way to use the source in the enum and we don't want to treat the Note that this pattern isn't available in thiserror, since |
Resolves #428
Related to #110, #200
Synopsis
Adds support for
#[error(forward)]attribute, which forwards the.source()implementation to a field.Solution
Use existing forward fields in
Statefor parsing the attributes, and keep the source-inferring logic the same as without forwarding.Backtrace forwarding
The current behaviour is that if the field annotated/inferred to be the source is annotated with
#[error(backtrace)], a forwardedprovide()is generated.This was in the example usage, but not documented in the list above, so I added it.
Checklist
#[error(forward)]when no source field was specified/inferred