fix(parser): allow nested destructured arrow functions inside ternary-consequent bodies#10152
fix(parser): allow nested destructured arrow functions inside ternary-consequent bodies#10152Zelys-DFKH wants to merge 2 commits into
Conversation
…-consequent bodies Fixes biomejs#10131. When `parse_arrow_body` enters the expression-body path with `in_conditional_consequent` set and the body starts with `({` or `([`, it was falling back to `parse_assignment_expression_or_higher_no_arrow` unconditionally. That guard prevents a TypeScript speculative-parse false positive (the ternary `:` being consumed as a return-type annotation), but it was too broad and also blocked legitimate nested arrow functions. The fix adds `is_paren_group_followed_by_fat_arrow`, a token-level lookahead that scans forward (tracking paren depth) and checks whether `=>` immediately follows the closing `)`. `=>` is syntactically unambiguous and a better discriminator than `:`. The `_no_arrow` guard is kept only when `=>` does not follow. Tests added for both TypeScript and JavaScript.
🦋 Changeset detectedLatest commit: 1db27bc The changes in this PR will be included in the next version bump. This PR includes changesets to release 13 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
WalkthroughThis PR fixes a parser regression where curried arrow functions with destructured parameters inside a ternary consequent were mis-parsed. It adds a lookahead that matches a parenthesised parameter group to check for a following Suggested reviewers
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
dyc3
left a comment
There was a problem hiding this comment.
nitpick: i think all the comments added in this pr are a bit hard to understand. they already include some abbreviated code samples, but maybe some more complete ones would help? idk, maybe i need sleep.
| @@ -0,0 +1,22 @@ | |||
| // Regression test for https://github.com/biomejs/biome/issues/10131 (JavaScript variant) | |||
| // Curried arrow in a ternary consequent where the inner arrow's parameters | |||
There was a problem hiding this comment.
what does "curried" mean in this context?
There was a problem hiding this comment.
Sorry for the unclear comments — I've been writing a novel and apparently it's bleeding into my code reviews. Rewrote the function.rs comment blocks with concrete before/after code snippets instead of prose. Left the test fixture comments as-is to avoid touching the snapshots — happy to update those separately if you'd prefer a different description there. Ping me if anything's still off.
Merging this PR will not alter performance
Comparing Footnotes
|
| // paren is the one checked for `=>`. Without this, `(a: () => T) =>` would stop | ||
| // at the inner `)` and return false. | ||
| fn is_paren_group_followed_by_fat_arrow(p: &mut JsParser) -> bool { | ||
| debug_assert!(p.at(T!['('])); |
There was a problem hiding this comment.
We usually want to add a small message with debug assertions. The message should be actionable, or try to be. The message should explain the error and hint at a possible solution (hence, actionable)
Fixes #10131.
The parser was rejecting valid code like this:
parse_arrow_bodyusesparse_assignment_expression_or_higher_no_arrowwhenin_conditional_consequentis set and the body starts with({or([. The guard is there for a real reason: in TypeScript mode, the ternary:can be misread as a return-type annotation, and the alternate's=>gets consumed as the arrow, making a parenthesized object literal look like a valid arrow function.The guard was too broad. It was blocking legitimate nested arrows along with the false positives it was meant to prevent.
Before falling back to
_no_arrow, a new helper scans forward token by token (tracking paren depth) to find the closing), then checks whether=>follows immediately. If it does, the expression must be a nested arrow, so normal parsing is allowed.=>only appears in arrow function syntax, which makes it a cleaner discriminator than checking:(TypeScript return-type annotations also produce:).One pre-existing edge case stays unchanged from
main: a nested arrow with both destructuring params and a return-type annotation, like({x}: T): R => body, inside another arrow body in a ternary consequent. That's a separate problem and I kept scope narrow here.Test plan
Added
crates/biome_js_parser/tests/js_test_suite/ok/conditional_nested_arrow_in_consequent.tsand.js, covering:(offset: number) => ({ photo, index, event }: ClickHandlerProps<TPhoto>) => { ... }(n: number) => ([a, b]: [string, string]) => { ... }(i: number) => ({ [CONTENT_SLOT]: i })still parses the body as a parenthesized object expressionAll 688 parser spec tests pass.
Docs
No documentation changes needed.