Bug 1444917: Combine tests for valid and canonical language tags in assertions. r=Waldo
authorAndré Bargull <andre.bargull@gmail.com>
Mon, 29 Oct 2018 05:41:59 -0700
changeset 446921 f77121fb76fc
parent 446920 8b5f41cdab35
child 446922 77223bb2fac2
child 446930 70a8eb10c67f
push id35057
push userccoroiu@mozilla.com
push dateSat, 17 Nov 2018 21:37:33 +0000
treeherdermozilla-central@77223bb2fac2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs1444917
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1444917: Combine tests for valid and canonical language tags in assertions. r=Waldo
js/src/builtin/intl/CommonFunctions.js
--- a/js/src/builtin/intl/CommonFunctions.js
+++ b/js/src/builtin/intl/CommonFunctions.js
@@ -1,30 +1,41 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* Portions Copyright Norbert Lindenberg 2011-2012. */
 
+#ifdef DEBUG
+#define assertIsValidAndCanonicalLanguageTag(locale, desc) \
+    do { \
+        let localeObj = parseLanguageTag(locale); \
+        assert(localeObj !== null, \
+               `${desc} is a structurally valid language tag`); \
+        assert(CanonicalizeLanguageTagFromObject(localeObj) === locale, \
+               `${desc} is a canonicalized language tag`); \
+    } while (false)
+#else
+#define assertIsValidAndCanonicalLanguageTag(locale, desc) ; // Elided assertion.
+#endif
+
 /**
  * Returns the start index of a "Unicode locale extension sequence", which the
  * specification defines as: "any substring of a language tag that starts with
  * a separator '-' and the singleton 'u' and includes the maximum sequence of
  * following non-singleton subtags and their preceding '-' separators."
  *
  * Alternatively, this may be defined as: the components of a language tag that
  * match the extension production in RFC 5646, where the singleton component is
  * "u".
  *
  * Spec: ECMAScript Internationalization API Specification, 6.2.1.
  */
 function startOfUnicodeExtensions(locale) {
     assert(typeof locale === "string", "locale is a string");
-    assert(IsStructurallyValidLanguageTag(locale), "locale is a language tag");
-    assert(CanonicalizeLanguageTag(locale) === locale, "locale is a canonicalized language tag");
 
     #define HYPHEN 0x2D
     assert(std_String_fromCharCode(HYPHEN) === "-",
            "code unit constant should match the expected character");
 
     // A wholly-privateuse or grandfathered locale has no extension sequences.
     if (callFunction(std_String_charCodeAt, locale, 1) === HYPHEN) {
         assert(locale[0] === "x" || locale[0] === "i",
@@ -48,18 +59,16 @@ function startOfUnicodeExtensions(locale
     return start;
 }
 
 /**
  * Returns the end index of a Unicode locale extension sequence.
  */
 function endOfUnicodeExtensions(locale, start) {
     assert(typeof locale === "string", "locale is a string");
-    assert(IsStructurallyValidLanguageTag(locale), "locale is a language tag");
-    assert(CanonicalizeLanguageTag(locale) === locale, "locale is a canonicalized language tag");
     assert(0 <= start && start < locale.length, "start is an index into locale");
     assert(Substring(locale, start, 3) === "-u-", "start points to Unicode extension sequence");
 
     #define HYPHEN 0x2D
     assert(std_String_fromCharCode(HYPHEN) === "-",
            "code unit constant should match the expected character");
 
     // Search for the start of the next singleton or privateuse subtag.
@@ -86,38 +95,41 @@ function endOfUnicodeExtensions(locale, 
     // sequence extends until the end of the string.
     return locale.length;
 }
 
 /**
  * Removes Unicode locale extension sequences from the given language tag.
  */
 function removeUnicodeExtensions(locale) {
+    assertIsValidAndCanonicalLanguageTag(locale, "locale with possible Unicode extension");
+
     var start = startOfUnicodeExtensions(locale);
     if (start < 0)
         return locale;
 
     var end = endOfUnicodeExtensions(locale, start);
 
     var left = Substring(locale, 0, start);
     var right = Substring(locale, end, locale.length - end);
     var combined = left + right;
 
-    assert(IsStructurallyValidLanguageTag(combined),
-           "recombination produced an invalid language tag");
+    assertIsValidAndCanonicalLanguageTag(combined, "the recombined locale");
     assert(startOfUnicodeExtensions(combined) < 0,
            "recombination failed to remove all Unicode locale extension sequences");
 
     return combined;
 }
 
 /**
  * Returns Unicode locale extension sequences from the given language tag.
  */
 function getUnicodeExtensions(locale) {
+    assertIsValidAndCanonicalLanguageTag(locale, "locale with Unicode extension");
+
     var start = startOfUnicodeExtensions(locale);
     assert(start >= 0, "start of Unicode extension sequence not found");
     var end = endOfUnicodeExtensions(locale, start);
 
     return Substring(locale, start, end - start);
 }
 
 /* eslint-disable complexity */
@@ -787,18 +799,17 @@ function DefaultLocaleIgnoringAvailableL
         if (hasOwn(candidate, oldStyleLanguageTagMappings))
             candidate = oldStyleLanguageTagMappings[candidate];
     }
 
     // Cache the candidate locale until the runtime default locale changes.
     localeCandidateCache.candidateDefaultLocale = candidate;
     localeCandidateCache.runtimeDefaultLocale = runtimeDefaultLocale;
 
-    assert(IsStructurallyValidLanguageTag(candidate),
-           "the candidate must be structurally valid");
+    assertIsValidAndCanonicalLanguageTag(candidate, "the candidate locale");
     assert(startOfUnicodeExtensions(candidate) < 0,
            "the candidate must not contain a Unicode extension sequence");
 
     return candidate;
 }
 
 /**
  * Returns the BCP 47 language tag for the host environment's current locale.
@@ -825,20 +836,17 @@ function DefaultLocale() {
                                                         dateTimeFormatInternalProperties),
                                            candidate))
     {
         locale = candidate;
     } else {
         locale = lastDitchLocale();
     }
 
-    assert(IsStructurallyValidLanguageTag(locale),
-           "the computed default locale must be structurally valid");
-    assert(locale === CanonicalizeLanguageTag(locale),
-           "the computed default locale must be canonical");
+    assertIsValidAndCanonicalLanguageTag(locale, "the computed default locale");
     assert(startOfUnicodeExtensions(locale) < 0,
            "the computed default locale must not contain a Unicode extension sequence");
 
     localeCache.defaultLocale = locale;
     localeCache.runtimeDefaultLocale = runtimeDefaultLocale;
 
     return locale;
 }
@@ -919,18 +927,17 @@ function CanonicalizeLocaleList(locales)
         k++;
     }
 
     // Step 8.
     return seen;
 }
 
 function BestAvailableLocaleHelper(availableLocales, locale, considerDefaultLocale) {
-    assert(IsStructurallyValidLanguageTag(locale), "invalid BestAvailableLocale locale structure");
-    assert(locale === CanonicalizeLanguageTag(locale), "non-canonical BestAvailableLocale locale");
+    assertIsValidAndCanonicalLanguageTag(locale, "BestAvailableLocale locale");
     assert(startOfUnicodeExtensions(locale) < 0, "locale must contain no Unicode extensions");
 
     // In the spec, [[availableLocales]] is formally a list of all available
     // locales.  But in our implementation, it's an *incomplete* list, not
     // necessarily including the default locale (and all locales implied by it,
     // e.g. "de" implied by "de-CH"), if that locale isn't in every
     // [[availableLocales]] list (because that locale is supported through
     // fallback, e.g. "de-CH" supported through "de").
@@ -1244,22 +1251,19 @@ function ResolveLocale(availableLocales,
         if (privateIndex === -1) {
             foundLocale += supportedExtension;
         } else {
             var preExtension = callFunction(String_substring, foundLocale, 0, privateIndex);
             var postExtension = callFunction(String_substring, foundLocale, privateIndex);
             foundLocale = preExtension + supportedExtension + postExtension;
         }
 
-        // Step 9.d.
-        assert(IsStructurallyValidLanguageTag(foundLocale), "invalid locale after concatenation");
-
-        // Step 9.e (Not required in this implementation, because we don't
-        // canonicalize Unicode extension subtags).
-        assert(foundLocale === CanonicalizeLanguageTag(foundLocale), "same locale with extension");
+        // Steps 9.d-e (Step 9.e is not required in this implementation,
+        // because we don't canonicalize Unicode extension subtags).
+        assertIsValidAndCanonicalLanguageTag(foundLocale, "locale after concatenation");
     }
 
     // Step 10.
     result.locale = foundLocale;
 
     // Step 11.
     return result;
 }