-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Editorial: mostly stop using strings for special values #2566
Conversation
spec.html
Outdated
@@ -28366,7 +28367,7 @@ <h1>Static Semantics: ExportEntries</h1> | |||
1. Return a List whose sole element is _entry_. | |||
</emu-alg> | |||
<emu-note> | |||
<p>*"\*default\*"* is used within this specification as a synthetic name for anonymous default export values.</p> | |||
<p>*"\*default\*"* is used within this specification as a synthetic name for anonymous default export values. See <emu-xref href="#note-star-default-star">this note</emu-xref> for more details.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<p>*"\*default\*"* is used within this specification as a synthetic name for anonymous default export values. See <emu-xref href="#note-star-default-star">this note</emu-xref> for more details.</p> | |
<p>*"\*default\*"* is used within this specification as a synthetic name for anonymous default export values. See <emu-xref href="#note-star-default-star"></emu-xref> for more details.</p> |
I don't like links that say things like "this" or "here".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That note does not have a name or section number, so there's nothing which would be generated there. We need to put some text there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this note
→ a note on BoundNames
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer the original text of "this note".
awesome, very happy to see #2155 replaced. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for writing the explanations, made reviewing this a lot easier.
spec.html
Outdated
@@ -27671,13 +27672,13 @@ <h1> | |||
1. For each ExportEntry Record _e_ of _module_.[[StarExportEntries]], do | |||
1. Let _importedModule_ be ? HostResolveImportedModule(_module_, _e_.[[ModuleRequest]]). | |||
1. Let _resolution_ be ? _importedModule_.ResolveExport(_exportName_, _resolveSet_). | |||
1. If _resolution_ is *"ambiguous"*, return *"ambiguous"*. | |||
1. If _resolution_ is ~ambiguous~ return ~ambiguous~. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1. If _resolution_ is ~ambiguous~ return ~ambiguous~. | |
1. If _resolution_ is ~ambiguous~, return ~ambiguous~. |
spec.html
Outdated
@@ -28366,7 +28367,7 @@ <h1>Static Semantics: ExportEntries</h1> | |||
1. Return a List whose sole element is _entry_. | |||
</emu-alg> | |||
<emu-note> | |||
<p>*"\*default\*"* is used within this specification as a synthetic name for anonymous default export values.</p> | |||
<p>*"\*default\*"* is used within this specification as a synthetic name for anonymous default export values. See <emu-xref href="#note-star-default-star">this note</emu-xref> for more details.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer the original text of "this note".
0899420
to
722165e
Compare
722165e
to
3da5683
Compare
Using an ECMAScript string value to represent internal state may cause readers to incorrectly assume that the state is directly observable from ECMAScript code. Replace with a internal specification value in accordance with the latest practice in ECMA262 [1]. Modify the values so that they will be distinctive in the context of the specification in order to facilitate tool-assisted search (e.g. via the `grep` command-line utility or via "Ctrl+F" in a web browser). [1] tc39/ecma262#2566
Using an ECMAScript string value to represent internal state may cause readers to incorrectly assume that the state is directly observable from ECMAScript code. Replace with a internal specification value in accordance with the latest practice in ECMA262 [1]. Modify the values so that they will be distinctive in the context of the specification in order to facilitate tool-assisted search (e.g. via the `grep` command-line utility or via "Ctrl+F" in a web browser). [1] tc39/ecma262#2566
Replaces/ closes #2155.
There are four special strings used in the import/export machinery, one of which is used in three different ways:
"*"
, used in the [[ImportName]] field of an ExportEntry to mark anexport * from 'mod'
; this has been renamed to~all-but-default~
"*"
, used in the [[ImportName]] field of an ExportEntry to mark anexport * as foo from 'mod'
export; this has been renamed to~all~
"*"
, used in the [[ImportName]] field of an ImportEntry to mark animport * as foo from 'mod'
import; this has been renamed to~namespace-object~
"*namespace*"
, used in the [[BindingName]] field of a ResolvedBinding to mark aexport * as foo from 'mod'
; this has been renamed to~namespace~
"ambiguous"
, used in the return value forResolveExport
when resolving a name exported by multipleexport * from 'mod'
exports; this has been renamed to~ambiguous~
."*default*"
, used for default exports which do not have any other name; this has been left alone, and the note about it expanded.The goal is to unblock #2154 by ensuring that we never use a special string as a placeholder in a context where that PR would allow arbitrary well-formed strings to appear.
@michaelficarra and I spent a couple hours staring at all of this stuff, most of which was fixing our own confusion about how this worked, to wit:
We originally thought that
"*default*"
was such a string, but it turns out not to be - it is only used as a name strictly internal to a module, to provide the linkage between the"default"
export and the local binding by using the same machinery as named exports.And internally, for named exports, that linkage uses string names looked up in the actual scope object for the module. So the
"*default*"
string is used in a context which does actually require a string, and thus can't be trivially replaced by a spec enum. We considered modifying the machinery for default exports to work in a different way, but that seemed like it would be more complexity for little benefit, given that it does not actually conflict with #2154, so we've left it along. I did expand the note about"*default*"
to hopefully make this clearer to future readers.On the other hand,
"*"
was actually being used in a position which would conflict with #2154, as you can see from the [[ImportName]] column of theimport * as ns from "mod";
row in this table. So was"*namespace*"
, as you can sort of see from step 9/10 of this algorithm. (Edit: actually I guess"*namespace*"
was ok, on thinking further - step 9 happens after the public -> local name translation has already occurred.)So this PR does still block #2154, even though we didn't actually end up needing to deal with
"*default*"
.Just to summarize the relevant machinery here, mostly for my own benefit:
An
import
creates an ImportEntry Record whose [[ImportName]] is the exported name and whose [[LocalName]] is strictly internal to the module. [[ImportName]] has/had a special case of"*"
which indicated a request for the namespace object rather than any particular name.An
export ... from 'foo'
creates an ExportEntry Record whose [[ExportName]] is the name visible to importers of this module and whose [[ImportName]] is the name exported by the upstream module ('foo'), and has/had the same special case for"*"
.An
export ...
without afrom
creates an ExportEntry Record whose [[ExportName]] is the name visible to importers of this module and whose [[LocalName]] is the name used within this module. [[LocalName]] has a special case of"*default*"
for anonymous default exports, which is actually a name used on the module's Environment object alongside other top-level variables.Resolution hooks up these entries to create a ResolvedBinding Record which holds the original module defining the export, and whose [[BindingName]] is the name within that module's environment. It has/had a special case of
"*namespace*"
which indicated a request for the namespace object rather than any particular name. The [[BindingName]] is derived from an ExportEntry's [[LocalName]], except when the request is for a namespace object. As such, it can be"*default*"
, which will get looked up within the module's environment like any other name.Also, if resolution is ambiguous, the string
"ambiguous"
is used instead of a ResolvedBinding. It's not used in a position where names occur at all.So, the [[ImportName]] / [[ExportName]] fields hold the actual linker-exposed names, which are the things relaxed by #2154; the other names are strictly internal to a module. Of the special strings, only
"*"
was used in the linker-exposed position (in [[ImportName]]) and so only"*"
actually needed to change. But we might as well get rid of the others while we're at it.