Version 2.13.0-172.0.dev

Merge commit '5621c9f76702123df04e13412e14105c50bf7959' into 'dev'
diff --git a/pkg/analysis_server/tool/code_completion/completion_metrics.dart b/pkg/analysis_server/tool/code_completion/completion_metrics.dart
index 850ffd7..1479595 100644
--- a/pkg/analysis_server/tool/code_completion/completion_metrics.dart
+++ b/pkg/analysis_server/tool/code_completion/completion_metrics.dart
@@ -106,33 +106,11 @@
   print('');
   print('Metrics computed in $duration');
 
-  File uniqueDataFile() {
-    var dataDir = result['mapDir'];
-    var baseFileName = provider.pathContext.basename(rootPath);
-    var index = 1;
-    while (index < 10000) {
-      var suffix = (index++).toString();
-      suffix = '0000'.substring(suffix.length) + suffix + '.json';
-      var fileName = baseFileName + suffix;
-      var filePath = provider.pathContext.join(dataDir, fileName);
-      var file = provider.getFile(filePath);
-      if (!file.exists) {
-        return file;
-      }
-    }
-
-    /// If there are more than 10000 directories with the same name, just
-    /// overwrite a previously generated file.
-    var fileName = baseFileName + '9999';
-    var filePath = provider.pathContext.join(dataDir, fileName);
-    return provider.getFile(filePath);
-  }
-
-  if (result.wasParsed('mapDir')) {
-    var dataFile = uniqueDataFile();
+  if (result.wasParsed('mapFile')) {
+    var mapFile = provider.getFile(result['mapFile'] as String);
     var map =
         computer.targetMetrics.map((metrics) => metrics.toJson()).toList();
-    dataFile.writeAsStringSync(json.encode(map));
+    mapFile.writeAsStringSync(json.encode(map));
   } else {
     computer.printResults();
   }
@@ -210,10 +188,10 @@
             'worst mrr scores.',
         negatable: false)
     ..addOption(
-      'mapDir',
-      help: 'The absolute path of the directory to which the completion '
-          'metrics data will be written. Using this option will prevent the '
-          'completion results from being written in a textual form.',
+      'mapFile',
+      help: 'The absolute path of the file to which the completion metrics '
+          'data will be written. Using this option will prevent the completion '
+          'results from being written in a textual form.',
     )
     ..addOption(
       'reduceDir',
@@ -247,8 +225,15 @@
     printUsage(parser, error: 'No package path specified.');
     return false;
   }
-  if (result.wasParsed('mapDir')) {
-    return validateDir(parser, result['mapDir']);
+  if (result.wasParsed('mapFile')) {
+    var mapFilePath = result['mapFile'];
+    if (mapFilePath is! String ||
+        !PhysicalResourceProvider.INSTANCE.pathContext
+            .isAbsolute(mapFilePath)) {
+      printUsage(parser,
+          error: 'The path "$mapFilePath" must be an absolute path.');
+      return false;
+    }
   }
   return validateDir(parser, result.rest[0]);
 }
diff --git a/pkg/analysis_server/tool/code_completion/relevance_table_generator.dart b/pkg/analysis_server/tool/code_completion/relevance_table_generator.dart
index 4b2ee62e..60a3f5b 100644
--- a/pkg/analysis_server/tool/code_completion/relevance_table_generator.dart
+++ b/pkg/analysis_server/tool/code_completion/relevance_table_generator.dart
@@ -75,34 +75,12 @@
     var rootPath = result.rest[0];
     print('Analyzing root: "$rootPath"');
 
-    File uniqueDataFile() {
-      var dataDir = result['mapDir'];
-      var baseFileName = provider.pathContext.basename(rootPath);
-      var index = 1;
-      while (index < 10000) {
-        var suffix = (index++).toString();
-        suffix = '0000'.substring(suffix.length) + suffix + '.json';
-        var fileName = baseFileName + suffix;
-        var filePath = provider.pathContext.join(dataDir, fileName);
-        var file = provider.getFile(filePath);
-        if (!file.exists) {
-          return file;
-        }
-      }
-
-      /// If there are more than 10000 directories with the same name, just
-      /// overwrite a previously generated file.
-      var fileName = baseFileName + '9999';
-      var filePath = provider.pathContext.join(dataDir, fileName);
-      return provider.getFile(filePath);
-    }
-
     var computer = RelevanceMetricsComputer();
     var stopwatch = Stopwatch()..start();
     await computer.compute(rootPath, verbose: result['verbose']);
-    if (result.wasParsed('mapDir')) {
-      var dataFile = uniqueDataFile();
-      dataFile.writeAsStringSync(computer.data.toJson());
+    if (result.wasParsed('mapFile')) {
+      var mapFile = provider.getFile(result['mapFile'] as String);
+      mapFile.writeAsStringSync(computer.data.toJson());
     } else {
       writeRelevanceTable(computer.data);
     }
@@ -123,9 +101,9 @@
     negatable: false,
   );
   parser.addOption(
-    'mapDir',
-    help: 'The absolute path of the directory to which the relevance data will '
-        'be written. Using this option will prevent the relevance table from '
+    'mapFile',
+    help: 'The absolute path of the file to which the relevance data will be '
+        'written. Using this option will prevent the relevance table from '
         'being written.',
   );
   parser.addOption(
@@ -167,8 +145,15 @@
     printUsage(parser, error: 'No package path specified.');
     return false;
   }
-  if (result.wasParsed('mapDir')) {
-    return validateDir(parser, result['mapDir']);
+  if (result.wasParsed('mapFile')) {
+    var mapFilePath = result['mapFile'];
+    if (mapFilePath is! String ||
+        !PhysicalResourceProvider.INSTANCE.pathContext
+            .isAbsolute(mapFilePath)) {
+      printUsage(parser,
+          error: 'The path "$mapFilePath" must be an absolute path.');
+      return false;
+    }
   }
   return validateDir(parser, result.rest[0]);
 }
diff --git a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
index e04a8cc..eb3b8ec 100644
--- a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
+++ b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
@@ -363,8 +363,8 @@
                   .GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
               typeArgumentList[i],
             );
+            continue;
           }
-          continue;
         }
 
         var fnTypeParam = fnTypeParams[i];
diff --git a/pkg/analyzer/lib/src/summary2/default_types_builder.dart b/pkg/analyzer/lib/src/summary2/default_types_builder.dart
index 1153c8e..8657fc7 100644
--- a/pkg/analyzer/lib/src/summary2/default_types_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/default_types_builder.dart
@@ -289,6 +289,19 @@
           visited,
         ),
       );
+      for (var typeParameter in startType.typeFormals) {
+        var bound = typeParameter.bound;
+        if (bound != null) {
+          paths.addAll(
+            _findRawTypePathsToDeclaration(
+              startParameter,
+              bound,
+              end,
+              visited,
+            ),
+          );
+        }
+      }
       for (var formalParameter in startType.parameters) {
         paths.addAll(
           _findRawTypePathsToDeclaration(
diff --git a/pkg/analyzer/lib/src/summary2/simply_bounded.dart b/pkg/analyzer/lib/src/summary2/simply_bounded.dart
index a325de8..45a0336 100644
--- a/pkg/analyzer/lib/src/summary2/simply_bounded.dart
+++ b/pkg/analyzer/lib/src/summary2/simply_bounded.dart
@@ -145,6 +145,7 @@
       var collector = _TypeCollector();
       if (type is GenericFunctionType) {
         collector.addType(type.returnType);
+        collector.visitTypeParameters(type.typeParameters);
         collector.visitParameters(type.parameters);
       } else {
         collector.addType(type);
@@ -283,6 +284,7 @@
     if (type is GenericFunctionType) {
       var collector = _TypeCollector();
       collector.addType(type.returnType);
+      collector.visitTypeParameters(type.typeParameters);
       collector.visitParameters(type.parameters);
       for (var type in collector.types) {
         if (!_visitType(dependencies, type, allowTypeParameters)) {
@@ -326,4 +328,12 @@
       visitParameter(parameter);
     }
   }
+
+  void visitTypeParameters(TypeParameterList? node) {
+    if (node != null) {
+      for (var typeParameter in node.typeParameters) {
+        addType(typeParameter.bound);
+      }
+    }
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/not_instantiated_bound_test.dart b/pkg/analyzer/test/src/diagnostics/not_instantiated_bound_test.dart
index d2c6f73..c7254f7 100644
--- a/pkg/analyzer/test/src/diagnostics/not_instantiated_bound_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/not_instantiated_bound_test.dart
@@ -102,6 +102,14 @@
     ]);
   }
 
+  test_class_recursion_notInstantiated_genericFunctionType2() async {
+    await assertErrorsInCode(r'''
+class A<T extends void Function<U extends A>()> {}
+''', [
+      error(CompileTimeErrorCode.NOT_INSTANTIATED_BOUND, 42, 1),
+    ]);
+  }
+
   test_class_recursion_typedef_notInstantiated() async {
     await assertErrorsInCode(r'''
 typedef F(C value);
diff --git a/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart b/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart
index cf8da3e..b8c2b5c 100644
--- a/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart
@@ -471,6 +471,30 @@
 ''');
   }
 
+  test_methodInvocation_genericFunctionTypeArgument_match() async {
+    await assertNoErrorsInCode(r'''
+typedef F = void Function<T extends num>();
+void f<T extends void Function<X extends num>()>() {}
+void g() {
+  f<F>();
+}
+''');
+  }
+
+  test_methodInvocation_genericFunctionTypeArgument_mismatch() async {
+    await assertErrorsInCode(r'''
+class A {}
+class B {}
+typedef F = void Function<T extends A>();
+void f<T extends void Function<U extends B>()>() {}
+void g() {
+  f<F>();
+}
+''', [
+      error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 131, 1),
+    ]);
+  }
+
   test_nonFunctionTypeAlias_interfaceType_parameter() async {
     await assertErrorsInCode(r'''
 class A {}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 9a6f814..7403527 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -1778,6 +1778,20 @@
         withTypeParameterVariance: true);
   }
 
+  test_class_typeParameters_defaultType_cycle_genericFunctionType2() async {
+    featureSet = FeatureSets.genericMetadata;
+    var library = await checkLibrary(r'''
+class C<T extends void Function<U extends C>()> {}
+''');
+    checkElementText(
+        library,
+        r'''
+notSimplyBounded class C<covariant T extends void Function<U extends C<dynamic>>()> {
+}
+''',
+        withTypeParameterVariance: true);
+  }
+
   test_class_typeParameters_defaultType_functionTypeAlias_contravariant_legacy() async {
     featureSet = FeatureSets.beforeNullSafe;
     var library = await checkLibrary(r'''
diff --git a/tests/language/regress/regress33479_test.dart b/tests/language/regress/regress33479_test.dart
index 568b6f8..a825b94 100644
--- a/tests/language/regress/regress33479_test.dart
+++ b/tests/language/regress/regress33479_test.dart
@@ -1,13 +1,17 @@
 class Hest<TypeX extends Fisk> {}
+//                       ^^^^
+// [analyzer] COMPILE_TIME_ERROR.NOT_INSTANTIATED_BOUND
 //         ^
 // [cfe] Type variables can't have generic function types in their bounds.
 
 typedef Fisk = void Function // don't merge lines
-// [error line 5, column 1, length 346]
+// [error line 7, column 1, length 346]
 // [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
 //      ^
 // [cfe] Generic type 'Fisk' can't be used without type arguments in the bounds of its own type variables. It is referenced indirectly through 'Hest'.
     <TypeY extends Hest>();
+//                 ^^^^
+// [analyzer] COMPILE_TIME_ERROR.NOT_INSTANTIATED_BOUND
 
 main() {
   Hest hest = new Hest();
diff --git a/tests/language_2/regress/regress33479_test.dart b/tests/language_2/regress/regress33479_test.dart
index 568b6f8..a825b94 100644
--- a/tests/language_2/regress/regress33479_test.dart
+++ b/tests/language_2/regress/regress33479_test.dart
@@ -1,13 +1,17 @@
 class Hest<TypeX extends Fisk> {}
+//                       ^^^^
+// [analyzer] COMPILE_TIME_ERROR.NOT_INSTANTIATED_BOUND
 //         ^
 // [cfe] Type variables can't have generic function types in their bounds.
 
 typedef Fisk = void Function // don't merge lines
-// [error line 5, column 1, length 346]
+// [error line 7, column 1, length 346]
 // [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
 //      ^
 // [cfe] Generic type 'Fisk' can't be used without type arguments in the bounds of its own type variables. It is referenced indirectly through 'Hest'.
     <TypeY extends Hest>();
+//                 ^^^^
+// [analyzer] COMPILE_TIME_ERROR.NOT_INSTANTIATED_BOUND
 
 main() {
   Hest hest = new Hest();
diff --git a/tools/VERSION b/tools/VERSION
index 8deb960..46449c0 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 13
 PATCH 0
-PRERELEASE 171
+PRERELEASE 172
 PRERELEASE_PATCH 0
\ No newline at end of file