@@ -14,6 +14,7 @@ import 'dart:_foreign_helper'
1414 JS_EMBEDDED_GLOBAL,
1515 JS_GET_FLAG,
1616 JS_GET_NAME,
17+ JS_STRING_CONCAT,
1718 RAW_DART_FUNCTION_REF,
1819 TYPE_REF,
1920 LEGACY_TYPE_REF;
@@ -571,7 +572,7 @@ Object? _substituteNamed(
571572 Object ? universe, Object ? namedArray, Object ? typeArguments, int depth) {
572573 bool changed = false ;
573574 int length = _Utils .arrayLength (namedArray);
574- assert (length % 3 == 0 );
575+ assert (_Utils . isMultipleOf ( length, 3 ) );
575576 Object ? result = JS ('' , '[]' );
576577 for (int i = 0 ; i < length; i += 3 ) {
577578 String name = _Utils .asString (_Utils .arrayAt (namedArray, i));
@@ -1696,6 +1697,27 @@ class _Universe {
16961697 return rti;
16971698 }
16981699
1700+ // These helpers are used for creating canonical recipes. The key feature of
1701+ // the generated code is that it makes no reference to the constant pool,
1702+ // which does not exist when the type$ pool is created.
1703+ //
1704+ // The strange association is so that usage like
1705+ //
1706+ // s = _recipeJoin3(s, a, b);
1707+ //
1708+ // associates as `s+=(a+b)` rather than `s=s+a+b`. As recipe fragments are
1709+ // small, this tends to create smaller cons-string trees.
1710+
1711+ static String _recipeJoin (String s1, String s2) => JS_STRING_CONCAT (s1, s2);
1712+ static String _recipeJoin3 (String s1, String s2, String s3) =>
1713+ JS_STRING_CONCAT (s1, JS_STRING_CONCAT (s2, s3));
1714+ static String _recipeJoin4 (String s1, String s2, String s3, String s4) =>
1715+ JS_STRING_CONCAT (s1, JS_STRING_CONCAT (JS_STRING_CONCAT (s2, s3), s4));
1716+ static String _recipeJoin5 (
1717+ String s1, String s2, String s3, String s4, String s5) =>
1718+ JS_STRING_CONCAT (s1,
1719+ JS_STRING_CONCAT (JS_STRING_CONCAT (JS_STRING_CONCAT (s2, s3), s4), s5));
1720+
16991721 // For each kind of Rti there are three methods:
17001722 //
17011723 // * `lookupXXX` which takes the component parts and returns an existing Rti
@@ -1714,19 +1736,19 @@ class _Universe {
17141736 static String _canonicalRecipeOfDynamic () => Recipe .pushDynamicString;
17151737 static String _canonicalRecipeOfVoid () => Recipe .pushVoidString;
17161738 static String _canonicalRecipeOfNever () =>
1717- Recipe .pushNeverExtensionString + Recipe .extensionOpString;
1739+ _recipeJoin ( Recipe .pushNeverExtensionString, Recipe .extensionOpString) ;
17181740 static String _canonicalRecipeOfAny () =>
1719- Recipe .pushAnyExtensionString + Recipe .extensionOpString;
1741+ _recipeJoin ( Recipe .pushAnyExtensionString, Recipe .extensionOpString) ;
17201742
17211743 static String _canonicalRecipeOfStar (Rti baseType) =>
1722- Rti ._getCanonicalRecipe (baseType) + Recipe .wrapStarString;
1744+ _recipeJoin ( Rti ._getCanonicalRecipe (baseType), Recipe .wrapStarString) ;
17231745 static String _canonicalRecipeOfQuestion (Rti baseType) =>
1724- Rti ._getCanonicalRecipe (baseType) + Recipe .wrapQuestionString;
1746+ _recipeJoin ( Rti ._getCanonicalRecipe (baseType), Recipe .wrapQuestionString) ;
17251747 static String _canonicalRecipeOfFutureOr (Rti baseType) =>
1726- Rti ._getCanonicalRecipe (baseType) + Recipe .wrapFutureOrString;
1748+ _recipeJoin ( Rti ._getCanonicalRecipe (baseType), Recipe .wrapFutureOrString) ;
17271749
17281750 static String _canonicalRecipeOfGenericFunctionParameter (int index) =>
1729- '$index ' + Recipe .genericFunctionTypeParameterIndexString;
1751+ _recipeJoin ( '$index ' , Recipe .genericFunctionTypeParameterIndexString) ;
17301752
17311753 static Rti _lookupErasedRti (Object ? universe) {
17321754 return _lookupTerminalRti (
@@ -1888,7 +1910,7 @@ class _Universe {
18881910 for (int i = 0 ; i < length; i++ ) {
18891911 Rti argument = _Utils .asRti (_Utils .arrayAt (arguments, i));
18901912 String subrecipe = Rti ._getCanonicalRecipe (argument);
1891- s += sep + subrecipe;
1913+ s = _recipeJoin3 (s, sep, subrecipe) ;
18921914 sep = Recipe .separatorString;
18931915 }
18941916 return s;
@@ -1897,17 +1919,16 @@ class _Universe {
18971919 static String _canonicalRecipeJoinNamed (Object ? arguments) {
18981920 String s = '' , sep = '' ;
18991921 int length = _Utils .arrayLength (arguments);
1900- assert (length % 3 == 0 );
1922+ assert (_Utils . isMultipleOf ( length, 3 ) );
19011923 for (int i = 0 ; i < length; i += 3 ) {
1902- s += sep;
19031924 String name = _Utils .asString (_Utils .arrayAt (arguments, i));
19041925 bool isRequired = _Utils .asBool (_Utils .arrayAt (arguments, i + 1 ));
19051926 String nameSep = isRequired
19061927 ? Recipe .requiredNameSeparatorString
19071928 : Recipe .nameSeparatorString;
19081929 Rti type = _Utils .asRti (_Utils .arrayAt (arguments, i + 2 ));
19091930 String subrecipe = Rti ._getCanonicalRecipe (type);
1910- s += name + nameSep + subrecipe;
1931+ s = _recipeJoin5 (s, sep, name, nameSep, subrecipe) ;
19111932 sep = Recipe .separatorString;
19121933 }
19131934 return s;
@@ -1918,9 +1939,8 @@ class _Universe {
19181939 String s = _Utils .asString (name);
19191940 int length = _Utils .arrayLength (arguments);
19201941 if (length != 0 ) {
1921- s += Recipe .startTypeArgumentsString +
1922- _canonicalRecipeJoin (arguments) +
1923- Recipe .endTypeArgumentsString;
1942+ s = _recipeJoin4 (s, Recipe .startTypeArgumentsString,
1943+ _canonicalRecipeJoin (arguments), Recipe .endTypeArgumentsString);
19241944 }
19251945 return s;
19261946 }
@@ -1954,13 +1974,13 @@ class _Universe {
19541974 JS_GET_NAME (JsGetName .FUTURE_CLASS_TYPE_NAME ), JS ('' , '[#]' , base ));
19551975
19561976 static String _canonicalRecipeOfBinding (Rti base , Object ? arguments) {
1957- String s = Rti . _getCanonicalRecipe ( base );
1958- s += Recipe
1959- .toTypeString; // TODO(sra): Omit when base encoding is Rti without ToType.
1960- s += Recipe .startTypeArgumentsString +
1961- _canonicalRecipeJoin (arguments) +
1962- Recipe .endTypeArgumentsString;
1963- return s ;
1977+ return _recipeJoin5 (
1978+ Rti . _getCanonicalRecipe ( base ),
1979+ // TODO(sra): Omit when base encoding is Rti without ToType:
1980+ Recipe .toTypeString,
1981+ Recipe .startTypeArgumentsString,
1982+ _canonicalRecipeJoin (arguments),
1983+ Recipe .endTypeArgumentsString) ;
19641984 }
19651985
19661986 /// [arguments] becomes owned by the created Rti.
@@ -1992,8 +2012,8 @@ class _Universe {
19922012
19932013 static String _canonicalRecipeOfFunction (
19942014 Rti returnType, _FunctionParameters parameters) =>
1995- Rti ._getCanonicalRecipe (returnType) +
1996- _canonicalRecipeOfFunctionParameters (parameters);
2015+ _recipeJoin ( Rti ._getCanonicalRecipe (returnType),
2016+ _canonicalRecipeOfFunctionParameters (parameters) );
19972017
19982018 static String _canonicalRecipeOfFunctionParameters (
19992019 _FunctionParameters parameters) {
@@ -2007,26 +2027,26 @@ class _Universe {
20072027 int namedLength = _Utils .arrayLength (named);
20082028 assert (optionalPositionalLength == 0 || namedLength == 0 );
20092029
2010- String recipe = Recipe .startFunctionArgumentsString +
2011- _canonicalRecipeJoin (requiredPositional);
2030+ String recipe = _recipeJoin ( Recipe .startFunctionArgumentsString,
2031+ _canonicalRecipeJoin (requiredPositional)) ;
20122032
20132033 if (optionalPositionalLength > 0 ) {
20142034 String sep = requiredPositionalLength > 0 ? Recipe .separatorString : '' ;
2015- recipe += sep +
2016- Recipe .startOptionalGroupString +
2017- _canonicalRecipeJoin (optionalPositional) +
2018- Recipe .endOptionalGroupString;
2035+ recipe = _recipeJoin5 (
2036+ recipe,
2037+ sep,
2038+ Recipe .startOptionalGroupString,
2039+ _canonicalRecipeJoin (optionalPositional),
2040+ Recipe .endOptionalGroupString);
20192041 }
20202042
20212043 if (namedLength > 0 ) {
20222044 String sep = requiredPositionalLength > 0 ? Recipe .separatorString : '' ;
2023- recipe += sep +
2024- Recipe .startNamedGroupString +
2025- _canonicalRecipeJoinNamed (named) +
2026- Recipe .endNamedGroupString;
2045+ recipe = _recipeJoin5 (recipe, sep, Recipe .startNamedGroupString,
2046+ _canonicalRecipeJoinNamed (named), Recipe .endNamedGroupString);
20272047 }
20282048
2029- return recipe + Recipe .endFunctionArgumentsString;
2049+ return _recipeJoin ( recipe, Recipe .endFunctionArgumentsString) ;
20302050 }
20312051
20322052 static Rti _lookupFunctionRti (
@@ -2051,10 +2071,11 @@ class _Universe {
20512071
20522072 static String _canonicalRecipeOfGenericFunction (
20532073 Rti baseFunctionType, Object ? bounds) =>
2054- Rti ._getCanonicalRecipe (baseFunctionType) +
2055- Recipe .startTypeArgumentsString +
2056- _canonicalRecipeJoin (bounds) +
2057- Recipe .endTypeArgumentsString;
2074+ _recipeJoin4 (
2075+ Rti ._getCanonicalRecipe (baseFunctionType),
2076+ Recipe .startTypeArgumentsString,
2077+ _canonicalRecipeJoin (bounds),
2078+ Recipe .endTypeArgumentsString);
20582079
20592080 static Rti _lookupGenericFunctionRti (
20602081 Object ? universe, Rti baseFunctionType, Object ? bounds, bool normalize) {
@@ -2552,7 +2573,7 @@ class _Parser {
25522573
25532574 static void toTypesNamed (Object ? universe, Rti environment, Object ? items) {
25542575 int length = _Utils .arrayLength (items);
2555- assert (length % 3 == 0 );
2576+ assert (_Utils . isMultipleOf ( length, 3 ) );
25562577 for (int i = 2 ; i < length; i += 3 ) {
25572578 var item = _Utils .arrayAt (items, i);
25582579 Rti type = toType (universe, environment, item);
@@ -2995,6 +3016,7 @@ bool isNullable(Rti t) {
29953016 kind == Rti .kindFutureOr && isNullable (Rti ._getFutureOrArgument (t));
29963017}
29973018
3019+ @pragma ('dart2js:parameter:trust' )
29983020bool isTopType (Rti t) =>
29993021 isStrongTopType (t) ||
30003022 isLegacyObjectType (t) ||
@@ -3040,6 +3062,8 @@ class _Utils {
30403062 static bool isNotIdentical (Object ? s, Object ? t) =>
30413063 JS ('bool' , '# !== #' , s, t);
30423064
3065+ static bool isMultipleOf (int n, int d) => JS ('bool' , '# % # === 0' , n, d);
3066+
30433067 static JSArray objectKeys (Object ? o) =>
30443068 JS ('returns:JSArray;new:true;' , 'Object.keys(#)' , o);
30453069
@@ -3089,6 +3113,7 @@ class _Utils {
30893113 JS ('' , '#.set(#, #)' , cache, key, value);
30903114 }
30913115}
3116+
30923117// -------- Entry points for testing -------------------------------------------
30933118
30943119String testingCanonicalRecipe (Rti rti) {
0 commit comments