[cfe] Allow generic types in arguments and bounds under a flag

The flag that enables the feature is the 'generic-metadata' experiment
flag.

Bug: https://github.com/dart-lang/sdk/issues/44916
Change-Id: I2770c672280831bf5af6643fde9cb0f1be3083b8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/188701
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index 92ac343..3017856 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -425,19 +425,21 @@
     Library library = libraryBuilder.library;
 
     List<TypeArgumentIssue> issues = findTypeArgumentIssues(
-        library,
         new InterfaceType(
             supertype.classNode, library.nonNullable, supertype.typeArguments),
         typeEnvironment,
         libraryBuilder.isNonNullableByDefault
             ? SubtypeCheckMode.withNullabilities
             : SubtypeCheckMode.ignoringNullabilities,
-        allowSuperBounded: false);
+        allowSuperBounded: false,
+        isNonNullableByDefault: library.isNonNullableByDefault,
+        areGenericArgumentsAllowed:
+            libraryBuilder.enableGenericMetadataInLibrary);
     for (TypeArgumentIssue issue in issues) {
       DartType argument = issue.argument;
       TypeParameter typeParameter = issue.typeParameter;
       bool inferred = libraryBuilder.inferredTypes.contains(argument);
-      if (isGenericFunctionTypeOrAlias(argument)) {
+      if (issue.isGenericTypeAsArgumentIssue) {
         if (inferred) {
           // Supertype can't be or contain super-bounded types, so null is
           // passed for super-bounded hint here.
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 e3158d4..e409ff0 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
@@ -32,8 +32,7 @@
         TypeArgumentIssue,
         findTypeArgumentIssues,
         findTypeArgumentIssuesForInvocation,
-        getGenericTypeName,
-        isGenericFunctionTypeOrAlias;
+        getGenericTypeName;
 
 import 'package:kernel/type_algebra.dart' show Substitution, substitute;
 
@@ -2923,15 +2922,17 @@
 
       bool haveErroneousBounds = false;
       if (!inErrorRecovery) {
-        for (int i = 0; i < variables.length; ++i) {
-          TypeVariableBuilder variable = variables[i];
-          List<TypeBuilder> genericFunctionTypes = <TypeBuilder>[];
-          findGenericFunctionTypes(variable.bound,
-              result: genericFunctionTypes);
-          if (genericFunctionTypes.length > 0) {
-            haveErroneousBounds = true;
-            addProblem(messageGenericFunctionTypeInBound, variable.charOffset,
-                variable.name.length, variable.fileUri);
+        if (!enableGenericMetadataInLibrary) {
+          for (int i = 0; i < variables.length; ++i) {
+            TypeVariableBuilder variable = variables[i];
+            List<TypeBuilder> genericFunctionTypes = <TypeBuilder>[];
+            findGenericFunctionTypes(variable.bound,
+                result: genericFunctionTypes);
+            if (genericFunctionTypes.length > 0) {
+              haveErroneousBounds = true;
+              addProblem(messageGenericFunctionTypeInBound, variable.charOffset,
+                  variable.name.length, variable.fileUri);
+            }
           }
         }
 
@@ -3170,7 +3171,7 @@
           inferredTypes.contains(argument);
       offset =
           typeArgumentsInfo?.getOffsetForIndex(issue.index, offset) ?? offset;
-      if (isGenericFunctionTypeOrAlias(argument)) {
+      if (issue.isGenericTypeAsArgumentIssue) {
         if (issueInferred) {
           message = templateGenericFunctionTypeInferredAsActualTypeArgument
               .withArguments(argument, isNonNullableByDefault);
@@ -3221,10 +3222,14 @@
         }
       }
 
+      // Don't show the hint about an attempted super-bounded type if the issue
+      // with the argument is that it's generic.
       reportTypeArgumentIssue(message, fileUri, offset,
           typeParameter: typeParameter,
-          superBoundedAttempt: issue.enclosingType,
-          superBoundedAttemptInverted: issue.invertedType);
+          superBoundedAttempt:
+              issue.isGenericTypeAsArgumentIssue ? null : issue.enclosingType,
+          superBoundedAttemptInverted:
+              issue.isGenericTypeAsArgumentIssue ? null : issue.invertedType);
     }
   }
 
@@ -3306,13 +3311,14 @@
     // Check in bounds of own type variables.
     for (TypeParameter parameter in typeParameters) {
       List<TypeArgumentIssue> issues = findTypeArgumentIssues(
-          library,
           parameter.bound,
           typeEnvironment,
           isNonNullableByDefault
               ? SubtypeCheckMode.withNullabilities
               : SubtypeCheckMode.ignoringNullabilities,
-          allowSuperBounded: true);
+          allowSuperBounded: true,
+          isNonNullableByDefault: library.isNonNullableByDefault,
+          areGenericArgumentsAllowed: enableGenericMetadataInLibrary);
       for (TypeArgumentIssue issue in issues) {
         DartType argument = issue.argument;
         TypeParameter typeParameter = issue.typeParameter;
@@ -3325,7 +3331,7 @@
           continue;
         }
 
-        if (isGenericFunctionTypeOrAlias(argument)) {
+        if (issue.isGenericTypeAsArgumentIssue) {
           reportTypeArgumentIssue(
               messageGenericFunctionTypeUsedAsActualTypeArgument,
               fileUri,
@@ -3382,13 +3388,14 @@
     }
     if (!skipReturnType && returnType != null) {
       List<TypeArgumentIssue> issues = findTypeArgumentIssues(
-          library,
           returnType,
           typeEnvironment,
           isNonNullableByDefault
               ? SubtypeCheckMode.withNullabilities
               : SubtypeCheckMode.ignoringNullabilities,
-          allowSuperBounded: true);
+          allowSuperBounded: true,
+          isNonNullableByDefault: library.isNonNullableByDefault,
+          areGenericArgumentsAllowed: enableGenericMetadataInLibrary);
       for (TypeArgumentIssue issue in issues) {
         DartType argument = issue.argument;
         TypeParameter typeParameter = issue.typeParameter;
@@ -3396,7 +3403,7 @@
         // We don't need to check if [argument] was inferred or specified
         // here, because inference in return types boils down to instantiate-
         // -to-bound, and it can't provide a type that violates the bound.
-        if (isGenericFunctionTypeOrAlias(argument)) {
+        if (issue.isGenericTypeAsArgumentIssue) {
           reportTypeArgumentIssue(
               messageGenericFunctionTypeUsedAsActualTypeArgument,
               fileUri,
@@ -3490,13 +3497,14 @@
       DartType type, TypeEnvironment typeEnvironment, Uri fileUri, int offset,
       {bool inferred, bool allowSuperBounded = true}) {
     List<TypeArgumentIssue> issues = findTypeArgumentIssues(
-        library,
         type,
         typeEnvironment,
         isNonNullableByDefault
             ? SubtypeCheckMode.withNullabilities
             : SubtypeCheckMode.ignoringNullabilities,
-        allowSuperBounded: allowSuperBounded);
+        allowSuperBounded: allowSuperBounded,
+        isNonNullableByDefault: library.isNonNullableByDefault,
+        areGenericArgumentsAllowed: enableGenericMetadataInLibrary);
     reportTypeArgumentIssues(issues, fileUri, offset, inferred: inferred);
   }
 
@@ -3554,14 +3562,15 @@
         ? const NeverType.nonNullable()
         : const NullType();
     List<TypeArgumentIssue> issues = findTypeArgumentIssuesForInvocation(
-        library,
         parameters,
         arguments,
         typeEnvironment,
         isNonNullableByDefault
             ? SubtypeCheckMode.withNullabilities
             : SubtypeCheckMode.ignoringNullabilities,
-        bottomType);
+        bottomType,
+        isNonNullableByDefault: library.isNonNullableByDefault,
+        areGenericArgumentsAllowed: enableGenericMetadataInLibrary);
     if (issues.isNotEmpty) {
       DartType targetReceiver;
       if (klass != null) {
@@ -3631,14 +3640,15 @@
         ? const NeverType.nonNullable()
         : const NullType();
     List<TypeArgumentIssue> issues = findTypeArgumentIssuesForInvocation(
-        library,
         instantiatedMethodParameters,
         arguments.types,
         typeEnvironment,
         isNonNullableByDefault
             ? SubtypeCheckMode.withNullabilities
             : SubtypeCheckMode.ignoringNullabilities,
-        bottomType);
+        bottomType,
+        isNonNullableByDefault: library.isNonNullableByDefault,
+        areGenericArgumentsAllowed: enableGenericMetadataInLibrary);
     reportTypeArgumentIssues(issues, fileUri, offset,
         typeArgumentsInfo: getTypeArgumentsInfo(arguments),
         targetReceiver: receiverType,
diff --git a/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart b/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart
new file mode 100644
index 0000000..c64ec6b
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart
@@ -0,0 +1,15 @@
+// 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 A<X> {}
+
+A<Y> foo<Y>(Y y) => throw 42;
+
+test() {
+  var x = foo(<Z>(Z) => throw 42);
+  var y = [foo];
+  var z = {y.first};
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.strong.expect b/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.strong.expect
new file mode 100644
index 0000000..19d9303
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.strong.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:collection" as col;
+
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+static method foo<Y extends core::Object? = dynamic>(self::foo::Y% y) → self::A<self::foo::Y%>
+  return throw 42;
+static method test() → dynamic {
+  self::A<<Z extends core::Object? = dynamic>(dynamic) → Never> x = self::foo<<Z extends core::Object? = dynamic>(dynamic) → Never>(<Z extends core::Object? = dynamic>(dynamic Z) → Never => throw 42);
+  core::List<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> y = <<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>>[#C1];
+  core::Set<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> z = block {
+    final core::Set<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> #t1 = col::LinkedHashSet::•<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>>();
+    #t1.{core::Set::add}{Invariant}(y.{core::Iterable::first});
+  } =>#t1;
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = tearoff self::foo
+}
diff --git a/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.strong.transformed.expect b/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.strong.transformed.expect
new file mode 100644
index 0000000..82c52ba
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.strong.transformed.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:collection" as col;
+
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+static method foo<Y extends core::Object? = dynamic>(self::foo::Y% y) → self::A<self::foo::Y%>
+  return throw 42;
+static method test() → dynamic {
+  self::A<<Z extends core::Object? = dynamic>(dynamic) → Never> x = self::foo<<Z extends core::Object? = dynamic>(dynamic) → Never>(<Z extends core::Object? = dynamic>(dynamic Z) → Never => throw 42);
+  core::List<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> y = core::_GrowableList::_literal1<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>>(#C1);
+  core::Set<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> z = block {
+    final core::Set<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> #t1 = new col::_CompactLinkedHashSet::•<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>>();
+    #t1.{core::Set::add}{Invariant}(y.{core::Iterable::first});
+  } =>#t1;
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = tearoff self::foo
+}
diff --git a/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.textual_outline.expect b/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.textual_outline.expect
new file mode 100644
index 0000000..15f399b
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.textual_outline.expect
@@ -0,0 +1,5 @@
+class A<X> {}
+
+A<Y> foo<Y>(Y y) => throw 42;
+test() {}
+main() {}
diff --git a/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..1bbbdaf
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.textual_outline_modelled.expect
@@ -0,0 +1,6 @@
+A<Y> foo<Y>(Y y) => throw 42;
+
+class A<X> {}
+
+main() {}
+test() {}
diff --git a/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.weak.expect b/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.weak.expect
new file mode 100644
index 0000000..19d9303
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.weak.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:collection" as col;
+
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+static method foo<Y extends core::Object? = dynamic>(self::foo::Y% y) → self::A<self::foo::Y%>
+  return throw 42;
+static method test() → dynamic {
+  self::A<<Z extends core::Object? = dynamic>(dynamic) → Never> x = self::foo<<Z extends core::Object? = dynamic>(dynamic) → Never>(<Z extends core::Object? = dynamic>(dynamic Z) → Never => throw 42);
+  core::List<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> y = <<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>>[#C1];
+  core::Set<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> z = block {
+    final core::Set<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> #t1 = col::LinkedHashSet::•<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>>();
+    #t1.{core::Set::add}{Invariant}(y.{core::Iterable::first});
+  } =>#t1;
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = tearoff self::foo
+}
diff --git a/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.weak.outline.expect b/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.weak.outline.expect
new file mode 100644
index 0000000..e9d3b90
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.weak.outline.expect
@@ -0,0 +1,14 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    ;
+}
+static method foo<Y extends core::Object? = dynamic>(self::foo::Y% y) → self::A<self::foo::Y%>
+  ;
+static method test() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.weak.transformed.expect b/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.weak.transformed.expect
new file mode 100644
index 0000000..82c52ba
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/inferred_generic_types_in_arguments_and_bounds.dart.weak.transformed.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:collection" as col;
+
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+static method foo<Y extends core::Object? = dynamic>(self::foo::Y% y) → self::A<self::foo::Y%>
+  return throw 42;
+static method test() → dynamic {
+  self::A<<Z extends core::Object? = dynamic>(dynamic) → Never> x = self::foo<<Z extends core::Object? = dynamic>(dynamic) → Never>(<Z extends core::Object? = dynamic>(dynamic Z) → Never => throw 42);
+  core::List<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> y = core::_GrowableList::_literal1<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>>(#C1);
+  core::Set<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> z = block {
+    final core::Set<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> #t1 = new col::_CompactLinkedHashSet::•<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>>();
+    #t1.{core::Set::add}{Invariant}(y.{core::Iterable::first});
+  } =>#t1;
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = tearoff self::foo
+}
diff --git a/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart b/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart
new file mode 100644
index 0000000..7f7f46e
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart
@@ -0,0 +1,15 @@
+// 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 A<X> {}
+
+A<Function<Y>(Y)> foo(A<Function<Y>(Y)> x) => throw 42;
+
+class B extends A<Function<Y>(Y)> {}
+
+class C<Z extends Function<Y>(Y)> {}
+
+bar<V extends Function<Y>(Y)>() => throw 42;
+
+main() {}
diff --git a/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.strong.expect b/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.strong.expect
new file mode 100644
index 0000000..0777872
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.strong.expect
@@ -0,0 +1,24 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+class B extends self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> {
+  synthetic constructor •() → self::B
+    : super self::A::•()
+    ;
+}
+class C<Z extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic> extends core::Object {
+  synthetic constructor •() → self::C<self::C::Z>
+    : super core::Object::•()
+    ;
+}
+static method foo(self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> x) → self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic>
+  return throw 42;
+static method bar<V extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic>() → dynamic
+  return throw 42;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.strong.transformed.expect b/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.strong.transformed.expect
new file mode 100644
index 0000000..0777872
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.strong.transformed.expect
@@ -0,0 +1,24 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+class B extends self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> {
+  synthetic constructor •() → self::B
+    : super self::A::•()
+    ;
+}
+class C<Z extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic> extends core::Object {
+  synthetic constructor •() → self::C<self::C::Z>
+    : super core::Object::•()
+    ;
+}
+static method foo(self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> x) → self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic>
+  return throw 42;
+static method bar<V extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic>() → dynamic
+  return throw 42;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.textual_outline.expect b/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.textual_outline.expect
new file mode 100644
index 0000000..8acc194
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.textual_outline.expect
@@ -0,0 +1,10 @@
+class A<X> {}
+
+A<Function<Y>(Y)> foo(A<Function<Y>(Y)> x) => throw 42;
+
+class B extends A<Function<Y>(Y)> {}
+
+class C<Z extends Function<Y>(Y)> {}
+
+bar<V extends Function<Y>(Y)>() => throw 42;
+main() {}
diff --git a/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..d712596
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.textual_outline_modelled.expect
@@ -0,0 +1,10 @@
+A<Function<Y>(Y)> foo(A<Function<Y>(Y)> x) => throw 42;
+bar<V extends Function<Y>(Y)>() => throw 42;
+
+class A<X> {}
+
+class B extends A<Function<Y>(Y)> {}
+
+class C<Z extends Function<Y>(Y)> {}
+
+main() {}
diff --git a/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.weak.expect b/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.weak.expect
new file mode 100644
index 0000000..0777872
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.weak.expect
@@ -0,0 +1,24 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+class B extends self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> {
+  synthetic constructor •() → self::B
+    : super self::A::•()
+    ;
+}
+class C<Z extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic> extends core::Object {
+  synthetic constructor •() → self::C<self::C::Z>
+    : super core::Object::•()
+    ;
+}
+static method foo(self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> x) → self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic>
+  return throw 42;
+static method bar<V extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic>() → dynamic
+  return throw 42;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.weak.outline.expect b/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.weak.outline.expect
new file mode 100644
index 0000000..13fcc95
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.weak.outline.expect
@@ -0,0 +1,22 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    ;
+}
+class B extends self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> {
+  synthetic constructor •() → self::B
+    ;
+}
+class C<Z extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic> extends core::Object {
+  synthetic constructor •() → self::C<self::C::Z>
+    ;
+}
+static method foo(self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> x) → self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic>
+  ;
+static method bar<V extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic>() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.weak.transformed.expect b/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.weak.transformed.expect
new file mode 100644
index 0000000..0777872
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/simple_generic_types_in_arguments_and_bounds.dart.weak.transformed.expect
@@ -0,0 +1,24 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+class B extends self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> {
+  synthetic constructor •() → self::B
+    : super self::A::•()
+    ;
+}
+class C<Z extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic> extends core::Object {
+  synthetic constructor •() → self::C<self::C::Z>
+    : super core::Object::•()
+    ;
+}
+static method foo(self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> x) → self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic>
+  return throw 42;
+static method bar<V extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic>() → dynamic
+  return throw 42;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart b/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart
new file mode 100644
index 0000000..3c977a6
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart
@@ -0,0 +1,17 @@
+// 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.
+
+typedef F = Function<Y>(Y);
+
+class A<X> {}
+
+A<F> foo(A<F> x) => throw 42;
+
+class B extends A<F> {}
+
+class C<Z extends F> {}
+
+bar<V extends F>() => throw 42;
+
+main() {}
diff --git a/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.strong.expect b/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.strong.expect
new file mode 100644
index 0000000..dd20ce4
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.strong.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef F = <Y extends core::Object? = dynamic>(Y%) → dynamic;
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+class B extends self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> {
+  synthetic constructor •() → self::B
+    : super self::A::•()
+    ;
+}
+class C<Z extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic> extends core::Object {
+  synthetic constructor •() → self::C<self::C::Z>
+    : super core::Object::•()
+    ;
+}
+static method foo(self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> x) → self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic>
+  return throw 42;
+static method bar<V extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic>() → dynamic
+  return throw 42;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.strong.transformed.expect b/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.strong.transformed.expect
new file mode 100644
index 0000000..dd20ce4
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.strong.transformed.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef F = <Y extends core::Object? = dynamic>(Y%) → dynamic;
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+class B extends self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> {
+  synthetic constructor •() → self::B
+    : super self::A::•()
+    ;
+}
+class C<Z extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic> extends core::Object {
+  synthetic constructor •() → self::C<self::C::Z>
+    : super core::Object::•()
+    ;
+}
+static method foo(self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> x) → self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic>
+  return throw 42;
+static method bar<V extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic>() → dynamic
+  return throw 42;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.textual_outline.expect b/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.textual_outline.expect
new file mode 100644
index 0000000..23b49a3
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.textual_outline.expect
@@ -0,0 +1,12 @@
+typedef F = Function<Y>(Y);
+
+class A<X> {}
+
+A<F> foo(A<F> x) => throw 42;
+
+class B extends A<F> {}
+
+class C<Z extends F> {}
+
+bar<V extends F>() => throw 42;
+main() {}
diff --git a/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..7ff1fb8
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.textual_outline_modelled.expect
@@ -0,0 +1,11 @@
+A<F> foo(A<F> x) => throw 42;
+bar<V extends F>() => throw 42;
+
+class A<X> {}
+
+class B extends A<F> {}
+
+class C<Z extends F> {}
+
+main() {}
+typedef F = Function<Y>(Y);
diff --git a/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.weak.expect b/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.weak.expect
new file mode 100644
index 0000000..dd20ce4
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.weak.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef F = <Y extends core::Object? = dynamic>(Y%) → dynamic;
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+class B extends self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> {
+  synthetic constructor •() → self::B
+    : super self::A::•()
+    ;
+}
+class C<Z extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic> extends core::Object {
+  synthetic constructor •() → self::C<self::C::Z>
+    : super core::Object::•()
+    ;
+}
+static method foo(self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> x) → self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic>
+  return throw 42;
+static method bar<V extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic>() → dynamic
+  return throw 42;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.weak.outline.expect b/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.weak.outline.expect
new file mode 100644
index 0000000..1fbe2f1
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.weak.outline.expect
@@ -0,0 +1,23 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef F = <Y extends core::Object? = dynamic>(Y%) → dynamic;
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    ;
+}
+class B extends self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> {
+  synthetic constructor •() → self::B
+    ;
+}
+class C<Z extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic> extends core::Object {
+  synthetic constructor •() → self::C<self::C::Z>
+    ;
+}
+static method foo(self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> x) → self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic>
+  ;
+static method bar<V extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic>() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.weak.transformed.expect b/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.weak.transformed.expect
new file mode 100644
index 0000000..dd20ce4
--- /dev/null
+++ b/pkg/front_end/testcases/generic_metadata/typedef_generic_types_in_arguments_and_bounds.dart.weak.transformed.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef F = <Y extends core::Object? = dynamic>(Y%) → dynamic;
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X%>
+    : super core::Object::•()
+    ;
+}
+class B extends self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> {
+  synthetic constructor •() → self::B
+    : super self::A::•()
+    ;
+}
+class C<Z extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic> extends core::Object {
+  synthetic constructor •() → self::C<self::C::Z>
+    : super core::Object::•()
+    ;
+}
+static method foo(self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> x) → self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic>
+  return throw 42;
+static method bar<V extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic>() → dynamic
+  return throw 42;
+static method main() → dynamic {}
diff --git a/pkg/kernel/lib/src/bounds_checks.dart b/pkg/kernel/lib/src/bounds_checks.dart
index f5a3b7f..6505325 100644
--- a/pkg/kernel/lib/src/bounds_checks.dart
+++ b/pkg/kernel/lib/src/bounds_checks.dart
@@ -237,9 +237,11 @@
   /// helpful to show the same type to the user.
   DartType? invertedType;
 
+  final bool isGenericTypeAsArgumentIssue;
+
   TypeArgumentIssue(
       this.index, this.argument, this.typeParameter, this.enclosingType,
-      {this.invertedType});
+      {this.invertedType, this.isGenericTypeAsArgumentIssue = false});
 
   int get hashCode {
     int hash = 0x3fffffff & index;
@@ -271,9 +273,16 @@
 // checks for super-boundness for construction of the auxiliary type.  For
 // details see Dart Language Specification, Section 14.3.2 The Instantiation to
 // Bound Algorithm.
-List<TypeArgumentIssue> findTypeArgumentIssues(Library library, DartType type,
+List<TypeArgumentIssue> findTypeArgumentIssues(DartType type,
     TypeEnvironment typeEnvironment, SubtypeCheckMode subtypeCheckMode,
-    {bool allowSuperBounded = false}) {
+    {bool allowSuperBounded = false,
+    required bool isNonNullableByDefault,
+    required bool areGenericArgumentsAllowed}) {
+  // ignore: unnecessary_null_comparison
+  assert(isNonNullableByDefault != null);
+  // ignore: unnecessary_null_comparison
+  assert(areGenericArgumentsAllowed != null);
+
   List<TypeParameter> variables = const <TypeParameter>[];
   List<DartType> arguments = const <DartType>[];
   List<TypeArgumentIssue> typedefRhsResult = const <TypeArgumentIssue>[];
@@ -291,8 +300,10 @@
         requiredParameterCount: functionType.requiredParameterCount,
         typedefType: null);
     typedefRhsResult = findTypeArgumentIssues(
-        library, cloned, typeEnvironment, subtypeCheckMode,
-        allowSuperBounded: true);
+        cloned, typeEnvironment, subtypeCheckMode,
+        allowSuperBounded: true,
+        isNonNullableByDefault: isNonNullableByDefault,
+        areGenericArgumentsAllowed: areGenericArgumentsAllowed);
     type = functionType.typedefType!;
   }
 
@@ -307,25 +318,33 @@
 
     for (TypeParameter parameter in type.typeParameters) {
       result.addAll(findTypeArgumentIssues(
-          library, parameter.bound!, typeEnvironment, subtypeCheckMode,
-          allowSuperBounded: true));
+          parameter.bound!, typeEnvironment, subtypeCheckMode,
+          allowSuperBounded: true,
+          isNonNullableByDefault: isNonNullableByDefault,
+          areGenericArgumentsAllowed: areGenericArgumentsAllowed));
     }
 
     for (DartType formal in type.positionalParameters) {
       result.addAll(findTypeArgumentIssues(
-          library, formal, typeEnvironment, subtypeCheckMode,
-          allowSuperBounded: true));
+          formal, typeEnvironment, subtypeCheckMode,
+          allowSuperBounded: true,
+          isNonNullableByDefault: isNonNullableByDefault,
+          areGenericArgumentsAllowed: areGenericArgumentsAllowed));
     }
 
     for (NamedType named in type.namedParameters) {
       result.addAll(findTypeArgumentIssues(
-          library, named.type, typeEnvironment, subtypeCheckMode,
-          allowSuperBounded: true));
+          named.type, typeEnvironment, subtypeCheckMode,
+          allowSuperBounded: true,
+          isNonNullableByDefault: isNonNullableByDefault,
+          areGenericArgumentsAllowed: areGenericArgumentsAllowed));
     }
 
     result.addAll(findTypeArgumentIssues(
-        library, type.returnType, typeEnvironment, subtypeCheckMode,
-        allowSuperBounded: true));
+        type.returnType, typeEnvironment, subtypeCheckMode,
+        allowSuperBounded: true,
+        isNonNullableByDefault: isNonNullableByDefault,
+        areGenericArgumentsAllowed: areGenericArgumentsAllowed));
 
     return result;
   } else if (type is FutureOrType) {
@@ -348,12 +367,13 @@
       new Map<TypeParameter, DartType>.fromIterables(variables, arguments);
   for (int i = 0; i < arguments.length; ++i) {
     DartType argument = arguments[i];
-    if (isGenericFunctionTypeOrAlias(argument)) {
+    if (!areGenericArgumentsAllowed && isGenericFunctionTypeOrAlias(argument)) {
       // Generic function types aren't allowed as type arguments either.
-      result.add(new TypeArgumentIssue(i, argument, variables[i], type));
+      result.add(new TypeArgumentIssue(i, argument, variables[i], type,
+          isGenericTypeAsArgumentIssue: true));
     } else if (variables[i].bound is! InvalidType) {
       DartType bound = substitute(variables[i].bound!, substitutionMap);
-      if (!library.isNonNullableByDefault) {
+      if (!isNonNullableByDefault) {
         bound = legacyErasure(bound);
       }
       if (!typeEnvironment.isSubtypeOf(argument, bound, subtypeCheckMode)) {
@@ -365,8 +385,10 @@
     }
 
     argumentsResult.addAll(findTypeArgumentIssues(
-        library, argument, typeEnvironment, subtypeCheckMode,
-        allowSuperBounded: true));
+        argument, typeEnvironment, subtypeCheckMode,
+        allowSuperBounded: true,
+        isNonNullableByDefault: isNonNullableByDefault,
+        areGenericArgumentsAllowed: areGenericArgumentsAllowed));
   }
   result.addAll(argumentsResult);
   result.addAll(typedefRhsResult);
@@ -376,8 +398,9 @@
   if (!allowSuperBounded) return result;
 
   bool isCorrectSuperBounded = true;
-  DartType? invertedType =
-      convertSuperBoundedToRegularBounded(library, typeEnvironment, type);
+  DartType? invertedType = convertSuperBoundedToRegularBounded(
+      typeEnvironment, type,
+      isNonNullableByDefault: isNonNullableByDefault);
 
   // The auxiliary type is the same as [type].  At this point we know that
   // [type] is not regular-bounded, which means that the inverted type is also
@@ -436,14 +459,21 @@
 // details see Dart Language Specification, Section 14.3.2 The Instantiation to
 // Bound Algorithm.
 List<TypeArgumentIssue> findTypeArgumentIssuesForInvocation(
-    Library library,
     List<TypeParameter> parameters,
     List<DartType> arguments,
     TypeEnvironment typeEnvironment,
     SubtypeCheckMode subtypeCheckMode,
-    DartType bottomType) {
+    DartType bottomType,
+    {required bool isNonNullableByDefault,
+    required bool areGenericArgumentsAllowed}) {
+  // ignore: unnecessary_null_comparison
+  assert(isNonNullableByDefault != null);
+  // ignore: unnecessary_null_comparison
+  assert(areGenericArgumentsAllowed != null);
+
   assert(arguments.length == parameters.length);
   assert(bottomType == const NeverType.nonNullable() || bottomType is NullType);
+
   List<TypeArgumentIssue> result = <TypeArgumentIssue>[];
   Map<TypeParameter, DartType> substitutionMap = <TypeParameter, DartType>{};
   for (int i = 0; i < arguments.length; ++i) {
@@ -452,13 +482,17 @@
   for (int i = 0; i < arguments.length; ++i) {
     DartType argument = arguments[i];
     if (argument is TypeParameterType && argument.promotedBound != null) {
+      // TODO(dmitryas): Consider recognizing this case with a flag on the issue
+      // object.
       result.add(new TypeArgumentIssue(i, argument, parameters[i], null));
-    } else if (isGenericFunctionTypeOrAlias(argument)) {
+    } else if (!areGenericArgumentsAllowed &&
+        isGenericFunctionTypeOrAlias(argument)) {
       // Generic function types aren't allowed as type arguments either.
-      result.add(new TypeArgumentIssue(i, argument, parameters[i], null));
+      result.add(new TypeArgumentIssue(i, argument, parameters[i], null,
+          isGenericTypeAsArgumentIssue: true));
     } else if (parameters[i].bound is! InvalidType) {
       DartType bound = substitute(parameters[i].bound!, substitutionMap);
-      if (!library.isNonNullableByDefault) {
+      if (!isNonNullableByDefault) {
         bound = legacyErasure(bound);
       }
       if (!typeEnvironment.isSubtypeOf(argument, bound, subtypeCheckMode)) {
@@ -467,8 +501,10 @@
     }
 
     result.addAll(findTypeArgumentIssues(
-        library, argument, typeEnvironment, subtypeCheckMode,
-        allowSuperBounded: true));
+        argument, typeEnvironment, subtypeCheckMode,
+        allowSuperBounded: true,
+        isNonNullableByDefault: isNonNullableByDefault,
+        areGenericArgumentsAllowed: areGenericArgumentsAllowed));
   }
   return result;
 }
@@ -486,11 +522,14 @@
 /// [BottomType] and all contravariant occurrences of `Null` and [BottomType]
 /// with `Object`.  Returns null if the converted type is the same as [type].
 DartType? convertSuperBoundedToRegularBounded(
-    Library clientLibrary, TypeEnvironment typeEnvironment, DartType type,
-    {int variance = Variance.covariant}) {
+    TypeEnvironment typeEnvironment, DartType type,
+    {int variance = Variance.covariant, required bool isNonNullableByDefault}) {
+  // ignore: unnecessary_null_comparison
+  assert(isNonNullableByDefault != null);
+
   return type.accept1(
       new _SuperBoundedTypeInverter(typeEnvironment,
-          isNonNullableByDefault: clientLibrary.isNonNullableByDefault),
+          isNonNullableByDefault: isNonNullableByDefault),
       variance);
 }