[wit-parser] Migrate to structured errors in the AST/package parser#2465
[wit-parser] Migrate to structured errors in the AST/package parser#2465PhoebeSzmucer wants to merge 7 commits intobytecodealliance:mainfrom
Conversation
| } | ||
|
|
||
| #[derive(Debug)] | ||
| pub enum Error { |
There was a problem hiding this comment.
Thsi went away now in favor of just using PackageParseError
|
|
||
| #[non_exhaustive] | ||
| #[derive(Debug, PartialEq, Eq)] | ||
| pub enum PackageParseErrorKind { |
There was a problem hiding this comment.
Note - I named it "package parse", because in the future we might want to expose a dedicated error for the "file parse" stage (a single WIT package can consist of many files).
Parsing is also usually thought of as converting a single file into an AST, so I think mentioning that this is about parsing a whole package makes things a bit clearer.
| /// | ||
| /// On failure returns `Err((self, e))` so the caller can use the source | ||
| /// map for error formatting if needed. | ||
| pub fn parse(self) -> Result<UnresolvedPackageGroup, (Self, PackageParseErrors)> { |
There was a problem hiding this comment.
Note that we're now returning the source map as well. Otherwise the consumers would need to clone the source map if they want to use it for resolving spans (since parse consumes self).
There was a problem hiding this comment.
Do you think it'd be reasonable to change this signature to &self to avoid the need for that? That's a bit more idiomatic and I'm not seeing off the top of my head why self is used here vs &self
| /// Runs `f` and, on error, attempts to add source highlighting to resolver | ||
| /// error types that still use `anyhow`. Only needed until the resolver is | ||
| /// migrated to structured errors. | ||
| pub(crate) fn rewrite_error<F, T>(&self, f: F) -> anyhow::Result<T> |
There was a problem hiding this comment.
This will go away once the resolver is also migrated to structured errors.
| @@ -1,4 +1,4 @@ | |||
| name `nonexistent` is not defined | |||
| name `nonexistent` does not exist | |||
There was a problem hiding this comment.
Previously we were doing a mix of "does not exist" and "is not defined". I'm going to standarize on "does not exist".
Once the structured error migration is done we might want to audit all error messages and see if anything could be better (now that we can track rich metadata easily).
| } | ||
|
|
||
| #[derive(Debug, PartialEq, Eq)] | ||
| pub struct PackageParseErrors(Box<PackageParseErrorKind>); |
There was a problem hiding this comment.
Happy to change this to a struct with #[repr(transparent)] if that's better (is there a practical difference between them?)
There was a problem hiding this comment.
Nah #[repr(transparent)] is kind of a niche concern and isn't required, it's fine to omit.
|
I apologize I've been extra busy the past few days and I'm about to get even busier traveling for a conference + then a vacation. I wanted to at least comment and say that I haven't forgotten about this and I'll try to get to it when I can. Other maintainers can certainly take a look too, but @PhoebeSzmucer wanted to at least let you know I may take a bit. |
|
@alexcrichton that's completely fine - I'm actually also on vacation now, plus this PR and the LSP is just a side project for me, so it can definitely wait. |
alexcrichton
left a comment
There was a problem hiding this comment.
Thanks again for your work on this! Overall looks good, but some comments on idioms/style below
| } | ||
|
|
||
| #[derive(Debug, PartialEq, Eq)] | ||
| pub struct PackageParseErrors(Box<PackageParseErrorKind>); |
There was a problem hiding this comment.
Nah #[repr(transparent)] is kind of a niche concern and isn't required, it's fine to omit.
| return Err(PackageParseErrors::from( | ||
| PackageParseErrorKind::Syntax { | ||
| span: f.name.span, | ||
| message: "duplicate constructors".to_owned(), | ||
| }, | ||
| )); |
There was a problem hiding this comment.
Bikeshedding this slightly, one option here might be:
return Err(PackageParseErrors::new_syntax(f.name.span, "duplicate constructors"))where the constructor new_syntax takes message: impl Into<String> or somthing like that.
| kind: &str, | ||
| deps: &IndexMap<&'a str, Vec<Id<'a>>>, | ||
| ) -> Result<Vec<&'a str>, Error> { | ||
| ) -> Result<Vec<&'a str>, PackageParseErrorKind> { |
There was a problem hiding this comment.
s/PackageParseErrorKind/PackageParseErrors/
| /// | ||
| /// On failure returns `Err((self, e))` so the caller can use the source | ||
| /// map for error formatting if needed. | ||
| pub fn parse(self) -> Result<UnresolvedPackageGroup, (Self, PackageParseErrors)> { |
There was a problem hiding this comment.
Do you think it'd be reasonable to change this signature to &self to avoid the need for that? That's a bit more idiomatic and I'm not seeing off the top of my head why self is used here vs &self
| let mut map = SourceMap::default(); | ||
| map.push_str(path, contents); | ||
| map.parse() | ||
| .map_err(|(map, e)| anyhow::anyhow!("{}", e.highlight(&map))) |
There was a problem hiding this comment.
We'll generally want to avoid stringifying errors like this since it loses type information -- but isn't the highlighting handled by by parse itself?
There was a problem hiding this comment.
Mind adding some brief comments to public types/enums/structs in this file as well as the module itself?
To bikeshed a bit, I find the naming here a bit too wordy. WDYT about something like this:
PackageParseErrors=>ParseErrors.- (future)
FileParseErrors=>FileErrors - (new)
type ParseResult<T, E = ParseErrors> = Result<T, E> - (new)
type LexResult<T, E = lex::Error> = Result<T, E>
That to me keeps the same flexibility for package/file distinctions insofar as there's different classes of errors, but I think it's useful for error ergonomics to not really get in the way when reading/writing code. To that extent I'm worried how verbose the error handling here is, so I'm hoping some renamings/idioms can help reduce the noise without adding too much complexity.
This PR replaces
anyhowerror handling in the AST/parser laye rwith structuredPackageParseErrorsandPackageParseErrorKindtypes. Errors now carry span information directly, enabling better error diagnostics and better integration with downstream tools that use wit-parser programatically.Part of a larger change: #2460 (see that link for API discussion).