Repository navigation
fix(parser): don't extend yield with member access, calls or binary operators - #669
Merged
Merged
Conversation
… operators
A YieldExpression is a complete AssignmentExpression, but it was parsed as a
primary expression, so callers went on to parse member accesses, calls,
tagged templates and binary operators after it. Invalid code such as
`function* g() { yield.x }` or `yield > 1` was accepted, and valid code that
relies on ASI after an operand-less `yield` (`yield\n(x)`, `yield\n[x]`,
`yield\n+x`) was parsed into a single wrong expression.
Report an operand-less `yield` followed on the same line by such a token,
and otherwise set `Flags.DisallowContinuation` so the caller stops before
the token.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
commit: |
Member
|
v7.4.1 is released. |
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.
A
YieldExpressionis a completeAssignmentExpression. It can't be the object of a member access, the callee of a call, a template tag, or the left operand of a binary operator. Meriyah parsesyieldinparsePrimaryExpression, and the callers then continue it as they would a primary expression.Invalid code is accepted:
function *g() { return yield.x; }isfail/84633c379e4010bf.jsin tc39/test262-parser-tests, and esprima and babel have the same input asinvalid-yield-generator-member-expression. V8 and acorn reject all four.Valid code gets the wrong AST.
yield [no LineTerminator here] AssignmentExpressionis a restricted production, so after a line break an operand-lessyieldends and ASI starts a new statement:The same thing happens with
[x](a MemberExpression), a template (a TaggedTemplateExpression) and+xor-x(a BinaryExpression). It also happens when ayieldargument ends in one of these cases, as inyield yield\n(x)oryield x => {}\n(x). Before this PR onlyyield\n*awas handled, by a special check.Fix: after a YieldExpression, if the current token is a member, call or template token or a binary operator:
Unexpected token;Flags.DisallowContinuation.parseMemberOrUpdateExpressionandparseBinaryExpressioncheck and clear this flag and return without consuming the token, the same wayFlags.DisallowCallandFlags.DisallowInvokework for block-body arrows. The statement then ends through ASI, or the enclosing parser reports the token ((yield\n(x))is still an error).These are unchanged:
(yield).x,yield, x,yield\n++x,yield\n/re/, and (withwebcompat)for (var a = yield b in c);.Tests: 10
failand 8passcases intest/parser/expressions/yield.ts, with snapshots.Verification: I couldn't install the dev dependencies, so I couldn't run vitest. Instead I ran the test files on Node 22 (
--experimental-transform-types) with a small stand-in for vitest'sdescribe/it/expect. The stand-in serializes snapshots the way vitest does: onmainit runs the 139 unit test files (91,991 tests, all passing) and reproduces all 101.snapfiles byte for byte. With this change all 92,009 tests pass, and the only snapshot changes are the 18 new entries. I also compared results before and after the change for:webcompat,lexicalandnextoff: identical.preserveParenson and off: identical.yield.xfiles linked above. The fourth is babel'sv8intrinsicfixtureyield %StringParseInt(...), which V8 also rejects without--allow-natives-syntax.🤖 Generated with Claude Code