tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit bfe0ba28059f68ea14978aec8444ca51d26d6843
parent 86a9e3ee8607b9435a0924fa72e4c030648366bf
Author: André Bargull <andre.bargull@gmail.com>
Date:   Thu, 27 Nov 2025 10:03:36 +0000

Bug 1955545 - Part 3: Remove support for "islamic" and "islamic-rgsa" calendars in Intl. r=spidermonkey-reviewers,dminor

Implements `Intl` related changes from:
<https://github.com/tc39/proposal-intl-era-monthcode/pull/46>

Differential Revision: https://phabricator.services.mozilla.com/D272029

Diffstat:
Mjs/public/friend/ErrorNumbers.msg | 1+
Mjs/src/builtin/intl/DateTimeFormat.js | 10++++++++++
Mjs/src/builtin/intl/DisplayNames.js | 10++++++++++
Mjs/src/builtin/intl/IntlObject.cpp | 6++++--
Mjs/src/tests/jstests.list | 3---
Mjs/src/tests/non262/Intl/DateTimeFormat/calendar-option.js | 2++
Mjs/src/tests/non262/Intl/DateTimeFormat/islamic.js | 17-----------------
Mjs/src/tests/non262/Intl/DateTimeFormat/related-year.js | 2+-
Ajs/src/tests/non262/Intl/DateTimeFormat/report-warning-for-deprecated-islamic.js | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mjs/src/tests/non262/Temporal/Intl/defaults.js | 5-----
Mjs/src/tests/non262/Temporal/Intl/start-of-primary-calendar-era.js | 4----
Mjs/src/vm/SelfHosting.cpp | 49++++++++++++++++++++++++++++++++++++++++++-------
12 files changed, 147 insertions(+), 39 deletions(-)

diff --git a/js/public/friend/ErrorNumbers.msg b/js/public/friend/ErrorNumbers.msg @@ -652,6 +652,7 @@ MSG_DEF(JSMSG_INTL_DURATION_INVALID_DISPLAY_OPTION, 1, JSEXN_RANGEERR, "{0} can' MSG_DEF(JSMSG_INTL_DURATION_INVALID_DISPLAY_OPTION_DEFAULT_STYLE, 1, JSEXN_RANGEERR, "{0} can't use \"always\" display when style defaults to \"numeric\"") MSG_DEF(JSMSG_INTL_DURATION_INVALID_DISPLAY_OPTION_DEFAULT_DISPLAY, 1, JSEXN_RANGEERR, "{0} can't use \"numeric\" style when display defaults to \"always\"") MSG_DEF(JSMSG_INVALID_FORMAT_OPTIONS, 1, JSEXN_TYPEERR, "can't format {0} using the requested options") +MSG_DEF(JSMSG_DEPRECATED_CALENDAR, 1, JSEXN_WARN, "\"{0}\" is deprecated, use \"islamic-tbla\" instead") // RegExp MSG_DEF(JSMSG_BAD_CLASS_RANGE, 0, JSEXN_SYNTAXERR, "invalid range in character class") diff --git a/js/src/builtin/intl/DateTimeFormat.js b/js/src/builtin/intl/DateTimeFormat.js @@ -70,6 +70,16 @@ function resolveDateTimeFormatInternals(lazyDateTimeFormatData) { localeData ); + // Changes from "Intl era and monthCode" proposal. + // + // https://tc39.es/proposal-intl-era-monthcode/#sec-createdatetimeformat + if (r.ca === "islamic" || r.ca === "islamic-rgsa") { + ReportWarning(JSMSG_DEPRECATED_CALENDAR, r.ca); + + // Fallback to "islamic-tbla" calendar. + r.ca = "islamic-tbla"; + } + // Steps 19-22. internalProps.locale = r.locale; internalProps.calendar = r.ca; diff --git a/js/src/builtin/intl/DisplayNames.js b/js/src/builtin/intl/DisplayNames.js @@ -76,6 +76,16 @@ function resolveDisplayNamesInternals(lazyDisplayNamesData) { } if (mozExtensions) { + // Changes from "Intl era and monthCode" proposal. + // + // https://tc39.es/proposal-intl-era-monthcode/#sec-createdatetimeformat + if (r.ca === "islamic" || r.ca === "islamic-rgsa") { + ReportWarning(JSMSG_DEPRECATED_CALENDAR, r.ca); + + // Fallback to "islamic-tbla" calendar. + r.ca = "islamic-tbla"; + } + internalProps.calendar = r.ca; } diff --git a/js/src/builtin/intl/IntlObject.cpp b/js/src/builtin/intl/IntlObject.cpp @@ -556,8 +556,10 @@ static bool EnumerationIntoList(JSContext* cx, Enumeration values, * |Intl.supportedValuesOf()|. */ static constexpr auto UnsupportedCalendars() { - // No calendar values are currently unsupported. - return std::array<const char*, 0>{}; + return std::array{ + "islamic", + "islamic-rgsa", + }; } // Defined outside of the function to workaround bugs in GCC<9. diff --git a/js/src/tests/jstests.list b/js/src/tests/jstests.list @@ -1062,9 +1062,6 @@ skip-if(release_or_beta) script test262/staging/Intl402/Temporal/old/non-iso-cal skip-if(release_or_beta) script test262/staging/Intl402/Temporal/old/islamic-calendars-islamic-umalqura.js skip-if(release_or_beta) script test262/intl402/Temporal/PlainMonthDay/from/constrain-to-leap-day.js -# Try re-enabling when Bug 1954138 or Bug 1955545 are fixed. -skip script test262/intl402/DateTimeFormat/constructor-options-calendar-islamic-fallback.js - # https://github.com/tc39/proposal-intl-era-monthcode/issues/23. ICU4X 2.0 doesn't have inverse type skip script test262/staging/Intl402/Temporal/old/non-iso-calendars-coptic.js diff --git a/js/src/tests/non262/Intl/DateTimeFormat/calendar-option.js b/js/src/tests/non262/Intl/DateTimeFormat/calendar-option.js @@ -53,6 +53,8 @@ const calendars = [ const canonical = { "islamicc": "islamic-civil", "ethiopic-amete-alem": "ethioaa", + "islamic": "islamic-tbla", + "islamic-rgsa": "islamic-tbla", }; for (let calendar of calendars) { diff --git a/js/src/tests/non262/Intl/DateTimeFormat/islamic.js b/js/src/tests/non262/Intl/DateTimeFormat/islamic.js @@ -10,11 +10,6 @@ function tabularDate(options, date) { return new Intl.DateTimeFormat("ar-SA-u-ca-islamic-tbla-nu-latn", opts).format(date); } -function sightingDate(options, date) { - var opts = Object.assign({timeZone: "Asia/Riyadh"}, options); - return new Intl.DateTimeFormat("ar-SA-u-ca-islamic-rgsa-nu-latn", opts).format(date); -} - function ummAlQuraDate(options, date) { var opts = Object.assign({timeZone: "Asia/Riyadh"}, options); return new Intl.DateTimeFormat("ar-SA-u-ca-islamic-umalqura-nu-latn", opts).format(date); @@ -34,17 +29,6 @@ function testIslamicTbla() { assertEq(Number(civilDate(day, date)) - Number(tabularDate(day, date)), -1); } -// Test islamic-rgsa (Saudi Arabia sighting). -// Sighting of the hilal (crescent moon) in Saudi Arabia. -function testIslamicRgsa() { - var date1 = new Date(Date.UTC(1975, 5 - 1, 6)); - var date2 = new Date(Date.UTC(2015, 1 - 1, 1)); - var dayMonthYear = {year: "numeric", month: "numeric", day: "numeric"}; - - assertEq(sightingDate(dayMonthYear, date1), tabularDate(dayMonthYear, date1)); - assertEq(sightingDate(dayMonthYear, date2), civilDate(dayMonthYear, date2)); -} - // Test islamic-umalqura (Umm al-Qura). function testIslamicUmalqura() { var year = {year: "numeric"}; @@ -82,7 +66,6 @@ function testIslamicUmalqura() { } testIslamicTbla(); -testIslamicRgsa(); testIslamicUmalqura(); if (typeof reportCompare === "function") diff --git a/js/src/tests/non262/Intl/DateTimeFormat/related-year.js b/js/src/tests/non262/Intl/DateTimeFormat/related-year.js @@ -139,7 +139,7 @@ const tests = [ { date: new Date("2019-01-01T00:00:00Z"), options: {}, - calendar: "islamic", + calendar: "islamic-umalqura", locales: { "en": [Month("4"), Literal("/"), Day("25"), Literal("/"), Year("1440"), Literal(" "), Era("AH")], "ar-EG": [Day("٢٥"), Literal("\u200F/"), Month("٤"), Literal("\u200F/"), Year("١٤٤٠"), Literal(" "), Era("هـ")], diff --git a/js/src/tests/non262/Intl/DateTimeFormat/report-warning-for-deprecated-islamic.js b/js/src/tests/non262/Intl/DateTimeFormat/report-warning-for-deprecated-islamic.js @@ -0,0 +1,77 @@ +// |reftest| skip-if(!this.hasOwnProperty("Intl")||!xulRuntime.shell) + +const locales = [ + "en", "ar", "ar-SA", "ar-EG", +]; + +const deprecated = [ + "islamic", + "islamic-rgsa" +]; + +const supportedCalendars = Intl.supportedValuesOf("calendar"); + +function test(calendar, locale, options = undefined) { + // Enable warning reporter. + enableLastWarning(); + + // Create new DateTimeFormat. + let dtf = new Intl.DateTimeFormat(locale, options); + + // Options are lazily resolved... + let resolved = dtf.resolvedOptions(); + + // Inspect last warning. + if (deprecated.includes(calendar)) { + let warning = getLastWarning(); + assertEq(warning !== null, true, `missing warning for ${locale}`); + assertEq( + warning.message.includes(calendar), + true, + `warning "${warning}" doesn't include calendar "${calendar}"` + ); + + assertEq( + resolved.calendar, + "islamic-tbla", + `bad resolved fallback calendar for ${locale}` + ); + } else { + let warning = getLastWarning(); + assertEq(warning === null, true, `unexpected warning for ${locale}`); + + assertEq( + resolved.calendar, + calendar, + `bad resolved calendar for ${locale}` + ); + } + + // Disable warning reporter. + disableLastWarning(); +} + +for (let calendar of [...deprecated, ...supportedCalendars]) { + if (deprecated.includes(calendar)) { + assertEq( + supportedCalendars.includes(calendar), + false, + `${calendar} is deprecated` + ); + } + + for (let locale of locales) { + // Test as option. + test(calendar, locale, {calendar}); + + // Test as Unicode local extension. + test(calendar, locale + "-u-ca-" + calendar); + + // Also test with non-canonical case. + test(calendar, locale, {calendar: calendar.toUpperCase()}); + test(calendar, locale + "-u-ca-" + calendar.toUpperCase()); + } +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/non262/Temporal/Intl/defaults.js b/js/src/tests/non262/Temporal/Intl/defaults.js @@ -25,11 +25,6 @@ let plainTime = zonedDateTime.toPlainTime(); for (let locale of locales) { for (let calendar of Intl.supportedValuesOf("calendar")) { - // Invalid calendar identifiers for Temporal. - if (calendar === "islamic" || calendar === "islamic-rgsa") { - continue; - } - // Calendar must match for YearMonth and MonthDay. // // https://github.com/js-temporal/proposal-temporal-v2/issues/29 diff --git a/js/src/tests/non262/Temporal/Intl/start-of-primary-calendar-era.js b/js/src/tests/non262/Temporal/Intl/start-of-primary-calendar-era.js @@ -11,9 +11,7 @@ const calendars = { gregory: "0001-01-01", hebrew: "-003760-09-07", indian: "0079-03-22", - islamic: "0622-07-19", "islamic-civil": "0622-07-19", - "islamic-rgsa": "0622-07-19", "islamic-tbla": "0622-07-18", "islamic-umalqura": "0622-07-19", japanese: "0001-01-01", @@ -28,8 +26,6 @@ assertEqArray( // See bug 1950425. const calendarsNotEnabledInRelease = [ - "islamic", - "islamic-rgsa", "islamic-umalqura", ]; assertEq(calendarsNotEnabledInRelease.every(c => c in calendars), true); diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp @@ -97,6 +97,7 @@ #include "vm/ToSource.h" // js::ValueToSource #include "vm/TypedArrayObject.h" #include "vm/Uint8Clamped.h" +#include "vm/Warnings.h" #include "vm/WrapperObject.h" #include "gc/WeakMap-inl.h" @@ -310,25 +311,25 @@ static bool intrinsic_SubstringKernel(JSContext* cx, unsigned argc, Value* vp) { return true; } -static void ThrowErrorWithType(JSContext* cx, JSExnType type, - const CallArgs& args) { - MOZ_RELEASE_ASSERT(args[0].isInt32()); +static bool PrepareErrorArguments(JSContext* cx, JSExnType type, + const CallArgs& args, + UniqueChars (&errorArgs)[3]) { +#ifdef DEBUG + MOZ_ASSERT(args[0].isInt32()); uint32_t errorNumber = args[0].toInt32(); -#ifdef DEBUG const JSErrorFormatString* efs = GetErrorMessage(nullptr, errorNumber); MOZ_ASSERT(efs->argCount == args.length() - 1); MOZ_ASSERT(efs->exnType == type, "error-throwing intrinsic and error number are inconsistent"); #endif - UniqueChars errorArgs[3]; for (unsigned i = 1; i < 4 && i < args.length(); i++) { HandleValue val = args[i]; if (val.isInt32() || val.isString()) { JSString* str = ToString<CanGC>(cx, val); if (!str) { - return; + return false; } errorArgs[i - 1] = QuoteString(cx, str); } else { @@ -336,9 +337,21 @@ static void ThrowErrorWithType(JSContext* cx, JSExnType type, DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, nullptr); } if (!errorArgs[i - 1]) { - return; + return false; } } + return true; +} + +static void ThrowErrorWithType(JSContext* cx, JSExnType type, + const CallArgs& args) { + MOZ_RELEASE_ASSERT(args[0].isInt32()); + uint32_t errorNumber = args[0].toInt32(); + + UniqueChars errorArgs[3]; + if (!PrepareErrorArguments(cx, type, args, errorArgs)) { + return; + } JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, errorNumber, errorArgs[0].get(), errorArgs[1].get(), @@ -397,6 +410,27 @@ static bool intrinsic_CreateSuppressedError(JSContext* cx, unsigned argc, } #endif +static bool intrinsic_ReportWarning(JSContext* cx, unsigned argc, Value* vp) { + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() >= 1); + + MOZ_RELEASE_ASSERT(args[0].isInt32()); + uint32_t errorNumber = args[0].toInt32(); + + UniqueChars errorArgs[3]; + if (!PrepareErrorArguments(cx, JSEXN_WARN, args, errorArgs)) { + return false; + } + + if (!WarnNumberUTF8(cx, errorNumber, errorArgs[0].get(), errorArgs[1].get(), + errorArgs[2].get())) { + return false; + } + + args.rval().setUndefined(); + return true; +} + /** * Handles an assertion failure in self-hosted code just like an assertion * failure in C++ code. Information about the failure can be provided in @@ -1785,6 +1819,7 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_INLINABLE_FN("RegExpSearcher", RegExpSearcher, 3, 0, RegExpSearcher), JS_INLINABLE_FN("RegExpSearcherLastLimit", RegExpSearcherLastLimit, 0, 0, RegExpSearcherLastLimit), + JS_FN("ReportWarning", intrinsic_ReportWarning, 4, 0), JS_INLINABLE_FN("SameValue", js::obj_is, 2, 0, ObjectIs), JS_FN("SetCopy", SetObject::copy, 1, 0), JS_FN("StringReplaceAllString", intrinsic_StringReplaceAllString, 3, 0),