Visitar URL original
fix(es/parser): Retry ambiguous Program parsing by magic-akari · Pull Request #12142 · swc-project/swc · GitHub
Skip to content

fix(es/parser): Retry ambiguous Program parsing - #12142

Merged
Donny/강동윤 (kdy1) merged 2 commits into
mainfrom
fix/parse-unambiguous
Aug 24, 2026
Merged

Donny/강동윤 (kdy1) merged 2 commits into
mainfrom
fix/parse-unambiguous

Conversation

@magic-akari

Copy link
Copy Markdown
Member

Description:

parse_program could classify a source as a Module too early when a top-level await token also had a valid Script interpretation.

For example, in the following code, await should be parsed as an identifier and the second import argument should remain a normal call expression:

function await() {}

import("./fixture.js", await(undefined));

This PR updates unambiguous Program parsing to:

  • initially parse using the Module Await grammar;
  • retry as Script when await has a distinct valid Script interpretation and no definitive module syntax was found;
  • retain the Module result when imports, exports, or unambiguous module-only syntax determine the parse goal;
  • restore lexer diagnostics and token state when retrying;
  • defer publishing comments until a parse result is selected, preventing duplicated comments;
  • preserve the grammar boundaries of functions, parameters, class fields, and static blocks.

The regular lexer/parser checkpoint remains unchanged. Non-ambiguous valid programs still use a single parsing pass; reparsing is limited to ambiguous or failed probes.

Regression coverage includes:

  • ambiguous await unary, binary, call, member, assignment, arrow, and for...of forms;
  • TypeScript as and satisfies expressions;
  • nested function and class-field grammar contexts;
  • comment preservation across retries;
  • parser fixtures and resolver output for the dynamic-import case.

Related issue (if exists):

N/A

@changeset-bot

changeset-bot Bot commented Aug 23, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 18c7608

The changes in this PR will be included in the next version bump.

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

@codspeed

codspeed Bot commented Aug 23, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 200 untouched benchmarks
⏩ 61 skipped benchmarks1


Comparing fix/parse-unambiguous (18c7608) with main (8dd98e4)

Open in CodSpeed

Footnotes

  1. 61 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@magic-akari
magic-akari force-pushed the fix/parse-unambiguous branch 2 times, most recently from 994f598 to 70ee744 Compare August 23, 2026 15:26
@magic-akari
magic-akari marked this pull request as ready for review August 23, 2026 23:34
@magic-akari
magic-akari requested review from a team as code owners August 23, 2026 23:34

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 70ee7446c7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "Codex (@codex) review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "Codex (@codex) address that feedback".

Comment thread crates/swc_ecma_parser/src/parser/expr.rs
Comment thread crates/swc_ecma_parser/src/parser/expr.rs Outdated
Comment thread crates/swc_ecma_parser/src/parser/expr.rs
Comment thread crates/swc_ecma_parser/src/parser/class_and_fn.rs
@magic-akari
magic-akari force-pushed the fix/parse-unambiguous branch from 70ee744 to 0d63d2d Compare August 24, 2026 00:32
@kdy1
Donny/강동윤 (kdy1) enabled auto-merge (squash) August 24, 2026 03:59

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 18c7608ebd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "Codex (@codex) review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "Codex (@codex) address that feedback".

Comment on lines +1927 to +1929
if self.can_classify_module() {
self.mark_found_module_item();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Check the await-using line break before classifying

With explicit resource management enabled, a nested block such as { await\nusing resource = null; } is a valid Script containing an await identifier expression followed by a using declaration, but this newly added classification runs before checking the line break and commits the module probe. After consuming await, parse_using_decl only checks for a line break between using and its binding, so the probe incorrectly combines the two lines into an await using declaration and returns a Module. Honor the line break between await and using, or classify only after confirming that the declaration is valid.

Useful? React with 👍 / 👎.

Comment on lines +2321 to +2322
if !ctx.contains(Context::InFunction)
&& ctx.intersects(Context::InClassField.union(Context::InStaticBlock))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject static-block await inherited from an async function

Fresh evidence beyond the earlier static-block coverage is an async enclosing function: async function outer() { class C { static { await value; } } } is accepted without a diagnostic because the static block inherits both InFunction and InAsync, causing this new guard to skip the error and the later AwaitInFunction check to skip it as well. Actual nested function bodies already clear InStaticBlock in parse_fn_body, so the function check should only protect class-field initializers, not direct expressions in static blocks.

Useful? React with 👍 / 👎.

@kdy1
Donny/강동윤 (kdy1) merged commit 141a320 into main Aug 24, 2026
116 checks passed
@kdy1
Donny/강동윤 (kdy1) deleted the fix/parse-unambiguous branch August 24, 2026 04:34
@github-actions github-actions Bot added this to the Planned milestone Aug 24, 2026
Donny/강동윤 (kdy1) pushed a commit that referenced this pull request Aug 26, 2026
**Description:**

Follow-up to #12142. Compared with `main`, this PR:

- refines Script/Module retry decisions around ambiguous `await`
expressions;
- handles line breaks, escaped contextual keywords, `!`, and `in`
correctly;
- fixes `await` handling in class fields, static blocks, and `await
using`;
- preserves the original Module result and diagnostics when both parses
fail;

Some edge cases were identified during the code review of #12142,
including `await!`, static-block `await`, and the line break in
`await\nusing`.

**Related issue:**

- #12142
@github-actions github-actions Bot modified the milestones: Planned, v1.16.2 Sep 11, 2026
@swc-project swc (swc-project) locked as resolved and limited conversation to collaborators Oct 11, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants