Skip to content

fix(hir): built-in function .name own-property (#2144) - #2185

Merged
proggeramlug merged 1 commit into
mainfrom
fix-2144-builtin-fn-name
May 28, 2026
Merged

proggeramlug merged 1 commit into
mainfrom
fix-2144-builtin-fn-name

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Summary

Built-in functions' .name own-property read back undefined. Promise.race.name, Math.min.name, Array.isArray.name, and built-in error constructors (TypeError.name, …) all returned 0 / undefined where the spec defines name as { value, writable:false, enumerable:false, configurable:true }. Follow-up to #2075 (which covered user-defined functions only).

Built-in constructors and namespace static functions in Perry aren't represented as named closure values — bare reads of them produce the globalThis lookup's sentinel, so .name on the result follows suit. assert.throws consequently reported the expected error constructor as undefined instead of TypeError/RangeError/etc., and Test262's built-ins/Function sample is dominated by Cannot read … (reading 'name').

Fix

HIR-level constant fold in lower/expr_member.rs and lower/expr_call/native_module.rs:

  • <BuiltinCtor>.name → Expr::String("<Ctor>")
  • <BuiltinNs>.<staticFn>.name → Expr::String("<fn>") (gated on a known spec-defined function table — numeric constants like Math.PI.name stay unfolded)
  • Object.getOwnPropertyDescriptor(<BuiltinFn>, "name") → the spec-compliant data descriptor object literal

Both fold sites gate on the lowered receiver matching GlobalGet(0) / PropertyGet { GlobalGet(0), … }, so a locally-shadowed const Math = … lowers to a LocalGet and correctly bypasses the fold.

Test plan

Surfaced by the #799 Test262 radar re-harvest. Part of #793.

A built-in function's `name` own-property read back `undefined`, and
`Object.getOwnPropertyDescriptor(Promise.race, "name")` returned undefined
too. Built-in constructors (`TypeError`, `Promise`, `Array`, …) and the
static functions on built-in namespaces / constructors (`Math.min`,
`Promise.race`, `Array.isArray`, …) are not represented as named closure
values in Perry — bare reads of them produce the `globalThis` lookup's
`0` / undefined sentinel, so `.name` on the result follows suit.
Follow-up to #2075 (#2059), which only covered user-defined function
declarations and expressions.

`assert.throws` reports `expectedErrorConstructor.name` to label thrown
errors (so every built-in `Error` constructor showed as `undefined`
instead of `TypeError`/`RangeError`/etc.) and Test262's
`built-ins/Function` sample is dominated by `Cannot read … (reading
'name')` once the sibling "built-in proto methods are undefined" gap
lands.

- `analysis::is_builtin_static_function_member`: spec-defined static
  function members of built-in namespaces / constructors. Function-typed
  members only — numeric constants like `Math.PI` stay unfolded so
  `(Math.PI).name` keeps producing `undefined` (matching Node).
- `lower/expr_member`: `<BuiltinCtor>.name` and
  `<BuiltinNs>.<staticFn>.name` fold to `Expr::String`. Gated on the
  *lowered* receiver matching `GlobalGet(0)` / `PropertyGet {
  GlobalGet(0), … }`, so a locally-shadowed `const Math = …` lowers to
  a `LocalGet` and bypasses the fold.
- `lower/expr_call/native_module` (`Object.getOwnPropertyDescriptor`
  arm): `…(<BuiltinFn>, "name")` folds to the spec-compliant data
  descriptor object literal `{ value, writable:false, enumerable:false,
  configurable:true }`. Same lowered-receiver gate as the `.name` fold.
- `lower/expr_call/name_fold` (new): AST recognizer + descriptor builder
  shared by both fold sites.

Parity test test-parity/node-suite/object/builtin-function-name.ts is
byte-identical to `node --experimental-strip-types`. The existing #2075
`function-name-descriptor.ts` parity test still passes. perry-hir lib
tests: 111/111.

Surfaced by the #799 Test262 radar re-harvest (built-ins/Function
~16% — 38× `Cannot read … (reading 'name')`). Part of #793.
@proggeramlug
proggeramlug merged commit f3812fb into main May 28, 2026
11 checks passed
@proggeramlug
proggeramlug deleted the fix-2144-builtin-fn-name branch May 28, 2026 11:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant