diff --git a/src/objects/js-number-format.cc b/src/objects/js-number-format.cc index fda9a940d6..80e8c70e6c 100644 --- a/src/objects/js-number-format.cc +++ b/src/objects/js-number-format.cc @@ -83,9 +83,6 @@ Handle JSNumberFormat::ResolvedOptions( icu::NumberFormat* number_format = number_format_holder->icu_number_format()->raw(); CHECK_NOT_NULL(number_format); - icu::DecimalFormat* decimal_format = - static_cast(number_format); - CHECK_NOT_NULL(decimal_format); Handle locale = Handle(number_format_holder->locale(), isolate); @@ -159,6 +156,11 @@ Handle JSNumberFormat::ResolvedOptions( factory->NewNumberFromInt(number_format->getMaximumFractionDigits()), Just(kDontThrow)) .FromJust()); + CHECK(number_format->getDynamicClassID() == + icu::DecimalFormat::getStaticClassID()); + icu::DecimalFormat* decimal_format = + static_cast(number_format); + CHECK_NOT_NULL(decimal_format); if (decimal_format->areSignificantDigitsUsed()) { CHECK(JSReceiver::CreateDataProperty( isolate, options, factory->minimumSignificantDigits_string(), @@ -335,22 +337,52 @@ MaybeHandle JSNumberFormat::Initialize( UErrorCode status = U_ZERO_ERROR; std::unique_ptr icu_number_format; + icu::Locale no_extension_locale(r.icu_locale.getBaseName()); if (style == Style::DECIMAL) { icu_number_format.reset( icu::NumberFormat::createInstance(r.icu_locale, status)); + // If the subclass is not DecimalFormat, fallback to no extension + // because other subclass has not support the format() with + // FieldPositionIterator yet. + if (U_FAILURE(status) || icu_number_format.get() == nullptr || + icu_number_format->getDynamicClassID() != + icu::DecimalFormat::getStaticClassID()) { + status = U_ZERO_ERROR; + icu_number_format.reset( + icu::NumberFormat::createInstance(no_extension_locale, status)); + } } else if (style == Style::PERCENT) { icu_number_format.reset( icu::NumberFormat::createPercentInstance(r.icu_locale, status)); + // If the subclass is not DecimalFormat, fallback to no extension + // because other subclass has not support the format() with + // FieldPositionIterator yet. + if (U_FAILURE(status) || icu_number_format.get() == nullptr || + icu_number_format->getDynamicClassID() != + icu::DecimalFormat::getStaticClassID()) { + status = U_ZERO_ERROR; + icu_number_format.reset(icu::NumberFormat::createPercentInstance( + no_extension_locale, status)); + } } else { DCHECK_EQ(style, Style::CURRENCY); icu_number_format.reset( icu::NumberFormat::createInstance(r.icu_locale, format_style, status)); + // If the subclass is not DecimalFormat, fallback to no extension + // because other subclass has not support the format() with + // FieldPositionIterator yet. + if (U_FAILURE(status) || icu_number_format.get() == nullptr || + icu_number_format->getDynamicClassID() != + icu::DecimalFormat::getStaticClassID()) { + status = U_ZERO_ERROR; + icu_number_format.reset(icu::NumberFormat::createInstance( + no_extension_locale, format_style, status)); + } } if (U_FAILURE(status) || icu_number_format.get() == nullptr) { status = U_ZERO_ERROR; // Remove extensions and try again. - icu::Locale no_extension_locale(r.icu_locale.getBaseName()); icu_number_format.reset( icu::NumberFormat::createInstance(no_extension_locale, status)); @@ -360,6 +392,8 @@ MaybeHandle JSNumberFormat::Initialize( } DCHECK(U_SUCCESS(status)); CHECK_NOT_NULL(icu_number_format.get()); + CHECK(icu_number_format->getDynamicClassID() == + icu::DecimalFormat::getStaticClassID()); if (style == Style::CURRENCY) { // 19. If style is "currency", set numberFormat.[[CurrencyDisplay]] to // currencyDisplay. @@ -396,6 +430,8 @@ MaybeHandle JSNumberFormat::Initialize( } // 22. Perform ? SetNumberFormatDigitOptions(numberFormat, options, // mnfdDefault, mxfdDefault). + CHECK(icu_number_format->getDynamicClassID() == + icu::DecimalFormat::getStaticClassID()); icu::DecimalFormat* icu_decimal_format = static_cast(icu_number_format.get()); Maybe maybe_set_number_for_digit_options = diff --git a/test/intl/regress-9035.js b/test/intl/regress-9035.js new file mode 100644 index 0000000000..62b088cb79 --- /dev/null +++ b/test/intl/regress-9035.js @@ -0,0 +1,27 @@ +// Copyright 2019 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// These Numbering Systems (nu) are listed in +// http://www.unicode.org/repos/cldr/tags/latest/common/bcp47/number.xml +// with " — algorithmic" in the description but are NOT listed in +// https://www.ecma-international.org/ecma-402/#table-numbering-system-digits +// So there are no mandate to support these nu in a particular way. +// Therefore in here we are only assure it won't throw exception in the +// constructor and format method. +assertDoesNotThrow(() => (new Intl.NumberFormat('en-u-nu-armn')).format(0)); +assertDoesNotThrow(() => (new Intl.NumberFormat('en-u-nu-armnlow')).format(0)); +assertDoesNotThrow(() => (new Intl.NumberFormat('en-u-nu-cyrl')).format(0)); +assertDoesNotThrow(() => (new Intl.NumberFormat('en-u-nu-ethi')).format(0)); +assertDoesNotThrow(() => (new Intl.NumberFormat('en-u-nu-geor')).format(0)); +assertDoesNotThrow(() => (new Intl.NumberFormat('en-u-nu-grek')).format(0)); +assertDoesNotThrow(() => (new Intl.NumberFormat('en-u-nu-greklow')).format(0)); +assertDoesNotThrow(() => (new Intl.NumberFormat('en-u-nu-hans')).format(0)); +assertDoesNotThrow(() => (new Intl.NumberFormat('en-u-nu-hansfin')).format(0)); +assertDoesNotThrow(() => (new Intl.NumberFormat('en-u-nu-hant')).format(0)); +assertDoesNotThrow(() => (new Intl.NumberFormat('en-u-nu-hantfin')).format(0)); +assertDoesNotThrow(() => (new Intl.NumberFormat('en-u-nu-hebr')).format(0)); +assertDoesNotThrow(() => (new Intl.NumberFormat('en-u-nu-jpanfin')).format(0)); +assertDoesNotThrow(() => (new Intl.NumberFormat('en-u-nu-roman')).format(0)); +assertDoesNotThrow(() => (new Intl.NumberFormat('en-u-nu-romanlow')).format(0)); +assertDoesNotThrow(() => (new Intl.NumberFormat('en-u-nu-taml')).format(0));