Skip to content

Editorial: dedupe and isolate modules traversal logic #3635

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

nicolo-ribaudo
Copy link
Member

@nicolo-ribaudo nicolo-ribaudo commented Jul 3, 2025

This PR separates the logic to perform a depth-first traversal on module graph out of InnerModuleLinking/InnerModuleEvaluation. It has two advantages:

  • it makes it obvious that traversal for linking and evaluation work the same way, since it's not copy&pasted code that needs to be kept in sync
  • especially for evaluation, it disentangles the traversal logic from the "keeping track of top-level await consequences" logic.

Whether this is an improvement or not is subjective (it adds a layer of indirection), so I'm
curious to read the editors opinion about it.

From an editorial/formatting point of view, ModuleGraphDFS is an AO that takes a bunch of callbacks. I've declared them inline in the Link()/Evaluate() concrete methods as abstract closures, even though they don't actually close over anything. I think having them inline rather than as separate AOs makes the reading flow simpler. Ideally, my preferred approach would be something that lets us write

1. Perform ModuleGraphDFS(_module_, _initialStatus_, _pendingStatus_) with
     Action(_m_):
       1. ...
     SCCCompletion(_m_, _sccRoot_):
       1. ...
     PostErrorCleanup(_m_, _errorCompletion_):
       1. ...

I suggest reading this commit-by-commit. The first two commits just move logic around so that what would go in the same AC of the third commit is already all in the same place.

This PR preserves the bugs that would be fixed by #3613 and #3583, but by implementing this PR + those two in engine262 all the tests I have still pass.

The import defer proposal would add a new callback to ModuleGraphDFS, _getModuleDescendants_, that for linking just returns the RequestedModules while for Evaluation it uses import defer's step 11 of https://tc39.es/proposal-defer-import-eval/#sec-innermoduleevaluation (with GatherAsynchronousTransitiveDependencies).

…loop

Rather than doing it in the DFS recursion loop.

This changes the order in which modules are pushed in [[PendingAsyncDependencies]]:
now they automatically are sorted by their [[AsyncEvaluationOrder]]. It does not
actually matter though, because GatherAvailableAncestors will merge various
[[PendingAsyncDependencies]] lists in a non-order-preserving way so
AsyncModuleExecutionFulfilled still needs to explicitly re-sort the resulting list.
@nicolo-ribaudo nicolo-ribaudo marked this pull request as ready for review July 3, 2025 12:19
This commit deduplicates the logic that is currently both in InnerModuleLinking
and InnerModuleEvaluation, clearly splitting what logic is relative to traversing
the graph and what is relative to actually linking/evaluating modules.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant