Improve literal function recovery

This fixes a crash when parsing literal functions
and improves recovery.

Change-Id: I22e7793d08e772bd186e1fb8fd01e09fa72ea13e
Reviewed-on: https://dart-review.googlesource.com/62380
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Dan Rubel <danrubel@google.com>
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 19a76ce..18d1d5a 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -7037,6 +7037,25 @@
     expect((expression.body as ExpressionFunctionBody).semicolon, isNull);
   }
 
+  void test_parseFunctionExpression_functionInPlaceOfTypeName() {
+    Expression expression = parseExpression('<test(' ', (){});>[0, 1, 2]',
+        codes: usingFastaParser
+            ? [
+                ParserErrorCode.EXPECTED_TOKEN,
+                ParserErrorCode.UNEXPECTED_TOKEN,
+                ParserErrorCode.MISSING_IDENTIFIER,
+                ParserErrorCode.MISSING_IDENTIFIER,
+                ParserErrorCode.EXPECTED_TOKEN,
+                ParserErrorCode.MISSING_FUNCTION_BODY,
+              ]
+            : [
+                ParserErrorCode.EXPECTED_TOKEN,
+                ParserErrorCode.MISSING_IDENTIFIER,
+                ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL,
+              ]);
+    expect(expression, isNotNull);
+  }
+
   void test_parseFunctionExpression_constAndTypeParameters2() {
     FunctionExpression expression =
         parseFunctionExpression('const <E>(E i) => i++');
diff --git a/pkg/analyzer/test/src/fasta/recovery/invalid_code_test.dart b/pkg/analyzer/test/src/fasta/recovery/invalid_code_test.dart
index 6e680c9..107fd21 100644
--- a/pkg/analyzer/test/src/fasta/recovery/invalid_code_test.dart
+++ b/pkg/analyzer/test/src/fasta/recovery/invalid_code_test.dart
@@ -63,14 +63,15 @@
   @failingTest
   void test_functionInPlaceOfTypeName() {
     // https://github.com/dart-lang/sdk/issues/30370
-    // TODO(danrubel): Fix this crash
+    // TODO(danrubel): Improve recovery. Currently, the fasta scanner
+    // does not associate `<` with `>` in this situation.
     testRecovery('''
 f() {
   return <test('', (){});>[0, 1, 2];
 }
 ''', [ParserErrorCode.UNEXPECTED_TOKEN], '''
 f() {
-  return <test>[0, 1, 2];
+  return _s_ < test('', (){}); _s_ > [0, 1, 2];
 }
 ''');
   }
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index d12753f..3b8f651 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -4079,21 +4079,17 @@
   /// This is a suffix parser because it is assumed that type arguments have
   /// been parsed, or `listener.handleNoTypeArguments(..)` has been executed.
   Token parseLiteralFunctionSuffix(Token token) {
-    Token next = token.next;
-    assert(optional('(', next));
-    Token closeBrace = next.endGroup;
-    if (closeBrace != null) {
-      Token nextToken = closeBrace.next;
-      int kind = nextToken.kind;
-      if (identical(kind, FUNCTION_TOKEN) ||
-          identical(kind, OPEN_CURLY_BRACKET_TOKEN) ||
-          (identical(kind, KEYWORD_TOKEN) &&
-              (optional('async', nextToken) || optional('sync', nextToken)))) {
-        return parseFunctionExpression(token);
-      }
-      // Fall through.
+    assert(optional('(', token.next));
+    // Scanner ensures `(` has matching `)`.
+    Token next = token.next.endGroup.next;
+    int kind = next.kind;
+    if (!identical(kind, FUNCTION_TOKEN) &&
+        !identical(kind, OPEN_CURLY_BRACKET_TOKEN) &&
+        (!identical(kind, KEYWORD_TOKEN) ||
+            !optional('async', next) && !optional('sync', next))) {
+      reportRecoverableErrorWithToken(next, fasta.templateUnexpectedToken);
     }
-    return reportUnexpectedToken(next);
+    return parseFunctionExpression(token);
   }
 
   /// genericListLiteral | genericMapLiteral | genericFunctionLiteral.