Skip to content

Commit

Permalink
Fix Reflect.construct polyfill to handle Chakra bug chakra-core/Chakr…
Browse files Browse the repository at this point in the history
…aCore#3217 correctly.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=160465539
  • Loading branch information
shicks authored and Yannic committed Jul 6, 2017
1 parent 7c40d05 commit 8c1a31b
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 22 deletions.
5 changes: 3 additions & 2 deletions src/com/google/javascript/jscomp/js/es6/reflect/construct.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@
'require util/polyfill';

$jscomp.polyfill('Reflect.construct', function(orig) {
return orig || $jscomp.construct;
}, 'es6', 'es3');
// NOTE: This is just Reflect.construct if it's present and functional.
return $jscomp.construct;
}, 'es6', 'es3');
73 changes: 54 additions & 19 deletions src/com/google/javascript/jscomp/js/es6/util/construct.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,65 @@

'require util/objectcreate';

$jscomp.construct =
(typeof Reflect != 'undefined' && Reflect.construct) ||
/**
* Polyfill for Reflect.construct() method:
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/construct
*
* Calls a constructor as with the 'new' operator.
* TODO(sdh): how to type 'target' with (new: TARGET) if opt_newTarget missing?
*
* @param {function(new: ?, ...?)} target The constructor to call.
* @param {!Array} argList The arguments as a list.
* @param {function(new: TARGET, ...?)=} opt_newTarget The constructor to instantiate.
* @return {TARGET} The result of the function call.
* @template TARGET
*/
$jscomp.construct = /** @type {function(): !Function} */ (function() {

// Check for https://github.com/Microsoft/ChakraCore/issues/3217
/** @return {boolean} */
function reflectConstructWorks() {
/** @constructor */ function Base() {}
/** @constructor */ function Derived() {}
new Base();
Reflect.construct(Base, [], Derived);
return new Base() instanceof Base;
}

if (typeof Reflect != 'undefined' && Reflect.construct) {
if (reflectConstructWorks()) return Reflect.construct;
var brokenConstruct = Reflect.construct;
/**
* @param {function(new: ?, ...?)} target The constructor to call.
* @param {!Array} argList The arguments as a list.
* @param {function(new: TARGET, ...?)=} opt_newTarget The constructor to instantiate.
* @return {TARGET} The result of the function call.
* @template TARGET
* @suppress {reportUnknownTypes}
*/
var patchedConstruct = function(target, argList, opt_newTarget) {
var out = brokenConstruct(target, argList);
if (opt_newTarget) Reflect.setPrototypeOf(out, opt_newTarget.prototype);
return out;
};
return patchedConstruct;
}

/**
* Polyfill for Reflect.construct() method:
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/construct
*
* Calls a constructor as with the 'new' operator.
* TODO(sdh): how to type 'target' with (new: TARGET) if opt_newTarget missing?
*
* @param {function(new: ?, ...?)} target The constructor to call.
* @param {!Array} argList The arguments as a list.
* @param {function(new: TARGET, ...?)=} opt_newTarget The constructor to instantiate.
* @return {TARGET} The result of the function call.
* @template TARGET
* @suppress {reportUnknownTypes}
*/
function(target, argList, opt_newTarget) {
// if (arguments.length < 3 || opt_newTarget == target) {
// return new target(...argList);
// }
if (opt_newTarget === undefined) opt_newTarget = target;
var proto = opt_newTarget.prototype || Object.prototype;
var obj = $jscomp.objectCreate(proto);
var apply = Function.prototype.apply;
var out = apply.call(target, obj, argList);
return out || obj;
};
function construct(target, argList, opt_newTarget) {
if (opt_newTarget === undefined) opt_newTarget = target;
var proto = opt_newTarget.prototype || Object.prototype;
var obj = $jscomp.objectCreate(proto);
var apply = Function.prototype.apply;
var out = apply.call(target, obj, argList);
return out || obj;
}
return construct;
})();
2 changes: 1 addition & 1 deletion src/com/google/javascript/jscomp/resources.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,13 @@ testSuite({
assertEquals(23, x.y());
assertUndefined(noCheck(x).x);
},

testChakraBug3217() {
// Tests workaround for https://github.com/Microsoft/ChakraCore/issues/3217
class Base {}
class Derived {}
assertFalse(new Base() instanceof Derived);
Reflect.construct(Base, [], Derived);
assertFalse(new Base() instanceof Derived);
}
});

0 comments on commit 8c1a31b

Please sign in to comment.