Support more type arguments in generic instantiation

The real solution requires more work, so this is to buy us some time.

Change-Id: I033a77d05c0ca7658475d1fe59760ce4e5919f7e
Reviewed-on: https://dart-review.googlesource.com/65541
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index 8a39e86..4d68545 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -1115,18 +1115,39 @@
   FunctionEntity get hashCodeForNativeObject =>
       _findHelperFunction('hashCodeForNativeObject');
 
-  ClassEntity get instantiation1Class => _findHelperClass('Instantiation1');
-  ClassEntity get instantiation2Class => _findHelperClass('Instantiation2');
-  ClassEntity get instantiation3Class => _findHelperClass('Instantiation3');
-  FunctionEntity get instantiate1 => _findHelperFunction('instantiate1');
-  FunctionEntity get instantiate2 => _findHelperFunction('instantiate2');
-  FunctionEntity get instantiate3 => _findHelperFunction('instantiate3');
+  // TODO(johnniwinther,sra): Support arbitrary type argument count.
+  void _checkTypeArgumentCount(int typeArgumentCount) {
+    assert(typeArgumentCount > 0);
+    if (typeArgumentCount > 20) {
+      failedAt(
+          NO_LOCATION_SPANNABLE,
+          "Unsupported instantiation argument count: "
+          "${typeArgumentCount}");
+    }
+  }
+
+  ClassEntity getInstantiationClass(int typeArgumentCount) {
+    _checkTypeArgumentCount(typeArgumentCount);
+    return _findHelperClass('Instantiation$typeArgumentCount');
+  }
+
+  FunctionEntity getInstantiateFunction(int typeArgumentCount) {
+    _checkTypeArgumentCount(typeArgumentCount);
+    return _findHelperFunction('instantiate$typeArgumentCount');
+  }
+
   FunctionEntity get instantiatedGenericFunctionType =>
       _findHelperFunction('instantiatedGenericFunctionType');
 
   FunctionEntity get extractFunctionTypeObjectFromInternal =>
       _findHelperFunction('extractFunctionTypeObjectFromInternal');
 
+  bool isInstantiationClass(ClassEntity cls) {
+    return cls.library == _jsHelperLibrary &&
+        cls.name != 'Instantiation' &&
+        cls.name.startsWith('Instantiation');
+  }
+
   // From dart:_internal
 
   ClassEntity _symbolImplementationClass;
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index 361ac44..b560560 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -768,18 +768,15 @@
     ]);
   }
 
-  BackendImpact _genericInstantiation;
+  Map<int, BackendImpact> _genericInstantiation = <int, BackendImpact>{};
 
-  BackendImpact get genericInstantiation =>
-      _genericInstantiation ??= new BackendImpact(staticUses: [
-        _commonElements.instantiate1,
-        _commonElements.instantiate2,
-        _commonElements.instantiate3,
+  BackendImpact getGenericInstantiation(int typeArgumentCount) =>
+      _genericInstantiation[typeArgumentCount] ??=
+          new BackendImpact(staticUses: [
+        _commonElements.getInstantiateFunction(typeArgumentCount),
         _commonElements.instantiatedGenericFunctionType,
         _commonElements.extractFunctionTypeObjectFromInternal,
       ], instantiatedClasses: [
-        _commonElements.instantiation1Class,
-        _commonElements.instantiation2Class,
-        _commonElements.instantiation3Class,
+        _commonElements.getInstantiationClass(typeArgumentCount),
       ]);
 }
diff --git a/pkg/compiler/lib/src/js_backend/codegen_listener.dart b/pkg/compiler/lib/src/js_backend/codegen_listener.dart
index 8332542..d276f51 100644
--- a/pkg/compiler/lib/src/js_backend/codegen_listener.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen_listener.dart
@@ -157,14 +157,8 @@
     } else if (constant is InstantiationConstantValue) {
       // TODO(johnniwinther): Register these using `BackendImpact`.
       impactBuilder.registerTypeUse(new TypeUse.instantiation(
-          _elementEnvironment
-              .getThisType(_commonElements.instantiation1Class)));
-      impactBuilder.registerTypeUse(new TypeUse.instantiation(
-          _elementEnvironment
-              .getThisType(_commonElements.instantiation2Class)));
-      impactBuilder.registerTypeUse(new TypeUse.instantiation(
-          _elementEnvironment
-              .getThisType(_commonElements.instantiation2Class)));
+          _elementEnvironment.getThisType(_commonElements
+              .getInstantiationClass(constant.typeArguments.length))));
       impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
           _commonElements.instantiatedGenericFunctionType,
           CallStructure.TWO_ARGS));
diff --git a/pkg/compiler/lib/src/js_backend/constant_emitter.dart b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
index f3e8913..709b64f 100644
--- a/pkg/compiler/lib/src/js_backend/constant_emitter.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
@@ -340,24 +340,8 @@
   @override
   jsAst.Expression visitInstantiation(InstantiationConstantValue constant,
       [_]) {
-    // TODO(johnniwinther,sra): Support arbitrary type argument count.
-    ClassEntity cls;
-    switch (constant.typeArguments.length) {
-      case 1:
-        cls = _commonElements.instantiation1Class;
-        break;
-      case 2:
-        cls = _commonElements.instantiation2Class;
-        break;
-      case 3:
-        cls = _commonElements.instantiation3Class;
-        break;
-      default:
-        failedAt(
-            NO_LOCATION_SPANNABLE,
-            "Unsupported instantiation argument count: "
-            "${constant.typeArguments.length}");
-    }
+    ClassEntity cls =
+        _commonElements.getInstantiationClass(constant.typeArguments.length);
     List<jsAst.Expression> fields = <jsAst.Expression>[
       constantReferenceGenerator(constant.function),
       _reifiedTypeArguments(constant, constant.typeArguments)
diff --git a/pkg/compiler/lib/src/js_backend/impact_transformer.dart b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
index 46e3e2d4..abec762 100644
--- a/pkg/compiler/lib/src/js_backend/impact_transformer.dart
+++ b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
@@ -301,9 +301,10 @@
     }
 
     if (worldImpact.genericInstantiations.isNotEmpty) {
-      registerImpact(_impacts.genericInstantiation);
       for (GenericInstantiation instantiation
           in worldImpact.genericInstantiations) {
+        registerImpact(_impacts
+            .getGenericInstantiation(instantiation.typeArguments.length));
         _rtiNeedBuilder.registerGenericInstantiation(instantiation);
       }
     }
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index 31545bb..7679275 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -718,9 +718,7 @@
       callStubs.add(_buildStubMethod(name, function));
     }
 
-    if (cls == _commonElements.instantiation1Class ||
-        cls == _commonElements.instantiation2Class ||
-        cls == _commonElements.instantiation3Class) {
+    if (_commonElements.isInstantiationClass(cls)) {
       callStubs.addAll(_generateInstantiationStubs(cls));
     }
 
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 188caba..d06f62d4 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -4363,7 +4363,8 @@
     }
     int typeArgumentCount = node.typeArguments.length;
     bool targetCanThrow = false; // TODO(sra): Is this true?
-    FunctionEntity target = _instantiator(typeArgumentCount);
+    FunctionEntity target =
+        _commonElements.getInstantiateFunction(typeArgumentCount);
     if (target == null) {
       reporter.internalError(
           _elementMap.getSpannable(targetElement, node),
@@ -4383,14 +4384,6 @@
     push(instruction);
   }
 
-  FunctionEntity _instantiator(int count) {
-    // TODO(johnniwinther,sra): Support arbitrary type argument count.
-    if (count == 1) return _commonElements.instantiate1;
-    if (count == 2) return _commonElements.instantiate2;
-    if (count == 3) return _commonElements.instantiate3;
-    return null;
-  }
-
   @override
   void visitMethodInvocation(ir.MethodInvocation node) {
     node.receiver.accept(this);
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index 6e5d05d..1a194f5 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -3103,7 +3103,7 @@
 }
 
 /// Instantiation classes are subclasses of [Instantiation]. For now we have a
-/// few canned subclasses. Later we might generate the classes on demand.
+/// fixed number of subclasses. Later we might generate the classes on demand.
 class Instantiation1<T1> extends Instantiation {
   Instantiation1(Closure f) : super(f);
   List get _types => [T1];
@@ -3119,16 +3119,283 @@
   List get _types => [T1, T2, T3];
 }
 
-Instantiation instantiate1<U>(Closure f) {
-  return new Instantiation1<U>(f);
+class Instantiation4<T1, T2, T3, T4> extends Instantiation {
+  Instantiation4(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4];
 }
 
-Instantiation instantiate2<U, V>(Closure f) {
-  return new Instantiation2<U, V>(f);
+class Instantiation5<T1, T2, T3, T4, T5> extends Instantiation {
+  Instantiation5(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4, T5];
 }
 
-Instantiation instantiate3<U, V, W>(Closure f) {
-  return new Instantiation3<U, V, W>(f);
+class Instantiation6<T1, T2, T3, T4, T5, T6> extends Instantiation {
+  Instantiation6(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4, T5, T6];
+}
+
+class Instantiation7<T1, T2, T3, T4, T5, T6, T7> extends Instantiation {
+  Instantiation7(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4, T5, T6, T7];
+}
+
+class Instantiation8<T1, T2, T3, T4, T5, T6, T7, T8> extends Instantiation {
+  Instantiation8(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4, T5, T6, T7, T8];
+}
+
+class Instantiation9<T1, T2, T3, T4, T5, T6, T7, T8, T9> extends Instantiation {
+  Instantiation9(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4, T5, T6, T7, T8, T9];
+}
+
+class Instantiation10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>
+    extends Instantiation {
+  Instantiation10(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10];
+}
+
+class Instantiation11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>
+    extends Instantiation {
+  Instantiation11(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11];
+}
+
+class Instantiation12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>
+    extends Instantiation {
+  Instantiation12(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12];
+}
+
+class Instantiation13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>
+    extends Instantiation {
+  Instantiation13(Closure f) : super(f);
+  List get _types => [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13];
+}
+
+class Instantiation14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14> extends Instantiation {
+  Instantiation14(Closure f) : super(f);
+  List get _types =>
+      [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14];
+}
+
+class Instantiation15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15> extends Instantiation {
+  Instantiation15(Closure f) : super(f);
+  List get _types =>
+      [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15];
+}
+
+class Instantiation16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16> extends Instantiation {
+  Instantiation16(Closure f) : super(f);
+  List get _types =>
+      [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16];
+}
+
+class Instantiation17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17> extends Instantiation {
+  Instantiation17(Closure f) : super(f);
+  List get _types => [
+        T1,
+        T2,
+        T3,
+        T4,
+        T5,
+        T6,
+        T7,
+        T8,
+        T9,
+        T10,
+        T11,
+        T12,
+        T13,
+        T14,
+        T15,
+        T16,
+        T17
+      ];
+}
+
+class Instantiation18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18> extends Instantiation {
+  Instantiation18(Closure f) : super(f);
+  List get _types => [
+        T1,
+        T2,
+        T3,
+        T4,
+        T5,
+        T6,
+        T7,
+        T8,
+        T9,
+        T10,
+        T11,
+        T12,
+        T13,
+        T14,
+        T15,
+        T16,
+        T17,
+        T18
+      ];
+}
+
+class Instantiation19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19> extends Instantiation {
+  Instantiation19(Closure f) : super(f);
+  List get _types => [
+        T1,
+        T2,
+        T3,
+        T4,
+        T5,
+        T6,
+        T7,
+        T8,
+        T9,
+        T10,
+        T11,
+        T12,
+        T13,
+        T14,
+        T15,
+        T16,
+        T17,
+        T18,
+        T19
+      ];
+}
+
+class Instantiation20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20> extends Instantiation {
+  Instantiation20(Closure f) : super(f);
+  List get _types => [
+        T1,
+        T2,
+        T3,
+        T4,
+        T5,
+        T6,
+        T7,
+        T8,
+        T9,
+        T10,
+        T11,
+        T12,
+        T13,
+        T14,
+        T15,
+        T16,
+        T17,
+        T18,
+        T19,
+        T20
+      ];
+}
+
+Instantiation instantiate1<T1>(Closure f) {
+  return new Instantiation1<T1>(f);
+}
+
+Instantiation instantiate2<T1, T2>(Closure f) {
+  return new Instantiation2<T1, T2>(f);
+}
+
+Instantiation instantiate3<T1, T2, T3>(Closure f) {
+  return new Instantiation3<T1, T2, T3>(f);
+}
+
+Instantiation instantiate4<T1, T2, T3, T4>(Closure f) {
+  return new Instantiation4<T1, T2, T3, T4>(f);
+}
+
+Instantiation instantiate5<T1, T2, T3, T4, T5>(Closure f) {
+  return new Instantiation5<T1, T2, T3, T4, T5>(f);
+}
+
+Instantiation instantiate6<T1, T2, T3, T4, T5, T6>(Closure f) {
+  return new Instantiation6<T1, T2, T3, T4, T5, T6>(f);
+}
+
+Instantiation instantiate7<T1, T2, T3, T4, T5, T6, T7>(Closure f) {
+  return new Instantiation7<T1, T2, T3, T4, T5, T6, T7>(f);
+}
+
+Instantiation instantiate8<T1, T2, T3, T4, T5, T6, T7, T8>(Closure f) {
+  return new Instantiation8<T1, T2, T3, T4, T5, T6, T7, T8>(f);
+}
+
+Instantiation instantiate9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(Closure f) {
+  return new Instantiation9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(f);
+}
+
+Instantiation instantiate10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(
+    Closure f) {
+  return new Instantiation10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(f);
+}
+
+Instantiation instantiate11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(
+    Closure f) {
+  return new Instantiation11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(f);
+}
+
+Instantiation instantiate12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(
+    Closure f) {
+  return new Instantiation12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(
+      f);
+}
+
+Instantiation
+    instantiate13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(
+        Closure f) {
+  return new Instantiation13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13>(f);
+}
+
+Instantiation
+    instantiate14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(
+        Closure f) {
+  return new Instantiation14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14>(f);
+}
+
+Instantiation instantiate15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+    T13, T14, T15>(Closure f) {
+  return new Instantiation15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15>(f);
+}
+
+Instantiation instantiate16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+    T13, T14, T15, T16>(Closure f) {
+  return new Instantiation16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16>(f);
+}
+
+Instantiation instantiate17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+    T13, T14, T15, T16, T17>(Closure f) {
+  return new Instantiation17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17>(f);
+}
+
+Instantiation instantiate18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+    T13, T14, T15, T16, T17, T18>(Closure f) {
+  return new Instantiation18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18>(f);
+}
+
+Instantiation instantiate19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+    T13, T14, T15, T16, T17, T18, T19>(Closure f) {
+  return new Instantiation19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19>(f);
+}
+
+Instantiation instantiate20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+    T13, T14, T15, T16, T17, T18, T19, T20>(Closure f) {
+  return new Instantiation20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20>(f);
 }
 
 bool jsHasOwnProperty(var jsObject, String property) {
diff --git a/tests/compiler/dart2js/generic_methods/instantiation_stub_test.dart b/tests/compiler/dart2js/generic_methods/instantiation_stub_test.dart
index 4933012..ff59958 100644
--- a/tests/compiler/dart2js/generic_methods/instantiation_stub_test.dart
+++ b/tests/compiler/dart2js/generic_methods/instantiation_stub_test.dart
@@ -87,11 +87,11 @@
           "Expected: $expectedStubs\n Actual: $actualStubs");
     }
 
-    checkStubs(closedWorld.commonElements.instantiation1Class,
+    checkStubs(closedWorld.commonElements.getInstantiationClass(1),
         [r'call$1', r'$signature']);
-    checkStubs(closedWorld.commonElements.instantiation2Class,
+    checkStubs(closedWorld.commonElements.getInstantiationClass(2),
         [r'call$2', r'$signature']);
-    checkStubs(closedWorld.commonElements.instantiation3Class,
+    checkStubs(closedWorld.commonElements.getInstantiationClass(3),
         [r'call$3', r'call$4', r'$signature']);
   });
 }
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index 69f5055..fc1fe8b 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -8,6 +8,7 @@
 class_test: Fail
 constant_javascript_semantics4_test: Fail, OK
 generic_class_is_test: Fail # Issue 32004
+many_instantiations_test/01: Crash # Issue 33819
 no_such_method_test: Fail # Wrong Invocation.memberName.
 statements_test: Fail
 typed_locals_test: Pass, Fail
diff --git a/tests/compiler/dart2js_extra/many_instantiations_test.dart b/tests/compiler/dart2js_extra/many_instantiations_test.dart
new file mode 100644
index 0000000..9ba578a
--- /dev/null
+++ b/tests/compiler/dart2js_extra/many_instantiations_test.dart
@@ -0,0 +1,296 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test generic instantiation with many type arguments.
+
+import 'package:expect/expect.dart';
+
+f1<T1>(T1 t1) => '$t1';
+f2<T1, T2>(T1 t1, T2 t2) => '$t1$t2';
+f3<T1, T2, T3>(T1 t1, T2 t2, T3 t3) => '$t1$t2$t3';
+f4<T1, T2, T3, T4>(T1 t1, T2 t2, T3 t3, T4 t4) => '$t1$t2$t3$t4';
+f5<T1, T2, T3, T4, T5>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) => '$t1$t2$t3$t4$t5';
+f6<T1, T2, T3, T4, T5, T6>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) =>
+    '$t1$t2$t3$t4$t5$t6';
+f7<T1, T2, T3, T4, T5, T6, T7>(
+        T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) =>
+    '$t1$t2$t3$t4$t5$t6$t7';
+f8<T1, T2, T3, T4, T5, T6, T7, T8>(
+        T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) =>
+    '$t1$t2$t3$t4$t5$t6$t7$t8';
+f9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
+        T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) =>
+    '$t1$t2$t3$t4$t5$t6$t7$t8$t9';
+f10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5,
+        T6 t6, T7 t7, T8 t8, T9 t9, T10 t10) =>
+    '$t1$t2$t3$t4$t5$t6$t7$t8$t9$t10';
+f11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(T1 t1, T2 t2, T3 t3, T4 t4,
+        T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10, T11 t11) =>
+    '$t1$t2$t3$t4$t5$t6$t7$t8$t9$t10$t11';
+f12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(T1 t1, T2 t2, T3 t3,
+        T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10, T11 t11, T12 t12) =>
+    '$t1$t2$t3$t4$t5$t6$t7$t8$t9$t10$t11$t12';
+f13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(
+        T1 t1,
+        T2 t2,
+        T3 t3,
+        T4 t4,
+        T5 t5,
+        T6 t6,
+        T7 t7,
+        T8 t8,
+        T9 t9,
+        T10 t10,
+        T11 t11,
+        T12 t12,
+        T13 t13) =>
+    '$t1$t2$t3$t4$t5$t6$t7$t8$t9$t10$t11$t12$t13';
+f14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(
+        T1 t1,
+        T2 t2,
+        T3 t3,
+        T4 t4,
+        T5 t5,
+        T6 t6,
+        T7 t7,
+        T8 t8,
+        T9 t9,
+        T10 t10,
+        T11 t11,
+        T12 t12,
+        T13 t13,
+        T14 t14) =>
+    '$t1$t2$t3$t4$t5$t6$t7$t8$t9$t10$t11$t12$t13$t14';
+f15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(
+        T1 t1,
+        T2 t2,
+        T3 t3,
+        T4 t4,
+        T5 t5,
+        T6 t6,
+        T7 t7,
+        T8 t8,
+        T9 t9,
+        T10 t10,
+        T11 t11,
+        T12 t12,
+        T13 t13,
+        T14 t14,
+        T15 t15) =>
+    '$t1$t2$t3$t4$t5$t6$t7$t8$t9$t10$t11$t12$t13$t14$t15';
+f16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(
+        T1 t1,
+        T2 t2,
+        T3 t3,
+        T4 t4,
+        T5 t5,
+        T6 t6,
+        T7 t7,
+        T8 t8,
+        T9 t9,
+        T10 t10,
+        T11 t11,
+        T12 t12,
+        T13 t13,
+        T14 t14,
+        T15 t15,
+        T16 t16) =>
+    '$t1$t2$t3$t4$t5$t6$t7$t8$t9$t10$t11$t12$t13$t14$t15$t16';
+f17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17>(
+        T1 t1,
+        T2 t2,
+        T3 t3,
+        T4 t4,
+        T5 t5,
+        T6 t6,
+        T7 t7,
+        T8 t8,
+        T9 t9,
+        T10 t10,
+        T11 t11,
+        T12 t12,
+        T13 t13,
+        T14 t14,
+        T15 t15,
+        T16 t16,
+        T17 t17) =>
+    '$t1$t2$t3$t4$t5$t6$t7$t8$t9$t10$t11$t12$t13$t14$t15$t16$t17';
+f18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17,
+            T18>(
+        T1 t1,
+        T2 t2,
+        T3 t3,
+        T4 t4,
+        T5 t5,
+        T6 t6,
+        T7 t7,
+        T8 t8,
+        T9 t9,
+        T10 t10,
+        T11 t11,
+        T12 t12,
+        T13 t13,
+        T14 t14,
+        T15 t15,
+        T16 t16,
+        T17 t17,
+        T18 t18) =>
+    '$t1$t2$t3$t4$t5$t6$t7$t8$t9$t10$t11$t12$t13$t14$t15$t16$t17$t18';
+f19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17,
+            T18, T19>(
+        T1 t1,
+        T2 t2,
+        T3 t3,
+        T4 t4,
+        T5 t5,
+        T6 t6,
+        T7 t7,
+        T8 t8,
+        T9 t9,
+        T10 t10,
+        T11 t11,
+        T12 t12,
+        T13 t13,
+        T14 t14,
+        T15 t15,
+        T16 t16,
+        T17 t17,
+        T18 t18,
+        T19 t19) =>
+    '$t1$t2$t3$t4$t5$t6$t7$t8$t9$t10$t11$t12$t13$t14$t15$t16$t17$t18$t19';
+f20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17,
+            T18, T19, T20>(
+        T1 t1,
+        T2 t2,
+        T3 t3,
+        T4 t4,
+        T5 t5,
+        T6 t6,
+        T7 t7,
+        T8 t8,
+        T9 t9,
+        T10 t10,
+        T11 t11,
+        T12 t12,
+        T13 t13,
+        T14 t14,
+        T15 t15,
+        T16 t16,
+        T17 t17,
+        T18 t18,
+        T19 t19,
+        T20 t20) =>
+    '$t1$t2$t3$t4$t5$t6$t7$t8$t9$t10$t11$t12$t13$t14$t15$t16$t17$t18$t19$t20';
+f21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17,
+            T18, T19, T20, T21>(
+        T1 t1,
+        T2 t2,
+        T3 t3,
+        T4 t4,
+        T5 t5,
+        T6 t6,
+        T7 t7,
+        T8 t8,
+        T9 t9,
+        T10 t10,
+        T11 t11,
+        T12 t12,
+        T13 t13,
+        T14 t14,
+        T15 t15,
+        T16 t16,
+        T17 t17,
+        T18 t18,
+        T19 t19,
+        T20 t20,
+        T21 t21) =>
+    '$t1$t2$t3$t4$t5$t6$t7$t8$t9$t10$t11$t12$t13$t14$t15$t16$t17$t18$t19$t20$t21';
+
+m1(Function(int) f) => f(1);
+m2(Function(int, int) f) => f(1, 2);
+m3(Function(int, int, int) f) => f(1, 2, 3);
+m4(Function(int, int, int, int) f) => f(1, 2, 3, 4);
+m5(Function(int, int, int, int, int) f) => f(1, 2, 3, 4, 5);
+m6(Function(int, int, int, int, int, int) f) => f(1, 2, 3, 4, 5, 6);
+m7(Function(int, int, int, int, int, int, int) f) => f(1, 2, 3, 4, 5, 6, 7);
+m8(Function(int, int, int, int, int, int, int, int) f) =>
+    f(1, 2, 3, 4, 5, 6, 7, 8);
+m9(Function(int, int, int, int, int, int, int, int, int) f) =>
+    f(1, 2, 3, 4, 5, 6, 7, 8, 9);
+m10(Function(int, int, int, int, int, int, int, int, int, int) f) =>
+    f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+m11(Function(int, int, int, int, int, int, int, int, int, int, int) f) =>
+    f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
+m12(Function(int, int, int, int, int, int, int, int, int, int, int, int) f) =>
+    f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
+m13(
+        Function(
+                int, int, int, int, int, int, int, int, int, int, int, int, int)
+            f) =>
+    f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
+m14(
+        Function(int, int, int, int, int, int, int, int, int, int, int, int,
+                int, int)
+            f) =>
+    f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);
+m15(
+        Function(int, int, int, int, int, int, int, int, int, int, int, int,
+                int, int, int)
+            f) =>
+    f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
+m16(
+        Function(int, int, int, int, int, int, int, int, int, int, int, int,
+                int, int, int, int)
+            f) =>
+    f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
+m17(
+        Function(int, int, int, int, int, int, int, int, int, int, int, int,
+                int, int, int, int, int)
+            f) =>
+    f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17);
+m18(
+        Function(int, int, int, int, int, int, int, int, int, int, int, int,
+                int, int, int, int, int, int)
+            f) =>
+    f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18);
+m19(
+        Function(int, int, int, int, int, int, int, int, int, int, int, int,
+                int, int, int, int, int, int, int)
+            f) =>
+    f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19);
+m20(
+        Function(int, int, int, int, int, int, int, int, int, int, int, int,
+                int, int, int, int, int, int, int, int)
+            f) =>
+    f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
+m21(
+        Function(int, int, int, int, int, int, int, int, int, int, int, int,
+                int, int, int, int, int, int, int, int, int)
+            f) =>
+    f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+        21);
+
+main() {
+  Expect.equals('1', m1(f1));
+  Expect.equals('12', m2(f2));
+  Expect.equals('123', m3(f3));
+  Expect.equals('1234', m4(f4));
+  Expect.equals('12345', m5(f5));
+  Expect.equals('123456', m6(f6));
+  Expect.equals('1234567', m7(f7));
+  Expect.equals('12345678', m8(f8));
+  Expect.equals('123456789', m9(f9));
+  Expect.equals('12345678910', m10(f10));
+  Expect.equals('1234567891011', m11(f11));
+  Expect.equals('123456789101112', m12(f12));
+  Expect.equals('12345678910111213', m13(f13));
+  Expect.equals('1234567891011121314', m14(f14));
+  Expect.equals('123456789101112131415', m15(f15));
+  Expect.equals('12345678910111213141516', m16(f16));
+  Expect.equals('1234567891011121314151617', m17(f17));
+  Expect.equals('123456789101112131415161718', m18(f18));
+  Expect.equals('12345678910111213141516171819', m19(f19));
+  Expect.equals('1234567891011121314151617181920', m20(f20));
+  Expect.equals('123456789101112131415161718192021', m21(f21)); //# 01: ok
+}