Title: [267500] trunk
Revision
267500
Author
[email protected]
Date
2020-09-23 14:26:09 -0700 (Wed, 23 Sep 2020)

Log Message

[JSC] Intl spec update: handle awkward rounding behavior
https://bugs.webkit.org/show_bug.cgi?id=216760

Reviewed by Ross Kirsling.

JSTests:

* stress/intl-numberformat.js:
* test262/expectations.yaml:

Source/_javascript_Core:

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):

Modified Paths

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();
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to