From 7694b7956d514222e407fab7efde31e17a807b1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Fri, 5 Jun 2026 19:12:48 +0200 Subject: [PATCH] fix(runtime): Number.isInteger/isSafeInteger usable as first-class function values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same reroute-undo issue as Date.now (#4622) / Array.isArray (#4626). All six Number statics (isFinite/isInteger/isNaN/isSafeInteger/parseFloat/parseInt) are reified with metadata via install_constructor_static, but the #973/#4139 reroute-undo collapsed value reads to GlobalGet(0)., whose intrinsic path dropped the metadata for isInteger/isSafeInteger (.name/.length undefined). Add Number to the reified-static reroute-undo exception. The already-named siblings (isFinite/isNaN/parseFloat/parseInt) are also reified, so routing them to the reified receiver preserves their names; direct calls keep the intrinsic fast path via the !member_is_call_callee gate. Byte-identical to node: Number.isInteger.name==='isInteger'/.length===1, isSafeInteger likewise; value-calls and direct calls work. Fixes test262 Number/{isInteger,isSafeInteger}/{name,length}. (String.fromCharCode/etc. are not reified yet — tracked in #4627.) --- crates/perry-hir/src/lower/expr_member.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/perry-hir/src/lower/expr_member.rs b/crates/perry-hir/src/lower/expr_member.rs index 2271330ebd..9c06bd8c58 100644 --- a/crates/perry-hir/src/lower/expr_member.rs +++ b/crates/perry-hir/src/lower/expr_member.rs @@ -1850,10 +1850,17 @@ fn lower_member_inner(ctx: &mut LoweringContext, member: &ast::MemberExpr) -> Re // undefined). `Array.fromAsync` is unreified and stays // undefined either way. Direct calls keep the intrinsic // fast path via the `!member_is_call_callee` gate. + // #4627: all six Number statics (isFinite / isInteger / + // isNaN / isSafeInteger / parseFloat / parseInt) are reified + // with metadata via install_constructor_static, so routing + // value reads to the reified Number receiver is safe and + // fixes the missing `.name`/`.length` on isInteger / + // isSafeInteger. (String's fromCharCode/etc. are NOT reified + // yet — left to #4627.) let outer_is_reified_builtin_static_value = !member_is_call_callee && matches!( property.as_str(), - "JSON" | "Reflect" | "BigInt" | "Symbol" | "Array" + "JSON" | "Reflect" | "BigInt" | "Symbol" | "Array" | "Number" ) && outer_static_member .map(|member| {