Partial fix of #33343. Reject generic function types as bounds.

Does not handle the other half of #33343, rejecting generic function
types as type arguments.

This revealed a secondary minor issue which was easy enough to fix. Type
arguments were not resolved within bounds:

class C<T extends S Function<S>(S)> {}

this would report 'undefined class S' for the return and parameter types
`S`. I almost split this into a separate CL, but, these two CLs are tied
together inherently by the tests case. Easy to solve at once.

Bug: 33343
Change-Id: Ib34a04d90be08d8d6c6f21a9d485a452017585ba
Reviewed-on: https://dart-review.googlesource.com/61103
Commit-Queue: Mike Fairhurst <mfairhurst@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index a47d7a0..316443a 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -129,6 +129,7 @@
   CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR,
   CompileTimeErrorCode.FINAL_INITIALIZED_MULTIPLE_TIMES,
   CompileTimeErrorCode.GENERIC_FUNCTION_TYPED_PARAM_UNSUPPORTED,
+  CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND,
   CompileTimeErrorCode.GETTER_AND_METHOD_WITH_SAME_NAME,
   CompileTimeErrorCode.IMPLEMENTS_DEFERRED_CLASS,
   CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS,
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index 4be6d72..e071c48 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -2400,6 +2400,16 @@
           correction: "Try using a type that is or is a subclass of '{1}'.");
 
   /**
+   * It is a compile-time error if a generic function type is used as a bound
+   * for a formal type parameter of a class or a function.
+   */
+  static const CompileTimeErrorCode GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND =
+      const CompileTimeErrorCode('GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND',
+          'Generic function types may not be used as type parameter bounds',
+          correction: 'Try making the free variable in the function type part'
+              ' of the larger declaration signature');
+
+  /**
    * 15.3.1 Typedef: Any self reference, either directly, or recursively via
    * another typedef, is a compile time error.
    */
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 204542e..7cf79c0 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -1239,6 +1239,7 @@
     _checkForTypeParameterSupertypeOfItsBound(node);
     _checkForTypeAnnotationDeferredClass(node.bound);
     _checkForImplicitDynamicType(node.bound);
+    _checkForGenericFunctionType(node.bound);
     if (_options.strongMode) node.bound?.accept(_uninstantiatedBoundChecker);
     return super.visitTypeParameter(node);
   }
@@ -4183,6 +4184,19 @@
     }
   }
 
+  void _checkForGenericFunctionType(TypeAnnotation node) {
+    if (node == null) {
+      return;
+    }
+    DartType type = node.type;
+    if (type is FunctionType && type.typeFormals.isNotEmpty) {
+      _errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND,
+          node,
+          [type]);
+    }
+  }
+
   void _checkForImplicitDynamicTypedLiteral(TypedLiteral node) {
     if (_options.implicitDynamic || node.typeArguments != null) {
       return;
@@ -5905,7 +5919,9 @@
    * Verify that the type arguments in the given [typeName] are all within
    * their bounds.
    *
-   * See [StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS].
+   * See [StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS],
+   * [CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS],
+   * [CompileTimeErrorCode.GENERIC_FUNCTION_CANNOT_BE_BOUND].
    */
   void _checkForTypeArgumentNotMatchingBounds(TypeName typeName) {
     if (typeName.typeArguments == null) {
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 663b76e..685704b 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -9043,7 +9043,10 @@
   TypeNameResolver typeNameResolver = null;
 
   TypeParameterBoundsResolver(
-      this.typeSystem, this.library, this.source, this.errorListener);
+      this.typeSystem, this.library, this.source, this.errorListener)
+      : libraryScope = new LibraryScope(library),
+        typeNameResolver = new TypeNameResolver(typeSystem,
+            typeSystem.typeProvider, library, source, errorListener);
 
   /**
    * Resolve bounds of type parameters of classes, class and function type
@@ -9070,27 +9073,40 @@
       typeNameResolver.resolveTypeName(type);
       // TODO(scheglov) report error when don't apply type bounds for type bounds
     } else if (type is GenericFunctionType) {
-      void resolveTypeParameter(TypeParameter t) {
-        _resolveTypeName(t.bound);
-      }
+      // While GenericFunctionTypes with free types are not allowed as bounds,
+      // those free types *should* ideally be recognized as type parameter types
+      // rather than classnames. Create a scope to accomplish that.
+      Scope previousScope = typeNameResolver.nameScope;
 
-      void resolveParameter(FormalParameter p) {
-        if (p is SimpleFormalParameter) {
-          _resolveTypeName(p.type);
-        } else if (p is DefaultFormalParameter) {
-          resolveParameter(p.parameter);
-        } else if (p is FieldFormalParameter) {
-          _resolveTypeName(p.type);
-        } else if (p is FunctionTypedFormalParameter) {
-          _resolveTypeName(p.returnType);
-          p.typeParameters?.typeParameters?.forEach(resolveTypeParameter);
-          p.parameters?.parameters?.forEach(resolveParameter);
+      try {
+        Scope typeParametersScope = new TypeParameterScope(
+            typeNameResolver.nameScope, type.type.element);
+        typeNameResolver.nameScope = typeParametersScope;
+
+        void resolveTypeParameter(TypeParameter t) {
+          _resolveTypeName(t.bound);
         }
-      }
 
-      _resolveTypeName(type.returnType);
-      type.typeParameters?.typeParameters?.forEach(resolveTypeParameter);
-      type.parameters?.parameters?.forEach(resolveParameter);
+        void resolveParameter(FormalParameter p) {
+          if (p is SimpleFormalParameter) {
+            _resolveTypeName(p.type);
+          } else if (p is DefaultFormalParameter) {
+            resolveParameter(p.parameter);
+          } else if (p is FieldFormalParameter) {
+            _resolveTypeName(p.type);
+          } else if (p is FunctionTypedFormalParameter) {
+            _resolveTypeName(p.returnType);
+            p.typeParameters?.typeParameters?.forEach(resolveTypeParameter);
+            p.parameters?.parameters?.forEach(resolveParameter);
+          }
+        }
+
+        _resolveTypeName(type.returnType);
+        type.typeParameters?.typeParameters?.forEach(resolveTypeParameter);
+        type.parameters?.parameters?.forEach(resolveParameter);
+      } finally {
+        typeNameResolver.nameScope = previousScope;
+      }
     }
   }
 
@@ -9111,10 +9127,10 @@
                 bound.type = typeParameterElement.bound;
               }
             } else {
-              libraryScope ??= new LibraryScope(library);
               typeParametersScope ??= createTypeParametersScope();
-              typeNameResolver ??= new TypeNameResolver(typeSystem,
-                  typeSystem.typeProvider, library, source, errorListener);
+              // _resolveTypeParameters is the entry point into each declaration
+              // with a separate scope. We can safely, and should, clobber the
+              // old scope here.
               typeNameResolver.nameScope = typeParametersScope;
               _resolveTypeName(bound);
               typeParameterElement.bound = bound.type;
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart
index 67aa952..8232bc7 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart
@@ -3098,6 +3098,41 @@
     // Test passes, even though if fails in the superclass
     await super.test_yieldInNonGenerator_async();
   }
+
+  @override
+  @failingTest
+  @potentialAnalyzerProblem
+  test_genericFunctionTypeAsBound_class() async {
+    await super.test_genericFunctionTypeAsBound_class();
+  }
+
+  @override
+  @failingTest
+  @potentialAnalyzerProblem
+  test_genericFunctionTypeAsBound_genericFunction() async {
+    await super.test_genericFunctionTypeAsBound_genericFunction();
+  }
+
+  @override
+  @failingTest
+  @potentialAnalyzerProblem
+  test_genericFunctionTypeAsBound_genericFunctionTypedef() async {
+    await super.test_genericFunctionTypeAsBound_genericFunctionTypedef();
+  }
+
+  @override
+  @failingTest
+  @potentialAnalyzerProblem
+  test_genericFunctionTypeAsBound_parameterOfFunction() async {
+    await super.test_genericFunctionTypeAsBound_parameterOfFunction();
+  }
+
+  @override
+  @failingTest
+  @potentialAnalyzerProblem
+  test_genericFunctionTypeAsBound_typedef() async {
+    await super.test_genericFunctionTypeAsBound_typedef();
+  }
 }
 
 /// Tests marked with this annotation fail because of a Fasta problem.
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
index 6923bc6..8b91102 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -2749,6 +2749,55 @@
     verify([source]);
   }
 
+  test_genericFunctionTypeAsBound_class() async {
+    Source source = addSource(r'''
+class C<T extends S Function<S>(S)> {
+}''');
+    await computeAnalysisResult(source);
+    assertErrors(
+        source, [CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND]);
+    verify([source]);
+  }
+
+  test_genericFunctionTypeAsBound_genericFunction() async {
+    Source source = addSource(r'''
+T Function<T extends S Function<S>(S)>(T) fun;
+''');
+    await computeAnalysisResult(source);
+    assertErrors(
+        source, [CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND]);
+    verify([source]);
+  }
+
+  test_genericFunctionTypeAsBound_genericFunctionTypedef() async {
+    Source source = addSource(r'''
+typedef foo = T Function<T extends S Function<S>(S)>(T t);
+''');
+    await computeAnalysisResult(source);
+    assertErrors(
+        source, [CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND]);
+    verify([source]);
+  }
+
+  test_genericFunctionTypeAsBound_parameterOfFunction() async {
+    Source source = addSource(r'''
+class C<T extends void Function(S Function<S>(S))> {
+}''');
+    await computeAnalysisResult(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  test_genericFunctionTypeAsBound_typedef() async {
+    Source source = addSource(r'''
+typedef T foo<T extends S Function<S>(S)>(T t);
+''');
+    await computeAnalysisResult(source);
+    assertErrors(
+        source, [CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND]);
+    verify([source]);
+  }
+
   test_genericFunctionTypedParameter() async {
     // Once dartbug.com/28515 is fixed, this syntax should no longer generate an
     // error.
diff --git a/pkg/analyzer/test/generated/non_error_resolver_kernel_test.dart b/pkg/analyzer/test/generated/non_error_resolver_kernel_test.dart
index 7b3f14b..b080ee6 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_kernel_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_kernel_test.dart
@@ -444,13 +444,6 @@
 
   @override
   @failingTest
-  @potentialAnalyzerProblem
-  test_typeArgument_boundToFunctionType() async {
-    return super.test_typeArgument_boundToFunctionType();
-  }
-
-  @override
-  @failingTest
   test_undefinedGetter_static_conditionalAccess() {
     // Bad state: No data for A at 36
     return super.test_undefinedGetter_static_conditionalAccess();
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index 1084149..6a12526 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -5386,7 +5386,7 @@
   }
 
   test_typeArgument_boundToFunctionType() async {
-    Source source = addSource("class A<T extends void Function<T>(T)>{}");
+    Source source = addSource("class A<T extends void Function(T)>{}");
     await computeAnalysisResult(source);
     assertNoErrors(source);
     verify([source]);
diff --git a/pkg/analyzer/test/generated/strong_mode_kernel_test.dart b/pkg/analyzer/test/generated/strong_mode_kernel_test.dart
index 9157b6d..0e94294 100644
--- a/pkg/analyzer/test/generated/strong_mode_kernel_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_kernel_test.dart
@@ -653,13 +653,6 @@
 
   @override
   @failingTest
-  test_notInstantiatedBound_ok_class_function() {
-    // Failed to resolve 1 nodes
-    return super.test_notInstantiatedBound_ok_class_function();
-  }
-
-  @override
-  @failingTest
   test_objectMethodOnFunctions_Typedef() {
     // UnimplementedError: TODO(paulberry): resynthesize generic typedef
     return super.test_objectMethodOnFunctions_Typedef();
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index 1414b83..a84ddc6 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -4107,7 +4107,7 @@
 
   test_notInstantiatedBound_ok_class_function() async {
     String code = r'''
-class A<T extends void Function<Z>()> {}
+class A<T extends void Function()> {}
 class B<T extends A> {}
 ''';
     await resolveTestUnit(code);