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=nigelb,facebookbustage
authorJeff Walden <jwalden@mit.edu>
Tue, 19 Aug 2014 22:10:20 -0700
changeset 200533 ffdd1a39810547f61fe551cea1c78d20c5722b25
parent 200493 83ced53b42981c4a233dff95f0a1e2210f3d3f5c
child 200534 1ddfd9afba40866d9755b495d9d7d456748ee595
push id47930
push useremorley@mozilla.com
push dateWed, 20 Aug 2014 14:19:23 +0000
treeherdermozilla-inbound@38769be77c60 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmjrosenb, nigelb, facebookbustage
bugs1054426
milestone34.0a1
first release with
nightly linux32
ffdd1a398105 / 34.0a1 / 20140820030202 / files
nightly linux64
ffdd1a398105 / 34.0a1 / 20140820030202 / files
nightly mac
ffdd1a398105 / 34.0a1 / 20140820030202 / files
nightly win32
ffdd1a398105 / 34.0a1 / 20140820030202 / files
nightly win64
ffdd1a398105 / 34.0a1 / 20140820030202 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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=nigelb,facebookbustage
js/src/builtin/Object.js
js/src/tests/ecma_6/Object/assign.js
--- 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();