[fasta] Reject generic function types in bounds of type variables

Fixes #33423.

Bug: http://dartbug.com/33423
Change-Id: Iff2a23ef456ebc05fcce8ea804b478db313cac1e
Reviewed-on: https://dart-review.googlesource.com/64544
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
Reviewed-by: Peter von der Ahé <ahe@google.com>
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
index a42ad93..cae26c2 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
@@ -2931,6 +2931,19 @@
     message: r"""'sync*' and 'async*' can't return a value.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeGenericFunctionTypeInBound =
+    messageGenericFunctionTypeInBound;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageGenericFunctionTypeInBound = const MessageCode(
+    "GenericFunctionTypeInBound",
+    analyzerCode: "GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND",
+    dart2jsCode: "*fatal*",
+    severity: Severity.error,
+    message:
+        r"""Type variables can't have generic function types in their bounds.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<Message Function(String name)> templateGetterNotFound =
     const Template<Message Function(String name)>(
         messageTemplate: r"""Getter not found: '#name'.""",
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
index 7821f30..efbcf07 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
@@ -39,6 +39,7 @@
         LocatedMessage,
         Message,
         messageConflictsWithTypeVariableCause,
+        messageGenericFunctionTypeInBound,
         messageTypeVariableDuplicatedName,
         messageTypeVariableSameNameAsEnclosing,
         noLength,
@@ -115,6 +116,7 @@
 import 'type_algorithms.dart'
     show
         calculateBounds,
+        findGenericFunctionTypes,
         getNonSimplicityIssuesForDeclaration,
         getNonSimplicityIssuesForTypeVariables;
 
@@ -1107,13 +1109,30 @@
         bool strongMode) {
       if (variables == null) return 0;
 
+      bool haveErroneousBounds = false;
       if (strongMode) {
-        List<KernelTypeBuilder> calculatedBounds =
-            calculateBounds(variables, dynamicType, bottomType, objectClass);
         for (int i = 0; i < variables.length; ++i) {
-          variables[i].defaultType = calculatedBounds[i];
+          TypeVariableBuilder<TypeBuilder, Object> 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);
+          }
         }
-      } else {
+
+        if (!haveErroneousBounds) {
+          List<KernelTypeBuilder> calculatedBounds =
+              calculateBounds(variables, dynamicType, bottomType, objectClass);
+          for (int i = 0; i < variables.length; ++i) {
+            variables[i].defaultType = calculatedBounds[i];
+          }
+        }
+      }
+
+      if (!strongMode || haveErroneousBounds) {
         // In Dart 1, put `dynamic` everywhere.
         for (int i = 0; i < variables.length; ++i) {
           variables[i].defaultType = dynamicType;
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart b/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
index 81b72d7..a45b739 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
@@ -693,3 +693,29 @@
   issues.addAll(convertRawTypeCyclesIntoIssues(declaration, cyclesToReport));
   return issues;
 }
+
+void findGenericFunctionTypes(TypeBuilder type, {List<TypeBuilder> result}) {
+  result ??= <TypeBuilder>[];
+  if (type is FunctionTypeBuilder) {
+    if (type.typeVariables != null && type.typeVariables.length > 0) {
+      result.add(type);
+
+      for (TypeVariableBuilder<TypeBuilder, Object> typeVariable
+          in type.typeVariables) {
+        findGenericFunctionTypes(typeVariable.bound, result: result);
+        findGenericFunctionTypes(typeVariable.defaultType, result: result);
+      }
+    }
+    findGenericFunctionTypes(type.returnType, result: result);
+    if (type.formals != null) {
+      for (FormalParameterBuilder<TypeBuilder> formal in type.formals) {
+        findGenericFunctionTypes(formal.type, result: result);
+      }
+    }
+  } else if (type is NamedTypeBuilder<TypeBuilder, Object> &&
+      type.arguments != null) {
+    for (TypeBuilder argument in type.arguments) {
+      findGenericFunctionTypes(argument, result: result);
+    }
+  }
+}
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index cf7d567..d90f6c5 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -2518,3 +2518,11 @@
       factory Foo.bar() = Foo.foo;
     }
     main() { var foo = new Foo.foo(); }
+
+GenericFunctionTypeInBound:
+  template: "Type variables can't have generic function types in their bounds."
+  analyzerCode: GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND
+  dart2jsCode: "*fatal*"
+  severity: ERROR
+  script: |
+    class Hest<X extends Y Function<Y>(Y)> {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.expect
index 372b447..c807c38 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.expect
@@ -1,3 +1,9 @@
+// Errors:
+//
+// pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart:11:12: Error: Type variables can't have generic function types in their bounds.
+// class Fisk<TypeY extends Function<TypeZ extends Hest<Null>>(TypeZ)> {}
+//            ^^^^^
+
 library;
 import self as self;
 import "dart:core" as core;
@@ -7,7 +13,7 @@
     : super core::Object::•()
     ;
 }
-class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null> = dynamic>(TypeZ) → dynamic = <TypeZ extends self::Hest<core::Null> = dynamic>(TypeZ) → dynamic> extends core::Object {
+class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null> = dynamic>(TypeZ) → dynamic = dynamic> extends core::Object {
   synthetic constructor •() → void
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.transformed.expect
index 372b447..c807c38 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.transformed.expect
@@ -1,3 +1,9 @@
+// Errors:
+//
+// pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart:11:12: Error: Type variables can't have generic function types in their bounds.
+// class Fisk<TypeY extends Function<TypeZ extends Hest<Null>>(TypeZ)> {}
+//            ^^^^^
+
 library;
 import self as self;
 import "dart:core" as core;
@@ -7,7 +13,7 @@
     : super core::Object::•()
     ;
 }
-class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null> = dynamic>(TypeZ) → dynamic = <TypeZ extends self::Hest<core::Null> = dynamic>(TypeZ) → dynamic> extends core::Object {
+class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null> = dynamic>(TypeZ) → dynamic = dynamic> extends core::Object {
   synthetic constructor •() → void
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart b/pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart
new file mode 100644
index 0000000..cdf7460
--- /dev/null
+++ b/pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test checks that generic function types are rejected with an appropriate
+// compile-time error message if encountered in bounds of type variables.
+
+class Hest<TypeX extends TypeY Function<TypeY>(TypeY)> {}
+
+main() {}
diff --git a/pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart.direct.expect b/pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart.direct.expect
new file mode 100644
index 0000000..8abcc85
--- /dev/null
+++ b/pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart.direct.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Hest<TypeX extends <TypeY extends core::Object = dynamic>(TypeY) → TypeY = dynamic> extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart.direct.transformed.expect b/pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart.direct.transformed.expect
new file mode 100644
index 0000000..8abcc85
--- /dev/null
+++ b/pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart.direct.transformed.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Hest<TypeX extends <TypeY extends core::Object = dynamic>(TypeY) → TypeY = dynamic> extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart.outline.expect b/pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart.outline.expect
new file mode 100644
index 0000000..1149d7f
--- /dev/null
+++ b/pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart.outline.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Hest<TypeX extends <TypeY extends core::Object = dynamic>(TypeY) → TypeY = dynamic> extends core::Object {
+  synthetic constructor •() → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart.strong.expect b/pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart.strong.expect
new file mode 100644
index 0000000..8bd0c4b
--- /dev/null
+++ b/pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart.strong.expect
@@ -0,0 +1,16 @@
+// Errors:
+//
+// pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart:8:12: Error: Type variables can't have generic function types in their bounds.
+// class Hest<TypeX extends TypeY Function<TypeY>(TypeY)> {}
+//            ^^^^^
+
+library;
+import self as self;
+import "dart:core" as core;
+
+class Hest<TypeX extends <TypeY extends core::Object = dynamic>(TypeY) → TypeY = dynamic> extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart.strong.transformed.expect b/pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart.strong.transformed.expect
new file mode 100644
index 0000000..8bd0c4b
--- /dev/null
+++ b/pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart.strong.transformed.expect
@@ -0,0 +1,16 @@
+// Errors:
+//
+// pkg/front_end/testcases/reject_generic_function_types_in_bounds.dart:8:12: Error: Type variables can't have generic function types in their bounds.
+// class Hest<TypeX extends TypeY Function<TypeY>(TypeY)> {}
+//            ^^^^^
+
+library;
+import self as self;
+import "dart:core" as core;
+
+class Hest<TypeX extends <TypeY extends core::Object = dynamic>(TypeY) → TypeY = dynamic> extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {}