Skip to content

Commit 4bd1872

Browse files
authored
Correctly handle resolving promises with other promises (#1190)
* Correctly handle resolving promises with other promises * Additional test
1 parent c8d8c73 commit 4bd1872

File tree

3 files changed

+125
-0
lines changed

3 files changed

+125
-0
lines changed

src/lualib/Promise.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,14 @@ class __TS__Promise<T> implements Promise<T> {
128128
}
129129

130130
private resolve(data: T): void {
131+
if (data instanceof __TS__Promise) {
132+
data.then(
133+
v => this.resolve(v),
134+
err => this.reject(err)
135+
);
136+
return;
137+
}
138+
131139
// Resolve this promise, if it is still pending. This function is passed to the constructor function.
132140
if (this.state === __TS__PromiseState.Pending) {
133141
this.state = __TS__PromiseState.Fulfilled;

test/unit/builtins/async-await.spec.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,63 @@ test("async function can forward varargs", () => {
384384
.expectToEqual(["resolved", "A", "B", "C"]);
385385
});
386386

387+
test("async function adopts pending promise", () => {
388+
util.testFunction`
389+
let resolve: (v: string) => void = () => {};
390+
async function receive(): Promise<string> {
391+
return new Promise(res => {
392+
resolve = res;
393+
});
394+
}
395+
396+
receive().then(v => {
397+
log(v);
398+
});
399+
400+
resolve("delayed resolve");
401+
402+
return allLogs;
403+
`
404+
.setTsHeader(promiseTestLib)
405+
.expectToEqual(["delayed resolve"]);
406+
});
407+
408+
test("async function adopts resolved promise", () => {
409+
util.testFunction`
410+
async function receive(): Promise<string> {
411+
return new Promise(resolve => {
412+
resolve("resolved!");
413+
});
414+
}
415+
416+
receive().then(v => {
417+
log(v);
418+
});
419+
420+
return allLogs;
421+
`
422+
.setTsHeader(promiseTestLib)
423+
.expectToEqual(["resolved!"]);
424+
});
425+
426+
test("async function adopts rejected promise", () => {
427+
util.testFunction`
428+
async function receive(): Promise<string> {
429+
return new Promise((_, reject) => {
430+
reject("rejected");
431+
});
432+
}
433+
434+
receive().catch(err => {
435+
log(err);
436+
});
437+
438+
return allLogs;
439+
`
440+
.setTsHeader(promiseTestLib)
441+
.expectToEqual(["rejected"]);
442+
});
443+
387444
test.each(["async function abc() {", "const abc = async () => {"])(
388445
"can throw error after await in async function (%p)",
389446
functionHeader => {

test/unit/builtins/promise.spec.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,66 @@ test("catch after then catches rejected promise", () => {
751751
.expectToEqual(["catch", "test error"]);
752752
});
753753

754+
test("promise unwraps resolved promise result", () => {
755+
util.testFunction`
756+
const { promise, resolve } = defer<string>();
757+
promise.then(v => log(v));
758+
759+
resolve(Promise.resolve("result"));
760+
761+
return allLogs;
762+
`
763+
.setTsHeader(promiseTestLib)
764+
.expectToEqual(["result"]);
765+
});
766+
767+
test("resolving promise with rejected promise rejects the promise", () => {
768+
util.testFunction`
769+
const { promise, resolve } = defer<string>();
770+
promise.catch(err => log(err));
771+
772+
resolve(Promise.reject("reject"));
773+
774+
return allLogs;
775+
`
776+
.setTsHeader(promiseTestLib)
777+
.expectToEqual(["reject"]);
778+
});
779+
780+
test("resolving promise with pending promise will keep pending until promise2 resolved", () => {
781+
util.testFunction`
782+
const { promise, resolve } = defer<string>();
783+
promise.then(v => log("promise 1", v));
784+
785+
const { promise: promise2, resolve: resolve2 } = defer<string>();
786+
promise2.then(v => log("promise 2", v));
787+
788+
resolve(promise2);
789+
resolve2("result");
790+
791+
return allLogs;
792+
`
793+
.setTsHeader(promiseTestLib)
794+
.expectToEqual(["promise 2", "result", "promise 1", "result"]);
795+
});
796+
797+
test("resolving promise with pending promise will keep pending until promise2 rejects", () => {
798+
util.testFunction`
799+
const { promise, resolve } = defer<string>();
800+
promise.catch(v => log("promise 1", v));
801+
802+
const { promise: promise2, reject: reject2 } = defer<string>();
803+
promise2.catch(v => log("promise 2", v));
804+
805+
resolve(promise2);
806+
reject2("rejection");
807+
808+
return allLogs;
809+
`
810+
.setTsHeader(promiseTestLib)
811+
.expectToEqual(["promise 2", "rejection", "promise 1", "rejection"]);
812+
});
813+
754814
describe("Promise.all", () => {
755815
test("resolves once all arguments are resolved", () => {
756816
util.testFunction`

0 commit comments

Comments
 (0)