Skip to content

Normative: make re-exporting a namespace object in 2 steps behave like 1 step#3715

Merged
ljharb merged 1 commit intomainfrom
unambiguous-export-star-from
Feb 17, 2026
Merged

Normative: make re-exporting a namespace object in 2 steps behave like 1 step#3715
ljharb merged 1 commit intomainfrom
unambiguous-export-star-from

Conversation

@bakkot
Copy link
Member

@bakkot bakkot commented Nov 8, 2025

Fixes #3710. Specifically, this makes it so that the example under "this throws" in this comment no longer throws, matching the behavior for re-exporting bindings rather than full namespaces.

I also added an explanatory comment about why we're doing this rewriting.

cc @nicolo-ribaudo @guybedford

@github-actions
Copy link

github-actions bot commented Nov 8, 2025

The rendered spec for this PR is available as a single page at https://tc39.es/ecma262/pr/3715 and as multiple pages at https://tc39.es/ecma262/pr/3715/multipage .

@ljharb ljharb added normative change Affects behavior required to correctly evaluate some ECMAScript source text needs consensus This needs committee consensus before it can be eligible to be merged. needs test262 tests The proposal should specify how to test an implementation. Ideally via github.com/tc39/test262 labels Nov 8, 2025
@nicolo-ribaudo nicolo-ribaudo added has consensus This has committee consensus. and removed needs consensus This needs committee consensus before it can be eligible to be merged. labels Nov 18, 2025
@nicolo-ribaudo nicolo-ribaudo added has test262 tests and removed needs test262 tests The proposal should specify how to test an implementation. Ideally via github.com/tc39/test262 labels Nov 26, 2025
lando-prod-mozilla bot pushed a commit to mozilla-firefox/firefox that referenced this pull request Nov 26, 2025
…=jonco

This patch implements tc39/ecma262#3715, to make

  import * as ns from "mod";
  export { ns };

behave the same as

  export * as ns from "mod";

Tested by tc39/test262#4606

Differential Revision: https://phabricator.services.mozilla.com/D274013
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified-and-comments-removed that referenced this pull request Nov 27, 2025
…=jonco

This patch implements tc39/ecma262#3715, to make

  import * as ns from "mod";
  export { ns };

behave the same as

  export * as ns from "mod";

Tested by tc39/test262#4606

Differential Revision: https://phabricator.services.mozilla.com/D274013

UltraBlame original commit: d14a908552e6d040c7538351430b3152a4a36887
gecko-dev-updater pushed a commit to marco-c/gecko-dev-comments-removed that referenced this pull request Nov 27, 2025
…=jonco

This patch implements tc39/ecma262#3715, to make

  import * as ns from "mod";
  export { ns };

behave the same as

  export * as ns from "mod";

Tested by tc39/test262#4606

Differential Revision: https://phabricator.services.mozilla.com/D274013

UltraBlame original commit: d14a908552e6d040c7538351430b3152a4a36887
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified that referenced this pull request Nov 27, 2025
…=jonco

This patch implements tc39/ecma262#3715, to make

  import * as ns from "mod";
  export { ns };

behave the same as

  export * as ns from "mod";

Tested by tc39/test262#4606

Differential Revision: https://phabricator.services.mozilla.com/D274013

UltraBlame original commit: d14a908552e6d040c7538351430b3152a4a36887
webkit-commit-queue pushed a commit to nicolo-ribaudo/WebKit that referenced this pull request Dec 5, 2025
https://bugs.webkit.org/show_bug.cgi?id=303141

Reviewed by Yusuke Suzuki and Sosuke Suzuki.

This patch changes JSC's handling of `import * as ns; export { ns }`
to align with tc39/ecma262#3715, which reached
consensus in the Nov 2025 TC39 meeting.

This will be tested by tc39/test262#4606, for
now I manually verified that the relevant tests in that PR are failing
before this patch and passing after it.

* Source/JavaScriptCore/parser/ModuleAnalyzer.cpp:
(JSC::ModuleAnalyzer::exportVariable):

Canonical link: https://commits.webkit.org/303952@main
@nicolo-ribaudo
Copy link
Member

nicolo-ribaudo commented Dec 5, 2025

The change has been implemented in SpiderMonkey and JavaScriptCore.

It has not been implemented in V8 yet, but V8 also did not match the original behavior.

@bakkot
Copy link
Member Author

bakkot commented Dec 5, 2025

Since this is just making an error into a non-error I think that's good enough, no need to wait for them to ship.

@bakkot bakkot added the editor call to be discussed in the next editor call label Dec 29, 2025
@bakkot bakkot removed the editor call to be discussed in the next editor call label Dec 29, 2025
@bakkot
Copy link
Member Author

bakkot commented Dec 29, 2025

V8 issue (at least according to test262.status): https://issues.chromium.org/issues/464065358

@michaelficarra wants to hold off for a couple months to see if V8 runs into any difficulties, but if they haven't landed by the time we cut the next yearly edition we'll include this either way.

@o-
Copy link

o- commented Jan 7, 2026

This is a bigger change on our end since apparently we never treated "export * as x" as proper re-exports. Hence the current behavior where you could not require such a namespace through multiple paths. I think there is a non-zero chance that we will run into problems.

@iamstolis
Copy link

If I understand correctly then this change modifies the behavior of deferred imports. If the re-exported namespace object was imported using a deferred import then the result was a deferred namespace object i.e. you got the deferred namespace object from the re-export. If you replace these 2 steps by a direct re-export then you get a regular namespace object (because there is nothing like a deferred export). Am I missing something or is this expected?

@nicolo-ribaudo
Copy link
Member

nicolo-ribaudo commented Jan 14, 2026

@iamstolis The import defer proposal would be updated to generate a binding that directly points to the [[DeferredNamespace]] slot when doing import defer+export{}, similarly to what this PR effectively does for non-deferred imports.

DevCheckOG pushed a commit to DevCheckOG/v8 that referenced this pull request Jan 21, 2026
This fixes a long standing issue where re-exported namespaces are not
disambiguated. If a namespace is re-exported in multiple dependencies,
then according to ecma262 this is not an ambiguous import.

Example:

                    export let x = 1
                        /       \
    export * as dep from ...    export * as dep from ...
                       \        /
                   export * from left
                   export * from right
                           |
                 import { dep } from ...
                 haz(dep.x)

While doing so we also implement the normative PR3715 [0] treating
`export * as dep from ...` the same as
`import * as dep from ...; export { dep }`.

Since modules can import themselves we must be able to produce a
shared binding cell to identify the namespace, before the namespace is
fully populated. To that end we store the namespace indirectly through
an additional binding cell in the module that we can use as a result
of the name resolution.

In other words in a module graph like

       export let x = 1
          |
       export * as dep from ...
          |
       import { dep } from ...

We will now resolve `{ dep }` to the special namespace binding cell on
the topmost module instead of the private re-export binding cell of the
middle module.

[0] tc39/ecma262#3715

Bug: 464065358
Change-Id: Ief31089987085772f92f3c32aecbf02db6796cee
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7362765
Auto-Submit: Olivier Flückiger <olivf@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#104825}
@nicolo-ribaudo
Copy link
Member

V8 implemented this. @o- are you ok with merging the PR now?

@o-
Copy link

o- commented Feb 12, 2026

So far we have not encountered issues. The fix will land with Chrome 146, which will become stable mid March. I am fine with going ahead already as I don't expect problems.

@guybedford
Copy link

We discussed this today in the modules meeting and the question came up why we couldn't refactor ~all~ and ~namespace-object~ to use the same internal keyword. I didn't fully trace this out yet, but it would be interesting to see if it's possible.

@michaelficarra
Copy link
Member

@guybedford For this change, we should only do the minimal thing needed to have the normative consequences we agreed upon. If we want to follow it up with an editorial simplification, that'd be great!

@guybedford
Copy link

@michaelficarra yes we agreed to land this as-is, but we will likely follow-up on the simplification.

@bakkot bakkot force-pushed the unambiguous-export-star-from branch from 3155c54 to 47886b7 Compare February 12, 2026 19:28
@bakkot bakkot added the ready to merge Editors believe this PR needs no further reviews, and is ready to land. label Feb 12, 2026
@ljharb ljharb force-pushed the unambiguous-export-star-from branch from 47886b7 to 1a78d83 Compare February 17, 2026 05:54
@ljharb ljharb merged commit 1a78d83 into main Feb 17, 2026
10 checks passed
@ljharb ljharb deleted the unambiguous-export-star-from branch February 17, 2026 05:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

has consensus This has committee consensus. has test262 tests normative change Affects behavior required to correctly evaluate some ECMAScript source text ready to merge Editors believe this PR needs no further reviews, and is ready to land.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Weird handling of import * as ns from "..."; export { ns }

7 participants