Skip to content

Commit

Permalink
[intl] Impl ECMA402 PR 471 rounding behavior
Browse files Browse the repository at this point in the history
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: tc39/ecma402#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}
  • Loading branch information
FrankYFTang authored and Commit Bot committed Oct 1, 2020
1 parent 82061a6 commit 40af6ae
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 30 deletions.
69 changes: 57 additions & 12 deletions src/objects/intl-objects.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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) {
Expand Down
9 changes: 9 additions & 0 deletions test/intl/number-format/check-minimum-fraction-digits.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'}));

This file was deleted.

2 changes: 1 addition & 1 deletion test/test262/test262.status
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 40af6ae

Please sign in to comment.