Closed bakkot closed 1 year ago
Per the spec text, an eval body is parsed with the Script goal symbol. Parsing a using
declaration in a Script that is not nested in a block or function body is an early error: https://tc39.es/proposal-explicit-resource-management/#sec-let-and-const-declarations-static-semantics-early-errors
eval(`using x = y`)
would be an error.
Is that intentional? It seems odd to me.
(The eval
behavior specifically, I mean.)
For the most part, yes. The Script restriction is intentional, and I didn't intend for using
to work in eval
. The fact that the Script restriction blocks using
at the top level of an eval
body is a coincidental benefit.
I guess I don't really care about eval
, but it does seem surprising - why didn't you intend for using
to work in eval
? It creates its own lexical context, so a priori it seems reasonable for using
to work inside of it.
eval
s lexical context isn't obvious. I would expect most JS devs aren't aware of the scoping rules.
Supporting eval
would require either changing its goal symbol, which would likely have other repurcussions, or completely redoing the early errors for using
, which might entail needing to thread through a new parser context parameter. It doesn't seem like the benefit would outweigh the complexity.
There is also no reasonable way to support async using
in eval either, so supporting it would be somewhat inconsistent.
Supporting
eval
would require either changing its goal symbol, which would likely have other repurcussions, or completely redoing the early errors forusing
, which might entail needing to thread through a new parser context parameter.
I don't like to use "that would be difficult to specify" as a reason to choose one semantics or another, as a rule.
But also this actually isn't hard to specify - it suffices to tack on "unless the source text containing this UsingDeclaration
is eval code" or something to that effect. That's already how we handle super
in direct eval
s.
There is also no reasonable way to support async
using
in eval either, so supporting it would be somewhat inconsistent.
I don't think that would be any additional inconsistency given that await
already isn't supported.
I'm still not entirely convinced that eval("using x = ...")
should be supported, though it should be noted that eval("{ using x = ... }")
is. I will reopen the issue for now though.
Certainly all forms of using
should be consistently allowed, or prohibited at the top level of eval, no?
Certainly all forms of
using
should be consistently allowed, or prohibited at the top level of eval, no?
Why? using await
is only allowed in an async function context, and normal await
is not allowed in eval
already. I could imagine using
being allowed in eval on the basis that const
and let
are, but that using await
is not allowed on the basis that await
isn't.
@rbuckton Right, to be clear I will not be terribly disappointed if this doesn't work, but I would like the default to be that things work inside of eval
absent a particular reason for them not to.
@ljharb The top level of eval
is a sync context, so features which are async-only - which is to say, async using
- wouldn't work in it, at any level of nesting.
fair point about the async ones not working :-) but as of this proposal, no async forms exist, so "all forms" only includes sync.
Per the January, 2023 TC39 plenary session, the consensus is to leave the current behavior as-is (i.e., using
remains banned at the top of an eval()
body), and potentially enable this later as either a needs-consensus PR or a follow-on proposal in the future depending on implementer and community feedback.
If you have
does
x
get disposed before or after theconsole.log
? I would assume before.I think the current spec actually neglects to dispose it at all - PerformEval needs to get updated with a call to
DisposeResources
, I think.