Diff
Modified: trunk/JSTests/ChangeLog (267499 => 267500)
--- trunk/JSTests/ChangeLog 2020-09-23 21:17:06 UTC (rev 267499)
+++ trunk/JSTests/ChangeLog 2020-09-23 21:26:09 UTC (rev 267500)
@@ -1,3 +1,13 @@
+2020-09-23 Yusuke Suzuki <[email protected]>
+
+ [JSC] Intl spec update: handle awkward rounding behavior
+ https://bugs.webkit.org/show_bug.cgi?id=216760
+
+ Reviewed by Ross Kirsling.
+
+ * stress/intl-numberformat.js:
+ * test262/expectations.yaml:
+
2020-09-23 Caio Lima <[email protected]>
[JSC][ESNext] Create a new opcode to handle private fields store/define
Modified: trunk/JSTests/stress/intl-numberformat.js (267499 => 267500)
--- trunk/JSTests/stress/intl-numberformat.js 2020-09-23 21:17:06 UTC (rev 267499)
+++ trunk/JSTests/stress/intl-numberformat.js 2020-09-23 21:26:09 UTC (rev 267500)
@@ -459,3 +459,63 @@
shouldBe(Intl.NumberFormat('ar').format(123456789n), '١٢٣٬٤٥٦٬٧٨٩');
shouldBe(Intl.NumberFormat('zh-Hans-CN-u-nu-hanidec').format(123456789n), '一二三,四五六,七八九');
shouldBe(Intl.NumberFormat('en', { maximumSignificantDigits: 3 }).format(123456n), '123,000');
+
+{
+ let nf = new Intl.NumberFormat('en', {
+ style: 'currency',
+ currency: 'USD',
+ maximumFractionDigits: 1
+ });
+ shouldBe(nf.resolvedOptions().maximumFractionDigits, 1);
+ shouldBe(nf.resolvedOptions().minimumFractionDigits, 1);
+ shouldBe(nf.format(30.333333333333), `$30.3`);
+ shouldBe(nf.format(30.35), `$30.4`);
+ shouldBe(nf.format(30), `$30.0`);
+}
+{
+ let nf = new Intl.NumberFormat('en', {
+ style: 'currency',
+ currency: 'USD',
+ maximumFractionDigits: 0
+ });
+ shouldBe(nf.resolvedOptions().maximumFractionDigits, 0);
+ shouldBe(nf.resolvedOptions().minimumFractionDigits, 0);
+ shouldBe(nf.format(30.3), `$30`);
+ shouldBe(nf.format(30.5), `$31`);
+ shouldBe(nf.format(30), `$30`);
+}
+{
+ let nf = new Intl.NumberFormat('en', {
+ style: 'currency',
+ currency: 'CLF',
+ maximumFractionDigits: 3
+ });
+ shouldBe(nf.resolvedOptions().maximumFractionDigits, 3);
+ shouldBe(nf.resolvedOptions().minimumFractionDigits, 3);
+ if ($vm.icuVersion() >= 64) {
+ shouldBe([`CLF 30.333`, `CLF 30.333`].includes(nf.format(30.333333333333)), true);
+ shouldBe([`CLF 30.000`, `CLF 30.000`].includes(nf.format(30)), true);
+ }
+}
+{
+ let nf = new Intl.NumberFormat('en', {
+ style: 'currency',
+ currency: 'CLF',
+ maximumFractionDigits: 0
+ });
+ shouldBe(nf.resolvedOptions().maximumFractionDigits, 0);
+ shouldBe(nf.resolvedOptions().minimumFractionDigits, 0);
+ if ($vm.icuVersion() >= 64) {
+ shouldBe([`CLF 30`, `CLF 30`].includes(nf.format(30.333333333333)), true);
+ shouldBe([`CLF 31`, `CLF 31`].includes(nf.format(30.5)), true);
+ shouldBe([`CLF 30`, `CLF 30`].includes(nf.format(30)), true);
+ }
+}
+shouldThrow(() => {
+ let nf = new Intl.NumberFormat('en', {
+ style: 'currency',
+ currency: 'CLF',
+ maximumFractionDigits: 0,
+ minimumFractionDigits: 100
+ });
+}, RangeError);
Modified: trunk/JSTests/test262/expectations.yaml (267499 => 267500)
--- trunk/JSTests/test262/expectations.yaml 2020-09-23 21:17:06 UTC (rev 267499)
+++ trunk/JSTests/test262/expectations.yaml 2020-09-23 21:26:09 UTC (rev 267500)
@@ -1470,6 +1470,9 @@
test/intl402/Locale/prototype/minimize/removing-likely-subtags-first-adds-likely-subtags.js:
default: 'Test262Error: "und".minimize() should be "en" Expected SameValue(«en-u-va-posix», «en») to be true'
strict mode: 'Test262Error: "und".minimize() should be "en" Expected SameValue(«en-u-va-posix», «en») to be true'
+test/intl402/NumberFormat/dft-currency-mnfd-range-check-mxfd.js:
+ default: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+ strict mode: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
test/language/arguments-object/mapped/nonconfigurable-nonenumerable-nonwritable-descriptors-set-by-arguments.js:
default: 'Test262Error: Expected obj[0] to have enumerable:false.'
test/language/arguments-object/mapped/nonconfigurable-nonenumerable-nonwritable-descriptors-set-by-param.js:
Modified: trunk/Source/_javascript_Core/ChangeLog (267499 => 267500)
--- trunk/Source/_javascript_Core/ChangeLog 2020-09-23 21:17:06 UTC (rev 267499)
+++ trunk/Source/_javascript_Core/ChangeLog 2020-09-23 21:26:09 UTC (rev 267500)
@@ -1,3 +1,23 @@
+2020-09-23 Yusuke Suzuki <[email protected]>
+
+ [JSC] Intl spec update: handle awkward rounding behavior
+ https://bugs.webkit.org/show_bug.cgi?id=216760
+
+ Reviewed by Ross Kirsling.
+
+ This patch supports new spec change of "handle awkward rounding behavior"[1].
+ This changes minimumFractionDigits / maximumFractionDigits calculation when the specified ones are less than currency-digits.
+
+ [1]: https://github.com/tc39/ecma402/pull/471
+
+ * runtime/CommonIdentifiers.h:
+ * runtime/IntlNumberFormat.cpp:
+ (JSC::IntlNumberFormat::resolvedOptions const):
+ * runtime/IntlNumberFormatInlines.h:
+ (JSC::setNumberFormatDigitOptions):
+ * runtime/IntlPluralRules.cpp:
+ (JSC::IntlPluralRules::resolvedOptions const):
+
2020-09-23 Caio Lima <[email protected]>
[JSC][ESNext] Create a new opcode to handle private fields store/define
Modified: trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h (267499 => 267500)
--- trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h 2020-09-23 21:17:06 UTC (rev 267499)
+++ trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h 2020-09-23 21:26:09 UTC (rev 267500)
@@ -153,7 +153,12 @@
macro(line) \
macro(locale) \
macro(localeMatcher) \
+ macro(maximumFractionDigits) \
+ macro(maximumSignificantDigits) \
macro(message) \
+ macro(minimumFractionDigits) \
+ macro(minimumIntegerDigits) \
+ macro(minimumSignificantDigits) \
macro(minute) \
macro(month) \
macro(multiline) \
Modified: trunk/Source/_javascript_Core/runtime/IntlNumberFormat.cpp (267499 => 267500)
--- trunk/Source/_javascript_Core/runtime/IntlNumberFormat.cpp 2020-09-23 21:17:06 UTC (rev 267499)
+++ trunk/Source/_javascript_Core/runtime/IntlNumberFormat.cpp 2020-09-23 21:26:09 UTC (rev 267500)
@@ -810,15 +810,15 @@
options->putDirect(vm, Identifier::fromString(vm, "unitDisplay"), jsNontrivialString(vm, unitDisplayString(m_unitDisplay)));
break;
}
- options->putDirect(vm, Identifier::fromString(vm, "minimumIntegerDigits"), jsNumber(m_minimumIntegerDigits));
+ options->putDirect(vm, vm.propertyNames->minimumIntegerDigits, jsNumber(m_minimumIntegerDigits));
switch (m_roundingType) {
case IntlRoundingType::FractionDigits:
- options->putDirect(vm, Identifier::fromString(vm, "minimumFractionDigits"), jsNumber(m_minimumFractionDigits));
- options->putDirect(vm, Identifier::fromString(vm, "maximumFractionDigits"), jsNumber(m_maximumFractionDigits));
+ options->putDirect(vm, vm.propertyNames->minimumFractionDigits, jsNumber(m_minimumFractionDigits));
+ options->putDirect(vm, vm.propertyNames->maximumFractionDigits, jsNumber(m_maximumFractionDigits));
break;
case IntlRoundingType::SignificantDigits:
- options->putDirect(vm, Identifier::fromString(vm, "minimumSignificantDigits"), jsNumber(m_minimumSignificantDigits));
- options->putDirect(vm, Identifier::fromString(vm, "maximumSignificantDigits"), jsNumber(m_maximumSignificantDigits));
+ options->putDirect(vm, vm.propertyNames->minimumSignificantDigits, jsNumber(m_minimumSignificantDigits));
+ options->putDirect(vm, vm.propertyNames->maximumSignificantDigits, jsNumber(m_maximumSignificantDigits));
break;
case IntlRoundingType::CompactRounding:
break;
Modified: trunk/Source/_javascript_Core/runtime/IntlNumberFormatInlines.h (267499 => 267500)
--- trunk/Source/_javascript_Core/runtime/IntlNumberFormatInlines.h 2020-09-23 21:17:06 UTC (rev 267499)
+++ trunk/Source/_javascript_Core/runtime/IntlNumberFormatInlines.h 2020-09-23 21:26:09 UTC (rev 267500)
@@ -38,19 +38,19 @@
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
- unsigned minimumIntegerDigits = intlNumberOption(globalObject, options, Identifier::fromString(vm, "minimumIntegerDigits"), 1, 21, 1);
+ unsigned minimumIntegerDigits = intlNumberOption(globalObject, options, vm.propertyNames->minimumIntegerDigits, 1, 21, 1);
RETURN_IF_EXCEPTION(scope, void());
- JSValue minimumFractionDigitsValue = options->get(globalObject, Identifier::fromString(vm, "minimumFractionDigits"));
+ JSValue minimumFractionDigitsValue = options->get(globalObject, vm.propertyNames->minimumFractionDigits);
RETURN_IF_EXCEPTION(scope, void());
- JSValue maximumFractionDigitsValue = options->get(globalObject, Identifier::fromString(vm, "maximumFractionDigits"));
+ JSValue maximumFractionDigitsValue = options->get(globalObject, vm.propertyNames->maximumFractionDigits);
RETURN_IF_EXCEPTION(scope, void());
- JSValue minimumSignificantDigitsValue = options->get(globalObject, Identifier::fromString(vm, "minimumSignificantDigits"));
+ JSValue minimumSignificantDigitsValue = options->get(globalObject, vm.propertyNames->minimumSignificantDigits);
RETURN_IF_EXCEPTION(scope, void());
- JSValue maximumSignificantDigitsValue = options->get(globalObject, Identifier::fromString(vm, "maximumSignificantDigits"));
+ JSValue maximumSignificantDigitsValue = options->get(globalObject, vm.propertyNames->maximumSignificantDigits);
RETURN_IF_EXCEPTION(scope, void());
intlInstance->m_minimumIntegerDigits = minimumIntegerDigits;
@@ -57,9 +57,9 @@
if (!minimumSignificantDigitsValue.isUndefined() || !maximumSignificantDigitsValue.isUndefined()) {
intlInstance->m_roundingType = IntlRoundingType::SignificantDigits;
- unsigned minimumSignificantDigits = intlDefaultNumberOption(globalObject, minimumSignificantDigitsValue, Identifier::fromString(vm, "minimumSignificantDigits"), 1, 21, 1);
+ unsigned minimumSignificantDigits = intlDefaultNumberOption(globalObject, minimumSignificantDigitsValue, vm.propertyNames->minimumSignificantDigits, 1, 21, 1);
RETURN_IF_EXCEPTION(scope, void());
- unsigned maximumSignificantDigits = intlDefaultNumberOption(globalObject, maximumSignificantDigitsValue, Identifier::fromString(vm, "maximumSignificantDigits"), minimumSignificantDigits, 21, 21);
+ unsigned maximumSignificantDigits = intlDefaultNumberOption(globalObject, maximumSignificantDigitsValue, vm.propertyNames->maximumSignificantDigits, minimumSignificantDigits, 21, 21);
RETURN_IF_EXCEPTION(scope, void());
intlInstance->m_minimumSignificantDigits = minimumSignificantDigits;
intlInstance->m_maximumSignificantDigits = maximumSignificantDigits;
@@ -67,12 +67,22 @@
}
if (!minimumFractionDigitsValue.isUndefined() || !maximumFractionDigitsValue.isUndefined()) {
+ constexpr unsigned undefinedValue = UINT32_MAX;
intlInstance->m_roundingType = IntlRoundingType::FractionDigits;
- unsigned minimumFractionDigits = intlDefaultNumberOption(globalObject, minimumFractionDigitsValue, Identifier::fromString(vm, "minimumFractionDigits"), 0, 20, minimumFractionDigitsDefault);
+ unsigned specifiedMinimumFractionDigits = intlDefaultNumberOption(globalObject, minimumFractionDigitsValue, vm.propertyNames->minimumFractionDigits, 0, 20, undefinedValue);
RETURN_IF_EXCEPTION(scope, void());
- unsigned maximumFractionDigitsActualDefault = std::max(minimumFractionDigits, maximumFractionDigitsDefault);
- unsigned maximumFractionDigits = intlDefaultNumberOption(globalObject, maximumFractionDigitsValue, Identifier::fromString(vm, "maximumFractionDigits"), minimumFractionDigits, 20, maximumFractionDigitsActualDefault);
+ unsigned specifiedMaximumFractionDigits = intlDefaultNumberOption(globalObject, maximumFractionDigitsValue, vm.propertyNames->maximumFractionDigits, 0, 20, undefinedValue);
RETURN_IF_EXCEPTION(scope, void());
+ if (specifiedMaximumFractionDigits != undefinedValue)
+ minimumFractionDigitsDefault = std::min(minimumFractionDigitsDefault, specifiedMaximumFractionDigits);
+ unsigned minimumFractionDigits = intlDefaultNumberOption(globalObject, (specifiedMinimumFractionDigits == undefinedValue) ? jsUndefined() : jsNumber(specifiedMinimumFractionDigits), vm.propertyNames->minimumFractionDigits, 0, 20, minimumFractionDigitsDefault);
+ RETURN_IF_EXCEPTION(scope, void());
+ unsigned maximumFractionDigits = intlDefaultNumberOption(globalObject, (specifiedMaximumFractionDigits == undefinedValue) ? jsUndefined() : jsNumber(specifiedMaximumFractionDigits), vm.propertyNames->maximumFractionDigits, 0, 20, std::max(maximumFractionDigitsDefault, minimumFractionDigits));
+ RETURN_IF_EXCEPTION(scope, void());
+ if (minimumFractionDigits > maximumFractionDigits) {
+ throwRangeError(globalObject, scope, "Computed minimumFractionDigits is larger than maximumFractionDigits"_s);
+ return;
+ }
intlInstance->m_minimumFractionDigits = minimumFractionDigits;
intlInstance->m_maximumFractionDigits = maximumFractionDigits;
return;
Modified: trunk/Source/_javascript_Core/runtime/IntlPluralRules.cpp (267499 => 267500)
--- trunk/Source/_javascript_Core/runtime/IntlPluralRules.cpp 2020-09-23 21:17:06 UTC (rev 267499)
+++ trunk/Source/_javascript_Core/runtime/IntlPluralRules.cpp 2020-09-23 21:26:09 UTC (rev 267500)
@@ -151,15 +151,15 @@
JSObject* options = constructEmptyObject(globalObject);
options->putDirect(vm, vm.propertyNames->locale, jsNontrivialString(vm, m_locale));
options->putDirect(vm, vm.propertyNames->type, jsNontrivialString(vm, m_type == Type::Ordinal ? "ordinal"_s : "cardinal"_s));
- options->putDirect(vm, Identifier::fromString(vm, "minimumIntegerDigits"), jsNumber(m_minimumIntegerDigits));
+ options->putDirect(vm, vm.propertyNames->minimumIntegerDigits, jsNumber(m_minimumIntegerDigits));
switch (m_roundingType) {
case IntlRoundingType::FractionDigits:
- options->putDirect(vm, Identifier::fromString(vm, "minimumFractionDigits"), jsNumber(m_minimumFractionDigits));
- options->putDirect(vm, Identifier::fromString(vm, "maximumFractionDigits"), jsNumber(m_maximumFractionDigits));
+ options->putDirect(vm, vm.propertyNames->minimumFractionDigits, jsNumber(m_minimumFractionDigits));
+ options->putDirect(vm, vm.propertyNames->maximumFractionDigits, jsNumber(m_maximumFractionDigits));
break;
case IntlRoundingType::SignificantDigits:
- options->putDirect(vm, Identifier::fromString(vm, "minimumSignificantDigits"), jsNumber(m_minimumSignificantDigits));
- options->putDirect(vm, Identifier::fromString(vm, "maximumSignificantDigits"), jsNumber(m_maximumSignificantDigits));
+ options->putDirect(vm, vm.propertyNames->minimumSignificantDigits, jsNumber(m_minimumSignificantDigits));
+ options->putDirect(vm, vm.propertyNames->maximumSignificantDigits, jsNumber(m_maximumSignificantDigits));
break;
default:
RELEASE_ASSERT_NOT_REACHED();