Skip to content
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

Normative: Re-resolve unresolvable references on the global in PutValue. #2205

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

syg
Copy link
Contributor

@syg syg commented Oct 14, 2020

Currently, JSC, V8, SM, and XS all do not throw on the following code,
contra spec:

"use strict";
undeclared = (this.undeclared = 42);

This has been a bug in implementations for a decade
(https://bugzilla.mozilla.org/show_bug.cgi?id=605515), and is arguably
implementation reality not only for the web but for most
implementations.

This changes the spec to match the implemented re-resolution behavior.

Also see

Currently, JSC, V8, SM, and XS all *do not throw* on the following code,
contra spec:

```javascript
"use strict";
undeclared = (this.undeclared = 42);
```

This has been a bug in implementations for a decade
(https://bugzilla.mozilla.org/show_bug.cgi?id=605515), and is arguably
implementation reality not only for the web but for most
implementations.

This changes the spec to match the implemented re-resolution behavior.

Also see
- tc39#467
- tc39/test262#1964
@syg syg 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. labels Oct 14, 2020
@mathiasbynens mathiasbynens added the needs test262 tests The proposal should specify how to test an implementation. Ideally via github.com/tc39/test262 label Oct 15, 2020
@ExE-Boss
Copy link
Contributor

ExE-Boss commented Oct 16, 2020

I’d prefer if this were Annex B‑only, since the this binding is module.exports in CommonJS and undefined in ES Modules.

@devsnek
Copy link
Member

devsnek commented Oct 16, 2020

Would it make you feel better if the example code was x = (globalThis.x = 42)

@rwaldron rwaldron 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 2, 2020
@Jack-Works
Copy link
Member

I’d prefer if this were Annex B‑only, since the this binding is module.exports in CommonJS and undefined in ES Modules.

I agree but we have eval

@syg
Copy link
Contributor Author

syg commented Nov 16, 2020

This needs more investigation.

@erights brought up in plenary that we should prefer late resolution over re-resolution, even if the observability point is [[HasProperty]], which I agree with. Further, we should endeavor to have consistent late resolution behavior across with scopes, global objects, and global lexical scopes, since in all three cases we are able to inject a binding in the RHS.

For with, something like this:

foo = "global";
let scopeObj = { };
with (scopeObj) {
  foo = (scopeObj.foo = "with1", "with2");
}
print(scopeObj.foo);
print(globalThis.foo);

Currently engines disagree:

#### jsc
with1
with2

#### sm
with1
with2

#### v8
with2
global

@syg
Copy link
Contributor Author

syg commented Nov 16, 2020

For the global lexical environment, I haven't crafted this yet but it should be possible to do so by injecting a <script> via document.write that introduces the new global lexical binding, then awaiting a Promise that doesn't get resolved until the injected script finishes executing.

@rkirsling
Copy link
Member

It seems like the with case might just be a V8 bug, but is this what you were envisioning for the global lexical environment one?

foo = 1;

var resolve;
new Promise((r) => { resolve = r }).then(() => {
  foo = (globalThis.foo = 3, 4);
  console.log(foo, globalThis.foo);
});

document.write(`<script>let foo = 2; resolve();</script>`);

Safari, Chrome, and FF all print 4 and 3 here.

@bathos
Copy link
Contributor

bathos commented Nov 21, 2022

@rkirsling I’m not 100% sure but I thought @syg was describing a scenario where a lexical binding can become declared during RHS eval where the LHS was unresolvable (not a global object env binding interaction) — i.e. ScriptEvaluation being entered in the RHS via document.write.

@nicolo-ribaudo
Copy link
Member

nicolo-ribaudo commented Nov 21, 2022

A test for global lexical bindings (i.e. converting @bathos's words to code):

let foo2 = foo = (document.write(`<script>let foo = 2</script>`), 4);
console.log(foo, foo2) 

Firefox and Safari log 2, 4, Chrome logs 4, 4.

@syg
Copy link
Contributor Author

syg commented Nov 21, 2022

let foo2 = foo = (document.write(`<script>let foo = 2</script>`), 4);

Quel cursed!

@syg
Copy link
Contributor Author

syg commented Nov 21, 2022

So there is indeed a spec compliance bug in V8 for the with scope case, for which I filed this issue. That might be the same root cause as #2205 (comment), but I'm not sure yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has test262 tests needs consensus This needs committee consensus before it can be eligible to be merged. normative change Affects behavior required to correctly evaluate some ECMAScript source text
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants