-
Notifications
You must be signed in to change notification settings - Fork 316
wit-parser: Add validation hooks for custom linting
#2419
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
wit-parser: Add validation hooks for custom linting
#2419
Conversation
wit-parser: Add validation hooks for custom linting
|
Redirecting review because I'm not familiar with |
wit-parser: Add validation hooks for custom lintingwit-parser: Add validation hooks for custom linting
|
Apologies for the delay in reviewing this, it's been a busy week! This is a conceptually large enough change that the design in this PR isn't a slam-dunk to me just yet, and it might still be worth considering some of the other options that you laid out. Could you describe your end goal with this a bit more to help shape the thinking there? For example what are you looking to do with spans after a |
|
No problem! Thanks for the response. I totally understand wanting to consider other options that's why I tried to explore and present a few. Not sure if you clicked the links but they lead to diffs with all the changes made for that strategy. The So the first strategy is about making The second strategy, the PR, is allowing consuming code to hook into the resolution process to add additional validation rules at a point in the lifecycle where the |
|
FWIW, I'm working on something for which I'd like to have source span information available as well. Not for validation, but to enable jumping to the line an item is defined in. More generally, making spans available seems like the strictly more expressive change, which might be worth considering. |
|
Ok thanks for the info @wilfreddenton, that helps me at least! Given your use case, what @tschneidereit is describing, and my own experience, I might actually lean more towards including spans on items themselves rather than having side tables or just one pass where the spans are available. I think that'll be the most flexible in terms of what consumers can do with the information. I agree though it's not an easy change, so I think it'd be worth to game it out first before fully committing to ensure it's reasonable. For the breaking change aspect that's ok, this crate has a new major version on all releases intentionally to enable this sort of development. For Default, going this route would I believe basically require that impl to exist. I think the most appropriate default value would be some sort of sentinel for "not present". @wilfreddenton with those two problems in theory resolved, how would you feel about the span-in-item route? |
|
Yes happy to go with the span-in-item route. My main concern with it was breaking changes. The strategy is pretty well explored here: main...wilfreddenton:wasm-tools:wit-parser-spans-in-structs
Are you saying that you want If we want
Would you please provide a quick initial pass of feedback on that diff above? Then I can make the updates and either force push those commits into this PR or close this one and make a new one, whichever you prefer. |
|
Apologies been pretty busy the past week... I think I misinterpreted what you were saying w.r.t. Feel free to push those commits over to this branch here, that's ok to update the PR title/description/etc in-place. Reading over it my main thought is that ideally the new |
03de7eb to
0c2b5e7
Compare
|
Ok this PR has been updated to the spans in items approach. I've adjusted it to use a single source map instead of a vec of them which removes the Next, I'd like to add spans to function parameters. Right now they're modeled as pub struct Param {
pub name: String,
pub ty: Type,
pub span: Option<Span>,
}
pub struct Function {
// ...
pub params: Vec<Param>,
// ...
}Thinking the There are some other public types that I think could have a span on them i.e. |
|
Agreed yeah |
alexcrichton
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few minor thoughts, but otherwise looks great. Thanks again!
crates/wit-parser/src/resolve/mod.rs
Outdated
| fn push_with_span_offset( | ||
| &mut self, | ||
| unresolved: UnresolvedPackage, | ||
| source_map: &SourceMap, | ||
| span_offset: u32, | ||
| ) -> Result<PackageId> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Historically I've tried to make sure that all the methods of Resolve trickle down into each other without branching out into private helpers because there's so many ways to push I find it easy to get lost if there's branches to where things end up (vs "everything goes through here and it's public too"). Given that I'd ideally prefer to avoid this new method which modifies push effectively.
How about a refactoring which more officially supports external SourceMaps? There could be a push_source_map method which takes SourceMap and returns u32, and then the push method takes a span_offset: u32 instead of &SourceMap. That would more easily fit into sort_unresolved_packages I think and also expose this infrastructural change to API users because otherwise push becomes basically buggy to use if anything else was pushed previously.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I believe I've addressed this but let me know if I misinterpreted you. A consequence of this change is rewrite_error also needs to take the span_offset and adjust the spans of the errors.
|
Yes happy to do the Not sure if you noticed but I just put the tests related to these changes here: https://github.com/bytecodealliance/wasm-tools/pull/2419/changes#diff-736cf01f18df117b373723a19f9594dce78b8cdaefe6192630fb893151c61244R4502 Not sure if this is the right place for them and/or if you prefer they be written in a different style. I'm just inlining the WIT test cases. I know there's a bunch of WIT fixtures in the |
alexcrichton
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests are perfect as-is yeah, thanks for adding them! They're dealing with some pretty specific details so it's fine to not try to shove everything under tests/cli/*
crates/wit-parser/src/resolve/mod.rs
Outdated
| self.assert_valid(); | ||
| } | ||
| ret | ||
| self.source_map.rewrite_error(span_offset, || ret) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is something that I think is a bit tricky because this means that errors only get properly rewritten if the pre-adjusted Span is used instead of the post-adjusted Span. Would it be possible to do a quick pass over the UnresolvedPackage to update all spans immediately (maybe even a method on that? maybe here as the first part of push? either way). That way this wouldn't have to make its way to rewrite_error and the only spans that's dealing with are post-processed Spans that have already been adjusted
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok after making this change I can see now that we have duplicate spans. We have the "parallel vec spans" i.e. interface_spans and type_spans and then Interface.span and TypeDef.span as well as others. I think maybe in a followup PR it makes sense to remove some of this duplication?
#2418
There are two strategies I've explored for giving consumers access to source locations:
Make spans available on resolved items so consumers can inspect them after resolution. There are two ways I found to do this
span: Option<Span>directly toTypeDef,Function,Interface,WorldHashMap<Id, Span>fields onResolveResolvederivesDefaultso not likely to break consumers)Hook into internal validation (this PR)
Keep spans private but let consumers hook into the resolution process via a
Validatortrait with callbacks.push_*calls, not after-the-fact inspectionThis PR implements Strategy 2 because it avoids breaking changes and has zero cost for existing. However, I'm happy to go with one of the other strategies or something totally new that I haven't considered.
Here's an example of how a consumer would use this new features: