Which engine is right about with statement and Symbol.unscopables?

# Michał Wadas (7 years ago)

stackoverflow.com/questions/40595389/why-does-browser-get-symbol-unscopables-twice

Which implementation is bugged? Can someone familiar specification details fill bug in proper engine?

|vara,b,flag =truewith(a ={x:7})with(b
={x:4,get[Symbol.unscopables](){return{x:flag=!flag }}})x++// Chrome
FFconsole.log(a)// {x:5} {x:7}console.log(b)// {x:4} {x:8}|
# Boris Zbarsky (7 years ago)

On 2/20/17 10:00 AM, Michał Wadas wrote:

stackoverflow.com/questions/40595389/why-does-browser-get-symbol-unscopables-twice

Which implementation is bugged? Can someone familiar specification details fill bug in proper engine?

var a, b, flag = true

with (a = { x: 7 }) with (b = { x: 4, get Symbol.unscopables { return { x: flag=!flag } } }) x++

               // Chrome   FF

console.log(a) // {x:5} {x:7} console.log(b) // {x:4} {x:8}

TL;DR: both are buggy. The correct output is {x:7}, {x:5}. I have filed bugzilla.mozilla.org/show_bug.cgi?id=1341061 and bugs.chromium.org/p/v8/issues/detail?id=5992

I think we come into tc39.github.io/ecma262/#sec-postfix-increment-operator-runtime-semantics-evaluation here. The first question is what "lhs" ends up being.

I'm pretty sure that evaluating "x" will call tc39.github.io/ecma262/#sec-getidentifierreference which will start with envRc being the object Environment Record created by the "with (b)" and start looking for the binding for "x". Specifically, it will call HasBinding() on envRec, which will call tc39.github.io/ecma262/#sec-object-environment-records-hasbinding-n which will check @@unscopables. It will get x: false, I think (assuming that none of the bareword lookups used in defining "b" end up looking up things in the "with (b)" environment. So we will get back a Reference whose base is the object Environment Record for "with (b)". This claim could use double-checking.

Anyway, if that's correct, then tc39.github.io/ecma262/#sec-postfix-increment-operator-runtime-semantics-evaluation step 2 does tc39.github.io/ecma262/#sec-getvalue which in step 6a goes to tc39.github.io/ecma262/#sec-object-environment-records-getbindingvalue-n-s which will return the value "4" afaict, without ever checking @@unscopables.

And then tc39.github.io/ecma262/#sec-postfix-increment-operator-runtime-semantics-evaluation step 4 will call tc39.github.io/ecma262/#sec-putvalue which in step 7a will call tc39.github.io/ecma262/#sec-object-environment-records-setmutablebinding-n-v-s which will set b.x to 5.

So as far as I can tell from the spec, the output should be: {x:7}, {x:5}, and there should be one single call to the getter. And both of the browsers tested are buggy.

In Safari, for what it's worth, I get the output I expect: {x:7}, {x:5}.