Repository navigation
runtime: make AggregateError consume iterable errors and reject non-iterables #2838
Copy link
Copy link
Closed
Description
Summary
new AggregateError(errors, message) should synchronously consume the errors iterable into the .errors array and throw TypeError when errors is omitted or non-iterable. Perry currently lowers the first argument as an array pointer and defaults missing errors to an empty array, so non-array iterables and invalid inputs do not match Node.
Node behavior
A local Node v25.9.0 probe shows:
new AggregateError([1, 2], "m").errors; // [1, 2]
new AggregateError(new Set([1, 2]), "m").errors; // [1, 2]
new AggregateError("ab", "m").errors; // ["a", "b"]
function* g() { yield "x"; yield "y"; }
new AggregateError(g(), "m").errors; // ["x", "y"]
new AggregateError(undefined, "m"); // throws TypeError
new AggregateError(1, "m"); // throws TypeError
new AggregateError(); // throws TypeErrorCurrent Perry evidence
crates/perry-hir/src/lower/expr_new.rshandlesAggregateErrorspecially as a two-argument form. It takes the first arg aserrors, the second asmessage, and defaults missingerrorstoExpr::Array(vec![])rather than a runtime TypeError.- The IR variant
Expr::AggregateErrorNew { errors, message }has no way to represent the iterable conversion or invalid-input throw; it just carries an expression expected to become an array-like value. crates/perry-codegen/src/expr/array_methods.rslowersAggregateErrorNewby unboxingerrorswithunbox_to_i64and passing it directly tojs_aggregateerror_new(errors_handle, msg_handle).crates/perry-runtime/src/error.rs::js_aggregateerror_new()acceptserrors: *mut ArrayHeaderand stores that pointer directly in the ErrorHeader. It does not consume the iterable protocol, convert strings/generators/Sets, or validate non-iterables.
Suggested test surface
Add node-suite tests for:
function show(label: string, fn: () => unknown) {
try { console.log(label + ":", JSON.stringify(fn())); }
catch (err: any) { console.log(label + ":", err?.name); }
}
show("array", () => new AggregateError([1, 2], "m").errors);
show("set", () => new AggregateError(new Set([1, 2]), "m").errors);
show("string", () => new AggregateError("ab" as any, "m").errors);
show("generator", () => {
function* g() { yield "x"; yield "y"; }
return new AggregateError(g(), "m").errors;
});
show("undefined", () => new AggregateError(undefined as any, "m"));
show("number", () => new AggregateError(1 as any, "m"));
show("omitted", () => new (AggregateError as any)());Expected output should materialize the iterable values for valid iterables and print TypeError for invalid inputs.
Scope / non-goals
This issue is about the AggregateError constructor's errors argument. It does not cover Promise.any combinator input handling (#2822) or AggregateError { cause } options (#2836).
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
fix(error): cause options, AggregateError iterables, Error.isError/st…