tc39 / ecma262

Status, process, and documents for ECMA-262
https://tc39.es/ecma262/
Other
15.06k stars 1.29k forks source link

Extending "Forbidden Extensions" #1323

Open littledan opened 6 years ago

littledan commented 6 years ago

This nice idea from @bakkot may deserve further investigation in TC39. What do you all think?

I think the "forbidden extensions" thing only really makes sense in the historical context of browsers experimenting with language extensions without consulting with each other or the broader community (e.g.). Since they don't seem to be inclined to do that sort of thing anymore (thankfully), I don't think we necessarily need to worry about people shipping a syntax before we have consensus on it.

Personally I'd be happiest if we could add a "everything not permitted is forbidden" part to the spec, but that might be hard to get through & would require some careful wording to allow browsers to ship stage 3 proposals (since the current spec makes no reference to the proposal process at all).

I'd be happiest with the strictest practical definition of what JS is, and I see nothing impractical about @bakkot 's proposal. This proposal could enable us to share more tests between implementations through test262, for one benefit.

bakkot commented 6 years ago

FWIW, test262-parser-tests already maintains a list (slightly outdated, but updating it is on my todo list) of illegal program texts, where "illegal" means "not currently permitted by the specification" rather than "explicitly not permitted by the specification". Part of the reason it's split out as a separate project is because of @leobalter's very valid concern that it is difficult to figure out which illegal program texts to include, and how to organize them; that project takes a more scattershot approach of "we'll include any test anyone thought worth writing, and we're not going to worry too much about coverage or duplication".

erights commented 6 years ago

Ignoring extensions, JavaScript has many useful inabilities; most obviously memory safety. However, I see nothing in the current spec that would forbid an implementation adding a non-config, non-write data property with builtin peek and poke methods, for directly accessing raw memory addresses. However, any theorem about what JS programs cannot do relies on such inabilities. As long as such extensions are not forbidden, such theorems are not sound.

I solicit help from formalists to help answer the following question:

What seem to be the intended inabilities that should enable useful theorems to proceed soundly? How should we specify them?

littledan commented 6 years ago

@erights What if we start with forbidding syntactic extensions, and then move on to considering semantic things to forbid as the next step?

erights commented 6 years ago

@littledan Anything that gets us started, makes progress, would be great!

allenwb commented 6 years ago

What if we start with forbidding syntactic extensions, and then move on to considering semantic things to forbid as the next step?

So, you would try to forbid implementations from implementing experimental syntactic features or even stage 4 features that are not yet in an actual Ecma GA approved edition of ECMA-262? Or host/environment specific features such as JSX?

In practice, such a probation would be ignored and that fact that TC39 is trying to enforce unrealistic demands would diminish TC39's "moral authority" to make important realistic demands.

The current "forbidden extensions" were all carefully selected to address very specific concerns. By being limited and targeted they convey that TC39 is serious about the importance of keeping the specific identified behaviors out of the language. Expending it to say something like "no new syntax" means that TC39 is neither serious or realistic when it talks about restricting extensions and makes it more likely that the actual important restriction could be ignored.

zenparsing commented 6 years ago

The current "forbidden extensions" were all carefully selected to address very specific concerns.

Also note that the specific concerns addressed by each restriction vary. The ":" restriction is interesting, as I think it can be interpreted two ways. On one hand, it may indicate the desire to reserve syntactic space for type annotations in JS. On the other hand, it may indicate the desire to reserve that space for compile-to-JS supersets.

@allenwb Do you remember what motivated the ":" restriction?

allenwb commented 6 years ago

Do you remember what motivated the ":" restriction?

type annotations

bakkot commented 6 years ago

@allenwb

So, you would try to forbid implementations from implementing experimental syntactic features or even stage 4 features that are not yet in an actual Ecma GA approved edition of ECMA-262?

per the OP: this "would require some careful wording to allow browsers to ship stage 3 proposals". I expect such wording could be written. We of course would not try to prevent implementations shipping stage 3 proposals which had not yet made it into the spec.

In practice, the such a probation would be ignored

Can you say more about why you think so? I'm not aware of any instance this decade in which someone intending to be an implementation of ECMAScript shipped any syntax which was neither proposed nor in the spec.

leobalter commented 6 years ago

I believe that generally forbidding syntax extensions is weak and too loose. The examples I'm aware so far can be specifically annotated and described. The prevented extensions for : on type annotations and the one proposed for dynamic imports are a good signal we can do a better job specifying what we want to secure for the web compat in the future. We can do the same work for other parts / proposals.

allenwb commented 6 years ago

Can you say more about why you think so?

The 70 year history of programming languages and how they evolve. Including the relative lack of success of previous attempts by various languages to restrict extensions. The times when it has worked (to some degree) have generally been situations where there were IP based contractual restrictions that limited extensions.

Standards are followed as long as they are useful to a business or user community. As soon as a potential competitive advantage or environmental requirement conflicts with a standard the standard goes out the window.

I'm not aware of any instance this decade in which someone intending to be an implementation of ECMAScript shipped any syntax which was neither proposed nor in the spec.

Ah... Babel; JSX; Node, non-standard top level semantics ...

Regardless, my most important point was:

that fact that TC39 is trying to enforce unrealistic demands would diminish TC39's "moral authority" to make important realistic demands.

Power can be lost if it isn't used carefully.

ljharb commented 6 years ago

Which implementations shipped runtime support for jsx? Babel is a build tool and is unconstrained by the spec in this regard, and thus not relevant to this thread.

devsnek commented 6 years ago

The only thing I can think of is V8's natives syntax feature, which allows embedders and V8 itself to inline calls to V8 internals from JS. (const target = %JSProxyGetTarget(someProxy);)

bathos commented 6 years ago

@ljharb I think the line gets fuzzy sometimes:

require('@babel/register');

ljharb commented 6 years ago

@bathos sure but that’s runtime stuff, not shipped by the implementation, nor syntax. If anything that’s an argument for forbidding any extensions, because it can always be enabled by a runtime mechanism.

allenwb commented 6 years ago

Babel is a build tool and is unconstrained by the spec in this regard, and thus not relevant to this thread.

Of course Babel is an implementation of ECMA-262 and historically one that has tended to have lots of deviations and extensions to the specification.

There is (intentionally) nothing in ECAM-262 that says what technologies or techniques must be used to implement the specified language. Source to source translation (regardless of the target language) is a perfectly valid implementation technique.

bakkot commented 6 years ago

Babel does not by default include any plugins which extend the spec, and plugins can and do change the syntax and semantics of things which are covered by the spec, rather than merely adding non-forbidden extensions. I don't think babel would have a problem with this, at least any more than it has a problem with the current spec - it is already the case the current spec does not carve out nearly enough space in what extensions it permits to fit all of babel's plugins. (I am technically a member of the babel team, but am not speaking on behalf of that team.)

Regardless, my most important point was:

that fact that TC39 is trying to enforce unrealistic demands would diminish TC39's "moral authority" to make important realistic demands.

Sure, but the question is whether this is actually unrealistic. To me, it looks like people who try to follow the ECMAScript standard have not, in recent years, wanted to ship non-standard non-proposed syntax. If we expect that to continue - and perhaps you're right that we shouldn't, but I'm not totally convinced - then this would not be an unrealistic demand.

allenwb commented 6 years ago

To me, it looks like people who try to follow the ECMAScript standard have not, in recent years, wanted to ship non-standard non-proposed syntax.

JSX?

If we expect that to continue - and perhaps you're right that we shouldn't, but I'm not totally convinced - then this would not be an unrealistic demand.

I expect change, in everything. Expecting that a status quo will continue is unrealistic.

zenparsing commented 6 years ago

I think @allenwb 's point is that ECMA-262's authority to prevent things is meager to begin with and that expanding this section may tend to dilute that authority rather than increase it.

bakkot commented 6 years ago

JSX?

To my knowledge most consumers of JSX also make use of :-style type annotations, which are currently explicitly forbidden by the spec. I don't think this has created problems for anyone.

I don't think those two things are meaningfully different. Either the spec should forbid both, and people wishing to use build tools to add non-standard syntax which compiles to spec-compliant JS can continue to ignore the part of spec forbidding such extensions just as they do today, or the spec should permit both.

I think @allenwb 's point is that ECMA-262's authority to prevent things is meager to begin with and that expanding this section may tend to dilute that authority rather than increase it.

Yeah; I think this depends on whether we think browsers will be sufficiently motivated to ship non-standard non-proposed syntax that they're willing to ignore that authority. Personally, I don't think they will. If the committee thinks otherwise, certainly we should not pursue this.

ljharb commented 6 years ago

Browsers and all major engines are on the committee - if the committee thinks that forbidding syntax extensions is tenable, how is that not an explicit indicator that the spec indeed does have the authority to do so, granted by the implementations themselves?

rwaldron commented 6 years ago

If ECMA-262 had disallowed all extensions of the language's syntax...

...I'm sure there are more, but you get the idea.


I am the person that originally suggested that the class private fields/methods proposal add a new item to the "Forbidden Extensions" list that would forbid the "shorthand" form as a syntactic extension, that could later be "relaxed" (ie. removed) when/if a new proposal came along to re-introduce a "shorthand" form for accessing private fields/methods.

rwaldron commented 6 years ago

@zenparsing

re:

I think @allenwb 's point is that ECMA-262's authority to prevent things is meager to begin with and that expanding this section may tend to dilute that authority rather than increase it.

Presumably, you're referring to this:

The current "forbidden extensions" were all carefully selected to address very specific concerns. By being limited and targeted they convey that TC39 is serious about the importance of keeping the specific identified behaviors out of the language. Expending it to say something like "no new syntax" means that TC39 is neither serious or realistic when it talks about restricting extensions and makes it more likely that the actual important restriction could be ignored.

In the context of my original suggestion, described above, I disagree with your interpretation, and I believe my strategy fits well within @allenwb's description of the use and intent of Forbidden Extensions.

The proposal put forth in this issue's original post: "everything not permitted is forbidden", is bad for JavaScript.

bakkot commented 6 years ago

@rwaldron, we also wouldn't have to have Annex B.3.3, which I personally think would alone outweigh the benefits of all those extensions by far.

littledan commented 6 years ago

Banning syntax extensions doesn't mean no one should or would extend the syntax. It just means that the extended language would no longer be standards-complaint JavaScript.

JSX and TypeScript both frame themselves as JavaScript extensions, but one is a forbidden extension and the other is permitted. I don't think this distinction is important for their users, though.

For me, one useful thing about this proposal will be being able to share tests for syntax errors between JS implementations. Another useful thing will be to be saying more precisely what it means to be standards-compliant, in particular that extensions need to be standardized to be JavaScript.

anba commented 6 years ago

Banning syntax extensions doesn't mean no one should or would extend the syntax. It just means that the extended language would no longer be standards-complaint JavaScript.

All browsers implement assignments to function calls as runtime errors, whereas the spec requires this to be a parser error. So, does that mean we need to label the JavaScript version implemented in browsers as non-standards-complaint JavaScript?

littledan commented 6 years ago

@anba I don't think that particular deviation from the specification is permitted as a section 16 "language extension", as the specification is explicit about the early ReferenceError in that case (search for the string "Reference Error" to see the occurrences). The specification is very specific:

An implementation must report as an early error any occurrence of a condition that is listed in a “Static Semantics: Early Errors” subclause of this specification.

I'd suggest that we address these sorts of web reality/spec mismatches via pull requests in this repository, rather than by expanding what sorts of language extensions are permitted.

leobalter commented 6 years ago

It just means that the extended language would no longer be standards-complaint JavaScript.

This is a legal concern for any implementation landing Stage 3 or 4 features or changes related to PRs that are not yet on any official release of EcmaScript.

The staging process is possible because we are allowed to keep implementations as legit standards complaint JS while we land features not yet released on new editions.

I urge this is a concern to have legal consulting within the implementations before we say it's ok.

ljharb commented 6 years ago

How is it a legal concern? Are there any engines that have a legal requirement in them to be compliant with the ecmascript standard?

leobalter commented 6 years ago

any new feature before a standard official release is an extension. If we ban extensions all the implementations might not be considered standards complaint anymore, unless they only implement features after the spec releases.

Also, not implementing a syntax feature of any released spec - by any reason - might also be considered an extension. That means, how do we allow not fully implemented engines to be spec complaint? Are all the major engines really ok with that?

bakkot commented 6 years ago

As it says in the original post, doing this at all would require some careful wording to allow browsers to ship stage 3 proposals.

That means, how do we allow not fully implemented engines to be spec complaint?

Such engines are already not spec compliant. The spec does not permit leaving out parts of the language (except Annex B).

littledan commented 5 years ago

What are the next steps on this thread? Does the committee have much appetite for pursuing this path that @bakkot suggested?

michaelficarra commented 3 years ago

Related to this topic, today we talked in the editor call about whether violation of early errors was a permitted extension. We agreed that we would like the editorial freedom to switch normative requirements between the grammar and an early error. This implies that violation of an early error should be a permitted extension in the same way that grammatical extensions are permitted. We did not, however, agree on whether this point was necessary of clarification within the spec, so we will not be making a change. Editor group decision was that since test262 is the only consumer who actually cares about this fact, we would make sure the test262 maintainers understand.

/cc @jmdyck since we talked about this in Matrix

ExE-Boss commented 3 years ago

So if an implementation parses function fn() { "\7"; "use strict"; } without any errors is this considered an extension?

Or it’s an old (ES3) implementation that doesn’t support strict mode at all (e.g.: IE6IE9caniuse and other extremely old browsers).

rwaldron commented 3 years ago

@michaelficarra

We did not, however, agree on whether this point was necessary of clarification within the spec, so we will not be making a change.

The spec is unambiguously clear that what you're describing as "an extension" is actually a conformance violation:

A conforming implementation must, prior to the first evaluation of a Script or Module, validate all of the early error rules of the productions used to parse that Script or Module. If any of the early error rules are violated the Script or Module is invalid and cannot be evaluated.

The extension you describe requires a change to the spec.

To put a finer point on it: there is no such explicit prose that says "a conforming implementation must not extend the grammar of the language" (except where it does say that, in Forbidden Extensions), which is why new syntactic forms that don't violate the existing grammar are allowed.


As an aside, I find this pronouncement rather disingenuous considering one of the editors works on the only implementation that willfully, intentionally violates this unambiguously defined component of the specification.

bakkot commented 3 years ago

In my experience in TC39 the decision about whether to make something fail to match the grammar or be an Early Error has rested purely on which was simpler and clearer to specify, and not at all about what extensions we intended to forbid. So while I respect that a strict reading of the requirements for conformance differentiates between those inputs which simply fail to match the grammar and those which are forbidden with Early Errors, I do not think that distinction is actually meaningful to the large majority of consumers of the specification.

Moreover, as a user of the language, I don't see why I would care. For a user, implementations which relax Early Errors are no more or less interoperable than those which add new productions to the grammar.

the only implementation that willfully, intentionally violates this unambiguously defined component of the specification.

This continues to be an aside, but: all major implementation intentionally allow if (false) { f() = 0; }, which is specified to be an Early Error. So I'm fairly certain that's false as a question of fact.

rwaldron commented 3 years ago

So I'm fairly certain that's false as a question of fact.

How about this fact: it was V8 that pressured Test262 into making the infamous $DONOTEVALUATE() hook so that their own Test262 runner could override the definition with a no-op. This replaced throw "Test262: This statement should not be evaluated."; in all tests that were verifying the conformance of early/parse errors. Because V8 defers the parsing of code within function bodies until sometime later, it would fail those tests because the test would throw an exception once evaluation began. With an overridable harness api hook, V8 was free to shut off the part of that test that exposed its lack of specification conformance. No other engine uses that hook.

Frankly, I completely agree with your points here:

I do not think that distinction is actually meaningful to the large majority of consumers of the specification.

Moreover, as a user of the language, I don't see why I would care.

But those do not sufficiently counter my argument (as much as I agree with them). Perhaps my point wasn't clear, so I will attempt to restate it: The change of understanding that @michaelficarra describes requires a change to the spec, not a hand-wavy agreement. And to further clarify: I'm not even opposed to that change!

bakkot commented 3 years ago

How about this fact: it was V8 that pressured Test262 into making the infamous $DONOTEVALUATE() hook so that their own Test262 runner could override the definition with a no-op. This replaced throw "Test262: This statement should not be evaluated."; in all tests that were verifying the conformance of early/parse errors. Because V8 defers the parsing of code within function bodies until sometime later, it would fail those tests because the test would throw an exception once evaluation began. With an overridable harness api hook, V8 was free to shut off the part of that test that exposed its lack of specification conformance. No other engine uses that hook.

Well, we're pretty far afield now, but you will perhaps be happy to learn that nearly a full decade after it was reported V8 has fixed the bug with Early Errors for RegExp literals as of a few months ago, and no longer uses the FAIL_PHASE_ONLY outcome in their test status at all (and hence presumably also does not use the hook).

(I'm still grateful to have that hook, though, because I too have been in the position of having a partially non-conforming implementation which I nevertheless wanted to test as much as I could.)

That one is kind of a funny case, because the Early Error is specified in terms of a grammar (it's an Early Error if a RegExp literal fails to conform to the Pattern grammar), but if conforming implementations are permitted to extend the Pattern grammar, which I believe they are, then they could reasonably claim to still be enforcing the Early Error while allowing additional RegExp syntax. If the intent of the specification is to disallow extensions to the RegExp grammar, that's not clear to me.

Anyway, as a user of the language, I'd've wanted V8 to fix the bug in question even if it was still "conforming" not to enforce those Early Errors, because it's not interoperable.


Perhaps my point wasn't clear, so I will attempt to restate it: The change of understanding that @michaelficarra describes requires a change to the spec, not a hand-wavy agreement.

OK. I agree with that, according to what's currently in the specification. Thanks for pointing that relaxing Early Errors is currently a forbidden extension, whereas adding new productions to the grammar is not. I don't think this distinction is useful, but I agree it's currently there.

jmdyck commented 3 years ago

if conforming implementations are permitted to extend the Pattern grammar, which I believe they are, ...

17 Error Handling and Language Extensions says: "Except as restricted in 17.1, a host or implementation may extend ... regular expression pattern or flag syntax."

leobalter commented 3 years ago

This discussion took a turn different from what I wanted to constructively discuss.

I'm retracting my comments above and please ignore my messages. Thanks for understanding.

michaelficarra commented 3 years ago

We discussed this in the editor call. There are effectively two kinds of early errors: those which describe committee intent and which should never be violated (mostly or entirely strict mode restrictions), and those which are effectively interchangeable with grammar restrictions and which may be violated. We would like to change the requirement about validating early errors to only refer to the former. Once we do that, we'd like to ask test262 to move any tests covering the latter to a separate directory (and importantly not delete them).

leobalter commented 3 years ago

@michaelficarra maybe you might not need a separate directory but some sort of flag. The changes in the test meta should help some sort of organization of the test files, but I'm not the one to have any final decision for test262.

bakkot commented 3 years ago

To be clear, when @michaelficarra says "may be violated", he means that we don't think these certain of these errors were intended to restrict allowable extensions, even though they do according to the spec as written and changing that would require consensus.

Once we do that, we'd like to ask test262 to move any tests covering the latter to a separate directory (and importantly not delete them).

FWIW I think it's fine if test262 leaves the tests where they are, but I don't mind if the tests end up in a different directory or flagged or whatever as long as they're still available. I just don't want any changes to the set of forbidden extensions we contemplate here to lead to fewer tests being available.

leobalter commented 3 years ago

I believe I agree with @michaelficarra's comment but I'd like some clarification on what is considered for those which are effectively interchangeable with grammar restrictions and which may be violated. Perhaps I have a different interpretation of what goes into this bucket.

michaelficarra commented 3 years ago

maybe you might not need a separate directory but some sort of flag

Yeah that works fine. I just meant some way to distinguish the tests.