mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-04 08:04:37 +08:00
Compare unions that hold promises as untyped values
A promise converted into a union's promise arm is a new promise, so two optional slots set to one promise each hold their own conversion, and a value narrowed out of such a slot may be one too. Union equality compared those arm payloads by pointer and answered false where Node answers true. Any comparison between a union with a promise arm and a promise or another such union now compares both sides as untyped values, where a converted promise answers with its origin's identity.
This commit is contained in:
@@ -2388,19 +2388,22 @@ export function lowerStrictEquality(
|
||||
loc,
|
||||
};
|
||||
}
|
||||
// A plain promise against a union whose promise arm has a different
|
||||
// payload (`chains.get(id) === tail` with a `Map<K, Promise<unknown>>`):
|
||||
// wrapping would convert the promise into that arm, and the converted
|
||||
// promise is a new object. Promises are objects to ===, so compare both
|
||||
// sides as untyped values, where a converted promise answers with its
|
||||
// origin's identity (the plain promise-vs-promise rule below).
|
||||
const plainPromise =
|
||||
left.type.kind === "promise" ? left : right.type.kind === "promise" ? right : null;
|
||||
// A promise against a union with a promise arm, or two such unions:
|
||||
// converting a promise into a union's promise arm of another payload
|
||||
// (`chains.get(id) === tail` with a `Map<K, Promise<unknown>>`, or
|
||||
// `a.pending === b.pending` after both were set to one promise) builds a
|
||||
// new promise, so either side may hold a conversion of the other's
|
||||
// promise, and a value narrowed out of the union may be one too.
|
||||
// Promises are objects to ===, so compare both sides as untyped values,
|
||||
// where a converted promise answers with its origin's identity (the plain
|
||||
// promise-vs-promise rule below).
|
||||
const holdsPromise = (type: IrType): boolean =>
|
||||
type.kind === "promise" ||
|
||||
(type.kind === "union" &&
|
||||
(lowerer.unions.get(type.unionId)?.arms ?? []).some((arm) => arm.kind === "promise"));
|
||||
if (
|
||||
!bothUnion &&
|
||||
plainPromise !== null &&
|
||||
lowerer.armTag(ut.unionId, plainPromise.type) < 0 &&
|
||||
unionArms.some((arm) => arm.kind === "promise") &&
|
||||
holdsPromise(left.type) &&
|
||||
holdsPromise(right.type) &&
|
||||
lowerer.dynConvertible(left.type) &&
|
||||
lowerer.dynConvertible(right.type)
|
||||
) {
|
||||
|
||||
@@ -58,6 +58,15 @@ async function main(): Promise<void> {
|
||||
console.log(store.pending === other);
|
||||
console.log(await store.pending);
|
||||
|
||||
// One promise in two optional slots: each holds its own conversion.
|
||||
const second: Store = {};
|
||||
second.pending = work;
|
||||
console.log(store.pending === second.pending, store.pending !== second.pending);
|
||||
const slots: Store[] = [store, second, { pending: other }];
|
||||
console.log(slots.map((slot) => slot.pending === slots[0]!.pending).join(","));
|
||||
second.lookup = findName;
|
||||
console.log(store.lookup === second.lookup);
|
||||
|
||||
const lookup = store.lookup;
|
||||
if (lookup) console.log(await lookup("abcd"), await lookup("ab"));
|
||||
console.log(store.scale?.(21));
|
||||
|
||||
Reference in New Issue
Block a user