Patterns parsing: improve error recovery for `late` in patternVariableDeclaration.

Bug: https://github.com/dart-lang/sdk/issues/50035
Change-Id: Id706ff0afab3f14d817fbf99112f772d1f1f7817
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/292800
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index 3edbcd7..086992b 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -8346,6 +8346,18 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeLatePatternVariableDeclaration =
+    messageLatePatternVariableDeclaration;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageLatePatternVariableDeclaration = const MessageCode(
+    "LatePatternVariableDeclaration",
+    index: 151,
+    problemMessage:
+        r"""A pattern variable declaration may not use the `late` keyword.""",
+    correctionMessage: r"""Try removing the keyword `late`.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeLibraryDirectiveNotFirst = messageLibraryDirectiveNotFirst;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
index b5ec6f4..1fd4676 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
@@ -7792,10 +7792,7 @@
       varFinalOrConst = context.varFinalOrConst;
     }
 
-    // TODO(paulberry): maybe some of the conditions in this `if` test should be
-    // removed to allow for better error recovery.
     if (allowPatterns &&
-        lateToken == null &&
         varFinalOrConst != null &&
         (optional('var', varFinalOrConst) ||
             optional('final', varFinalOrConst))) {
@@ -7804,6 +7801,10 @@
           (optional('=', afterOuterPattern.next!) ||
               (forPartsContext != null &&
                   optional('in', afterOuterPattern.next!)))) {
+        if (lateToken != null) {
+          reportRecoverableError(
+              lateToken, codes.messageLatePatternVariableDeclaration);
+        }
         // If there was any metadata, then the caller was responsible for
         // parsing it; if not, then we need to let the listener know there
         // wasn't any.
diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
index 7260bc4..5067849 100644
--- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
+++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
@@ -2530,6 +2530,8 @@
   status: needsEvaluation
 ParserErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION:
   status: needsEvaluation
+ParserErrorCode.LATE_PATTERN_VARIABLE_DECLARATION:
+  status: needsEvaluation
 ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST:
   status: needsEvaluation
 ParserErrorCode.LITERAL_WITH_CLASS_AND_NEW:
diff --git a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
index 821d4fb..9bcd01f 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
@@ -165,6 +165,7 @@
   ParserErrorCode.SEALED_MIXIN,
   ParserErrorCode.VARIABLE_PATTERN_KEYWORD_IN_DECLARATION_CONTEXT,
   ParserErrorCode.INVALID_INSIDE_UNARY_PATTERN,
+  ParserErrorCode.LATE_PATTERN_VARIABLE_DECLARATION,
 ];
 
 class ParserErrorCode extends ErrorCode {
@@ -1128,6 +1129,14 @@
     hasPublishedDocs: true,
   );
 
+  ///  No parameters.
+  static const ParserErrorCode LATE_PATTERN_VARIABLE_DECLARATION =
+      ParserErrorCode(
+    'LATE_PATTERN_VARIABLE_DECLARATION',
+    "A pattern variable declaration may not use the `late` keyword.",
+    correctionMessage: "Try removing the keyword `late`.",
+  );
+
   static const ParserErrorCode LIBRARY_DIRECTIVE_NOT_FIRST = ParserErrorCode(
     'LIBRARY_DIRECTIVE_NOT_FIRST',
     "The library directive must appear before all other directives.",
diff --git a/pkg/analyzer/lib/src/error/error_code_values.g.dart b/pkg/analyzer/lib/src/error/error_code_values.g.dart
index 3a7ecc8..50da53f 100644
--- a/pkg/analyzer/lib/src/error/error_code_values.g.dart
+++ b/pkg/analyzer/lib/src/error/error_code_values.g.dart
@@ -754,6 +754,7 @@
   ParserErrorCode.INVALID_UNICODE_ESCAPE_U_NO_BRACKET,
   ParserErrorCode.INVALID_UNICODE_ESCAPE_U_STARTED,
   ParserErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION,
+  ParserErrorCode.LATE_PATTERN_VARIABLE_DECLARATION,
   ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST,
   ParserErrorCode.LITERAL_WITH_CLASS,
   ParserErrorCode.LITERAL_WITH_CLASS_AND_NEW,
diff --git a/pkg/analyzer/test/generated/patterns_parser_test.dart b/pkg/analyzer/test/generated/patterns_parser_test.dart
index 11a490b..2fbf973 100644
--- a/pkg/analyzer/test/generated/patterns_parser_test.dart
+++ b/pkg/analyzer/test/generated/patterns_parser_test.dart
@@ -7538,20 +7538,43 @@
 ''');
   }
 
-  test_patternVariableDeclarationStatement_disallowsLate() {
+  test_patternVariableDeclarationStatement_disallowsConst() {
     // TODO(paulberry): do better error recovery.
     _parse('''
 f(x) {
+  const (_) = x;
+}
+''', errors: [
+      error(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 9, 9),
+      error(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 9, 9),
+      error(ParserErrorCode.RECORD_LITERAL_ONE_POSITIONAL_NO_TRAILING_COMMA, 17,
+          1),
+    ]);
+  }
+
+  test_patternVariableDeclarationStatement_disallowsLate() {
+    _parse('''
+f(x) {
   late var (_) = x;
 }
 ''', errors: [
-      error(ParserErrorCode.MISSING_IDENTIFIER, 18, 1),
-      error(ParserErrorCode.EXPECTED_TOKEN, 18, 1),
-      error(ParserErrorCode.EXPECTED_TOKEN, 19, 1),
-      error(ParserErrorCode.MISSING_IDENTIFIER, 20, 1),
-      error(ParserErrorCode.UNEXPECTED_TOKEN, 20, 1),
-      error(ParserErrorCode.MISSING_IDENTIFIER, 22, 1),
+      error(ParserErrorCode.LATE_PATTERN_VARIABLE_DECLARATION, 9, 4),
     ]);
+    var node = findNode.patternVariableDeclarationStatement('= x');
+    assertParsedNodeText(node, r'''
+PatternVariableDeclarationStatement
+  declaration: PatternVariableDeclaration
+    keyword: var
+    pattern: ParenthesizedPattern
+      leftParenthesis: (
+      pattern: WildcardPattern
+        name: _
+      rightParenthesis: )
+    equals: =
+    expression: SimpleIdentifier
+      token: x
+  semicolon: ;
+''');
   }
 
   test_patternVariableDeclarationStatement_noMetadata_final_extractor() {
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 633fff6..608df3a 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -6720,6 +6720,18 @@
       if (x case _ as int as num) {}
     }
 
+LatePatternVariableDeclaration:
+  problemMessage: A pattern variable declaration may not use the `late` keyword.
+  correctionMessage: Try removing the keyword `late`.
+  analyzerCode: ParserErrorCode.LATE_PATTERN_VARIABLE_DECLARATION
+  index: 151
+  experiments: patterns
+  comment: No parameters.
+  script: |
+    void f(x) {
+      late var (y, z) = x;
+    }
+
 WeakReferenceNotStatic:
   problemMessage: "Weak reference pragma can be used on a static method only."
 
diff --git a/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsConst.dart b/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsConst.dart
new file mode 100644
index 0000000..aa293ef
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsConst.dart
@@ -0,0 +1,3 @@
+f(x) {
+  const (_) = x;
+}
diff --git a/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsConst.dart.expect b/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsConst.dart.expect
new file mode 100644
index 0000000..c7ffe1f
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsConst.dart.expect
@@ -0,0 +1,44 @@
+Problems reported:
+
+parser/patterns/patternVariableDeclarationStatement_disallowsConst:2:11: A record literal with exactly one positional field requires a trailing comma.
+  const (_) = x;
+          ^
+
+beginCompilationUnit(f)
+  beginMetadataStar(f)
+  endMetadataStar(0)
+  beginTopLevelMember(f)
+    beginTopLevelMethod(, null, null)
+      handleNoType()
+      handleIdentifier(f, topLevelFunctionDeclaration)
+      handleNoTypeVariables(()
+      beginFormalParameters((, MemberKind.TopLevelMethod)
+        beginMetadataStar(x)
+        endMetadataStar(0)
+        beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+          handleNoType(()
+          handleIdentifier(x, formalParameterDeclaration)
+          handleFormalParameterWithoutValue())
+        endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+      endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+      handleAsyncModifier(null, null)
+      beginBlockFunctionBody({)
+        beginConstLiteral(()
+          beginParenthesizedExpressionOrRecordLiteral(()
+            handleIdentifier(_, expression)
+            handleNoTypeArguments())
+            handleNoArguments())
+            handleSend(_, ))
+            handleRecoverableError(RecordLiteralOnePositionalFieldNoTrailingComma, ), ))
+          endRecordLiteral((, 1, const)
+        endConstLiteral(=)
+        handleIdentifier(x, expression)
+        handleNoTypeArguments(;)
+        handleNoArguments(;)
+        handleSend(x, ;)
+        handleAssignmentExpression(=)
+        handleExpressionStatement(;)
+      endBlockFunctionBody(1, {, })
+    endTopLevelMethod(f, null, })
+  endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsConst.dart.intertwined.expect b/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsConst.dart.intertwined.expect
new file mode 100644
index 0000000..69803ba
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsConst.dart.intertwined.expect
@@ -0,0 +1,95 @@
+parseUnit(f)
+  skipErrorTokens(f)
+  listener: beginCompilationUnit(f)
+  syntheticPreviousToken(f)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(f)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl()
+      listener: beginTopLevelMember(f)
+      isReservedKeyword(()
+      parseTopLevelMethod(, null, null, , Instance of 'NoType', null, f, false)
+        listener: beginTopLevelMethod(, null, null)
+        listener: handleNoType()
+        ensureIdentifierPotentiallyRecovered(, topLevelFunctionDeclaration, false)
+          listener: handleIdentifier(f, topLevelFunctionDeclaration)
+        parseMethodTypeVar(f)
+          listener: handleNoTypeVariables(()
+        parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
+          parseFormalParameters(f, MemberKind.TopLevelMethod)
+            parseFormalParametersRest((, MemberKind.TopLevelMethod)
+              listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+              parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+                parseMetadataStar(()
+                  listener: beginMetadataStar(x)
+                  listener: endMetadataStar(0)
+                listener: beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+                listener: handleNoType(()
+                ensureIdentifier((, formalParameterDeclaration)
+                  listener: handleIdentifier(x, formalParameterDeclaration)
+                listener: handleFormalParameterWithoutValue())
+                listener: endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+              listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+        parseAsyncModifierOpt())
+          listener: handleAsyncModifier(null, null)
+          inPlainSync()
+        parseFunctionBody(), false, false)
+          listener: beginBlockFunctionBody({)
+          notEofOrValue(}, const)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrConstDeclaration({)
+                parseExpressionStatement({)
+                  parseExpression({)
+                    looksLikeOuterPatternEquals({)
+                      skipOuterPattern({)
+                    parsePrecedenceExpression({, 1, true, ConstantPatternContext.none)
+                      parseUnaryExpression({, true, ConstantPatternContext.none)
+                        parsePrimary({, expression, ConstantPatternContext.none)
+                          parseConstExpression({)
+                            listener: beginConstLiteral(()
+                            parseParenthesizedExpressionOrRecordLiteral(const, const, ConstantPatternContext.none)
+                              listener: beginParenthesizedExpressionOrRecordLiteral(()
+                              parseExpression(()
+                                looksLikeOuterPatternEquals(()
+                                  skipOuterPattern(()
+                                    skipObjectPatternRest(_)
+                                parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
+                                  parseUnaryExpression((, true, ConstantPatternContext.none)
+                                    parsePrimary((, expression, ConstantPatternContext.none)
+                                      parseSendOrFunctionLiteral((, expression, ConstantPatternContext.none)
+                                        parseSend((, expression, ConstantPatternContext.none)
+                                          isNextIdentifier(()
+                                          ensureIdentifier((, expression)
+                                            listener: handleIdentifier(_, expression)
+                                          listener: handleNoTypeArguments())
+                                          parseArgumentsOpt(_)
+                                            listener: handleNoArguments())
+                                          listener: handleSend(_, ))
+                              ensureCloseParen(_, ()
+                              reportRecoverableError(), RecordLiteralOnePositionalFieldNoTrailingComma)
+                                listener: handleRecoverableError(RecordLiteralOnePositionalFieldNoTrailingComma, ), ))
+                              listener: endRecordLiteral((, 1, const)
+                            listener: endConstLiteral(=)
+                      parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none)
+                        parseUnaryExpression(=, true, ConstantPatternContext.none)
+                          parsePrimary(=, expression, ConstantPatternContext.none)
+                            parseSendOrFunctionLiteral(=, expression, ConstantPatternContext.none)
+                              parseSend(=, expression, ConstantPatternContext.none)
+                                isNextIdentifier(=)
+                                ensureIdentifier(=, expression)
+                                  listener: handleIdentifier(x, expression)
+                                listener: handleNoTypeArguments(;)
+                                parseArgumentsOpt(x)
+                                  listener: handleNoArguments(;)
+                                listener: handleSend(x, ;)
+                      listener: handleAssignmentExpression(=)
+                  ensureSemicolon(x)
+                  listener: handleExpressionStatement(;)
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(1, {, })
+        listener: endTopLevelMethod(f, null, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(f)
+  listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsConst.dart.parser.expect b/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsConst.dart.parser.expect
new file mode 100644
index 0000000..79f293d
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsConst.dart.parser.expect
@@ -0,0 +1,9 @@
+f(x) {
+const (_) = x;
+}
+
+
+f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] ([BeginToken]_[StringToken])[SimpleToken] =[SimpleToken] x[StringToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsConst.dart.scanner.expect b/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsConst.dart.scanner.expect
new file mode 100644
index 0000000..79f293d
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsConst.dart.scanner.expect
@@ -0,0 +1,9 @@
+f(x) {
+const (_) = x;
+}
+
+
+f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] ([BeginToken]_[StringToken])[SimpleToken] =[SimpleToken] x[StringToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.expect b/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.expect
index b11f423..6a64cb8 100644
--- a/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.expect
+++ b/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.expect
@@ -1,32 +1,8 @@
 Problems reported:
 
-parser/patterns/patternVariableDeclarationStatement_disallowsLate:2:12: Expected an identifier, but got '('.
+parser/patterns/patternVariableDeclarationStatement_disallowsLate:2:3: A pattern variable declaration may not use the `late` keyword.
   late var (_) = x;
-           ^
-
-parser/patterns/patternVariableDeclarationStatement_disallowsLate:2:12: Expected ';' after this.
-  late var (_) = x;
-           ^
-
-parser/patterns/patternVariableDeclarationStatement_disallowsLate:2:13: Expected ';' after this.
-  late var (_) = x;
-            ^
-
-parser/patterns/patternVariableDeclarationStatement_disallowsLate:2:14: Expected an identifier, but got ')'.
-  late var (_) = x;
-             ^
-
-parser/patterns/patternVariableDeclarationStatement_disallowsLate:2:13: Expected ';' after this.
-  late var (_) = x;
-            ^
-
-parser/patterns/patternVariableDeclarationStatement_disallowsLate:2:14: Unexpected token ';'.
-  late var (_) = x;
-             ^
-
-parser/patterns/patternVariableDeclarationStatement_disallowsLate:2:16: Expected an identifier, but got '='.
-  late var (_) = x;
-               ^
+  ^^^^
 
 beginCompilationUnit(f)
   beginMetadataStar(f)
@@ -47,43 +23,18 @@
       endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
       handleAsyncModifier(null, null)
       beginBlockFunctionBody({)
+        handleRecoverableError(LatePatternVariableDeclaration, late, late)
         beginMetadataStar(late)
         endMetadataStar(0)
-        handleNoType(var)
-        beginVariablesDeclaration((, late, var)
-          handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got '('., Try inserting an identifier before '('., {lexeme: (}], (, ()
-          handleIdentifier(, localVariableDeclaration)
-          beginInitializedIdentifier()
-            handleNoVariableInitializer()
-          endInitializedIdentifier()
-          handleRecoverableError(Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}], (, ()
-        endVariablesDeclaration(1, ;)
-        handleIdentifier(_, expression)
-        handleNoTypeArguments())
-        handleNoArguments())
-        handleSend(_, ))
-        handleRecoverableError(Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}], _, _)
-        handleExpressionStatement(;)
-        handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got ')'., Try inserting an identifier before ')'., {lexeme: )}], ), ))
-        handleIdentifier(, expression)
-        handleNoTypeArguments())
-        handleNoArguments())
-        handleSend(, ))
-        handleRecoverableError(Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}], _, _)
-        handleExpressionStatement(;)
-        handleRecoverableError(Message[UnexpectedToken, Unexpected token ';'., null, {lexeme: ;}], ), ))
-        handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got '='., Try inserting an identifier before '='., {lexeme: =}], =, =)
-        handleIdentifier(, expression)
-        handleNoTypeArguments(=)
-        handleNoArguments(=)
-        handleSend(, =)
+        handleNoType(_)
+        handleWildcardPattern(null, _)
+        handleParenthesizedPattern(()
         handleIdentifier(x, expression)
         handleNoTypeArguments(;)
         handleNoArguments(;)
         handleSend(x, ;)
-        handleAssignmentExpression(=)
-        handleExpressionStatement(;)
-      endBlockFunctionBody(4, {, })
+        handlePatternVariableDeclarationStatement(var, =, ;)
+      endBlockFunctionBody(1, {, })
     endTopLevelMethod(f, null, })
   endTopLevelDeclaration()
 endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.intertwined.expect b/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.intertwined.expect
index 5dadf33..07a2084 100644
--- a/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.intertwined.expect
@@ -41,126 +41,42 @@
             parseStatementX({)
               parseExpressionStatementOrDeclaration({, null)
                 parseExpressionStatementOrDeclarationAfterModifiers(var, {, late, var, null, null)
-                  looksLikeLocalFunction(()
+                  skipOuterPattern(var)
+                  reportRecoverableError(late, LatePatternVariableDeclaration)
+                    listener: handleRecoverableError(LatePatternVariableDeclaration, late, late)
                   listener: beginMetadataStar(late)
                   listener: endMetadataStar(0)
-                  listener: handleNoType(var)
-                  listener: beginVariablesDeclaration((, late, var)
-                  parseVariablesDeclarationRest(var, true)
-                    parseOptionallyInitializedIdentifier(var)
-                      ensureIdentifier(var, localVariableDeclaration)
-                        reportRecoverableErrorWithToken((, Instance of 'Template<(Token) => Message>')
-                          listener: handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got '('., Try inserting an identifier before '('., {lexeme: (}], (, ()
-                        rewriter()
-                        listener: handleIdentifier(, localVariableDeclaration)
-                      listener: beginInitializedIdentifier()
-                      parseVariableInitializerOpt()
-                        listener: handleNoVariableInitializer()
-                      listener: endInitializedIdentifier()
-                    ensureSemicolon()
-                      reportRecoverableError((, Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}])
-                        listener: handleRecoverableError(Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}], (, ()
-                      rewriter()
-                    listener: endVariablesDeclaration(1, ;)
-          notEofOrValue(}, _)
-          parseStatement(;)
-            parseStatementX(;)
-              parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, null)
-                looksLikeLocalFunction(_)
-                parseExpressionStatement(;)
-                  parseExpression(;)
-                    looksLikeOuterPatternEquals(;)
-                      skipOuterPattern(;)
-                        skipObjectPatternRest(_)
-                    parsePrecedenceExpression(;, 1, true, ConstantPatternContext.none)
-                      parseUnaryExpression(;, true, ConstantPatternContext.none)
-                        parsePrimary(;, expression, ConstantPatternContext.none)
-                          parseSendOrFunctionLiteral(;, expression, ConstantPatternContext.none)
-                            parseSend(;, expression, ConstantPatternContext.none)
-                              isNextIdentifier(;)
-                              ensureIdentifier(;, expression)
-                                listener: handleIdentifier(_, expression)
-                              listener: handleNoTypeArguments())
-                              parseArgumentsOpt(_)
-                                listener: handleNoArguments())
-                              listener: handleSend(_, ))
-                  ensureSemicolon(_)
-                    reportRecoverableError(_, Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}])
-                      listener: handleRecoverableError(Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}], _, _)
-                    rewriter()
-                  listener: handleExpressionStatement(;)
-          notEofOrValue(}, ))
-          parseStatement(;)
-            parseStatementX(;)
-              parseExpressionStatementOrDeclaration(;, null)
-                parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, null)
-                  looksLikeLocalFunction())
-                  parseExpressionStatement(;)
-                    parseExpression(;)
-                      looksLikeOuterPatternEquals(;)
-                        skipOuterPattern(;)
-                      parsePrecedenceExpression(;, 1, true, ConstantPatternContext.none)
-                        parseUnaryExpression(;, true, ConstantPatternContext.none)
-                          parsePrimary(;, expression, ConstantPatternContext.none)
-                            parseSend(;, expression, ConstantPatternContext.none)
-                              isNextIdentifier(;)
-                              ensureIdentifier(;, expression)
-                                reportRecoverableErrorWithToken(), Instance of 'Template<(Token) => Message>')
-                                  listener: handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got ')'., Try inserting an identifier before ')'., {lexeme: )}], ), ))
-                                rewriter()
-                                listener: handleIdentifier(, expression)
-                              listener: handleNoTypeArguments())
-                              parseArgumentsOpt()
-                                listener: handleNoArguments())
-                              listener: handleSend(, ))
-                    ensureSemicolon()
-                      reportRecoverableError(_, Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}])
-                        listener: handleRecoverableError(Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}], _, _)
-                      rewriter()
-                    listener: handleExpressionStatement(;)
-          reportRecoverableError(;, Message[UnexpectedToken, Unexpected token ';'., null, {lexeme: ;}])
-            listener: handleRecoverableError(Message[UnexpectedToken, Unexpected token ';'., null, {lexeme: ;}], ), ))
-          notEofOrValue(}, =)
-          parseStatement())
-            parseStatementX())
-              parseExpressionStatementOrDeclaration(), null)
-                parseExpressionStatementOrDeclarationAfterModifiers(), ), null, null, null, null)
-                  looksLikeLocalFunction(=)
-                  parseExpressionStatement())
-                    parseExpression())
-                      looksLikeOuterPatternEquals())
-                        skipOuterPattern())
-                      parsePrecedenceExpression(), 1, true, ConstantPatternContext.none)
-                        parseUnaryExpression(), true, ConstantPatternContext.none)
-                          parsePrimary(), expression, ConstantPatternContext.none)
-                            parseSend(), expression, ConstantPatternContext.none)
-                              isNextIdentifier())
-                              ensureIdentifier(), expression)
-                                reportRecoverableErrorWithToken(=, Instance of 'Template<(Token) => Message>')
-                                  listener: handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got '='., Try inserting an identifier before '='., {lexeme: =}], =, =)
-                                rewriter()
-                                listener: handleIdentifier(, expression)
-                              listener: handleNoTypeArguments(=)
-                              parseArgumentsOpt()
-                                listener: handleNoArguments(=)
-                              listener: handleSend(, =)
-                        parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none)
-                          parseUnaryExpression(=, true, ConstantPatternContext.none)
-                            parsePrimary(=, expression, ConstantPatternContext.none)
-                              parseSendOrFunctionLiteral(=, expression, ConstantPatternContext.none)
-                                parseSend(=, expression, ConstantPatternContext.none)
-                                  isNextIdentifier(=)
-                                  ensureIdentifier(=, expression)
-                                    listener: handleIdentifier(x, expression)
-                                  listener: handleNoTypeArguments(;)
-                                  parseArgumentsOpt(x)
-                                    listener: handleNoArguments(;)
-                                  listener: handleSend(x, ;)
-                        listener: handleAssignmentExpression(=)
+                  parsePatternVariableDeclarationStatement(var, {, var)
+                    parsePattern(var, PatternContext.declaration, precedence: 1)
+                      parsePrimaryPattern(var, PatternContext.declaration)
+                        parseParenthesizedPatternOrRecordPattern(var, PatternContext.declaration)
+                          parsePattern((, PatternContext.declaration, precedence: 1)
+                            parsePrimaryPattern((, PatternContext.declaration)
+                              parseVariablePattern((, PatternContext.declaration, typeInfo: Instance of 'NoType')
+                                listener: handleNoType(_)
+                                listener: handleWildcardPattern(null, _)
+                          ensureCloseParen(_, ()
+                          listener: handleParenthesizedPattern(()
+                    parseExpression(=)
+                      looksLikeOuterPatternEquals(=)
+                        skipOuterPattern(=)
+                          skipObjectPatternRest(x)
+                      parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none)
+                        parseUnaryExpression(=, true, ConstantPatternContext.none)
+                          parsePrimary(=, expression, ConstantPatternContext.none)
+                            parseSendOrFunctionLiteral(=, expression, ConstantPatternContext.none)
+                              parseSend(=, expression, ConstantPatternContext.none)
+                                isNextIdentifier(=)
+                                ensureIdentifier(=, expression)
+                                  listener: handleIdentifier(x, expression)
+                                listener: handleNoTypeArguments(;)
+                                parseArgumentsOpt(x)
+                                  listener: handleNoArguments(;)
+                                listener: handleSend(x, ;)
                     ensureSemicolon(x)
-                    listener: handleExpressionStatement(;)
+                    listener: handlePatternVariableDeclarationStatement(var, =, ;)
           notEofOrValue(}, })
-          listener: endBlockFunctionBody(4, {, })
+          listener: endBlockFunctionBody(1, {, })
         listener: endTopLevelMethod(f, null, })
   listener: endTopLevelDeclaration()
   reportAllErrorTokens(f)
diff --git a/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.parser.expect b/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.parser.expect
index 5878358..50323ff 100644
--- a/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.parser.expect
+++ b/pkg/front_end/parser_testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.parser.expect
@@ -1,11 +1,9 @@
-NOTICE: Stream was rewritten by parser!
-
 f(x) {
-late var (*synthetic*;_;*synthetic*;) *synthetic*= x;
+late var (_) = x;
 }
 
 
 f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
-late[KeywordToken] var[KeywordToken] ([BeginToken][SyntheticStringToken];[SyntheticToken]_[StringToken];[SyntheticToken][SyntheticStringToken];[SyntheticToken])[SimpleToken] [SyntheticStringToken]=[SimpleToken] x[StringToken];[SimpleToken]
+late[KeywordToken] var[KeywordToken] ([BeginToken]_[StringToken])[SimpleToken] =[SimpleToken] x[StringToken];[SimpleToken]
 }[SimpleToken]
 [SimpleToken]
diff --git a/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.strong.expect b/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.strong.expect
index cbacc5d..1332fa1 100644
--- a/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.strong.expect
+++ b/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.strong.expect
@@ -2,37 +2,18 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:12: Error: Expected an identifier, but got '('.
-// Try inserting an identifier before '('.
+// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:3: Error: A pattern variable declaration may not use the `late` keyword.
+// Try removing the keyword `late`.
 //   late var (_) = x;
-//            ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:12: Error: Expected ';' after this.
-//   late var (_) = x;
-//            ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:13: Error: Expected ';' after this.
-//   late var (_) = x;
-//             ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:13: Error: Undefined name '_'.
-//   late var (_) = x;
-//             ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:14: Error: Expected an identifier, but got ')'.
-// Try inserting an identifier before ')'.
-//   late var (_) = x;
-//              ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:14: Error: Unexpected token ';'.
-//   late var (_) = x;
-//              ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:16: Error: Expected an identifier, but got '='.
-// Try inserting an identifier before '='.
-//   late var (_) = x;
-//                ^
+//   ^^^^
 //
 import self as self;
+import "dart:core" as core;
 
-static method f(dynamic x) → dynamic {}
+static method f(dynamic x) → dynamic {
+  {
+    final synthesized dynamic #0#0 = x;
+    if(!true)
+      throw new core::StateError::•("Pattern matching error");
+  }
+}
diff --git a/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.strong.transformed.expect
index cbacc5d..81a3665 100644
--- a/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.strong.transformed.expect
@@ -2,37 +2,23 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:12: Error: Expected an identifier, but got '('.
-// Try inserting an identifier before '('.
+// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:3: Error: A pattern variable declaration may not use the `late` keyword.
+// Try removing the keyword `late`.
 //   late var (_) = x;
-//            ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:12: Error: Expected ';' after this.
-//   late var (_) = x;
-//            ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:13: Error: Expected ';' after this.
-//   late var (_) = x;
-//             ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:13: Error: Undefined name '_'.
-//   late var (_) = x;
-//             ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:14: Error: Expected an identifier, but got ')'.
-// Try inserting an identifier before ')'.
-//   late var (_) = x;
-//              ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:14: Error: Unexpected token ';'.
-//   late var (_) = x;
-//              ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:16: Error: Expected an identifier, but got '='.
-// Try inserting an identifier before '='.
-//   late var (_) = x;
-//                ^
+//   ^^^^
 //
 import self as self;
+import "dart:core" as core;
 
-static method f(dynamic x) → dynamic {}
+static method f(dynamic x) → dynamic {
+  {
+    final synthesized dynamic #0#0 = x;
+    if(!true)
+      throw new core::StateError::•("Pattern matching error");
+  }
+}
+
+
+Extra constant evaluation status:
+Evaluated: Not @ org-dartlang-testcase:///patternVariableDeclarationStatement_disallowsLate.dart:6:13 -> BoolConstant(false)
+Extra constant evaluation: evaluated: 4, effectively constant: 1
diff --git a/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.weak.expect b/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.weak.expect
index cbacc5d..1332fa1 100644
--- a/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.weak.expect
+++ b/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.weak.expect
@@ -2,37 +2,18 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:12: Error: Expected an identifier, but got '('.
-// Try inserting an identifier before '('.
+// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:3: Error: A pattern variable declaration may not use the `late` keyword.
+// Try removing the keyword `late`.
 //   late var (_) = x;
-//            ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:12: Error: Expected ';' after this.
-//   late var (_) = x;
-//            ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:13: Error: Expected ';' after this.
-//   late var (_) = x;
-//             ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:13: Error: Undefined name '_'.
-//   late var (_) = x;
-//             ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:14: Error: Expected an identifier, but got ')'.
-// Try inserting an identifier before ')'.
-//   late var (_) = x;
-//              ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:14: Error: Unexpected token ';'.
-//   late var (_) = x;
-//              ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:16: Error: Expected an identifier, but got '='.
-// Try inserting an identifier before '='.
-//   late var (_) = x;
-//                ^
+//   ^^^^
 //
 import self as self;
+import "dart:core" as core;
 
-static method f(dynamic x) → dynamic {}
+static method f(dynamic x) → dynamic {
+  {
+    final synthesized dynamic #0#0 = x;
+    if(!true)
+      throw new core::StateError::•("Pattern matching error");
+  }
+}
diff --git a/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.weak.modular.expect b/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.weak.modular.expect
index cbacc5d..1332fa1 100644
--- a/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.weak.modular.expect
@@ -2,37 +2,18 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:12: Error: Expected an identifier, but got '('.
-// Try inserting an identifier before '('.
+// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:3: Error: A pattern variable declaration may not use the `late` keyword.
+// Try removing the keyword `late`.
 //   late var (_) = x;
-//            ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:12: Error: Expected ';' after this.
-//   late var (_) = x;
-//            ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:13: Error: Expected ';' after this.
-//   late var (_) = x;
-//             ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:13: Error: Undefined name '_'.
-//   late var (_) = x;
-//             ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:14: Error: Expected an identifier, but got ')'.
-// Try inserting an identifier before ')'.
-//   late var (_) = x;
-//              ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:14: Error: Unexpected token ';'.
-//   late var (_) = x;
-//              ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:16: Error: Expected an identifier, but got '='.
-// Try inserting an identifier before '='.
-//   late var (_) = x;
-//                ^
+//   ^^^^
 //
 import self as self;
+import "dart:core" as core;
 
-static method f(dynamic x) → dynamic {}
+static method f(dynamic x) → dynamic {
+  {
+    final synthesized dynamic #0#0 = x;
+    if(!true)
+      throw new core::StateError::•("Pattern matching error");
+  }
+}
diff --git a/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.weak.transformed.expect b/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.weak.transformed.expect
index cbacc5d..81a3665 100644
--- a/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart.weak.transformed.expect
@@ -2,37 +2,23 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:12: Error: Expected an identifier, but got '('.
-// Try inserting an identifier before '('.
+// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:3: Error: A pattern variable declaration may not use the `late` keyword.
+// Try removing the keyword `late`.
 //   late var (_) = x;
-//            ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:12: Error: Expected ';' after this.
-//   late var (_) = x;
-//            ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:13: Error: Expected ';' after this.
-//   late var (_) = x;
-//             ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:13: Error: Undefined name '_'.
-//   late var (_) = x;
-//             ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:14: Error: Expected an identifier, but got ')'.
-// Try inserting an identifier before ')'.
-//   late var (_) = x;
-//              ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:14: Error: Unexpected token ';'.
-//   late var (_) = x;
-//              ^
-//
-// pkg/front_end/testcases/patterns/patternVariableDeclarationStatement_disallowsLate.dart:6:16: Error: Expected an identifier, but got '='.
-// Try inserting an identifier before '='.
-//   late var (_) = x;
-//                ^
+//   ^^^^
 //
 import self as self;
+import "dart:core" as core;
 
-static method f(dynamic x) → dynamic {}
+static method f(dynamic x) → dynamic {
+  {
+    final synthesized dynamic #0#0 = x;
+    if(!true)
+      throw new core::StateError::•("Pattern matching error");
+  }
+}
+
+
+Extra constant evaluation status:
+Evaluated: Not @ org-dartlang-testcase:///patternVariableDeclarationStatement_disallowsLate.dart:6:13 -> BoolConstant(false)
+Extra constant evaluation: evaluated: 4, effectively constant: 1