wiggle: new error configuration for generating a "trappable error"#5276
Merged
Conversation
b2b5875 to
468939f
Compare
start refactoring how errors are generated and configured put a pin in this - you can now configure a generated error but i need to go fix Names Names is no longer a struct, rt is hardcoded to wiggle rest of fixes to pass tests its called a trappable error now don't generate UserErrorConversion trait if empty mention in macro docs
2ea9247 to
ecf8780
Compare
Subscribe to Label Actioncc @kubkon DetailsThis issue or pull request has been labeled: "wasi"Thus the following users have been cc'd because of the following labels:
To subscribe or unsubscribe from this label, edit the |
alexcrichton
approved these changes
Nov 16, 2022
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Largely due to pains in wasi-common and experimentation in wit-bindgen, I have added a slightly different error handling strategy to
wiggle.When the user specifies
errno => trappable Errorin the macro's optionalerrors: {...}argument, wiggle will now generate a type namedErrorto be used in all positions where a function returned a witxerrnoin the error position.The generated error type is an opaque struct. Internally, it contains either the errno (which wiggle generates as an
enum Errno), or ananyhow::Errorfor trapping execution. These are constructed using either the generatedimpl From<Errno> for Errorimpl, or theError::trap(t: anyhow::Error) -> Selfconstructor.The error can be destructured using
Error::downcast(self) -> Result<Errno, anyhow::Error>, inspected usingError::downcast_ref(&self) -> Option<&Errno>, and it can have context added viaError::context(self, s: Into<String>) -> Self. The context is only observable via the Debug and Display impls.This design came about because the user defined error type wasn't really serving our needs in
wasi-common. There, we had essentially 2 choices:thiserrorstyle error enum that contains all of theerrnovalues, plus aTrap(anyhow::Error)variation for trapping execution. They then writeFromimpls for all of the foreign error types that need to be converted into their error enum, e.g.impl From<std::io::Error> for MyErrno. They then implement the (very mechanical) translation to the wiggle generatedErrnocases inUserErrorConversion.anyhow::Error. To implement the translation toErrnoor trap, the user downcasts all of the foreign error types they suspect may be thrown in their implementations.I used both of these designs in wasi-common, in that chronological order. I found that both had real drawbacks:
cap_rand::Errorwas thrown in the random methods, but I never tried to downcast to it inUserErrorConversion. The end result is that any error in the cap_rand crate would end up trapping execution of the wasm module, rather than returning it an appropriate errno. I don't think I ever would have discovered this bug if I hadn't attempted a refactor back towards design 1.So, my design here basically uses code generation to generate an acceptable implementation of design 1, while providing the
.context("help figuring out what went wrong")method available in design 2. I was reluctant to give up the ergonomics of approach 2, but the design of wasi is evolving to give us lots of different concrete errnos in the preview 2 interfaces, so I wanted to give us as much type safety as possible when managing the complexity of the coming evolution in this crate.