You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Browse filesBrowse the repository at this point in the historyBrowse files
authored
fix(runtime): #5587 — subclassing a Temporal.<Type> gives the instance the Temporal brand (#5672)
* fix(runtime): #5587 — subclassing a Temporal.<Type> constructor gives the instance the Temporal brand
`class X extends Temporal.Duration { constructor(){ super(...args) } }` produced an
empty plain object: `super()` ran the native Temporal constructor (which returns a
fresh NaN-boxed cell rather than mutating the implicit `this`) and DISCARDED the
returned cell. The subclass instance then had no brand, so `instance.abs()` resolved
`abs` to `undefined` and threw `TypeError: value is not a function` — the dominant
failure (36 cases) in the test262 `built-ins/Temporal/**/subclassing-ignored.js`
cluster.
Mirror the existing `class X extends Request/Response` fetch-handle pattern: when a
`super()` parent resolves to a Temporal constructor, run it and stash the returned
cell on `this` under `__perry_temporal_cell__`. Both `super()` lowerings are covered
— `js_fetch_or_value_super` (non-spread `super(a, b)`) and `js_super_construct_apply`
(the `super(...spread)` form the helper actually uses, via the decl-time-recorded
dynamic parent value). Method-call, property-get, and `instanceof` dispatch recover
the cell from there.
Also fixes the surrounding real-cell gaps the same tests exercise:
- `Object.getPrototypeOf(temporalCell)` returned `null`; now resolves
`Temporal.<Type>.prototype` via the live namespace, so
`assert.sameValue(Object.getPrototypeOf(result), construct.prototype)` holds.
- Reading a prototype method as a value (`d.abs`, not `d.abs()`) returned
`undefined`, breaking the `instance[method](...spread)` read+apply form; now
returns a bound method (gated on a real per-kind method predicate so unknown
properties still read as `undefined`). Applies to real cells and subclass
instances.
- Construct-only Temporal ctors (`PlainDate`/`PlainTime`/`Instant`/…) threw
"requires 'new'" when invoked from `super()`; `new.target` is now set for the call.
Known remaining limitation (separate, non-Temporal bug): a class method/constructor
defined inside a function captures an enclosing `let` by value, not by cell, so the
helper's `assert.sameValue(called, 1)` still fails for in-function subclasses. This
affects all classes (reproduces with a plain user-class subclass), not just Temporal,
and is out of scope here; with it the subclassing-ignored cases now run all the way
through the Temporal logic and fail only on that `called` assertion.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix+style: #5587 — address CodeRabbit review (aliased/raw-I64 receivers) + rustfmt/clippy
- fetch_globals: non-spread `super()` now recovers the Temporal parent from the
decl-time class-id stash when the immediate heritage value is a stale alias
(`const D = Temporal.Duration; class X extends D`), mirroring the
Request/Response recovery. (CodeRabbit major)
- instanceof: the Temporal subclass-brand check now also accepts the raw-I64
receiver form (top16 == 0), how module-level object vars are stored, not just
the NaN-boxed 0x7FFD form. (CodeRabbit minor)
- has_method: `matches!(x, Some(_))` → `.is_some()`; rustfmt.
- New regression test for the aliased-heritage path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Ralph <ralph@skelpo.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0 commit comments