Bug 1054426 - Make Object.assign skip null/undefined source arguments if any are passed, to match not-yet-drafted semantics agreed upon in TC39 meeting minutes. Also fixes Facebook bustage. r=mjrosenb over IRC
--- a/js/src/builtin/Object.js
+++ b/js/src/builtin/Object.js
@@ -9,18 +9,24 @@ function ObjectStaticAssign(target, firs
// Step 3.
if (arguments.length < 2)
return to;
// Step 4.
var i = 1;
do {
- // Step 5.a-b.
+ // Step 5.a-b, plus an unspecified flourish to skip null/undefined, so
+ // any site depending on agreed-upon (but not-yet-drafted) semantics
+ // from TC39 meeting minutes will work. (Yes, implausibly, such a site
+ // exists. See bug 1054426.)
var nextSource = arguments[i];
+ if (nextSource === null || nextSource === undefined)
+ continue;
+
var from = ToObject(nextSource);
// Step 5.c-d.
var keysArray = OwnPropertyKeys(from);
// Steps 5.e-f.
var len = keysArray.length;
@@ -53,15 +59,14 @@ function ObjectStaticAssign(target, firs
// Step 5.j.vi.
nextIndex++;
}
// Step 5.k.
if (pendingException !== MISSING)
throw pendingException;
- i++;
- } while (i < arguments.length);
+ } while (++i < arguments.length);
// Step 6.
return to;
}
--- a/js/src/tests/ecma_6/Object/assign.js
+++ b/js/src/tests/ecma_6/Object/assign.js
@@ -33,22 +33,37 @@ function basicSymbols() {
var aSymbol = Symbol("aSymbol");
b[aSymbol] = 22;
Object.assign(a, b);
assertEq(a.bProp, 7);
assertEq(a[aSymbol], 22);
}
basicSymbols();
-// Calls ToObject() for target and source
+// Calls ToObject() for target, skips null/undefined sources, uses
+// ToObject(source) otherwise.
function testToObject() {
assertThrowsInstanceOf(() => Object.assign(null, null), TypeError);
assertThrowsInstanceOf(() => Object.assign(), TypeError);
assertThrowsInstanceOf(() => Object.assign(null, {}), TypeError);
- assertThrowsInstanceOf(() => Object.assign({}, null), TypeError);
+ assertEq(Object.assign({}, null) instanceof Object, true);
+ assertEq(Object.assign({}, undefined) instanceof Object, true);
+
+ // Technically an embedding could have this as extension acting differently
+ // from ours, so a feature-test is inadequate. We can move this subtest
+ // into extensions/ if that ever matters.
+ if (typeof objectEmulatingUndefined === "function") {
+ var falsyObject = objectEmulatingUndefined();
+ falsyObject.foo = 7;
+
+ var obj = Object.assign({}, falsyObject);
+ assertEq(obj instanceof Object, true);
+ assertEq(obj.foo, 7);
+ }
+
assertEq(Object.assign(true, {}) instanceof Boolean, true);
assertEq(Object.assign(1, {}) instanceof Number, true);
assertEq(Object.assign("string", {}) instanceof String, true);
var o = {};
assertEq(Object.assign(o, {}), o);
}
testToObject();