diff --git a/build/autoconf/icu.m4 b/build/autoconf/icu.m4 index 49896cae9a7c..6afa262b073e 100644 --- a/build/autoconf/icu.m4 +++ b/build/autoconf/icu.m4 @@ -14,7 +14,7 @@ MOZ_ARG_WITH_BOOL(system-icu, MOZ_SYSTEM_ICU=1) if test -n "$MOZ_SYSTEM_ICU"; then - PKG_CHECK_MODULES(MOZ_ICU, icu-i18n >= 64.1) + PKG_CHECK_MODULES(MOZ_ICU, icu-i18n >= 63.1) CFLAGS="$CFLAGS $MOZ_ICU_CFLAGS" CXXFLAGS="$CXXFLAGS $MOZ_ICU_CFLAGS" AC_DEFINE(MOZ_SYSTEM_ICU) diff --git a/config/check_spidermonkey_style.py b/config/check_spidermonkey_style.py index 11e80abc8499..9df1e412bcfa 100644 --- a/config/check_spidermonkey_style.py +++ b/config/check_spidermonkey_style.py @@ -97,7 +97,6 @@ included_inclnames_to_ignore = set([ 'unicode/udatpg.h', # ICU 'unicode/udisplaycontext.h', # ICU 'unicode/uenum.h', # ICU - 'unicode/uformattedvalue.h', # ICU 'unicode/uloc.h', # ICU 'unicode/unistr.h', # ICU 'unicode/unorm2.h', # ICU diff --git a/config/system-headers.mozbuild b/config/system-headers.mozbuild index 0af5e2afe22c..bcf5c4925564 100644 --- a/config/system-headers.mozbuild +++ b/config/system-headers.mozbuild @@ -1330,7 +1330,6 @@ if CONFIG['MOZ_SYSTEM_ICU']: 'unicode/udatpg.h', 'unicode/udisplaycontext.h', 'unicode/uenum.h', - 'unicode/uformattedvalue.h', 'unicode/unistr.h', 'unicode/unorm.h', 'unicode/unum.h', diff --git a/js/src/builtin/intl/DateTimeFormat.cpp b/js/src/builtin/intl/DateTimeFormat.cpp index 409078821593..fea9ed385c3c 100644 --- a/js/src/builtin/intl/DateTimeFormat.cpp +++ b/js/src/builtin/intl/DateTimeFormat.cpp @@ -946,13 +946,10 @@ bool js::intl_FormatDateTime(JSContext* cx, unsigned argc, Value* vp) { Rooted dateTimeFormat(cx); dateTimeFormat = &args[0].toObject().as(); - bool formatToParts = args[2].toBoolean(); - ClippedTime x = TimeClip(args[1].toNumber()); if (!x.isValid()) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, - JSMSG_DATE_NOT_FINITE, "DateTimeFormat", - formatToParts ? "formatToParts" : "format"); + JSMSG_DATE_NOT_FINITE, "DateTimeFormat"); return false; } @@ -971,6 +968,7 @@ bool js::intl_FormatDateTime(JSContext* cx, unsigned argc, Value* vp) { } // Use the UDateFormat to actually format the time stamp. - return formatToParts ? intl_FormatToPartsDateTime(cx, df, x, args.rval()) - : intl_FormatDateTime(cx, df, x, args.rval()); + return args[2].toBoolean() + ? intl_FormatToPartsDateTime(cx, df, x, args.rval()) + : intl_FormatDateTime(cx, df, x, args.rval()); } diff --git a/js/src/builtin/intl/ICUStubs.h b/js/src/builtin/intl/ICUStubs.h index f7e3f586c5d5..6272bf056b62 100644 --- a/js/src/builtin/intl/ICUStubs.h +++ b/js/src/builtin/intl/ICUStubs.h @@ -28,7 +28,6 @@ # include "unicode/udatpg.h" # include "unicode/udisplaycontext.h" # include "unicode/uenum.h" -# include "unicode/uformattedvalue.h" # include "unicode/uloc.h" # include "unicode/unum.h" # include "unicode/unumsys.h" @@ -47,6 +46,8 @@ #if !ENABLE_INTL_API +# define U_ICU_VERSION_MAJOR_NUM 64 + enum UErrorCode { U_ZERO_ERROR, U_BUFFER_OVERFLOW_ERROR, @@ -673,74 +674,6 @@ inline int32_t ureldatefmt_formatNumeric( MOZ_CRASH("ureldatefmt_formatNumeric: Intl API disabled"); } -struct UFormattedRelativeDateTime; - -inline UFormattedRelativeDateTime* ureldatefmt_openResult(UErrorCode* status) { - MOZ_CRASH("ureldatefmt_openResult: Intl API disabled"); -} - -inline void ureldatefmt_closeResult(UFormattedRelativeDateTime* ufrdt) { - MOZ_CRASH("ureldatefmt_closeResult: Intl API disabled"); -} - -inline void ureldatefmt_formatToResult( - const URelativeDateTimeFormatter* reldatefmt, double offset, - URelativeDateTimeUnit unit, UFormattedRelativeDateTime* result, - UErrorCode* status) { - MOZ_CRASH("ureldatefmt_formatToResult: Intl API disabled"); -} - -inline void ureldatefmt_formatNumericToResult( - const URelativeDateTimeFormatter* reldatefmt, double offset, - URelativeDateTimeUnit unit, UFormattedRelativeDateTime* result, - UErrorCode* status) { - MOZ_CRASH("ureldatefmt_formatToResult: Intl API disabled"); -} - -struct UFormattedValue; - -inline const UFormattedValue* ureldatefmt_resultAsValue( - const UFormattedRelativeDateTime* ufrdt, UErrorCode* status) { - MOZ_CRASH("ureldatefmt_resultAsValue: Intl API disabled"); -} - -inline const UChar* ufmtval_getString(const UFormattedValue* ufmtval, - int32_t* pLength, UErrorCode* status) { - MOZ_CRASH("ufmtval_getString: Intl API disabled"); -} - -inline UConstrainedFieldPosition* ucfpos_open(UErrorCode* status) { - MOZ_CRASH("ucfpos_open: Intl API disabled"); -} - -inline void ucfpos_close(UConstrainedFieldPosition* ucfpos) { - MOZ_CRASH("ucfpos_close: Intl API disabled"); -} - -typedef enum UFieldCategory { UFIELD_CATEGORY_NUMBER } UFieldCategory; - -inline void ucfpos_constrainCategory(UConstrainedFieldPosition* ucfpos, - int32_t category, UErrorCode* status) { - MOZ_CRASH("ucfpos_constrainCategory: Intl API disabled"); -} - -inline bool ufmtval_nextPosition(const UFormattedValue* ufmtval, - UConstrainedFieldPosition* ucfpos, - UErrorCode* status) { - MOZ_CRASH("ufmtval_nextPosition: Intl API disabled"); -} - -inline int32_t ucfpos_getField(const UConstrainedFieldPosition* ucfpos, - UErrorCode* status) { - MOZ_CRASH("ucfpos_getField: Intl API disabled"); -} - -inline void ucfpos_getIndexes(const UConstrainedFieldPosition* ucfpos, - int32_t* pStart, int32_t* pLimit, - UErrorCode* status) { - MOZ_CRASH("ucfpos_getIndexes: Intl API disabled"); -} - #endif // !ENABLE_INTL_API #endif /* builtin_intl_ICUStubs_h */ diff --git a/js/src/builtin/intl/NumberFormat.cpp b/js/src/builtin/intl/NumberFormat.cpp index f0a03dc0d5bb..7b49dec41899 100644 --- a/js/src/builtin/intl/NumberFormat.cpp +++ b/js/src/builtin/intl/NumberFormat.cpp @@ -433,8 +433,10 @@ static bool intl_FormatNumber(JSContext* cx, UNumberFormat* nf, double x, return true; } -static intl::FieldType GetFieldTypeForNumberField(UNumberFormatFields fieldName, - double d) { +using FieldType = ImmutablePropertyNamePtr JSAtomState::*; + +static FieldType GetFieldTypeForNumberField(UNumberFormatFields fieldName, + double d) { // See intl/icu/source/i18n/unicode/unum.h for a detailed field list. This // list is deliberately exhaustive: cases might have to be added/removed if // this code is compiled with a different ICU with more UNumberFormatFields @@ -494,6 +496,7 @@ static intl::FieldType GetFieldTypeForNumberField(UNumberFormatFields fieldName, break; #ifndef U_HIDE_DRAFT_API +# if U_ICU_VERSION_MAJOR_NUM >= 64 case UNUM_MEASURE_UNIT_FIELD: MOZ_ASSERT_UNREACHABLE( "unexpected measure unit field found, even though " @@ -507,6 +510,7 @@ static intl::FieldType GetFieldTypeForNumberField(UNumberFormatFields fieldName, "we don't use any user-defined patterns that " "would require a compact number notation"); break; +# endif #endif #ifndef U_HIDE_DEPRECATED_API @@ -524,29 +528,72 @@ static intl::FieldType GetFieldTypeForNumberField(UNumberFormatFields fieldName, return nullptr; } -bool js::intl::NumberFormatFields::append(int32_t field, int32_t begin, - int32_t end) { - MOZ_ASSERT(begin >= 0); - MOZ_ASSERT(end >= 0); - MOZ_ASSERT(begin < end, "erm, aren't fields always non-empty?"); +static bool intl_FormatNumberToParts(JSContext* cx, UNumberFormat* nf, double x, + MutableHandleValue result) { + UErrorCode status = U_ZERO_ERROR; - FieldType type = - GetFieldTypeForNumberField(UNumberFormatFields(field), number_); - return fields_.emplaceBack(uint32_t(begin), uint32_t(end), type); -} + UFieldPositionIterator* fpositer = ufieldpositer_open(&status); + if (U_FAILURE(status)) { + intl::ReportInternalError(cx); + return false; + } -ArrayObject* js::intl::NumberFormatFields::toArray(JSContext* cx, - HandleString overallResult, - FieldType unitType) { - // Merge sort the fields vector. Expand the vector to have scratch space for - // performing the sort. - size_t fieldsLen = fields_.length(); - if (!fields_.resizeUninitialized(fieldsLen * 2)) { - return nullptr; + MOZ_ASSERT(fpositer); + ScopedICUObject toClose( + fpositer); + + RootedString overallResult(cx, PartitionNumberPattern(cx, nf, &x, fpositer)); + if (!overallResult) { + return false; + } + + RootedArrayObject partsArray(cx, NewDenseEmptyArray(cx)); + if (!partsArray) { + return false; + } + + // First, vacuum up fields in the overall formatted string. + + struct Field { + uint32_t begin; + uint32_t end; + FieldType type; + + // Needed for vector-resizing scratch space. + Field() = default; + + Field(uint32_t begin, uint32_t end, FieldType type) + : begin(begin), end(end), type(type) {} + }; + + using FieldsVector = Vector; + FieldsVector fields(cx); + + int32_t fieldInt, beginIndexInt, endIndexInt; + while ((fieldInt = ufieldpositer_next(fpositer, &beginIndexInt, + &endIndexInt)) >= 0) { + MOZ_ASSERT(beginIndexInt >= 0); + MOZ_ASSERT(endIndexInt >= 0); + MOZ_ASSERT(beginIndexInt < endIndexInt, + "erm, aren't fields always non-empty?"); + + FieldType type = + GetFieldTypeForNumberField(UNumberFormatFields(fieldInt), x); + if (!fields.emplaceBack(uint32_t(beginIndexInt), uint32_t(endIndexInt), + type)) { + return false; + } + } + + // Second, merge sort the fields vector. Expand the vector to have scratch + // space for performing the sort. + size_t fieldsLen = fields.length(); + if (!fields.resizeUninitialized(fieldsLen * 2)) { + return false; } MOZ_ALWAYS_TRUE(MergeSort( - fields_.begin(), fieldsLen, fields_.begin() + fieldsLen, + fields.begin(), fieldsLen, fields.begin() + fieldsLen, [](const Field& left, const Field& right, bool* lessOrEqual) { // Sort first by begin index, then to place // enclosing fields before nested fields. @@ -556,13 +603,13 @@ ArrayObject* js::intl::NumberFormatFields::toArray(JSContext* cx, })); // Deallocate the scratch space. - if (!fields_.resize(fieldsLen)) { - return nullptr; + if (!fields.resize(fieldsLen)) { + return false; } - // Then iterate over the sorted field list to generate a sequence of parts - // (what ECMA-402 actually exposes). A part is a maximal character sequence - // entirely within no field or a single most-nested field. + // Third, iterate over the sorted field list to generate a sequence of + // parts (what ECMA-402 actually exposes). A part is a maximal character + // sequence entirely within no field or a single most-nested field. // // Diagrams may be helpful to illustrate how fields map to parts. Consider // formatting -19,766,580,028,249.41, the US national surplus (negative @@ -767,17 +814,12 @@ ArrayObject* js::intl::NumberFormatFields::toArray(JSContext* cx, RootedObject singlePart(cx); RootedValue propVal(cx); - RootedArrayObject partsArray(cx, NewDenseEmptyArray(cx)); - if (!partsArray) { - return nullptr; - } - - PartGenerator gen(cx, fields_, overallResult->length()); + PartGenerator gen(cx, fields, overallResult->length()); do { bool hasPart; Part part; if (!gen.nextPart(&hasPart, &part)) { - return nullptr; + return false; } if (!hasPart) { @@ -791,35 +833,28 @@ ArrayObject* js::intl::NumberFormatFields::toArray(JSContext* cx, singlePart = NewBuiltinClassInstance(cx); if (!singlePart) { - return nullptr; + return false; } propVal.setString(cx->names().*type); if (!DefineDataProperty(cx, singlePart, cx->names().type, propVal)) { - return nullptr; + return false; } JSLinearString* partSubstr = NewDependentString( cx, overallResult, lastEndIndex, endIndex - lastEndIndex); if (!partSubstr) { - return nullptr; + return false; } propVal.setString(partSubstr); if (!DefineDataProperty(cx, singlePart, cx->names().value, propVal)) { - return nullptr; - } - - if (unitType != nullptr && type != &JSAtomState::literal) { - propVal.setString(cx->names().*unitType); - if (!DefineDataProperty(cx, singlePart, cx->names().unit, propVal)) { - return nullptr; - } + return false; } propVal.setObject(*singlePart); if (!DefineDataElement(cx, partsArray, partIndex, propVal)) { - return nullptr; + return false; } lastEndIndex = endIndex; @@ -829,45 +864,7 @@ ArrayObject* js::intl::NumberFormatFields::toArray(JSContext* cx, MOZ_ASSERT(lastEndIndex == overallResult->length(), "result array must partition the entire string"); - return partsArray; -} - -static bool intl_FormatNumberToParts(JSContext* cx, UNumberFormat* nf, double x, - MutableHandleValue result) { - UErrorCode status = U_ZERO_ERROR; - - UFieldPositionIterator* fpositer = ufieldpositer_open(&status); - if (U_FAILURE(status)) { - intl::ReportInternalError(cx); - return false; - } - - MOZ_ASSERT(fpositer); - ScopedICUObject toClose( - fpositer); - - RootedString overallResult(cx, PartitionNumberPattern(cx, nf, &x, fpositer)); - if (!overallResult) { - return false; - } - - // Vacuum up fields in the overall formatted string. - - intl::NumberFormatFields fields(cx, x); - - int32_t field, beginIndex, endIndex; - while ((field = ufieldpositer_next(fpositer, &beginIndex, &endIndex)) >= 0) { - if (!fields.append(field, beginIndex, endIndex)) { - return false; - } - } - - ArrayObject* array = fields.toArray(cx, overallResult, nullptr); - if (!array) { - return false; - } - - result.setObject(*array); + result.setObject(*partsArray); return true; } diff --git a/js/src/builtin/intl/NumberFormat.h b/js/src/builtin/intl/NumberFormat.h index 5384da14d263..b6c2458ba2ce 100644 --- a/js/src/builtin/intl/NumberFormat.h +++ b/js/src/builtin/intl/NumberFormat.h @@ -12,15 +12,11 @@ #include #include "builtin/SelfHostingDefines.h" -#include "gc/Barrier.h" #include "js/Class.h" -#include "js/Vector.h" #include "vm/NativeObject.h" -#include "vm/Runtime.h" namespace js { -class ArrayObject; class FreeOp; class NumberFormatObject : public NativeObject { @@ -88,40 +84,6 @@ extern MOZ_MUST_USE bool intl_numberingSystem(JSContext* cx, unsigned argc, extern MOZ_MUST_USE bool intl_FormatNumber(JSContext* cx, unsigned argc, Value* vp); -namespace intl { - -using FieldType = js::ImmutablePropertyNamePtr JSAtomState::*; - -struct Field { - uint32_t begin; - uint32_t end; - FieldType type; - - // Needed for vector-resizing scratch space. - Field() = default; - - Field(uint32_t begin, uint32_t end, FieldType type) - : begin(begin), end(end), type(type) {} -}; - -class NumberFormatFields { - using FieldsVector = Vector; - - FieldsVector fields_; - double number_; - - public: - NumberFormatFields(JSContext* cx, double number) - : fields_(cx), number_(number) {} - - MOZ_MUST_USE bool append(int32_t field, int32_t begin, int32_t end); - - MOZ_MUST_USE ArrayObject* toArray(JSContext* cx, - JS::HandleString overallResult, - FieldType unitType); -}; - -} // namespace intl } // namespace js #endif /* builtin_intl_NumberFormat_h */ diff --git a/js/src/builtin/intl/RelativeTimeFormat.cpp b/js/src/builtin/intl/RelativeTimeFormat.cpp index 86aaa83735b9..e91535fa1b96 100644 --- a/js/src/builtin/intl/RelativeTimeFormat.cpp +++ b/js/src/builtin/intl/RelativeTimeFormat.cpp @@ -13,19 +13,19 @@ #include "builtin/intl/CommonFunctions.h" #include "builtin/intl/ICUStubs.h" -#include "builtin/intl/NumberFormat.h" #include "builtin/intl/ScopedICUObject.h" #include "gc/FreeOp.h" #include "js/CharacterEncoding.h" #include "js/PropertySpec.h" #include "vm/GlobalObject.h" #include "vm/JSContext.h" -#include "vm/StringType.h" #include "vm/NativeObject-inl.h" using namespace js; +using mozilla::IsNegativeZero; + using js::intl::CallICU; using js::intl::GetAvailableLocales; using js::intl::IcuLocale; @@ -63,10 +63,6 @@ static const JSFunctionSpec relativeTimeFormat_methods[] = { JS_SELF_HOSTED_FN("resolvedOptions", "Intl_RelativeTimeFormat_resolvedOptions", 0, 0), JS_SELF_HOSTED_FN("format", "Intl_RelativeTimeFormat_format", 2, 0), -#ifndef U_HIDE_DRAFT_API - JS_SELF_HOSTED_FN("formatToParts", "Intl_RelativeTimeFormat_formatToParts", - 2, 0), -#endif JS_FN(js_toSource_str, relativeTimeFormat_toSource, 0, 0), JS_FS_END}; static const JSPropertySpec relativeTimeFormat_properties[] = { @@ -261,176 +257,14 @@ enum class RelativeTimeNumeric { Auto, }; -static bool intl_FormatRelativeTime(JSContext* cx, - URelativeDateTimeFormatter* rtf, double t, - URelativeDateTimeUnit unit, - RelativeTimeNumeric numeric, - MutableHandleValue result) { - JSString* str = CallICU( - cx, - [rtf, t, unit, numeric](UChar* chars, int32_t size, UErrorCode* status) { - auto fmt = numeric == RelativeTimeNumeric::Auto - ? ureldatefmt_format - : ureldatefmt_formatNumeric; - return fmt(rtf, t, unit, chars, size, status); - }); - if (!str) { - return false; - } - - result.setString(str); - return true; -} - -#ifndef U_HIDE_DRAFT_API -static bool intl_FormatToPartsRelativeTime(JSContext* cx, - URelativeDateTimeFormatter* rtf, - double t, URelativeDateTimeUnit unit, - RelativeTimeNumeric numeric, - MutableHandleValue result) { - UErrorCode status = U_ZERO_ERROR; - UFormattedRelativeDateTime* formatted = ureldatefmt_openResult(&status); - if (U_FAILURE(status)) { - intl::ReportInternalError(cx); - return false; - } - ScopedICUObject toClose( - formatted); - - if (numeric == RelativeTimeNumeric::Auto) { - ureldatefmt_formatToResult(rtf, t, unit, formatted, &status); - } else { - ureldatefmt_formatNumericToResult(rtf, t, unit, formatted, &status); - } - if (U_FAILURE(status)) { - intl::ReportInternalError(cx); - return false; - } - - const UFormattedValue* formattedValue = - ureldatefmt_resultAsValue(formatted, &status); - if (U_FAILURE(status)) { - intl::ReportInternalError(cx); - return false; - } - - int32_t strLength; - const char16_t* str = ufmtval_getString(formattedValue, &strLength, &status); - if (U_FAILURE(status)) { - intl::ReportInternalError(cx); - return false; - } - MOZ_ASSERT(strLength >= 0); - - RootedString overallResult(cx, - NewStringCopyN(cx, str, size_t(strLength))); - if (!overallResult) { - return false; - } - - intl::FieldType unitType; - switch (unit) { - case UDAT_REL_UNIT_SECOND: - unitType = &JSAtomState::second; - break; - case UDAT_REL_UNIT_MINUTE: - unitType = &JSAtomState::minute; - break; - case UDAT_REL_UNIT_HOUR: - unitType = &JSAtomState::hour; - break; - case UDAT_REL_UNIT_DAY: - unitType = &JSAtomState::day; - break; - case UDAT_REL_UNIT_WEEK: - unitType = &JSAtomState::week; - break; - case UDAT_REL_UNIT_MONTH: - unitType = &JSAtomState::month; - break; - case UDAT_REL_UNIT_QUARTER: - unitType = &JSAtomState::quarter; - break; - case UDAT_REL_UNIT_YEAR: - unitType = &JSAtomState::year; - break; - default: - MOZ_CRASH("unexpected relative time unit"); - } - - UConstrainedFieldPosition* fpos = ucfpos_open(&status); - if (U_FAILURE(status)) { - intl::ReportInternalError(cx); - return false; - } - ScopedICUObject toCloseFpos(fpos); - - // The possible field position categories are UFIELD_CATEGORY_NUMBER and - // UFIELD_CATEGORY_RELATIVE_DATETIME. For the parts array we only need to - // iterate over the number formatted fields. - ucfpos_constrainCategory(fpos, UFIELD_CATEGORY_NUMBER, &status); - if (U_FAILURE(status)) { - intl::ReportInternalError(cx); - return false; - } - - intl::NumberFormatFields fields(cx, t); - - while (true) { - bool hasMore = ufmtval_nextPosition(formattedValue, fpos, &status); - if (U_FAILURE(status)) { - intl::ReportInternalError(cx); - return false; - } - if (!hasMore) { - break; - } - - int32_t field = ucfpos_getField(fpos, &status); - if (U_FAILURE(status)) { - intl::ReportInternalError(cx); - return false; - } - - int32_t beginIndex, endIndex; - ucfpos_getIndexes(fpos, &beginIndex, &endIndex, &status); - if (U_FAILURE(status)) { - intl::ReportInternalError(cx); - return false; - } - - if (!fields.append(field, beginIndex, endIndex)) { - return false; - } - } - - ArrayObject* array = fields.toArray(cx, overallResult, unitType); - if (!array) { - return false; - } - - result.setObject(*array); - return true; -} -#endif - bool js::intl_FormatRelativeTime(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - MOZ_ASSERT(args.length() == 5); + MOZ_ASSERT(args.length() == 4); Rooted relativeTimeFormat(cx); relativeTimeFormat = &args[0].toObject().as(); - bool formatToParts = args[4].toBoolean(); - - // PartitionRelativeTimePattern, step 4. double t = args[1].toNumber(); - if (!mozilla::IsFinite(t)) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, - JSMSG_DATE_NOT_FINITE, "RelativeTimeFormat", - formatToParts ? "formatToParts" : "format"); - return false; - } // Obtain a cached URelativeDateTimeFormatter object. constexpr auto RT_FORMAT_SLOT = @@ -453,7 +287,6 @@ bool js::intl_FormatRelativeTime(JSContext* cx, unsigned argc, Value* vp) { return false; } - // PartitionRelativeTimePattern, step 5. if (StringEqualsAscii(unit, "second") || StringEqualsAscii(unit, "seconds")) { relDateTimeUnit = UDAT_REL_UNIT_SECOND; @@ -475,16 +308,10 @@ bool js::intl_FormatRelativeTime(JSContext* cx, unsigned argc, Value* vp) { } else if (StringEqualsAscii(unit, "quarter") || StringEqualsAscii(unit, "quarters")) { relDateTimeUnit = UDAT_REL_UNIT_QUARTER; - } else if (StringEqualsAscii(unit, "year") || - StringEqualsAscii(unit, "years")) { - relDateTimeUnit = UDAT_REL_UNIT_YEAR; } else { - if (auto unitChars = StringToNewUTF8CharsZ(cx, *unit)) { - JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, - JSMSG_INVALID_OPTION_VALUE, "unit", - unitChars.get()); - } - return false; + MOZ_ASSERT(StringEqualsAscii(unit, "year") || + StringEqualsAscii(unit, "years")); + relDateTimeUnit = UDAT_REL_UNIT_YEAR; } } @@ -503,15 +330,18 @@ bool js::intl_FormatRelativeTime(JSContext* cx, unsigned argc, Value* vp) { } } -#ifndef U_HIDE_DRAFT_API - return formatToParts - ? intl_FormatToPartsRelativeTime(cx, rtf, t, relDateTimeUnit, - relDateTimeNumeric, args.rval()) - : intl_FormatRelativeTime(cx, rtf, t, relDateTimeUnit, - relDateTimeNumeric, args.rval()); -#else - MOZ_ASSERT(!formatToParts); - return intl_FormatRelativeTime(cx, rtf, t, relDateTimeUnit, - relDateTimeNumeric, args.rval()); -#endif + JSString* str = + CallICU(cx, [rtf, t, relDateTimeUnit, relDateTimeNumeric]( + UChar* chars, int32_t size, UErrorCode* status) { + auto fmt = relDateTimeNumeric == RelativeTimeNumeric::Auto + ? ureldatefmt_format + : ureldatefmt_formatNumeric; + return fmt(rtf, t, relDateTimeUnit, chars, size, status); + }); + if (!str) { + return false; + } + + args.rval().setString(str); + return true; } diff --git a/js/src/builtin/intl/RelativeTimeFormat.h b/js/src/builtin/intl/RelativeTimeFormat.h index b3c71404cb30..9574c215d059 100644 --- a/js/src/builtin/intl/RelativeTimeFormat.h +++ b/js/src/builtin/intl/RelativeTimeFormat.h @@ -62,7 +62,7 @@ extern MOZ_MUST_USE bool intl_RelativeTimeFormat_availableLocales( * |numeric| should be "always" or "auto". * * Usage: formatted = intl_FormatRelativeTime(relativeTimeFormat, t, - * unit, numeric, formatToParts) + * unit, numeric) */ extern MOZ_MUST_USE bool intl_FormatRelativeTime(JSContext* cx, unsigned argc, JS::Value* vp); diff --git a/js/src/builtin/intl/RelativeTimeFormat.js b/js/src/builtin/intl/RelativeTimeFormat.js index 7ce9df5fc96a..e5570930c383 100644 --- a/js/src/builtin/intl/RelativeTimeFormat.js +++ b/js/src/builtin/intl/RelativeTimeFormat.js @@ -201,48 +201,42 @@ function Intl_RelativeTimeFormat_format(value, unit) { // Step 4. let u = ToString(unit); - // Step 5. - return intl_FormatRelativeTime(relativeTimeFormat, t, u, internals.numeric, - false); -} - -/** - * Returns an Array composed of the components of a relative date formatted - * according to the effective locale and the formatting options of this - * RelativeTimeFormat object. - * - * Spec: ECMAScript 402 API, RelativeTImeFormat, 1.4.4. - */ -function Intl_RelativeTimeFormat_formatToParts(value, unit) { - // Step 1. - let relativeTimeFormat = this; - - // Step 2. - if (!IsObject(relativeTimeFormat) || - (relativeTimeFormat = GuardToRelativeTimeFormat(relativeTimeFormat)) === null) - { - return callFunction(CallRelativeTimeFormatMethodIfWrapped, this, value, unit, - "Intl_RelativeTimeFormat_formatToParts"); + // PartitionRelativeTimePattern, step 4. + if (!Number_isFinite(t)) { + ThrowRangeError(JSMSG_DATE_NOT_FINITE, "RelativeTimeFormat"); } - // Ensure the RelativeTimeFormat internals are resolved. - var internals = getRelativeTimeFormatInternals(relativeTimeFormat); - - // Step 3. - let t = ToNumber(value); - - // Step 4. - let u = ToString(unit); + // PartitionRelativeTimePattern, step 5. + switch (u) { + case "second": + case "seconds": + case "minute": + case "minutes": + case "hour": + case "hours": + case "day": + case "days": + case "week": + case "weeks": + case "month": + case "months": + case "quarter": + case "quarters": + case "year": + case "years": + break; + default: + ThrowRangeError(JSMSG_INVALID_OPTION_VALUE, "unit", u); + } // Step 5. - return intl_FormatRelativeTime(relativeTimeFormat, t, u, internals.numeric, - true); + return intl_FormatRelativeTime(relativeTimeFormat, t, u, internals.numeric); } /** * Returns the resolved options for a RelativeTimeFormat object. * - * Spec: ECMAScript 402 API, RelativeTimeFormat, 1.4.5. + * Spec: ECMAScript 402 API, RelativeTimeFormat, 1.4.4. */ function Intl_RelativeTimeFormat_resolvedOptions() { // Step 1. diff --git a/js/src/js.msg b/js/src/js.msg index bb0dfcaa73dc..3318d0a767d3 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -519,7 +519,7 @@ MSG_DEF(JSMSG_TESTING_SCRIPTS_ONLY, 0, JSEXN_TYPEERR, "only works on scripts") MSG_DEF(JSMSG_TRACELOGGER_ENABLE_FAIL, 1, JSEXN_ERR, "enabling tracelogger failed: {0}") // Intl -MSG_DEF(JSMSG_DATE_NOT_FINITE, 2, JSEXN_RANGEERR, "date value is not finite in {0}.{1}()") +MSG_DEF(JSMSG_DATE_NOT_FINITE, 1, JSEXN_RANGEERR, "date value is not finite in {0}.format()") MSG_DEF(JSMSG_INTERNAL_INTL_ERROR, 0, JSEXN_ERR, "internal error while computing Intl data") MSG_DEF(JSMSG_INVALID_CURRENCY_CODE, 1, JSEXN_RANGEERR, "invalid currency code in NumberFormat(): {0}") MSG_DEF(JSMSG_INVALID_DIGITS_VALUE, 1, JSEXN_RANGEERR, "invalid digits value: {0}") diff --git a/js/src/tests/jstests.list b/js/src/tests/jstests.list index 2c3c2e49ee62..162856a4f900 100644 --- a/js/src/tests/jstests.list +++ b/js/src/tests/jstests.list @@ -16,7 +16,6 @@ slow script test262/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js skip-if((xulRuntime.XPCOMABI.match(/aarch64/))&&(xulRuntime.OS=="WINNT")) script non262/Math/fround.js skip-if((xulRuntime.XPCOMABI.match(/aarch64/))&&(xulRuntime.OS=="WINNT")) script non262/Math/log2-approx.js - ########################################################################### # Generated jstests.list for test262 when inline |reftest| isn't possible # ########################################################################### @@ -437,6 +436,9 @@ skip script test262/annexB/built-ins/Function/createdynfn-no-line-terminator-htm # https://bugzilla.mozilla.org/show_bug.cgi?id=1462745 skip script test262/annexB/language/function-code/block-decl-nested-blocks-with-fun-decl.js +# https://bugzilla.mozilla.org/show_bug.cgi?id=1473229 +skip include test262/intl402/RelativeTimeFormat/prototype/formatToParts/jstests.list + # https://bugzilla.mozilla.org/show_bug.cgi?id=1508683 skip script test262/built-ins/RegExp/prototype/multiline/cross-realm.js skip script test262/built-ins/RegExp/prototype/global/cross-realm.js diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index 9f160ad78264..da00e2f856b7 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -341,7 +341,6 @@ MACRO(proto, proto, "__proto__") \ MACRO(prototype, prototype, "prototype") \ MACRO(proxy, proxy, "proxy") \ - MACRO(quarter, quarter, "quarter") \ MACRO(raw, raw, "raw") \ MACRO(reason, reason, "reason") \ MACRO(RegExpBuiltinExec, RegExpBuiltinExec, "RegExpBuiltinExec") \ @@ -457,7 +456,6 @@ MACRO(WeakSetConstructorInit, WeakSetConstructorInit, \ "WeakSetConstructorInit") \ MACRO(WeakSet_add, WeakSet_add, "WeakSet_add") \ - MACRO(week, week, "week") \ MACRO(weekday, weekday, "weekday") \ MACRO(weekendEnd, weekendEnd, "weekendEnd") \ MACRO(weekendStart, weekendStart, "weekendStart") \