Skip to content

fix(runtime): Temporal PlainDate/YearMonth/MonthDay/Time/Instant/Now tail -> ~98%#4923

Merged
proggeramlug merged 1 commit into
mainfrom
temporal-tail-rest-parity
Jun 10, 2026
Merged

fix(runtime): Temporal PlainDate/YearMonth/MonthDay/Time/Instant/Now tail -> ~98%#4923
proggeramlug merged 1 commit into
mainfrom
temporal-tail-rest-parity

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Summary

Pushes the remaining Temporal.Plain* / Instant / Now test262 tails to ~98%, grouped by root cause, zero regressions.

Measured on the 48-core box vs node v26 (self-validating Temporal cases), built-ins/Temporal/{PlainDate,PlainYearMonth,PlainMonthDay,PlainTime,Instant,Now}, PERRY_NO_AUTO_OPTIMIZE=1 --jobs 12 (the contended default run mislabels ~66 cache/auto-opt races as compile-fail; the clean run shows the real picture):

pass runtime-fail parity
before 2241 143 94.0%
after 2343 41 98.3%

+102 tests, 0 regressions.

Broad regression check — built-ins language shard 0/12 (2645 cases) diffed vs the branch base:

  • Regressions (pass to fail): 0
  • Fixed (fail to pass): 12 (all Temporal)

Root causes fixed (grouped)

1. from() / ToTemporalX bag reading (~40 tests). Rewrote the property-bag path for PlainDate/PlainYearMonth/PlainMonthDay/PlainTime:

  • calendar slot read first, then the calendar's date fields alphabetically (day,[era,eraYear],month,monthCode,year; era/eraYear only for non-ISO calendars), then overflow last — matching the observable order-of-operations.
  • monthCode now ToPrimitiveAndRequireString (was str_field, which dropped a toString-wrapped value); month/day now ToPositiveIntegerWithTruncation (a value < 1 is a RangeError even under constrain, was silently saturated to 255).
  • A string item is parsed first (invalid -> RangeError) before options is validated; a wrong-typed options is a TypeError only after the fields are read. PlainMonthDay.from previously ignored options/overflow entirely.
  • Non-target Temporal values (e.g. a PlainDate passed to PlainYearMonth.from) are read as property bags, not rejected.

2. Constructors (~10). PlainDate/PlainYearMonth/PlainMonthDay/PlainTime now coerce each numeric field via real ToNumber (ToIntegerWithTruncation — observes valueOf, rejects Infinity/NaN with a RangeError at the field's read position) and resolve calendar via the strict ToTemporalCalendarIdentifier. All five are now [[Construct]]-only — calling without new is a TypeError.

3. with() (~16). PlainDate/PlainYearMonth/PlainMonthDay/PlainTime with now run RejectObjectWithCalendarOrTimeZone (reads calendar+timeZone first, TypeError if present), read fields alphabetically with positive validation, and read overflow last. withCalendar() with a missing argument is a TypeError.

4. valueOf / relational (5). A statically-lowered temporal.valueOf() (lowered to DateValueOf for an any receiver) and temporal < temporal (relational ToPrimitive(number)) now route to the Temporal brand dispatch, which throws TypeError per spec.

5. Instant / Now / misc.

  • Now.plainDate*ISO(tz) / PlainDate.toZonedDateTime(tz): a wrong-typed time-zone is now TypeError (was silently dropped / RangeError).
  • new Temporal.Instant("abc123") -> SyntaxError; Instant.fromEpochMilliseconds -> real ToNumber (BigInt/Symbol TypeError) + NumberToBigInt integral check (RangeError).
  • Instant.prototype no longer advertises the removed epochSeconds/epochMicroseconds accessors.
  • PlainMonthDay.prototype.equals compares the reference (ISO) year.
  • toPlainDate reads only day (YearMonth) / year (MonthDay) from its argument.

Deferred (out of scope / other workers)

  • Subclassing (~31): Temporal cells have no [[Prototype]] link; full subclass support is an architectural change (also deferred by the big-3 worker).
  • PlainDate.add/subtract duration-bag order-of-operations (2): lives in duration.rs (big-3 worker's domain).
  • exact-multiple-of-larger-unit / float64-representable-integer (6): temporal_rs 0.2.3 rounding-precision internals.
  • Instant/large-bigint (1): pre-existing BigInt unary-negation bug, outside Temporal.

Files

crates/perry-runtime/src/temporal/{options,plain_date,plain_year_month,plain_month_day,plain_time,instant,now,dispatch}.rs, object/global_this.rs, date.rs, builtins/arithmetic.rs.

…tail -> 98.3%

ToTemporalX rewrite (calendar-first, alphabetical fields, overflow-last,
positive month/day, real ToNumber on constructors), require-new, with()
RejectObjectWithCalendarOrTimeZone, Instant epoch coercion + SyntaxError,
Now timezone wrong-type, valueOf TypeError, MonthDay equals reference-year.
@proggeramlug proggeramlug merged commit 23c8ef7 into main Jun 10, 2026
11 of 13 checks passed
@proggeramlug proggeramlug deleted the temporal-tail-rest-parity branch June 10, 2026 13:26
proggeramlug added a commit that referenced this pull request Jun 10, 2026
date.rs grew to 2008 lines (pushed over by the Temporal tail in #4923), tripping
scripts/check_file_size.sh and failing the required lint gate on every open PR
(the check runs against each PR's merge with current main).

Extract the date-string parsing cluster - parse_date_string + its per-grammar
helpers (parse_iso8601, parse_rfc_or_named, parse_tz_offset, normalize_millis,
month_from_name, FULL_MONTHS) - into a new crates/perry-runtime/src/date/parse.rs
submodule (Rust 2018 keeps date.rs alongside date/parse.rs, no rename). date.rs
declares `mod parse;` and re-exports the single entry point via
`use parse::parse_date_string;`; the per-grammar helpers stay private to the
submodule. Shared time math (make_utc_ms, time_clip,
timestamp_to_local_components) stays in the parent and is reached via super::
(a child module can see its ancestor's private items, so no visibility was
widened beyond parse_date_string).

Pure code movement, no behavior change. date.rs 2008 -> 1675 lines,
date/parse.rs 347. fmt clean; all date tests pass except the pre-existing
test_full_year_setters_revive_invalid_date_only, which is timezone-dependent
(asserts local hours == 0 after a local setFullYear) and fails identically on
clean main on a non-UTC host - CI runs UTC and passes it.

Co-authored-by: Ralph Kuepper <ralph@skelpo.com>
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