Fix TypeInfo.couldBeExpression in recovery situations

Change-Id: Ia9f1735b8ad28dbfcde1f54ac70628e85b65c1d3
Reviewed-on: https://dart-review.googlesource.com/c/88480
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Dan Rubel <danrubel@google.com>
diff --git a/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart b/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
index de844a0..4204c6f 100644
--- a/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
+++ b/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
@@ -417,7 +417,8 @@
   }
 
   @override
-  bool get couldBeExpression => false;
+  bool get couldBeExpression =>
+      typeArguments == noTypeParamOrArg && typeVariableStarters.isEmpty;
 
   @override
   bool get isNullable => false;
diff --git a/pkg/front_end/test/fasta/parser/type_info_test.dart b/pkg/front_end/test/fasta/parser/type_info_test.dart
index 0febbe0..bf2f35b 100644
--- a/pkg/front_end/test/fasta/parser/type_info_test.dart
+++ b/pkg/front_end/test/fasta/parser/type_info_test.dart
@@ -29,6 +29,7 @@
     defineReflectiveTests(NoTypeParamOrArgTest);
     defineReflectiveTests(SimpleTypeParamOrArgTest);
     defineReflectiveTests(TypeParamOrArgInfoTest);
+    defineReflectiveTests(CouldBeExpressionTest);
   });
 }
 
@@ -435,7 +436,9 @@
     expectInfo(simpleType, 'C(', required: true);
     expectInfo(simpleType, 'C<', required: true);
     expectComplexInfo('C.',
-        required: true, expectedErrors: [error(codeExpectedType, 2, 0)]);
+        required: true,
+        couldBeExpression: true,
+        expectedErrors: [error(codeExpectedType, 2, 0)]);
     expectInfo(simpleType, 'C=', required: true);
     expectInfo(simpleType, 'C*', required: true);
     expectInfo(simpleType, 'C do', required: true);
@@ -664,14 +667,19 @@
 class TypeInfoTest {
   void test_computeType_basic() {
     expectInfo(noType, '.', required: false);
-    expectComplexInfo('.', required: true, expectedErrors: [
-      error(codeExpectedType, 0, 1),
-      error(codeExpectedType, 1, 0)
-    ]);
+    expectComplexInfo('.',
+        required: true,
+        couldBeExpression: true,
+        expectedErrors: [
+          error(codeExpectedType, 0, 1),
+          error(codeExpectedType, 1, 0)
+        ]);
 
     expectInfo(noType, '.Foo', required: false);
     expectComplexInfo('.Foo',
-        required: true, expectedErrors: [error(codeExpectedType, 0, 1)]);
+        required: true,
+        couldBeExpression: true,
+        expectedErrors: [error(codeExpectedType, 0, 1)]);
   }
 
   void test_computeType_builtin() {
@@ -679,16 +687,20 @@
     // an error for the builtin used as a type.
     expectComplexInfo('abstract',
         required: true,
+        couldBeExpression: true,
         expectedErrors: [error(codeBuiltInIdentifierAsType, 0, 8)]);
     expectComplexInfo('export',
         required: true,
+        couldBeExpression: true,
         expectedErrors: [error(codeBuiltInIdentifierAsType, 0, 6)]);
     expectComplexInfo('abstract Function()',
         required: false,
+        couldBeExpression: true,
         expectedAfter: 'Function',
         expectedErrors: [error(codeBuiltInIdentifierAsType, 0, 8)]);
     expectComplexInfo('export Function()',
         required: false,
+        couldBeExpression: true,
         expectedAfter: 'Function',
         expectedErrors: [error(codeBuiltInIdentifierAsType, 0, 6)]);
   }
@@ -2034,6 +2046,30 @@
   }
 }
 
+@reflectiveTest
+class CouldBeExpressionTest {
+  void couldBeExpression(String code, bool expected) {
+    final typeInfo = computeType(scan(code), true);
+    expect(typeInfo.couldBeExpression, expected);
+  }
+
+  void test_simple() {
+    couldBeExpression('S', true);
+  }
+
+  void test_partial() {
+    couldBeExpression('.S', true);
+  }
+
+  void test_prefixed() {
+    couldBeExpression('p.S', true);
+  }
+
+  void test_typeArg() {
+    couldBeExpression('S<T>', false);
+  }
+}
+
 void expectInfo(expectedInfo, String source, {bool required}) {
   if (required == null) {
     compute(expectedInfo, source, scan(source), true);
@@ -2046,17 +2082,18 @@
 void expectComplexInfo(String source,
     {bool required,
     bool inDeclaration = false,
+    bool couldBeExpression = false,
     String expectedAfter,
     List<String> expectedCalls,
     List<ExpectedError> expectedErrors}) {
   if (required == null) {
-    computeComplex(source, scan(source), true, inDeclaration, expectedAfter,
-        expectedCalls, expectedErrors);
-    computeComplex(source, scan(source), false, inDeclaration, expectedAfter,
-        expectedCalls, expectedErrors);
+    computeComplex(source, scan(source), true, inDeclaration, couldBeExpression,
+        expectedAfter, expectedCalls, expectedErrors);
+    computeComplex(source, scan(source), false, inDeclaration,
+        couldBeExpression, expectedAfter, expectedCalls, expectedErrors);
   } else {
-    computeComplex(source, scan(source), required, inDeclaration, expectedAfter,
-        expectedCalls, expectedErrors);
+    computeComplex(source, scan(source), required, inDeclaration,
+        couldBeExpression, expectedAfter, expectedCalls, expectedErrors);
   }
 }
 
@@ -2085,6 +2122,7 @@
     Token start,
     bool required,
     bool inDeclaration,
+    bool couldBeExpression,
     String expectedAfter,
     List<String> expectedCalls,
     List<ExpectedError> expectedErrors) {
@@ -2093,7 +2131,7 @@
       const isInstanceOf<ComplexTypeInfo>(), source, start, required,
       inDeclaration: inDeclaration);
   expect(typeInfo.start, start.next, reason: source);
-  expect(typeInfo.couldBeExpression, isFalse);
+  expect(typeInfo.couldBeExpression, couldBeExpression);
   expectEnd(expectedAfter, typeInfo.skipType(start));
   expect(countGtGtAndNullEnd(start), expectedGtGtAndNullEndCount,
       reason: 'TypeInfo.skipType should not modify the token stream');