Reland "[intl] Impl ECMA402 PR 471 rounding behavior"

This is a reland of 40af6aeebf

Change from the rollbacked version
- removes the passed test fixed by this PR in test/test262/test262.status

TBR=jkummerow@chromium.org

Original change's description:
> [intl] Impl ECMA402 PR 471 rounding behavior
>
> Fix awkward rounding behavior
> Change Intl::SetNumberFormatDigitOptions to fix the awkward rounding
> behavior in NumberFormat when formatting a currency with
> "maximumFractionDigits" set to a value less than 2.
>
> Bug: v8:10844
> Change-Id: I2ff4afa9f747cd79cb9964fe4c77a0dd2b8977b5
> Refs: https://github.com/tc39/ecma402/pull/471
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2442191
> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
> Commit-Queue: Frank Tang <ftang@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#70270}

Bug: v8:10844
Change-Id: Icfe7363f63d402abccc038e2b8bd78b38d0d9c49
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2444210
Commit-Queue: Frank Tang <ftang@chromium.org>
Reviewed-by: Frank Tang <ftang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70273}
This commit is contained in:
Frank Tang 2020-10-01 16:35:19 -07:00 committed by Commit Bot
parent 894bf6df72
commit 940d11ecee
4 changed files with 66 additions and 32 deletions

View File

@ -24,6 +24,7 @@
#include "src/objects/js-number-format-inl.h" #include "src/objects/js-number-format-inl.h"
#include "src/objects/objects-inl.h" #include "src/objects/objects-inl.h"
#include "src/objects/property-descriptor.h" #include "src/objects/property-descriptor.h"
#include "src/objects/smi.h"
#include "src/objects/string.h" #include "src/objects/string.h"
#include "src/strings/string-case.h" #include "src/strings/string-case.h"
#include "unicode/basictz.h" #include "unicode/basictz.h"
@ -1275,28 +1276,72 @@ Maybe<Intl::NumberFormatDigitOptions> Intl::SetNumberFormatDigitOptions(
// 15. Else If mnfd is not undefined or mxfd is not undefined, then // 15. Else If mnfd is not undefined or mxfd is not undefined, then
if (!mnfd_obj->IsUndefined(isolate) || !mxfd_obj->IsUndefined(isolate)) { if (!mnfd_obj->IsUndefined(isolate) || !mxfd_obj->IsUndefined(isolate)) {
// 15. b. Let mnfd be ? DefaultNumberOption(mnfd, 0, 20, mnfdDefault). Handle<String> mxfd_str = factory->maximumFractionDigits_string();
Handle<String> mnfd_str = factory->minimumFractionDigits_string(); Handle<String> mnfd_str = factory->minimumFractionDigits_string();
if (!DefaultNumberOption(isolate, mnfd_obj, 0, 20, mnfd_default, mnfd_str)
int specified_mnfd;
int specified_mxfd;
// a. Let _specifiedMnfd_ be ? DefaultNumberOption(_mnfd_, 0, 20,
// *undefined*).
if (!DefaultNumberOption(isolate, mnfd_obj, 0, 20, -1, mnfd_str)
.To(&specified_mnfd)) {
return Nothing<NumberFormatDigitOptions>();
}
Handle<Object> specifiedMnfd_obj;
if (specified_mnfd < 0) {
specifiedMnfd_obj = factory->undefined_value();
} else {
specifiedMnfd_obj = handle(Smi::FromInt(specified_mnfd), isolate);
}
// b. Let _specifiedMxfd_ be ? DefaultNumberOption(_mxfd_, 0, 20,
// *undefined*).
if (!DefaultNumberOption(isolate, mxfd_obj, 0, 20, -1, mxfd_str)
.To(&specified_mxfd)) {
return Nothing<NumberFormatDigitOptions>();
}
Handle<Object> specifiedMxfd_obj;
if (specified_mxfd < 0) {
specifiedMxfd_obj = factory->undefined_value();
} else {
specifiedMxfd_obj = handle(Smi::FromInt(specified_mxfd), isolate);
}
// c. If _specifiedMxfd_ is not *undefined*, set _mnfdDefault_ to
// min(_mnfdDefault_, _specifiedMxfd_).
if (specified_mxfd >= 0) {
mnfd_default = std::min(mnfd_default, specified_mxfd);
}
// d. Set _mnfd_ to ! DefaultNumberOption(_specifiedMnfd_, 0, 20,
// _mnfdDefault_).
if (!DefaultNumberOption(isolate, specifiedMnfd_obj, 0, 20, mnfd_default,
mnfd_str)
.To(&mnfd)) { .To(&mnfd)) {
return Nothing<NumberFormatDigitOptions>(); return Nothing<NumberFormatDigitOptions>();
} }
// 15. c. Let mxfdActualDefault be max( mnfd, mxfdDefault ). // e. Set _mxfd_ to ! DefaultNumberOption(_specifiedMxfd_, 0, 20,
int mxfd_actual_default = std::max(mnfd, mxfd_default); // max(_mxfdDefault_, _mnfd_)).
if (!DefaultNumberOption(isolate, specifiedMxfd_obj, 0, 20,
// 15. d. Let mxfd be ? DefaultNumberOption(mxfd, mnfd, 20, std::max(mxfd_default, mnfd), mxfd_str)
// mxfdActualDefault).
Handle<String> mxfd_str = factory->maximumFractionDigits_string();
if (!DefaultNumberOption(isolate, mxfd_obj, mnfd, 20, mxfd_actual_default,
mxfd_str)
.To(&mxfd)) { .To(&mxfd)) {
return Nothing<NumberFormatDigitOptions>(); return Nothing<NumberFormatDigitOptions>();
} }
// 15. e. Set intlObj.[[MinimumFractionDigits]] to mnfd.
// f. If _mnfd_ is greater than _mxfd_, throw a *RangeError* exception.
if (mnfd > mxfd) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate,
NewRangeError(MessageTemplate::kPropertyValueOutOfRange, mxfd_str),
Nothing<NumberFormatDigitOptions>());
}
// g. Set intlObj.[[MinimumFractionDigits]] to mnfd.
digit_options.minimum_fraction_digits = mnfd; digit_options.minimum_fraction_digits = mnfd;
// 15. f. Set intlObj.[[MaximumFractionDigits]] to mxfd. // h. Set intlObj.[[MaximumFractionDigits]] to mxfd.
digit_options.maximum_fraction_digits = mxfd; digit_options.maximum_fraction_digits = mxfd;
// Else If intlObj.[[Notation]] is "compact", then // Else If intlObj.[[Notation]] is "compact", then
} else if (notation_is_compact) { } else if (notation_is_compact) {

View File

@ -55,3 +55,12 @@ nf = new Intl.NumberFormat('en', {maximumFractionDigits: 3, style: 'currency', c
assertEquals("$54,306.405", nf.format(54306.4047970)); assertEquals("$54,306.405", nf.format(54306.4047970));
assertEquals("$54,306.40", nf.format(54306.4)); assertEquals("$54,306.40", nf.format(54306.4));
assertEquals("$54,306.00", nf.format(54306)); assertEquals("$54,306.00", nf.format(54306));
nf = new Intl.NumberFormat('en', {maximumFractionDigits: 0, style: 'currency', currency: 'USD'});
assertEquals("$54,306", nf.format(54306.4047970));
assertEquals("$54,306", nf.format(54306.4));
assertEquals("$54,306", nf.format(54306));
assertThrows(() => new Intl.NumberFormat('en',
{minimumFractionDigits: 1, maximumFractionDigits: 0, style: 'currency', currency: 'USD'}));

View File

@ -1,17 +0,0 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// This code is governed by the license found in the LICENSE file.
/*---
esid: ECMA-402 #sec-setnfdigitoptions
description: >
When a currency is used in Intl.NumberFormat and minimumFractionDigits is
not provided, maximumFractionDigits should be range-checked against it.
include: [assert.js]
---*/
assert.throws(RangeError,
() => new Intl.NumberFormat('en', {
style: 'currency',
currency: 'USD',
maximumFractionDigits: 1
}));

View File

@ -533,9 +533,6 @@
# https://bugs.chromium.org/p/v8/issues/detail?id=7472 # https://bugs.chromium.org/p/v8/issues/detail?id=7472
'intl402/NumberFormat/currency-digits': [FAIL], 'intl402/NumberFormat/currency-digits': [FAIL],
# http://crbug/v8/10844
'intl402/NumberFormat/dft-currency-mnfd-range-check-mxfd': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=7831 # https://bugs.chromium.org/p/v8/issues/detail?id=7831
'language/statements/generators/generator-created-after-decl-inst': [FAIL], 'language/statements/generators/generator-created-after-decl-inst': [FAIL],
'language/expressions/generators/generator-created-after-decl-inst': [FAIL], 'language/expressions/generators/generator-created-after-decl-inst': [FAIL],