Diff
Modified: trunk/JSTests/ChangeLog (271119 => 271120)
--- trunk/JSTests/ChangeLog 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/JSTests/ChangeLog 2021-01-02 19:27:42 UTC (rev 271120)
@@ -1,5 +1,18 @@
2021-01-02 Alexey Shvayka <[email protected]>
+ Improve error message for uninitialized |this| in derived constructor
+ https://bugs.webkit.org/show_bug.cgi?id=220221
+
+ Reviewed by Yusuke Suzuki.
+
+ * stress/async-arrow-functions-lexical-binding-in-class.js:
+ * stress/async-arrow-functions-lexical-super-binding.js:
+ * stress/class-derived-from-null.js:
+ * stress/generator-eval-this.js:
+ * stress/super-property-access-tdz.js:
+
+2021-01-02 Alexey Shvayka <[email protected]>
+
Don't throw if `function.caller` is a non-strict / generator / async function
https://bugs.webkit.org/show_bug.cgi?id=220216
Modified: trunk/JSTests/stress/async-arrow-functions-lexical-binding-in-class.js (271119 => 271120)
--- trunk/JSTests/stress/async-arrow-functions-lexical-binding-in-class.js 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/JSTests/stress/async-arrow-functions-lexical-binding-in-class.js 2021-01-02 19:27:42 UTC (rev 271120)
@@ -254,7 +254,7 @@
// We do not care about this error
}
drainMicrotasks();
- const error = asyncError.error instanceof ReferenceError && asyncError.error.toString() === 'ReferenceError: Cannot access uninitialized variable.';
+ const error = asyncError.error.toString() === `ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object.`;
if (!error) throw new Error('TDZ error is expected, but appeared:' + asyncError.error);
}
Modified: trunk/JSTests/stress/async-arrow-functions-lexical-super-binding.js (271119 => 271120)
--- trunk/JSTests/stress/async-arrow-functions-lexical-super-binding.js 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/JSTests/stress/async-arrow-functions-lexical-super-binding.js 2021-01-02 19:27:42 UTC (rev 271120)
@@ -123,7 +123,7 @@
shouldBe(childA4, undefined);
shouldBe(value, 'abc');
shouldBe(error, undefined);
-shouldBe(catchError.toString(), 'ReferenceError: Cannot access uninitialized variable.');
+shouldBe(catchError.toString(), `ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object.`);
catchError = undefined;
error = undefined;
Modified: trunk/JSTests/stress/class-derived-from-null.js (271119 => 271120)
--- trunk/JSTests/stress/class-derived-from-null.js 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/JSTests/stress/class-derived-from-null.js 2021-01-02 19:27:42 UTC (rev 271120)
@@ -41,7 +41,7 @@
return this;
}
}
- assertThrow(()=>(new E), 'ReferenceError: Cannot access uninitialized variable.');
+ assertThrow(()=>(new E), `ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object.`);
assert(Reflect.getPrototypeOf(E.prototype) === null);
}
test(test1);
@@ -116,7 +116,7 @@
class E extends jsNull() { constructor() { let ret = this; return ret; } }
class F extends jsNull() { constructor() { return 25; } }
class G extends jsNull() { constructor() { super(); } }
- assertThrow(() => Reflect.construct(E, [], D), 'ReferenceError: Cannot access uninitialized variable.');
+ assertThrow(() => Reflect.construct(E, [], D), `ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object.`);
assertThrow(() => Reflect.construct(F, [], D), 'TypeError: Cannot return a non-object type in the constructor of a derived class.');
let threw = false;
Modified: trunk/JSTests/stress/generator-eval-this.js (271119 => 271120)
--- trunk/JSTests/stress/generator-eval-this.js 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/JSTests/stress/generator-eval-this.js 2021-01-02 19:27:42 UTC (rev 271120)
@@ -43,7 +43,7 @@
shouldThrow(() => {
new A();
-}, `ReferenceError: Cannot access uninitialized variable.`);
+}, `ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object.`);
class C {
*generator()
Modified: trunk/JSTests/stress/super-property-access-tdz.js (271119 => 271120)
--- trunk/JSTests/stress/super-property-access-tdz.js 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/JSTests/stress/super-property-access-tdz.js 2021-01-02 19:27:42 UTC (rev 271120)
@@ -15,7 +15,7 @@
f();
} catch(e) {
assert(e instanceof ReferenceError);
- assert(e.toString() === "ReferenceError: Cannot access uninitialized variable.");
+ assert(e.toString() === `ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object.`);
threw = true;
}
assert(threw);
Modified: trunk/LayoutTests/ChangeLog (271119 => 271120)
--- trunk/LayoutTests/ChangeLog 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/LayoutTests/ChangeLog 2021-01-02 19:27:42 UTC (rev 271120)
@@ -1,5 +1,20 @@
2021-01-02 Alexey Shvayka <[email protected]>
+ Improve error message for uninitialized |this| in derived constructor
+ https://bugs.webkit.org/show_bug.cgi?id=220221
+
+ Reviewed by Yusuke Suzuki.
+
+ * js/arrowfunction-supercall-expected.txt:
+ * js/arrowfunction-superproperty-expected.txt:
+ * js/class-syntax-extends-expected.txt:
+ * js/class-syntax-super-expected.txt:
+ * js/script-tests/arrowfunction-supercall.js:
+ * js/script-tests/arrowfunction-superproperty.js:
+ * js/script-tests/class-syntax-super.js:
+
+2021-01-02 Alexey Shvayka <[email protected]>
+
Don't throw if `function.caller` is a non-strict / generator / async function
https://bugs.webkit.org/show_bug.cgi?id=220216
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (271119 => 271120)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2021-01-02 19:27:42 UTC (rev 271120)
@@ -1,3 +1,12 @@
+2021-01-02 Alexey Shvayka <[email protected]>
+
+ Improve error message for uninitialized |this| in derived constructor
+ https://bugs.webkit.org/show_bug.cgi?id=220221
+
+ Reviewed by Yusuke Suzuki.
+
+ * web-platform-tests/custom-elements/parser/parser-fallsback-to-unknown-element-expected.txt:
+
2020-12-30 Yusuke Suzuki <[email protected]>
[JSC] WebAssembly Table/Memory/Global should allow inheritance
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/custom-elements/parser/parser-fallsback-to-unknown-element-expected.txt (271119 => 271120)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/custom-elements/parser/parser-fallsback-to-unknown-element-expected.txt 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/custom-elements/parser/parser-fallsback-to-unknown-element-expected.txt 2021-01-02 19:27:42 UTC (rev 271120)
@@ -1,6 +1,6 @@
CONSOLE MESSAGE: TypeError: The result of constructing a custom element must be a HTMLElement
CONSOLE MESSAGE: TypeError: The result of constructing a custom element must be a HTMLElement
-CONSOLE MESSAGE: ReferenceError: Cannot access uninitialized variable.
+CONSOLE MESSAGE: ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object.
CONSOLE MESSAGE: Bad
PASS HTML parser must create a fallback HTMLUnknownElement when a custom element constructor returns a Text node
Modified: trunk/LayoutTests/js/arrowfunction-supercall-expected.txt (271119 => 271120)
--- trunk/LayoutTests/js/arrowfunction-supercall-expected.txt 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/LayoutTests/js/arrowfunction-supercall-expected.txt 2021-01-02 19:27:42 UTC (rev 271120)
@@ -22,8 +22,8 @@
PASS indexOfarrowInChildConstructorInStackError > -1 && errorStack.indexOf('arrowInChildConstructor', indexOfarrowInChildConstructorInStackError + 1) === -1 is true
PASS indexOfChildClassInStackError > -1 && errorStack.indexOf('ChildClass', indexOfChildClassInStackError + 1) === -1 is true
PASS (new class extends A { constructor() { ((a = super())=>{})() } }).id is value
-PASS (new class extends A { constructor() { ((a = this)=>{ return a; })() } }) threw exception ReferenceError: Cannot access uninitialized variable..
-PASS (new class extends A { constructor() { ((a = this, b=super())=>{ return a; })() } }) threw exception ReferenceError: Cannot access uninitialized variable..
+PASS (new class extends A { constructor() { ((a = this)=>{ return a; })() } }) threw exception ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object..
+PASS (new class extends A { constructor() { ((a = this, b=super())=>{ return a; })() } }) threw exception ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object..
PASS (new class extends A { constructor() { ((a = new.target)=>{ return a; })(); super(); } }) did not throw exception.
PASS (new class extends A { constructor() { ((a = new.target, b=super())=>{ return a; })() } }) did not throw exception.
PASS successfullyParsed is true
Modified: trunk/LayoutTests/js/arrowfunction-superproperty-expected.txt (271119 => 271120)
--- trunk/LayoutTests/js/arrowfunction-superproperty-expected.txt 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/LayoutTests/js/arrowfunction-superproperty-expected.txt 2021-01-02 19:27:42 UTC (rev 271120)
@@ -5,7 +5,7 @@
PASS (new B()).getValueParentFunction() is expectedValue
PASS (new C(false)).value is expectedValue
-PASS (new C(true)) threw exception ReferenceError: Cannot access uninitialized variable..
+PASS (new C(true)) threw exception ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object..
PASS E.getParentStaticValue() is expectedValue
PASS f.prop is expectedValue + "-" + expectedValue
PASS f.prop is expectedValue + "-" + "new-value"
@@ -14,14 +14,14 @@
PASS (new F()).genGetParentValueDeepArrow().next().value is expectedValue
PASS (new class extends A { constructor() { ((a = super(), b = super.getValue())=>{ this.id = b; })() } }).id is expectedValue
PASS (new class extends A { constructor() { ((a = super(), b = new.target)=>{ this.newTarget = b; })(); expectedNewTarget = new.target;} }).newTarget is expectedNewTarget
-PASS (new class extends A { constructor() { ((a = super.getValue())=>{ this.id = a; })() } }) threw exception ReferenceError: Cannot access uninitialized variable..
-PASS (new class extends A { constructor() { ((a = super.getValue(), b=super())=>{ this.id = a; })() } }) threw exception ReferenceError: Cannot access uninitialized variable..
-PASS (new class extends F { constructor() { ((a = super.prop)=>{ return a; })() } }) threw exception ReferenceError: Cannot access uninitialized variable..
-PASS (new class extends F { constructor() { ((a = super.prop, b=super())=>{ return a; })() } }) threw exception ReferenceError: Cannot access uninitialized variable..
-PASS (new class extends F { constructor() { ((a = (super.prop = "value"))=>{ this.id = a; })() } }) threw exception ReferenceError: Cannot access uninitialized variable..
-PASS (new class extends F { constructor() { ((a = (super.prop = "value"), b=super())=>{ this.id = a; })() } }) threw exception ReferenceError: Cannot access uninitialized variable..
-PASS (new class extends F { constructor() { ((a = super.genGetParentValue().next().value)=>{ this.id = a; })() } }) threw exception ReferenceError: Cannot access uninitialized variable..
-PASS (new class extends F { constructor() { ((a = super.genGetParentValue().next().value, b=super())=>{ this.id = a; })() } }) threw exception ReferenceError: Cannot access uninitialized variable..
+PASS (new class extends A { constructor() { ((a = super.getValue())=>{ this.id = a; })() } }) threw exception ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object..
+PASS (new class extends A { constructor() { ((a = super.getValue(), b=super())=>{ this.id = a; })() } }) threw exception ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object..
+PASS (new class extends F { constructor() { ((a = super.prop)=>{ return a; })() } }) threw exception ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object..
+PASS (new class extends F { constructor() { ((a = super.prop, b=super())=>{ return a; })() } }) threw exception ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object..
+PASS (new class extends F { constructor() { ((a = (super.prop = "value"))=>{ this.id = a; })() } }) threw exception ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object..
+PASS (new class extends F { constructor() { ((a = (super.prop = "value"), b=super())=>{ this.id = a; })() } }) threw exception ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object..
+PASS (new class extends F { constructor() { ((a = super.genGetParentValue().next().value)=>{ this.id = a; })() } }) threw exception ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object..
+PASS (new class extends F { constructor() { ((a = super.genGetParentValue().next().value, b=super())=>{ this.id = a; })() } }) threw exception ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object..
PASS successfullyParsed is true
TEST COMPLETE
Modified: trunk/LayoutTests/js/class-syntax-extends-expected.txt (271119 => 271120)
--- trunk/LayoutTests/js/class-syntax-extends-expected.txt 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/LayoutTests/js/class-syntax-extends-expected.txt 2021-01-02 19:27:42 UTC (rev 271120)
@@ -57,7 +57,7 @@
PASS new (class extends undefined { constructor () { this } }):::TypeError: The superclass is not a constructor.
PASS x = undefined; new (class extends x { constructor () { super(); } }):::TypeError: The superclass is not a constructor.
PASS class x {}; new (class extends null { constructor () { return new x; } }) instanceof x
-PASS new (class extends null { constructor () { this; } }):::ReferenceError: Cannot access uninitialized variable.
+PASS new (class extends null { constructor () { this; } }):::ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object.
PASS new (class extends null { constructor () { super(); } }):::TypeError: function is not a constructor (evaluating 'super()')
PASS x = {}; new (class extends null { constructor () { return x } }):::x
PASS y = 12; class C extends null { constructor () { return y; } }; new C;:::TypeError: Cannot return a non-object type in the constructor of a derived class.
Modified: trunk/LayoutTests/js/class-syntax-super-expected.txt (271119 => 271120)
--- trunk/LayoutTests/js/class-syntax-super-expected.txt 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/LayoutTests/js/class-syntax-super-expected.txt 2021-01-02 19:27:42 UTC (rev 271120)
@@ -6,7 +6,7 @@
PASS (new Base) instanceof Base
PASS (new Derived) instanceof Derived
PASS (new DerivedWithEval) instanceof DerivedWithEval
-PASS (new DerivedWithEval(true)):::ReferenceError: Cannot access uninitialized variable.
+PASS (new DerivedWithEval(true)):::ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object.
PASS (new Derived).callBaseMethod():::baseMethodValue
PASS x = (new Derived).callBaseMethod; x():::baseMethodValue
PASS (new Derived).callBaseMethodInGetter:::baseMethodValue
@@ -30,17 +30,17 @@
PASS (new (class { constructor() { var arr = () => eval('super.property = "ABC"'); arr(); } })).property === "ABC"
PASS new (class { constructor() { return undefined; } }) instanceof Object
PASS new (class { constructor() { return 1; } }) instanceof Object
-PASS new (class extends Base { constructor() { return undefined } }):::ReferenceError: Cannot access uninitialized variable.
+PASS new (class extends Base { constructor() { return undefined } }):::ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object.
PASS new (class extends Base { constructor() { super(); return undefined } }) instanceof Object
PASS x = { }; new (class extends Base { constructor() { return x } });:::x
PASS x instanceof Base
-PASS new (class extends Base { constructor() { } }):::ReferenceError: Cannot access uninitialized variable.
+PASS new (class extends Base { constructor() { } }):::ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object.
PASS new (class extends Base { constructor() { return 1; } }):::TypeError: Cannot return a non-object type in the constructor of a derived class.
-PASS new (class extends null { constructor() { return undefined } }):::ReferenceError: Cannot access uninitialized variable.
+PASS new (class extends null { constructor() { return undefined } }):::ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object.
PASS new (class extends null { constructor() { super(); return undefined } }):::TypeError: function is not a constructor (evaluating 'super()')
PASS x = { }; new (class extends null { constructor() { return x } });:::x
PASS x instanceof Object
-PASS new (class extends null { constructor() { } }):::ReferenceError: Cannot access uninitialized variable.
+PASS new (class extends null { constructor() { } }):::ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object.
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: super is not valid in this context.
@@ -56,9 +56,9 @@
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 new (class extends Base { constructor() { super(); super();}}):::ReferenceError: 'super()' can't be called more than once in a constructor.
-PASS (new class D extends class { m() {}} { constructor() { eval('super["m"]()') } }):::ReferenceError: Cannot access uninitialized variable.
-PASS new class extends class { m() {}} { constructor() { super["m"](super()) } }:::ReferenceError: Cannot access uninitialized variable.
-PASS (new class D extends class { m() {}} { constructor(f) { super[f()]() } }(()=>"m")):::ReferenceError: Cannot access uninitialized variable.
+PASS (new class D extends class { m() {}} { constructor() { eval('super["m"]()') } }):::ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object.
+PASS new class extends class { m() {}} { constructor() { super["m"](super()) } }:::ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object.
+PASS (new class D extends class { m() {}} { constructor(f) { super[f()]() } }(()=>"m")):::ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object.
PASS (new class D extends class { m() {}} { constructor() { super(); eval('super["m"]()') } })
PASS new class extends class { m() {}} { constructor() { super(); super["m"](super()) } }:::ReferenceError: 'super()' can't be called more than once in a constructor.
PASS (new class D extends class { m() {}} { constructor(f) { super(); super[f()]() } }(()=>"m"))
Modified: trunk/LayoutTests/js/script-tests/arrowfunction-supercall.js (271119 => 271120)
--- trunk/LayoutTests/js/script-tests/arrowfunction-supercall.js 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/LayoutTests/js/script-tests/arrowfunction-supercall.js 2021-01-02 19:27:42 UTC (rev 271120)
@@ -149,8 +149,8 @@
shouldBeTrue("indexOfChildClassInStackError > -1 && errorStack.indexOf('ChildClass', indexOfChildClassInStackError + 1) === -1");
shouldBe("(new class extends A { constructor() { ((a = super())=>{})() } }).id", "value");
-shouldThrow('(new class extends A { constructor() { ((a = this)=>{ return a; })() } })', '"ReferenceError: Cannot access uninitialized variable."');
-shouldThrow('(new class extends A { constructor() { ((a = this, b=super())=>{ return a; })() } })', '"ReferenceError: Cannot access uninitialized variable."');
+shouldThrow('(new class extends A { constructor() { ((a = this)=>{ return a; })() } })', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`);
+shouldThrow('(new class extends A { constructor() { ((a = this, b=super())=>{ return a; })() } })', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`);
shouldNotThrow('(new class extends A { constructor() { ((a = new.target)=>{ return a; })(); super(); } })');
shouldNotThrow('(new class extends A { constructor() { ((a = new.target, b=super())=>{ return a; })() } })');
Modified: trunk/LayoutTests/js/script-tests/arrowfunction-superproperty.js (271119 => 271120)
--- trunk/LayoutTests/js/script-tests/arrowfunction-superproperty.js 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/LayoutTests/js/script-tests/arrowfunction-superproperty.js 2021-01-02 19:27:42 UTC (rev 271120)
@@ -77,7 +77,7 @@
shouldBe('(new C(false)).value', 'expectedValue');
-shouldThrow('(new C(true))', '"ReferenceError: Cannot access uninitialized variable."');
+shouldThrow('(new C(true))', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`);
shouldBe('E.getParentStaticValue()', 'expectedValue');
@@ -95,13 +95,13 @@
shouldBe('(new class extends A { constructor() { ((a = super(), b = super.getValue())=>{ this.id = b; })() } }).id', 'expectedValue');
var expectedNewTarget;
shouldBe('(new class extends A { constructor() { ((a = super(), b = new.target)=>{ this.newTarget = b; })(); expectedNewTarget = new.target;} }).newTarget', 'expectedNewTarget');
-shouldThrow('(new class extends A { constructor() { ((a = super.getValue())=>{ this.id = a; })() } })', '"ReferenceError: Cannot access uninitialized variable."');
-shouldThrow('(new class extends A { constructor() { ((a = super.getValue(), b=super())=>{ this.id = a; })() } })', '"ReferenceError: Cannot access uninitialized variable."');
-shouldThrow('(new class extends F { constructor() { ((a = super.prop)=>{ return a; })() } })', '"ReferenceError: Cannot access uninitialized variable."');
-shouldThrow('(new class extends F { constructor() { ((a = super.prop, b=super())=>{ return a; })() } })', '"ReferenceError: Cannot access uninitialized variable."');
-shouldThrow('(new class extends F { constructor() { ((a = (super.prop = "value"))=>{ this.id = a; })() } })', '"ReferenceError: Cannot access uninitialized variable."');
-shouldThrow('(new class extends F { constructor() { ((a = (super.prop = "value"), b=super())=>{ this.id = a; })() } })', '"ReferenceError: Cannot access uninitialized variable."');
-shouldThrow('(new class extends F { constructor() { ((a = super.genGetParentValue().next().value)=>{ this.id = a; })() } })', '"ReferenceError: Cannot access uninitialized variable."');
-shouldThrow('(new class extends F { constructor() { ((a = super.genGetParentValue().next().value, b=super())=>{ this.id = a; })() } })', '"ReferenceError: Cannot access uninitialized variable."');
+shouldThrow('(new class extends A { constructor() { ((a = super.getValue())=>{ this.id = a; })() } })', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`);
+shouldThrow('(new class extends A { constructor() { ((a = super.getValue(), b=super())=>{ this.id = a; })() } })', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`);
+shouldThrow('(new class extends F { constructor() { ((a = super.prop)=>{ return a; })() } })', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`);
+shouldThrow('(new class extends F { constructor() { ((a = super.prop, b=super())=>{ return a; })() } })', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`);
+shouldThrow('(new class extends F { constructor() { ((a = (super.prop = "value"))=>{ this.id = a; })() } })', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`);
+shouldThrow('(new class extends F { constructor() { ((a = (super.prop = "value"), b=super())=>{ this.id = a; })() } })', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`);
+shouldThrow('(new class extends F { constructor() { ((a = super.genGetParentValue().next().value)=>{ this.id = a; })() } })', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`);
+shouldThrow('(new class extends F { constructor() { ((a = super.genGetParentValue().next().value, b=super())=>{ this.id = a; })() } })', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`);
var successfullyParsed = true;
Modified: trunk/LayoutTests/js/script-tests/class-syntax-super.js (271119 => 271120)
--- trunk/LayoutTests/js/script-tests/class-syntax-super.js 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/LayoutTests/js/script-tests/class-syntax-super.js 2021-01-02 19:27:42 UTC (rev 271120)
@@ -88,7 +88,7 @@
shouldBeTrue('(new Base) instanceof Base');
shouldBeTrue('(new Derived) instanceof Derived');
shouldBeTrue('(new DerivedWithEval) instanceof DerivedWithEval');
-shouldThrow('(new DerivedWithEval(true))', '"ReferenceError: Cannot access uninitialized variable."');
+shouldThrow('(new DerivedWithEval(true))', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`);
shouldBe('(new Derived).callBaseMethod()', 'baseMethodValue');
shouldBe('x = (new Derived).callBaseMethod; x()', 'baseMethodValue');
shouldBe('(new Derived).callBaseMethodInGetter', 'baseMethodValue');
@@ -117,7 +117,7 @@
shouldBeTrue('new (class extends Base { constructor() { super(); return undefined } }) instanceof Object');
shouldBe('x = { }; new (class extends Base { constructor() { return x } });', 'x');
shouldBeFalse('x instanceof Base');
-shouldThrow('new (class extends Base { constructor() { } })', '"ReferenceError: Cannot access uninitialized variable."');
+shouldThrow('new (class extends Base { constructor() { } })', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`);
shouldThrow('new (class extends Base { constructor() { return 1; } })', '"TypeError: Cannot return a non-object type in the constructor of a derived class."');
shouldThrow('new (class extends null { constructor() { return undefined } })');
shouldThrow('new (class extends null { constructor() { super(); return undefined } })', '"TypeError: function is not a constructor (evaluating \'super()\')"');
@@ -142,9 +142,9 @@
shouldThrow('(new (class { method() { (function () { eval("super.method()");})(); }})).method()', '"SyntaxError: super is not valid in this context."');
shouldThrow('new (class extends Base { constructor() { super(); super();}})', '"ReferenceError: \'super()\' can\'t be called more than once in a constructor."');
-shouldThrow('(new class D extends class { m() {}} { constructor() { eval(\'super["m"]()\') } })', '"ReferenceError: Cannot access uninitialized variable."');
-shouldThrow('new class extends class { m() {}} { constructor() { super["m"](super()) } }', '"ReferenceError: Cannot access uninitialized variable."');
-shouldThrow('(new class D extends class { m() {}} { constructor(f) { super[f()]() } }(()=>"m"))', '"ReferenceError: Cannot access uninitialized variable."');
+shouldThrow('(new class D extends class { m() {}} { constructor() { eval(\'super["m"]()\') } })', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`);
+shouldThrow('new class extends class { m() {}} { constructor() { super["m"](super()) } }', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`);
+shouldThrow('(new class D extends class { m() {}} { constructor(f) { super[f()]() } }(()=>"m"))', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`);
shouldNotThrow('(new class D extends class { m() {}} { constructor() { super(); eval(\'super["m"]()\') } })');
shouldThrow('new class extends class { m() {}} { constructor() { super(); super["m"](super()) } }', '"ReferenceError: \'super()\' can\'t be called more than once in a constructor."');
Modified: trunk/Source/_javascript_Core/ChangeLog (271119 => 271120)
--- trunk/Source/_javascript_Core/ChangeLog 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-01-02 19:27:42 UTC (rev 271120)
@@ -1,5 +1,34 @@
2021-01-02 Alexey Shvayka <[email protected]>
+ Improve error message for uninitialized |this| in derived constructor
+ https://bugs.webkit.org/show_bug.cgi?id=220221
+
+ Reviewed by Yusuke Suzuki.
+
+ Since class constructors perform `return this;` by default, and derived
+ constructors require `super()` to be called before |this| access, regular
+ TDZ error message is quite confusing, given the following code:
+
+ `new (class extends Object { constructor() { } });`
+
+ Considering that currently op_check_tdz is called on thisRegister() only
+ in derived constructors, this patch modifies its slow path to throw a
+ helpful error message that covers |this| access and non-object returns.
+
+ V8 and SpiderMonkey have similar error messages, mentioning `super()`.
+
+ slow_path_throw_tdz_error is merged into slow_path_check_tdz, which is
+ invoked from baseline JIT, so we can reliably acquire the bytecode and
+ avoid code duplication.
+
+ * llint/LowLevelInterpreter32_64.asm:
+ * llint/LowLevelInterpreter64.asm:
+ * runtime/CommonSlowPaths.cpp:
+ (JSC::JSC_DEFINE_COMMON_SLOW_PATH):
+ * runtime/CommonSlowPaths.h:
+
+2021-01-02 Alexey Shvayka <[email protected]>
+
Don't throw if `function.caller` is a non-strict / generator / async function
https://bugs.webkit.org/show_bug.cgi?id=220216
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm (271119 => 271120)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm 2021-01-02 19:27:42 UTC (rev 271120)
@@ -838,7 +838,7 @@
get(m_targetVirtualRegister, t0)
loadConstantOrVariableTag(size, t0, t1)
bineq t1, EmptyValueTag, .opNotTDZ
- callSlowPath(_slow_path_throw_tdz_error)
+ callSlowPath(_slow_path_check_tdz)
.opNotTDZ:
dispatch()
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (271119 => 271120)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2021-01-02 19:27:42 UTC (rev 271120)
@@ -824,7 +824,7 @@
get(m_targetVirtualRegister, t0)
loadConstantOrVariable(size, t0, t1)
bqneq t1, ValueEmpty, .opNotTDZ
- callSlowPath(_slow_path_throw_tdz_error)
+ callSlowPath(_slow_path_check_tdz)
.opNotTDZ:
dispatch()
Modified: trunk/Source/_javascript_Core/runtime/CommonSlowPaths.cpp (271119 => 271120)
--- trunk/Source/_javascript_Core/runtime/CommonSlowPaths.cpp 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/Source/_javascript_Core/runtime/CommonSlowPaths.cpp 2021-01-02 19:27:42 UTC (rev 271120)
@@ -371,16 +371,14 @@
RETURN_WITH_PROFILING_CUSTOM(bytecode.m_srcDst, value, PROFILE_VALUE(value));
}
-JSC_DEFINE_COMMON_SLOW_PATH(slow_path_throw_tdz_error)
-{
- BEGIN();
- THROW(createTDZError(globalObject));
-}
-
JSC_DEFINE_COMMON_SLOW_PATH(slow_path_check_tdz)
{
BEGIN();
- THROW(createTDZError(globalObject));
+ auto bytecode = pc->as<OpCheckTdz>();
+ if (bytecode.m_targetVirtualRegister == codeBlock->thisRegister())
+ THROW(createReferenceError(globalObject, "'super()' must be called in derived constructor before accessing |this| or returning non-object."_s));
+ else
+ THROW(createTDZError(globalObject));
}
JSC_DEFINE_COMMON_SLOW_PATH(slow_path_throw_strict_mode_readonly_property_write_error)
Modified: trunk/Source/_javascript_Core/runtime/CommonSlowPaths.h (271119 => 271120)
--- trunk/Source/_javascript_Core/runtime/CommonSlowPaths.h 2021-01-02 18:41:47 UTC (rev 271119)
+++ trunk/Source/_javascript_Core/runtime/CommonSlowPaths.h 2021-01-02 19:27:42 UTC (rev 271120)
@@ -214,7 +214,6 @@
JSC_DECLARE_COMMON_SLOW_PATH(slow_path_create_this);
JSC_DECLARE_COMMON_SLOW_PATH(slow_path_enter);
JSC_DECLARE_COMMON_SLOW_PATH(slow_path_to_this);
-JSC_DECLARE_COMMON_SLOW_PATH(slow_path_throw_tdz_error);
JSC_DECLARE_COMMON_SLOW_PATH(slow_path_check_tdz);
JSC_DECLARE_COMMON_SLOW_PATH(slow_path_throw_strict_mode_readonly_property_write_error);
JSC_DECLARE_COMMON_SLOW_PATH(slow_path_not);