diff options
Diffstat (limited to 'js/src/tests/ecma_6/Expressions')
20 files changed, 1592 insertions, 0 deletions
diff --git a/js/src/tests/ecma_6/Expressions/ToPropertyKey-symbols.js b/js/src/tests/ecma_6/Expressions/ToPropertyKey-symbols.js new file mode 100644 index 000000000..32b3994b3 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/ToPropertyKey-symbols.js @@ -0,0 +1,90 @@ +var symbols = [ + Symbol(), Symbol("iterator"), Symbol.for("iterator"), Symbol.iterator +]; + +for (var sym of symbols) { + var key = { + toString() { return sym; } + }; + + // Test that ToPropertyKey can return a symbol in each of the following + // contexts. + + // Computed property names. + var obj = {[key]: 13}; + var found = Reflect.ownKeys(obj); + assertEq(found.length, 1); + assertEq(found[0], sym); + + // Computed accessor property names. + var obj2 = { + get [key]() { return "got"; }, + set [key](v) { this.v = v; } + }; + assertEq(obj2[sym], "got"); + obj2[sym] = 33; + assertEq(obj2.v, 33); + + // Getting and setting properties. + assertEq(obj[key], 13); + obj[key] = 19; + assertEq(obj[sym], 19); + (function () { "use strict"; obj[key] = 20; })(); + assertEq(obj[sym], 20); + obj[key]++; + assertEq(obj[sym], 21); + + // Getting properties of primitive values. + Number.prototype[sym] = "success"; + assertEq(Math.PI[key], "success"); + delete Number.prototype[sym]; + + // Getting a super property. + class X { + [sym]() { return "X"; } + } + class Y extends X { + [sym]() { return super[key]() + "Y"; } + } + var y = new Y(); + assertEq(y[sym](), "XY"); + + // Setting a super property. + class Z { + set [sym](v) { + this.self = this; + this.value = v; + } + } + class W extends Z { + set [sym](v) { + this.isW = true; + super[key] = v; + } + } + var w = new W(); + w[key] = "ok"; + assertEq(w.self, w); + assertEq(w.value, "ok"); + assertEq(w.isW, true); + + // Deleting properties. + obj = {[sym]: 1}; + assertEq(delete obj[key], true); + assertEq(sym in obj, false); + + // LHS of `in` expressions. + assertEq(key in {iterator: 0}, false); + assertEq(key in {[sym]: 0}, true); + + // Methods of Object and Object.prototype + obj = {}; + Object.defineProperty(obj, key, {value: "ok", enumerable: true}); + assertEq(obj[sym], "ok"); + assertEq(obj.hasOwnProperty(key), true); + assertEq(obj.propertyIsEnumerable(key), true); + var desc = Object.getOwnPropertyDescriptor(obj, key); + assertEq(desc.value, "ok"); +} + +reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Expressions/binary-literals.js b/js/src/tests/ecma_6/Expressions/binary-literals.js new file mode 100644 index 000000000..df1f2ed6f --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/binary-literals.js @@ -0,0 +1,115 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 894026; +var summary = "Implement ES6 binary literals"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var chars = ['b', 'B']; + +for (var i = 0; i < 2; i++) +{ + if (i === 2) + { + chars.forEach(function(v) + { + try + { + eval('0' + v + i); + throw "didn't throw"; + } + catch (e) + { + assertEq(e instanceof SyntaxError, true, + "no syntax error evaluating 0" + v + i + ", " + + "got " + e); + } + }); + continue; + } + + for (var j = 0; j < 2; j++) + { + if (j === 2) + { + chars.forEach(function(v) + { + try + { + eval('0' + v + i + j); + throw "didn't throw"; + } + catch (e) + { + assertEq(e instanceof SyntaxError, true, + "no syntax error evaluating 0" + v + i + j + ", " + + "got " + e); + } + }); + continue; + } + + for (var k = 0; k < 2; k++) + { + if (k === 2) + { + chars.forEach(function(v) + { + try + { + eval('0' + v + i + j + k); + throw "didn't throw"; + } + catch (e) + { + assertEq(e instanceof SyntaxError, true, + "no syntax error evaluating 0" + v + i + j + k + ", " + + "got " + e); + } + }); + continue; + } + + chars.forEach(function(v) + { + assertEq(eval('0' + v + i + j + k), i * 4 + j * 2 + k); + }); + } + } +} + +chars.forEach(function(v) +{ + try + { + } + catch (e) + { + assertEq(e instanceof SyntaxError, true, + "no syntax error evaluating 0" + v + ", got " + e); + } +}); + +// Off-by-one check: '/' immediately precedes '0'. +assertEq(0b110/1, 6); +assertEq(0B10110/1, 22); + +function strict() +{ + "use strict"; + return 0b11010101; +} +assertEq(strict(), 128 + 64 + 16 + 4 + 1); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Expressions/browser.js b/js/src/tests/ecma_6/Expressions/browser.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/browser.js diff --git a/js/src/tests/ecma_6/Expressions/computed-property-side-effects.js b/js/src/tests/ecma_6/Expressions/computed-property-side-effects.js new file mode 100644 index 000000000..54dec7416 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/computed-property-side-effects.js @@ -0,0 +1,35 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1199695; +var summary = + "Computed property names must be considered as always effectful even when " + + "the name expression isn't effectful, because calling ToPropertyKey on " + + "some non-effectful expressions has user-modifiable behavior"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +RegExp.prototype.toString = () => { throw 42; }; +assertThrowsValue(function() { + ({ [/regex/]: 0 }); // ToPropertyKey(/regex/) throws 42 +}, 42); + +function Q() { + ({ [new.target]: 0 }); // new.target will be Q, ToPropertyKey(Q) throws 17 +} +Q.toString = () => { throw 17; }; +assertThrowsValue(function() { + new Q; +}, 17); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Expressions/delete-constant-folded-and-or.js b/js/src/tests/ecma_6/Expressions/delete-constant-folded-and-or.js new file mode 100644 index 000000000..9576413a6 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/delete-constant-folded-and-or.js @@ -0,0 +1,41 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1183400; +var summary = + "Deletion of a && or || expression that constant-folds to a name must not " + + "attempt to delete the name"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +Object.defineProperty(this, "nonconfigurable", { value: 42 }); +assertEq(nonconfigurable, 42); + +assertEq(delete nonconfigurable, false); +assertEq(delete (true && nonconfigurable), true); + +function nested() +{ + assertEq(delete nonconfigurable, false); + assertEq(delete (true && nonconfigurable), true); +} +nested(); + +function nestedStrict() +{ + "use strict"; + assertEq(delete (true && nonconfigurable), true); +} +nestedStrict(); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Expressions/delete-name-parenthesized-early-error-strict-mode.js b/js/src/tests/ecma_6/Expressions/delete-name-parenthesized-early-error-strict-mode.js new file mode 100644 index 000000000..d28afb665 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/delete-name-parenthesized-early-error-strict-mode.js @@ -0,0 +1,76 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1111101; +var summary = + "delete (foo), delete ((foo)), and so on are strict mode early errors"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +function checkSyntaxError(code) +{ + function helper(maker) + { + var earlyError = false; + try + { + var f = maker(code); + + var error = "no early error, created a function with code <" + code + ">"; + try + { + f(); + error += ", and the function can be called without error"; + } + catch (e) + { + error +=", and calling the function throws " + e; + } + + throw new Error(error); + } + catch (e) + { + assertEq(e instanceof SyntaxError, true, + "expected syntax error, got " + e); + } + } + + helper(Function); + helper(eval); +} + +checkSyntaxError("function f() { 'use strict'; delete escape; } f();"); +checkSyntaxError("function f() { 'use strict'; delete escape; }"); +checkSyntaxError("function f() { 'use strict'; delete (escape); } f();"); +checkSyntaxError("function f() { 'use strict'; delete (escape); }"); +checkSyntaxError("function f() { 'use strict'; delete ((escape)); } f();"); +checkSyntaxError("function f() { 'use strict'; delete ((escape)); }"); + +// Meanwhile, non-strict all of these should work + +function checkFine(code) +{ + Function(code); + (1, eval)(code); // indirect, to be consistent w/above +} + +checkFine("function f() { delete escape; } f();"); +checkFine("function f() { delete escape; }"); +checkFine("function f() { delete (escape); } f();"); +checkFine("function f() { delete (escape); }"); +checkFine("function f() { delete ((escape)); } f();"); +checkFine("function f() { delete ((escape)); }"); + + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Expressions/destructuring-array-default-call.js b/js/src/tests/ecma_6/Expressions/destructuring-array-default-call.js new file mode 100644 index 000000000..a3a362205 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/destructuring-array-default-call.js @@ -0,0 +1,10 @@ +var BUGNUMBER = 1184922; +var summary = "Array destructuring with various default values in various context - call/new expression"; + +print(BUGNUMBER + ": " + summary); + +testDestructuringArrayDefault("func()"); +testDestructuringArrayDefault("new func()"); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Expressions/destructuring-array-default-class.js b/js/src/tests/ecma_6/Expressions/destructuring-array-default-class.js new file mode 100644 index 000000000..808308928 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/destructuring-array-default-class.js @@ -0,0 +1,72 @@ +var BUGNUMBER = 1184922; +var summary = "Array destructuring with various default values in various context - class expression and super/new.target"; + +print(BUGNUMBER + ": " + summary); + +testDestructuringArrayDefault(`class E { + constructor() {} + method() {} + get v() {} + set v(_) {} + static method() {} + static get v() {} + static set v(_) {} +}`); + +testDestructuringArrayDefault(`class E extends C { + constructor() {} + method() {} + get v() {} + set v(_) {} + static method() {} + static get v() {} + static set v(_) {} +}`); + +var opt = { + no_plain: true, + no_func: true, + no_func_arg: true, + no_gen: true, + no_gen_arg: true, + no_ctor: true, + no_method: true, + no_pre_super: true, + no_comp: true, + + no_derived_ctor: false, +}; +testDestructuringArrayDefault("super()", opt); + +opt = { + no_plain: true, + no_func: true, + no_func_arg: true, + no_gen: true, + no_gen_arg: true, + no_ctor: true, + no_comp: true, + + no_derived_ctor: false, + no_method: false, + no_pre_super: false, +}; +testDestructuringArrayDefault("super.foo()", opt); + +opt = { + no_plain: true, + + no_func: false, + no_func_arg: false, + no_gen: false, + no_gen_arg: false, + no_ctor: false, + no_derived_ctor: false, + no_method: false, + no_pre_super: false, + no_comp: false, +}; +testDestructuringArrayDefault("new.target", opt); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Expressions/destructuring-array-default-function-nested.js b/js/src/tests/ecma_6/Expressions/destructuring-array-default-function-nested.js new file mode 100644 index 000000000..99260b989 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/destructuring-array-default-function-nested.js @@ -0,0 +1,11 @@ +var BUGNUMBER = 1184922; +var summary = "Array destructuring with various default values in various context - function expression with nested objects"; + +print(BUGNUMBER + ": " + summary); + +testDestructuringArrayDefault("function f() { return { f() {}, *g() {}, r: /a/ }; }"); +testDestructuringArrayDefault("function* g() { return { f() {}, *g() {}, r: /b/ }; }"); +testDestructuringArrayDefault("() => { return { f() {}, *g() {}, r: /c/ }; }"); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Expressions/destructuring-array-default-function.js b/js/src/tests/ecma_6/Expressions/destructuring-array-default-function.js new file mode 100644 index 000000000..5d2ffef18 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/destructuring-array-default-function.js @@ -0,0 +1,11 @@ +var BUGNUMBER = 1184922; +var summary = "Array destructuring with various default values in various context - function expression"; + +print(BUGNUMBER + ": " + summary); + +testDestructuringArrayDefault("function f() {}"); +testDestructuringArrayDefault("function* g() {}"); +testDestructuringArrayDefault("() => {}"); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Expressions/destructuring-array-default-simple.js b/js/src/tests/ecma_6/Expressions/destructuring-array-default-simple.js new file mode 100644 index 000000000..50c6c37f3 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/destructuring-array-default-simple.js @@ -0,0 +1,16 @@ +var BUGNUMBER = 1184922; +var summary = "Array destructuring with various default values in various context - simple literal"; + +print(BUGNUMBER + ": " + summary); + +testDestructuringArrayDefault("'foo'"); +testDestructuringArrayDefault("`foo`"); +testDestructuringArrayDefault("func`foo`"); + +testDestructuringArrayDefault("/foo/"); + +testDestructuringArrayDefault("{}"); +testDestructuringArrayDefault("[]"); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Expressions/destructuring-array-default-yield.js b/js/src/tests/ecma_6/Expressions/destructuring-array-default-yield.js new file mode 100644 index 000000000..57ff9e947 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/destructuring-array-default-yield.js @@ -0,0 +1,22 @@ +var BUGNUMBER = 1184922; +var summary = "Array destructuring with various default values in various context - yield expression"; + +print(BUGNUMBER + ": " + summary); + +var opt = { + no_plain: true, + no_func: true, + no_func_arg: true, + no_gen_arg: true, + no_ctor: true, + no_derived_ctor: true, + no_method: true, + no_pre_super: true, + no_comp: true, + + no_gen: false, +}; +testDestructuringArrayDefault("yield 1", opt); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Expressions/destructuring-array-done.js b/js/src/tests/ecma_6/Expressions/destructuring-array-done.js new file mode 100644 index 000000000..f2c7e9410 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/destructuring-array-done.js @@ -0,0 +1,319 @@ +var BUGNUMBER = 1184922; +var summary = "iterator.next() should not be called when after iterator completes"; + +print(BUGNUMBER + ": " + summary); + +var log; +function reset() { + log = ""; +} +var obj = new Proxy({}, { + set(that, name, value) { + var v; + if (value instanceof Function || value instanceof RegExp) + v = value.toString(); + else + v = JSON.stringify(value); + log += "set:" + name + "=" + v + ","; + } +}); +function createIterable(n) { + return { + i: 0, + [Symbol.iterator]() { + return this; + }, + next() { + log += "next,"; + this.i++; + if (this.i <= n) + return {value: this.i, done: false}; + return {value: 0, done: true}; + } + }; +} + +// Simple pattern. + +reset(); +[obj.a, obj.b, obj.c] = createIterable(0); +assertEq(log, + "next," + + "set:a=undefined," + + "set:b=undefined," + + "set:c=undefined,"); + +reset(); +[obj.a, obj.b, obj.c] = createIterable(1); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "set:b=undefined," + + "set:c=undefined,"); + +reset(); +[obj.a, obj.b, obj.c] = createIterable(2); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "set:b=2," + + "next," + + "set:c=undefined,"); + +reset(); +[obj.a, obj.b, obj.c] = createIterable(3); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "set:b=2," + + "next," + + "set:c=3,"); + +// Elision. + +reset(); +[obj.a, , obj.b, , , obj.c, ,] = createIterable(0); +assertEq(log, + "next," + + "set:a=undefined," + + "set:b=undefined," + + "set:c=undefined,"); + +reset(); +[obj.a, , obj.b, , , obj.c, ,] = createIterable(1); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "set:b=undefined," + + "set:c=undefined,"); + +reset(); +[obj.a, , obj.b, , , obj.c, ,] = createIterable(2); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "next," + + "set:b=undefined," + + "set:c=undefined,"); + +reset(); +[obj.a, , obj.b, , , obj.c, ,] = createIterable(3); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "next," + + "set:b=3," + + "next," + + "set:c=undefined,"); + +reset(); +[obj.a, , obj.b, , , obj.c, ,] = createIterable(4); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "next," + + "set:b=3," + + "next," + + "next," + + "set:c=undefined,"); + +reset(); +[obj.a, , obj.b, , , obj.c, ,] = createIterable(5); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "next," + + "set:b=3," + + "next," + + "next," + + "next," + + "set:c=undefined,"); + +reset(); +[obj.a, , obj.b, , , obj.c, ,] = createIterable(6); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "next," + + "set:b=3," + + "next," + + "next," + + "next," + + "set:c=6," + + "next,"); + +reset(); +[obj.a, , obj.b, , , obj.c, ,] = createIterable(7); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "next," + + "set:b=3," + + "next," + + "next," + + "next," + + "set:c=6," + + "next,"); + +// Rest. + +reset(); +[...obj.r] = createIterable(0); +assertEq(log, + "next," + + "set:r=[],"); + +reset(); +[...obj.r] = createIterable(1); +assertEq(log, + "next," + + "next," + + "set:r=[1],"); + +reset(); +[obj.a, ...obj.r] = createIterable(0); +assertEq(log, + "next," + + "set:a=undefined," + + "set:r=[],"); + +reset(); +[obj.a, ...obj.r] = createIterable(1); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "set:r=[],"); + +reset(); +[obj.a, ...obj.r] = createIterable(2); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "next," + + "set:r=[2],"); + +reset(); +[obj.a, obj.b, ...obj.r] = createIterable(0); +assertEq(log, + "next," + + "set:a=undefined," + + "set:b=undefined," + + "set:r=[],"); + +reset(); +[obj.a, obj.b, ...obj.r] = createIterable(1); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "set:b=undefined," + + "set:r=[],"); + +reset(); +[obj.a, obj.b, ...obj.r] = createIterable(2); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "set:b=2," + + "next," + + "set:r=[],"); + +reset(); +[obj.a, obj.b, ...obj.r] = createIterable(3); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "set:b=2," + + "next," + + "next," + + "set:r=[3],"); + +// Rest and elision. + +reset(); +[, ...obj.r] = createIterable(0); +assertEq(log, + "next," + + "set:r=[],"); + +reset(); +[, ...obj.r] = createIterable(1); +assertEq(log, + "next," + + "next," + + "set:r=[],"); + +reset(); +[, ...obj.r] = createIterable(2); +assertEq(log, + "next," + + "next," + + "next," + + "set:r=[2],"); + +reset(); +[obj.a, obj.b, , ...obj.r] = createIterable(0); +assertEq(log, + "next," + + "set:a=undefined," + + "set:b=undefined," + + "set:r=[],"); + +reset(); +[obj.a, obj.b, , ...obj.r] = createIterable(1); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "set:b=undefined," + + "set:r=[],"); + +reset(); +[obj.a, obj.b, , ...obj.r] = createIterable(2); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "set:b=2," + + "next," + + "set:r=[],"); + +reset(); +[obj.a, obj.b, , ...obj.r] = createIterable(3); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "set:b=2," + + "next," + + "next," + + "set:r=[],"); + +reset(); +[obj.a, obj.b, , ...obj.r] = createIterable(4); +assertEq(log, + "next," + + "set:a=1," + + "next," + + "set:b=2," + + "next," + + "next," + + "next," + + "set:r=[4],"); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Expressions/destructuring-array-lexical.js b/js/src/tests/ecma_6/Expressions/destructuring-array-lexical.js new file mode 100644 index 000000000..133858a09 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/destructuring-array-lexical.js @@ -0,0 +1,12 @@ +var BUGNUMBER = 1184922; +var summary = "Array destructuring with accessing uninitialized lexical binding."; + +print(BUGNUMBER + ": " + summary); + +assertThrowsInstanceOf(() => { let y = [y] = []; }, + ReferenceError); +assertThrowsInstanceOf(() => { let y = [y] = [,]; }, + ReferenceError); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Expressions/destructuring-pattern-parenthesized.js b/js/src/tests/ecma_6/Expressions/destructuring-pattern-parenthesized.js new file mode 100644 index 000000000..ca495c886 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/destructuring-pattern-parenthesized.js @@ -0,0 +1,140 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1146136; +var summary = + 'Parenthesized "destructuring patterns" are not usable as destructuring ' + + 'patterns'; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +// Don't pollute the top-level script with eval references. +var savedEval = this[String.fromCharCode(101, 118, 97, 108)]; + +function checkError(code, nonstrictErr, strictErr) +{ + function helper(exec, prefix, err) + { + var fullCode = prefix + code; + try + { + var f = exec(fullCode); + + var error = + "no early error, parsed code <" + fullCode + "> using " + exec.name; + if (typeof f === "function") + { + try + { + f(); + error += ", and the function can be called without error"; + } + catch (e) + { + error +=", and calling the function throws " + e; + } + } + + throw new Error(error); + } + catch (e) + { + assertEq(e instanceof err, true, + "expected " + err.name + ", got " + e + " " + + "for code <" + fullCode + "> when parsed using " + exec.name); + } + } + + helper(Function, "", nonstrictErr); + helper(Function, "'use strict'; ", strictErr); + helper(savedEval, "", nonstrictErr); + helper(savedEval, "'use strict'; ", strictErr); +} + +// Parenthesized destructuring patterns don't trigger grammar refinement, so we +// get the currently-usual ReferenceError for an invalid assignment target, per +// 12.14.1 second bullet. +checkError("var a, b; ([a, b]) = [1, 2];", ReferenceError, ReferenceError); +checkError("var a, b; ({a, b}) = { a: 1, b: 2 };", ReferenceError, ReferenceError); + +// *Nested* parenthesized destructuring patterns, on the other hand, do trigger +// grammar refinement. But subtargets in a destructuring pattern must be +// either object/array literals that match the destructuring pattern refinement +// *or* valid simple assignment targets (or such things with a default, with the +// entire subtarget unparenthesized: |a = 3| is fine, |(a) = 3| is fine for +// destructuring in an expression, |(a = 3)| is forbidden). Parenthesized +// object/array patterns are neither. And so 12.14.5.1 third bullet requires an +// early SyntaxError. +checkError("var a, b; ({ a: ({ b: b }) } = { a: { b: 42 } });", SyntaxError, SyntaxError); +checkError("var a, b; ({ a: { b: (b = 7) } } = { a: {} });", SyntaxError, SyntaxError); +checkError("var a, b; ({ a: ([b]) } = { a: [42] });", SyntaxError, SyntaxError); +checkError("var a, b; [(a = 5)] = [1];", SyntaxError, SyntaxError); +checkError("var a, b; ({ a: (b = 7)} = { b: 1 });", SyntaxError, SyntaxError); + +Function("var a, b; [(a), b] = [1, 2];")(); +Function("var a, b; [(a) = 5, b] = [1, 2];")(); +Function("var a, b; [(arguments), b] = [1, 2];")(); +Function("var a, b; [(arguments) = 5, b] = [1, 2];")(); +Function("var a, b; [(eval), b] = [1, 2];")(); +Function("var a, b; [(eval) = 5, b] = [1, 2];")(); + +var repair = {}, demolition = {}; + +Function("var a, b; [(repair.man), b] = [1, 2];")(); +Function("var a, b; [(demolition['man']) = 'motel', b] = [1, 2];")(); +Function("var a, b; [(demolition['man' + {}]) = 'motel', b] = [1, 2];")(); // evade constant-folding + +function classesEnabled() +{ + try + { + new Function("class B { constructor() { } }; class D extends B { constructor() { super(); } }"); + return true; + } + catch (e if e instanceof SyntaxError) + { + return false; + } +} + +if (classesEnabled()) +{ + Function("var a, b; var obj = { x() { [(super.man), b] = [1, 2]; } };")(); + Function("var a, b; var obj = { x() { [(super[8]) = 'motel', b] = [1, 2]; } };")(); + Function("var a, b; var obj = { x() { [(super[8 + {}]) = 'motel', b] = [1, 2]; } };")(); // evade constant-folding +} + +// As noted above, when the assignment element has an initializer, the +// assignment element must not be parenthesized. +checkError("var a, b; [(repair.man = 17)] = [1];", SyntaxError, SyntaxError); +checkError("var a, b; [(demolition['man'] = 'motel')] = [1, 2];", SyntaxError, SyntaxError); +checkError("var a, b; [(demolition['man' + {}] = 'motel')] = [1];", SyntaxError, SyntaxError); // evade constant-folding +if (classesEnabled()) +{ + checkError("var a, b; var obj = { x() { [(super.man = 5)] = [1]; } };", SyntaxError, SyntaxError); + checkError("var a, b; var obj = { x() { [(super[8] = 'motel')] = [1]; } };", SyntaxError, SyntaxError); + checkError("var a, b; var obj = { x() { [(super[8 + {}] = 'motel')] = [1]; } };", SyntaxError, SyntaxError); // evade constant-folding +} + +// In strict mode, assignment to funcall *immediately* triggers ReferenceError +// before we can recognize this doesn't even match the destructuring grammar to +// begin with. Bleh. :-( Probably they should all be made SyntaxError in the +// specs; see <https://bugs.ecmascript.org/show_bug.cgi?id=4375>. +checkError("var a, b; [f() = 'ohai', b] = [1, 2];", SyntaxError, ReferenceError); +checkError("var a, b; [(f()) = 'kthxbai', b] = [1, 2];", SyntaxError, ReferenceError); + +Function("var a, b; ({ a: (a), b} = { a: 1, b: 2 });")(); +Function("var a, b; ({ a: (a) = 5, b} = { a: 1, b: 2 });")(); + + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Expressions/object-literal-__proto__.js b/js/src/tests/ecma_6/Expressions/object-literal-__proto__.js new file mode 100644 index 000000000..531ef7fc5 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/object-literal-__proto__.js @@ -0,0 +1,267 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1061853; +var summary = + "__proto__ in object literals in non-__proto__:v contexts doesn't modify " + + "[[Prototype]]"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +function hasOwn(obj, prop) +{ + return Object.getOwnPropertyDescriptor(obj, prop) !== undefined; +} + +var objectStart = "{ "; +var objectEnd = " }"; + +var members = + { + nullProto: "__proto__: null", + functionProtoProto: "__proto__: Function.prototype", + computedNull: "['__proto__']: null", + method: "__proto__() {}", + computedMethod: "['__proto__']() {}", + generatorMethod: "*__proto__() {}", + computedGenerator: "*['__proto__']() {}", + shorthand: "__proto__", + getter: "get __proto__() { return 42; }", + getterComputed: "get ['__proto__']() { return 42; }", + setter: "set __proto__(v) { }", + setterComputed: "set ['__proto__'](v) { }", + }; + +function isProtoMutation(key) +{ + return key === "nullProto" || key === "functionProtoProto"; +} + +function isGetter(key) +{ + return key === "getter" || key === "getterComputed"; +} + +function isSetter(key) +{ + return key === "setter" || key === "setterComputed"; +} + +function isData(key) +{ + return !isProtoMutation(key) && !isGetter(key) && !isSetter(key); +} + +var __proto__ = "string value"; + +function typeOfProto(key) +{ + if (key === "computedNull") + return "object"; + if (key === "method" || key === "computedMethod" || + key === "computedGenerator" || key === "generatorMethod") + { + return "function"; + } + if (key === "getter" || key === "getterComputed") + return "number"; + assertEq(key, "shorthand", "bug in test!"); + return "string"; +} + +for (var first in members) +{ + var fcode = "return " + objectStart + members[first] + objectEnd; + var f = Function(fcode); + var oneProp = f(); + + if (first === "nullProto") + { + assertEq(Object.getPrototypeOf(oneProp), null); + assertEq(hasOwn(oneProp, "__proto__"), false); + } + else if (first === "functionProtoProto") + { + assertEq(Object.getPrototypeOf(oneProp), Function.prototype); + assertEq(hasOwn(oneProp, "__proto__"), false); + } + else if (isSetter(first)) + { + assertEq(Object.getPrototypeOf(oneProp), Object.prototype); + assertEq(hasOwn(oneProp, "__proto__"), true); + assertEq(typeof Object.getOwnPropertyDescriptor(oneProp, "__proto__").set, + "function"); + } + else + { + assertEq(Object.getPrototypeOf(oneProp), Object.prototype); + assertEq(hasOwn(oneProp, "__proto__"), true); + assertEq(typeof oneProp.__proto__, typeOfProto(first)); + } + + for (var second in members) + { + try + { + var gcode = "return " + objectStart + members[first] + ", " + + members[second] + objectEnd; + var g = Function(gcode); + } + catch (e) + { + assertEq(e instanceof SyntaxError, true, + "__proto__ member conflicts should be syntax errors, got " + e); + assertEq(+(first === "nullProto" || first === "functionProtoProto") + + +(second === "nullProto" || second === "functionProtoProto") > 1, + true, + "unexpected conflict between members: " + first + ", " + second); + continue; + } + + var twoProps = g(); + + if (first === "nullProto" || second === "nullProto") + assertEq(Object.getPrototypeOf(twoProps), null); + else if (first === "functionProtoProto" || second === "functionProtoProto") + assertEq(Object.getPrototypeOf(twoProps), Function.prototype); + else + assertEq(Object.getPrototypeOf(twoProps), Object.prototype); + + if (isSetter(second)) + { + assertEq(hasOwn(twoProps, "__proto__"), true); + assertEq(typeof Object.getOwnPropertyDescriptor(twoProps, "__proto__").get, + isGetter(first) ? "function" : "undefined"); + } + else if (!isProtoMutation(second)) + { + assertEq(hasOwn(twoProps, "__proto__"), true); + assertEq(typeof twoProps.__proto__, typeOfProto(second)); + if (isGetter(second)) + { + assertEq(typeof Object.getOwnPropertyDescriptor(twoProps, "__proto__").get, + "function"); + assertEq(typeof Object.getOwnPropertyDescriptor(twoProps, "__proto__").set, + isSetter(first) ? "function" : "undefined"); + } + } + else if (isSetter(first)) + { + assertEq(hasOwn(twoProps, "__proto__"), true); + assertEq(typeof Object.getOwnPropertyDescriptor(twoProps, "__proto__").set, + "function"); + assertEq(typeof Object.getOwnPropertyDescriptor(twoProps, "__proto__").get, + "undefined"); + } + else if (!isProtoMutation(first)) + { + assertEq(hasOwn(twoProps, "__proto__"), true); + assertEq(typeof twoProps.__proto__, typeOfProto(first)); + } + else + { + assertEq(true, false, "should be unreachable: " + first + ", " + second); + } + + for (var third in members) + { + try + { + var hcode = "return " + objectStart + members[first] + ", " + + members[second] + ", " + + members[third] + objectEnd; + var h = Function(hcode); + } + catch (e) + { + assertEq(e instanceof SyntaxError, true, + "__proto__ member conflicts should be syntax errors, got " + e); + assertEq(+(first === "nullProto" || first === "functionProtoProto") + + +(second === "nullProto" || second === "functionProtoProto") + + +(third === "nullProto" || third === "functionProtoProto") > 1, + true, + "unexpected conflict among members: " + + first + ", " + second + ", " + third); + continue; + } + + var threeProps = h(); + + if (first === "nullProto" || second === "nullProto" || + third === "nullProto") + { + assertEq(Object.getPrototypeOf(threeProps), null); + } + else if (first === "functionProtoProto" || + second === "functionProtoProto" || + third === "functionProtoProto") + { + assertEq(Object.getPrototypeOf(threeProps), Function.prototype); + } + else + { + assertEq(Object.getPrototypeOf(threeProps), Object.prototype); + } + + if (isSetter(third)) + { + assertEq(hasOwn(threeProps, "__proto__"), true); + assertEq(typeof Object.getOwnPropertyDescriptor(threeProps, "__proto__").get, + isGetter(second) || (!isData(second) && isGetter(first)) + ? "function" + : "undefined", + "\n" + hcode); + } + else if (!isProtoMutation(third)) + { + assertEq(hasOwn(threeProps, "__proto__"), true); + assertEq(typeof threeProps.__proto__, typeOfProto(third), first + ", " + second + ", " + third); + if (isGetter(third)) + { + var desc = Object.getOwnPropertyDescriptor(threeProps, "__proto__"); + assertEq(typeof desc.get, "function"); + assertEq(typeof desc.set, + isSetter(second) || (!isData(second) && isSetter(first)) + ? "function" + : "undefined"); + } + } + else if (isSetter(second)) + { + assertEq(hasOwn(threeProps, "__proto__"), true); + assertEq(typeof Object.getOwnPropertyDescriptor(threeProps, "__proto__").get, + isGetter(first) ? "function" : "undefined"); + } + else if (!isProtoMutation(second)) + { + assertEq(hasOwn(threeProps, "__proto__"), true); + assertEq(typeof threeProps.__proto__, typeOfProto(second)); + if (isGetter(second)) + { + var desc = Object.getOwnPropertyDescriptor(threeProps, "__proto__"); + assertEq(typeof desc.get, "function"); + assertEq(typeof desc.set, + isSetter(first) ? "function" : "undefined"); + } + } + else + { + assertEq(true, false, + "should be unreachable: " + + first + ", " + second + ", " + third); + } + } + } +} + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Expressions/object-literal-computed-property-evaluation.js b/js/src/tests/ecma_6/Expressions/object-literal-computed-property-evaluation.js new file mode 100644 index 000000000..d26783d35 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/object-literal-computed-property-evaluation.js @@ -0,0 +1,38 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1199546; +var summary = + "Convert computed property name expressions to property key before " + + "evaluating the property's value"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var s = "foo"; +var convertsToS = { toString() { return s; } }; + +var o = { + [convertsToS]: // after ToPropertyKey becomes "foo" + (function() { + s = 'bar'; + return 'abc'; // so we have "foo": "bar" for the first property + })(), + + [convertsToS]: // |s| was set above to "bar", so after ToPropertyKey, "bar" + 'efg' // so we have "bar": "efg" for the second property +}; + +assertEq(o.foo, "abc"); +assertEq(o.bar, "efg"); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Expressions/octal-literals.js b/js/src/tests/ecma_6/Expressions/octal-literals.js new file mode 100644 index 000000000..abeef8736 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/octal-literals.js @@ -0,0 +1,103 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 894026; +var summary = "Implement ES6 octal literals"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var chars = ['o', 'O']; + +for (var i = 0; i < 8; i++) +{ + if (i === 8) + { + chars.forEach(function(v) + { + try + { + eval('0' + v + i); + throw "didn't throw"; + } + catch (e) + { + assertEq(e instanceof SyntaxError, true, + "no syntax error evaluating 0" + v + i + ", " + + "got " + e); + } + }); + continue; + } + + for (var j = 0; j < 8; j++) + { + if (j === 8) + { + chars.forEach(function(v) + { + try + { + eval('0' + v + i + j); + throw "didn't throw"; + } + catch (e) + { + assertEq(e instanceof SyntaxError, true, + "no syntax error evaluating 0" + v + i + j + ", " + + "got " + e); + } + }); + continue; + } + + for (var k = 0; k < 8; k++) + { + if (k === 8) + { + chars.forEach(function(v) + { + try + { + eval('0' + v + i + j + k); + throw "didn't throw"; + } + catch (e) + { + assertEq(e instanceof SyntaxError, true, + "no syntax error evaluating 0" + v + i + j + k + ", " + + "got " + e); + } + }); + continue; + } + + chars.forEach(function(v) + { + assertEq(eval('0' + v + i + j + k), i * 64 + j * 8 + k); + }); + } + } +} + +// Off-by-one check: '/' immediately precedes '0'. +assertEq(0o110/2, 36); +assertEq(0O644/2, 210); + +function strict() +{ + "use strict"; + return 0o755; +} +assertEq(strict(), 7 * 64 + 5 * 8 + 5); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Expressions/shell.js b/js/src/tests/ecma_6/Expressions/shell.js new file mode 100644 index 000000000..0a0a24656 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/shell.js @@ -0,0 +1,186 @@ +(function(global) { + function func() { + } + class C { + foo() { + } + static foo() { + } + } + + function test_one(pattern, val, opt) { + var stmts = []; + var i = 0; + var c; + + stmts.push(`var ${pattern} = ${val};`); + if (!opt.no_comp) { + stmts.push(`[for (x of [1]) ${pattern} = ${val}];`); + stmts.push(`[...(for (x of [1]) ${pattern} = ${val})];`); + } + + for (var stmt of stmts) { + if (!opt.no_plain) { + eval(` +${stmt} +`); + } + + if (!opt.no_func) { + eval(` +function f${i}() { + ${stmt} +} +f${i}(); +`); + i++; + + eval(` +var f${i} = function foo() { + ${stmt} +}; +f${i}(); +`); + i++; + + eval(` +var f${i} = () => { + ${stmt} +}; +f${i}(); +`); + i++; + } + + if (!opt.no_gen) { + eval(` +function* g${i}() { + ${stmt} +} +[...g${i}()]; +`); + i++; + + eval(` +var g${i} = function* foo() { + ${stmt} +}; +[...g${i}()]; +`); + i++; + } + + if (!opt.no_ctor) { + eval(` +class D${i} { + constructor() { + ${stmt} + } +} +new D${i}(); +`); + i++; + } + + if (!opt.no_derived_ctor) { + if (opt.no_pre_super) { + eval(` +class D${i} extends C { + constructor() { + ${stmt} + try { super(); } catch (e) {} + } +} +new D${i}(); +`); + i++; + } else { + eval(` +class D${i} extends C { + constructor() { + super(); + ${stmt} + } +} +new D${i}(); +`); + i++; + } + } + + if (!opt.no_method) { + eval(` +class D${i} extends C { + method() { + ${stmt} + } + static staticMethod() { + ${stmt} + } +} +new D${i}().method(); +D${i}.staticMethod(); +`); + i++; + } + } + + if (!opt.no_func_arg) { + eval(` +function f${i}(${pattern}) {} +f${i}(${val}); +`); + i++; + + eval(` +var f${i} = function foo(${pattern}) {}; +f${i}(${val}); +`); + i++; + + eval(` +var f${i} = (${pattern}) => {}; +f${i}(${val}); +`); + i++; + } + + if (!opt.no_gen_arg) { + eval(` +function* g${i}(${pattern}) {} +[...g${i}(${val})]; +`); + i++; + + eval(` +var g${i} = function* foo(${pattern}) {}; +[...g${i}(${val})]; +`); + i++; + } + } + + function test(expr, opt={}) { + var pattern = `[a=${expr}, ...c]`; + test_one(pattern, "[]", opt); + test_one(pattern, "[1]", opt); + + pattern = `[,a=${expr}]`; + test_one(pattern, "[]", opt); + test_one(pattern, "[1]", opt); + test_one(pattern, "[1, 2]", opt); + + pattern = `[{x: [a=${expr}]}]`; + test_one(pattern, "[{x: [1]}]", opt); + + pattern = `[x=[a=${expr}]=[]]`; + test_one(pattern, "[]", opt); + test_one(pattern, "[1]", opt); + + pattern = `[x=[a=${expr}]=[1]]`; + test_one(pattern, "[]", opt); + test_one(pattern, "[1]", opt); + } + + global.testDestructuringArrayDefault = test; +})(this); diff --git a/js/src/tests/ecma_6/Expressions/tagged-template-constant-folding.js b/js/src/tests/ecma_6/Expressions/tagged-template-constant-folding.js new file mode 100644 index 000000000..6041cbc16 --- /dev/null +++ b/js/src/tests/ecma_6/Expressions/tagged-template-constant-folding.js @@ -0,0 +1,28 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1182373; +var summary = + "Don't let constant-folding in the MemberExpression part of a tagged " + + "template cause an incorrect |this| be passed to the callee"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var prop = "global"; + +var obj = { prop: "obj", f: function() { return this.prop; } }; + +assertEq(obj.f``, "obj"); +assertEq((true ? obj.f : null)``, "global"); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); |