-
Notifications
You must be signed in to change notification settings - Fork 18
Move Error
trait into core
#3
Comments
I attempted to prototype the move to libcore with The mentioned impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> { comes up as an issue. In particular it will trigger coherence's wrath with
|
Here's a link to a related zulip discussion thread: https://rust-lang.zulipchat.com/#narrow/stream/257204-project-error-handling/topic/Stabilizing.20Backtrace.20.2F.20Core.20Error.20Proof.20of.20Concept/near/211291775 Once we've talked through potential solutions to the orphan rule issue more I'll come back and summarize the potential steps forward in the top level issue. |
This comment has been minimized.
This comment has been minimized.
I'm still unconvinced that hooks are the best solution as opposed to defining a Backtrace trait in core. Here is my analysis of the trade offs. Comparison
To my pattern matching brain traits feel like a universally quantified form of dynamic dispatch whereas these ad-hoc hooks feel like an existentially quantified form of const dynamic dispatch. Previously @withoutboats raised concerns about stability when using traits. I don't think this is a fundamental issue though. We could twrap the trait in a newtype and make the trait itself unstable, which is essentially what we're doing with the hooks. Either way if the user is ever allowed to provide the vtable, whether via traits or hooks, adding new items to that vtable will require handling the default case. The question is, which is more appropriate for backtraces?
|
This is a full example of what @yaahc, @mystor and I have discussed (I don't plan to be actively involved, but felt like I needed to exemplify my suggestions): https://play.rust-lang.org/?version=nightly&mode=release&edition=2018&gist=63b4720d0347d05391643df9da08c72f Also here's a more pseudocode version of it (and without most implementation details), to facilitate discussion: mod core::panic {
// perma(?)-unstable
pub trait RawBacktraceImpl: fmt::Debug + fmt::Display + 'static {
unsafe fn drop_and_free(self: *mut Self);
}
#[stable]
pub struct Backtrace(*mut dyn RawBacktraceImpl);
impl Backtrace {
// perma(?)-unstable
pub unsafe fn new(p: *mut dyn RawBacktraceImpl) -> Self {
Self(p)
}
#[stable]
pub fn capture() -> Option<Self> {
extern "Rust" {
#[lang_item = "backtrace_capture"]
fn backtrace_capture() -> Option<Backtrace>;
}
unsafe { backtrace_capture() }
}
}
impl !Send for Backtrace {}
impl !Sync for Backtrace {}
impl Drop for Backtrace {...}
impl fmt::Debug for Backtrace {...}
impl fmt::Display for Backtrace {...}
} mod alloc::panic {
#[stable]
pub trait BacktraceImpl: fmt::Debug + fmt::Display + 'static {}
impl<T: BacktraceImpl> From<Box<T>> for Backtrace {
fn from(x: Box<T>) -> Self {
struct Wrapper<T>(T);
impl<T: BacktraceImpl> RawBacktraceImpl for Wrapper<T> {...}
impl<T: fmt::Debug> fmt::Debug for Wrapper<T> {...}
impl<T: fmt::Display> fmt::Display for Wrapper<T> {...}
unsafe {
Backtrace::new(Box::into_raw(x) as *mut Wrapper<T> as *mut dyn RawBacktraceImpl)
}
}
}
} mod std::panic {
#[lang_item = "backtrace_capture"]
fn backtrace_capture() -> Option<Backtrace> {
struct StdBacktrace;
impl fmt::Debug for StdBacktrace {...}
impl fmt::Display for StdBacktrace {...}
impl BacktraceImpl for StdBacktrace {}
Some(Box::new(StdBacktrace).into())
}
} |
Status UpdateWe're getting a clearer and clearer picture of what's needed to move the error trait into core so here is a list of the specific blockers that need to be resolved still: Integrate negative trait impls with Coherence checksCurrently tracked in:
This feature is necessary to handle the following from impl on box. impl From<&str> for Box<dyn Error> { ... } Without having negative traits affect coherence moving the error trait into Resolve
|
core::error::Error
to prove that stabilizing fn backtrace
will not prevent a later move of the error trait to coreError
trait into core
…it, r=nikomatsakis Implement coherence checks for negative trait impls The main purpose of this PR is to be able to [move Error trait to core](rust-lang/project-error-handling#3). This feature is necessary to handle the following from impl on box. ```rust impl From<&str> for Box<dyn Error> { ... } ``` Without having negative traits affect coherence moving the error trait into `core` and moving that `From` impl to `alloc` will cause the from impl to no longer compiler because of a potential future incompatibility. The compiler indicates that `&str` _could_ introduce an `Error` impl in the future, and thus prevents the `From` impl in `alloc` that would cause overlap with `From<E: Error> for Box<dyn Error>`. Adding `impl !Error for &str {}` with the negative trait coherence feature will disable this error by encoding a stability guarantee that `&str` will never implement `Error`, making the `From` impl compile. We would have this in `alloc`: ```rust impl From<&str> for Box<dyn Error> {} // A impl<E> From<E> for Box<dyn Error> where E: Error {} // B ``` and this in `core`: ```rust trait Error {} impl !Error for &str {} ``` r? `@nikomatsakis` This PR was built on top of `@yaahc` PR rust-lang#85764. Language team proposal: to rust-lang/lang-team#96
Implement coherence checks for negative trait impls was just merged rust-lang/rust#90104 |
Now trialing moving WIP PR: rust-lang/rust#90328 |
Regarding this comment, rust-lang/rust#72981 (comment), the trial from rust-lang/rust#90328 seems to have shown that moving the impl to be on error[E0599]: no function or associated item named `downcast` found for trait object `dyn core::error::Error` in the current scope --> library/alloc/src/boxed.rs:2101:22 | 2101 | <dyn Error>::downcast(err).map_err(|s| unsafe { | ^^^^^^^^ function or associated item not found in `dyn core::error::Error` error[E0599]: no function or associated item named `downcast` found for trait object `dyn core::error::Error` in the current scope --> library/alloc/src/boxed.rs:2115:22 | 2115 | <dyn Error>::downcast(err).map_err(|s| unsafe { | ^^^^^^^^ function or associated item not found in `dyn core::error::Error` For more information about this error, try `rustc --explain E0599`. The original plan for this was to leverage a lang-item or something to allow the incoherent impl on |
Update I was able to get rust-lang/rust#90328 compiling, now testing everything but hopefully that should all be sorted, which means the negative trait impls in coherence and downcast issues have both been resolved 🎉. The only remaining blocker to moving the |
Ohh I thought negative trait in coherence wasn't going to work for your use case because it doesn't work in some cases. Cool if the current solution does work for you :). Anyway, we are going to be making some modifications to negative traits in coherence. More info https://rust-lang.github.io/negative-impls-initiative/explainer/coherence-check.html |
Update There's been a lot of progress in the last few months. Since the last update we've
At this point there are no remaining blockers per-se, though there are due diligence steps that still need to be done.
With any luck and assuming I don't have too many distractions pop up I should be able to have this done asap, hopefully within the next few days. |
It looks like a relevant change has landed in Rust - does this mean that Rust 1.65 will have the Error trait in core? If so woohoo! |
Amazing work @yaahc, thank you very much for your effort! |
Amazing work @yaahc, thank you very much for your effort! |
Wow, how did this fly under the radar? Amazing work, Jane! Thank you so much! <3 |
It looks like the error can be used in core but is marked as unstable - can someone confirm this is what people meant by
I read that and thought it was stable - happy to use it with unstable features if necessary :) |
Beta has it behind the error_in_core feature gate. |
For completeness, the tracking issue for |
Any update on this? Since rust-lang/rust#103765 was done. |
EDIT: Current Status Update
Building upon these prior issues:
From this comment
Backtrace
stabilization is currently blocked on prototyping one or more of the suggested solutions for moving thestd::error::Error
trait into coreThat comment suggests three possible solutions.
Option one is already known to work, and so it does not need to be prototyped. In addition to these backtrace related issues a prototype of the error trait in
core
will need to find a way to work aroundpub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>>
sinceBox
won't be available incore
. The top level comment in @withoutboats's stabilization PR goes into more detail on this second issue and outlines how a newcore::error::Error
implementation could use hooks that are defined instd
, similar to panic hooks, to work solve the issues aroundBox
.Boats has already raised issues about option two in this comment so I think the best way forward is to start working on a
core::error::Error
trait andcore::backtrace::Backtrace
type that both rely on hooks / manual vtables to maintain backwards compatibility with the existing error trait.The text was updated successfully, but these errors were encountered: