test(async): #1013 — pin Promise.all + array destructure regression#1064
Conversation
…HIR collapse `const [a, b] = await Promise.all([fn1(), fn2()])` returned undefined under Perry HEAD=13dc587a (v0.5.1004, pre-#1007). Bisected: the bug disappears at f78361f (#1007 — restore built-in static identity in member position), which collapses `Promise.all` from `PropertyGet { PropertyGet { GlobalGet(0), "Promise" }, "all" }` down to `PropertyGet { GlobalGet(0), "all" }`. The codegen Promise-static dispatch at that commit only matched the bare `GlobalGet(_)` receiver, so the deeper shape fell through to `js_native_call_method("all", …)` against the Promise constructor — returning 0.0 (no such method on a function value) and breaking the destructure. Current main is doubly-protected: (1) the #1007 HIR collapse keeps the shallow shape, and (2) PR #1030 introduced `is_global_constructor_expr`, which accepts both shapes at the codegen dispatch. No code change is required — the bug is fixed in current main as a side effect of #1007 + #1030. This test pins the byte-for-byte node match so a future regression of either piece (the HIR collapse or the helper) fails immediately. Closes #1013.
|
This looks like the right root cause for #1013: the bad One coverage suggestion before merge: the original issue’s repro shape used cross-module imported async helpers that awaited and then returned property reads, e.g. A stronger regression would add a small fixture module exporting const [accessToken, userPlan] = await Promise.all([
getAccessToken("u1"),
getUserPlan("u1"),
]);Not a blocker if the intent is only to pin the bisected root cause, but it would guard the full #1013 surface more directly. |
…ape (#1068) Per PR #1064 review (@andrewtdiz): the original gscmaster-api repro used cross-module imported async helpers that awaited an inner lookup and returned a property read off the resolved value (`return user.accessToken`). The previous test only pinned the same-file literal-return shape, which covers the dispatch bug but not the exact reported async/module/property boundary. Added `test-files/fixtures/issue_1013/user_lookup.ts` exporting `getAccessToken` / `getUserPlan` against an inner `await lookupUser(id)`, returning property reads. The test now destructures both shapes from `Promise.all` and verifies byte-for-byte parity with Node.
Closes #1013.
Summary
The reporter's bug —
const [a, b] = await Promise.all([fn1(), fn2()])returninga === undefined/b === undefined— is already fixed on current main as a side effect of two PRs that landed after the reported HEAD (13dc587a/ v0.5.1004):fix(hir): #1001 — restore built-in static identity in member position) collapsesPromise.allfromPropertyGet { PropertyGet { GlobalGet(0), "Promise" }, "all" }toPropertyGet { GlobalGet(0), "all" }.fix: address #945 scalar method allocation regression) addedis_global_constructor_exprin the codegen Promise-static dispatch, which accepts both the shallow (GlobalGet(0)) and deeper (PropertyGet { GlobalGet(0), "Promise" }) receiver shapes.This PR adds a regression test (
test-files/test_issue_1013_promise_all_destructure.ts) that pins the byte-for-byte node match. No code change.Root cause (pre-fix)
At
13dc587a, the HIR forPromise.all([fetchA(), fetchB()])wasPropertyGet { object: PropertyGet { GlobalGet(0), "Promise" }, property: "all" }. The codegen Promise-static dispatch only matchedmatches!(object.as_ref(), Expr::GlobalGet(_)), so this deeper shape fell through to the genericjs_native_call_method("all", …)block — which called"all"against the global Promise constructor function. No such method on a function value, returned0.0. The awaited value was then a number, and[a, b] = 0.0produceda=0, b=undefined.Bisect
13dc587a(#1010, reporter HEAD)a: 0 typeof: number / b: undefined42ec277c(#949test harden, parent of #1007)f78361f1(#1007 HIR collapse)a: "hello-from-A" / b: {"plan":"pro"}3856caad(current main)Repro
Expected (node
--experimental-strip-types):Test plan
test-files/test_issue_1013_promise_all_destructure.tsmatches node byte-for-byte on current mainNo version bump or changelog change.