Title: [196261] trunk
Revision
196261
Author
commit-qu...@webkit.org
Date
2016-02-08 11:29:24 -0800 (Mon, 08 Feb 2016)

Log Message

[ES6] Arrow function syntax. Using 'super' in arrow function that declared out of the class should lead to Syntax error
https://bugs.webkit.org/show_bug.cgi?id=150893

Patch by Skachkov Oleksandr <gskach...@gmail.com> on 2016-02-08
Reviewed by Saam Barati.
Source/_javascript_Core:

'super' and 'super()' inside of the arrow function should lead to syntax error if they are used
out of the class context or they wrapped by ordinary function. Now JSC returns ReferenceError but
should return SyntaxError according to the following specs:
http://www.ecma-international.org/ecma-262/6.0/#sec-function-definitions-static-semantics-early-errors
and http://www.ecma-international.org/ecma-262/6.0/#sec-arrow-function-definitions-runtime-semantics-evaluation
Curren patch implemented only one case when super/super() are used inside of the arrow function
Case when super/super() are used within the eval:
   class A {}
   class B extends A {
       costructor() { eval("super()");}
   }
is not part of this patch and will be implemented in this issue https://bugs.webkit.org/show_bug.cgi?id=153864.
The same for case when eval with super/super() is invoked in arrow function will be
implemented in issue https://bugs.webkit.org/show_bug.cgi?id=153977.

* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseFunctionInfo):
* parser/Parser.h:
(JSC::Scope::Scope):
(JSC::Scope::setExpectedSuperBinding):
(JSC::Scope::expectedSuperBinding):
(JSC::Scope::setConstructorKind):
(JSC::Scope::constructorKind):
(JSC::Parser::closestParentNonArrowFunctionNonLexicalScope):
* tests/stress/arrowfunction-lexical-bind-supercall-4.js:
* tests/stress/arrowfunction-lexical-bind-superproperty.js:

LayoutTests:

Adding tests for using of the 'super' inside of the arrow function

* js/arrowfunction-superproperty-expected.txt:
* js/arrowfunction-syntax-errors-expected.txt:
* js/script-tests/arrowfunction-superproperty.js:
* js/script-tests/arrowfunction-syntax-errors.js:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (196260 => 196261)


--- trunk/LayoutTests/ChangeLog	2016-02-08 19:27:01 UTC (rev 196260)
+++ trunk/LayoutTests/ChangeLog	2016-02-08 19:29:24 UTC (rev 196261)
@@ -1,3 +1,17 @@
+2016-02-08  Skachkov Oleksandr  <gskach...@gmail.com>
+
+        [ES6] Arrow function syntax. Using 'super' in arrow function that declared out of the class should lead to Syntax error
+        https://bugs.webkit.org/show_bug.cgi?id=150893
+
+        Reviewed by Saam Barati.
+       
+        Adding tests for using of the 'super' inside of the arrow function
+ 
+        * js/arrowfunction-superproperty-expected.txt:
+        * js/arrowfunction-syntax-errors-expected.txt:
+        * js/script-tests/arrowfunction-superproperty.js:
+        * js/script-tests/arrowfunction-syntax-errors.js:
+
 2016-02-08  Adrien Plazas  <apla...@igalia.com>
 
         Timeouts in tests because of non implemented UIScriptController::singleTapAtPoint()

Modified: trunk/LayoutTests/js/arrowfunction-superproperty-expected.txt (196260 => 196261)


--- trunk/LayoutTests/js/arrowfunction-superproperty-expected.txt	2016-02-08 19:27:01 UTC (rev 196260)
+++ trunk/LayoutTests/js/arrowfunction-superproperty-expected.txt	2016-02-08 19:29:24 UTC (rev 196261)
@@ -9,7 +9,6 @@
 PASS f.prop is expectedValue + "-" + expectedValue
 PASS f.prop is expectedValue + "-" + "new-value"
 PASS (new F()).getParentValue() is expectedValue
-PASS (new F()).getParentValueWithError()() threw exception TypeError: undefined is not an object (evaluating 'super.getValue').
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/js/arrowfunction-syntax-errors-expected.txt (196260 => 196261)


--- trunk/LayoutTests/js/arrowfunction-syntax-errors-expected.txt	2016-02-08 19:27:01 UTC (rev 196260)
+++ trunk/LayoutTests/js/arrowfunction-syntax-errors-expected.txt	2016-02-08 19:29:24 UTC (rev 196261)
@@ -131,6 +131,19 @@
 PASS var arr2 = {a, b} => a + b; threw exception SyntaxError: Unexpected token '=>'. Expected ';' after variable declaration..
 PASS var arr3 = {c:a,d:b} => a + b; threw exception SyntaxError: Unexpected token '=>'. Expected ';' after variable declaration..
 PASS var arr3 = {c:b,d:a} => a + b; threw exception SyntaxError: Unexpected token '=>'. Expected ';' after variable declaration..
+PASS var arr4 = () => { super(); }; threw exception SyntaxError: Cannot call super() outside of a class constructor..
+PASS var arr4 = () => { super; }; threw exception SyntaxError: Cannot reference super..
+PASS var arr5 = () => { super.getValue(); }; threw exception SyntaxError: super can only be used in a method of a derived class..
+PASS var arr6 = () =>  super(); threw exception SyntaxError: Cannot call super() outside of a class constructor..
+PASS var arr7 = () =>  super; threw exception SyntaxError: Cannot reference super..
+PASS var arr8 = () =>  super.getValue(); threw exception SyntaxError: super can only be used in a method of a derived class..
+PASS class A { constructor() { function a () { return () => { super(); };}} threw exception SyntaxError: Cannot call super() outside of a class constructor..
+PASS class B { constructor() { function b () { return () => { super; }; }; }} threw exception SyntaxError: Cannot reference super..
+PASS class C { constructor() { function c () { return () => { super.getValue(); };}} threw exception SyntaxError: super can only be used in a method of a derived class..
+PASS class D { constructor() { function a () { return () => super(); }} threw exception SyntaxError: Cannot call super() outside of a class constructor..
+PASS class E { constructor() { function b () { return () => super; }; }} threw exception SyntaxError: Cannot reference super..
+PASS class F { constructor() { function c () { return () => super.getValue(); }} threw exception SyntaxError: super can only be used in a method of a derived class..
+PASS class G {}; class G2 extends G { getValue() { function c () { return () => super.getValue(); }} threw exception SyntaxError: super can only be used in a method of a derived class..
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/js/script-tests/arrowfunction-superproperty.js (196260 => 196261)


--- trunk/LayoutTests/js/script-tests/arrowfunction-superproperty.js	2016-02-08 19:27:01 UTC (rev 196260)
+++ trunk/LayoutTests/js/script-tests/arrowfunction-superproperty.js	2016-02-08 19:29:24 UTC (rev 196261)
@@ -63,12 +63,6 @@
         let arrow = () => () => super.getValue();
         return arrow()();
     }
-    getParentValueWithError() {
-        var f =  function () {
-            return () => super.getValue();
-        };
-        return f();
-    }
  };
 
 shouldBe('(new B()).getValueParentFunction()', 'expectedValue');
@@ -90,6 +84,4 @@
 
 shouldBe('(new F()).getParentValue()', 'expectedValue');
 
-shouldThrow('(new F()).getParentValueWithError()()');
-
 var successfullyParsed = true;

Modified: trunk/LayoutTests/js/script-tests/arrowfunction-syntax-errors.js (196260 => 196261)


--- trunk/LayoutTests/js/script-tests/arrowfunction-syntax-errors.js	2016-02-08 19:27:01 UTC (rev 196260)
+++ trunk/LayoutTests/js/script-tests/arrowfunction-syntax-errors.js	2016-02-08 19:29:24 UTC (rev 196261)
@@ -48,4 +48,21 @@
 shouldThrow('var arr3 = {c:a,d:b} => a + b;');
 shouldThrow('var arr3 = {c:b,d:a} => a + b;');
 
+shouldThrow('var arr4 = () => { super(); };', '"SyntaxError: Cannot call super() outside of a class constructor."');
+shouldThrow('var arr4 = () => { super; };', '"SyntaxError: Cannot reference super."');
+shouldThrow('var arr5 = () => { super.getValue(); };', '"SyntaxError: super can only be used in a method of a derived class."');
+
+shouldThrow('var arr6 = () =>  super();', '"SyntaxError: Cannot call super() outside of a class constructor."');
+shouldThrow('var arr7 = () =>  super;', '"SyntaxError: Cannot reference super."');
+shouldThrow('var arr8 = () =>  super.getValue();', '"SyntaxError: super can only be used in a method of a derived class."');
+
+shouldThrow('class A { constructor() { function a () { return () => { super(); };}}', '"SyntaxError: Cannot call super() outside of a class constructor."');
+shouldThrow('class B { constructor() { function b () { return () => { super; }; }; }}', '"SyntaxError: Cannot reference super."');
+shouldThrow('class C { constructor() { function c () { return () => { super.getValue(); };}}', '"SyntaxError: super can only be used in a method of a derived class."');
+
+shouldThrow('class D { constructor() { function a () { return () => super(); }}', '"SyntaxError: Cannot call super() outside of a class constructor."');
+shouldThrow('class E { constructor() { function b () { return () => super; }; }}', '"SyntaxError: Cannot reference super."');
+shouldThrow('class F { constructor() { function c () { return () => super.getValue(); }}', '"SyntaxError: super can only be used in a method of a derived class."');
+shouldThrow('class G {}; class G2 extends G { getValue() { function c () { return () => super.getValue(); }}', '"SyntaxError: super can only be used in a method of a derived class."');
+
 var successfullyParsed = true;

Modified: trunk/Source/_javascript_Core/ChangeLog (196260 => 196261)


--- trunk/Source/_javascript_Core/ChangeLog	2016-02-08 19:27:01 UTC (rev 196260)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-02-08 19:29:24 UTC (rev 196261)
@@ -1,3 +1,37 @@
+2016-02-08  Skachkov Oleksandr  <gskach...@gmail.com>
+
+        [ES6] Arrow function syntax. Using 'super' in arrow function that declared out of the class should lead to Syntax error
+        https://bugs.webkit.org/show_bug.cgi?id=150893
+
+        Reviewed by Saam Barati.
+
+        'super' and 'super()' inside of the arrow function should lead to syntax error if they are used 
+        out of the class context or they wrapped by ordinary function. Now JSC returns ReferenceError but 
+        should return SyntaxError according to the following specs:
+        http://www.ecma-international.org/ecma-262/6.0/#sec-function-definitions-static-semantics-early-errors
+        and http://www.ecma-international.org/ecma-262/6.0/#sec-arrow-function-definitions-runtime-semantics-evaluation 
+        Curren patch implemented only one case when super/super() are used inside of the arrow function
+        Case when super/super() are used within the eval:
+           class A {} 
+           class B extends A { 
+               costructor() { eval("super()");} 
+           }
+        is not part of this patch and will be implemented in this issue https://bugs.webkit.org/show_bug.cgi?id=153864. 
+        The same for case when eval with super/super() is invoked in arrow function will be 
+        implemented in issue https://bugs.webkit.org/show_bug.cgi?id=153977. 
+ 
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseFunctionInfo):
+        * parser/Parser.h:
+        (JSC::Scope::Scope):
+        (JSC::Scope::setExpectedSuperBinding):
+        (JSC::Scope::expectedSuperBinding):
+        (JSC::Scope::setConstructorKind):
+        (JSC::Scope::constructorKind):
+        (JSC::Parser::closestParentNonArrowFunctionNonLexicalScope):
+        * tests/stress/arrowfunction-lexical-bind-supercall-4.js:
+        * tests/stress/arrowfunction-lexical-bind-superproperty.js:
+
 2016-02-08  Filip Pizlo  <fpi...@apple.com>
 
         Parser should detect error before calls to parseAssignmentExpression()

Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (196260 => 196261)


--- trunk/Source/_javascript_Core/parser/Parser.cpp	2016-02-08 19:27:01 UTC (rev 196260)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp	2016-02-08 19:29:24 UTC (rev 196261)
@@ -1976,8 +1976,9 @@
         functionBodyType = StandardFunctionBodyBlock;
     }
 
-    bool isClassConstructor = constructorKind != ConstructorKind::None;
-    
+    functionScope->setConstructorKind(constructorKind);
+    functionScope->setExpectedSuperBinding(expectedSuperBinding);
+
     functionInfo.bodyStartColumn = startColumn;
     
     // If we know about this function already, we can use the cached info and skip the parser to the end of the function.
@@ -2066,12 +2067,24 @@
         semanticFailIfTrue(m_vm->propertyNames->arguments == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
         semanticFailIfTrue(m_vm->propertyNames->eval == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
     }
-    if (functionScope->hasDirectSuper() && functionBodyType == StandardFunctionBodyBlock) {
-        semanticFailIfTrue(!isClassConstructor, "Cannot call super() outside of a class constructor");
-        semanticFailIfTrue(constructorKind != ConstructorKind::Derived, "Cannot call super() in a base class constructor");
+    // It unncecessary to check of using super during reparsing one more time. Also it can lead to syntax error
+    // in case of arrow function becuase during reparsing we don't know that parse arrow function
+    // inside of the constructor or method
+    if (!m_lexer->isReparsingFunction()) {
+        if (functionScope->hasDirectSuper()) {
+            ConstructorKind functionConstructorKind = functionBodyType == StandardFunctionBodyBlock
+                ? constructorKind
+                : closestParentNonArrowFunctionNonLexicalScope()->constructorKind();
+            semanticFailIfTrue(functionConstructorKind == ConstructorKind::None, "Cannot call super() outside of a class constructor");
+            semanticFailIfTrue(functionConstructorKind != ConstructorKind::Derived, "Cannot call super() in a base class constructor");
+        }
+        if (functionScope->needsSuperBinding()) {
+            SuperBinding functionSuperBinding = functionBodyType == StandardFunctionBodyBlock
+                ? expectedSuperBinding
+                : closestParentNonArrowFunctionNonLexicalScope()->expectedSuperBinding();
+            semanticFailIfTrue(functionSuperBinding == SuperBinding::NotNeeded, "super can only be used in a method of a derived class");
+        }
     }
-    if (functionScope->needsSuperBinding() && functionBodyType == StandardFunctionBodyBlock)
-        semanticFailIfTrue(expectedSuperBinding == SuperBinding::NotNeeded, "super can only be used in a method of a derived class");
 
     JSTokenLocation location = JSTokenLocation(m_token.m_location);
     functionInfo.endOffset = m_token.m_data.offset;
@@ -2083,7 +2096,9 @@
     
     // Cache the tokenizer state and the function scope the first time the function is parsed.
     // Any future reparsing can then skip the function.
-    static const int minimumFunctionLengthToCache = 16;
+    // For arrow function is 8 = x=>x + 4 symbols;
+    // For ordinary function is 16  = function(){} + 4 symbols
+    const int minimumFunctionLengthToCache = functionBodyType == StandardFunctionBodyBlock ? 16 : 8;
     std::unique_ptr<SourceProviderCacheItem> newInfo;
     int functionLength = functionInfo.endOffset - functionInfo.startOffset;
     if (TreeBuilder::CanUseFunctionCache && m_functionCache && functionLength > minimumFunctionLengthToCache) {

Modified: trunk/Source/_javascript_Core/parser/Parser.h (196260 => 196261)


--- trunk/Source/_javascript_Core/parser/Parser.h	2016-02-08 19:27:01 UTC (rev 196260)
+++ trunk/Source/_javascript_Core/parser/Parser.h	2016-02-08 19:29:24 UTC (rev 196261)
@@ -175,6 +175,8 @@
         , m_isFunctionBoundary(false)
         , m_isValidStrictMode(true)
         , m_hasArguments(false)
+        , m_constructorKind(static_cast<unsigned>(ConstructorKind::None))
+        , m_expectedSuperBinding(static_cast<unsigned>(SuperBinding::NotNeeded))
         , m_loopDepth(0)
         , m_switchDepth(0)
     {
@@ -197,6 +199,8 @@
         , m_isFunctionBoundary(rhs.m_isFunctionBoundary)
         , m_isValidStrictMode(rhs.m_isValidStrictMode)
         , m_hasArguments(rhs.m_hasArguments)
+        , m_constructorKind(rhs.m_constructorKind)
+        , m_expectedSuperBinding(rhs.m_expectedSuperBinding)
         , m_loopDepth(rhs.m_loopDepth)
         , m_switchDepth(rhs.m_switchDepth)
         , m_moduleScopeData(rhs.m_moduleScopeData)
@@ -458,6 +462,11 @@
 
     bool needsSuperBinding() { return m_needsSuperBinding; }
     void setNeedsSuperBinding() { m_needsSuperBinding = true; }
+    
+    void setExpectedSuperBinding(SuperBinding superBinding) { m_expectedSuperBinding = static_cast<unsigned>(superBinding); }
+    SuperBinding expectedSuperBinding() const { return static_cast<SuperBinding>(m_expectedSuperBinding); }
+    void setConstructorKind(ConstructorKind constructorKind) { m_constructorKind = static_cast<unsigned>(constructorKind); }
+    ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
 
     void collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables)
     {
@@ -614,6 +623,8 @@
     bool m_isFunctionBoundary : 1;
     bool m_isValidStrictMode : 1;
     bool m_hasArguments : 1;
+    unsigned m_constructorKind : 2;
+    unsigned m_expectedSuperBinding : 2;
     int m_loopDepth;
     int m_switchDepth;
 
@@ -866,6 +877,15 @@
         return ScopeRef(&m_scopeStack, i);
     }
 
+    ScopeRef closestParentNonArrowFunctionNonLexicalScope()
+    {
+        unsigned i = m_scopeStack.size() - 1;
+        ASSERT(i < m_scopeStack.size() && m_scopeStack.size());
+        while (i && (!m_scopeStack[i].isFunctionBoundary() || m_scopeStack[i].isArrowFunction()))
+            i--;
+        // When reaching the top level scope (it can be non function scope), we return it.
+        return ScopeRef(&m_scopeStack, i);
+    }
     
     ScopeRef pushScope()
     {

Modified: trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-supercall-4.js (196260 => 196261)


--- trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-supercall-4.js	2016-02-08 19:27:01 UTC (rev 196260)
+++ trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-supercall-4.js	2016-02-08 19:29:24 UTC (rev 196261)
@@ -51,6 +51,9 @@
     }
 };
 
+// FIXME: Arrow function does not support using of eval with super/super()
+// https://bugs.webkit.org/show_bug.cgi?id=153977
+/*
 for (var i=0; i < 1000; i++) {
     new B(true);
     var c = new C();
@@ -60,6 +63,7 @@
     var e = new E();
     testCase(e.id, 'new-value', 'Error during set value in eval #3');
 }
+*/
 
 var testException = function (value, index) {
     var exception;

Modified: trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-superproperty.js (196260 => 196261)


--- trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-superproperty.js	2016-02-08 19:27:01 UTC (rev 196260)
+++ trunk/Source/_javascript_Core/tests/stress/arrowfunction-lexical-bind-superproperty.js	2016-02-08 19:29:24 UTC (rev 196261)
@@ -123,12 +123,6 @@
      getParentValue() {
          return super.getValue();
      }
-     getParentValueWithError() {
-         var f =  function () {
-             return () => super.getValue();
-         };
-         return f();
-     }
  };
 
  var g = new G();
@@ -149,20 +143,6 @@
     testCase(getValue(), 'new-value', 'Error: Some problem with using arrow and "super" inside of the method that retun arrow function');
 }
 
-var g2 = new G();
-for (var i = 0; i < 10000; i++) {
-    let error = false;
-    try {
-       g2.getParentValueWithError()();
-    } catch(e) {
-      // FIXME: should by check if e instanceof SyntaxError
-      // https://bugs.webkit.org/show_bug.cgi?id=150893
-      error = true;
-    }
-    testCase(error, true, 'Error: using "super" should lead to error');
-}
-
-
 var H = class H extends A {
     constructor() {
         var arrow = () => () => super.getValue();
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to