test262: test262/test/language/global-code/new.target-arrow.js
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 15 Apr 2017 22:44:02 +0000 (22:44 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 15 Apr 2017 22:44:02 +0000 (22:44 +0000)
https://bugs.webkit.org/show_bug.cgi?id=170872

Patch by Joseph Pecoraro <pecoraro@apple.com> on 2017-04-15
Reviewed by Saam Barati.

JSTests:

* stress/async-arrow-functions-lexical-new.target-binding.js:
(shouldThrowAsync): Deleted.
(shouldThrowAsync.async): Deleted.
This code should have thrown a SyntaxError. Instead it was throwing
a ReferenceError for the internal @newTargetLocal variable.

* stress/new-target-syntax-errors.js:
Cover the arrow function in global code cases.

* ChakraCore.yaml:
* ChakraCore/test/es6/globalLambdaNewTargetSyntaxError.baseline-jsc:
We now pass with an expected SyntaxError. Our error message is different.

* test262.yaml:

Source/JavaScriptCore:

* parser/Parser.cpp:
(JSC::Parser<LexerType>::Parser):
Mark the global code scope.

(JSC::Parser<LexerType>::parseMemberExpression):
If new.target is detected in an arrow function defined in global scope
throw a SyntaxError.

* parser/Parser.h:
(JSC::Scope::Scope):
(JSC::Scope::setIsGlobalCodeScope):
(JSC::Scope::isGlobalCodeScope):
Marker for a global code scope.

* parser/ParserModes.h:
(JSC::isModuleParseMode):
(JSC::isProgramParseMode):
(JSC::isProgramOrModuleParseMode):
Helper for detecting global code based on parse mode.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@215395 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JSTests/ChakraCore.yaml
JSTests/ChakraCore/test/es6/globalLambdaNewTargetSyntaxError.baseline-jsc
JSTests/ChangeLog
JSTests/stress/async-arrow-functions-lexical-new.target-binding.js
JSTests/stress/new-target-syntax-errors.js
JSTests/test262.yaml
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/Parser.h
Source/JavaScriptCore/parser/ParserModes.h

index 6792f09..0ab84ab 100644 (file)
   # On line 254, JSC throws error during parsing while Chakra throws at runtime.
   cmd: runChakra :skip, "NoException", "", ["../UnitTestFramework/UnitTestFramework.js"]
 - path: ChakraCore/test/es6/globalLambdaNewTargetSyntaxError.js
-  cmd: runChakra :baseline, "ReferenceError", "globalLambdaNewTargetSyntaxError.baseline-jsc", []
+  cmd: runChakra :baseline, "SyntaxError", "globalLambdaNewTargetSyntaxError.baseline-jsc", []
 - path: ChakraCore/test/es6/globalNewTargetSyntaxError.js
   cmd: runChakra :baseline, "SyntaxError", "globalNewTargetSyntaxError.baseline-jsc", []
 - path: ChakraCore/test/es6/globalCatchNewTargetSyntaxError.js
index a6cd2ba..fc03dab 100644 (file)
@@ -1,3 +1,2 @@
-Exception: ReferenceError: Can't find private variable: @newTargetLocal
-f@globalLambdaNewTargetSyntaxError.js:6:9
-global code@globalLambdaNewTargetSyntaxError.js:7:2
+Exception: SyntaxError: new.target is not valid inside arrow functions in global code.
+at globalLambdaNewTargetSyntaxError.js:6
index ac9d27c..653d35b 100644 (file)
@@ -1,3 +1,25 @@
+2017-04-15  Joseph Pecoraro  <pecoraro@apple.com>
+
+        test262: test262/test/language/global-code/new.target-arrow.js
+        https://bugs.webkit.org/show_bug.cgi?id=170872
+
+        Reviewed by Saam Barati.
+
+        * stress/async-arrow-functions-lexical-new.target-binding.js:
+        (shouldThrowAsync): Deleted.
+        (shouldThrowAsync.async): Deleted.
+        This code should have thrown a SyntaxError. Instead it was throwing
+        a ReferenceError for the internal @newTargetLocal variable.
+
+        * stress/new-target-syntax-errors.js:
+        Cover the arrow function in global code cases.
+
+        * ChakraCore.yaml:
+        * ChakraCore/test/es6/globalLambdaNewTargetSyntaxError.baseline-jsc:
+        We now pass with an expected SyntaxError. Our error message is different.
+
+        * test262.yaml:
+
 2017-04-14  Saam Barati  <sbarati@apple.com>
 
         ParseInt intrinsic in DFG backend doesn't properly flush its operands
index e0e9d83..843a737 100644 (file)
@@ -20,21 +20,6 @@ function shouldBeAsync(expected, run, msg) {
     shouldBe(expected, actual, msg);
 }
 
-function shouldThrowAsync(run, errorType, message) {
-    let actual;
-    var hadError = false;
-    run().then(function(value) { actual = value; },
-               function(error) { hadError = true; actual = error; });
-    drainMicrotasks();
-
-    if (!hadError)
-        throw new Error("Expected " + run + "() to throw " + errorType.name + ", but did not throw.");
-    if (!(actual instanceof errorType))
-        throw new Error("Expected " + run + "() to throw " + errorType.name + ", but threw '" + actual + "'");
-    if (message !== void 0 && actual.message !== message)
-        throw new Error("Expected " + run + "() to throw '" + message + "', but threw '" + actual.message + "'");
-}
-
 function C1() {
     return async () => await new.target;
 }
@@ -56,6 +41,3 @@ shouldBeAsync(C2, new C2());
 shouldBeAsync(undefined, C2());
 shouldBeAsync(C2WithAwait, new C2WithAwait());
 shouldBeAsync(undefined, C2WithAwait());
-
-shouldThrowAsync(async () => await new.target, ReferenceError);
-shouldThrowAsync(async () => { return await new.target; }, ReferenceError);
index 3f880de..bc1c238 100644 (file)
@@ -1,3 +1,8 @@
+function assert(b) {
+    if (!b)
+        throw new Error("Bad assertion")
+}
+
 function shouldBeSyntaxError(str) {
     let failed = true;
     try {
@@ -84,3 +89,88 @@ for (let operator of prePostFixOperators) {
 }
 
 shouldBeSyntaxError(`({foo: new.target} = {foo:20})`);
+
+// Scripts - 15.1.1 Static Semantics: Early Errors
+// https://tc39.github.io/ecma262/#sec-scripts-static-semantics-early-errors
+//
+// Modules - 15.2.1.1 Static Semantics: Early Errors
+// https://tc39.github.io/ecma262/#sec-module-semantics-static-semantics-early-errors
+//
+// new.target is not allowed in arrow functions in global scope.
+
+let sawSyntaxError;
+
+sawSyntaxError = false;
+try {
+    eval(`() => new.target`);
+} catch(e) {
+    sawSyntaxError = e instanceof SyntaxError;
+}
+assert(sawSyntaxError);
+
+sawSyntaxError = false;
+try {
+    eval(`() => { new.target }`);
+} catch(e) {
+    sawSyntaxError = e instanceof SyntaxError;
+}
+assert(sawSyntaxError);
+
+sawSyntaxError = false;
+try {
+    eval(`async () => new.target`);
+} catch(e) {
+    sawSyntaxError = e instanceof SyntaxError;
+}
+assert(sawSyntaxError);
+
+sawSyntaxError = false;
+try {
+    eval(`async () => { new.target }`);
+} catch(e) {
+    sawSyntaxError = e instanceof SyntaxError;
+}
+assert(sawSyntaxError);
+
+sawSyntaxError = false;
+try {
+    eval(`async () => await new.target`);
+} catch(e) {
+    sawSyntaxError = e instanceof SyntaxError;
+}
+assert(sawSyntaxError);
+
+sawSyntaxError = false;
+try {
+    eval(`async () => { await new.target }`);
+} catch(e) {
+    sawSyntaxError = e instanceof SyntaxError;
+}
+assert(sawSyntaxError);
+
+let sawError = false;
+try {
+    new Function(`() => new.target`);
+    new Function(`() => { new.target }`);
+    new Function(`async () => new.target`);
+    new Function(`async () => { new.target }`);
+    new Function(`async () => await new.target`);
+    new Function(`async () => { await new.target }`);
+
+    function f() { () => new.target };
+    function f() { () => { new.target } };
+    function f() { async () => new.target };
+    function f() { async () => { new.target } };
+    function f() { async () => await new.target };
+    function f() { async () => { await new.target } };
+
+    (function() { eval(`() => new.target`) })();
+    (function() { eval(`() => { new.target }`) })();
+    (function() { eval(`async () => new.target`) })();
+    (function() { eval(`async () => { new.target }`) })();
+    (function() { eval(`async () => await new.target`) })();
+    (function() { eval(`async () => { await new.target }`) })();
+} catch (e) {
+    sawError = true;
+}
+assert(!sawError);
index 138dfe6..6d1fdb6 100644 (file)
 - path: test262/test/language/global-code/import.js
   cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:strict]
 - path: test262/test/language/global-code/new.target-arrow.js
-  cmd: runTest262 :fail, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], []
+  cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], []
 - path: test262/test/language/global-code/new.target-arrow.js
-  cmd: runTest262 :fail, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:strict]
+  cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:strict]
 - path: test262/test/language/global-code/new.target.js
   cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], []
 - path: test262/test/language/global-code/new.target.js
index 84ea981..36d5aba 100644 (file)
@@ -1,3 +1,30 @@
+2017-04-15  Joseph Pecoraro  <pecoraro@apple.com>
+
+        test262: test262/test/language/global-code/new.target-arrow.js
+        https://bugs.webkit.org/show_bug.cgi?id=170872
+
+        Reviewed by Saam Barati.
+
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::Parser):
+        Mark the global code scope.
+
+        (JSC::Parser<LexerType>::parseMemberExpression):
+        If new.target is detected in an arrow function defined in global scope
+        throw a SyntaxError.
+
+        * parser/Parser.h:
+        (JSC::Scope::Scope):
+        (JSC::Scope::setIsGlobalCodeScope):
+        (JSC::Scope::isGlobalCodeScope):
+        Marker for a global code scope.
+
+        * parser/ParserModes.h:
+        (JSC::isModuleParseMode):
+        (JSC::isProgramParseMode):
+        (JSC::isProgramOrModuleParseMode):
+        Helper for detecting global code based on parse mode.
+
 2017-04-14  Nikita Vasilyev  <nvasilyev@apple.com>
 
         Web Inspector: WebSockets: messages with non-latin letters are displayed incorrectly
index b77f877..f829acb 100644 (file)
@@ -147,9 +147,12 @@ Parser<LexerType>::Parser(VM* vm, const SourceCode& source, JSParserBuiltinMode
     if (strictMode == JSParserStrictMode::Strict)
         scope->setStrictMode();
 
-    if (parseMode == SourceParseMode::ModuleAnalyzeMode || parseMode == SourceParseMode::ModuleEvaluateMode)
+    if (isModuleParseMode(parseMode))
         m_moduleScopeData = ModuleScopeData::create();
 
+    if (isProgramOrModuleParseMode(parseMode))
+        scope->setIsGlobalCodeScope();
+
     next();
 }
 
@@ -4404,10 +4407,13 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpres
         if (match(IDENT)) {
             const Identifier* ident = m_token.m_data.ident;
             if (m_vm->propertyNames->target == *ident) {
-                semanticFailIfFalse(currentScope()->isFunction() || closestParentOrdinaryFunctionNonLexicalScope()->evalContextType() == EvalContextType::FunctionEvalContext, "new.target is only valid inside functions");
+                ScopeRef closestOrdinaryFunctionScope = closestParentOrdinaryFunctionNonLexicalScope();
+                semanticFailIfFalse(currentScope()->isFunction() || closestOrdinaryFunctionScope->evalContextType() == EvalContextType::FunctionEvalContext, "new.target is only valid inside functions");
                 baseIsNewTarget = true;
-                if (currentScope()->isArrowFunction())
+                if (currentScope()->isArrowFunction()) {
+                    semanticFailIfFalse(!closestOrdinaryFunctionScope->isGlobalCodeScope() || closestOrdinaryFunctionScope->evalContextType() == EvalContextType::FunctionEvalContext, "new.target is not valid inside arrow functions in global code");
                     currentScope()->setInnerArrowFunctionUsesNewTarget();
+                }
                 base = context.createNewTargetExpr(location);
                 newCount--;
                 next();
index e89a874..09b710a 100644 (file)
@@ -172,6 +172,7 @@ public:
         , m_isAsyncFunction(isAsyncFunction)
         , m_isAsyncFunctionBoundary(false)
         , m_isLexicalScope(false)
+        , m_isGlobalCodeScope(false)
         , m_isFunctionBoundary(false)
         , m_isValidStrictMode(true)
         , m_hasArguments(false)
@@ -205,6 +206,7 @@ public:
         , m_isAsyncFunction(other.m_isAsyncFunction)
         , m_isAsyncFunctionBoundary(other.m_isAsyncFunctionBoundary)
         , m_isLexicalScope(other.m_isLexicalScope)
+        , m_isGlobalCodeScope(other.m_isGlobalCodeScope)
         , m_isFunctionBoundary(other.m_isFunctionBoundary)
         , m_isValidStrictMode(other.m_isValidStrictMode)
         , m_hasArguments(other.m_hasArguments)
@@ -313,6 +315,9 @@ public:
 
     bool hasArguments() const { return m_hasArguments; }
 
+    void setIsGlobalCodeScope() { m_isGlobalCodeScope = true; }
+    bool isGlobalCodeScope() const { return m_isGlobalCodeScope; }
+
     void setIsLexicalScope() 
     { 
         m_isLexicalScope = true;
@@ -800,6 +805,7 @@ private:
     bool m_isAsyncFunction;
     bool m_isAsyncFunctionBoundary;
     bool m_isLexicalScope;
+    bool m_isGlobalCodeScope;
     bool m_isFunctionBoundary;
     bool m_isValidStrictMode;
     bool m_hasArguments;
index 6da8837..5929846 100644 (file)
@@ -173,18 +173,25 @@ ALWAYS_INLINE bool isArrowFunctionParseMode(SourceParseMode parseMode)
         SourceParseMode::AsyncArrowFunctionBodyMode).contains(parseMode);
 }
 
-
 ALWAYS_INLINE bool isModuleParseMode(SourceParseMode parseMode) 
 { 
     return SourceParseModeSet( 
         SourceParseMode::ModuleAnalyzeMode, 
         SourceParseMode::ModuleEvaluateMode).contains(parseMode); 
-} 
+}
 
 ALWAYS_INLINE bool isProgramParseMode(SourceParseMode parseMode) 
 { 
     return SourceParseModeSet(SourceParseMode::ProgramMode).contains(parseMode); 
-} 
+}
+
+ALWAYS_INLINE bool isProgramOrModuleParseMode(SourceParseMode parseMode)
+{
+    return SourceParseModeSet(
+        SourceParseMode::ProgramMode, 
+        SourceParseMode::ModuleAnalyzeMode, 
+        SourceParseMode::ModuleEvaluateMode).contains(parseMode); 
+}
 
 ALWAYS_INLINE ConstructAbility constructAbilityForParseMode(SourceParseMode parseMode) 
 {