Relax type bound restrictions slightly, apply to typedefs.

This relaxes the restriction on raw types in bounds slightly, to allow
parameterized types in bounds to be used without type arguments if
their bounds are empty.

This CL also fixes the error check for raw types in type bounds to
apply to typedefs as well.

BUG=
R=scheglov@google.com

Review-Url: https://codereview.chromium.org/2658303002 .
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index ffef5db..26c1a02 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -5239,9 +5239,13 @@
     if (node is TypeName) {
       if (node.typeArguments == null) {
         DartType type = node.type;
-        if (type is InterfaceType && type.element.typeParameters.isNotEmpty) {
-          _errorReporter.reportErrorForNode(
-              StrongModeCode.NOT_INSTANTIATED_BOUND, node, [type]);
+        if (type is ParameterizedType) {
+          Element element = type.element;
+          if (element is TypeParameterizedElement &&
+              element.typeParameters.any((p) => p.bound != null)) {
+            _errorReporter.reportErrorForNode(
+                StrongModeCode.NOT_INSTANTIATED_BOUND, node, [type]);
+          }
         }
       } else {
         node.typeArguments.arguments.forEach(_checkForNotInstantiatedBound);
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index a90fe14..364bcf5 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -2717,7 +2717,7 @@
 
 class B<T extends num> {}
 
-class C<S extends int, T extends B<S>, U extends B> {}
+class C<S extends int, T extends B<S>, U extends A> {}
 
 void test() {
 //
@@ -2729,13 +2729,13 @@
   var cc = new C();
 }
 ''';
-    await resolveTestUnit(code, noErrors: false);
+    await resolveTestUnit(code);
     expectIdentifierType('ai', "A<dynamic>");
     expectIdentifierType('bi', "B<num>");
-    expectIdentifierType('ci', "C<int, B<int>, B<dynamic>>");
+    expectIdentifierType('ci', "C<int, B<int>, A<dynamic>>");
     expectIdentifierType('aa', "A<dynamic>");
     expectIdentifierType('bb', "B<num>");
-    expectIdentifierType('cc', "C<int, B<int>, B<dynamic>>");
+    expectIdentifierType('cc', "C<int, B<int>, A<dynamic>>");
   }
 
   test_instantiateToBounds_class_error_recursion() async {
@@ -2769,6 +2769,28 @@
     expectIdentifierType('c;', 'C<dynamic>');
   }
 
+  test_instantiateToBounds_class_error_typedef() async {
+    String code = r'''
+typedef T F<T>(T x);
+class C<T extends F<T>> {}
+C c;
+''';
+    await resolveTestUnit(code, noErrors: false);
+    assertErrors(testSource, [StrongModeCode.NO_DEFAULT_BOUNDS]);
+    expectIdentifierType('c;', 'C<dynamic>');
+  }
+
+  test_instantiateToBounds_class_ok_implicitDynamic_multi() async {
+    String code = r'''
+class C<T0 extends Map<T1, T2>, T1 extends List, T2 extends int> {}
+C c;
+''';
+    await resolveTestUnit(code);
+    assertNoErrors(testSource);
+    expectIdentifierType(
+        'c;', 'C<Map<List<dynamic>, int>, List<dynamic>, int>');
+  }
+
   test_instantiateToBounds_class_ok_referenceOther_after() async {
     String code = r'''
 class C<T0 extends T1, T1 extends int> {}
@@ -2814,11 +2836,12 @@
 class A<T> {}
 class B<T extends num> {}
 class C<T extends List<int>> {}
-
+class D<T extends A> {}
 void main() {
   A a;
   B b;
   C c;
+  D d;
 }
 ''';
     await resolveTestUnit(code);
@@ -2826,6 +2849,7 @@
     expectIdentifierType('a;', 'A<dynamic>');
     expectIdentifierType('b;', 'B<num>');
     expectIdentifierType('c;', 'C<List<int>>');
+    expectIdentifierType('d;', 'D<A<dynamic>>');
   }
 
   test_instantiateToBounds_method_ok_referenceOther_before() async {
@@ -2858,29 +2882,51 @@
     expectStaticInvokeType('m(null)', '(T) → void');
   }
 
-  test_notInstantiatedBound_direct() async {
+  test_notInstantiatedBound_direct_class_class() async {
     String code = r'''
-class A<T> {}
+class A<T extends int> {}
 class C<T extends A> {}
 ''';
     await resolveTestUnit(code, noErrors: false);
     assertErrors(testSource, [StrongModeCode.NOT_INSTANTIATED_BOUND]);
   }
 
-  test_notInstantiatedBound_indirect() async {
+  test_notInstantiatedBound_direct_class_typedef() async {
+    // Check that if the bound of a class is an uninstantiated typedef
+    // we emit an error
+    String code = r'''
+typedef void F<T extends int>();
+class C<T extends F> {}
+''';
+    await resolveTestUnit(code, noErrors: false);
+    assertErrors(testSource, [StrongModeCode.NOT_INSTANTIATED_BOUND]);
+  }
+
+  test_notInstantiatedBound_direct_typedef_class() async {
+    // Check that if the bound of a typeded is an uninstantiated class
+    // we emit an error
+    String code = r'''
+class C<T extends int> {}
+typedef void F<T extends C>();
+''';
+    await resolveTestUnit(code, noErrors: false);
+    assertErrors(testSource, [StrongModeCode.NOT_INSTANTIATED_BOUND]);
+  }
+
+  test_notInstantiatedBound_indirect_class_class() async {
     String code = r'''
 class A<T> {}
-class B<T> {}
+class B<T extends int> {}
 class C<T extends A<B>> {}
 ''';
     await resolveTestUnit(code, noErrors: false);
     assertErrors(testSource, [StrongModeCode.NOT_INSTANTIATED_BOUND]);
   }
 
-  test_notInstantiatedBound_indirect2() async {
+  test_notInstantiatedBound_indirect_class_class2() async {
     String code = r'''
 class A<K, V> {}
-class B<T> {}
+class B<T extends int> {}
 class C<T extends A<B, B>> {}
 ''';
     await resolveTestUnit(code, noErrors: false);
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index 69ae478..c38122e 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -2427,7 +2427,7 @@
   void test_implicitDynamic_type() {
     addFile(r'''
 class C<T> {}
-class M1<T extends /*error:IMPLICIT_DYNAMIC_TYPE*//*error:NOT_INSTANTIATED_BOUND*/List> {}
+class M1<T extends /*error:IMPLICIT_DYNAMIC_TYPE*/List> {}
 class M2<T> {}
 class I<T> {}
 class D<T, S> extends /*error:IMPLICIT_DYNAMIC_TYPE*/C
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index f201874..541e75f 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -4290,7 +4290,7 @@
   void test_instantiateToBounds_generic2_noBound() {
     var unit = checkFile(r'''
 class A<T> {}
-class B<T extends /*error:NOT_INSTANTIATED_BOUND*/A> {}
+class B<T extends A> {}
 B v = null;
 ''');
     expect(unit.topLevelVariables[0].type.toString(), 'B<A<dynamic>>');