"10.5.5 Eval Declaration Instantiation" is not yet specified, so it's hard to tell how lexical declarations interact with eval'ed code, but I'd still like to suggest to change 15.1.2.1, step 14 to add an else-branch which creates a new declarative environment:
14. If strictScript is true or if direct is true and strictCaller is true, then
a. Let strictVarEnv be the result of calling NewDeclarativeEnvironment passing lexEnv as the argument.
b. Let lexEnv be strictVarEnv.
c. Let varEnv be strictVarEnv.
15. Else
a. Let newLexEnv be the result of calling NewDeclarativeEnvironment passing lexEnv as the argument.
b. Let lexEnv be newLexEnv.
With this change lexical declarations in the eval'ed code are always created within a new declarative environment. That means the following code does not add a let-bound variable to the block scope:
---
let x = 0;
{ /* block scope */
eval("let x = 1");
}
---
It also ensures lexical declarations are true lexical declarations. Without a new lexical environment, this code would create a data property "x" in the object "o" with value `1`:
---
let o = {};
with(o) eval("let x = 1");
---
And obviously this approach is also beneficial for VMs, because they can give block scopes static shapes.
SpiderMonkey handles this a bit different, basically "let <id> = <expression>" is rewritten to "var <id>; <id> = <expression>;". This also gives block scopes static shapes, but lexical declarations can still degenerate into other declaration forms as the following test case shows:
---
let o = {x: 0};
with(o) eval("let x=1");
assertEq(o.x, 1);
assertEq('x' in this, true);
---
sounds like a good idea. Probably need to discuss it on es-discuss or at TC39 meeting
fixed in rev28 editor's draft
fixed in rev28