-
Notifications
You must be signed in to change notification settings - Fork 316
buck2_error -> lsp diagnostics #1152
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?
Conversation
There is very little point using the std::file!() macro outside of a macro.
Otherwise every buck2 startup involves scanning the target folder looking for build files. This gets old pretty quickly.
... when converting starlark errors to buck2_error::Error. Previously it only got added for starlark ErrorKind::Native, but we need it for every kind of evaluation error. We need to give the user a span for every kind of thing that goes wrong in starlark. This also changes the effect of skip_stacktrace to operate on the StarlarkContext, which is necessary to make it still make sense. I checked this works for the one place we use skip_stacktrace=True i.e. bxl's fail_no_stacktrace()
This improves the call stack rendering very slightly. It also enables us to search through call stacks to find more spans to attach diagnostics to in LSP.
There was a failing test here, may as well
LSP needs the span. We need to always attach StarlarkContext so the span is not lost. But we need to do more than that -- we need to delete any code that throws away StarlarkContext. In inject_starlark-context, we were previously just formatting StarlarkContext & overwriting the root's description with that. This is unacceptable, as it loses the span by rendering it into a string. So now, such a StarlarkContext sits right above the root and says "i have the same error message as root, but with a span, so render me instead." An alternative would be to make ErrorRoot span-aware and then handle both StarlarkContext and ErrorRoot when doing the callstack collapsing etc. We rejig the inject_starlark_context tests to just make assertions about non-repetition, instead of the pop/replace with StarlarkContext behaviour.
Useful for tests, when you have a Vec of them.
This will be for .buck_error_context() calls that we don't currently pollute the buck output with spans for, and want to silently change for LSP only.
This is used with buck_error_context().
Just to check that I haven't broken anything or duplicated error messages.
I could not get the regular From<starlark_syntax::Error> + buck2_error formatter
to do what I wanted for starlark LSP use. So I made an exporter.
Sometimes error context makes LSP a bit verbose, like the 'Error
parsing: cell//path/...' line of context for syntax errors. The error
message in LSP is now
Parse error: unexpected new indentation block here, expected one of "\n", "(", "+", "-", "...", ...
Caused by:
0: Error parsing: `gh_facebook_buck2//:BUCK`
1: Parse error: unexpected new indentation block here, expected one of "\n", "(", "+", "-", "...", ...
Whis is worse than if we just eliminated this context line and tried to keep everything as starlark_syntax::Error:
Parse error: unexpected new indentation block here, expected one of "\n", "(", "+", "-", "...", ...
But acceptable.
This grabs the project relative path to show/hide spans as necessary.
So we can see this as an LSP diagnostic. There is no change to the buck output, this only shows up in LSP.
Before:
BUILD FAILED
Error loading `load` of `abc` from `BUCK:5:6-11`
Caused by:
Import path must have suffix `.bzl`: `gh_facebook_buck2//abc`
After:
BUILD FAILED
error: Error loading `load` of `abc`
--> BUCK:5:6
|
5 | load("abc", "def")
| ^^^^^
|
Caused by:
Import path must have suffix `.bzl`: `gh_facebook_buck2//abc`
|
@facebook-github-bot has imported this pull request. If you are a Meta employee, you can view this in D87982059. (Because this pull request was imported automatically, there will not be any future comments.) |
ahornby
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.
added suggestions to get it past the internal format lints. They currently show as red in the internal CI
| WithContext(ContextValue, Error), | ||
| /// The output of [`e.mark_emitted()`][Error::mark_emitted]; recursively contains Error. | ||
| /// There is eventually a [Self::Root] at the bottom. | ||
| /// |
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 field enables us to keep an actual StarlarkContext tha can be rendered | ||
| /// as an LSP span instead of literally replacing the root context with a | ||
| /// stringified span. | ||
| /// |
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.
| /// |
| /// Whereas if you render this in blah.bzl, you do not need to see | ||
| /// a printout of the code you are literally already looking at. | ||
| /// So we skip rendering this. | ||
| /// |
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.
| /// |
|
|
||
| /// We have `AstModule::parse(project_relative_path.as_str(), ...)` | ||
| /// So all our codemaps, file spans, etc, are project relative paths. | ||
| /// |
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.
| /// |
JakobDegen
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.
Thanks, this is cool.
I reviewed this like I would internally, so that mostly means I stopped after the commit I left the big comment on with the expectation that the rest of the stack was going to have to change a bit following resolution of that.
Reviewing this I did find some decrepit code that should be gone, I might try and get that deleted which in turn may create some light conflicts, but only things that'll be trivial to resolve
| .frames | ||
| .iter() | ||
| .chain(ctx.call_stack.frames.iter()) | ||
| .cloned() |
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.
(nit)
.frames
.iter()
.cloned()
.chain(ctx.call_stack.frames)
And maybe self by value and you can avoid the remaining clones?
| self.id | ||
| } | ||
|
|
||
| #[allow(unused)] |
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.
FIXME(cormacrelf,JakobDegen): Can't be right?
That's a bit disconcerting
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.
I was a bit alarmed when I saw this too. I deleted the only actual usage, which was to construct a new ErrorRoot with the same metadata as a previous one.
| // A string or other context_value is popped & replaced by a StarlarkContext | ||
| // that describes it. | ||
| // | ||
| // XXX: we are losing the Typed nature of the context. |
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.
Wow, this is a bit insane lol.
So I apologize a bit for making you fix bugs you didn't write here, but this code is just super hard to reason about and that makes me a bit nervous.
Instead of doing this, can we just push all of this bullshit into the formatting? So, I'd propose:
- Unimplement
DisplayonContextValueandStarlarkContext - Remove the
error_msgfield fromStarlarkContext - Completely replace
inject_starlark_contextwith just blindly pushing aStarlarkContexton top - When creating a starlark error in the non-native case, just
inject_starlark_context(Error::new(description)), so create a chain like[starlark_msg, starlark_ctx] - When formatting, merge adjacent stuff together at that time so that you can render the starlark error however you like
I think you should be able to do this mostly without regressions, but I'd also be happy to take small rendering regressions in exchange for the simplicity
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.
Basically yes, I would prefer it that way.
JakobDegen
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.
Review automatically exported from Phabricator review in Meta.
This fixes #1126 (no spans on parse errors in LSP) in a pretty comprehensive way. It is #1132, but cleaner and without the eval-on-save parts.
The simple way was to remove buck2_error wrapping of parse errors, leaving only starlark errors which preserved their spans. But this lost the error context for buck2 output, since buck2_error was providing that. And it did nothing for actual buck2_errors, like those from eval-on-save. So instead, I wrote an LSP formatter for arbitrary buck2_errors.
Features:
This is good enough for eval-on-save, where errors come from all over the place and have starlark attached midway through, or twice, etc. I have another branch where this is adapted to provide workspace diagnostics to LSP, i.e. take you right to a parse error in another file.
Why was this so complicated?
buck2_error is very stringy. Firstly, we were losing spans almost as soon as they entered buck2_error, only preserving them in some cases, and other times immediately rendering them to string. We were then losing any spans we managed to save, due to pre-rendering StarlarkContext as strings basically whenever we convert the buck2_error to/from anything else. So this PR preserves StarlarkContext everywhere, which was a lot of work to get right.
Note that you do not get a span attached directly when you
starlark::Error::from(buck2_error). It is hidden deep inside there in some buck2 context, which will resurface when you convert back to buck2_error.There is a lot of change to buck2_error, but very few observable changes outside LSP. It changes only one golden test, with better merging of CallStacks.