⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 267500 in webkit


Ignore:
Timestamp:
Sep 23, 2020, 2:26:09 PM (6 years ago)
Author:
ysuzuki@apple.com
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/JavaScriptCore:

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

Location:
trunk
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r267489 r267500  
     12020-09-23  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Intl spec update: handle awkward rounding behavior
     4        https://bugs.webkit.org/show_bug.cgi?id=216760
     5
     6        Reviewed by Ross Kirsling.
     7
     8        * stress/intl-numberformat.js:
     9        * test262/expectations.yaml:
     10
    1112020-09-23  Caio Lima  <ticaiolima@gmail.com>
    212
  • trunk/JSTests/stress/intl-numberformat.js

    r266973 r267500  
    460460shouldBe(Intl.NumberFormat('zh-Hans-CN-u-nu-hanidec').format(123456789n), '一二三,四五六,七八九');
    461461shouldBe(Intl.NumberFormat('en', { maximumSignificantDigits: 3 }).format(123456n), '123,000');
     462
     463{
     464    let nf = new Intl.NumberFormat('en', {
     465        style: 'currency',
     466        currency: 'USD',
     467        maximumFractionDigits: 1
     468    });
     469    shouldBe(nf.resolvedOptions().maximumFractionDigits, 1);
     470    shouldBe(nf.resolvedOptions().minimumFractionDigits, 1);
     471    shouldBe(nf.format(30.333333333333), `$30.3`);
     472    shouldBe(nf.format(30.35), `$30.4`);
     473    shouldBe(nf.format(30), `$30.0`);
     474}
     475{
     476    let nf = new Intl.NumberFormat('en', {
     477        style: 'currency',
     478        currency: 'USD',
     479        maximumFractionDigits: 0
     480    });
     481    shouldBe(nf.resolvedOptions().maximumFractionDigits, 0);
     482    shouldBe(nf.resolvedOptions().minimumFractionDigits, 0);
     483    shouldBe(nf.format(30.3), `$30`);
     484    shouldBe(nf.format(30.5), `$31`);
     485    shouldBe(nf.format(30), `$30`);
     486}
     487{
     488    let nf = new Intl.NumberFormat('en', {
     489        style: 'currency',
     490        currency: 'CLF',
     491        maximumFractionDigits: 3
     492    });
     493    shouldBe(nf.resolvedOptions().maximumFractionDigits, 3);
     494    shouldBe(nf.resolvedOptions().minimumFractionDigits, 3);
     495    if ($vm.icuVersion() >= 64) {
     496        shouldBe([`CLF 30.333`, `CLF 30.333`].includes(nf.format(30.333333333333)), true);
     497        shouldBe([`CLF 30.000`, `CLF 30.000`].includes(nf.format(30)), true);
     498    }
     499}
     500{
     501    let nf = new Intl.NumberFormat('en', {
     502        style: 'currency',
     503        currency: 'CLF',
     504        maximumFractionDigits: 0
     505    });
     506    shouldBe(nf.resolvedOptions().maximumFractionDigits, 0);
     507    shouldBe(nf.resolvedOptions().minimumFractionDigits, 0);
     508    if ($vm.icuVersion() >= 64) {
     509        shouldBe([`CLF 30`, `CLF 30`].includes(nf.format(30.333333333333)), true);
     510        shouldBe([`CLF 31`, `CLF 31`].includes(nf.format(30.5)), true);
     511        shouldBe([`CLF 30`, `CLF 30`].includes(nf.format(30)), true);
     512    }
     513}
     514shouldThrow(() => {
     515    let nf = new Intl.NumberFormat('en', {
     516        style: 'currency',
     517        currency: 'CLF',
     518        maximumFractionDigits: 0,
     519        minimumFractionDigits: 100
     520    });
     521}, RangeError);
  • trunk/JSTests/test262/expectations.yaml

    r267348 r267500  
    14711471  default: 'Test262Error: "und".minimize() should be "en" Expected SameValue(«en-u-va-posix», «en») to be true'
    14721472  strict mode: 'Test262Error: "und".minimize() should be "en" Expected SameValue(«en-u-va-posix», «en») to be true'
     1473test/intl402/NumberFormat/dft-currency-mnfd-range-check-mxfd.js:
     1474  default: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
     1475  strict mode: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
    14731476test/language/arguments-object/mapped/nonconfigurable-nonenumerable-nonwritable-descriptors-set-by-arguments.js:
    14741477  default: 'Test262Error: Expected obj[0] to have enumerable:false.'
  • trunk/Source/JavaScriptCore/ChangeLog

    r267489 r267500  
     12020-09-23  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Intl spec update: handle awkward rounding behavior
     4        https://bugs.webkit.org/show_bug.cgi?id=216760
     5
     6        Reviewed by Ross Kirsling.
     7
     8        This patch supports new spec change of "handle awkward rounding behavior"[1].
     9        This changes minimumFractionDigits / maximumFractionDigits calculation when the specified ones are less than currency-digits.
     10
     11        [1]: https://github.com/tc39/ecma402/pull/471
     12
     13        * runtime/CommonIdentifiers.h:
     14        * runtime/IntlNumberFormat.cpp:
     15        (JSC::IntlNumberFormat::resolvedOptions const):
     16        * runtime/IntlNumberFormatInlines.h:
     17        (JSC::setNumberFormatDigitOptions):
     18        * runtime/IntlPluralRules.cpp:
     19        (JSC::IntlPluralRules::resolvedOptions const):
     20
    1212020-09-23  Caio Lima  <ticaiolima@gmail.com>
    222
  • trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.h

    r267186 r267500  
    154154    macro(locale) \
    155155    macro(localeMatcher) \
     156    macro(maximumFractionDigits) \
     157    macro(maximumSignificantDigits) \
    156158    macro(message) \
     159    macro(minimumFractionDigits) \
     160    macro(minimumIntegerDigits) \
     161    macro(minimumSignificantDigits) \
    157162    macro(minute) \
    158163    macro(month) \
  • trunk/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp

    r266044 r267500  
    811811        break;
    812812    }
    813     options->putDirect(vm, Identifier::fromString(vm, "minimumIntegerDigits"), jsNumber(m_minimumIntegerDigits));
     813    options->putDirect(vm, vm.propertyNames->minimumIntegerDigits, jsNumber(m_minimumIntegerDigits));
    814814    switch (m_roundingType) {
    815815    case IntlRoundingType::FractionDigits:
    816         options->putDirect(vm, Identifier::fromString(vm, "minimumFractionDigits"), jsNumber(m_minimumFractionDigits));
    817         options->putDirect(vm, Identifier::fromString(vm, "maximumFractionDigits"), jsNumber(m_maximumFractionDigits));
     816        options->putDirect(vm, vm.propertyNames->minimumFractionDigits, jsNumber(m_minimumFractionDigits));
     817        options->putDirect(vm, vm.propertyNames->maximumFractionDigits, jsNumber(m_maximumFractionDigits));
    818818        break;
    819819    case IntlRoundingType::SignificantDigits:
    820         options->putDirect(vm, Identifier::fromString(vm, "minimumSignificantDigits"), jsNumber(m_minimumSignificantDigits));
    821         options->putDirect(vm, Identifier::fromString(vm, "maximumSignificantDigits"), jsNumber(m_maximumSignificantDigits));
     820        options->putDirect(vm, vm.propertyNames->minimumSignificantDigits, jsNumber(m_minimumSignificantDigits));
     821        options->putDirect(vm, vm.propertyNames->maximumSignificantDigits, jsNumber(m_maximumSignificantDigits));
    822822        break;
    823823    case IntlRoundingType::CompactRounding:
  • trunk/Source/JavaScriptCore/runtime/IntlNumberFormatInlines.h

    r266655 r267500  
    3939    auto scope = DECLARE_THROW_SCOPE(vm);
    4040
    41     unsigned minimumIntegerDigits = intlNumberOption(globalObject, options, Identifier::fromString(vm, "minimumIntegerDigits"), 1, 21, 1);
     41    unsigned minimumIntegerDigits = intlNumberOption(globalObject, options, vm.propertyNames->minimumIntegerDigits, 1, 21, 1);
    4242    RETURN_IF_EXCEPTION(scope, void());
    4343
    44     JSValue minimumFractionDigitsValue = options->get(globalObject, Identifier::fromString(vm, "minimumFractionDigits"));
     44    JSValue minimumFractionDigitsValue = options->get(globalObject, vm.propertyNames->minimumFractionDigits);
    4545    RETURN_IF_EXCEPTION(scope, void());
    4646
    47     JSValue maximumFractionDigitsValue = options->get(globalObject, Identifier::fromString(vm, "maximumFractionDigits"));
     47    JSValue maximumFractionDigitsValue = options->get(globalObject, vm.propertyNames->maximumFractionDigits);
    4848    RETURN_IF_EXCEPTION(scope, void());
    4949
    50     JSValue minimumSignificantDigitsValue = options->get(globalObject, Identifier::fromString(vm, "minimumSignificantDigits"));
     50    JSValue minimumSignificantDigitsValue = options->get(globalObject, vm.propertyNames->minimumSignificantDigits);
    5151    RETURN_IF_EXCEPTION(scope, void());
    5252
    53     JSValue maximumSignificantDigitsValue = options->get(globalObject, Identifier::fromString(vm, "maximumSignificantDigits"));
     53    JSValue maximumSignificantDigitsValue = options->get(globalObject, vm.propertyNames->maximumSignificantDigits);
    5454    RETURN_IF_EXCEPTION(scope, void());
    5555
     
    5858    if (!minimumSignificantDigitsValue.isUndefined() || !maximumSignificantDigitsValue.isUndefined()) {
    5959        intlInstance->m_roundingType = IntlRoundingType::SignificantDigits;
    60         unsigned minimumSignificantDigits = intlDefaultNumberOption(globalObject, minimumSignificantDigitsValue, Identifier::fromString(vm, "minimumSignificantDigits"), 1, 21, 1);
     60        unsigned minimumSignificantDigits = intlDefaultNumberOption(globalObject, minimumSignificantDigitsValue, vm.propertyNames->minimumSignificantDigits, 1, 21, 1);
    6161        RETURN_IF_EXCEPTION(scope, void());
    62         unsigned maximumSignificantDigits = intlDefaultNumberOption(globalObject, maximumSignificantDigitsValue, Identifier::fromString(vm, "maximumSignificantDigits"), minimumSignificantDigits, 21, 21);
     62        unsigned maximumSignificantDigits = intlDefaultNumberOption(globalObject, maximumSignificantDigitsValue, vm.propertyNames->maximumSignificantDigits, minimumSignificantDigits, 21, 21);
    6363        RETURN_IF_EXCEPTION(scope, void());
    6464        intlInstance->m_minimumSignificantDigits = minimumSignificantDigits;
     
    6868
    6969    if (!minimumFractionDigitsValue.isUndefined() || !maximumFractionDigitsValue.isUndefined()) {
     70        constexpr unsigned undefinedValue = UINT32_MAX;
    7071        intlInstance->m_roundingType = IntlRoundingType::FractionDigits;
    71         unsigned minimumFractionDigits = intlDefaultNumberOption(globalObject, minimumFractionDigitsValue, Identifier::fromString(vm, "minimumFractionDigits"), 0, 20, minimumFractionDigitsDefault);
     72        unsigned specifiedMinimumFractionDigits = intlDefaultNumberOption(globalObject, minimumFractionDigitsValue, vm.propertyNames->minimumFractionDigits, 0, 20, undefinedValue);
    7273        RETURN_IF_EXCEPTION(scope, void());
    73         unsigned maximumFractionDigitsActualDefault = std::max(minimumFractionDigits, maximumFractionDigitsDefault);
    74         unsigned maximumFractionDigits = intlDefaultNumberOption(globalObject, maximumFractionDigitsValue, Identifier::fromString(vm, "maximumFractionDigits"), minimumFractionDigits, 20, maximumFractionDigitsActualDefault);
     74        unsigned specifiedMaximumFractionDigits = intlDefaultNumberOption(globalObject, maximumFractionDigitsValue, vm.propertyNames->maximumFractionDigits, 0, 20, undefinedValue);
    7575        RETURN_IF_EXCEPTION(scope, void());
     76        if (specifiedMaximumFractionDigits != undefinedValue)
     77            minimumFractionDigitsDefault = std::min(minimumFractionDigitsDefault, specifiedMaximumFractionDigits);
     78        unsigned minimumFractionDigits = intlDefaultNumberOption(globalObject, (specifiedMinimumFractionDigits == undefinedValue) ? jsUndefined() : jsNumber(specifiedMinimumFractionDigits), vm.propertyNames->minimumFractionDigits, 0, 20, minimumFractionDigitsDefault);
     79        RETURN_IF_EXCEPTION(scope, void());
     80        unsigned maximumFractionDigits = intlDefaultNumberOption(globalObject, (specifiedMaximumFractionDigits == undefinedValue) ? jsUndefined() : jsNumber(specifiedMaximumFractionDigits), vm.propertyNames->maximumFractionDigits, 0, 20, std::max(maximumFractionDigitsDefault, minimumFractionDigits));
     81        RETURN_IF_EXCEPTION(scope, void());
     82        if (minimumFractionDigits > maximumFractionDigits) {
     83            throwRangeError(globalObject, scope, "Computed minimumFractionDigits is larger than maximumFractionDigits"_s);
     84            return;
     85        }
    7686        intlInstance->m_minimumFractionDigits = minimumFractionDigits;
    7787        intlInstance->m_maximumFractionDigits = maximumFractionDigits;
  • trunk/Source/JavaScriptCore/runtime/IntlPluralRules.cpp

    r266031 r267500  
    152152    options->putDirect(vm, vm.propertyNames->locale, jsNontrivialString(vm, m_locale));
    153153    options->putDirect(vm, vm.propertyNames->type, jsNontrivialString(vm, m_type == Type::Ordinal ? "ordinal"_s : "cardinal"_s));
    154     options->putDirect(vm, Identifier::fromString(vm, "minimumIntegerDigits"), jsNumber(m_minimumIntegerDigits));
     154    options->putDirect(vm, vm.propertyNames->minimumIntegerDigits, jsNumber(m_minimumIntegerDigits));
    155155    switch (m_roundingType) {
    156156    case IntlRoundingType::FractionDigits:
    157         options->putDirect(vm, Identifier::fromString(vm, "minimumFractionDigits"), jsNumber(m_minimumFractionDigits));
    158         options->putDirect(vm, Identifier::fromString(vm, "maximumFractionDigits"), jsNumber(m_maximumFractionDigits));
     157        options->putDirect(vm, vm.propertyNames->minimumFractionDigits, jsNumber(m_minimumFractionDigits));
     158        options->putDirect(vm, vm.propertyNames->maximumFractionDigits, jsNumber(m_maximumFractionDigits));
    159159        break;
    160160    case IntlRoundingType::SignificantDigits:
    161         options->putDirect(vm, Identifier::fromString(vm, "minimumSignificantDigits"), jsNumber(m_minimumSignificantDigits));
    162         options->putDirect(vm, Identifier::fromString(vm, "maximumSignificantDigits"), jsNumber(m_maximumSignificantDigits));
     161        options->putDirect(vm, vm.propertyNames->minimumSignificantDigits, jsNumber(m_minimumSignificantDigits));
     162        options->putDirect(vm, vm.propertyNames->maximumSignificantDigits, jsNumber(m_maximumSignificantDigits));
    163163        break;
    164164    default:
Note: See TracChangeset for help on using the changeset viewer.