Commit 40af6aee authored by Frank Tang's avatar Frank Tang Committed by Commit Bot

[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/+/2442191Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Frank Tang <ftang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70270}
parent 82061a66
......@@ -24,6 +24,7 @@
#include "src/objects/js-number-format-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/property-descriptor.h"
#include "src/objects/smi.h"
#include "src/objects/string.h"
#include "src/strings/string-case.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
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();
if (!DefaultNumberOption(isolate, mnfd_obj, 0, 20, mnfd_default, mnfd_str)
.To(&mnfd)) {
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);
}
// 15. c. Let mxfdActualDefault be max( mnfd, mxfdDefault ).
int mxfd_actual_default = std::max(mnfd, mxfd_default);
// c. If _specifiedMxfd_ is not *undefined*, set _mnfdDefault_ to
// min(_mnfdDefault_, _specifiedMxfd_).
if (specified_mxfd >= 0) {
mnfd_default = std::min(mnfd_default, specified_mxfd);
}
// 15. d. Let mxfd be ? DefaultNumberOption(mxfd, mnfd, 20,
// mxfdActualDefault).
Handle<String> mxfd_str = factory->maximumFractionDigits_string();
if (!DefaultNumberOption(isolate, mxfd_obj, mnfd, 20, mxfd_actual_default,
mxfd_str)
// d. Set _mnfd_ to ! DefaultNumberOption(_specifiedMnfd_, 0, 20,
// _mnfdDefault_).
if (!DefaultNumberOption(isolate, specifiedMnfd_obj, 0, 20, mnfd_default,
mnfd_str)
.To(&mnfd)) {
return Nothing<NumberFormatDigitOptions>();
}
// e. Set _mxfd_ to ! DefaultNumberOption(_specifiedMxfd_, 0, 20,
// max(_mxfdDefault_, _mnfd_)).
if (!DefaultNumberOption(isolate, specifiedMxfd_obj, 0, 20,
std::max(mxfd_default, mnfd), mxfd_str)
.To(&mxfd)) {
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;
// 15. f. Set intlObj.[[MaximumFractionDigits]] to mxfd.
// h. Set intlObj.[[MaximumFractionDigits]] to mxfd.
digit_options.maximum_fraction_digits = mxfd;
// Else If intlObj.[[Notation]] is "compact", then
} else if (notation_is_compact) {
......
......@@ -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.40", nf.format(54306.4));
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'}));
// 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
}));
......@@ -533,7 +533,7 @@
# https://bugs.chromium.org/p/v8/issues/detail?id=7472
'intl402/NumberFormat/currency-digits': [FAIL],
# http://crbug/v8/10844
# https://github.com/tc39/test262/pull/2830
'intl402/NumberFormat/dft-currency-mnfd-range-check-mxfd': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=7831
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment