-
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
Annex B.3.3.3 should not unconditionally overwrite global bindings with undefined
in EvalDeclarationInstantiation
#753
Comments
In particular, according to B.3.3.3 (
|
Contrast the behavior in a function: function a() {
var f = 42;
eval("print(f); { function f(){} }");
}
a(); Per spec this prints 42, because B.3.3.3.1.d.ii.7.a.ii.i avoids clobbering the existing |
FWIW no implementation implements the current spec behavior of overwriting with "undefined". |
Ugh, what should the semantics be? Will it read the value of the property of the global object and rewrite it (invoking getters at the top of the eval block)? Does any browser do that? EDIT: Not sure what I was thinking when I wrote this; please ignore this comment. |
It's just occurred to me that this comes up without <script>
var f = 42;
</script>
<script>
console.log(window.f); // per spec, prints 'undefined'
{
function f(){}
}
</script> I think the semantics should be, in both cases, that you don't create a new binding if one already exists but you still overwrite it when executing the The two aren't completely symmetric, in that in the global case you perform |
One more only tangentially related thing: I've just noticed that all of {v8, SpiderMonkey, JSC} agree that <script>
let f = 42;
</script>
<script>
{
function f(){}
}
</script> is a SyntaxError, but <script>
let f = 42;
</script>
<script>
"use strict";
{
function f(){}
}
</script> is fine. This seems wrong. I expect this is because the |
So that just means they don't implement step 2.d.ii.1 of B.3.3.2?
|
If we replace the CreateGlobalFunctionBinding calls in B.3.3.2 and B.3.3.3 with CreateGlobalVarBinding, we probably achieve the desired effect of not overwriting an existing binding value, because CreateGlobalVarBinding has an additional HasOwnProperty check. |
FWIW now some test262 tests reflect the state of the specification, e.g., annexB/language/eval-code/indirect/global-if-decl-else-decl-a-eval-global-existing-global-init . What's been said on this thread about what the semantics should be sounds reasonable to me. |
@anba Your suggestion would have the effect of making the environment record enumerable, whereas it's currently not enumerable, wouldn't it? |
@littledan Can you clarify? https://tc39.github.io/ecma262/#sec-createglobalfunctionbinding also creates enumerable properties, so using https://tc39.github.io/ecma262/#sec-createglobalvarbinding shouldn't make a difference here. |
@anba Not sure what I was thinking of; of course they're made enumerable in both cases. Staring at the spec longer, it seems like the only distinction might be that different Proxy traps are invoked. However, the distinction should be unobservable on the web. If we did care about that, an alternative to calling CreateGlobalVarBinding would be to allow |
Do you mean something like this?
This seems a bit too complicated to me, I'd rather prefer a different abstract operation in this case.
No. CreateGlobalFunctionBinding overrides existing property attributes whereas CreateGlobalVarBinding keeps the current attributes: var global = this;
Object.defineProperty(global, "f", {configurable: true, writable: false});
eval("{ function f() {} }");
// Current spec: {"writable":true,"enumerable":true,"configurable":true}
print(JSON.stringify(Object.getOwnPropertyDescriptor(global, "f")));
// Current spec: function f() {}
print(global.f); When CreateGlobalFunctionBinding is used, the global property will be changed to {[[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, whereas when CreateGlobalVarBinding is used, the property will keep the original attributes, that means it will be {[[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true}. Considering this example, we may also want to change CanDeclareGlobalFunction to CanDeclareGlobalVar (if we want to align the spec with current engine behaviour). var global = this;
Object.defineProperty(global, "f", {writable: true, enumerable: false, configurable: false});
eval("{ function f() {} }");
// Current spec: {"writable":true,"enumerable":false,"configurable":false}
print(JSON.stringify(Object.getOwnPropertyDescriptor(global, "f")));
// Current spec: undefined (b/c CanDeclareGlobalFunction returned false!)
print(global.f); |
This patch removes a case where a synthetic *undefined* was visible as a result of legacy sloppy-mode function hoisting. This patch addresses tc39#753
These tests are againt a proposed fix for tc39/ecma262#753 They seem to pass in V8, JSC and SpiderMonkey, though ChakraCore hews slightly closer to the previous specification.
@anba OK, thanks for explaining and bearing with me on this. I wrote a spec patch and test262 tests for this. It seems to be the semantics from three engines (minus ChakraCore). Any thoughts? |
These tests are againt a proposed fix for tc39/ecma262#753 They seem to pass in V8, JSC and SpiderMonkey, though ChakraCore hews slightly closer to the previous specification.
These tests are againt a proposed fix for tc39/ecma262#753 They seem to pass in V8, JSC and SpiderMonkey, though ChakraCore hews slightly closer to the previous specification.
Spec tests landed: tc39/test262#969 |
This patch removes a case where a synthetic *undefined* was visible as a result of legacy sloppy-mode function hoisting. This patch addresses tc39#753
Closed in #888. |
These tests are againt a proposed fix for tc39/ecma262#753 They seem to pass in V8, JSC and SpiderMonkey, though ChakraCore hews slightly closer to the previous specification.
André Bargull filed the following bug for Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1317373
This seems like a spec bug to me. EDI probably needs extra steps other than CanDeclareGlobalFunction to see if it should call CreateGlobalFunctionBinding.
The above bug reproduced inline for ease:
Test case:
Expected: Prints "undefined"
Actual: Prints "x"
V8 and Chakra print "x", JSC prints "function f() { }".
ES2017 spec: B.3.3.3, step 7.a.i.i
https://tc39.github.io/ecma262/#sec-web-compat-evaldeclarationinstantiation
The text was updated successfully, but these errors were encountered: