Skip to content

Restore import defer = parsing #61837

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

Merged

Conversation

nicolo-ribaudo
Copy link
Contributor

Fixes #60757 (comment)

I also added a bunch more tests for when using defer as a binding identifier in ES import declarations. Note that import defer from from "foo" is invalid, but I added a test to verify that it reports the same error as for import defer foo from "foo".

cc @jakebailey

@Copilot Copilot AI review requested due to automatic review settings June 9, 2025 12:50
@github-project-automation github-project-automation bot moved this to Not started in PR Backlog Jun 9, 2025
@typescript-bot typescript-bot added the For Uncommitted Bug PR for untriaged, rejected, closed or missing bug label Jun 9, 2025
@typescript-bot
Copy link
Collaborator

This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise.

1 similar comment
@typescript-bot
Copy link
Collaborator

This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise.

Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR restores the parsing of the "defer" identifier in import equals declarations and enhances the test coverage for various scenarios involving "defer" in import statements.

  • Adds new test cases for valid and invalid "defer" usage in various module systems.
  • Updates baseline outputs to reflect the corrections.
  • Refines the parser logic in src/compiler/parser.ts to correctly distinguish "defer" as a phase modifier.

Reviewed Changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated no comments.

File Description
tests/cases/conformance/importDefer/*.ts Added tests for "defer" usage in import equals and import declarations.
tests/baselines/reference/* Updated baselines reflecting the new parsing behavior.
src/compiler/parser.ts Modified the condition for recognizing "defer" to improve parsing accuracy.
Comments suppressed due to low confidence (2)

src/compiler/parser.ts:8396

  • [nitpick] The compound condition for detecting a deferred import is complex; adding an inline comment or refactoring using intermediate variables could improve code clarity.
identifier?.escapedText === "defer" && (token() === SyntaxKind.FromKeyword ? !lookAhead(nextTokenIsStringLiteral) : token() !== SyntaxKind.CommaToken && token() !== SyntaxKind.EqualsToken)

src/compiler/parser.ts:8396

  • [nitpick] Consider caching the result of token() in a local variable before the condition to ensure consistency and potentially reduce function calls.
identifier?.escapedText === "defer" && (token() === SyntaxKind.FromKeyword ? !lookAhead(nextTokenIsStringLiteral) : token() !== SyntaxKind.CommaToken && token() !== SyntaxKind.EqualsToken)

@jakebailey
Copy link
Member

@typescript-bot test it

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jun 9, 2025

Starting jobs; this comment will be updated as builds start and complete.

Command Status Results
test top400 ✅ Started ✅ Results
user test this ✅ Started ✅ Results
run dt ✅ Started ✅ Results
perf test this faster ✅ Started 👀 Results

@typescript-bot
Copy link
Collaborator

Hey @jakebailey, the results of running the DT tests are ready.

Everything looks the same!

You can check the log here.

@typescript-bot
Copy link
Collaborator

@jakebailey Here are the results of running the user tests with tsc comparing main and refs/pull/61837/merge:

Everything looks good!

@typescript-bot
Copy link
Collaborator

@jakebailey
The results of the perf run you requested are in!

Here they are:

tsc

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Compiler-Unions - node (v18.15.0, x64)
Errors 34 34 ~ ~ ~ p=1.000 n=6
Symbols 62,390 62,390 ~ ~ ~ p=1.000 n=6
Types 50,395 50,395 ~ ~ ~ p=1.000 n=6
Memory used 195,424k (± 0.91%) 194,741k (± 1.01%) ~ 192,918k 196,579k p=0.173 n=6
Parse Time 1.30s (± 0.79%) 1.30s (± 0.75%) ~ 1.29s 1.31s p=0.784 n=6
Bind Time 0.73s 0.73s ~ ~ ~ p=1.000 n=6
Check Time 9.71s (± 0.20%) 9.72s (± 0.20%) ~ 9.70s 9.75s p=0.514 n=6
Emit Time 2.74s (± 0.69%) 2.74s (± 0.68%) ~ 2.72s 2.77s p=0.744 n=6
Total Time 14.49s (± 0.10%) 14.49s (± 0.26%) ~ 14.46s 14.55s p=0.935 n=6
angular-1 - node (v18.15.0, x64)
Errors 56 56 ~ ~ ~ p=1.000 n=6
Symbols 949,249 949,249 ~ ~ ~ p=1.000 n=6
Types 411,061 411,061 ~ ~ ~ p=1.000 n=6
Memory used 1,225,146k (± 0.01%) 1,225,136k (± 0.00%) ~ 1,225,106k 1,225,233k p=0.688 n=6
Parse Time 6.58s (± 0.89%) 6.61s (± 0.29%) ~ 6.58s 6.63s p=0.295 n=6
Bind Time 1.88s (± 0.73%) 1.88s (± 0.78%) ~ 1.86s 1.90s p=0.934 n=6
Check Time 31.96s (± 0.22%) 31.99s (± 0.32%) ~ 31.85s 32.13s p=0.810 n=6
Emit Time 14.87s (± 0.09%) 14.87s (± 0.36%) ~ 14.79s 14.95s p=1.000 n=6
Total Time 55.29s (± 0.16%) 55.35s (± 0.17%) ~ 55.24s 55.49s p=0.630 n=6
mui-docs - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 2,583,014 2,583,014 ~ ~ ~ p=1.000 n=6
Types 892,129 892,129 ~ ~ ~ p=1.000 n=6
Memory used 2,862,982k (± 0.00%) 2,862,941k (± 0.00%) ~ 2,862,903k 2,862,994k p=0.092 n=6
Parse Time 9.17s (± 0.37%) 9.14s (± 0.33%) ~ 9.10s 9.18s p=0.225 n=6
Bind Time 2.29s (± 0.48%) 2.29s (± 0.36%) ~ 2.28s 2.30s p=0.383 n=6
Check Time 87.34s (± 0.49%) 87.37s (± 0.27%) ~ 87.02s 87.74s p=0.810 n=6
Emit Time 0.30s (± 1.74%) 0.30s (± 1.74%) ~ 0.29s 0.30s p=1.000 n=6
Total Time 99.10s (± 0.43%) 99.11s (± 0.24%) ~ 98.76s 99.50s p=0.689 n=6
self-build-src - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 1,228,901 1,228,901 ~ ~ ~ p=1.000 n=6
Types 267,535 267,535 ~ ~ ~ p=1.000 n=6
Memory used 2,362,748k (± 0.01%) 2,606,544k (±14.49%) ~ 2,361,973k 3,095,135k p=1.000 n=6
Parse Time 5.18s (± 0.83%) 5.24s (± 1.44%) ~ 5.16s 5.34s p=0.066 n=6
Bind Time 1.80s (± 0.47%) 1.79s (± 1.08%) ~ 1.76s 1.82s p=0.612 n=6
Check Time 35.48s (± 0.43%) 35.63s (± 0.42%) ~ 35.37s 35.75s p=0.128 n=6
Emit Time 2.95s (± 0.55%) 3.01s (± 0.99%) +0.05s (+ 1.86%) 2.97s 3.05s p=0.008 n=6
Total Time 45.43s (± 0.36%) 45.67s (± 0.40%) ~ 45.39s 45.85s p=0.065 n=6
self-build-src-public-api - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 1,228,901 1,228,901 ~ ~ ~ p=1.000 n=6
Types 267,535 267,535 ~ ~ ~ p=1.000 n=6
Memory used 3,067,152k (± 7.59%) 3,041,022k (± 9.80%) ~ 2,432,339k 3,163,333k p=0.378 n=6
Parse Time 6.87s (± 1.12%) 6.90s (± 1.31%) ~ 6.75s 7.02s p=0.575 n=6
Bind Time 2.18s (± 1.89%) 2.18s (± 1.46%) ~ 2.15s 2.24s p=1.000 n=6
Check Time 42.89s (± 0.77%) 43.08s (± 0.28%) ~ 42.96s 43.29s p=0.298 n=6
Emit Time 3.40s (± 2.91%) 3.52s (± 2.75%) ~ 3.41s 3.69s p=0.066 n=6
Total Time 55.35s (± 0.67%) 55.68s (± 0.19%) +0.33s (+ 0.59%) 55.50s 55.79s p=0.031 n=6
self-compiler - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 263,517 263,517 ~ ~ ~ p=1.000 n=6
Types 107,246 107,246 ~ ~ ~ p=1.000 n=6
Memory used 442,127k (± 0.01%) 442,144k (± 0.02%) ~ 442,046k 442,277k p=0.689 n=6
Parse Time 3.51s (± 0.69%) 3.54s (± 0.56%) ~ 3.51s 3.56s p=0.106 n=6
Bind Time 1.31s (± 1.64%) 1.32s (± 1.17%) ~ 1.30s 1.34s p=0.684 n=6
Check Time 18.90s (± 0.36%) 18.93s (± 0.34%) ~ 18.80s 18.98s p=0.170 n=6
Emit Time 1.52s (± 1.21%) 1.53s (± 1.07%) ~ 1.51s 1.55s p=0.359 n=6
Total Time 25.25s (± 0.40%) 25.31s (± 0.29%) ~ 25.19s 25.41s p=0.228 n=6
ts-pre-modules - node (v18.15.0, x64)
Errors 71 71 ~ ~ ~ p=1.000 n=6
Symbols 225,981 225,981 ~ ~ ~ p=1.000 n=6
Types 94,356 94,356 ~ ~ ~ p=1.000 n=6
Memory used 371,280k (± 0.01%) 371,362k (± 0.05%) ~ 371,145k 371,617k p=0.575 n=6
Parse Time 2.88s (± 0.95%) 2.89s (± 1.80%) ~ 2.83s 2.96s p=0.748 n=6
Bind Time 1.59s (± 1.38%) 1.59s (± 1.72%) ~ 1.57s 1.64s p=1.000 n=6
Check Time 16.50s (± 0.35%) 16.57s (± 0.37%) ~ 16.49s 16.65s p=0.126 n=6
Emit Time 0.00s 0.00s ~ ~ ~ p=1.000 n=6
Total Time 20.97s (± 0.38%) 21.05s (± 0.17%) ~ 21.02s 21.10s p=0.065 n=6
vscode - node (v18.15.0, x64)
Errors 38 38 ~ ~ ~ p=1.000 n=6
Symbols 3,495,769 3,495,769 ~ ~ ~ p=1.000 n=6
Types 1,180,236 1,180,236 ~ ~ ~ p=1.000 n=6
Memory used 3,537,356k (± 0.01%) 3,537,327k (± 0.01%) ~ 3,536,912k 3,537,532k p=0.689 n=6
Parse Time 14.98s (± 0.53%) 14.94s (± 0.35%) ~ 14.87s 15.01s p=0.624 n=6
Bind Time 4.86s (± 0.40%) 4.87s (± 1.00%) ~ 4.81s 4.94s p=0.746 n=6
Check Time 96.06s (± 3.79%) 96.83s (± 3.53%) ~ 94.26s 101.57s p=0.748 n=6
Emit Time 29.89s (± 4.18%) 30.98s (± 6.65%) ~ 29.32s 34.97s p=0.173 n=6
Total Time 145.79s (± 3.34%) 147.61s (± 2.55%) ~ 143.27s 152.00s p=0.298 n=6
webpack - node (v18.15.0, x64)
Errors 2 2 ~ ~ ~ p=1.000 n=6
Symbols 320,092 320,092 ~ ~ ~ p=1.000 n=6
Types 140,399 140,399 ~ ~ ~ p=1.000 n=6
Memory used 474,405k (± 0.02%) 474,331k (± 0.02%) ~ 474,249k 474,441k p=0.128 n=6
Parse Time 4.34s (± 0.81%) 4.34s (± 0.56%) ~ 4.32s 4.39s p=0.809 n=6
Bind Time 1.76s (± 1.74%) 1.76s (± 0.86%) ~ 1.74s 1.78s p=1.000 n=6
Check Time 20.82s (± 0.62%) 20.83s (± 0.39%) ~ 20.72s 20.93s p=0.936 n=6
Emit Time 0.00s 0.00s ~ ~ ~ p=1.000 n=6
Total Time 26.93s (± 0.41%) 26.95s (± 0.29%) ~ 26.83s 27.02s p=0.689 n=6
xstate-main - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 662,826 662,826 ~ ~ ~ p=1.000 n=6
Types 197,993 197,993 ~ ~ ~ p=1.000 n=6
Memory used 568,656k (± 0.01%) 568,738k (± 0.01%) ~ 568,669k 568,896k p=0.066 n=6
Parse Time 4.43s (± 0.79%) 4.43s (± 0.60%) ~ 4.40s 4.48s p=0.872 n=6
Bind Time 1.32s (± 1.12%) 1.32s (± 0.96%) ~ 1.31s 1.34s p=0.869 n=6
Check Time 20.55s (± 0.32%) 20.42s (± 1.55%) ~ 19.80s 20.66s p=0.573 n=6
Emit Time 0.00s 0.00s ~ ~ ~ p=1.000 n=6
Total Time 26.30s (± 0.30%) 26.18s (± 1.09%) ~ 25.62s 26.40s p=0.574 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • Compiler-Unions - node (v18.15.0, x64)
  • angular-1 - node (v18.15.0, x64)
  • mui-docs - node (v18.15.0, x64)
  • self-build-src - node (v18.15.0, x64)
  • self-build-src-public-api - node (v18.15.0, x64)
  • self-compiler - node (v18.15.0, x64)
  • ts-pre-modules - node (v18.15.0, x64)
  • vscode - node (v18.15.0, x64)
  • webpack - node (v18.15.0, x64)
  • xstate-main - node (v18.15.0, x64)
Benchmark Name Iterations
Current pr 6
Baseline baseline 6

Developer Information:

Download Benchmarks

@@ -8392,7 +8392,10 @@ namespace Parser {
phaseModifier = SyntaxKind.TypeKeyword;
identifier = isIdentifier() ? parseIdentifier() : undefined;
}
else if (identifier?.escapedText === "defer" && token() !== SyntaxKind.FromKeyword) {
else if (
Copy link
Member

@jakebailey jakebailey Jun 9, 2025

Choose a reason for hiding this comment

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

Why isn't this just the same as what's done for type above? You can't mix type and defer, so I would have expected both to parse in the same fashion.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The difference is that the type parsing considers type as a modifier in import type foo =, while the defer parsing doesn't in import defer foo =.

Do you prefer if I unify the path, but then add a "nice" error for import defer foo = rather than just complaining about the unexpected foo/=?

Copy link
Member

Choose a reason for hiding this comment

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

Daniel pointed out there's a difference between them in other ways like import type foo, { bar } from "..." is not legal as it's ambiguous whether or not bar is type or not. So, all good.

Copy link
Contributor Author

@nicolo-ribaudo nicolo-ribaudo Jun 9, 2025

Choose a reason for hiding this comment

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

Well technically we could still unify parsing for them and report that type case as an "early error" while still building the proper AST.

(I'm happy to both keep the code as-is or to update it)

Copy link
Member

Choose a reason for hiding this comment

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

After thinking more, technically neither allow named bindings or defaults. I think this is okay as-is. I'll make a second PR to add more tests.

@typescript-bot
Copy link
Collaborator

@jakebailey Here are the results of running the top 400 repos with tsc comparing main and refs/pull/61837/merge:

Everything looks good!

@github-project-automation github-project-automation bot moved this from Not started to Needs merge in PR Backlog Jun 9, 2025
@DanielRosenwasser DanielRosenwasser merged commit 0dfd0c2 into microsoft:main Jun 9, 2025
32 checks passed
@github-project-automation github-project-automation bot moved this from Needs merge to Done in PR Backlog Jun 9, 2025
@nicolo-ribaudo nicolo-ribaudo deleted the restore-import-defer-equals branch June 9, 2025 22:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Uncommitted Bug PR for untriaged, rejected, closed or missing bug
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

4 participants