Skip to content

Commit 584fd67

Browse files
committed
Normative: Look up calendar methods only once
Introduce a new spec type, Calendar Methods Record, which stores a calendar object's methods once they have been observably looked up. The record is passed around into abstract operations instead of the calendar object itself. The mechanism doesn't currently allow for storing all Temporal.Calendar methods, only the ones that are explicitly called internally in other places than the Zoned and Plain types' methods of the same name, as part of a different API call. Some methods not included in the record are only called by the same-named methods on other Temporal types (example, Calendar.p.dayOfWeek is only called by ZonedDateTime.p.dayOfWeek, PlainDateTime.p.dayOfWeek, and PlainDate.p.dayOfWeek.) Other methods not included in the record are potentially called through lookups in PrepareTemporalFields, so it's not possible to pre-fetch them without making polyfilling difficult. (Example, Calendar.p.monthCode is called in `plainYearMonth.toPlainDate(...)` by looking up the `plainYearMonth.monthCode` property in PrepareTemporalFields. Shortcutting that lookup would mean that PlainDate.p.monthCode could never be polyfilled.) This is a large commit but most of it is mechanical replacement of Temporal.Calendar variables with Calendar Methods Record variables.
1 parent 6e2acfd commit 584fd67

16 files changed

+1129
-672
lines changed

polyfill/lib/duration.mjs

Lines changed: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import bigInt from 'big-integer';
44

55
import * as ES from './ecmascript.mjs';
66
import { MakeIntrinsicClass } from './intrinsicclass.mjs';
7+
import { CalendarMethodRecord } from './methodrecord.mjs';
78
import {
89
YEARS,
910
MONTHS,
@@ -329,13 +330,48 @@ export class Duration {
329330
plainRelativeTo = ES.TemporalDateTimeToDate(precalculatedPlainDateTime);
330331
}
331332

333+
let calendarRec;
334+
if (zonedRelativeTo || plainRelativeTo) {
335+
const calendar = GetSlot(zonedRelativeTo ?? plainRelativeTo, CALENDAR);
336+
calendarRec = new CalendarMethodRecord(calendar);
337+
if (
338+
years !== 0 ||
339+
months !== 0 ||
340+
weeks !== 0 ||
341+
largestUnit === 'year' ||
342+
largestUnit === 'month' ||
343+
largestUnit === 'week' ||
344+
smallestUnit === 'year' ||
345+
smallestUnit === 'month' ||
346+
smallestUnit === 'week'
347+
) {
348+
calendarRec.lookup('dateAdd');
349+
}
350+
if (
351+
largestUnit === 'year' ||
352+
(largestUnit === 'month' && years !== 0) ||
353+
smallestUnit === 'year' ||
354+
// Edge condition in AdjustRoundedDurationDays:
355+
(zonedRelativeTo &&
356+
!roundingGranularityIsNoop &&
357+
smallestUnit !== 'year' &&
358+
smallestUnit !== 'month' &&
359+
smallestUnit !== 'week' &&
360+
smallestUnit !== 'day' &&
361+
(largestUnit === 'year' || largestUnit === 'month' || largestUnit === 'week'))
362+
) {
363+
calendarRec.lookup('dateUntil');
364+
}
365+
}
366+
332367
({ years, months, weeks, days } = ES.UnbalanceDateDurationRelative(
333368
years,
334369
months,
335370
weeks,
336371
days,
337372
largestUnit,
338-
plainRelativeTo
373+
plainRelativeTo,
374+
calendarRec
339375
));
340376
({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } =
341377
ES.RoundDuration(
@@ -353,6 +389,7 @@ export class Duration {
353389
smallestUnit,
354390
roundingMode,
355391
plainRelativeTo,
392+
calendarRec,
356393
zonedRelativeTo,
357394
timeZoneRec,
358395
precalculatedPlainDateTime
@@ -374,6 +411,7 @@ export class Duration {
374411
smallestUnit,
375412
roundingMode,
376413
zonedRelativeTo,
414+
calendarRec,
377415
timeZoneRec,
378416
precalculatedPlainDateTime
379417
));
@@ -408,7 +446,8 @@ export class Duration {
408446
weeks,
409447
days,
410448
largestUnit,
411-
plainRelativeTo
449+
plainRelativeTo,
450+
calendarRec
412451
));
413452

414453
return new Duration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds);
@@ -458,20 +497,38 @@ export class Duration {
458497
plainRelativeTo = ES.TemporalDateTimeToDate(precalculatedPlainDateTime);
459498
}
460499

500+
let calendar, calendarRec;
501+
if (zonedRelativeTo) {
502+
calendar = GetSlot(zonedRelativeTo, CALENDAR);
503+
} else if (plainRelativeTo) {
504+
calendar = GetSlot(plainRelativeTo, CALENDAR);
505+
}
506+
if (calendar) {
507+
calendarRec = new CalendarMethodRecord(calendar);
508+
if (years !== 0 || months !== 0 || weeks !== 0 || unit === 'year' || unit === 'month' || unit === 'week') {
509+
calendarRec.lookup('dateAdd');
510+
}
511+
if (unit === 'year' || (unit === 'month' && years !== 0)) {
512+
calendarRec.lookup('dateUntil');
513+
}
514+
}
515+
461516
// Convert larger units down to days
462517
({ years, months, weeks, days } = ES.UnbalanceDateDurationRelative(
463518
years,
464519
months,
465520
weeks,
466521
days,
467522
unit,
468-
plainRelativeTo
523+
plainRelativeTo,
524+
calendarRec
469525
));
470526
// If the unit we're totalling is smaller than `days`, convert days down to that unit.
471527
let balanceResult;
472528
if (zonedRelativeTo) {
473529
const intermediate = ES.MoveRelativeZonedDateTime(
474530
zonedRelativeTo,
531+
calendarRec,
475532
timeZoneRec,
476533
years,
477534
months,
@@ -525,6 +582,7 @@ export class Duration {
525582
unit,
526583
'trunc',
527584
plainRelativeTo,
585+
calendarRec,
528586
zonedRelativeTo,
529587
timeZoneRec,
530588
precalculatedPlainDateTime
@@ -668,15 +726,20 @@ export class Duration {
668726

669727
const calendarUnitsPresent = y1 !== 0 || y2 !== 0 || mon1 !== 0 || mon2 !== 0 || w1 !== 0 || w2 !== 0;
670728

729+
let calendarRec;
730+
if (zonedRelativeTo || plainRelativeTo) {
731+
calendarRec = new CalendarMethodRecord(GetSlot(zonedRelativeTo ?? plainRelativeTo, CALENDAR));
732+
if (calendarUnitsPresent) calendarRec.lookup('dateAdd');
733+
}
734+
671735
if (zonedRelativeTo && (calendarUnitsPresent || d1 != 0 || d2 !== 0)) {
672736
const instant = GetSlot(zonedRelativeTo, INSTANT);
673-
const calendar = GetSlot(zonedRelativeTo, CALENDAR);
674-
const precalculatedPlainDateTime = ES.GetPlainDateTimeFor(timeZoneRec, instant, calendar);
737+
const precalculatedPlainDateTime = ES.GetPlainDateTimeFor(timeZoneRec, instant, calendarRec.receiver);
675738

676739
const after1 = ES.AddZonedDateTime(
677740
instant,
678741
timeZoneRec,
679-
calendar,
742+
calendarRec,
680743
y1,
681744
mon1,
682745
w1,
@@ -692,7 +755,7 @@ export class Duration {
692755
const after2 = ES.AddZonedDateTime(
693756
instant,
694757
timeZoneRec,
695-
calendar,
758+
calendarRec,
696759
y2,
697760
mon2,
698761
w2,
@@ -710,8 +773,8 @@ export class Duration {
710773

711774
if (calendarUnitsPresent) {
712775
// plainRelativeTo may be undefined, and if so Unbalance will throw
713-
({ days: d1 } = ES.UnbalanceDateDurationRelative(y1, mon1, w1, d1, 'day', plainRelativeTo));
714-
({ days: d2 } = ES.UnbalanceDateDurationRelative(y2, mon2, w2, d2, 'day', plainRelativeTo));
776+
({ days: d1 } = ES.UnbalanceDateDurationRelative(y1, mon1, w1, d1, 'day', plainRelativeTo, calendarRec));
777+
({ days: d2 } = ES.UnbalanceDateDurationRelative(y2, mon2, w2, d2, 'day', plainRelativeTo, calendarRec));
715778
}
716779
h1 = bigInt(h1).add(bigInt(d1).multiply(24));
717780
h2 = bigInt(h2).add(bigInt(d2).multiply(24));

0 commit comments

Comments
 (0)