-
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
Normative: function implementation hiding #1739
base: main
Are you sure you want to change the base?
Normative: function implementation hiding #1739
Conversation
FYI I would still like feedback on alternative directive names at tc39/proposal-function-implementation-hiding#3. I don't really love the current ones, but haven't heard anything better. |
Ping @wycats @waldemarhorwat @mikesamuel. You are the stage 2 reviewers for this proposal. |
Ping @wycats @waldemarhorwat @mikesamuel once more. Please review before the upcoming meeting. I would like this proposal to advance to stage 3. |
Hi @michaelficarra , has anything changed since our discussion? IOW, is it essentially the same as what I approved in that discussion? Can I see a rendered form of this? I do not want to evaluate this by reading ecmarkup source. |
@erights The only changes were the ones we talked about in our last call. See the most recently closed issues, particularly tc39/proposal-function-implementation-hiding#32, tc39/proposal-function-implementation-hiding#31, and tc39/proposal-function-implementation-hiding#30. You can see a rendering of any PRs to ecma262, including this one, by clicking "Details" next to the words "Deploy preview ready!" in the CI checks below. |
Good to know, thanks! |
I'm having trouble reviewing what GetDirectiveContext is doing. It seems to make some unstated assumptions about what happens to be on the execution context stack at the time it is called. I can't tell whether that matches the lexical scope for all of the possible call paths (and note that Scope is passed as a separate parameter and strict mode scoping is done differently). Furthermore, more call paths may be added in the future, so relying on this kind of a hidden side effect seems brittle. |
If I understand it correctly, GetDirectiveContext seems broken. Just filed an issue for it. |
@waldemarhorwat You're right, I think I had a bug. I've removed |
19687c8
to
6c093fa
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although I think the pragma contents will still need some bikeshedding, from an editor standpoint, I'm good!
I'm happy to bikeshed names during plenary, though sad to waste committee time on it. Haven't gotten much feedback from other delegates on tc39/proposal-function-implementation-hiding#3, unfortunately, so it would be irresponsible not to at least bring it up. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the delay. Looks mostly good. Some questions below.
+1. As a reviewer, I sign off on this for stage 3. |
As far as I can tell, the bug is fixed. The thing that makes me uneasy is that the use of a running execution context to implement lexical scoping makes it difficult to follow what's happening here — I had to do a deep trace of code throughout the spec to find all possible things that could be on the running execution context stack when OrdinaryFunctionCreate is called. Module and function lexical scopes push onto the execution context, but class lexical scopes don't, which is weird and not apparent without looking at the implementation. I'm with @allenwb here. |
@waldemarhorwat , I would also like to see lexical concepts avoid needless dependencies on dynamic concepts. How should this be stated? |
ec41948
to
06de41c
Compare
@waldemarhorwat @erights @allenwb I've update this PR to use static information for deriving |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, I think this update has move in the right direction. However, eval code is still dependent upon the running execution context rather than being lexically based. As I said in #1739 (comment) "...there should be no significant difference in the handling of these new directives from how the strict mode direct[ive] is currently handled." But that isn't the case in this updated PR.
You have to take into account that eval
is really two different things depending upon whether it is a direct eval or an indirect eval. Direct eval and indirect eval code have different lexical contexts (ignoring here for simplicity the additional differences between strict and non-strict eval code) that are statically knowable without reference to the current execution environment (notice that while it is not always knowable that a particular eval
-like expression is a direct or indirect eval (or an eval at all). its possible direct and indirect eval lexical contexts are statically knowable so all that needs to be determine at execution time is whether or not the eval
is direct as is done in https://tc39.es/ecma262/#sec-function-calls-runtime-semantics-evaluation 6.a.iv-vi .
I disagree with this. The strict mode directive is currently handled by defining a new kind of code, in prose, in a way which has caused pain in the past. I do not think the appropriate way to introduce these directives is to add two new kinds of code. I'm fine with changing this PR to be more static; I think that should be doable by introducing definitions for |
Sorry, I should clarify. I wasn't talking about how you approach specifying the determination and semantics of the different kinds of directives. I was talking about the rules (that a human needs to learn) concerning how the extent of the affect of directive is determined. The extent of affect of a lexically enclosing I don't care strongly about how exactly this is expressed in the specification but I agree that the kinds of code prose may be outliving its usefulness. |
Oh, I see. That's always been true: in an earlier version of this PR the behavior was specified using knowledge of the execution environment, but that was just for editorial convenience; the actual semantics have always been static and have not changed across revisions of this PR. I had thought your concern was just about the editorial mechanism by which it was specified. Anyway, sounds like we're on the same page. |
4921f31
to
caf3fe7
Compare
@waldemarhorwat or @erights Can you review the spec text here before the next meeting? Note that I will be asking to split the proposal and only advance the |
I have just reviewed with this split in mind. The portions of this relating just to hiding source text, as well as the resulting suppression of position and source location within a stack frame but no more, LGTM. This is still a Draft so this comment is adequate, yes? |
@erights Yes that is perfect. Thank you! |
I see at https://github.com/tc39/ecma262/pull/1739/files#r351043373 that @allenwb also prefers orthogonal "hide source" and "hide stack" directives. The resulting thread asks for a use case. Here's one: When computing across a membrane, the stack frames of the membrane mechanism itself are often a distraction to the debugging experience. Debugger often do have better ways of handling the suppression of such unwanted detail. But for so-called printf debugging, looking at stacks dumped to logs, this could reduce the verbosity a lot. The Error stacks proposal will give better knobs for this as well. My point is that I can imagine wanting to suppress stack traces for reasons that would not imply that I also want to suppress source. Altogether, I am happy to see this go forward with only |
2449ea6
to
223caaa
Compare
FYI I've split the proposal into two commits in this PR to illustrate the intended proposal split more clearly. |
<emu-alg> | ||
1. If |CallExpression| occurs within a |ScriptBody|, |ModuleBody|, or |FunctionBody| that has a Directive Prologue that contains a Sensitive Directive, return *false*. | ||
1. If the source text matched by |CallExpression| is eval code resulting from a direct eval, then | ||
1. Return PresentInStackTraces of the |CallExpression| whose evaluation is the direct eval. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I get what you're trying to do here, but magically rematerializing the instance of the ancestor |CallExpression| that resulted in the particular direct eval that led to the instance of this |CallExpression| is harder to think about than I'd like. I wonder if there's a way to write this in a more obvious top-down manner, but the interleaving of static and run-time semantics definitely makes that very challenging.
One option is to have an argument-taking Static Semantics where direct eval can pass in the inherited "is sensitive" or "hide source" state. Not sure if that's a net editorial improvement...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One option is to have an argument-taking Static Semantics where direct eval can pass in the inherited "is sensitive" or "hide source" state. Not sure if that's a net editorial improvement...
The problem is that we need the relevant bit at this point, during runtime semantics. Having it at the point that you are doing the eval
call doesn't really help unless you propagate that information on some runtime construct like lexical environments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I see. If we can't come up with more obvious verbiage here, I think that sentence warrants some note that all this is doing is trying to reflect propagate the "lexical" nesting of the directives across (space and?) time, due to direct evals.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could add a NOTE reading something like
NOTE: Sensitive Directives apply to nested functions, including to code within a direct call to
eval
.
I'm not in love with that wording but don't have a better one off the top of my head.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
first commit LGTM otherwise
223caaa
to
9c3c9cc
Compare
@@ -490,7 +490,7 @@ <h1>The Numeric String Grammar</h1> | |||
<h1>The Syntactic Grammar</h1> | |||
<p>The <em>syntactic grammar</em> for ECMAScript is given in clauses 11, 12, 13, 14, and 15. This grammar has ECMAScript tokens defined by the lexical grammar as its terminal symbols (<emu-xref href="#sec-lexical-and-regexp-grammars"></emu-xref>). It defines a set of productions, starting from two alternative goal symbols |Script| and |Module|, that describe how sequences of tokens form syntactically correct independent components of ECMAScript programs.</p> | |||
<p>When a stream of code points is to be parsed as an ECMAScript |Script| or |Module|, it is first converted to a stream of input elements by repeated application of the lexical grammar; this stream of input elements is then parsed by a single application of the syntactic grammar. The input stream is syntactically in error if the tokens in the stream of input elements cannot be parsed as a single instance of the goal nonterminal (|Script| or |Module|), with no tokens left over.</p> | |||
<p>When a parse is successful, it constructs a <em>parse tree</em>, a rooted tree structure in which each node is a <dfn>Parse Node</dfn>. Each Parse Node is an <em>instance</em> of a symbol in the grammar; it represents a span of the source text that can be derived from that symbol. The root node of the parse tree, representing the whole of the source text, is an instance of the parse's goal symbol. When a Parse Node is an instance of a nonterminal, it is also an instance of some production that has that nonterminal as its left-hand side. Moreover, it has zero or more <em>children</em>, one for each symbol on the production's right-hand side: each child is a Parse Node that is an instance of the corresponding symbol.</p> | |||
<p>When a parse is successful, it constructs a <em>parse tree</em>, a rooted tree structure in which each node is a <dfn>Parse Node</dfn>. Each Parse Node is an <em>instance</em> of a symbol in the grammar; it represents a span of the source text that can be derived from that symbol. The root node of the parse tree, representing the whole of the source text, is an instance of the parse's goal symbol. When a Parse Node is an instance of a nonterminal, it is also an instance of some production that has that nonterminal as its left-hand side. Moreover, it has zero or more <em>children</em>, one for each symbol on the production's right-hand side: each child is a Parse Node that is an instance of the corresponding symbol. A Parse Node _A_ <dfn>occurs within</dfn> another Parse Node _B_ if _A_ is the child of _B_ or if _A_ is the child of some Parse Node _C_ where _C_ occurs within _B_.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are 13 existing uses of the phrase "occurs within", none of which match this definition but all of which get linked as a consequence of defining it here (e.g. "Every other finite time value t is defined relative to the greatest preceding time value s that is such a multiple, and represents the instant that occurs within the same UTC day as s but follows it by t − s milliseconds".)
I think it's probably fine not to mark this as a definition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like our new use of it to be linked though. How do I do that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, you could use an explicit <emu-xref>
on the occurrences you want to link, or an <emu-not-ref>
on the ones you don't want to link, but I think both of those approaches are sub-optimal. It would be better to come up with a different (distinct) phrase for this sense of "occurs within". E.g., "is a descendant of" or "descends from": either is a natural extension of the "child" terminology already established for parse trees, and neither occurs anywhere else in the spec.
9c3c9cc
to
373610b
Compare
3d0c24c
to
7a79833
Compare
This PR implements the currently stage 2 function implementation hiding proposal. I am opening it now to get reviewer feedback and editor sign-off, and to start having a linkable spec text rendering. It is my intention to present this proposal for stage 3 at the June 2020 TC39 meeting.