summaryrefslogtreecommitdiffstats
path: root/js/src/tests/non262/class
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/tests/non262/class
parentInitial commit. (diff)
downloadfirefox-esr-upstream.tar.xz
firefox-esr-upstream.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--js/src/tests/non262/class/boundFunctionSubclassing.js37
-rw-r--r--js/src/tests/non262/class/browser.js0
-rw-r--r--js/src/tests/non262/class/bytecodePatternMatching.js29
-rw-r--r--js/src/tests/non262/class/classConstructorNoCall.js21
-rw-r--r--js/src/tests/non262/class/classHeritage.js97
-rw-r--r--js/src/tests/non262/class/className.js248
-rw-r--r--js/src/tests/non262/class/classPrototype.js65
-rw-r--r--js/src/tests/non262/class/compPropDestr.js11
-rw-r--r--js/src/tests/non262/class/compPropNames.js243
-rw-r--r--js/src/tests/non262/class/constructorCalled.js45
-rw-r--r--js/src/tests/non262/class/defaultConstructorBase.js18
-rw-r--r--js/src/tests/non262/class/defaultConstructorDerivedSpread.js23
-rw-r--r--js/src/tests/non262/class/defaultConstructorNotCallable.js8
-rw-r--r--js/src/tests/non262/class/derivedConstructorArrowEvalBinding.js12
-rw-r--r--js/src/tests/non262/class/derivedConstructorArrowEvalClosed.js11
-rw-r--r--js/src/tests/non262/class/derivedConstructorArrowEvalEscape.js13
-rw-r--r--js/src/tests/non262/class/derivedConstructorArrowEvalEscapeUninitialized.js38
-rw-r--r--js/src/tests/non262/class/derivedConstructorArrowEvalGetThis.js10
-rw-r--r--js/src/tests/non262/class/derivedConstructorArrowEvalNestedSuperCall.js34
-rw-r--r--js/src/tests/non262/class/derivedConstructorArrowEvalSuperCall.js18
-rw-r--r--js/src/tests/non262/class/derivedConstructorInlining.js19
-rw-r--r--js/src/tests/non262/class/derivedConstructorName.js11
-rw-r--r--js/src/tests/non262/class/derivedConstructorReturnPrimitive.js15
-rw-r--r--js/src/tests/non262/class/derivedConstructorTDZExplicitThis.js12
-rw-r--r--js/src/tests/non262/class/derivedConstructorTDZOffEdge.js11
-rw-r--r--js/src/tests/non262/class/derivedConstructorTDZReturnAliasedTry.js14
-rw-r--r--js/src/tests/non262/class/derivedConstructorTDZReturnObject.js13
-rw-r--r--js/src/tests/non262/class/derivedConstructorTDZReturnTry.js16
-rw-r--r--js/src/tests/non262/class/derivedConstructorTDZReturnUndefined.js13
-rw-r--r--js/src/tests/non262/class/extendBuiltinConstructors.js110
-rw-r--r--js/src/tests/non262/class/fields-instance-class-name-binding-eval.js40
-rw-r--r--js/src/tests/non262/class/fields-instance-class-name-binding.js40
-rw-r--r--js/src/tests/non262/class/fields-static-class-name-binding-eval.js59
-rw-r--r--js/src/tests/non262/class/fields-static-class-name-binding.js59
-rw-r--r--js/src/tests/non262/class/geterNoExprClosure.js20
-rw-r--r--js/src/tests/non262/class/innerBinding.js86
-rw-r--r--js/src/tests/non262/class/member-expr-after-super.js44
-rw-r--r--js/src/tests/non262/class/methDefn.js204
-rw-r--r--js/src/tests/non262/class/methDefnGen.js83
-rw-r--r--js/src/tests/non262/class/method-named-static.js56
-rw-r--r--js/src/tests/non262/class/methodInstallation.js101
-rw-r--r--js/src/tests/non262/class/methodName.js40
-rw-r--r--js/src/tests/non262/class/methodOverwrites.js80
-rw-r--r--js/src/tests/non262/class/methodsPrototype.js39
-rw-r--r--js/src/tests/non262/class/newTargetArgumentsIntact.js44
-rw-r--r--js/src/tests/non262/class/newTargetArrow.js24
-rw-r--r--js/src/tests/non262/class/newTargetBound.js16
-rw-r--r--js/src/tests/non262/class/newTargetCCW.js10
-rw-r--r--js/src/tests/non262/class/newTargetDVG.js7
-rw-r--r--js/src/tests/non262/class/newTargetDefaults.js25
-rw-r--r--js/src/tests/non262/class/newTargetDirectInvoke.js50
-rw-r--r--js/src/tests/non262/class/newTargetEval.js40
-rw-r--r--js/src/tests/non262/class/newTargetGenerators.js14
-rw-r--r--js/src/tests/non262/class/newTargetMethods.js51
-rw-r--r--js/src/tests/non262/class/newTargetNonFunction.js10
-rw-r--r--js/src/tests/non262/class/newTargetProxyNative.js5
-rw-r--r--js/src/tests/non262/class/outerBinding.js48
-rw-r--r--js/src/tests/non262/class/parenExprToString.js8
-rw-r--r--js/src/tests/non262/class/shell.js10
-rw-r--r--js/src/tests/non262/class/staticConstructor.js22
-rw-r--r--js/src/tests/non262/class/staticMethods.js15
-rw-r--r--js/src/tests/non262/class/strictExecution.js38
-rw-r--r--js/src/tests/non262/class/stringConstructor.js12
-rw-r--r--js/src/tests/non262/class/subclassedArrayUnboxed.js22
-rw-r--r--js/src/tests/non262/class/superCallBadDynamicSuperClass.js12
-rw-r--r--js/src/tests/non262/class/superCallBadNewTargetPrototype.js25
-rw-r--r--js/src/tests/non262/class/superCallBaseInvoked.js55
-rw-r--r--js/src/tests/non262/class/superCallIllegal.js7
-rw-r--r--js/src/tests/non262/class/superCallInvalidBase.js9
-rw-r--r--js/src/tests/non262/class/superCallOrder.js28
-rw-r--r--js/src/tests/non262/class/superCallProperBase.js34
-rw-r--r--js/src/tests/non262/class/superCallSpreadCall.js27
-rw-r--r--js/src/tests/non262/class/superCallThisInit.js48
-rw-r--r--js/src/tests/non262/class/superElemDelete.js68
-rw-r--r--js/src/tests/non262/class/superPropBasicCalls.js27
-rw-r--r--js/src/tests/non262/class/superPropBasicChain.js11
-rw-r--r--js/src/tests/non262/class/superPropBasicGetter.js36
-rw-r--r--js/src/tests/non262/class/superPropBasicNew.js17
-rw-r--r--js/src/tests/non262/class/superPropChains.js58
-rw-r--r--js/src/tests/non262/class/superPropDVG.js17
-rw-r--r--js/src/tests/non262/class/superPropDelete.js64
-rw-r--r--js/src/tests/non262/class/superPropDerivedCalls.js77
-rw-r--r--js/src/tests/non262/class/superPropDestructuring.js43
-rw-r--r--js/src/tests/non262/class/superPropEvalInsideArrow.js11
-rw-r--r--js/src/tests/non262/class/superPropEvalInsideNested.js13
-rw-r--r--js/src/tests/non262/class/superPropFor.js25
-rw-r--r--js/src/tests/non262/class/superPropHeavyweightArrow.js12
-rw-r--r--js/src/tests/non262/class/superPropHomeObject.js61
-rw-r--r--js/src/tests/non262/class/superPropIncDecElem.js24
-rw-r--r--js/src/tests/non262/class/superPropLazyInnerFunction.js19
-rw-r--r--js/src/tests/non262/class/superPropNoOverwriting.js58
-rw-r--r--js/src/tests/non262/class/superPropOrdering.js93
-rw-r--r--js/src/tests/non262/class/superPropProtoChanges.js22
-rw-r--r--js/src/tests/non262/class/superPropProxies.js83
-rw-r--r--js/src/tests/non262/class/superPropSkips.js45
-rw-r--r--js/src/tests/non262/class/superPropStatics.js34
-rw-r--r--js/src/tests/non262/class/superPropStrictAssign.js23
-rw-r--r--js/src/tests/non262/class/superThisStrictNoBoxing.js31
-rw-r--r--js/src/tests/non262/class/uninitializedThisError.js53
99 files changed, 3907 insertions, 0 deletions
diff --git a/js/src/tests/non262/class/boundFunctionSubclassing.js b/js/src/tests/non262/class/boundFunctionSubclassing.js
new file mode 100644
index 0000000000..be9058bb9e
--- /dev/null
+++ b/js/src/tests/non262/class/boundFunctionSubclassing.js
@@ -0,0 +1,37 @@
+class func extends Function { }
+let inst = new func("x", "return this.bar + x");
+
+// First, ensure that we get sane prototype chains for the bound instance
+let bound = inst.bind({bar: 3}, 4);
+assertEq(bound instanceof func, true);
+assertEq(bound(), 7);
+
+// Check the corner case for Function.prototype.bind where the function has
+// a null [[Prototype]]
+Object.setPrototypeOf(inst, null);
+bound = Function.prototype.bind.call(inst, {bar:1}, 3);
+assertEq(Object.getPrototypeOf(bound), null);
+assertEq(bound(), 4);
+
+// Check that we actually pass the proper new.target when calling super()
+function toBind() { }
+
+var boundArgs = [];
+for (let i = 0; i < 5; i++) {
+ boundArgs.push(i);
+ let bound = toBind.bind(undefined, ...boundArgs);
+
+ // We have to wire it up by hand to allow us to use a bound function
+ // as a superclass, but it's doable.
+ bound.prototype = {};
+ class test extends bound { };
+ let passedArgs = [];
+ for (let j = 0; j < 15; j++) {
+ passedArgs.push(j);
+ assertEq(Object.getPrototypeOf(new test(...passedArgs)), test.prototype);
+ }
+}
+
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/browser.js b/js/src/tests/non262/class/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/non262/class/browser.js
diff --git a/js/src/tests/non262/class/bytecodePatternMatching.js b/js/src/tests/non262/class/bytecodePatternMatching.js
new file mode 100644
index 0000000000..446184f805
--- /dev/null
+++ b/js/src/tests/non262/class/bytecodePatternMatching.js
@@ -0,0 +1,29 @@
+// Constructors can't be called so we can't pattern match
+// them in replace and sort.
+function a() {
+ var b = {a: "A"};
+
+ class X {
+ constructor(a) {
+ return b[a]
+ }
+ };
+
+ assertThrowsInstanceOf(() => "a".replace(/a/, X), TypeError);
+}
+
+function b() {
+ class X {
+ constructor(x, y) {
+ return x - y;
+ }
+ }
+
+ assertThrowsInstanceOf(() => [1, 2, 3].sort(X), TypeError);
+}
+
+a();
+b();
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "OK");
diff --git a/js/src/tests/non262/class/classConstructorNoCall.js b/js/src/tests/non262/class/classConstructorNoCall.js
new file mode 100644
index 0000000000..f59f87b9c5
--- /dev/null
+++ b/js/src/tests/non262/class/classConstructorNoCall.js
@@ -0,0 +1,21 @@
+// Class constructors don't have a [[Call]]
+class Foo {
+ constructor() { }
+}
+
+assertThrowsInstanceOf(Foo, TypeError);
+
+class Bar extends Foo {
+ constructor() { }
+}
+
+assertThrowsInstanceOf(Bar, TypeError);
+
+assertThrowsInstanceOf(class { constructor() { } }, TypeError);
+assertThrowsInstanceOf(class extends Foo { constructor() { } }, TypeError);
+
+assertThrowsInstanceOf(class foo { constructor() { } }, TypeError);
+assertThrowsInstanceOf(class foo extends Foo { constructor() { } }, TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/classHeritage.js b/js/src/tests/non262/class/classHeritage.js
new file mode 100644
index 0000000000..478c23fc21
--- /dev/null
+++ b/js/src/tests/non262/class/classHeritage.js
@@ -0,0 +1,97 @@
+// It's an error to have a non-constructor as your heritage
+assertThrowsInstanceOf(() => eval(`class a extends Math.sin {
+ constructor() { }
+ }`), TypeError);
+assertThrowsInstanceOf(() => eval(`(class a extends Math.sin {
+ constructor() { }
+ })`), TypeError);
+
+// Unless it's null, in which case it works like a normal class, except that
+// the prototype object does not inherit from Object.prototype.
+class basic {
+ constructor() { }
+}
+class nullExtends extends null {
+ constructor() { }
+}
+var nullExtendsExpr = class extends null { constructor() { } };
+
+assertEq(Object.getPrototypeOf(basic), Function.prototype);
+assertEq(Object.getPrototypeOf(basic.prototype), Object.prototype);
+
+for (let extension of [nullExtends, nullExtendsExpr]) {
+ assertEq(Object.getPrototypeOf(extension), Function.prototype);
+ assertEq(Object.getPrototypeOf(extension.prototype), null);
+}
+
+var baseMethodCalled;
+var staticMethodCalled;
+var overrideCalled;
+class base {
+ constructor() { };
+ method() { baseMethodCalled = true; }
+ static staticMethod() { staticMethodCalled = true; }
+ override() { overrideCalled = "base" }
+}
+class derived extends base {
+ constructor() { super(); };
+ override() { overrideCalled = "derived"; }
+}
+var derivedExpr = class extends base {
+ constructor() { super(); };
+ override() { overrideCalled = "derived"; }
+};
+
+// Make sure we get the right object layouts.
+for (let extension of [derived, derivedExpr]) {
+ baseMethodCalled = false;
+ staticMethodCalled = false;
+ overrideCalled = "";
+ // Make sure we get the right object layouts.
+ assertEq(Object.getPrototypeOf(extension), base);
+ assertEq(Object.getPrototypeOf(extension.prototype), base.prototype);
+
+ // We do inherit the methods, right?
+ (new extension()).method();
+ assertEq(baseMethodCalled, true);
+
+ // But we can still override them?
+ (new extension()).override();
+ assertEq(overrideCalled, "derived");
+
+ // What about the statics?
+ extension.staticMethod();
+ assertEq(staticMethodCalled, true);
+}
+
+// Gotta extend an object, or null.
+function nope() {
+ class Foo extends "Bar" {
+ constructor() { }
+ }
+}
+function nopeExpr() {
+ (class extends "Bar" {
+ constructor() { }
+ });
+}
+assertThrowsInstanceOf(nope, TypeError);
+assertThrowsInstanceOf(nopeExpr, TypeError);
+
+// The .prototype of the extension must be an object, or null.
+nope.prototype = "not really, no";
+function stillNo() {
+ class Foo extends nope {
+ constructor() { }
+ }
+}
+function stillNoExpr() {
+ (class extends nope {
+ constructor() { }
+ });
+}
+assertThrowsInstanceOf(stillNo, TypeError);
+assertThrowsInstanceOf(stillNoExpr, TypeError);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "OK");
diff --git a/js/src/tests/non262/class/className.js b/js/src/tests/non262/class/className.js
new file mode 100644
index 0000000000..e72510e18d
--- /dev/null
+++ b/js/src/tests/non262/class/className.js
@@ -0,0 +1,248 @@
+function testName(C, name, hasValue, hasGetter, hasSetter, isFunction=false) {
+ if (isFunction) {
+ assertEq(typeof C.name, "function");
+ } else {
+ assertEq(C.name, name);
+ }
+
+ var desc = Object.getOwnPropertyDescriptor(C, "name");
+ if (!hasValue && !hasGetter && !hasSetter) {
+ assertEq(desc, undefined);
+ return;
+ }
+
+ if (hasValue) {
+ assertEq("value" in desc, true);
+ if (isFunction) {
+ assertEq(typeof desc.value, "function");
+ } else {
+ assertEq(desc.value, name);
+ }
+ // FIXME: Methods defined in classes should not be enumerable
+ // (bug 1144630).
+ // assertEq(desc.enumerable, false);
+ assertEq(desc.configurable, true);
+
+ assertEq("get" in desc, false);
+ assertEq("set" in desc, false);
+
+ return;
+ }
+
+ assertEq("value" in desc, false);
+
+ if (hasGetter) {
+ assertEq("get" in desc, true);
+ assertEq(desc.get(), name);
+ // assertEq(desc.enumerable, false);
+ assertEq(desc.configurable, true);
+ } else {
+ assertEq("get" in desc, true);
+ assertEq(desc.get, undefined);
+ // assertEq(desc.enumerable, false);
+ assertEq(desc.configurable, true);
+ }
+
+ if (hasSetter) {
+ assertEq("set" in desc, true);
+ assertEq(typeof desc.set, "function");
+ // assertEq(desc.enumerable, false);
+ assertEq(desc.configurable, true);
+ } else {
+ assertEq("set" in desc, true);
+ assertEq(desc.set, undefined);
+ // assertEq(desc.enumerable, false);
+ assertEq(desc.configurable, true);
+ }
+}
+
+// ---- declaration ---
+
+class Decl {
+ constructor() {}
+}
+testName(Decl, "Decl", true, false, false);
+
+class DeclWithFunc {
+ constructor() {}
+ static name() {}
+}
+testName(DeclWithFunc, "DeclWithFunc", true, false, false, true);
+
+class DeclWithGetter {
+ constructor() {}
+ static get name() { return "base"; }
+}
+testName(DeclWithGetter, "base", false, true, false);
+
+class DeclWithSetter {
+ constructor() {}
+ static set name(v) {}
+}
+testName(DeclWithSetter, undefined, false, false, true);
+
+class DeclWithGetterSetter {
+ constructor() {}
+ static get name() { return "base"; }
+ static set name(v) {}
+}
+testName(DeclWithGetterSetter, "base", false, true, true);
+
+function prop() {
+ return "name";
+}
+class DeclWithComputed {
+ constructor() {}
+ static get [prop()]() { return "base"; }
+}
+testName(DeclWithGetterSetter, "base", false, true, true);
+
+class ExtendedDecl1 extends Decl {
+ constructor() {}
+}
+testName(ExtendedDecl1, "ExtendedDecl1", true, false, false);
+delete ExtendedDecl1.name;
+testName(ExtendedDecl1, "Decl", false, false, false);
+
+class ExtendedDecl2 extends DeclWithGetterSetter {
+ constructor() {}
+ static get name() { return "extend"; }
+}
+testName(ExtendedDecl2, "extend", false, true, false);
+delete ExtendedDecl2.name;
+testName(ExtendedDecl2, "base", false, false, false);
+
+class ExtendedDecl3 extends DeclWithGetterSetter {
+ constructor() {}
+ static set name(v) {}
+}
+testName(ExtendedDecl3, undefined, false, false, true);
+delete ExtendedDecl3.name;
+testName(ExtendedDecl3, "base", false, false, false);
+
+// ---- expression ---
+
+let Expr = class Expr {
+ constructor() {}
+};
+testName(Expr, "Expr", true, false, false);
+
+let ExprWithGetter = class ExprWithGetter {
+ constructor() {}
+ static get name() { return "base"; }
+};
+testName(ExprWithGetter, "base", false, true, false);
+
+let ExprWithSetter = class ExprWithSetter {
+ constructor() {}
+ static set name(v) {}
+};
+testName(ExprWithSetter, undefined, false, false, true);
+
+let ExprWithGetterSetter = class ExprWithGetterSetter {
+ constructor() {}
+ static get name() { return "base"; }
+ static set name(v) {}
+};
+testName(ExprWithGetterSetter, "base", false, true, true);
+
+
+let ExtendedExpr1 = class ExtendedExpr1 extends Expr {
+ constructor() {}
+};
+testName(ExtendedExpr1, "ExtendedExpr1", true, false, false);
+delete ExtendedExpr1.name;
+testName(ExtendedExpr1, "Expr", false, false, false);
+
+let ExtendedExpr2 = class ExtendedExpr2 extends ExprWithGetterSetter {
+ constructor() {}
+ static get name() { return "extend"; }
+};
+testName(ExtendedExpr2, "extend", false, true, false);
+delete ExtendedExpr2.name;
+testName(ExtendedExpr2, "base", false, false, false);
+
+let ExtendedExpr3 = class ExtendedExpr3 extends ExprWithGetterSetter {
+ constructor() {}
+ static set name(v) {}
+};
+testName(ExtendedExpr3, undefined, false, false, true);
+delete ExtendedExpr3.name;
+testName(ExtendedExpr3, "base", false, false, false);
+
+// ---- anonymous ----
+
+// Anonymous class expressions use the empty string as the default name property.
+// Use property assignment to avoid setting name property.
+let tmp = {};
+let Anon = tmp.value = class {
+ constructor() {}
+};
+testName(Anon, "", true, false, false);
+
+let AnonDefault = tmp.value = class { };
+testName(AnonDefault, "", true, false, false);
+
+let AnonWithGetter = tmp.value = class {
+ constructor() {}
+ static get name() { return "base"; }
+};
+testName(AnonWithGetter, "base", false, true, false);
+
+let AnonWithSetter = tmp.value = class {
+ constructor() {}
+ static set name(v) {}
+};
+testName(AnonWithSetter, undefined, false, false, true);
+
+let AnonWithGetterSetter = tmp.value = class {
+ constructor() {}
+ static get name() { return "base"; }
+ static set name(v) {}
+};
+testName(AnonWithGetterSetter, "base", false, true, true);
+
+
+let ExtendedAnon1 = tmp.value = class extends Anon {
+ constructor() {}
+};
+testName(ExtendedAnon1, "", true, false, false);
+
+let ExtendedAnonDefault = tmp.value = class extends Anon { };
+testName(ExtendedAnonDefault, "", true, false, false);
+
+let ExtendedAnon2 = tmp.value = class extends AnonWithGetterSetter {
+ constructor() {}
+ static get name() { return "extend"; }
+};
+testName(ExtendedAnon2, "extend", false, true, false);
+delete ExtendedAnon2.name;
+testName(ExtendedAnon2, "base", false, false, false);
+
+let ExtendedAnon3 = tmp.value = class extends AnonWithGetterSetter {
+ constructor() {}
+ static set name(v) {}
+};
+testName(ExtendedAnon3, undefined, false, false, true);
+delete ExtendedAnon3.name;
+testName(ExtendedAnon3, "base", false, false, false);
+
+// ---- mixed ----
+
+let ExtendedExpr4 = class ExtendedExpr4 extends Anon {
+ constructor() {}
+}
+testName(ExtendedExpr4, "ExtendedExpr4", true, false, false);
+delete ExtendedExpr4.name;
+testName(ExtendedExpr4, "", false, false, false);
+
+let ExtendedExpr5 = class ExtendedExpr5 extends AnonWithGetterSetter {
+ constructor() {}
+ static get name() { return "extend"; }
+}
+testName(ExtendedExpr5, "extend", false, true, false);
+delete ExtendedExpr5.name;
+testName(ExtendedExpr5, "base", false, false, false);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "OK");
diff --git a/js/src/tests/non262/class/classPrototype.js b/js/src/tests/non262/class/classPrototype.js
new file mode 100644
index 0000000000..0d2296037c
--- /dev/null
+++ b/js/src/tests/non262/class/classPrototype.js
@@ -0,0 +1,65 @@
+// The prototype of a class is a non-writable, non-configurable, non-enumerable data property.
+class a { constructor() { } }
+let b = class { constructor() { } };
+for (let test of [a,b]) {
+ var protoDesc = Object.getOwnPropertyDescriptor(test, "prototype");
+ assertEq(protoDesc.writable, false);
+ assertEq(protoDesc.configurable, false);
+ assertEq(protoDesc.enumerable, false);
+
+ var prototype = protoDesc.value;
+ assertEq(typeof prototype, "object");
+ assertEq(Object.getPrototypeOf(prototype), Object.prototype);
+ assertEq(Object.isExtensible(prototype), true);
+
+ var desiredPrototype = {};
+ Object.defineProperty(desiredPrototype, "constructor", { writable: true,
+ configurable: true,
+ enumerable: false,
+ value: test });
+ assertDeepEq(prototype, desiredPrototype);
+}
+
+// As such, it should by a TypeError to try and overwrite "prototype" with a
+// static member. The only way to try is with a computed property name; the rest
+// are early errors.
+assertThrowsInstanceOf(() => eval(`
+ class a {
+ constructor() { };
+ static ["prototype"]() { }
+ }
+ `), TypeError);
+assertThrowsInstanceOf(() => eval(`
+ class a {
+ constructor() { };
+ static get ["prototype"]() { }
+ }
+ `), TypeError);
+assertThrowsInstanceOf(() => eval(`
+ class a {
+ constructor() { };
+ static set ["prototype"](x) { }
+ }
+ `), TypeError);
+
+assertThrowsInstanceOf(() => eval(`(
+ class a {
+ constructor() { };
+ static ["prototype"]() { }
+ }
+ )`), TypeError);
+assertThrowsInstanceOf(() => eval(`(
+ class a {
+ constructor() { };
+ static get ["prototype"]() { }
+ }
+ )`), TypeError);
+assertThrowsInstanceOf(() => eval(`(
+ class a {
+ constructor() { };
+ static set ["prototype"](x) { }
+ }
+ )`), TypeError);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "OK");
diff --git a/js/src/tests/non262/class/compPropDestr.js b/js/src/tests/non262/class/compPropDestr.js
new file mode 100644
index 0000000000..2bd8cbd49a
--- /dev/null
+++ b/js/src/tests/non262/class/compPropDestr.js
@@ -0,0 +1,11 @@
+var BUGNUMBER = 924688;
+var summary = 'Computed Property Names';
+
+print(BUGNUMBER + ": " + summary);
+
+var key = "z";
+var { [key]: foo } = { z: "bar" };
+assertEq(foo, "bar");
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0, "ok");
diff --git a/js/src/tests/non262/class/compPropNames.js b/js/src/tests/non262/class/compPropNames.js
new file mode 100644
index 0000000000..1c4064d8a5
--- /dev/null
+++ b/js/src/tests/non262/class/compPropNames.js
@@ -0,0 +1,243 @@
+var BUGNUMBER = 924688;
+var summary = 'Computed Property Names';
+
+print(BUGNUMBER + ": " + summary);
+
+// Function definitions.
+function syntaxError (script) {
+ try {
+ Function(script);
+ } catch (e) {
+ if (e instanceof SyntaxError) {
+ return;
+ }
+ }
+ throw new Error('Expected syntax error: ' + script);
+}
+
+
+// Tests begin.
+
+assertThrowsInstanceOf(function() { var a = {[field1]: "a", [field2]: "b"}; }, ReferenceError);
+
+assertThrowsInstanceOf(function() {
+ field1 = 1;
+ var a = {[field1]: "a", [field2]: "b"};
+ }, ReferenceError);
+
+var f1 = 1;
+var f2 = 2;
+var a = {[f1]: "a", [f2]: "b"};
+assertEq(a[1], "a");
+assertEq(a[2], "b");
+
+var a = {[f1]: "a", f2: "b"};
+assertEq(a[1], "a");
+assertEq(a.f2, "b");
+
+var a = {["f1"]: "a", [++f2]: "b"};
+assertEq(a.f1, "a");
+assertEq(a[3], "b");
+
+var a = {["f1"]: "a", f2: "b"};
+assertEq(a.f1, "a");
+assertEq(a.f2, "b");
+
+
+var i = 0;
+var a = {
+ ["foo" + ++i]: i,
+ ["foo" + ++i]: i,
+ ["foo" + ++i]: i
+};
+assertEq(a.foo1, 1);
+assertEq(a.foo2, 2);
+assertEq(a.foo3, 3);
+
+var expr = "abc";
+syntaxError("({[");
+syntaxError("({[expr");
+syntaxError("({[expr]");
+syntaxError("({[expr]})");
+syntaxError("({[expr] 0})");
+syntaxError("({[expr], 0})");
+syntaxError("[[expr]: 0]");
+syntaxError("({[expr]: name: 0})");
+syntaxError("({[1, 2]: 3})"); // because '1,2' is an Expression but not an AssignmentExpression
+syntaxError("({[1;]: 1})"); // and not an ExpressionStatement
+syntaxError("({[if (0) 0;]})"); // much less a Statement
+syntaxError("function f() { {[x]: 1} }"); // that's not even an ObjectLiteral
+syntaxError("function f() { [x]: 1 }"); // or that
+syntaxError('a = {[f1@]: "a", [f2]: "b"}'); // unexpected symbol at end of AssignmentExpression
+try { JSON.parse('{["a"]:4}'); } catch(e) {
+ if (!(e instanceof SyntaxError)) throw new Error('Expected syntax error');
+}
+
+// Property characteristics.
+a = { ["b"] : 4 };
+b = Object.getOwnPropertyDescriptor(a, "b");
+assertEq(b.configurable, true);
+assertEq(b.enumerable, true);
+assertEq(b.writable, true);
+assertEq(b.value, 4);
+
+// Setter and getter are not hit.
+Object.defineProperty(Object.prototype, "x", { set: function (x) { throw "FAIL"; },
+ get: function (x) { throw "FAIL"; } });
+var a = {["x"]: 0};
+assertEq(a.x, 0);
+
+a = {["x"]: 1, ["x"]: 2};
+assertEq(a.x, 2);
+a = {x: 1, ["x"]: 2};
+assertEq(a.x, 2);
+a = {["x"]: 1, x: 2};
+assertEq(a.x, 2);
+
+// Symbols
+var unique_sym = Symbol("1"), registered_sym = Symbol.for("2");
+a = { [unique_sym] : 2, [registered_sym] : 3 };
+assertEq(a[unique_sym], 2);
+assertEq(a[registered_sym], 3);
+
+// Same expression can be run several times to build objects with different property names.
+a = [];
+for (var i = 0; i < 3; i++) {
+ a[i] = {["foo" + i]: i};
+}
+assertEq(a[0].foo0, 0);
+assertEq(a[1].foo1, 1);
+assertEq(a[2].foo2, 2);
+
+// Following are stored in object's elements rather than slots.
+var i = 0;
+a = { [++i] : i,
+ [++i] : i,
+ [++i] : i,
+ [++i] : i,
+ [++i] : i,
+ [++i] : i,
+ [++i] : i,
+ [++i] : i
+}
+for (var i = 1; i < 9; i++)
+ assertEq(a[i], i);
+syntaxError("a.1");
+syntaxError("a.2");
+syntaxError("a.3");
+syntaxError("a.4");
+syntaxError("a.5");
+syntaxError("a.6");
+syntaxError("a.7");
+syntaxError("a.8");
+
+// Adding a single large index.
+var i = 0;
+a = { [++i] : i,
+ [++i] : i,
+ [++i] : i,
+ [++i] : i,
+ [++i] : i,
+ [++i] : i,
+ [++i] : i,
+ [++i] : i,
+ [3000] : 2999
+}
+for (var i = 1; i < 9; i++)
+ assertEq(a[i], i);
+assertEq(a[3000], 2999);
+
+// Defining several properties using eval.
+var code = "({";
+for (i = 0; i < 1000; i++)
+ code += "['foo' + " + i + "]: 'ok', "
+code += "['bar']: 'ok'});";
+var obj = eval(code);
+for (i = 0; i < 1000; i++)
+ assertEq(obj["foo" + i], "ok");
+assertEq(obj["bar"], "ok");
+
+// Can yield in a computed property name which is in a generator.
+function* g() {
+ var a = { [yield 1]: 2, [yield 2]: 3};
+ return a;
+}
+
+var it = g();
+var next = it.next();
+assertEq(next.done, false);
+assertEq(next.value, 1);
+next = it.next("hello");
+assertEq(next.done, false);
+assertEq(next.value, 2);
+next = it.next("world");
+assertEq(next.done, true);
+assertEq(next.value.hello, 2);
+assertEq(next.value.world, 3);
+
+// get and set.
+expr = "abc";
+syntaxError("({get [");
+syntaxError("({get [expr()");
+syntaxError("({get [expr]()");
+syntaxError("({get [expr]()})");
+syntaxError("({get [expr] 0 ()})");
+syntaxError("({get [expr], 0(})");
+syntaxError("[get [expr]: 0()]");
+syntaxError("({get [expr](: name: 0})");
+syntaxError("({get [1, 2](): 3})");
+syntaxError("({get [1;](): 1})");
+syntaxError("({get [if (0) 0;](){}})");
+syntaxError("({set [(a)");
+syntaxError("({set [expr(a)");
+syntaxError("({set [expr](a){}");
+syntaxError("({set [expr]}(a)");
+syntaxError("({set [expr](a), 0})");
+syntaxError("[set [expr](a): 0]");
+syntaxError("({set [expr](a): name: 0})");
+syntaxError("({set [1, 2](a) {return 3;}})");
+syntaxError("({set [1;](a) {return 1}})");
+syntaxError("({set [if (0) 0;](a){}})");
+syntaxError("function f() { {get [x](): 1} }");
+syntaxError("function f() { get [x](): 1 }");
+syntaxError("function f() { {set [x](a): 1} }");
+syntaxError("function f() { set [x](a): 1 }");
+f1 = "abc";
+syntaxError('a = {get [f1@](){}, set [f1](a){}}'); // unexpected symbol at end of AssignmentExpression
+syntaxError('a = {get@ [f1](){}, set [f1](a){}}'); // unexpected symbol after get
+syntaxError('a = {get [f1](){}, set@ [f1](a){}}'); // unexpected symbol after set
+
+expr = "hey";
+a = {get [expr]() { return 3; }, set[expr](v) { throw 2; }};
+assertEq(a.hey, 3);
+assertThrowsValue(() => { a.hey = 5; }, 2);
+
+// Symbols with duplicate get and set.
+expr = Symbol("hey");
+a = {get [expr]() { return 3; }, set[expr](v) { throw 2; },
+ set [expr] (w) { throw 4; }, get[expr](){return 5; }};
+assertEq(a[expr], 5);
+assertThrowsValue(() => { a[expr] = 7; }, 4);
+
+// expressions with side effects are called in the right order
+log = "";
+obj = {
+ "a": log += 'a',
+ get [log += 'b']() {},
+ [log += 'c']: log += 'd',
+ set [log += 'e'](a) {}
+};
+assertEq(log, "abcde");
+
+// assignment expressions, objects and regex in computed names
+obj = {
+ get [a = "hey"]() { return 1; },
+ get [a = {b : 4}.b]() { return 2; },
+ set [/x/.source](a) { throw 3; }
+}
+assertEq(obj.hey, 1);
+assertEq(obj[4], 2);
+assertThrowsValue(() => { obj.x = 7; }, 3);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0, "ok");
diff --git a/js/src/tests/non262/class/constructorCalled.js b/js/src/tests/non262/class/constructorCalled.js
new file mode 100644
index 0000000000..144cc08c79
--- /dev/null
+++ b/js/src/tests/non262/class/constructorCalled.js
@@ -0,0 +1,45 @@
+// The constructor specified should get called, regardless of order, or
+// other distractions
+
+var called = false;
+class a { constructor(x) { assertEq(x, 4); called = true } }
+new a(4);
+assertEq(called, true);
+
+called = false;
+var aExpr = class { constructor(x) { assertEq(x, 4); called = true } };
+new aExpr(4);
+assertEq(called, true);
+
+called = false;
+class b { constructor() { called = true } method() { } }
+new b();
+assertEq(called, true);
+
+called = false;
+var bExpr = class { constructor() { called = true } method() { } };
+new bExpr();
+assertEq(called, true);
+
+called = false;
+class c { method() { } constructor() { called = true; } }
+new c();
+assertEq(called, true);
+
+called = false;
+var cExpr = class { method() { } constructor() { called = true; } }
+new cExpr();
+assertEq(called, true);
+
+called = false;
+class d { ["constructor"]() { throw new Error("NO"); } constructor() { called = true; } }
+new d();
+assertEq(called, true);
+
+called = false;
+var dExpr = class { ["constructor"]() { throw new Error("NO"); } constructor() { called = true; } }
+new dExpr();
+assertEq(called, true);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "OK");
diff --git a/js/src/tests/non262/class/defaultConstructorBase.js b/js/src/tests/non262/class/defaultConstructorBase.js
new file mode 100644
index 0000000000..2d977935dd
--- /dev/null
+++ b/js/src/tests/non262/class/defaultConstructorBase.js
@@ -0,0 +1,18 @@
+class base {
+ method() { return 1; }
+ *gen() { return 2; }
+ static sMethod() { return 3; }
+ get answer() { return 42; }
+}
+
+// Having a default constructor should work, and also not make you lose
+// everything for no good reason
+
+assertEq(Object.getPrototypeOf(new base()), base.prototype);
+assertEq(new base().method(), 1);
+assertEq(new base().gen().next().value, 2);
+assertEq(base.sMethod(), 3);
+assertEq(new base().answer, 42);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/defaultConstructorDerivedSpread.js b/js/src/tests/non262/class/defaultConstructorDerivedSpread.js
new file mode 100644
index 0000000000..4de18ec2fb
--- /dev/null
+++ b/js/src/tests/non262/class/defaultConstructorDerivedSpread.js
@@ -0,0 +1,23 @@
+/* Make sure that the default derived class constructor has the required spread semantics.
+ *
+ * Test credit André Bargull
+ */
+
+// <https://github.com/tc39/ecma262/pull/2216> changed default derived class
+// constructors to no longer execute the spread iteration protocol.
+Array.prototype[Symbol.iterator] = function*() {
+ throw new Error("unexpected call");
+};
+
+class Base {
+ constructor(a, b) {
+ assertEq(a, 1);
+ assertEq(b, 2);
+ }
+};
+class Derived extends Base {};
+
+new Derived(1, 2);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/defaultConstructorNotCallable.js b/js/src/tests/non262/class/defaultConstructorNotCallable.js
new file mode 100644
index 0000000000..558f8dcc2f
--- /dev/null
+++ b/js/src/tests/non262/class/defaultConstructorNotCallable.js
@@ -0,0 +1,8 @@
+class badBase {}
+assertThrowsInstanceOf(badBase, TypeError);
+
+class badSub extends (class {}) {}
+assertThrowsInstanceOf(badSub, TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/derivedConstructorArrowEvalBinding.js b/js/src/tests/non262/class/derivedConstructorArrowEvalBinding.js
new file mode 100644
index 0000000000..d6b15baab3
--- /dev/null
+++ b/js/src/tests/non262/class/derivedConstructorArrowEvalBinding.js
@@ -0,0 +1,12 @@
+// Make sure it doesn't matter when we make the arrow function
+new class extends class { } {
+ constructor() {
+ let arrow = () => this;
+ assertThrowsInstanceOf(arrow, ReferenceError);
+ super();
+ assertEq(arrow(), this);
+ }
+}();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/derivedConstructorArrowEvalClosed.js b/js/src/tests/non262/class/derivedConstructorArrowEvalClosed.js
new file mode 100644
index 0000000000..431a73c92f
--- /dev/null
+++ b/js/src/tests/non262/class/derivedConstructorArrowEvalClosed.js
@@ -0,0 +1,11 @@
+new class extends class { } {
+ constructor() {
+ let a1 = () => this;
+ let a2 = (() => super());
+ assertThrowsInstanceOf(a1, ReferenceError);
+ assertEq(a2(), a1());
+ }
+}();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/derivedConstructorArrowEvalEscape.js b/js/src/tests/non262/class/derivedConstructorArrowEvalEscape.js
new file mode 100644
index 0000000000..2676d4b946
--- /dev/null
+++ b/js/src/tests/non262/class/derivedConstructorArrowEvalEscape.js
@@ -0,0 +1,13 @@
+let arrow;
+
+class foo extends class { } {
+ constructor() {
+ arrow = () => this;
+ super();
+ }
+}
+
+assertEq(new foo(), arrow());
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/derivedConstructorArrowEvalEscapeUninitialized.js b/js/src/tests/non262/class/derivedConstructorArrowEvalEscapeUninitialized.js
new file mode 100644
index 0000000000..970beb0436
--- /dev/null
+++ b/js/src/tests/non262/class/derivedConstructorArrowEvalEscapeUninitialized.js
@@ -0,0 +1,38 @@
+let superArrow;
+let thisArrow;
+
+let thisStash;
+
+class base {
+ constructor() {
+ // We run this constructor twice as part of the double init check
+ if (!thisStash)
+ thisStash = {prop:45};
+ return thisStash;
+ }
+}
+
+class foo extends base {
+ constructor() {
+ superArrow = (()=>super());
+ thisArrow = ()=>this;
+ }
+}
+
+// Populate the arrow function saves. Since we never invoke super(), we throw
+assertThrowsInstanceOf(()=>new foo(), ReferenceError);
+
+// No |this| binding in the closure, yet
+assertThrowsInstanceOf(thisArrow, ReferenceError);
+
+// call super()
+superArrow();
+
+// Can't call it twice
+assertThrowsInstanceOf(superArrow, ReferenceError);
+
+// Oh look, |this| is populated, now.
+assertEq(thisArrow(), thisStash);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/derivedConstructorArrowEvalGetThis.js b/js/src/tests/non262/class/derivedConstructorArrowEvalGetThis.js
new file mode 100644
index 0000000000..26f9843d2c
--- /dev/null
+++ b/js/src/tests/non262/class/derivedConstructorArrowEvalGetThis.js
@@ -0,0 +1,10 @@
+new class extends class { } {
+ constructor() {
+ super();
+ assertEq(this, (()=>this)());
+ assertEq(this, eval("this"));
+ }
+}();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/derivedConstructorArrowEvalNestedSuperCall.js b/js/src/tests/non262/class/derivedConstructorArrowEvalNestedSuperCall.js
new file mode 100644
index 0000000000..d81f186485
--- /dev/null
+++ b/js/src/tests/non262/class/derivedConstructorArrowEvalNestedSuperCall.js
@@ -0,0 +1,34 @@
+new class extends class { } {
+ constructor() {
+ (()=>eval("super()"))();
+ assertEq(this, eval("this"));
+ assertEq(this, (()=>this)());
+ }
+}();
+
+new class extends class { } {
+ constructor() {
+ (()=>(()=>super())())();
+ assertEq(this, eval("this"));
+ assertEq(this, (()=>this)());
+ }
+}();
+
+new class extends class { } {
+ constructor() {
+ eval("(()=>super())()");
+ assertEq(this, eval("this"));
+ assertEq(this, (()=>this)());
+ }
+}();
+
+new class extends class { } {
+ constructor() {
+ eval("eval('super()')");
+ assertEq(this, eval("this"));
+ assertEq(this, (()=>this)());
+ }
+}();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/derivedConstructorArrowEvalSuperCall.js b/js/src/tests/non262/class/derivedConstructorArrowEvalSuperCall.js
new file mode 100644
index 0000000000..0f60df7465
--- /dev/null
+++ b/js/src/tests/non262/class/derivedConstructorArrowEvalSuperCall.js
@@ -0,0 +1,18 @@
+new class extends class { } {
+ constructor() {
+ assertEq(eval("super(); this"), this);
+ assertEq(this, eval("this"));
+ assertEq(this, (()=>this)());
+ }
+}();
+
+new class extends class { } {
+ constructor() {
+ (()=>super())();
+ assertEq(this, eval("this"));
+ assertEq(this, (()=>this)());
+ }
+}();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/derivedConstructorInlining.js b/js/src/tests/non262/class/derivedConstructorInlining.js
new file mode 100644
index 0000000000..53b6a52f24
--- /dev/null
+++ b/js/src/tests/non262/class/derivedConstructorInlining.js
@@ -0,0 +1,19 @@
+// Since we (for now!) can't emit jitcode for derived class statements. Make
+// sure we can correctly invoke derived class constructors.
+
+class foo extends null {
+ constructor() {
+ // Anything that tests |this| should throw, so just let it run off the
+ // end.
+ }
+}
+
+function intermediate() {
+ new foo();
+}
+
+for (let i = 0; i < 1100; i++)
+ assertThrownErrorContains(intermediate, "this");
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/derivedConstructorName.js b/js/src/tests/non262/class/derivedConstructorName.js
new file mode 100644
index 0000000000..13d47addb4
--- /dev/null
+++ b/js/src/tests/non262/class/derivedConstructorName.js
@@ -0,0 +1,11 @@
+class A {
+ constructor() { }
+}
+
+class B extends A { }
+
+var b = new B();
+assertEq(b.constructor.name, "B");
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/derivedConstructorReturnPrimitive.js b/js/src/tests/non262/class/derivedConstructorReturnPrimitive.js
new file mode 100644
index 0000000000..8b1594fa81
--- /dev/null
+++ b/js/src/tests/non262/class/derivedConstructorReturnPrimitive.js
@@ -0,0 +1,15 @@
+class foo extends null {
+ constructor() {
+ // Returning a primitive is a TypeError in derived constructors. This
+ // ensures that super() can take the return value directly, without
+ // checking it. Use |null| here, as a tricky check to make sure we
+ // didn't lump it in with the object check, somehow.
+ return null;
+ }
+}
+
+for (let i = 0; i < 1100; i++)
+ assertThrownErrorContains(() => new foo(), "return");
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/derivedConstructorTDZExplicitThis.js b/js/src/tests/non262/class/derivedConstructorTDZExplicitThis.js
new file mode 100644
index 0000000000..4a4922d57e
--- /dev/null
+++ b/js/src/tests/non262/class/derivedConstructorTDZExplicitThis.js
@@ -0,0 +1,12 @@
+class foo extends null {
+ constructor() {
+ this;
+ assertEq(false, true);
+ }
+}
+
+for (let i = 0; i < 1100; i++)
+ assertThrownErrorContains(() => new foo(), "this");
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/derivedConstructorTDZOffEdge.js b/js/src/tests/non262/class/derivedConstructorTDZOffEdge.js
new file mode 100644
index 0000000000..28a2c377ca
--- /dev/null
+++ b/js/src/tests/non262/class/derivedConstructorTDZOffEdge.js
@@ -0,0 +1,11 @@
+class foo extends null {
+ constructor() {
+ // Let it fall off the edge and throw.
+ }
+}
+
+for (let i = 0; i < 1100; i++)
+ assertThrownErrorContains(() => new foo(), "this");
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/derivedConstructorTDZReturnAliasedTry.js b/js/src/tests/non262/class/derivedConstructorTDZReturnAliasedTry.js
new file mode 100644
index 0000000000..3399c69b0c
--- /dev/null
+++ b/js/src/tests/non262/class/derivedConstructorTDZReturnAliasedTry.js
@@ -0,0 +1,14 @@
+class base {}
+class derived extends base {
+ constructor() {
+ try {
+ (function() { p1(eval()) }())
+ } catch (e) {
+ return
+ }
+ }
+}
+assertThrowsInstanceOf(()=>new derived(), ReferenceError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/derivedConstructorTDZReturnObject.js b/js/src/tests/non262/class/derivedConstructorTDZReturnObject.js
new file mode 100644
index 0000000000..48206a881e
--- /dev/null
+++ b/js/src/tests/non262/class/derivedConstructorTDZReturnObject.js
@@ -0,0 +1,13 @@
+class foo extends null {
+ constructor() {
+ // If you return an object, we don't care that |this| went
+ // uninitialized
+ return {};
+ }
+}
+
+for (let i = 0; i < 1100; i++)
+ new foo();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/derivedConstructorTDZReturnTry.js b/js/src/tests/non262/class/derivedConstructorTDZReturnTry.js
new file mode 100644
index 0000000000..96791c0e78
--- /dev/null
+++ b/js/src/tests/non262/class/derivedConstructorTDZReturnTry.js
@@ -0,0 +1,16 @@
+class base {}
+class derived extends base {
+ constructor() {
+ try {
+ return;
+ } catch (e) {
+ try {
+ return;
+ } catch (e) {}
+ }
+ }
+}
+assertThrowsInstanceOf(() => new derived, ReferenceError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/derivedConstructorTDZReturnUndefined.js b/js/src/tests/non262/class/derivedConstructorTDZReturnUndefined.js
new file mode 100644
index 0000000000..21b8a3a05c
--- /dev/null
+++ b/js/src/tests/non262/class/derivedConstructorTDZReturnUndefined.js
@@ -0,0 +1,13 @@
+class foo extends null {
+ constructor() {
+ // Explicit returns of undefined should act the same as falling off the
+ // end of the function. That is to say, they should throw.
+ return undefined;
+ }
+}
+
+for (let i = 0; i < 1100; i++)
+ assertThrownErrorContains(() => new foo(), "this");
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/extendBuiltinConstructors.js b/js/src/tests/non262/class/extendBuiltinConstructors.js
new file mode 100644
index 0000000000..f823d81343
--- /dev/null
+++ b/js/src/tests/non262/class/extendBuiltinConstructors.js
@@ -0,0 +1,110 @@
+function testBuiltinInstanceIsInstanceOf(instance, builtin, class_) {
+ assertEq(instance instanceof class_, true);
+ assertEq(instance instanceof builtin, true);
+
+ if (builtin === Array)
+ assertEq(Array.isArray(instance), true);
+}
+
+function testBuiltinInstance(builtin, ...args) {
+ class sub extends builtin {
+ constructor(...args) {
+ super(...args);
+ this.called = true;
+ }
+ }
+
+ let instance = new sub(...args);
+ assertEq(instance.called, true);
+ testBuiltinInstanceIsInstanceOf(instance, builtin, sub);
+}
+
+function testBuiltinMultipleSubclasses(builtin, ...args) {
+ function f(obj, prop) {
+ assertEq(obj.prop, prop);
+ }
+
+ class sub1 extends builtin { };
+ class sub2 extends builtin { };
+
+ const prop1 = "A";
+ const prop2 = "B";
+
+ sub1.prototype.prop = prop1;
+ sub2.prototype.prop = prop2;
+
+ let instance1 = new sub1(...args);
+ let instance2 = new sub2(...args);
+
+ // Also make sure we get the properties we want with a default constructor
+ testBuiltinInstanceIsInstanceOf(instance1, builtin, sub1);
+
+ for (let i = 0; i < 10; i++) {
+ f(instance1, prop1);
+ f(instance2, prop2);
+ }
+}
+
+function testBuiltin(builtin, ...args) {
+ testBuiltinInstance(builtin, ...args);
+ testBuiltinMultipleSubclasses(builtin, ...args);
+}
+
+function testBuiltinTypedArrays() {
+ let typedArrays = [Int8Array,
+ Uint8Array,
+ Uint8ClampedArray,
+ Int16Array,
+ Uint16Array,
+ Int32Array,
+ Uint32Array,
+ Float32Array,
+ Float64Array];
+
+ for (let array of typedArrays) {
+ testBuiltin(array);
+ testBuiltin(array, 5);
+ testBuiltin(array, new array());
+ testBuiltin(array, new ArrayBuffer());
+ }
+}
+
+testBuiltin(Function);
+testBuiltin(Object);
+testBuiltin(Boolean);
+testBuiltin(Error);
+testBuiltin(EvalError);
+testBuiltin(RangeError);
+testBuiltin(ReferenceError);
+testBuiltin(SyntaxError);
+testBuiltin(TypeError);
+testBuiltin(URIError);
+testBuiltin(Number);
+testBuiltin(Date);
+testBuiltin(Date, 5);
+testBuiltin(Date, 5, 10);
+testBuiltin(RegExp);
+testBuiltin(RegExp, /Regexp Argument/);
+testBuiltin(RegExp, "String Argument");
+testBuiltin(Map);
+testBuiltin(Set);
+testBuiltin(WeakMap);
+testBuiltin(WeakSet);
+testBuiltin(ArrayBuffer);
+testBuiltinTypedArrays();
+testBuiltin(DataView, new ArrayBuffer());
+testBuiltin(DataView, new (newGlobal().ArrayBuffer)());
+testBuiltin(String);
+testBuiltin(Array);
+testBuiltin(Array, 15);
+testBuiltin(Array, 3.0);
+testBuiltin(Array, "non-length one-arg");
+testBuiltin(Array, 5, 10, 15, "these are elements");
+// More Promise subclassing tests can be found in non262/Promise/promise-subclassing.js
+testBuiltin(Promise, _=>{});
+
+if (this.SharedArrayBuffer)
+ testBuiltin(SharedArrayBuffer);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/fields-instance-class-name-binding-eval.js b/js/src/tests/non262/class/fields-instance-class-name-binding-eval.js
new file mode 100644
index 0000000000..6b6d3a0857
--- /dev/null
+++ b/js/src/tests/non262/class/fields-instance-class-name-binding-eval.js
@@ -0,0 +1,40 @@
+// Instance field initialisers can access the inner name binding for class definitions.
+{
+ class C {
+ field = eval("C");
+ }
+ assertEq(new C().field, C);
+}
+{
+ let C = class Inner {
+ field = eval("Inner");
+ };
+ assertEq(new C().field, C);
+}
+
+// Instance field initialiser expressions always resolve the inner name binding.
+{
+ class C {
+ field = () => eval("C");
+ }
+ assertEq(new C().field(), C);
+
+ const D = C;
+ C = null;
+
+ assertEq(new D().field(), D);
+}
+{
+ let C = class Inner {
+ field = () => eval("Inner");
+ }
+ assertEq(new C().field(), C);
+
+ const D = C;
+ C = null;
+
+ assertEq(new D().field(), D);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/class/fields-instance-class-name-binding.js b/js/src/tests/non262/class/fields-instance-class-name-binding.js
new file mode 100644
index 0000000000..10cac12504
--- /dev/null
+++ b/js/src/tests/non262/class/fields-instance-class-name-binding.js
@@ -0,0 +1,40 @@
+// Instance field initialisers can access the inner name binding for class definitions.
+{
+ class C {
+ field = C;
+ }
+ assertEq(new C().field, C);
+}
+{
+ let C = class Inner {
+ field = Inner;
+ };
+ assertEq(new C().field, C);
+}
+
+// Instance field initialiser expressions always resolve the inner name binding.
+{
+ class C {
+ field = () => C;
+ }
+ assertEq(new C().field(), C);
+
+ const D = C;
+ C = null;
+
+ assertEq(new D().field(), D);
+}
+{
+ let C = class Inner {
+ field = () => Inner;
+ }
+ assertEq(new C().field(), C);
+
+ const D = C;
+ C = null;
+
+ assertEq(new D().field(), D);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/class/fields-static-class-name-binding-eval.js b/js/src/tests/non262/class/fields-static-class-name-binding-eval.js
new file mode 100644
index 0000000000..34185e7ecd
--- /dev/null
+++ b/js/src/tests/non262/class/fields-static-class-name-binding-eval.js
@@ -0,0 +1,59 @@
+// Static field initialisers can access the inner name binding for class definitions.
+{
+ class C {
+ static field = eval("C");
+ }
+ assertEq(C.field, C);
+}
+{
+ let C = class Inner {
+ static field = eval("Inner");
+ };
+ assertEq(C.field, C);
+}
+
+// Static field initialisers can't access the outer name binding for class expressions
+// before it has been initialised.
+{
+ assertThrowsInstanceOf(() => {
+ let C = class {
+ static field = eval("C");
+ };
+ }, ReferenceError);
+}
+
+// Static field initialisers can access the outer name binding for class expressions after
+// the binding has been initialised
+{
+ let C = class {
+ static field = () => eval("C");
+ };
+ assertEq(C.field(), C);
+}
+
+// Static field initialiser expressions always resolve the inner name binding.
+{
+ class C {
+ static field = () => eval("C");
+ }
+ assertEq(C.field(), C);
+
+ const D = C;
+ C = null;
+
+ assertEq(D.field(), D);
+}
+{
+ let C = class Inner {
+ static field = () => eval("Inner");
+ }
+ assertEq(C.field(), C);
+
+ const D = C;
+ C = null;
+
+ assertEq(D.field(), D);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/class/fields-static-class-name-binding.js b/js/src/tests/non262/class/fields-static-class-name-binding.js
new file mode 100644
index 0000000000..54032b03ff
--- /dev/null
+++ b/js/src/tests/non262/class/fields-static-class-name-binding.js
@@ -0,0 +1,59 @@
+// Static field initialisers can access the inner name binding for class definitions.
+{
+ class C {
+ static field = C;
+ }
+ assertEq(C.field, C);
+}
+{
+ let C = class Inner {
+ static field = Inner;
+ };
+ assertEq(C.field, C);
+}
+
+// Static field initialisers can't access the outer name binding for class expressions
+// before it has been initialised.
+{
+ assertThrowsInstanceOf(() => {
+ let C = class {
+ static field = C;
+ };
+ }, ReferenceError);
+}
+
+// Static field initialisers can access the outer name binding for class expressions after
+// the binding has been initialised
+{
+ let C = class {
+ static field = () => C;
+ };
+ assertEq(C.field(), C);
+}
+
+// Static field initialiser expressions always resolve the inner name binding.
+{
+ class C {
+ static field = () => C;
+ }
+ assertEq(C.field(), C);
+
+ const D = C;
+ C = null;
+
+ assertEq(D.field(), D);
+}
+{
+ let C = class Inner {
+ static field = () => Inner;
+ }
+ assertEq(C.field(), C);
+
+ const D = C;
+ C = null;
+
+ assertEq(D.field(), D);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/class/geterNoExprClosure.js b/js/src/tests/non262/class/geterNoExprClosure.js
new file mode 100644
index 0000000000..e37cb287a9
--- /dev/null
+++ b/js/src/tests/non262/class/geterNoExprClosure.js
@@ -0,0 +1,20 @@
+// getter/setter with expression closure is allowed only in object literal.
+
+assertThrowsInstanceOf(() => eval(`
+ class foo {
+ constructor() {}
+
+ get a() 1
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(`
+ class foo {
+ constructor() {}
+
+ set a(v) 1
+ }
+`), SyntaxError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/innerBinding.js b/js/src/tests/non262/class/innerBinding.js
new file mode 100644
index 0000000000..b1afa177e0
--- /dev/null
+++ b/js/src/tests/non262/class/innerBinding.js
@@ -0,0 +1,86 @@
+// Named class definitions should create an immutable inner binding.
+// Since all code in classes is in strict mode, attempts to mutate it
+// should throw.
+class Foof { constructor() { }; tryBreak() { Foof = 4; } }
+for (let result of [Foof, class Bar { constructor() { }; tryBreak() { Bar = 4; } }])
+ assertThrowsInstanceOf(() => new result().tryBreak(), TypeError);
+
+{
+ class foo { constructor() { }; tryBreak() { foo = 4; } }
+ for (let result of [foo, class Bar { constructor() { }; tryBreak() { Bar = 4 } }])
+ assertThrowsInstanceOf(() => new result().tryBreak(), TypeError);
+}
+
+// TDZ applies to inner bindings
+assertThrowsInstanceOf(()=>eval(`class Bar {
+ constructor() { };
+ [Bar] () { };
+ }`), ReferenceError);
+
+assertThrowsInstanceOf(()=>eval(`(class Bar {
+ constructor() { };
+ [Bar] () { };
+ })`), ReferenceError);
+
+// There's no magic "inner binding" global
+{
+ class Foo {
+ constructor() { };
+ test() {
+ class Bar {
+ constructor() { }
+ test() { return Foo === Bar }
+ }
+ return new Bar().test();
+ }
+ }
+ assertEq(new Foo().test(), false);
+ assertEq(new class foo {
+ constructor() { };
+ test() {
+ return new class bar {
+ constructor() { }
+ test() { return foo === bar }
+ }().test();
+ }
+ }().test(), false);
+}
+
+// Inner bindings are shadowable
+{
+ class Foo {
+ constructor() { }
+ test(Foo) { return Foo; }
+ }
+ assertEq(new Foo().test(4), 4);
+ assertEq(new class foo {
+ constructor() { };
+ test(foo) { return foo }
+ }().test(4), 4);
+}
+
+// Inner bindings in expressions should shadow even existing names.
+class Foo { constructor() { } static method() { throw new Error("NO!"); } }
+assertEq(new class Foo {
+ constructor() { };
+ static method() { return 4; };
+ test() { return Foo.method(); }
+ }().test(), 4);
+
+// The outer binding is distinct from the inner one
+{
+ let orig_X;
+
+ class X {
+ constructor() { }
+ f() { assertEq(X, orig_X); }
+ }
+
+ orig_X = X;
+ X = 13;
+ assertEq(X, 13);
+ new orig_X().f();
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "OK");
diff --git a/js/src/tests/non262/class/member-expr-after-super.js b/js/src/tests/non262/class/member-expr-after-super.js
new file mode 100644
index 0000000000..fa965b24e5
--- /dev/null
+++ b/js/src/tests/non262/class/member-expr-after-super.js
@@ -0,0 +1,44 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+class Base {
+ get test() {
+ return "ok";
+ }
+}
+
+class SuperThenProperty extends Base {
+ constructor() {
+ var result = super().test;
+ return {result};
+ }
+}
+assertEq(new SuperThenProperty().result, "ok");
+
+class SuperThenMember extends Base {
+ constructor() {
+ var result = super()["tes" + String.fromCodePoint("t".codePointAt(0))];
+ return {result};
+ }
+}
+assertEq(new SuperThenMember().result, "ok");
+
+class SuperThenCall extends Function {
+ constructor() {
+ var result = super("o, k", "return o + k;")("o", "k");
+ return {result};
+ }
+}
+assertEq(new SuperThenCall().result, "ok");
+
+class SuperThenTemplateCall extends Function {
+ constructor() {
+ var result = super("cooked", "return cooked[0][0] + cooked.raw[0][1];")`ok`;
+ return {result};
+ }
+}
+assertEq(new SuperThenTemplateCall().result, "ok");
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/class/methDefn.js b/js/src/tests/non262/class/methDefn.js
new file mode 100644
index 0000000000..9513bdfb30
--- /dev/null
+++ b/js/src/tests/non262/class/methDefn.js
@@ -0,0 +1,204 @@
+var BUGNUMBER = 924672;
+var summary = 'Method Definitions'
+
+print(BUGNUMBER + ": " + summary);
+
+// Function definitions.
+function syntaxError (script) {
+ try {
+ Function(script);
+ } catch (e) {
+ if (e instanceof SyntaxError) {
+ return;
+ }
+ }
+ throw new Error('Expected syntax error: ' + script);
+}
+
+
+// Tests begin.
+
+syntaxError("{a(){}}");
+syntaxError("b = {a(");
+syntaxError("b = {a)");
+syntaxError("b = {a(}");
+syntaxError("b = {a)}");
+syntaxError("b = {a()");
+syntaxError("b = {a()}");
+syntaxError("b = {a(){}");
+syntaxError("b = {a){}");
+syntaxError("b = {a}}");
+syntaxError("b = {a{}}");
+syntaxError("b = {a({}}");
+syntaxError("b = {a@(){}}");
+syntaxError("b = {a() => 0}");
+syntaxError("b = {a() void 0}");
+syntaxError("b = {a() 1}");
+syntaxError("b = {a() false}");
+
+b = {a(){return 5;}};
+assertEq(b.a(), 5);
+
+b = {a(){return "hey";}};
+assertEq(b.a(), "hey");
+
+b = {a(){return arguments;}};
+assertEq(b.a().length, 0);
+
+b = {a(c){return arguments;}};
+assertEq(b.a().length, 0);
+
+b = {a(c){return arguments;}};
+assertEq(b.a(1).length, 1);
+
+b = {a(c){return arguments;}};
+assertEq(b.a(1)[0], 1);
+
+b = {a(c,d){return arguments;}};
+assertEq(b.a(1,2).length, 2);
+
+b = {a(c,d){return arguments;}};
+assertEq(b.a(1,2)[0], 1);
+
+b = {a(c,d){return arguments;}};
+assertEq(b.a(1,2)[1], 2);
+
+// Methods along with other properties.
+syntaxError("b = {,a(){}}");
+syntaxError("b = {@,a(){}}");
+syntaxError("b = {a(){},@}");
+syntaxError("b = {a : 5 , (){}}");
+syntaxError("b = {a : 5@ , a(){}}");
+syntaxError("b = {a : , a(){}}");
+syntaxError("b = {a : 5, a()}}");
+syntaxError("b = {a : 5, a({}}");
+syntaxError("b = {a : 5, a){}}");
+syntaxError("b = {a : 5, a(){}");
+var c = "d";
+b = { a : 5,
+ [c] : "hey",
+ e() {return 6;},
+ get f() {return 7;},
+ set f(g) {this.h = 9;}
+}
+assertEq(b.a, 5);
+assertEq(b.d, "hey");
+assertEq(b.e(), 6);
+assertEq(b.f, 7);
+assertEq(b.h !== 9, true);
+b.f = 15;
+assertEq(b.h, 9);
+
+
+var i = 0;
+var a = {
+ foo0 : function (){return 0;},
+ ["foo" + ++i](){return 1;},
+ ["foo" + ++i](){return 2;},
+ ["foo" + ++i](){return 3;},
+ foo4(){return 4;}
+};
+assertEq(a.foo0(), 0);
+assertEq(a.foo1(), 1);
+assertEq(a.foo2(), 2);
+assertEq(a.foo3(), 3);
+assertEq(a.foo4(), 4);
+
+// Symbols.
+var unique_sym = Symbol("1"), registered_sym = Symbol.for("2");
+a = { [unique_sym](){return 2;}, [registered_sym](){return 3;} };
+assertEq(a[unique_sym](), 2);
+assertEq(a[registered_sym](), 3);
+
+// Method characteristics.
+a = { b(){ return 4;} };
+b = Object.getOwnPropertyDescriptor(a, "b");
+assertEq(b.configurable, true);
+assertEq(b.enumerable, true);
+assertEq(b.writable, true);
+assertEq(b.value(), 4);
+
+// prototype property
+assertEq(a.b.prototype, undefined);
+assertEq(a.b.hasOwnProperty("prototype"), false);
+
+// Defining several methods using eval.
+var code = "({";
+for (i = 0; i < 1000; i++)
+ code += "['foo' + " + i + "]() {return 'ok';}, "
+code += "['bar']() {return 'all ok'}});";
+var obj = eval(code);
+for (i = 0; i < 1000; i++)
+ assertEq(obj["foo" + i](), "ok");
+assertEq(obj["bar"](), "all ok");
+
+// this
+var obj = {
+ a : "hey",
+ meth(){return this.a;}
+}
+assertEq(obj.meth(), "hey");
+
+// Inheritance
+var obj2 = Object.create(obj);
+assertEq(obj2.meth(), "hey");
+
+var obj = {
+ a() {
+ return "hey";
+ }
+}
+assertEq(obj.a.call(), "hey");
+
+// Duplicates
+var obj = {
+ meth : 3,
+ meth() { return 4; },
+ meth() { return 5; }
+}
+assertEq(obj.meth(), 5);
+
+var obj = {
+ meth() { return 4; },
+ meth() { return 5; },
+ meth : 3
+}
+assertEq(obj.meth, 3);
+assertThrowsInstanceOf(function() {obj.meth();}, TypeError);
+
+// Strict mode
+a = {b(c){"use strict";return c;}};
+assertEq(a.b(1), 1);
+a = {["b"](c){"use strict";return c;}};
+assertEq(a.b(1), 1);
+
+// Allow strict-reserved names as methods in objects.
+// (Bug 1124362)
+a = { static() { return 4; } };
+assertEq(a.static(), 4);
+
+a = { get static() { return 4; } };
+assertEq(a.static, 4);
+
+a = { set static(x) { assertEq(x, 4); } };
+a.static = 4;
+
+function testStrictMode() {
+ "use strict";
+ var obj = { static() { return 4; } };
+ assertEq(obj.static(), 4);
+
+ obj = { get static() { return 4; } };
+ assertEq(obj.static, 4);
+
+ obj = { set static(x) { assertEq(x, 4); } };
+ obj.static = 4;
+}
+testStrictMode();
+
+// Tests provided by benvie in the bug to distinguish from ES5 desugar.
+assertEq(({ method() {} }).method.name, "method");
+assertThrowsInstanceOf(function() {({ method() { method() } }).method() }, ReferenceError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0, "ok");
diff --git a/js/src/tests/non262/class/methDefnGen.js b/js/src/tests/non262/class/methDefnGen.js
new file mode 100644
index 0000000000..3165ed4481
--- /dev/null
+++ b/js/src/tests/non262/class/methDefnGen.js
@@ -0,0 +1,83 @@
+var BUGNUMBER = 924672;
+var summary = 'Method Definitions - Generators'
+
+print(BUGNUMBER + ": " + summary);
+
+// Function definitions.
+function syntaxError (script) {
+ try {
+ Function(script);
+ } catch (e) {
+ if (e instanceof SyntaxError) {
+ return;
+ }
+ }
+ throw new Error('Expected syntax error: ' + script);
+}
+
+
+// Tests begin.
+
+syntaxError("{*a(){}}");
+syntaxError("b = {*(){}");
+syntaxError("b = {*{}");
+syntaxError("b = {*){}");
+syntaxError("b = {*({}");
+syntaxError("b = {*(){");
+syntaxError("b = {*()}");
+syntaxError("b = {*a(");
+syntaxError("b = {*a)");
+syntaxError("b = {*a(}");
+syntaxError("b = {*a)}");
+syntaxError("b = {*a()");
+syntaxError("b = {*a()}");
+syntaxError("b = {*a(){}");
+syntaxError("b = {*a){}");
+syntaxError("b = {*a}}");
+syntaxError("b = {*a{}}");
+syntaxError("b = {*a({}}");
+syntaxError("b = {*a@(){}}");
+syntaxError("b = {*@(){}}");
+syntaxError("b = {*get a(){}}");
+syntaxError("b = {get *a(){}}");
+syntaxError("b = {get a*(){}}");
+syntaxError("b = {*set a(c){}}");
+syntaxError("b = {set *a(c){}}");
+syntaxError("b = {set a*(c){}}");
+syntaxError("b = {*a : 1}");
+syntaxError("b = {a* : 1}");
+syntaxError("b = {a :* 1}");
+syntaxError("b = {a*(){}}");
+
+// Generator methods.
+b = { * g() {
+ var a = { [yield 1]: 2, [yield 2]: 3};
+ return a;
+} }
+var it = b.g();
+var next = it.next();
+assertEq(next.done, false);
+assertEq(next.value, 1);
+next = it.next("hello");
+assertEq(next.done, false);
+assertEq(next.value, 2);
+next = it.next("world");
+assertEq(next.done, true);
+assertEq(next.value.hello, 2);
+assertEq(next.value.world, 3);
+
+// prototype property
+assertEq(b.g.hasOwnProperty("prototype"), true);
+
+// Strict mode
+a = {*b(c){"use strict";yield c;}};
+assertEq(a.b(1).next().value, 1);
+a = {*["b"](c){"use strict";return c;}};
+assertEq(a.b(1).next().value, 1);
+
+// Generators should not have [[Construct]]
+a = {*g() { yield 1; }}
+assertThrowsInstanceOf(() => { new a.g }, TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0, "ok");
diff --git a/js/src/tests/non262/class/method-named-static.js b/js/src/tests/non262/class/method-named-static.js
new file mode 100644
index 0000000000..c5a2ed8827
--- /dev/null
+++ b/js/src/tests/non262/class/method-named-static.js
@@ -0,0 +1,56 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Instance method named "static", with and without escape sequence.
+assertEq((new class {
+ static() { return "method-static-no-escape"; }
+}).static(), "method-static-no-escape");
+
+assertEq((new class {
+ st\u0061tic() { return "method-static-escape"; }
+}).static(), "method-static-escape");
+
+// Instance getter named "static", with and without escape sequence.
+assertEq((new class {
+ get static() { return "getter-static-no-escape"; }
+}).static, "getter-static-no-escape");
+
+assertEq((new class {
+ get static() { return "getter-static-escape"; }
+}).static, "getter-static-escape");
+
+// Static method named "static", with and without escape sequence.
+assertEq(class {
+ static static() { return "static-method-static-no-escape"; }
+}.static(), "static-method-static-no-escape");
+
+assertEq(class {
+ static st\u0061tic() { return "static-method-static-escape"; }
+}.static(), "static-method-static-escape");
+
+// Static getter named "static", with and without escape sequence.
+assertEq(class {
+ static get static() { return "static-getter-static-no-escape"; }
+}.static, "static-getter-static-no-escape");
+
+assertEq(class {
+ static get st\u0061tic() { return "static-getter-static-escape"; }
+}.static, "static-getter-static-escape");
+
+
+// The static modifier itself must not contain any escape sequences.
+assertThrowsInstanceOf(() => eval(String.raw`
+ class C {
+ st\u0061tic m() {}
+ }
+`), SyntaxError);
+
+assertThrowsInstanceOf(() => eval(String.raw`
+ class C {
+ st\u0061tic get m() {}
+ }
+`), SyntaxError);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "ok");
diff --git a/js/src/tests/non262/class/methodInstallation.js b/js/src/tests/non262/class/methodInstallation.js
new file mode 100644
index 0000000000..bbb6c2f727
--- /dev/null
+++ b/js/src/tests/non262/class/methodInstallation.js
@@ -0,0 +1,101 @@
+// Do the things we write in classes actually appear as they are supposed to?
+
+var methodCalled;
+var getterCalled;
+var setterCalled;
+var constructorCalled;
+var staticMethodCalled;
+var staticGetterCalled;
+var staticSetterCalled;
+class testClass {
+ constructor() { constructorCalled = true; }
+ __proto__() { methodCalled = true }
+ get getter() { getterCalled = true; }
+ set setter(x) { setterCalled = true; }
+ static staticMethod() { staticMethodCalled = true; }
+ static get staticGetter() { staticGetterCalled = true; }
+ static set staticSetter(x) { staticSetterCalled = true; }
+ *[Symbol.iterator]() { yield "cow"; yield "pig"; }
+}
+
+for (let a of [testClass,
+ class {
+ constructor() { constructorCalled = true; }
+ __proto__() { methodCalled = true }
+ get getter() { getterCalled = true; }
+ set setter(x) { setterCalled = true; }
+ static staticMethod() { staticMethodCalled = true; }
+ static get staticGetter() { staticGetterCalled = true; }
+ static set staticSetter(x) { staticSetterCalled = true; }
+ *[Symbol.iterator]() { yield "cow"; yield "pig"; }
+ }]) {
+
+ methodCalled = false;
+ getterCalled = false;
+ setterCalled = false;
+ constructorCalled = false;
+ staticMethodCalled = false;
+ staticGetterCalled = false;
+ staticSetterCalled = false;
+
+ var aConstDesc = Object.getOwnPropertyDescriptor(a.prototype, "constructor");
+ assertEq(aConstDesc.writable, true);
+ assertEq(aConstDesc.configurable, true);
+ assertEq(aConstDesc.enumerable, false);
+ new aConstDesc.value();
+ assertEq(constructorCalled, true);
+
+ // __proto__ is just an identifier for classes. No prototype changes are made.
+ assertEq(Object.getPrototypeOf(a.prototype), Object.prototype);
+ var aMethDesc = Object.getOwnPropertyDescriptor(a.prototype, "__proto__");
+ assertEq(aMethDesc.writable, true);
+ assertEq(aMethDesc.configurable, true);
+ assertEq(aMethDesc.enumerable, false);
+ aMethDesc.value();
+ assertEq(methodCalled, true);
+
+ var aGetDesc = Object.getOwnPropertyDescriptor(a.prototype, "getter");
+ assertEq(aGetDesc.configurable, true);
+ assertEq(aGetDesc.enumerable, false);
+ aGetDesc.get();
+ assertThrowsInstanceOf(() => new aGetDesc.get, TypeError);
+ assertEq(getterCalled, true);
+
+ var aSetDesc = Object.getOwnPropertyDescriptor(a.prototype, "setter");
+ assertEq(aSetDesc.configurable, true);
+ assertEq(aSetDesc.enumerable, false);
+ aSetDesc.set();
+ assertThrowsInstanceOf(() => new aSetDesc.set, TypeError);
+ assertEq(setterCalled, true);
+ assertDeepEq(aSetDesc, Object.getOwnPropertyDescriptor(a.prototype, "setter"));
+
+ assertEq(Object.getOwnPropertyDescriptor(new a(), "staticMethod"), undefined);
+ var aStaticMethDesc = Object.getOwnPropertyDescriptor(a, "staticMethod");
+ assertEq(aStaticMethDesc.configurable, true);
+ assertEq(aStaticMethDesc.enumerable, false);
+ assertEq(aStaticMethDesc.writable, true);
+ aStaticMethDesc.value();
+ assertThrowsInstanceOf(() => new aStaticMethDesc.value, TypeError);
+ assertEq(staticMethodCalled, true);
+
+ assertEq(Object.getOwnPropertyDescriptor(new a(), "staticGetter"), undefined);
+ var aStaticGetDesc = Object.getOwnPropertyDescriptor(a, "staticGetter");
+ assertEq(aStaticGetDesc.configurable, true);
+ assertEq(aStaticGetDesc.enumerable, false);
+ aStaticGetDesc.get();
+ assertThrowsInstanceOf(() => new aStaticGetDesc.get, TypeError);
+ assertEq(staticGetterCalled, true);
+
+ assertEq(Object.getOwnPropertyDescriptor(new a(), "staticSetter"), undefined);
+ var aStaticSetDesc = Object.getOwnPropertyDescriptor(a, "staticSetter");
+ assertEq(aStaticSetDesc.configurable, true);
+ assertEq(aStaticSetDesc.enumerable, false);
+ aStaticSetDesc.set();
+ assertThrowsInstanceOf(() => new aStaticSetDesc.set, TypeError);
+ assertEq(staticSetterCalled, true);
+
+ assertEq([...new a()].join(), "cow,pig");
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "OK");
diff --git a/js/src/tests/non262/class/methodName.js b/js/src/tests/non262/class/methodName.js
new file mode 100644
index 0000000000..02a726c105
--- /dev/null
+++ b/js/src/tests/non262/class/methodName.js
@@ -0,0 +1,40 @@
+class TestClass {
+ get getter() { }
+ set setter(x) { }
+ method() { }
+
+ static get staticGetter() { }
+ static set staticSetter(x) { }
+ static staticMethod() { }
+
+ get 1() { }
+ set 2(v) { }
+ 3() { }
+
+ static get 4() { }
+ static set 5(x) { }
+ static 6() { }
+}
+
+function name(obj, property, get) {
+ let desc = Object.getOwnPropertyDescriptor(obj, property);
+ return (get ? desc.get : desc.set).name;
+}
+
+assertEq(name(TestClass.prototype, "getter", true), "get getter");
+assertEq(name(TestClass.prototype, "setter", false), "set setter");
+assertEq(TestClass.prototype.method.name, "method");
+
+assertEq(name(TestClass, "staticGetter", true), "get staticGetter");
+assertEq(name(TestClass, "staticSetter", false), "set staticSetter");
+assertEq(TestClass.staticMethod.name, "staticMethod");
+
+assertEq(name(TestClass.prototype, "1", true), "get 1");
+assertEq(name(TestClass.prototype, "2", false), "set 2");
+assertEq(TestClass.prototype[3].name, "3");
+
+assertEq(name(TestClass, "4", true), "get 4");
+assertEq(name(TestClass, "5", false), "set 5");
+assertEq(TestClass[6].name, "6");
+
+reportCompare(true, true);
diff --git a/js/src/tests/non262/class/methodOverwrites.js b/js/src/tests/non262/class/methodOverwrites.js
new file mode 100644
index 0000000000..c1c460a28c
--- /dev/null
+++ b/js/src/tests/non262/class/methodOverwrites.js
@@ -0,0 +1,80 @@
+// Ensure that we can overwrite methods when more tha one is present.
+{
+ var result = 0;
+ // Regardless of order, the constructor is overridden by any CPN, because it's
+ // processed seperately.
+ class a { ["constructor"]() { result += 1; }; constructor() { result += 2; } }
+ var aInst = new a();
+ assertEq(result, 2);
+ aInst.constructor();
+ assertEq(result, 3);
+
+ class b { constructor() { result += 2; } ["constructor"]() { result += 1; }; }
+ var bInst = new b();
+ assertEq(result, 5);
+ bInst.constructor();
+ assertEq(result, 6);
+
+ class c { constructor() { } method() { result += 1 } get method() { result += 2 } }
+ new c().method;
+ assertEq(result, 8);
+
+ class d { constructor() { } get method() { result += 1 } method() { result += 2 } }
+ new d().method();
+ assertEq(result, 10);
+
+ // getters and setter should not overwrite each other, but merge cleanly.
+ class e { constructor() { } get method() { result += 1 } set method(x) { } }
+ new e().method;
+ assertEq(result, 11);
+
+ class f { constructor() { }
+ set method(x) { throw "NO"; }
+ method() { throw "NO" }
+ get method() { return new Function("result += 1"); }
+ }
+ new f().method();
+ assertEq(result, 12);
+}
+
+// Try again with expressions.
+{
+ var result = 0;
+ // Regardless of order, the constructor is overridden by any CPN, because it's
+ // processed seperately.
+ let a = class { ["constructor"]() { result += 1; }; constructor() { result += 2; } };
+ var aInst = new a();
+ assertEq(result, 2);
+ aInst.constructor();
+ assertEq(result, 3);
+
+ let b = class { constructor() { result += 2; } ["constructor"]() { result += 1; }; };
+ var bInst = new b();
+ assertEq(result, 5);
+ bInst.constructor();
+ assertEq(result, 6);
+
+ let c = class { constructor() { } method() { result += 1 } get method() { result += 2 } };
+ new c().method;
+ assertEq(result, 8);
+
+ let d = class { constructor() { } get method() { result += 1 } method() { result += 2 } };
+ new d().method();
+ assertEq(result, 10);
+
+ // getters and setter should not overwrite each other, but merge cleanly.
+ let e = class { constructor() { } get method() { result += 1 } set method(x) { } };
+ new e().method;
+ assertEq(result, 11);
+
+ let f = class { constructor() { }
+ set method(x) { throw "NO"; }
+ method() { throw "NO" }
+ get method() { return new Function("result += 1"); }
+ };
+ new f().method();
+ assertEq(result, 12);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "OK");
diff --git a/js/src/tests/non262/class/methodsPrototype.js b/js/src/tests/non262/class/methodsPrototype.js
new file mode 100644
index 0000000000..07a565ceb6
--- /dev/null
+++ b/js/src/tests/non262/class/methodsPrototype.js
@@ -0,0 +1,39 @@
+class TestClass {
+ constructor() { }
+ method() { }
+ get getter() { }
+ set setter(x) { }
+ *generator() { }
+ static staticMethod() { }
+ static get staticGetter() { }
+ static set staticSetter(x) { }
+ static *staticGenerator() { }
+}
+
+var test = new TestClass();
+
+var hasPrototype = [
+ test.constructor,
+ test.generator,
+ TestClass.staticGenerator
+]
+
+for (var fun of hasPrototype) {
+ assertEq(fun.hasOwnProperty('prototype'), true);
+}
+
+var hasNoPrototype = [
+ test.method,
+ Object.getOwnPropertyDescriptor(test.__proto__, 'getter').get,
+ Object.getOwnPropertyDescriptor(test.__proto__, 'setter').set,
+ TestClass.staticMethod,
+ Object.getOwnPropertyDescriptor(TestClass, 'staticGetter').get,
+ Object.getOwnPropertyDescriptor(TestClass, 'staticSetter').set,
+]
+
+for (var fun of hasNoPrototype) {
+ assertEq(fun.hasOwnProperty('prototype'), false);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "OK");
diff --git a/js/src/tests/non262/class/newTargetArgumentsIntact.js b/js/src/tests/non262/class/newTargetArgumentsIntact.js
new file mode 100644
index 0000000000..d047085ea0
--- /dev/null
+++ b/js/src/tests/non262/class/newTargetArgumentsIntact.js
@@ -0,0 +1,44 @@
+// Since we put new.target at the end of the arguments vector, ensrue that it
+// doesn't interact with the arguments object
+
+var argsContent;
+
+function argsWithNewTarget(foo) {
+ assertEq(arguments.length, argsContent.length);
+ for (let i = 0; i < arguments.length; i++)
+ assertEq(arguments[i], argsContent[i]);
+ let nt = new.target;
+
+ // Assigning to the arguments object shouldn't infect new.target, either
+ arguments[arguments.length] = 42;
+ assertEq(new.target, nt);
+}
+
+// Test constructing invocations, with under and overflow
+argsContent = [];
+for (let i = 0; i < 100; i++)
+ new argsWithNewTarget();
+
+argsContent = [1];
+for (let i = 0; i < 100; i++)
+ new argsWithNewTarget(1);
+
+argsContent = [1,2,3];
+for (let i = 0; i < 100; i++)
+ new argsWithNewTarget(1, 2, 3);
+
+// Test spreadnew as well.
+argsContent = [];
+for (let i = 0; i < 100; i++)
+ new argsWithNewTarget(...[]);
+
+argsContent = [1];
+for (let i = 0; i < 100; i++)
+ new argsWithNewTarget(...[1]);
+
+argsContent = [1,2,3];
+for (let i = 0; i < 100; i++)
+ new argsWithNewTarget(...[1,2,3]);
+
+if (typeof reportCompare === "function")
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/newTargetArrow.js b/js/src/tests/non262/class/newTargetArrow.js
new file mode 100644
index 0000000000..548f750475
--- /dev/null
+++ b/js/src/tests/non262/class/newTargetArrow.js
@@ -0,0 +1,24 @@
+// new.target is valid in any arrow function not in a global context.
+new Function('(() => new.target)()');
+
+// It's also good inside eval, but not global eval
+assertThrowsInstanceOf(() => eval('() => new.target'), SyntaxError);
+
+function assertNewTarget(expected) {
+ assertEq((()=>new.target)(), expected);
+ assertEq(eval('()=>new.target')(), expected);
+
+ // Make sure that arrow functions can escape their original context and
+ // still get the right answer.
+ return (() => new.target);
+}
+
+const ITERATIONS = 550;
+for (let i = 0; i < ITERATIONS; i++)
+ assertEq(assertNewTarget(undefined)(), undefined);
+
+for (let i = 0; i < ITERATIONS; i++)
+ assertEq(new assertNewTarget(assertNewTarget)(), assertNewTarget);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/newTargetBound.js b/js/src/tests/non262/class/newTargetBound.js
new file mode 100644
index 0000000000..f65cfe3caf
--- /dev/null
+++ b/js/src/tests/non262/class/newTargetBound.js
@@ -0,0 +1,16 @@
+function boundTarget(expected) {
+ assertEq(new.target, expected);
+}
+
+let bound = boundTarget.bind(undefined);
+
+const TEST_ITERATIONS = 550;
+
+for (let i = 0; i < TEST_ITERATIONS; i++)
+ bound(undefined);
+
+for (let i = 0; i < TEST_ITERATIONS; i++)
+ new bound(boundTarget);
+
+if (typeof reportCompare === "function")
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/newTargetCCW.js b/js/src/tests/non262/class/newTargetCCW.js
new file mode 100644
index 0000000000..9f5f870d40
--- /dev/null
+++ b/js/src/tests/non262/class/newTargetCCW.js
@@ -0,0 +1,10 @@
+// Make sure we wrap the new target on CCW construct calls.
+var g = newGlobal();
+
+let f = g.eval('(function (expected) { this.accept = new.target === expected; })');
+
+for (let i = 0; i < 1100; i++)
+ assertEq(new f(f).accept, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/newTargetDVG.js b/js/src/tests/non262/class/newTargetDVG.js
new file mode 100644
index 0000000000..1f9c7d7fc5
--- /dev/null
+++ b/js/src/tests/non262/class/newTargetDVG.js
@@ -0,0 +1,7 @@
+function thunk() {
+ new.target();
+}
+assertThrownErrorContains(thunk, "new.target");
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "OK");
diff --git a/js/src/tests/non262/class/newTargetDefaults.js b/js/src/tests/non262/class/newTargetDefaults.js
new file mode 100644
index 0000000000..d5a4c5640b
--- /dev/null
+++ b/js/src/tests/non262/class/newTargetDefaults.js
@@ -0,0 +1,25 @@
+// Check that new.target works properly in defaults.
+
+function check(expected, actual = new.target) { assertEq(actual, expected); }
+new check(check);
+check(undefined);
+
+let evaldCheck = eval("(" + check.toString() + ")");
+new evaldCheck(evaldCheck);
+evaldCheck(undefined);
+
+function testInFunction() {
+ function checkInFunction(expected, actual = new.target) { assertEq(actual, expected); }
+ new checkInFunction(checkInFunction);
+ checkInFunction(undefined);
+
+ let evaldCheckInFunction = eval("(" + checkInFunction.toString() + ")");
+ new evaldCheckInFunction(evaldCheckInFunction);
+ evaldCheckInFunction(undefined);
+}
+
+testInFunction();
+new testInFunction();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/newTargetDirectInvoke.js b/js/src/tests/non262/class/newTargetDirectInvoke.js
new file mode 100644
index 0000000000..d2cd1128c3
--- /dev/null
+++ b/js/src/tests/non262/class/newTargetDirectInvoke.js
@@ -0,0 +1,50 @@
+// new.target is valid inside Function() invocations
+var func = new Function("new.target");
+
+// Note that this will also test new.target in ion inlines. When the toplevel
+// script is compiled, assertNewTarget will be inlined.
+function assertNewTarget(expected, unused) { assertEq(new.target, expected); }
+
+// Test non-constructing invocations, with arg underflow, overflow, and correct
+// numbers
+for (let i = 0; i < 100; i++)
+ assertNewTarget(undefined, null);
+
+for (let i = 0; i < 100; i++)
+ assertNewTarget(undefined);
+
+for (let i = 0; i < 100; i++)
+ assertNewTarget(undefined, null, 1);
+
+// Test spread-call
+for (let i = 0; i < 100; i++)
+ assertNewTarget(...[undefined]);
+
+for (let i = 0; i < 100; i++)
+ assertNewTarget(...[undefined, null]);
+
+for (let i = 0; i < 100; i++)
+ assertNewTarget(...[undefined, null, 1]);
+
+// Test constructing invocations, again with under and overflow
+for (let i = 0; i < 100; i++)
+ new assertNewTarget(assertNewTarget, null);
+
+for (let i = 0; i < 100; i++)
+ new assertNewTarget(assertNewTarget);
+
+for (let i = 0; i < 100; i++)
+ new assertNewTarget(assertNewTarget, null, 1);
+
+// Test spreadnew as well.
+for (let i = 0; i < 100; i++)
+ new assertNewTarget(...[assertNewTarget]);
+
+for (let i = 0; i < 100; i++)
+ new assertNewTarget(...[assertNewTarget, null]);
+
+for (let i = 0; i < 100; i++)
+ new assertNewTarget(...[assertNewTarget, null, 1]);
+
+if (typeof reportCompare === "function")
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/newTargetEval.js b/js/src/tests/non262/class/newTargetEval.js
new file mode 100644
index 0000000000..f7581c5ab8
--- /dev/null
+++ b/js/src/tests/non262/class/newTargetEval.js
@@ -0,0 +1,40 @@
+// Eval of new.target is invalid outside functions.
+try {
+ eval('new.target');
+ assertEq(false, true);
+} catch (e) {
+ if (!(e instanceof SyntaxError))
+ throw e;
+}
+
+// new.target is invalid inside eval inside top-level arrow functions
+assertThrowsInstanceOf(() => eval('new.target'), SyntaxError);
+
+// new.target is invalid inside indirect eval.
+let ieval = eval;
+try {
+ (function () { return ieval('new.target'); })();
+ assertEq(false, true);
+} catch (e) {
+ if (!(e instanceof SyntaxError))
+ throw e;
+}
+
+function assertNewTarget(expected) {
+ assertEq(eval('new.target'), expected);
+ assertEq((()=>eval('new.target'))(), expected);
+
+ // Also test nestings "by induction"
+ assertEq(eval('eval("new.target")'), expected);
+ assertEq(eval("eval('eval(`new.target`)')"), expected);
+}
+
+const ITERATIONS = 550;
+for (let i = 0; i < ITERATIONS; i++)
+ assertNewTarget(undefined);
+
+for (let i = 0; i < ITERATIONS; i++)
+ new assertNewTarget(assertNewTarget);
+
+if (typeof reportCompare === "function")
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/newTargetGenerators.js b/js/src/tests/non262/class/newTargetGenerators.js
new file mode 100644
index 0000000000..614b1ab908
--- /dev/null
+++ b/js/src/tests/non262/class/newTargetGenerators.js
@@ -0,0 +1,14 @@
+function *generatorNewTarget(expected) {
+ assertEq(new.target, expected);
+ assertEq(eval('new.target'), expected);
+ assertEq((() => new.target)(), expected);
+ yield (() => new.target);
+}
+
+const ITERATIONS = 25;
+
+for (let i = 0; i < ITERATIONS; i++)
+ assertEq(generatorNewTarget(undefined).next().value(), undefined);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/newTargetMethods.js b/js/src/tests/non262/class/newTargetMethods.js
new file mode 100644
index 0000000000..2383dc8bd8
--- /dev/null
+++ b/js/src/tests/non262/class/newTargetMethods.js
@@ -0,0 +1,51 @@
+// Just like newTargetDirectInvoke, except to prove it works in functions
+// defined with method syntax as well. Note that methods, getters, and setters
+// are not constructible.
+
+let ol = {
+ olTest(arg) { assertEq(arg, 4); assertEq(new.target, undefined); },
+ get ol() { assertEq(new.target, undefined); },
+ set ol(arg) { assertEq(arg, 4); assertEq(new.target, undefined); }
+}
+
+class cl {
+ constructor() { assertEq(new.target, cl); }
+ clTest(arg) { assertEq(arg, 4); assertEq(new.target, undefined); }
+ get cl() { assertEq(new.target, undefined); }
+ set cl(arg) { assertEq(arg, 4); assertEq(new.target, undefined); }
+
+ static staticclTest(arg) { assertEq(arg, 4); assertEq(new.target, undefined); }
+ static get staticcl() { assertEq(new.target, undefined); }
+ static set staticcl(arg) { assertEq(arg, 4); assertEq(new.target, undefined); }
+}
+
+const TEST_ITERATIONS = 150;
+
+for (let i = 0; i < TEST_ITERATIONS; i++)
+ ol.olTest(4);
+for (let i = 0; i < TEST_ITERATIONS; i++)
+ ol.ol;
+for (let i = 0; i < TEST_ITERATIONS; i++)
+ ol.ol = 4;
+
+for (let i = 0; i < TEST_ITERATIONS; i++)
+ cl.staticclTest(4);
+for (let i = 0; i < TEST_ITERATIONS; i++)
+ cl.staticcl;
+for (let i = 0; i < TEST_ITERATIONS; i++)
+ cl.staticcl = 4;
+
+for (let i = 0; i < TEST_ITERATIONS; i++)
+ new cl();
+
+let clInst = new cl();
+
+for (let i = 0; i < TEST_ITERATIONS; i++)
+ clInst.clTest(4);
+for (let i = 0; i < TEST_ITERATIONS; i++)
+ clInst.cl;
+for (let i = 0; i < TEST_ITERATIONS; i++)
+ clInst.cl = 4;
+
+if (typeof reportCompare === "function")
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/newTargetNonFunction.js b/js/src/tests/non262/class/newTargetNonFunction.js
new file mode 100644
index 0000000000..59e6febef7
--- /dev/null
+++ b/js/src/tests/non262/class/newTargetNonFunction.js
@@ -0,0 +1,10 @@
+// Make sure that we can plumb new.target, even if the results are going to
+// throw.
+
+assertThrowsInstanceOf(() => new ""(...Array()), TypeError);
+
+assertThrowsInstanceOf(() => new ""(), TypeError);
+assertThrowsInstanceOf(() => new ""(1), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/newTargetProxyNative.js b/js/src/tests/non262/class/newTargetProxyNative.js
new file mode 100644
index 0000000000..89cdd64ab1
--- /dev/null
+++ b/js/src/tests/non262/class/newTargetProxyNative.js
@@ -0,0 +1,5 @@
+var proxyToArray = new Proxy(Array, {});
+new proxyToArray();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/outerBinding.js b/js/src/tests/non262/class/outerBinding.js
new file mode 100644
index 0000000000..19ffcb3e4a
--- /dev/null
+++ b/js/src/tests/non262/class/outerBinding.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!xulRuntime.shell)
+//
+// The above skip-if is because global lexicals aren't yet implemented. Remove
+// that and the |evaluate| call below once they are.
+//
+// A class statement creates a mutable lexical outer binding.
+
+class Foo { constructor() { } }
+assertEq(typeof Foo, "function");
+Foo = 5;
+assertEq(Foo, 5);
+
+{
+ class foo { constructor() { } }
+ assertEq(typeof foo, "function");
+ foo = 4;
+ assertEq(foo, 4);
+}
+
+{
+ class PermanentBinding { constructor() { } }
+ delete PermanentBinding;
+ // That...didn't actually work, right?
+ assertEq(typeof PermanentBinding, "function");
+}
+
+evaluate("const globalConstant = 0; var earlyError = true;");
+
+try {
+ evaluate("earlyError = false; class globalConstant { constructor() { } }");
+} catch (e) {
+ if (!(e instanceof SyntaxError))
+ throw e;
+}
+assertEq(earlyError, true);
+
+function strictEvalShadows() {
+ "use strict";
+ let x = 4;
+ eval(`class x { constructor() { } }
+ assertEq(typeof x, "function");
+ `);
+ assertEq(x, 4);
+}
+strictEvalShadows()
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "OK");
diff --git a/js/src/tests/non262/class/parenExprToString.js b/js/src/tests/non262/class/parenExprToString.js
new file mode 100644
index 0000000000..a93972ce92
--- /dev/null
+++ b/js/src/tests/non262/class/parenExprToString.js
@@ -0,0 +1,8 @@
+// Test that parenthesized class expressions don't get their toString offsets
+// messed up.
+
+assertEq((class {}).toString(), "class {}");
+assertEq(((class {})).toString(), "class {}");
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "OK");
diff --git a/js/src/tests/non262/class/shell.js b/js/src/tests/non262/class/shell.js
new file mode 100644
index 0000000000..1169b2c5f4
--- /dev/null
+++ b/js/src/tests/non262/class/shell.js
@@ -0,0 +1,10 @@
+function assertThrownErrorContains(thunk, substr) {
+ try {
+ thunk();
+ } catch (e) {
+ if (e.message.indexOf(substr) !== -1)
+ return;
+ throw new Error("Expected error containing " + substr + ", got " + e);
+ }
+ throw new Error("Expected error containing " + substr + ", no exception thrown");
+}
diff --git a/js/src/tests/non262/class/staticConstructor.js b/js/src/tests/non262/class/staticConstructor.js
new file mode 100644
index 0000000000..bd79c22005
--- /dev/null
+++ b/js/src/tests/non262/class/staticConstructor.js
@@ -0,0 +1,22 @@
+class testBasic {
+ constructor() { }
+ static constructor() { }
+}
+
+class testWithExtends extends null {
+ constructor() { };
+ static constructor() { };
+}
+
+class testOrder {
+ static constructor() { };
+ constructor() { };
+}
+
+class testOrderWithExtends extends null {
+ static constructor() { };
+ constructor() { };
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/staticMethods.js b/js/src/tests/non262/class/staticMethods.js
new file mode 100644
index 0000000000..756e5abf56
--- /dev/null
+++ b/js/src/tests/non262/class/staticMethods.js
@@ -0,0 +1,15 @@
+// basic static method test
+class X {
+ static count() { return ++this.hits; }
+ constructor() { }
+}
+X.hits = 0;
+assertEq(X.count(), 1);
+
+// A static method is just a function.
+assertEq(X.count instanceof Function, true);
+assertEq(X.count.length, 0);
+assertEq(X.count.bind({hits: 77})(), 78);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "OK");
diff --git a/js/src/tests/non262/class/strictExecution.js b/js/src/tests/non262/class/strictExecution.js
new file mode 100644
index 0000000000..f459311e55
--- /dev/null
+++ b/js/src/tests/non262/class/strictExecution.js
@@ -0,0 +1,38 @@
+// Classes are always strict mode. Check computed property names and heritage
+// expressions as well.
+
+class a { constructor() { Object.preventExtensions({}).prop = 0; } }
+assertThrowsInstanceOf(() => new a(), TypeError);
+var aExpr = class { constructor() { Object.preventExtensions().prop = 0; } };
+assertThrowsInstanceOf(() => new aExpr(), TypeError);
+
+function shouldThrowCPN() {
+ class b {
+ [Object.preventExtensions({}).prop = 4]() { }
+ constructor() { }
+ }
+}
+function shouldThrowCPNExpr() {
+ var b = class {
+ [Object.preventExtensions({}).prop = 4]() { }
+ constructor() { }
+ };
+}
+assertThrowsInstanceOf(shouldThrowCPN, TypeError);
+assertThrowsInstanceOf(shouldThrowCPNExpr, TypeError);
+
+function shouldThrowHeritage() {
+ class b extends (Object.preventExtensions({}).prop = 4) {
+ constructor() { }
+ }
+}
+function shouldThrowHeritageExpr() {
+ var b = class extends (Object.preventExtensions({}).prop = 4) {
+ constructor() { }
+ };
+}
+assertThrowsInstanceOf(shouldThrowHeritage, TypeError);
+assertThrowsInstanceOf(shouldThrowHeritageExpr, TypeError);
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0, "OK");
diff --git a/js/src/tests/non262/class/stringConstructor.js b/js/src/tests/non262/class/stringConstructor.js
new file mode 100644
index 0000000000..4e8ae3331f
--- /dev/null
+++ b/js/src/tests/non262/class/stringConstructor.js
@@ -0,0 +1,12 @@
+class A {
+ "constructor"() { return {}; }
+}
+assertEq(new A() instanceof A, false);
+
+class B extends class { } {
+ "constructor"() { return {}; }
+}
+assertEq(new B() instanceof B, false);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/subclassedArrayUnboxed.js b/js/src/tests/non262/class/subclassedArrayUnboxed.js
new file mode 100644
index 0000000000..eb27a960d0
--- /dev/null
+++ b/js/src/tests/non262/class/subclassedArrayUnboxed.js
@@ -0,0 +1,22 @@
+class foo extends Array { }
+
+function testArrs(arrs) {
+ for (let arr of arrs) {
+ assertEq(Object.getPrototypeOf(arr), foo.prototype);
+ }
+}
+
+var arrs = [];
+for (var i = 0; i < 25; i++)
+ arrs.push(new foo(1));
+
+testArrs(arrs);
+
+arrs[0].nonIndexedProp = "uhoh";
+
+arrs.push(new foo(1));
+
+testArrs(arrs);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superCallBadDynamicSuperClass.js b/js/src/tests/non262/class/superCallBadDynamicSuperClass.js
new file mode 100644
index 0000000000..f5b3ac3c0c
--- /dev/null
+++ b/js/src/tests/non262/class/superCallBadDynamicSuperClass.js
@@ -0,0 +1,12 @@
+class base { constructor() { } }
+
+class inst extends base { constructor() { super(); } }
+Object.setPrototypeOf(inst, Math.sin);
+assertThrowsInstanceOf(() => new inst(), TypeError);
+
+class defaultInst extends base { }
+Object.setPrototypeOf(inst, Math.sin);
+assertThrowsInstanceOf(() => new inst(), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superCallBadNewTargetPrototype.js b/js/src/tests/non262/class/superCallBadNewTargetPrototype.js
new file mode 100644
index 0000000000..43d1eb60d1
--- /dev/null
+++ b/js/src/tests/non262/class/superCallBadNewTargetPrototype.js
@@ -0,0 +1,25 @@
+class base { constructor() { } }
+
+// lies and the lying liars who tell them
+function lies() { }
+lies.prototype = 4;
+
+assertThrowsInstanceOf(()=>Reflect.consruct(base, [], lies), TypeError);
+
+// lie a slightly different way
+function get(target, property, receiver) {
+ if (property === "prototype")
+ return 42;
+ return Reflect.get(target, property, receiver);
+}
+
+class inst extends base {
+ constructor() { super(); }
+}
+assertThrowsInstanceOf(()=>new new Proxy(inst, {get})(), TypeError);
+
+class defaultInst extends base {}
+assertThrowsInstanceOf(()=>new new Proxy(defaultInst, {get})(), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superCallBaseInvoked.js b/js/src/tests/non262/class/superCallBaseInvoked.js
new file mode 100644
index 0000000000..b66f9be170
--- /dev/null
+++ b/js/src/tests/non262/class/superCallBaseInvoked.js
@@ -0,0 +1,55 @@
+function testBase(base) {
+ class instance extends base {
+ constructor(inst, one) {
+ super(inst, one);
+ }
+ }
+
+ let inst = new instance(instance, 1);
+ assertEq(Object.getPrototypeOf(inst), instance.prototype);
+ assertEq(inst.calledBase, true);
+
+ class defaultInstance extends base { }
+ let defInst = new defaultInstance(defaultInstance, 1);
+ assertEq(Object.getPrototypeOf(defInst), defaultInstance.prototype);
+ assertEq(defInst.calledBase, true);
+}
+
+class base {
+ // Base class must be [[Construct]]ed, as you cannot [[Call]] a class
+ // constructor
+ constructor(nt, one) {
+ assertEq(new.target, nt);
+
+ // Check argument ordering
+ assertEq(one, 1);
+ this.calledBase = true;
+ }
+}
+
+testBase(base);
+testBase(class extends base {
+ constructor(nt, one) {
+ // Every step of the way, new.target and args should be right
+ assertEq(new.target, nt);
+ assertEq(one, 1);
+ super(nt, one);
+ }
+ });
+function baseFunc(nt, one) {
+ assertEq(new.target, nt);
+ assertEq(one, 1);
+ this.calledBase = true;
+}
+
+testBase(baseFunc);
+
+let handler = {};
+let p = new Proxy(baseFunc, handler);
+testBase(p);
+
+handler.construct = (target, args, nt) => Reflect.construct(target, args, nt);
+testBase(p);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superCallIllegal.js b/js/src/tests/non262/class/superCallIllegal.js
new file mode 100644
index 0000000000..8b7b36397d
--- /dev/null
+++ b/js/src/tests/non262/class/superCallIllegal.js
@@ -0,0 +1,7 @@
+// super() invalid outside derived class constructors, including in dynamic
+// functions and eval
+assertThrowsInstanceOf(() => new Function("super();"), SyntaxError);
+assertThrowsInstanceOf(() => eval("super()"), SyntaxError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superCallInvalidBase.js b/js/src/tests/non262/class/superCallInvalidBase.js
new file mode 100644
index 0000000000..86b24f96c5
--- /dev/null
+++ b/js/src/tests/non262/class/superCallInvalidBase.js
@@ -0,0 +1,9 @@
+class instance extends null {
+ constructor() { super(); }
+}
+
+assertThrowsInstanceOf(() => new instance(), TypeError);
+assertThrowsInstanceOf(() => new class extends null { }(), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superCallOrder.js b/js/src/tests/non262/class/superCallOrder.js
new file mode 100644
index 0000000000..46a1b0e57c
--- /dev/null
+++ b/js/src/tests/non262/class/superCallOrder.js
@@ -0,0 +1,28 @@
+function base() { }
+
+class beforeSwizzle extends base {
+ constructor() {
+ super(Object.setPrototypeOf(beforeSwizzle, null));
+ }
+}
+
+new beforeSwizzle();
+
+function MyError() {}
+
+// Again, testing both dynamic prototype dispatch, and that we verify the function
+// is a constructor after evaluating args
+class beforeThrow extends base {
+ constructor() {
+ function thrower() { throw new MyError(); }
+ super(thrower());
+ }
+}
+
+Object.setPrototypeOf(beforeThrow, Math.sin);
+
+// Won't throw that Math.sin is not a constructor before evaluating the args
+assertThrowsInstanceOf(() => new beforeThrow(), MyError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superCallProperBase.js b/js/src/tests/non262/class/superCallProperBase.js
new file mode 100644
index 0000000000..cc03f57d08
--- /dev/null
+++ b/js/src/tests/non262/class/superCallProperBase.js
@@ -0,0 +1,34 @@
+class base1 {
+ constructor() {
+ this.base = 1;
+ }
+}
+
+class base2 {
+ constructor() {
+ this.base = 2;
+ }
+}
+
+class inst extends base1 {
+ constructor() {
+ super();
+ }
+}
+
+assertEq(new inst().base, 1);
+
+Object.setPrototypeOf(inst, base2);
+
+assertEq(new inst().base, 2);
+
+// Still works with default constructor
+
+class defaultInst extends base1 { }
+
+assertEq(new defaultInst().base, 1);
+Object.setPrototypeOf(defaultInst, base2);
+assertEq(new defaultInst().base, 2);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superCallSpreadCall.js b/js/src/tests/non262/class/superCallSpreadCall.js
new file mode 100644
index 0000000000..1045f1a22a
--- /dev/null
+++ b/js/src/tests/non262/class/superCallSpreadCall.js
@@ -0,0 +1,27 @@
+class base {
+ constructor(a, b, c) {
+ assertEq(a, 1);
+ assertEq(b, 2);
+ assertEq(c, 3);
+ this.calledBase = true;
+ }
+}
+
+class doTest extends base {
+ constructor(arr) {
+ super(...arr);
+ }
+}
+
+assertEq(new doTest([1,2,3]).calledBase, true);
+
+class testRest extends base {
+ constructor(...args) {
+ super(...args);
+ }
+}
+
+assertEq(new testRest(1,2,3).calledBase, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superCallThisInit.js b/js/src/tests/non262/class/superCallThisInit.js
new file mode 100644
index 0000000000..935f6b69ff
--- /dev/null
+++ b/js/src/tests/non262/class/superCallThisInit.js
@@ -0,0 +1,48 @@
+function base() { this.prop = 42; }
+
+class testInitialize extends base {
+ constructor() {
+ // A poor man's assertThrowsInstanceOf, as arrow functions are currently
+ // disabled in this context
+ try {
+ this;
+ throw new Error();
+ } catch (e) {
+ if (!(e instanceof ReferenceError))
+ throw e;
+ }
+ super();
+ assertEq(this.prop, 42);
+ }
+}
+assertEq(new testInitialize().prop, 42);
+
+// super() twice is a no-go.
+class willThrow extends base {
+ constructor() {
+ super();
+ super();
+ }
+}
+assertThrowsInstanceOf(()=>new willThrow(), ReferenceError);
+
+// This is determined at runtime, not the syntax level.
+class willStillThrow extends base {
+ constructor() {
+ for (let i = 0; i < 3; i++) {
+ super();
+ }
+ }
+}
+assertThrowsInstanceOf(()=>new willStillThrow(), ReferenceError);
+
+class canCatchThrow extends base {
+ constructor() {
+ super();
+ try { super(); } catch(e) { }
+ }
+}
+assertEq(new canCatchThrow().prop, 42);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superElemDelete.js b/js/src/tests/non262/class/superElemDelete.js
new file mode 100644
index 0000000000..74d2c94e15
--- /dev/null
+++ b/js/src/tests/non262/class/superElemDelete.js
@@ -0,0 +1,68 @@
+// Make sure we get the proper side effects.
+// |delete super[expr]| applies ToPropertyKey on |expr| before throwing.
+
+class base {
+ constructor() { }
+}
+
+class derived extends base {
+ constructor() { super(); }
+ testDeleteElem() {
+ let sideEffect = 0;
+ let key = {
+ toString() {
+ sideEffect++;
+ return "";
+ }
+ };
+ assertThrowsInstanceOf(() => delete super[key], ReferenceError);
+ assertEq(sideEffect, 1);
+ }
+ testDeleteElemPropValFirst() {
+ // The deletion error is a reference error, even after munging the prototype
+ // chain.
+ let key = {
+ toString() {
+ Object.setPrototypeOf(derived.prototype, null);
+ return "";
+ }
+ };
+ delete super[key];
+ }
+}
+
+class derivedTestDeleteElem extends base {
+ constructor() {
+ let sideEffect = 0;
+ let key = {
+ toString() {
+ sideEffect++;
+ return "";
+ }
+ };
+
+ assertThrowsInstanceOf(() => delete super[key], ReferenceError);
+ assertEq(sideEffect, 0);
+
+ super();
+
+ assertThrowsInstanceOf(() => delete super[key], ReferenceError);
+ assertEq(sideEffect, 1);
+
+ Object.setPrototypeOf(derivedTestDeleteElem.prototype, null);
+
+ assertThrowsInstanceOf(() => delete super[key], ReferenceError);
+ assertEq(sideEffect, 2);
+
+ return {};
+ }
+}
+
+var d = new derived();
+d.testDeleteElem();
+assertThrowsInstanceOf(() => d.testDeleteElemPropValFirst(), ReferenceError);
+
+new derivedTestDeleteElem();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropBasicCalls.js b/js/src/tests/non262/class/superPropBasicCalls.js
new file mode 100644
index 0000000000..c05d0ec26c
--- /dev/null
+++ b/js/src/tests/non262/class/superPropBasicCalls.js
@@ -0,0 +1,27 @@
+// Super property (and calls) works in non-extending classes and object
+// litterals.
+class toStringTest {
+ constructor() {
+ // Install a property to make it plausible that it's the same this
+ this.foo = "rhinoceros";
+ }
+
+ test() {
+ assertEq(super.toString(), super["toString"]());
+ assertEq(super.toString(), this.toString());
+ }
+}
+
+new toStringTest().test();
+
+let toStrOL = {
+ test() {
+ assertEq(super.toString(), super["toString"]());
+ assertEq(super.toString(), this.toString());
+ }
+}
+
+toStrOL.test();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropBasicChain.js b/js/src/tests/non262/class/superPropBasicChain.js
new file mode 100644
index 0000000000..12bf84820e
--- /dev/null
+++ b/js/src/tests/non262/class/superPropBasicChain.js
@@ -0,0 +1,11 @@
+var o = {
+ access() {
+ super.foo.bar;
+ }
+};
+
+// Delazify
+assertThrowsInstanceOf(o.access, TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropBasicGetter.js b/js/src/tests/non262/class/superPropBasicGetter.js
new file mode 100644
index 0000000000..fe1f4eeee8
--- /dev/null
+++ b/js/src/tests/non262/class/superPropBasicGetter.js
@@ -0,0 +1,36 @@
+class base {
+ constructor() {}
+
+ getValue() {
+ return this._prop;
+ }
+
+ setValue(v) {
+ this._prop = v;
+ }
+}
+
+class derived extends base {
+ constructor() { super(); }
+
+ get a() { return super.getValue(); }
+ set a(v) { super.setValue(v); }
+
+ get b() { return eval('super.getValue()'); }
+ set b(v) { eval('super.setValue(v);'); }
+
+ test() {
+ this.a = 15;
+ assertEq(this.a, 15);
+
+ assertEq(this.b, 15);
+ this.b = 30;
+ assertEq(this.b, 30);
+ }
+}
+
+var derivedInstance = new derived();
+derivedInstance.test();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropBasicNew.js b/js/src/tests/non262/class/superPropBasicNew.js
new file mode 100644
index 0000000000..e1ca9b4ae1
--- /dev/null
+++ b/js/src/tests/non262/class/superPropBasicNew.js
@@ -0,0 +1,17 @@
+class Base {
+ constructor() {}
+}
+class Mid extends Base {
+ constructor() { super(); }
+ f() { return new super.constructor(); }
+}
+class Derived extends Mid {
+ constructor() { super(); }
+}
+
+let d = new Derived();
+var df = d.f();
+assertEq(df.constructor, Base);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropChains.js b/js/src/tests/non262/class/superPropChains.js
new file mode 100644
index 0000000000..e8c0de05cd
--- /dev/null
+++ b/js/src/tests/non262/class/superPropChains.js
@@ -0,0 +1,58 @@
+// First, let's test the trivial. A chain of three works.
+class base {
+ constructor() { }
+ testChain() {
+ this.baseCalled = true;
+ }
+}
+
+class middle extends base {
+ constructor() { super(); }
+ testChain() {
+ this.middleCalled = true;
+ super.testChain();
+ }
+}
+
+class derived extends middle {
+ constructor() { super(); }
+ testChain() {
+ super.testChain();
+ assertEq(this.middleCalled, true);
+ assertEq(this.baseCalled, true);
+ }
+}
+
+new derived().testChain();
+
+// Super even chains in a wellbehaved fashion with normal functions.
+function bootlegMiddle() { }
+bootlegMiddle.prototype = middle.prototype;
+
+new class extends bootlegMiddle {
+ constructor() { super(); }
+ testChain() {
+ super.testChain();
+ assertEq(this.middleCalled, true);
+ assertEq(this.baseCalled, true);
+ }
+ }().testChain();
+
+// Now let's try out some "long" chains
+base.prototype.x = "yeehaw";
+
+let chain = class extends base { constructor() { super(); } }
+
+const CHAIN_LENGTH = 100;
+for (let i = 0; i < CHAIN_LENGTH; i++)
+ chain = class extends chain { constructor() { super(); } }
+
+// Now we poke the chain
+let inst = new chain();
+inst.testChain();
+assertEq(inst.baseCalled, true);
+
+assertEq(inst.x, "yeehaw");
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropDVG.js b/js/src/tests/non262/class/superPropDVG.js
new file mode 100644
index 0000000000..f187cb6ea1
--- /dev/null
+++ b/js/src/tests/non262/class/superPropDVG.js
@@ -0,0 +1,17 @@
+// Super property accesses should play nice with the pretty printer.
+class testNonExistent {
+ constructor() {
+ super["prop"]();
+ }
+}
+// Should fold to super.prop
+assertThrownErrorContains(() => new testNonExistent(), 'super.prop');
+
+var ol = { testNonExistent() { super.prop(); } };
+assertThrownErrorContains(() => ol.testNonExistent(), "super.prop");
+
+var olElem = { testNonExistent() { var prop = "prop"; super[prop](); } };
+assertThrownErrorContains(() => olElem.testNonExistent(), "super[prop]");
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropDelete.js b/js/src/tests/non262/class/superPropDelete.js
new file mode 100644
index 0000000000..e0b71613ea
--- /dev/null
+++ b/js/src/tests/non262/class/superPropDelete.js
@@ -0,0 +1,64 @@
+// Make sure we get the proper side effects.
+// |delete super.prop| and |delete super[expr]| throw universally.
+
+class base {
+ constructor() { }
+}
+
+class derived extends base {
+ constructor() { super(); }
+ testDeleteProp() { delete super.prop; }
+ testDeleteElem() {
+ let sideEffect = 0;
+ assertThrowsInstanceOf(() => delete super[sideEffect = 1], ReferenceError);
+ assertEq(sideEffect, 1);
+ }
+ testDeleteElemPropValFirst() {
+ // The deletion error is a reference error, but by munging the prototype
+ // chain, we can force a typeerror from JSOP_SUPERBASE
+ delete super[Object.setPrototypeOf(derived.prototype, null)];
+ }
+}
+
+var d = new derived();
+assertThrowsInstanceOf(() => d.testDeleteProp(), ReferenceError);
+d.testDeleteElem();
+assertThrowsInstanceOf(() => d.testDeleteElemPropValFirst(), TypeError);
+
+// |delete super.x| does not delete anything before throwing.
+var thing1 = {
+ go() { delete super.toString; }
+};
+let saved = Object.prototype.toString;
+assertThrowsInstanceOf(() => thing1.go(), ReferenceError);
+assertEq(Object.prototype.toString, saved);
+
+// |delete super.x| does not tell the prototype to delete anything, when it's a proxy.
+var thing2 = {
+ go() { delete super.prop; }
+};
+Object.setPrototypeOf(thing2, new Proxy({}, {
+ deleteProperty(x) { throw "FAIL"; }
+}));
+assertThrowsInstanceOf(() => thing2.go(), ReferenceError);
+
+class derivedTestDeleteProp extends base {
+ constructor() {
+ // The deletion error is a reference error, even after munging the prototype
+ // chain.
+ Object.setPrototypeOf(derivedTestDeleteProp.prototype, null);
+
+ assertThrowsInstanceOf(() => delete super.prop, ReferenceError);
+
+ super();
+
+ assertThrowsInstanceOf(() => delete super.prop, ReferenceError);
+
+ return {};
+ }
+}
+
+new derivedTestDeleteProp();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropDerivedCalls.js b/js/src/tests/non262/class/superPropDerivedCalls.js
new file mode 100644
index 0000000000..1a8a036057
--- /dev/null
+++ b/js/src/tests/non262/class/superPropDerivedCalls.js
@@ -0,0 +1,77 @@
+let derivedInstance;
+
+class base {
+ constructor() { }
+ method(a, b, c) {
+ assertEq(this, derivedInstance);
+ this.methodCalled = true;
+ assertEq(a, 1);
+ assertEq(b, 2);
+ assertEq(c, 3);
+ }
+
+ get prop() {
+ assertEq(this, derivedInstance);
+ this.getterCalled = true;
+ return this._prop;
+ }
+
+ set prop(val) {
+ assertEq(this, derivedInstance);
+ this.setterCalled = true;
+ this._prop = val;
+ }
+}
+
+class derived extends base {
+ constructor() { super(); }
+
+ // |super| actually checks the chain, not |this|
+ method() { throw "FAIL"; }
+ get prop() { throw "FAIL"; }
+ set prop(v) { throw "FAIL"; }
+
+ test() {
+ this.reset();
+ // While we're here. Let's check on super spread calls...
+ let spread = [1,2,3];
+ super.method(...spread);
+ super.prop++;
+ this.asserts();
+ }
+
+ testInEval() {
+ this.reset();
+ eval("super.method(1,2,3); super.prop++");
+ this.asserts();
+ }
+
+ testInArrow() {
+ this.reset();
+ (() => (super.method(1,2,3), super.prop++))();
+ this.asserts();
+ }
+
+ reset() {
+ this._prop = 0;
+ this.methodCalled = false;
+ this.setterCalled = false;
+ this.getterCalled = false;
+ }
+
+ asserts() {
+ assertEq(this.methodCalled, true);
+ assertEq(this.getterCalled, true);
+ assertEq(this.setterCalled, true);
+ assertEq(this._prop, 1);
+ }
+
+}
+
+derivedInstance = new derived();
+derivedInstance.test();
+derivedInstance.testInEval();
+derivedInstance.testInArrow();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropDestructuring.js b/js/src/tests/non262/class/superPropDestructuring.js
new file mode 100644
index 0000000000..84d1bb517a
--- /dev/null
+++ b/js/src/tests/non262/class/superPropDestructuring.js
@@ -0,0 +1,43 @@
+class base {
+ constructor() { }
+}
+
+let seenValues;
+Object.defineProperty(base.prototype, "minutes",
+ {
+ set(x) {
+ assertEq(x, 525600);
+ seenValues.push(x);
+ }
+ });
+Object.defineProperty(base.prototype, "intendent",
+ {
+ set(x) {
+ assertEq(x, "Fred");
+ seenValues.push(x)
+ }
+ });
+
+const testArr = [525600, "Fred"];
+class derived extends base {
+ constructor() { super(); }
+ prepForTest() { seenValues = []; }
+ testAsserts() { assertDeepEq(seenValues, testArr); }
+ testProps() {
+ this.prepForTest();
+ [super.minutes, super.intendent] = testArr;
+ this.testAsserts();
+ }
+ testElems() {
+ this.prepForTest();
+ [super["minutes"], super["intendent"]] = testArr;
+ this.testAsserts();
+ }
+}
+
+let d = new derived();
+d.testProps();
+d.testElems();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropEvalInsideArrow.js b/js/src/tests/non262/class/superPropEvalInsideArrow.js
new file mode 100644
index 0000000000..882f93ba0a
--- /dev/null
+++ b/js/src/tests/non262/class/superPropEvalInsideArrow.js
@@ -0,0 +1,11 @@
+class foo {
+ constructor() { }
+
+ method() {
+ return (() => eval('super.toString'));
+ }
+}
+assertEq(new foo().method()(), Object.prototype.toString);
+
+if (typeof reportCompare === "function")
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropEvalInsideNested.js b/js/src/tests/non262/class/superPropEvalInsideNested.js
new file mode 100644
index 0000000000..04cdab0499
--- /dev/null
+++ b/js/src/tests/non262/class/superPropEvalInsideNested.js
@@ -0,0 +1,13 @@
+// It's invalid to eval super.prop inside a nested non-method, even if it
+// appears inside a method definition
+assertThrowsInstanceOf(() =>
+({
+ method() {
+ (function () {
+ eval('super.toString');
+ })();
+ }
+}).method(), SyntaxError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropFor.js b/js/src/tests/non262/class/superPropFor.js
new file mode 100644
index 0000000000..23b222cb3e
--- /dev/null
+++ b/js/src/tests/non262/class/superPropFor.js
@@ -0,0 +1,25 @@
+class testForIn {
+ constructor() {
+ let hits = 0;
+ for (super.prop in { prop1: 1, prop2: 2 })
+ hits++;
+ assertEq(this.prop, "prop2");
+ assertEq(hits, 2);
+ }
+}
+
+new testForIn();
+
+
+({
+ testForOf() {
+ let hits = 0;
+ for (super["prop"] of [1, 2])
+ hits++;
+ assertEq(this.prop, 2);
+ assertEq(hits, 2);
+ }
+}).testForOf();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropHeavyweightArrow.js b/js/src/tests/non262/class/superPropHeavyweightArrow.js
new file mode 100644
index 0000000000..ce30690d53
--- /dev/null
+++ b/js/src/tests/non262/class/superPropHeavyweightArrow.js
@@ -0,0 +1,12 @@
+class foo {
+ constructor() { }
+
+ method() {
+ return (() => (eval(''), super.toString));
+ }
+}
+
+assertEq(new foo().method()(), Object.prototype.toString);
+
+if (typeof reportCompare === "function")
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropHomeObject.js b/js/src/tests/non262/class/superPropHomeObject.js
new file mode 100644
index 0000000000..b23c115dd5
--- /dev/null
+++ b/js/src/tests/non262/class/superPropHomeObject.js
@@ -0,0 +1,61 @@
+// This is super weird. A super property reference in the spec contains two
+// things. The first is the object to do the lookup on, the super base. This
+// should be unchanged, no matter what's going on: I can move the method to
+// another object. I can pull it out as its own function. I can put it on my
+// head and run around the front yard. No changes. The other half, the |this|
+// for invoked calls, is the this at the time of referencing the property, which
+// means it's gonna vary wildly as stuff gets moved around.
+
+class base {
+ constructor() { }
+ test(expectedThis) { assertEq(this, expectedThis); }
+}
+
+class derived extends base {
+ constructor() { super(); }
+ test(expected) { super.test(expected); }
+ testArrow() { return (() => super.test(this)); }
+ ["testCPN"](expected) { super.test(expected); }
+}
+
+let derivedInstance = new derived();
+derivedInstance.test(derivedInstance);
+derivedInstance.testCPN(derivedInstance);
+
+let obj = { test: derivedInstance.test };
+obj.test(obj);
+
+// Classes are strict, so primitives are not boxed/turned into globals
+let testSolo = derivedInstance.test;
+testSolo(undefined);
+
+let anotherObject = { };
+derivedInstance.test.call(anotherObject, anotherObject);
+
+let strThis = "this is not an object!";
+derivedInstance.test.call(strThis, strThis);
+
+// You can take the arrow function out of the super, ... or something like that
+let arrowTest = derivedInstance.testArrow();
+arrowTest();
+
+// There's no magic "super script index" per code location.
+class base1 {
+ constructor() { }
+ test() { return "llama"; }
+}
+class base2 {
+ constructor() { }
+ test() { return "alpaca"; }
+}
+
+let animals = [];
+for (let exprBase of [base1, base2])
+ new class extends exprBase {
+ constructor() { super(); }
+ test() { animals.push(super["test"]()); }
+ }().test();
+assertDeepEq(animals, ["llama", "alpaca"]);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropIncDecElem.js b/js/src/tests/non262/class/superPropIncDecElem.js
new file mode 100644
index 0000000000..a7b93eb371
--- /dev/null
+++ b/js/src/tests/non262/class/superPropIncDecElem.js
@@ -0,0 +1,24 @@
+// #1
+function base() { }
+
+base.prototype = {
+ test() {
+ --super[1];
+ }
+}
+
+var d = new base();
+d.test();
+
+// #2
+class test2 {
+ test() {
+ super[1]++;
+ }
+}
+
+var d = new test2();
+d.test()
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropLazyInnerFunction.js b/js/src/tests/non262/class/superPropLazyInnerFunction.js
new file mode 100644
index 0000000000..d7a441f93b
--- /dev/null
+++ b/js/src/tests/non262/class/superPropLazyInnerFunction.js
@@ -0,0 +1,19 @@
+testcase();
+function testcase() {
+ var tokenCodes = {
+ get try() {
+ try {
+ super.actual();
+ } catch (e) {}
+ }
+ };
+ var arr = [
+ 'try',
+ ];
+ for (var i = 0; i < arr.length; i++) {
+ if (tokenCodes[arr[i]] !== i) {};
+ }
+}
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropNoOverwriting.js b/js/src/tests/non262/class/superPropNoOverwriting.js
new file mode 100644
index 0000000000..db44b509c5
--- /dev/null
+++ b/js/src/tests/non262/class/superPropNoOverwriting.js
@@ -0,0 +1,58 @@
+class X {
+ constructor() {
+ Object.defineProperty(this, "prop1", {
+ configurable: true,
+ writable: false,
+ value: 1
+ });
+
+ Object.defineProperty(this, "prop2", {
+ configurable: true,
+ get: function() { return 15; }
+ });
+
+ Object.defineProperty(this, "prop3", {
+ configurable: true,
+ set: function(a) { }
+ });
+
+ Object.defineProperty(this, "prop4", {
+ configurable: true,
+ get: function() { return 20; },
+ set: function(a) { }
+ });
+ }
+
+ f1() {
+ super.prop1 = 2;
+ }
+
+ f2() {
+ super.prop2 = 3;
+ }
+
+ f3() {
+ super.prop3 = 4;
+ }
+
+ f4() {
+ super.prop4 = 5;
+ }
+}
+
+var x = new X();
+
+assertThrowsInstanceOf(() => x.f1(), TypeError);
+assertEq(x.prop1, 1);
+
+assertThrowsInstanceOf(() => x.f2(), TypeError);
+assertEq(x.prop2, 15);
+
+assertThrowsInstanceOf(() => x.f3(), TypeError);
+assertEq(x.prop3, undefined);
+
+assertThrowsInstanceOf(() => x.f4(), TypeError);
+assertEq(x.prop4, 20);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropOrdering.js b/js/src/tests/non262/class/superPropOrdering.js
new file mode 100644
index 0000000000..1374d52c1c
--- /dev/null
+++ b/js/src/tests/non262/class/superPropOrdering.js
@@ -0,0 +1,93 @@
+class base {
+ constructor() { }
+ method() { this.methodCalled++; }
+}
+
+class derived extends base {
+ constructor() { super(); this.methodCalled = 0; }
+
+ // Test orderings of various evaluations relative to the superbase
+
+ // Unlike in regular element evaluation, the propVal is evaluated before
+ // checking the starting object ([[HomeObject]].[[Prototype]])
+ testElem() { super[ruin()]; }
+
+ // The starting object for looking up super.method is determined before
+ // ruin() is called.
+ testProp() { super.method(ruin()); }
+
+ // The entire super.method property lookup has concluded before the args
+ // are evaluated
+ testPropCallDeleted() { super.method(()=>delete base.prototype.method); }
+
+ // The starting object for looking up super["prop"] is determined before
+ // ruin() is called.
+ testElemAssign() { super["prop"] = ruin(); }
+
+ // Test the normal assignment gotchas
+ testAssignElemPropValChange() {
+ let x = "prop1";
+ super[x] = (()=>(x = "prop2", 0))();
+ assertEq(this.prop1, 0);
+ assertEq(this.prop2, undefined);
+ }
+
+ testAssignProp() {
+ Object.defineProperty(base.prototype, "piggy",
+ {
+ configurable: true,
+ set() { throw "WEE WEE WEE WEE"; }
+ });
+
+ // The property lookup is noted, but not actually evaluated, until the
+ // right hand side is. Please don't make the piggy cry.
+ super.piggy = (() => delete base.prototype.piggy)();
+ }
+ testCompoundAssignProp() {
+ let getterCalled = false;
+ Object.defineProperty(base.prototype, "horse",
+ {
+ configurable: true,
+ get() { getterCalled = true; return "Of course"; },
+ set() { throw "NO!"; }
+ });
+ super.horse += (()=>(delete base.prototype.horse, ", of course!"))();
+ assertEq(getterCalled, true);
+
+ // So, is a horse a horse?
+ assertEq(this.horse, "Of course, of course!");
+ }
+}
+
+function ruin() {
+ Object.setPrototypeOf(derived.prototype, null);
+ return 5;
+}
+
+function reset() {
+ Object.setPrototypeOf(derived.prototype, base.prototype);
+}
+
+let instance = new derived();
+assertThrowsInstanceOf(() => instance.testElem(), TypeError);
+reset();
+
+instance.testProp();
+assertEq(instance.methodCalled, 1);
+reset();
+
+instance.testPropCallDeleted();
+assertEq(instance.methodCalled, 2);
+
+instance.testElemAssign();
+assertEq(instance.prop, 5);
+reset();
+
+instance.testAssignElemPropValChange();
+
+instance.testAssignProp();
+
+instance.testCompoundAssignProp();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropProtoChanges.js b/js/src/tests/non262/class/superPropProtoChanges.js
new file mode 100644
index 0000000000..d16ca16659
--- /dev/null
+++ b/js/src/tests/non262/class/superPropProtoChanges.js
@@ -0,0 +1,22 @@
+class base {
+ constructor() { }
+ test() {
+ return false;
+ }
+}
+
+let standin = { test() { return true; } };
+
+class derived extends base {
+ constructor() { super(); }
+ test() {
+ assertEq(super.test(), false);
+ Object.setPrototypeOf(derived.prototype, standin);
+ assertEq(super["test"](), true);
+ }
+}
+
+new derived().test();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropProxies.js b/js/src/tests/non262/class/superPropProxies.js
new file mode 100644
index 0000000000..3ec43b279c
--- /dev/null
+++ b/js/src/tests/non262/class/superPropProxies.js
@@ -0,0 +1,83 @@
+class base {
+ constructor() { }
+}
+
+let midStaticHandler = { };
+
+// We shouldn't use the |this.called| strategy here, since we have proxies
+// snooping property accesses.
+let getterCalled, setterCalled;
+
+class mid extends new Proxy(base, midStaticHandler) {
+ constructor() { super(); }
+ testSuperInProxy() {
+ super.prop = "looking";
+ assertEq(setterCalled, true);
+ assertEq(super.prop, "found");
+ assertEq(getterCalled, true);
+ }
+}
+
+class child extends mid {
+ constructor() { super(); }
+ static testStaticLookups() {
+ // This funtion is called more than once.
+ this.called = false;
+ super.prop;
+ assertEq(this.called, true);
+ }
+}
+
+let midInstance = new mid();
+
+// Make sure proxies are searched properly on the prototype chain
+let baseHandler = {
+ get(target, p, receiver) {
+ assertEq(receiver, midInstance);
+ getterCalled = true;
+ return "found";
+ },
+
+ set(t,p,val,receiver) {
+ assertEq(receiver, midInstance);
+ assertEq(val, "looking");
+ setterCalled = true;
+ return true;
+ }
+}
+Object.setPrototypeOf(base.prototype, new Proxy(Object.prototype, baseHandler));
+
+// make sure subclasses are not searched on static or super lookups.
+let childHandler = {
+ get() { throw "NO!"; },
+ set() { throw "NO!"; }
+}
+Object.setPrototypeOf(child.prototype, new Proxy(mid.prototype, childHandler));
+
+midInstance.testSuperInProxy();
+
+// Don't do this earlier to avoid the lookup of .prototype during class creation
+function midGet(target, p, receiver) {
+ assertEq(receiver, child);
+ receiver.called = true;
+}
+midStaticHandler.get = midGet;
+
+child.testStaticLookups();
+
+// Hey does super work in a proxy?
+assertEq(new Proxy(({ method() { return super.hasOwnProperty("method"); } }), {}).method(), true);
+
+// What about a CCW?
+var g = newGlobal();
+var wrappedSuper = g.eval("({ method() { return super.hasOwnProperty('method'); } })");
+assertEq(wrappedSuper.method(), true);
+
+// With a CCW on the proto chain?
+var wrappedBase = g.eval("({ method() { return this.__secretProp__; } })");
+var unwrappedDerived = { __secretProp__: 42, method() { return super.method(); } }
+Object.setPrototypeOf(unwrappedDerived, wrappedBase);
+assertEq(unwrappedDerived.method(), 42);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropSkips.js b/js/src/tests/non262/class/superPropSkips.js
new file mode 100644
index 0000000000..c9587c72f1
--- /dev/null
+++ b/js/src/tests/non262/class/superPropSkips.js
@@ -0,0 +1,45 @@
+// Ensure that super lookups and sets skip over properties on the |this| object.
+// That is, super lookups start with the superclass, not the current class.
+
+// The whole point: an empty superclass
+class base {
+ constructor() { }
+}
+
+class derived extends base {
+ constructor() { super(); this.prop = "flamingo"; }
+
+ toString() { throw "No!"; }
+
+ testSkipGet() {
+ assertEq(super.prop, undefined);
+ }
+
+ testSkipDerivedOverrides() {
+ assertEq(super["toString"](), Object.prototype.toString.call(this));
+ }
+
+ testSkipSet() {
+ // since there's no prop on the chain, we should set the data property
+ // on the receiver, |this|
+ super.prop = "rat";
+ assertEq(this.prop, "rat");
+
+ // Since the receiver is the instance, we can overwrite inherited
+ // properties of the instance, even non-writable ones, as they could be
+ // skipped in the super lookup.
+ assertEq(this.nonWritableProp, "pony");
+ super.nonWritableProp = "bear";
+ assertEq(this.nonWritableProp, "bear");
+ }
+}
+
+Object.defineProperty(derived.prototype, "nonWritableProp", { writable: false, value: "pony" });
+
+let instance = new derived();
+instance.testSkipGet();
+instance.testSkipDerivedOverrides();
+instance.testSkipSet();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropStatics.js b/js/src/tests/non262/class/superPropStatics.js
new file mode 100644
index 0000000000..32624b5d28
--- /dev/null
+++ b/js/src/tests/non262/class/superPropStatics.js
@@ -0,0 +1,34 @@
+class base {
+ constructor() { }
+ static found() {
+ this.foundCalled = true;
+ }
+ static get accessor() {
+ assertEq(this, derived);
+ return 45;
+ }
+ notFound() { }
+}
+
+class derived extends base {
+ constructor() { }
+
+ static found() { throw "NO!"; }
+ static get accessor() { throw "NO!"; }
+
+ static test() {
+ assertEq(super["notFound"], undefined);
+ super.found();
+
+ // foundCalled is set on |derived| specifically.
+ let calledDesc = Object.getOwnPropertyDescriptor(derived, "foundCalled");
+ assertEq(calledDesc.value, true);
+
+ assertEq(super.accessor, 45);
+ }
+}
+
+derived.test();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superPropStrictAssign.js b/js/src/tests/non262/class/superPropStrictAssign.js
new file mode 100644
index 0000000000..4b5444a3cf
--- /dev/null
+++ b/js/src/tests/non262/class/superPropStrictAssign.js
@@ -0,0 +1,23 @@
+// While |super| is common in classes, it also works in object litterals,
+// where there is no guarantee of strict mode. Check that we do not somehow
+// get strict mode semantics when they were not called for
+
+// |undefined|, writable: false
+Object.defineProperty(Object.prototype, "prop", { writable: false });
+
+class strictAssignmentTest {
+ constructor() {
+ // Strict mode. Throws.
+ super.prop = 14;
+ }
+}
+
+assertThrowsInstanceOf(()=>new strictAssignmentTest(), TypeError);
+
+// Non-strict. Silent failure.
+({ test() { super.prop = 14; } }).test();
+
+assertEq(Object.prototype.prop, undefined);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0,0,"OK");
diff --git a/js/src/tests/non262/class/superThisStrictNoBoxing.js b/js/src/tests/non262/class/superThisStrictNoBoxing.js
new file mode 100644
index 0000000000..f479ac036a
--- /dev/null
+++ b/js/src/tests/non262/class/superThisStrictNoBoxing.js
@@ -0,0 +1,31 @@
+class C {
+ get prop_this() { return this; }
+}
+
+var g_prop_this = 'prop_this';
+class D extends C {
+ super_prop() { return super.prop_this; }
+ super_elem() { return super[g_prop_this]; }
+}
+
+var barsym = Symbol("bar");
+
+// Test that primitive |this| values are not boxed, and undefined/null are not
+// globals for super.property.
+assertEq(new D().super_prop.call(3), 3);
+assertEq(new D().super_prop.call("foo"), "foo");
+assertEq(new D().super_prop.call(true), true);
+assertEq(new D().super_prop.call(barsym), barsym);
+assertEq(new D().super_prop.call(null), null);
+assertEq(new D().super_prop.call(undefined), undefined);
+
+// Ditto for super[elem]
+assertEq(new D().super_elem.call(3), 3);
+assertEq(new D().super_elem.call("foo"), "foo");
+assertEq(new D().super_elem.call(true), true);
+assertEq(new D().super_elem.call(barsym), barsym);
+assertEq(new D().super_elem.call(null), null);
+assertEq(new D().super_elem.call(undefined), undefined);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/class/uninitializedThisError.js b/js/src/tests/non262/class/uninitializedThisError.js
new file mode 100644
index 0000000000..658ef8002c
--- /dev/null
+++ b/js/src/tests/non262/class/uninitializedThisError.js
@@ -0,0 +1,53 @@
+function checkErr(f) {
+ var expected = "must call super constructor before using 'this' in derived class constructor";
+ try {
+ f();
+ assertEq(0, 1);
+ } catch (e) {
+ assertEq(e.name, "ReferenceError");
+ assertEq(e.message, expected);
+ }
+}
+class TestNormal extends class {} {
+ constructor() { this; }
+}
+checkErr(() => new TestNormal());
+
+class TestEval extends class {} {
+ constructor() { eval("this") }
+}
+checkErr(() => new TestEval());
+
+class TestNestedEval extends class {} {
+ constructor() { eval("eval('this')") }
+}
+checkErr(() => new TestNestedEval());
+
+checkErr(() => {
+ new class extends class {} {
+ constructor() { eval("this") }
+ }
+});
+
+class TestArrow extends class {} {
+ constructor() { (() => this)(); }
+}
+checkErr(() => new TestArrow());
+
+class TestArrowEval extends class {} {
+ constructor() { (() => eval("this"))(); }
+}
+checkErr(() => new TestArrowEval());
+
+class TestEvalArrow extends class {} {
+ constructor() { eval("(() => this)()"); }
+}
+checkErr(() => new TestEvalArrow());
+
+class TestTypeOf extends class {} {
+ constructor() { eval("typeof this"); }
+}
+checkErr(() => new TestTypeOf());
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);