[cfe] Build extension types as their on-types if they are enabled

Change-Id: Iae52f25ffcc0517e9ec05c445ae1227af9fa3b97
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/185881
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
index 725ff20..c4c4e5c 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -593,7 +593,7 @@
           null);
     }
 
-    // arguments.length == typeVariables.length
+    assert(arguments.length == typeVariablesCount);
     List<DartType> result =
         new List<DartType>.filled(arguments.length, null, growable: true);
     for (int i = 0; i < result.length; ++i) {
diff --git a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
index 5c150ad..1ef8de3 100644
--- a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
@@ -6,20 +6,23 @@
 
 import 'package:kernel/ast.dart';
 import 'package:kernel/core_types.dart';
+import 'package:kernel/type_algebra.dart';
 
-import '../fasta_codes.dart' show templateInternalProblemNotFoundIn;
+import '../fasta_codes.dart'
+    show templateInternalProblemNotFoundIn, templateTypeArgumentMismatch;
 import '../scope.dart';
+import '../source/source_library_builder.dart';
 import '../problems.dart';
 import '../util/helpers.dart';
 
 import 'builder.dart';
+import 'declaration_builder.dart';
 import 'library_builder.dart';
 import 'member_builder.dart';
 import 'metadata_builder.dart';
 import 'nullability_builder.dart';
 import 'type_builder.dart';
 import 'type_variable_builder.dart';
-import 'declaration_builder.dart';
 
 abstract class ExtensionBuilder implements DeclarationBuilder {
   List<TypeVariableBuilder> get typeParameters;
@@ -86,14 +89,82 @@
   DartType buildType(LibraryBuilder library,
       NullabilityBuilder nullabilityBuilder, List<TypeBuilder> arguments,
       [bool notInstanceContext]) {
-    throw new UnsupportedError("ExtensionBuilder.buildType is not supported.");
+    if (library is SourceLibraryBuilder &&
+        library.enableExtensionTypesInLibrary) {
+      return buildTypesWithBuiltArguments(
+          library,
+          nullabilityBuilder.build(library),
+          buildTypeArguments(library, arguments, notInstanceContext));
+    } else {
+      throw new UnsupportedError("ExtensionBuilder.buildType is not supported"
+          "in library '${library.importUri}'.");
+    }
   }
 
   @override
   DartType buildTypesWithBuiltArguments(LibraryBuilder library,
       Nullability nullability, List<DartType> arguments) {
-    throw new UnsupportedError("ExtensionBuilder.buildTypesWithBuiltArguments "
-        "is not supported.");
+    if (library is SourceLibraryBuilder &&
+        library.enableExtensionTypesInLibrary) {
+      // TODO(dmitryas): Build the extension type rather than the on-type.
+      DartType builtOnType = onType.build(library);
+      if (typeParameters != null) {
+        List<TypeParameter> typeParameterNodes = <TypeParameter>[];
+        for (TypeVariableBuilder typeParameter in typeParameters) {
+          typeParameterNodes.add(typeParameter.parameter);
+        }
+        builtOnType = Substitution.fromPairs(typeParameterNodes, arguments)
+            .substituteType(builtOnType);
+      }
+      return builtOnType;
+    } else {
+      throw new UnsupportedError(
+          "ExtensionBuilder.buildTypesWithBuiltArguments "
+          "is not supported in library '${library.importUri}'.");
+    }
+  }
+
+  @override
+  int get typeVariablesCount => typeParameters?.length ?? 0;
+
+  List<DartType> buildTypeArguments(
+      LibraryBuilder library, List<TypeBuilder> arguments,
+      [bool notInstanceContext]) {
+    if (arguments == null && typeParameters == null) {
+      return <DartType>[];
+    }
+
+    if (arguments == null && typeParameters != null) {
+      List<DartType> result = new List<DartType>.filled(
+          typeParameters.length, null,
+          growable: true);
+      for (int i = 0; i < result.length; ++i) {
+        result[i] = typeParameters[i].defaultType.build(library);
+      }
+      if (library is SourceLibraryBuilder) {
+        library.inferredTypes.addAll(result);
+      }
+      return result;
+    }
+
+    if (arguments != null && arguments.length != typeVariablesCount) {
+      // That should be caught and reported as a compile-time error earlier.
+      return unhandled(
+          templateTypeArgumentMismatch
+              .withArguments(typeVariablesCount)
+              .message,
+          "buildTypeArguments",
+          -1,
+          null);
+    }
+
+    assert(arguments.length == typeVariablesCount);
+    List<DartType> result =
+        new List<DartType>.filled(arguments.length, null, growable: true);
+    for (int i = 0; i < result.length; ++i) {
+      result[i] = arguments[i].build(library);
+    }
+    return result;
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
index 6004b66..c0e9971 100644
--- a/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
@@ -37,6 +37,8 @@
 
 import '../scope.dart';
 
+import '../source/source_library_builder.dart';
+
 import 'builder.dart';
 import 'builtin_type_declaration_builder.dart';
 import 'class_builder.dart';
@@ -140,7 +142,9 @@
       return;
     } else if (member is TypeDeclarationBuilder) {
       declaration = member.origin;
-      if (!declaration.isExtension) {
+      if (!declaration.isExtension ||
+          library is SourceLibraryBuilder &&
+              library.enableExtensionTypesInLibrary) {
         return;
       }
     }
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index ec1a7ec..edcd72b 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -442,6 +442,11 @@
 
   DartType get implicitTypeArgument => const ImplicitTypeArgument();
 
+  @override
+  bool get enableExtensionTypesInLibrary {
+    return libraryBuilder.enableExtensionTypesInLibrary;
+  }
+
   void _enterLocalState({bool inLateLocalInitializer: false}) {
     _localInitializerState =
         _localInitializerState.prepend(inLateLocalInitializer);
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
index d179e00..3208247 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -2975,7 +2975,7 @@
   @override
   TypeBuilder buildTypeWithResolvedArguments(
       NullabilityBuilder nullabilityBuilder, List<UnresolvedType> arguments) {
-    if (declaration.isExtension) {
+    if (declaration.isExtension && !_helper.enableExtensionTypesInLibrary) {
       // Extension declarations cannot be used as types.
       return super
           .buildTypeWithResolvedArguments(nullabilityBuilder, arguments);
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
index 8d03df8..128205c 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
@@ -62,6 +62,8 @@
   /// `true` if we are in the type of an as expression.
   bool get inIsOrAsOperatorType;
 
+  bool get enableExtensionTypesInLibrary;
+
   scopeLookup(Scope scope, String name, Token token,
       {bool isQualified: false, PrefixBuilder prefix});
 
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index b476720..11b2502 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -299,6 +299,7 @@
   bool _enableTripleShiftInLibrary;
   bool _enableExtensionMethodsInLibrary;
   bool _enableGenericMetadataInLibrary;
+  bool _enableExtensionTypesInLibrary;
 
   bool get enableVarianceInLibrary =>
       _enableVarianceInLibrary ??= loader.target.isExperimentEnabledInLibrary(
@@ -337,6 +338,10 @@
       loader.target.isExperimentEnabledInLibrary(
           ExperimentalFlag.genericMetadata, _packageUri ?? importUri);
 
+  bool get enableExtensionTypesInLibrary => _enableExtensionTypesInLibrary ??=
+      loader.target.isExperimentEnabledInLibrary(
+          ExperimentalFlag.extensionTypes, _packageUri ?? importUri);
+
   void updateLibraryNNBDSettings() {
     library.isNonNullableByDefault = isNonNullableByDefault;
     if (enableNonNullableInLibrary) {
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index 1b92362..185fede 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -11,7 +11,10 @@
 
 a0x
 a1x
+a2i
 a2x
+a3i
+a4i
 aa
 aaa
 abc
diff --git a/pkg/front_end/testcases/extension_types/folder.options b/pkg/front_end/testcases/extension_types/folder.options
new file mode 100644
index 0000000..f936fab
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/folder.options
@@ -0,0 +1 @@
+--enable-experiment=extension-types
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extension_types/simple.dart b/pkg/front_end/testcases/extension_types/simple.dart
new file mode 100644
index 0000000..b9a9997
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/simple.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2021, 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.
+
+class Foo<X> {}
+class Bar<X, Y> {}
+
+extension A1 on dynamic {}
+A1 foo1(A1 a) => throw 42;
+
+extension A2<X> on Foo<X> {}
+A2 foo2(A2<int> a, A2 ai) => throw 42;
+
+extension A3<X, Y extends Function(X)> on Bar<X, Y> {}
+A3 foo3(A3<int, Function(num)> a, A3 ai) => throw 42;
+
+extension A4<X, Y extends Function(X)> on Foo<Y> {}
+A4 foo4(A4<int, Function(num)> a, A4 ai) => throw 42;
+
+bar() {
+  A1 a1;
+  A2<int> a2;
+  A2 a2i;
+  A3<int, Function(num)> a3;
+  A3 a3i;
+  A4<int, Function(num)> a4;
+  A4 a4i;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/extension_types/simple.dart.strong.expect b/pkg/front_end/testcases/extension_types/simple.dart.strong.expect
new file mode 100644
index 0000000..aa31646
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/simple.dart.strong.expect
@@ -0,0 +1,40 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Foo<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::Foo<self::Foo::X%>
+    : super core::Object::•()
+    ;
+}
+class Bar<X extends core::Object? = dynamic, Y extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::Bar<self::Bar::X%, self::Bar::Y%>
+    : super core::Object::•()
+    ;
+}
+extension A1 on dynamic {
+}
+extension A2<X extends core::Object? = dynamic> on self::Foo<X%> {
+}
+extension A3<X extends core::Object? = dynamic, Y extends (X%) → dynamic = (Never) → dynamic> on self::Bar<X%, Y> {
+}
+extension A4<X extends core::Object? = dynamic, Y extends (X%) → dynamic = (Never) → dynamic> on self::Foo<Y> {
+}
+static method foo1(dynamic a) → dynamic
+  return throw 42;
+static method foo2(self::Foo<core::int> a, self::Foo<dynamic> ai) → self::Foo<dynamic>
+  return throw 42;
+static method foo3(self::Bar<core::int, (core::num) → dynamic> a, self::Bar<dynamic, (Never) → dynamic> ai) → self::Bar<dynamic, (Never) → dynamic>
+  return throw 42;
+static method foo4(self::Foo<(core::num) → dynamic> a, self::Foo<(Never) → dynamic> ai) → self::Foo<(Never) → dynamic>
+  return throw 42;
+static method bar() → dynamic {
+  dynamic a1;
+  self::Foo<core::int> a2;
+  self::Foo<dynamic> a2i;
+  self::Bar<core::int, (core::num) → dynamic> a3;
+  self::Bar<dynamic, (Never) → dynamic> a3i;
+  self::Foo<(core::num) → dynamic> a4;
+  self::Foo<(Never) → dynamic> a4i;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extension_types/simple.dart.strong.transformed.expect b/pkg/front_end/testcases/extension_types/simple.dart.strong.transformed.expect
new file mode 100644
index 0000000..aa31646
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/simple.dart.strong.transformed.expect
@@ -0,0 +1,40 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Foo<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::Foo<self::Foo::X%>
+    : super core::Object::•()
+    ;
+}
+class Bar<X extends core::Object? = dynamic, Y extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::Bar<self::Bar::X%, self::Bar::Y%>
+    : super core::Object::•()
+    ;
+}
+extension A1 on dynamic {
+}
+extension A2<X extends core::Object? = dynamic> on self::Foo<X%> {
+}
+extension A3<X extends core::Object? = dynamic, Y extends (X%) → dynamic = (Never) → dynamic> on self::Bar<X%, Y> {
+}
+extension A4<X extends core::Object? = dynamic, Y extends (X%) → dynamic = (Never) → dynamic> on self::Foo<Y> {
+}
+static method foo1(dynamic a) → dynamic
+  return throw 42;
+static method foo2(self::Foo<core::int> a, self::Foo<dynamic> ai) → self::Foo<dynamic>
+  return throw 42;
+static method foo3(self::Bar<core::int, (core::num) → dynamic> a, self::Bar<dynamic, (Never) → dynamic> ai) → self::Bar<dynamic, (Never) → dynamic>
+  return throw 42;
+static method foo4(self::Foo<(core::num) → dynamic> a, self::Foo<(Never) → dynamic> ai) → self::Foo<(Never) → dynamic>
+  return throw 42;
+static method bar() → dynamic {
+  dynamic a1;
+  self::Foo<core::int> a2;
+  self::Foo<dynamic> a2i;
+  self::Bar<core::int, (core::num) → dynamic> a3;
+  self::Bar<dynamic, (Never) → dynamic> a3i;
+  self::Foo<(core::num) → dynamic> a4;
+  self::Foo<(Never) → dynamic> a4i;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extension_types/simple.dart.textual_outline.expect b/pkg/front_end/testcases/extension_types/simple.dart.textual_outline.expect
new file mode 100644
index 0000000..39e9531
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/simple.dart.textual_outline.expect
@@ -0,0 +1,21 @@
+class Foo<X> {}
+
+class Bar<X, Y> {}
+
+extension A1 on dynamic {}
+
+A1 foo1(A1 a) => throw 42;
+
+extension A2<X> on Foo<X> {}
+
+A2 foo2(A2<int> a, A2 ai) => throw 42;
+
+extension A3<X, Y extends Function(X)> on Bar<X, Y> {}
+
+A3 foo3(A3<int, Function(num)> a, A3 ai) => throw 42;
+
+extension A4<X, Y extends Function(X)> on Foo<Y> {}
+
+A4 foo4(A4<int, Function(num)> a, A4 ai) => throw 42;
+bar() {}
+main() {}
diff --git a/pkg/front_end/testcases/extension_types/simple.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/extension_types/simple.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..d876d2a
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/simple.dart.textual_outline_modelled.expect
@@ -0,0 +1,19 @@
+A1 foo1(A1 a) => throw 42;
+A2 foo2(A2<int> a, A2 ai) => throw 42;
+A3 foo3(A3<int, Function(num)> a, A3 ai) => throw 42;
+A4 foo4(A4<int, Function(num)> a, A4 ai) => throw 42;
+bar() {}
+
+class Bar<X, Y> {}
+
+class Foo<X> {}
+
+extension A1 on dynamic {}
+
+extension A2<X> on Foo<X> {}
+
+extension A3<X, Y extends Function(X)> on Bar<X, Y> {}
+
+extension A4<X, Y extends Function(X)> on Foo<Y> {}
+
+main() {}
diff --git a/pkg/front_end/testcases/extension_types/simple.dart.weak.expect b/pkg/front_end/testcases/extension_types/simple.dart.weak.expect
new file mode 100644
index 0000000..aa31646
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/simple.dart.weak.expect
@@ -0,0 +1,40 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Foo<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::Foo<self::Foo::X%>
+    : super core::Object::•()
+    ;
+}
+class Bar<X extends core::Object? = dynamic, Y extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::Bar<self::Bar::X%, self::Bar::Y%>
+    : super core::Object::•()
+    ;
+}
+extension A1 on dynamic {
+}
+extension A2<X extends core::Object? = dynamic> on self::Foo<X%> {
+}
+extension A3<X extends core::Object? = dynamic, Y extends (X%) → dynamic = (Never) → dynamic> on self::Bar<X%, Y> {
+}
+extension A4<X extends core::Object? = dynamic, Y extends (X%) → dynamic = (Never) → dynamic> on self::Foo<Y> {
+}
+static method foo1(dynamic a) → dynamic
+  return throw 42;
+static method foo2(self::Foo<core::int> a, self::Foo<dynamic> ai) → self::Foo<dynamic>
+  return throw 42;
+static method foo3(self::Bar<core::int, (core::num) → dynamic> a, self::Bar<dynamic, (Never) → dynamic> ai) → self::Bar<dynamic, (Never) → dynamic>
+  return throw 42;
+static method foo4(self::Foo<(core::num) → dynamic> a, self::Foo<(Never) → dynamic> ai) → self::Foo<(Never) → dynamic>
+  return throw 42;
+static method bar() → dynamic {
+  dynamic a1;
+  self::Foo<core::int> a2;
+  self::Foo<dynamic> a2i;
+  self::Bar<core::int, (core::num) → dynamic> a3;
+  self::Bar<dynamic, (Never) → dynamic> a3i;
+  self::Foo<(core::num) → dynamic> a4;
+  self::Foo<(Never) → dynamic> a4i;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extension_types/simple.dart.weak.outline.expect b/pkg/front_end/testcases/extension_types/simple.dart.weak.outline.expect
new file mode 100644
index 0000000..3364bc3
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/simple.dart.weak.outline.expect
@@ -0,0 +1,32 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Foo<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::Foo<self::Foo::X%>
+    ;
+}
+class Bar<X extends core::Object? = dynamic, Y extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::Bar<self::Bar::X%, self::Bar::Y%>
+    ;
+}
+extension A1 on dynamic {
+}
+extension A2<X extends core::Object? = dynamic> on self::Foo<X%> {
+}
+extension A3<X extends core::Object? = dynamic, Y extends (X%) → dynamic = (Never) → dynamic> on self::Bar<X%, Y> {
+}
+extension A4<X extends core::Object? = dynamic, Y extends (X%) → dynamic = (Never) → dynamic> on self::Foo<Y> {
+}
+static method foo1(dynamic a) → dynamic
+  ;
+static method foo2(self::Foo<core::int> a, self::Foo<dynamic> ai) → self::Foo<dynamic>
+  ;
+static method foo3(self::Bar<core::int, (core::num) → dynamic> a, self::Bar<dynamic, (Never) → dynamic> ai) → self::Bar<dynamic, (Never) → dynamic>
+  ;
+static method foo4(self::Foo<(core::num) → dynamic> a, self::Foo<(Never) → dynamic> ai) → self::Foo<(Never) → dynamic>
+  ;
+static method bar() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extension_types/simple.dart.weak.transformed.expect b/pkg/front_end/testcases/extension_types/simple.dart.weak.transformed.expect
new file mode 100644
index 0000000..aa31646
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/simple.dart.weak.transformed.expect
@@ -0,0 +1,40 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Foo<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::Foo<self::Foo::X%>
+    : super core::Object::•()
+    ;
+}
+class Bar<X extends core::Object? = dynamic, Y extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::Bar<self::Bar::X%, self::Bar::Y%>
+    : super core::Object::•()
+    ;
+}
+extension A1 on dynamic {
+}
+extension A2<X extends core::Object? = dynamic> on self::Foo<X%> {
+}
+extension A3<X extends core::Object? = dynamic, Y extends (X%) → dynamic = (Never) → dynamic> on self::Bar<X%, Y> {
+}
+extension A4<X extends core::Object? = dynamic, Y extends (X%) → dynamic = (Never) → dynamic> on self::Foo<Y> {
+}
+static method foo1(dynamic a) → dynamic
+  return throw 42;
+static method foo2(self::Foo<core::int> a, self::Foo<dynamic> ai) → self::Foo<dynamic>
+  return throw 42;
+static method foo3(self::Bar<core::int, (core::num) → dynamic> a, self::Bar<dynamic, (Never) → dynamic> ai) → self::Bar<dynamic, (Never) → dynamic>
+  return throw 42;
+static method foo4(self::Foo<(core::num) → dynamic> a, self::Foo<(Never) → dynamic> ai) → self::Foo<(Never) → dynamic>
+  return throw 42;
+static method bar() → dynamic {
+  dynamic a1;
+  self::Foo<core::int> a2;
+  self::Foo<dynamic> a2i;
+  self::Bar<core::int, (core::num) → dynamic> a3;
+  self::Bar<dynamic, (Never) → dynamic> a3i;
+  self::Foo<(core::num) → dynamic> a4;
+  self::Foo<(Never) → dynamic> a4i;
+}
+static method main() → dynamic {}