commit c239c1f224a35434175a2d7fe78c7e2fa7f7480a
parent 4f65b6d60c7a7ff8556d0c46bc7b1d32c72987bd
Author: André Bargull <andre.bargull@gmail.com>
Date: Thu, 27 Nov 2025 10:03:37 +0000
Bug 1999316 - Part 4: CalendarDateYear and CalendarDateMonthCode are infallible. r=spidermonkey-reviewers,mgaudet
Both functions can no longer throw when we've updated to a more recent ICU4X.
Also adds `CalendarDateWithOrdinalMonth` instead of reusing `ISODate`.
Differential Revision: https://phabricator.services.mozilla.com/D272034
Diffstat:
1 file changed, 60 insertions(+), 120 deletions(-)
diff --git a/js/src/builtin/temporal/Calendar.cpp b/js/src/builtin/temporal/Calendar.cpp
@@ -1470,8 +1470,8 @@ static bool CalendarDateEra(JSContext* cx, CalendarId calendar,
/**
* Return the extended (non-era) year from |date|.
*/
-static bool CalendarDateYear(JSContext* cx, CalendarId calendar,
- const icu4x::capi::Date* date, int32_t* result) {
+static int32_t CalendarDateYear(CalendarId calendar,
+ const icu4x::capi::Date* date) {
MOZ_ASSERT(calendar != CalendarId::ISO8601);
switch (calendar) {
@@ -1487,15 +1487,13 @@ static bool CalendarDateYear(JSContext* cx, CalendarId calendar,
case CalendarId::IslamicTabular:
case CalendarId::IslamicUmmAlQura:
case CalendarId::Japanese: {
- *result = icu4x::capi::icu4x_Date_extended_year_mv1(date);
- return true;
+ return icu4x::capi::icu4x_Date_extended_year_mv1(date);
}
case CalendarId::Chinese:
case CalendarId::Dangi: {
// Return the related ISO year for Chinese/Dangi.
- *result = icu4x::capi::icu4x_Date_era_year_or_related_iso_mv1(date);
- return true;
+ return icu4x::capi::icu4x_Date_era_year_or_related_iso_mv1(date);
}
case CalendarId::Ethiopian: {
@@ -1520,8 +1518,7 @@ static bool CalendarDateYear(JSContext* cx, CalendarId calendar,
year = FromAmeteAlemToAmeteMihret(year);
}
- *result = year;
- return true;
+ return year;
}
case CalendarId::ROC: {
@@ -1552,8 +1549,7 @@ static bool CalendarDateYear(JSContext* cx, CalendarId calendar,
year = -(year - 1);
}
- *result = year;
- return true;
+ return year;
}
}
MOZ_CRASH("invalid calendar id");
@@ -1563,9 +1559,8 @@ static bool CalendarDateYear(JSContext* cx, CalendarId calendar,
* Retrieve the month code from |date| and then map the returned ICU4X month
* code to the corresponding |MonthCode| member.
*/
-static bool CalendarDateMonthCode(JSContext* cx, CalendarId calendar,
- const icu4x::capi::Date* date,
- MonthCode* result) {
+static MonthCode CalendarDateMonthCode(CalendarId calendar,
+ const icu4x::capi::Date* date) {
MOZ_ASSERT(calendar != CalendarId::ISO8601);
// Valid month codes are "M01".."M13" and "M01L".."M12L".
@@ -1596,10 +1591,9 @@ static bool CalendarDateMonthCode(JSContext* cx, CalendarId calendar,
auto monthCode = MonthCode{ordinal, isLeapMonth};
// The month code must be valid for this calendar.
- MOZ_ASSERT(CalendarMonthCodes(calendar).contains(monthCode));
+ MOZ_ASSERT(IsValidMonthCodeForCalendar(calendar, monthCode));
- *result = monthCode;
- return true;
+ return monthCode;
}
class MonthCodeString {
@@ -1935,10 +1929,7 @@ static bool CalendarFieldEraYearMatchesYear(JSContext* cx, CalendarId calendar,
int32_t intYear;
MOZ_ALWAYS_TRUE(mozilla::NumberEqualsInt32(year, &intYear));
- int32_t yearFromEraYear;
- if (!CalendarDateYear(cx, calendar, date, &yearFromEraYear)) {
- return false;
- }
+ int32_t yearFromEraYear = CalendarDateYear(calendar, date);
// The user requested year must match the actual (extended/epoch) year.
if (intYear != yearFromEraYear) {
@@ -2170,16 +2161,10 @@ static bool NonISOMonthDayToISOReferenceDate(JSContext* cx, CalendarId calendar,
}
// Find the calendar year for the ISO start date.
- int32_t calendarYear;
- if (!CalendarDateYear(cx, calendar, fromIsoDate.get(), &calendarYear)) {
- return false;
- }
+ int32_t calendarYear = CalendarDateYear(calendar, fromIsoDate.get());
// Find the calendar year for the ISO end date.
- int32_t toCalendarYear;
- if (!CalendarDateYear(cx, calendar, toIsoDate.get(), &toCalendarYear)) {
- return false;
- }
+ int32_t toCalendarYear = CalendarDateYear(calendar, toIsoDate.get());
while (direction < 0 ? calendarYear >= toCalendarYear
: calendarYear <= toCalendarYear) {
@@ -2302,9 +2287,7 @@ static bool NonISOMonthDayToISOReferenceDate(JSContext* cx, CalendarId calendar,
}
if (!fields.has(CalendarField::MonthCode)) {
- if (!CalendarDateMonthCode(cx, calendar, date.get(), &monthCode)) {
- return false;
- }
+ monthCode = CalendarDateMonthCode(calendar, date.get());
}
MOZ_ASSERT(monthCode != MonthCode{});
@@ -2621,11 +2604,7 @@ bool js::temporal::CalendarYear(JSContext* cx, Handle<CalendarValue> calendar,
return false;
}
- int32_t year;
- if (!CalendarDateYear(cx, calendarId, dt.get(), &year)) {
- return false;
- }
-
+ int32_t year = CalendarDateYear(calendarId, dt.get());
result.setInt32(year);
return true;
}
@@ -2691,11 +2670,7 @@ bool js::temporal::CalendarMonthCode(JSContext* cx,
return false;
}
- MonthCode monthCode;
- if (!CalendarDateMonthCode(cx, calendarId, dt.get(), &monthCode)) {
- return false;
- }
-
+ auto monthCode = CalendarDateMonthCode(calendarId, dt.get());
auto* str = NewStringCopy<CanGC>(cx, std::string_view{monthCode});
if (!str) {
return false;
@@ -3102,10 +3077,7 @@ static bool ISODateToFields(JSContext* cx, Handle<CalendarValue> calendar,
}
// Step 3.
- MonthCode monthCode;
- if (!CalendarDateMonthCode(cx, calendarId, dt.get(), &monthCode)) {
- return false;
- }
+ auto monthCode = CalendarDateMonthCode(calendarId, dt.get());
result.setMonthCode(monthCode);
// Step 4.
@@ -3116,10 +3088,7 @@ static bool ISODateToFields(JSContext* cx, Handle<CalendarValue> calendar,
// Step 5.
if (type == DateFieldType::YearMonth || type == DateFieldType::Date) {
- int32_t year;
- if (!CalendarDateYear(cx, calendarId, dt.get(), &year)) {
- return false;
- }
+ int32_t year = CalendarDateYear(calendarId, dt.get());
result.setYear(year);
}
@@ -3395,6 +3364,12 @@ struct CalendarDate {
int32_t day = 0;
};
+struct CalendarDateWithOrdinalMonth {
+ int32_t year = 0;
+ int32_t month = 0;
+ int32_t day = 0;
+};
+
/**
* CompareISODate adjusted for calendar dates.
*/
@@ -3412,47 +3387,39 @@ static int32_t CompareCalendarDate(const CalendarDate& one,
return 0;
}
-static bool ToCalendarDate(JSContext* cx, CalendarId calendarId,
- const icu4x::capi::Date* dt, CalendarDate* result) {
- int32_t year;
- if (!CalendarDateYear(cx, calendarId, dt, &year)) {
- return false;
- }
-
- MonthCode monthCode;
- if (!CalendarDateMonthCode(cx, calendarId, dt, &monthCode)) {
- return false;
- }
+/**
+ * CompareISODate adjusted for calendar dates.
+ */
+static int32_t CompareCalendarDate(const CalendarDateWithOrdinalMonth& one,
+ const CalendarDateWithOrdinalMonth& two) {
+ return CompareISODate(ISODate{one.year, one.month, one.day},
+ ISODate{two.year, two.month, two.day});
+}
+static CalendarDate ToCalendarDate(CalendarId calendarId,
+ const icu4x::capi::Date* dt) {
+ int32_t year = CalendarDateYear(calendarId, dt);
+ auto monthCode = CalendarDateMonthCode(calendarId, dt);
int32_t day = DayOfMonth(dt);
- *result = {year, monthCode, day};
- return true;
+ return {year, monthCode, day};
}
-/**
- * Store a calendar date in a |ISODate| struct when leap months don't matter.
- */
-static bool ToCalendarDate(JSContext* cx, CalendarId calendarId,
- const icu4x::capi::Date* dt, ISODate* result) {
+static CalendarDateWithOrdinalMonth ToCalendarDateWithOrdinalMonth(
+ CalendarId calendarId, const icu4x::capi::Date* dt) {
MOZ_ASSERT(!CalendarHasLeapMonths(calendarId));
- int32_t year;
- if (!CalendarDateYear(cx, calendarId, dt, &year)) {
- return false;
- }
-
+ int32_t year = CalendarDateYear(calendarId, dt);
int32_t month = OrdinalMonth(dt);
int32_t day = DayOfMonth(dt);
- *result = {year, month, day};
- return true;
+ return {year, month, day};
}
-static bool AddYearMonthDuration(JSContext* cx, CalendarId calendarId,
- const ISODate& calendarDate,
- const DateDuration& duration,
- CalendarDate* result) {
+static bool AddYearMonthDuration(
+ JSContext* cx, CalendarId calendarId,
+ const CalendarDateWithOrdinalMonth& calendarDate,
+ const DateDuration& duration, CalendarDate* result) {
MOZ_ASSERT(!CalendarHasLeapMonths(calendarId));
MOZ_ASSERT(IsValidDuration(duration));
@@ -3560,10 +3527,7 @@ static bool AddYearMonthDuration(JSContext* cx, CalendarId calendarId,
return false;
}
- if (!CalendarDateMonthCode(cx, calendarId, firstDayOfMonth.get(),
- &monthCode)) {
- return false;
- }
+ monthCode = CalendarDateMonthCode(calendarId, firstDayOfMonth.get());
}
*result = {year, monthCode, day};
@@ -3585,18 +3549,12 @@ static bool AddNonISODate(JSContext* cx, CalendarId calendarId,
CalendarDate calendarDate;
if (!CalendarHasLeapMonths(calendarId)) {
- ISODate date;
- if (!ToCalendarDate(cx, calendarId, dt.get(), &date)) {
- return false;
- }
+ auto date = ToCalendarDateWithOrdinalMonth(calendarId, dt.get());
if (!AddYearMonthDuration(cx, calendarId, date, duration, &calendarDate)) {
return false;
}
} else {
- CalendarDate date;
- if (!ToCalendarDate(cx, calendarId, dt.get(), &date)) {
- return false;
- }
+ auto date = ToCalendarDate(calendarId, dt.get());
if (!AddYearMonthDuration(cx, calendarId, cal.get(), date, duration,
&calendarDate)) {
return false;
@@ -3836,17 +3794,10 @@ static bool DifferenceNonISODate(JSContext* cx, CalendarId calendarId,
// implementation to compute the date duration.
int32_t monthsPerYear = CalendarMonthsPerYear(calendarId);
- ISODate oneDate;
- if (!ToCalendarDate(cx, calendarId, dtOne.get(), &oneDate)) {
- return false;
- }
+ auto oneDate = ToCalendarDateWithOrdinalMonth(calendarId, dtOne.get());
+ auto twoDate = ToCalendarDateWithOrdinalMonth(calendarId, dtTwo.get());
- ISODate twoDate;
- if (!ToCalendarDate(cx, calendarId, dtTwo.get(), &twoDate)) {
- return false;
- }
-
- int32_t sign = -CompareISODate(oneDate, twoDate);
+ int32_t sign = -CompareCalendarDate(oneDate, twoDate);
MOZ_ASSERT(sign != 0);
years = twoDate.year - oneDate.year;
@@ -3855,17 +3806,17 @@ static bool DifferenceNonISODate(JSContext* cx, CalendarId calendarId,
// If |oneDate + years| surpasses |twoDate|, reduce |years| by one and add
// |monthsPerYear| to |months|. The next step will balance the intermediate
// result.
- auto intermediate =
- ISODate{oneDate.year + years, oneDate.month, oneDate.day};
- if (CompareISODate(intermediate, twoDate) * sign > 0) {
+ auto intermediate = CalendarDateWithOrdinalMonth{
+ oneDate.year + years, oneDate.month, oneDate.day};
+ if (CompareCalendarDate(intermediate, twoDate) * sign > 0) {
years -= sign;
months += monthsPerYear * sign;
}
// Add both |years| and |months| and then balance the intermediate result to
// ensure its month is within the valid bounds.
- intermediate =
- ISODate{oneDate.year + years, oneDate.month + months, oneDate.day};
+ intermediate = CalendarDateWithOrdinalMonth{
+ oneDate.year + years, oneDate.month + months, oneDate.day};
if (intermediate.month > monthsPerYear) {
intermediate.month -= monthsPerYear;
intermediate.year += 1;
@@ -3875,7 +3826,7 @@ static bool DifferenceNonISODate(JSContext* cx, CalendarId calendarId,
}
// If |intermediate| surpasses |twoDate|, reduce |month| by one.
- if (CompareISODate(intermediate, twoDate) * sign > 0) {
+ if (CompareCalendarDate(intermediate, twoDate) * sign > 0) {
months -= sign;
}
@@ -3901,15 +3852,8 @@ static bool DifferenceNonISODate(JSContext* cx, CalendarId calendarId,
MOZ_ASSERT(CompareISODate(constrainedIso, two) * sign <= 0,
"constrained doesn't surpass two");
} else {
- CalendarDate oneDate;
- if (!ToCalendarDate(cx, calendarId, dtOne.get(), &oneDate)) {
- return false;
- }
-
- CalendarDate twoDate;
- if (!ToCalendarDate(cx, calendarId, dtTwo.get(), &twoDate)) {
- return false;
- }
+ auto oneDate = ToCalendarDate(calendarId, dtOne.get());
+ auto twoDate = ToCalendarDate(calendarId, dtTwo.get());
int32_t sign = -CompareCalendarDate(oneDate, twoDate);
MOZ_ASSERT(sign != 0);
@@ -3927,11 +3871,7 @@ static bool DifferenceNonISODate(JSContext* cx, CalendarId calendarId,
return false;
}
- CalendarDate constrainedDate;
- if (!ToCalendarDate(cx, calendarId, constrained.get(), &constrainedDate)) {
- return false;
- }
-
+ auto constrainedDate = ToCalendarDate(calendarId, constrained.get());
if (CompareCalendarDate(constrainedDate, twoDate) * sign > 0) {
years -= sign;
}