Skip to content
Permalink
Browse files
super should be available in object literals
https://bugs.webkit.org/show_bug.cgi?id=156933

Reviewed by Saam Barati.

Source/JavaScriptCore:

When we originally implemented classes, super seemed to be a class-only
feature. But the final spec says it's available in object literals too.

* bytecompiler/NodesCodegen.cpp:
(JSC::PropertyListNode::emitBytecode): Having 'super' and being a class
property are no longer synonymous, so we track two separate variables.

(JSC::PropertyListNode::emitPutConstantProperty): Being inside the super
branch no longer guarantees that you're a class property, so we decide
our attributes and our function name dynamically.

* parser/ASTBuilder.h:
(JSC::ASTBuilder::createArrowFunctionExpr):
(JSC::ASTBuilder::createGetterOrSetterProperty):
(JSC::ASTBuilder::createArguments):
(JSC::ASTBuilder::createArgumentsList):
(JSC::ASTBuilder::createProperty):
(JSC::ASTBuilder::createPropertyList): Pass through state to indicate
whether we're a class property, since we can't infer it from 'super'
anymore.

* parser/NodeConstructors.h:
(JSC::PropertyNode::PropertyNode): See ASTBuilder.h.

* parser/Nodes.h:
(JSC::PropertyNode::expressionName):
(JSC::PropertyNode::name):
(JSC::PropertyNode::type):
(JSC::PropertyNode::needsSuperBinding):
(JSC::PropertyNode::isClassProperty):
(JSC::PropertyNode::putType): See ASTBuilder.h.

* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseFunctionInfo):
(JSC::Parser<LexerType>::parseClass):
(JSC::Parser<LexerType>::parseProperty):
(JSC::Parser<LexerType>::parsePropertyMethod):
(JSC::Parser<LexerType>::parseGetterSetter):
(JSC::Parser<LexerType>::parseMemberExpression): I made these error
messages generic because it is no longer practical to say concise things
about the list of places you can use super.

* parser/Parser.h:

* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createArgumentsList):
(JSC::SyntaxChecker::createProperty):
(JSC::SyntaxChecker::appendExportSpecifier):
(JSC::SyntaxChecker::appendConstDecl):
(JSC::SyntaxChecker::createGetterOrSetterProperty): Updated for
interface change.

* tests/stress/generator-with-super.js:
(test):
* tests/stress/modules-syntax-error.js:
* tests/stress/super-in-lexical-scope.js:
(testSyntaxError):
(testSyntaxError.test):
* tests/stress/tagged-templates-syntax.js: Updated for error message
changes. See Parser.cpp.

LayoutTests:

Updated expected results and added a few new tests.

* js/arrowfunction-syntax-errors-expected.txt:
* js/class-syntax-super-expected.txt:
* js/object-literal-methods-expected.txt:
* js/script-tests/arrowfunction-syntax-errors.js:
* js/script-tests/class-syntax-super.js:
* js/script-tests/object-literal-methods.js:


Canonical link: https://commits.webkit.org/175044@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@199927 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
geoffreygaren committed Apr 22, 2016
1 parent 0ed60b1 commit 97100093a2d7533cc576788f36fccedc5ec69005
Showing 20 changed files with 247 additions and 133 deletions.
@@ -1,3 +1,19 @@
2016-04-22 Geoffrey Garen <ggaren@apple.com>

super should be available in object literals
https://bugs.webkit.org/show_bug.cgi?id=156933

Reviewed by Saam Barati.

Updated expected results and added a few new tests.

* js/arrowfunction-syntax-errors-expected.txt:
* js/class-syntax-super-expected.txt:
* js/object-literal-methods-expected.txt:
* js/script-tests/arrowfunction-syntax-errors.js:
* js/script-tests/class-syntax-super.js:
* js/script-tests/object-literal-methods.js:

2016-04-22 Ryan Haddad <ryanhaddad@apple.com>

Rebaselining inspector/model/stack-trace.html after r199897
@@ -131,20 +131,20 @@ PASS var arr1 = [a, b] => a + b; threw exception SyntaxError: Unexpected token '
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 class H {}; class H2 extends H { method() { function *gen() { let arr = () => super.getValue(); arr(); } } } threw exception SyntaxError: super can only be used in a method of a derived class..
PASS var arr4 = () => { super(); }; threw exception SyntaxError: super is not valid in this context..
PASS var arr4 = () => { super; }; threw exception SyntaxError: super is not valid in this context..
PASS var arr5 = () => { super.getValue(); }; threw exception SyntaxError: super is not valid in this context..
PASS var arr6 = () => super(); threw exception SyntaxError: super is not valid in this context..
PASS var arr7 = () => super; threw exception SyntaxError: super is not valid in this context..
PASS var arr8 = () => super.getValue(); threw exception SyntaxError: super is not valid in this context..
PASS class A { constructor() { function a () { return () => { super(); };}} threw exception SyntaxError: super is not valid in this context..
PASS class B { constructor() { function b () { return () => { super; }; }; }} threw exception SyntaxError: super is not valid in this context..
PASS class C { constructor() { function c () { return () => { super.getValue(); };}} threw exception SyntaxError: super is not valid in this context..
PASS class D { constructor() { function a () { return () => super(); }} threw exception SyntaxError: super is not valid in this context..
PASS class E { constructor() { function b () { return () => super; }; }} threw exception SyntaxError: super is not valid in this context..
PASS class F { constructor() { function c () { return () => super.getValue(); }} threw exception SyntaxError: super is not valid in this context..
PASS class G {}; class G2 extends G { getValue() { function c () { return () => super.getValue(); }} threw exception SyntaxError: super is not valid in this context..
PASS class H {}; class H2 extends H { method() { function *gen() { let arr = () => super.getValue(); arr(); } } } threw exception SyntaxError: super is not valid in this context..
PASS successfullyParsed is true

TEST COMPLETE
@@ -16,8 +16,8 @@ PASS (new Derived).baseMethodInGetterSetter = 1; valueInSetter:::(new Base).base
PASS Derived.staticMethod():::"base3"
PASS (new SecondDerived).chainMethod().toString():::["base", "derived", "secondDerived"].toString()
PASS x = class extends Base { constructor() { super(); } super() {} }
PASS x = class extends Base { constructor() { super(); } method() { super() } }:::SyntaxError: Cannot call super() outside of a class constructor.
PASS x = class extends Base { constructor() { super(); } method() { super } }:::SyntaxError: Cannot reference super.
PASS x = class extends Base { constructor() { super(); } method() { super() } }:::SyntaxError: super is not valid in this context.
PASS x = class extends Base { constructor() { super(); } method() { super } }:::SyntaxError: super is not valid in this context.
PASS x = class extends Base { constructor() { super(); } method() { return new super } }:::SyntaxError: Cannot use new with super.
PASS x = class extends Base { constructor() { super(); } method1() { delete (super.foo) } method2() { delete super["foo"] } }
PASS (new x).method1():::ReferenceError: Cannot delete a super property
@@ -37,18 +37,18 @@ PASS x instanceof Object
PASS new (class extends null { constructor() { } }):::ReferenceError: Cannot access uninitialized variable.
PASS new (class extends null { constructor() { return 1; } }):::TypeError: Cannot return a non-object type in the constructor of a derived class.
PASS new (class extends null { constructor() { super() } }):::TypeError: function is not a constructor (evaluating 'super()')
PASS new (class { constructor() { super() } }):::SyntaxError: Cannot call super() in a base class constructor.
PASS function x() { super(); }:::SyntaxError: Cannot call super() outside of a class constructor.
PASS new (class extends Object { constructor() { function x() { super() } } }):::SyntaxError: Cannot call super() outside of a class constructor.
PASS new (class extends Object { constructor() { function x() { super.method } } }):::SyntaxError: super can only be used in a method of a derived class.
PASS function x() { super.method(); }:::SyntaxError: super can only be used in a method of a derived class.
PASS function x() { super(); }:::SyntaxError: Cannot call super() outside of a class constructor.
PASS eval("super.method()"):::SyntaxError: 'super' is only valid inside a function or an 'eval' inside a function.
PASS eval("super()"):::SyntaxError: 'super' is only valid inside a function or an 'eval' inside a function.
PASS (function () { eval("super.method()");})():::SyntaxError: 'super' is only valid inside a function or an 'eval' inside a function.
PASS (function () { eval("super()");})():::SyntaxError: 'super' is only valid inside a function or an 'eval' inside a function.
PASS new (class { constructor() { (function () { eval("super()");})(); } }):::SyntaxError: 'super' is only valid inside a function or an 'eval' inside a function.
PASS (new (class { method() { (function () { eval("super.method()");})(); }})).method():::SyntaxError: 'super' is only valid inside a function or an 'eval' inside a function.
PASS new (class { constructor() { super() } }):::SyntaxError: super is not valid in this context.
PASS function x() { super(); }:::SyntaxError: super is not valid in this context.
PASS new (class extends Object { constructor() { function x() { super() } } }):::SyntaxError: super is not valid in this context.
PASS new (class extends Object { constructor() { function x() { super.method } } }):::SyntaxError: super is not valid in this context.
PASS function x() { super.method(); }:::SyntaxError: super is not valid in this context.
PASS function x() { super(); }:::SyntaxError: super is not valid in this context.
PASS eval("super.method()"):::SyntaxError: super is not valid in this context.
PASS eval("super()"):::SyntaxError: super is not valid in this context.
PASS (function () { eval("super.method()");})():::SyntaxError: super is not valid in this context.
PASS (function () { eval("super()");})():::SyntaxError: super is not valid in this context.
PASS new (class { constructor() { (function () { eval("super()");})(); } }):::SyntaxError: super is not valid in this context.
PASS (new (class { method() { (function () { eval("super.method()");})(); }})).method():::SyntaxError: super is not valid in this context.
PASS successfullyParsed

TEST COMPLETE
@@ -68,6 +68,14 @@ PASS ({ foo(a, b) { if }, bar(){} }) threw exception SyntaxError: Unexpected tok
PASS ({__proto__: function(){}}) instanceof Function is true
PASS ({__proto__(){}}) instanceof Function is false
PASS ({__proto__(){}}).__proto__ instanceof Function is true
PASS { f() { return super.f(); } }.f() threw exception SyntaxError: Unexpected token '{'.
PASS new ({ f() { return super(); }.f) threw exception SyntaxError: super is not valid in this context..
PASS o = { f() { } }; new ({ __proto__: o, f() { return super(); } }).f threw exception SyntaxError: super is not valid in this context..
PASS ({ f() { return (() => super.f())(); } }).f() threw exception TypeError: super.f is not a function. (In 'super.f()', 'super.f' is undefined).
PASS o = { f() { return true; } }; ({ __proto__: o, f() { return super.f(); } }).f() is true
PASS o = { get p() { return true; } }; ({ __proto__: o, get p() { return super.p; } }).p is true
PASS o = { set p(p2) { } }; ({ __proto__: o, set p(p2) { super.p = p2; } }).p = true is true
PASS o = { f() { return true; } }; ({ __proto__: o, f() { return (() => super.f())(); } }).f() is true
PASS successfullyParsed is true

TEST COMPLETE
@@ -48,22 +48,22 @@ shouldThrow('var arr2 = {a, b} => a + b;');
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 arr4 = () => { super(); };', '"SyntaxError: super is not valid in this context."');
shouldThrow('var arr4 = () => { super; };', '"SyntaxError: super is not valid in this context."');
shouldThrow('var arr5 = () => { super.getValue(); };', '"SyntaxError: super is not valid in this context."');

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('var arr6 = () => super();', '"SyntaxError: super is not valid in this context."');
shouldThrow('var arr7 = () => super;', '"SyntaxError: super is not valid in this context."');
shouldThrow('var arr8 = () => super.getValue();', '"SyntaxError: super is not valid in this context."');

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 A { constructor() { function a () { return () => { super(); };}}', '"SyntaxError: super is not valid in this context."');
shouldThrow('class B { constructor() { function b () { return () => { super; }; }; }}', '"SyntaxError: super is not valid in this context."');
shouldThrow('class C { constructor() { function c () { return () => { super.getValue(); };}}', '"SyntaxError: super is not valid in this context."');

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."');
shouldThrow('class H {}; class H2 extends H { method() { function *gen() { let arr = () => super.getValue(); arr(); } } }', '"SyntaxError: super can only be used in a method of a derived class."');
shouldThrow('class D { constructor() { function a () { return () => super(); }}', '"SyntaxError: super is not valid in this context."');
shouldThrow('class E { constructor() { function b () { return () => super; }; }}', '"SyntaxError: super is not valid in this context."');
shouldThrow('class F { constructor() { function c () { return () => super.getValue(); }}', '"SyntaxError: super is not valid in this context."');
shouldThrow('class G {}; class G2 extends G { getValue() { function c () { return () => super.getValue(); }}', '"SyntaxError: super is not valid in this context."');
shouldThrow('class H {}; class H2 extends H { method() { function *gen() { let arr = () => super.getValue(); arr(); } } }', '"SyntaxError: super is not valid in this context."');

var successfullyParsed = true;
@@ -99,8 +99,8 @@ shouldBe('Derived.staticMethod()', '"base3"');
shouldBe('(new SecondDerived).chainMethod().toString()', '["base", "derived", "secondDerived"].toString()');
shouldNotThrow('x = class extends Base { constructor() { super(); } super() {} }');
shouldThrow('x = class extends Base { constructor() { super(); } method() { super() } }',
'"SyntaxError: Cannot call super() outside of a class constructor."');
shouldThrow('x = class extends Base { constructor() { super(); } method() { super } }', '"SyntaxError: Cannot reference super."');
'"SyntaxError: super is not valid in this context."');
shouldThrow('x = class extends Base { constructor() { super(); } method() { super } }', '"SyntaxError: super is not valid in this context."');
shouldThrow('x = class extends Base { constructor() { super(); } method() { return new super } }', '"SyntaxError: Cannot use new with super."');
shouldNotThrow('x = class extends Base { constructor() { super(); } method1() { delete (super.foo) } method2() { delete super["foo"] } }');
shouldThrow('(new x).method1()', '"ReferenceError: Cannot delete a super property"');
@@ -120,19 +120,19 @@ shouldBeTrue('x instanceof Object');
shouldThrow('new (class extends null { constructor() { } })', '"ReferenceError: Cannot access uninitialized variable."');
shouldThrow('new (class extends null { constructor() { return 1; } })', '"TypeError: Cannot return a non-object type in the constructor of a derived class."');
shouldThrow('new (class extends null { constructor() { super() } })', '"TypeError: function is not a constructor (evaluating \'super()\')"');
shouldThrow('new (class { constructor() { super() } })', '"SyntaxError: Cannot call super() in a base class constructor."');
shouldThrow('function x() { super(); }', '"SyntaxError: Cannot call super() outside of a class constructor."');
shouldThrow('new (class extends Object { constructor() { function x() { super() } } })', '"SyntaxError: Cannot call super() outside of a class constructor."');
shouldThrow('new (class extends Object { constructor() { function x() { super.method } } })', '"SyntaxError: super can only be used in a method of a derived class."');
shouldThrow('function x() { super.method(); }', '"SyntaxError: super can only be used in a method of a derived class."');
shouldThrow('function x() { super(); }', '"SyntaxError: Cannot call super() outside of a class constructor."');
shouldThrow('eval("super.method()")', '"SyntaxError: \'super\' is only valid inside a function or an \'eval\' inside a function."');
shouldThrow('eval("super()")', '"SyntaxError: \'super\' is only valid inside a function or an \'eval\' inside a function."');

shouldThrow('(function () { eval("super.method()");})()', '"SyntaxError: \'super\' is only valid inside a function or an \'eval\' inside a function."');
shouldThrow('(function () { eval("super()");})()', '"SyntaxError: \'super\' is only valid inside a function or an \'eval\' inside a function."');

shouldThrow('new (class { constructor() { (function () { eval("super()");})(); } })', '"SyntaxError: \'super\' is only valid inside a function or an \'eval\' inside a function."');
shouldThrow('(new (class { method() { (function () { eval("super.method()");})(); }})).method()', '"SyntaxError: \'super\' is only valid inside a function or an \'eval\' inside a function."');
shouldThrow('new (class { constructor() { super() } })', '"SyntaxError: super is not valid in this context."');
shouldThrow('function x() { super(); }', '"SyntaxError: super is not valid in this context."');
shouldThrow('new (class extends Object { constructor() { function x() { super() } } })', '"SyntaxError: super is not valid in this context."');
shouldThrow('new (class extends Object { constructor() { function x() { super.method } } })', '"SyntaxError: super is not valid in this context."');
shouldThrow('function x() { super.method(); }', '"SyntaxError: super is not valid in this context."');
shouldThrow('function x() { super(); }', '"SyntaxError: super is not valid in this context."');
shouldThrow('eval("super.method()")', '"SyntaxError: super is not valid in this context."');
shouldThrow('eval("super()")', '"SyntaxError: super is not valid in this context."');

shouldThrow('(function () { eval("super.method()");})()', '"SyntaxError: super is not valid in this context."');
shouldThrow('(function () { eval("super()");})()', '"SyntaxError: super is not valid in this context."');

shouldThrow('new (class { constructor() { (function () { eval("super()");})(); } })', '"SyntaxError: super is not valid in this context."');
shouldThrow('(new (class { method() { (function () { eval("super.method()");})(); }})).method()', '"SyntaxError: super is not valid in this context."');

var successfullyParsed = true;
@@ -82,3 +82,12 @@ shouldThrow("({ foo(a, b) { if }, bar(){} })");
shouldBeTrue("({__proto__: function(){}}) instanceof Function");
shouldBeFalse("({__proto__(){}}) instanceof Function");
shouldBeTrue("({__proto__(){}}).__proto__ instanceof Function");

shouldThrow("{ f() { return super.f(); } }.f()");
shouldThrow("new ({ f() { return super(); }.f)");
shouldThrow("o = { f() { } }; new ({ __proto__: o, f() { return super(); } }).f");
shouldThrow("({ f() { return (() => super.f())(); } }).f()");
shouldBeTrue("o = { f() { return true; } }; ({ __proto__: o, f() { return super.f(); } }).f()");
shouldBeTrue("o = { get p() { return true; } }; ({ __proto__: o, get p() { return super.p; } }).p");
shouldBeTrue("o = { set p(p2) { } }; ({ __proto__: o, set p(p2) { super.p = p2; } }).p = true");
shouldBeTrue("o = { f() { return true; } }; ({ __proto__: o, f() { return (() => super.f())(); } }).f()");

0 comments on commit 9710009

Please sign in to comment.