Changeset 220481 in webkit


Ignore:
Timestamp:
Aug 9, 2017 2:34:20 PM (7 years ago)
Author:
caitp@igalia.com
Message:

Early error on ANY operator before new.target
https://bugs.webkit.org/show_bug.cgi?id=157970

Reviewed by Saam Barati.

Instead of throwing if any unary operator precedes new.target, only
throw if the unary operator updates the reference.

The following become legal in JSC:

`
!new.target
~new.target
typeof new.target
delete new.target
void new.target
`

All of which are legal in v8 and SpiderMonkey in strict and sloppy mode

JSTests:

  • stress/new-target-syntax-errors.js:
  • stress/new-target.js:

Source/JavaScriptCore:

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseUnaryExpression):

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r220458 r220481  
     12017-08-09  Caitlin Potter  <caitp@igalia.com>
     2
     3        Early error on ANY operator before new.target
     4        https://bugs.webkit.org/show_bug.cgi?id=157970
     5
     6        Reviewed by Saam Barati.
     7
     8        Instead of throwing if any unary operator precedes new.target, only
     9        throw if the unary operator updates the reference.
     10
     11        The following become legal in JSC:
     12
     13        ```
     14        !new.target
     15        ~new.target
     16        typeof new.target
     17        delete new.target
     18        void new.target
     19        ```
     20
     21        All of which are legal in v8 and SpiderMonkey in strict and sloppy mode
     22
     23        * stress/new-target-syntax-errors.js:
     24        * stress/new-target.js:
     25
    1262017-08-09  Ryan Haddad  <ryanhaddad@apple.com>
    227
  • trunk/JSTests/stress/default-value-parsing-should-propagate-error.js

    r200293 r220481  
    1717function f()
    1818{
    19     ({v = (typeof new.target)} = {})
     19    ({v = (++new.target)} = {})
    2020}
    2121`, `SyntaxError: Unexpected token '='. Expected a ':' following the property name 'v'.`);
  • trunk/JSTests/stress/new-target-syntax-errors.js

    r215395 r220481  
    8989}
    9090
     91let otherUnaryOperators = ["!", "~", "+", "-", "typeof ", "void ", "delete "];
     92for (let operator of otherUnaryOperators) {
     93    function strict(body) { return `"use strict" ${body}`; }
     94    let functionBody = `${operator}new.target`;
     95    shouldNotBeSyntaxError(functionBody);
     96    shouldNotBeSyntaxError(strict(functionBody));
     97}
     98
    9199shouldBeSyntaxError(`({foo: new.target} = {foo:20})`);
    92100
  • trunk/JSTests/stress/new-target.js

    r198980 r220481  
    2121
    2222function test(result, expected, message) {
    23     if (result !== expected)
     23    if (result !== expected && !(expected !== expected && result !== result))
    2424        throw "Error: " + message + ". was: " + result + " wanted: " + expected;
    2525}
     
    126126};
    127127newTargetInFunctionInEval();
     128
     129function testUnaryOps() {
     130  var result;
     131  function call(f) { f(); return result; }
     132  function construct(f) { new f(); return result; }
     133 
     134  function unaryExclamation() { result = !new.target; }
     135  test(construct(unaryExclamation), false, "`!new.target` should be false when new.target is not undefined");
     136  test(call(unaryExclamation), true, "`!new.target` should be true when new.target is undefined");
     137
     138  function unaryBitwiseNot() { result = ~new.target; }
     139  test(construct(unaryBitwiseNot), -1, "`~new.target` should be -1");
     140  test(call(unaryBitwiseNot), -1, "`~new.target` should be -1");
     141
     142  function unaryTypeof() { result = typeof new.target; }
     143  test(construct(unaryTypeof), "function", "`typeof new.target` should be 'function' when new.target is not undefined");
     144  test(call(unaryTypeof), "undefined", "`typeof new.target` should be 'undefined' when new.target is undefined");
     145
     146  function unaryVoid() { result = void new.target; }
     147  test(construct(unaryVoid), undefined, "`void new.target` should be undefined");
     148  test(call(unaryVoid), undefined, "`void new.target` should be undefined");
     149
     150  function unaryAbs() { result = +new.target; }
     151  test(construct(unaryAbs), NaN, "+new.target should be NaN");
     152  test(call(unaryAbs), NaN, "+new.target should be NaN");
     153
     154  function unaryNeg() { result = -new.target; }
     155  test(construct(unaryNeg), NaN, "-new.target should be NaN");
     156  test(call(unaryNeg), NaN, "-new.target should be NaN");
     157
     158  // Multiple variations of delete are tested for completeness:
     159  function unaryDelete() { result = delete new.target; }
     160  function strictUnaryDelete() { "use strict"; result = delete new.target; }
     161
     162  // If Type(ref) is not Reference, return true. (per #sec-delete-operator-runtime-semantics-evaluation)
     163  test(construct(unaryDelete), true, "`delete new.target` should be true");
     164  test(call(unaryDelete), true, "`delete new.target` should be true");
     165  test(construct(strictUnaryDelete), true, "`delete new.target` should be true");
     166  test(call(strictUnaryDelete), true, "`delete new.target` should be true");
     167
     168  var unaryDeleteProp = function unaryDeleteProp() { result = delete new.target.prop; }
     169  var strictUnaryDeleteProp = function strictUnaryDeleteProp() { "use strict"; result = delete new.target.prop; }
     170  unaryDeleteProp.prop = 1;
     171  test(construct(unaryDeleteProp), true, "`delete new.target.prop` should be true when new.target is not undefined and prop is a configurable property");
     172  strictUnaryDeleteProp.prop = 1;
     173  test(construct(strictUnaryDeleteProp), true, "`delete new.target.prop` should be true when new.target is not undefined and prop is a configurable property");
     174 
     175  unaryDeleteProp = function unaryDeleteProp() { result = delete new.target.prop; }
     176  Object.defineProperty(unaryDeleteProp, "prop", { value: false, configurable: false });
     177  test(construct(unaryDeleteProp), false, "`delete new.target.prop` should be false when new.target is not undefined and prop is a non-configurable property");
     178
     179  strictUnaryDeleteProp = function strictUnaryDeleteProp() { "use strict"; result = delete new.target.prop; }
     180  // If deleteStatus is false and IsStrictReference(ref) is true, throw a TypeError exception.
     181  Object.defineProperty(strictUnaryDeleteProp, "prop", { value: false, configurable: false });
     182  try {
     183    var passed = false;
     184    construct(strictUnaryDeleteProp);
     185  } catch (e) {
     186    passed = e instanceof TypeError && e.message.indexOf("delete") >= 0;
     187  }
     188  test(passed, true, "`delete new.target.prop` should throw a TypeError in strict code when prop is a non-configurable property");
     189
     190  unaryDeleteProp = function unaryDeleteProp() { result = delete new.target.prop; }
     191  unaryDeleteProp.prop = 1;
     192  try {
     193    var passed = false;
     194    call(unaryDeleteProp);
     195  } catch (e) {
     196    passed = e instanceof TypeError && e.message.indexOf("undefined") >= 0;
     197  }
     198  test(passed, true, "`delete new.target.prop` should throw a TypeError when new.target is undefined");
     199}
     200testUnaryOps();
     201
  • trunk/Source/JavaScriptCore/ChangeLog

    r220478 r220481  
     12017-08-09  Caitlin Potter  <caitp@igalia.com>
     2
     3        Early error on ANY operator before new.target
     4        https://bugs.webkit.org/show_bug.cgi?id=157970
     5
     6        Reviewed by Saam Barati.
     7
     8        Instead of throwing if any unary operator precedes new.target, only
     9        throw if the unary operator updates the reference.
     10
     11        The following become legal in JSC:
     12
     13        ```
     14        !new.target
     15        ~new.target
     16        typeof new.target
     17        delete new.target
     18        void new.target
     19        ```
     20
     21        All of which are legal in v8 and SpiderMonkey in strict and sloppy mode
     22
     23        * parser/Parser.cpp:
     24        (JSC::Parser<LexerType>::parseUnaryExpression):
     25
    1262017-08-09  Sam Weinig  <sam@webkit.org>
    227
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r220323 r220481  
    48844884        failWithMessage("Cannot parse member expression");
    48854885    }
    4886     if (UNLIKELY(lastOperator && context.isNewTarget(expr)))
     4886    if (UNLIKELY(isUpdateOp(static_cast<JSTokenType>(lastOperator)) && context.isNewTarget(expr)))
    48874887        internalFailWithMessage(false, "new.target can't come after a prefix operator");
    48884888    bool isEvalOrArguments = false;
Note: See TracChangeset for help on using the changeset viewer.