Commit 56914501 authored by littledan's avatar littledan Committed by Commit bot

Add @@species/better subclassing support to Promises

This patch makes Promise.prototype.then use @@species as specified
in ES2015. The fix is hoped for by certain users, such as legacy
core.js versions which encounter an unhandled Promise reject (complete
with an ugly console message) when Promise subclassing is supported
in a mostly correct way, and we do error checking on Promise
constructors, but @@species is not supported.

BUG=chromium:575314,v8:4633
LOG=Y
R=adamk

Review URL: https://codereview.chromium.org/1577223002

Cr-Commit-Position: refs/heads/master@{#33225}
parent 150887a1
...@@ -23,10 +23,12 @@ var promiseOnResolveSymbol = ...@@ -23,10 +23,12 @@ var promiseOnResolveSymbol =
var promiseRawSymbol = utils.ImportNow("promise_raw_symbol"); var promiseRawSymbol = utils.ImportNow("promise_raw_symbol");
var promiseStatusSymbol = utils.ImportNow("promise_status_symbol"); var promiseStatusSymbol = utils.ImportNow("promise_status_symbol");
var promiseValueSymbol = utils.ImportNow("promise_value_symbol"); var promiseValueSymbol = utils.ImportNow("promise_value_symbol");
var SpeciesConstructor;
var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
utils.Import(function(from) { utils.Import(function(from) {
MakeTypeError = from.MakeTypeError; MakeTypeError = from.MakeTypeError;
SpeciesConstructor = from.SpeciesConstructor;
}); });
// ------------------------------------------------------------------- // -------------------------------------------------------------------
...@@ -276,7 +278,7 @@ function PromiseThen(onResolve, onReject) { ...@@ -276,7 +278,7 @@ function PromiseThen(onResolve, onReject) {
throw MakeTypeError(kNotAPromise, this); throw MakeTypeError(kNotAPromise, this);
} }
var constructor = this.constructor; var constructor = SpeciesConstructor(this, GlobalPromise);
onResolve = IS_CALLABLE(onResolve) ? onResolve : PromiseIdResolveHandler; onResolve = IS_CALLABLE(onResolve) ? onResolve : PromiseIdResolveHandler;
onReject = IS_CALLABLE(onReject) ? onReject : PromiseIdRejectHandler; onReject = IS_CALLABLE(onReject) ? onReject : PromiseIdRejectHandler;
var deferred = NewPromiseCapability(constructor); var deferred = NewPromiseCapability(constructor);
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-species --allow-natives-syntax
// Test that Promises use @@species appropriately
// Another constructor with no species will not be instantiated
var test = new Promise(function(){});
var bogoCount = 0;
function bogusConstructor() { bogoCount++; }
test.constructor = bogusConstructor;
assertTrue(Promise.resolve(test) instanceof Promise);
assertFalse(Promise.resolve(test) instanceof bogusConstructor);
// Tests that chromium:575314 is fixed thoroughly
Promise.resolve(test).catch(e => %AbortJS("Error " + e)).then(() => {
if (bogoCount != 0) %AbortJS("bogoCount was " + bogoCount + " should be 0");
});
// If there is a species, it will be instantiated
// @@species will be read exactly once, and the constructor is called with a
// function
var count = 0;
var params;
class MyPromise extends Promise {
constructor(...args) {
super(...args);
params = args;
}
static get [Symbol.species]() {
count++
return this;
}
}
var myPromise = MyPromise.resolve().then();
assertEquals(1, count);
assertEquals(1, params.length);
assertEquals('function', typeof(params[0]));
assertTrue(myPromise instanceof MyPromise);
assertTrue(myPromise instanceof Promise);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment