[parser] Change recovery of multiple extends with comma

E.g. class Foo extends Bar, Baz {} would before have parsed weirdly,
but it will parse as you'd (probably) expect with an error saying
you cannot do that. For now at least both CFE and Analyzer will
pretend like you just specified the first one but I suppose Analyzer
could for instance use the extra information to propose converting
other ones to implements clauses or similar.

Fixes https://github.com/dart-lang/sdk/issues/22313

Change-Id: I180cdd8ab07143dd74fd21c9976ec2a46c428d8e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/158261
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
index 2a728d5..12d346c 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
@@ -1121,8 +1121,8 @@
   }
 
   @override
-  void handleClassExtends(Token extendsKeyword) {
-    listener?.handleClassExtends(extendsKeyword);
+  void handleClassExtends(Token extendsKeyword, int typeCount) {
+    listener?.handleClassExtends(extendsKeyword, typeCount);
   }
 
   @override
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
index 53906bc..735b41c 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
@@ -126,7 +126,10 @@
 
   /// Handle an extends clause in a class declaration. Substructures:
   /// - supertype (may be a mixin application)
-  void handleClassExtends(Token extendsKeyword) {
+  /// The typeCount is for error recovery: Invalid code might have more than one
+  /// class specified in the extends clause. A parser error has already been
+  /// issued.
+  void handleClassExtends(Token extendsKeyword, int typeCount) {
     logEvent("ClassExtends");
   }
 
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 4d1f27b..3a835f3 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
@@ -1903,10 +1903,7 @@
           const ['extend', 'on'].contains(token.next.lexeme)) {
         reportRecoverableError(
             token.next, codes.templateExpectedInstead.withArguments('extends'));
-        Token incorrectExtendsKeyword = token.next;
-        token = computeType(incorrectExtendsKeyword, /* required = */ true)
-            .ensureTypeNotVoid(incorrectExtendsKeyword, this);
-        listener.handleClassExtends(incorrectExtendsKeyword);
+        token = parseClassExtendsSeenExtendsClause(token.next, token);
       } else {
         token = parseClassExtendsOpt(token);
       }
@@ -1966,17 +1963,36 @@
     // extends <typeNotVoid>
     Token next = token.next;
     if (optional('extends', next)) {
-      Token extendsKeyword = next;
-      token = computeType(next, /* required = */ true)
-          .ensureTypeNotVoid(next, this);
-      listener.handleClassExtends(extendsKeyword);
+      token = parseClassExtendsSeenExtendsClause(next, token);
     } else {
       listener.handleNoType(token);
-      listener.handleClassExtends(/* extendsKeyword = */ null);
+      listener.handleClassExtends(null, 1);
     }
     return token;
   }
 
+  Token parseClassExtendsSeenExtendsClause(Token extendsKeyword, Token token) {
+    Token next = extendsKeyword;
+    token =
+        computeType(next, /* required = */ true).ensureTypeNotVoid(next, this);
+    int count = 1;
+
+    // Error recovery: extends <typeNotVoid>, <typeNotVoid> [...]
+    if (optional(',', token.next)) {
+      reportRecoverableError(token.next, codes.messageMultipleExtends);
+
+      while (optional(',', token.next)) {
+        next = token.next;
+        token = computeType(next, /* required = */ true)
+            .ensureTypeNotVoid(next, this);
+        count++;
+      }
+    }
+
+    listener.handleClassExtends(extendsKeyword, count);
+    return token;
+  }
+
   /// ```
   /// implementsClause:
   ///   'implements' typeName (',' typeName)*
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/recovery_listeners.dart b/pkg/_fe_analyzer_shared/lib/src/parser/recovery_listeners.dart
index 4c1921b..9320871 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/recovery_listeners.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/recovery_listeners.dart
@@ -18,9 +18,9 @@
   }
 
   @override
-  void handleClassExtends(Token extendsKeyword) {
+  void handleClassExtends(Token extendsKeyword, int typeCount) {
     this.extendsKeyword = extendsKeyword;
-    super.handleClassExtends(extendsKeyword);
+    super.handleClassExtends(extendsKeyword, typeCount);
   }
 
   @override
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/stack_listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/stack_listener.dart
index b5b58a5..a29d6f0 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/stack_listener.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/stack_listener.dart
@@ -306,7 +306,7 @@
   }
 
   @override
-  void handleClassExtends(Token extendsKeyword) {
+  void handleClassExtends(Token extendsKeyword, int typeCount) {
     debugEvent("ClassExtends");
   }
 
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 839f9a6..0421a6d 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -2447,10 +2447,16 @@
   }
 
   @override
-  void handleClassExtends(Token extendsKeyword) {
+  void handleClassExtends(Token extendsKeyword, int typeCount) {
     assert(extendsKeyword == null || extendsKeyword.isKeywordOrIdentifier);
     debugEvent("ClassExtends");
 
+    // If more extends clauses was specified (parser has already issued an
+    // error) throw them away for now and pick the first one.
+    while (typeCount > 1) {
+      pop();
+      typeCount--;
+    }
     TypeName supertype = pop();
     if (supertype != null) {
       push(ast.extendsClause(extendsKeyword, supertype));
diff --git a/pkg/analyzer/test/generated/parser_fasta_listener.dart b/pkg/analyzer/test/generated/parser_fasta_listener.dart
index bb429e9..130997a 100644
--- a/pkg/analyzer/test/generated/parser_fasta_listener.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_listener.dart
@@ -1260,9 +1260,9 @@
   }
 
   @override
-  void handleClassExtends(Token extendsKeyword) {
+  void handleClassExtends(Token extendsKeyword, int typeCount) {
     expectIn('ClassDeclaration');
-    listener.handleClassExtends(extendsKeyword);
+    listener.handleClassExtends(extendsKeyword, typeCount);
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
index 7fa2286..4ed6843 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -522,6 +522,11 @@
   @override
   void handleRecoverClassHeader() {
     debugEvent("handleRecoverClassHeader");
+    // TODO(jensj): Possibly use these instead... E.g. "class A extend B {}"
+    // will get here (because it's 'extends' with an 's') and discard the B...
+    // Also Analyzer actually merges the information meaning that the two could
+    // give different errors (if, say, one later assigns
+    // A to a variable of type B).
     pop(NullValue.TypeBuilderList); // Interfaces.
     pop(); // Supertype offset.
     pop(); // Supertype.
@@ -530,13 +535,19 @@
   @override
   void handleRecoverMixinHeader() {
     debugEvent("handleRecoverMixinHeader");
+    // TODO(jensj): Possibly use these instead...
+    // See also handleRecoverClassHeader
     pop(NullValue.TypeBuilderList); // Interfaces.
     pop(NullValue.TypeBuilderList); // Supertype constraints.
   }
 
   @override
-  void handleClassExtends(Token extendsKeyword) {
+  void handleClassExtends(Token extendsKeyword, int typeCount) {
     debugEvent("handleClassExtends");
+    while (typeCount > 1) {
+      pop();
+      typeCount--;
+    }
     push(extendsKeyword?.charOffset ?? -1);
   }
 
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 04ff108..a16abd1 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -481,8 +481,6 @@
 MixinInferenceNoMatchingClass/example: Fail
 ModifierOutOfOrder/part_wrapped_script1: Fail
 ModifierOutOfOrder/script1: Fail
-MultipleExtends/part_wrapped_script: Fail
-MultipleExtends/script: Fail
 MultipleImplements/part_wrapped_script: Fail
 MultipleImplements/script: Fail
 MultipleLibraryDirectives/example: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index d41b3ac..c5a9dce 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -366,7 +366,9 @@
   template: "Each class definition can have at most one extends clause."
   tip: "Try choosing one superclass and define your class to implement (or mix in) the others."
   analyzerCode: ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES
-  script: "class A extends B extends C {}"
+  script:
+    - "class B{} class C{} class A extends B extends C {}"
+    - "class B{} class C{} class A extends B, C {}"
 
 MultipleWith:
   index: 24
diff --git a/pkg/front_end/parser_testcases/error_recovery/bracket_mismatch_01.dart.expect b/pkg/front_end/parser_testcases/error_recovery/bracket_mismatch_01.dart.expect
index 9dc7216..ce13632 100644
--- a/pkg/front_end/parser_testcases/error_recovery/bracket_mismatch_01.dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/bracket_mismatch_01.dart.expect
@@ -28,7 +28,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, C)
       handleNoType(C)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
@@ -128,7 +128,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, D)
       handleNoType(D)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/error_recovery/bracket_mismatch_01.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/bracket_mismatch_01.dart.intertwined.expect
index 75db5c6..eb5a793 100644
--- a/pkg/front_end/parser_testcases/error_recovery/bracket_mismatch_01.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/bracket_mismatch_01.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(C, class, class)
             parseClassExtendsOpt(C)
               listener: handleNoType(C)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(C)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(C)
@@ -263,7 +263,7 @@
           parseClassHeaderOpt(D, class, class)
             parseClassExtendsOpt(D)
               listener: handleNoType(D)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(D)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(D)
diff --git a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_general.crash_dart.expect b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_general.crash_dart.expect
index 6a0a8a9..e21f896 100644
--- a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_general.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_general.crash_dart.expect
@@ -128,7 +128,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Foo)
       handleNoType(Foo)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_general.crash_dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_general.crash_dart.intertwined.expect
index f3d8756..5590321 100644
--- a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_general.crash_dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_general.crash_dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(Foo, class, class)
             parseClassExtendsOpt(Foo)
               listener: handleNoType(Foo)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Foo)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Foo)
diff --git a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_get.crash_dart.expect b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_get.crash_dart.expect
index d876a54..cae9938 100644
--- a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_get.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_get.crash_dart.expect
@@ -36,7 +36,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Foo)
       handleNoType(Foo)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_get.crash_dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_get.crash_dart.intertwined.expect
index 5d87d53..6b6b94b 100644
--- a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_get.crash_dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_get.crash_dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(Foo, class, class)
             parseClassExtendsOpt(Foo)
               listener: handleNoType(Foo)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Foo)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Foo)
diff --git a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_return_type.crash_dart.expect b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_return_type.crash_dart.expect
index 2939c3c..df016c6 100644
--- a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_return_type.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_return_type.crash_dart.expect
@@ -32,7 +32,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Foo)
       handleNoType(Foo)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_return_type.crash_dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_return_type.crash_dart.intertwined.expect
index 9fd9286..960ba0b 100644
--- a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_return_type.crash_dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_return_type.crash_dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(Foo, class, class)
             parseClassExtendsOpt(Foo)
               listener: handleNoType(Foo)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Foo)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Foo)
diff --git a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_set.crash_dart.expect b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_set.crash_dart.expect
index a6c7f4b..4fdb547 100644
--- a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_set.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_set.crash_dart.expect
@@ -32,7 +32,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Foo)
       handleNoType(Foo)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_set.crash_dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_set.crash_dart.intertwined.expect
index 41adc50..5b09d19 100644
--- a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_set.crash_dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_bad_name_set.crash_dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(Foo, class, class)
             parseClassExtendsOpt(Foo)
               listener: handleNoType(Foo)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Foo)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Foo)
diff --git a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_get.dart.expect b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_get.dart.expect
index 32c5c13..0a3de66 100644
--- a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_get.dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_get.dart.expect
@@ -32,7 +32,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Foo)
       handleNoType(Foo)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_get.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_get.dart.intertwined.expect
index 8dd7398..f618dcd 100644
--- a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_get.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_get.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(Foo, class, class)
             parseClassExtendsOpt(Foo)
               listener: handleNoType(Foo)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Foo)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Foo)
diff --git a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_ok.dart.expect b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_ok.dart.expect
index 6993a8e..003aeba 100644
--- a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_ok.dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_ok.dart.expect
@@ -6,7 +6,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Foo)
       handleNoType(Foo)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_ok.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_ok.dart.intertwined.expect
index 742aa8b..07a34d8 100644
--- a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_ok.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_ok.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(Foo, class, class)
             parseClassExtendsOpt(Foo)
               listener: handleNoType(Foo)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Foo)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Foo)
diff --git a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_operator.crash_dart.expect b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_operator.crash_dart.expect
index a000871..91ce6a3 100644
--- a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_operator.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_operator.crash_dart.expect
@@ -80,7 +80,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Foo)
       handleNoType(Foo)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_operator.crash_dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_operator.crash_dart.intertwined.expect
index a035119..99def95 100644
--- a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_operator.crash_dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_operator.crash_dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(Foo, class, class)
             parseClassExtendsOpt(Foo)
               listener: handleNoType(Foo)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Foo)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Foo)
diff --git a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_return_type.dart.expect b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_return_type.dart.expect
index e78442d..3bcea14 100644
--- a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_return_type.dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_return_type.dart.expect
@@ -24,7 +24,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Foo)
       handleNoType(Foo)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_return_type.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_return_type.dart.intertwined.expect
index 4bbafcb..cde829e 100644
--- a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_return_type.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_return_type.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(Foo, class, class)
             parseClassExtendsOpt(Foo)
               listener: handleNoType(Foo)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Foo)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Foo)
diff --git a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_set.dart.expect b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_set.dart.expect
index 4240ac2..3219c73 100644
--- a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_set.dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_set.dart.expect
@@ -24,7 +24,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Foo)
       handleNoType(Foo)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_set.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_set.dart.intertwined.expect
index 223fd14..7233bf3 100644
--- a/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_set.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/constructor_recovery_set.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(Foo, class, class)
             parseClassExtendsOpt(Foo)
               listener: handleNoType(Foo)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Foo)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Foo)
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_22313.dart b/pkg/front_end/parser_testcases/error_recovery/issue_22313.dart
new file mode 100644
index 0000000..b6a003a
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_22313.dart
@@ -0,0 +1,15 @@
+class A { }
+
+class B { }
+
+class Foo extends A, B {
+  Foo() { }
+}
+
+class Bar extend A, B {
+  Bar() { }
+}
+
+class Baz on A, B {
+  Baz() { }
+}
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_22313.dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_22313.dart.expect
new file mode 100644
index 0000000..cf35cb4
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_22313.dart.expect
@@ -0,0 +1,174 @@
+Problems reported:
+
+parser/error_recovery/issue_22313:5:20: Each class definition can have at most one extends clause.
+class Foo extends A, B {
+                   ^
+
+parser/error_recovery/issue_22313:9:11: Expected 'extends' instead of this.
+class Bar extend A, B {
+          ^^^^^^
+
+parser/error_recovery/issue_22313:9:19: Each class definition can have at most one extends clause.
+class Bar extend A, B {
+                  ^
+
+parser/error_recovery/issue_22313:13:11: Expected 'extends' instead of this.
+class Baz on A, B {
+          ^^
+
+parser/error_recovery/issue_22313:13:15: Each class definition can have at most one extends clause.
+class Baz on A, B {
+              ^
+
+beginCompilationUnit(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(A, classOrMixinDeclaration)
+    handleNoTypeVariables({)
+    beginClassDeclaration(class, null, A)
+      handleNoType(A)
+      handleClassExtends(null, 1)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+      endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+    endClassDeclaration(class, })
+  endTopLevelDeclaration(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(B, classOrMixinDeclaration)
+    handleNoTypeVariables({)
+    beginClassDeclaration(class, null, B)
+      handleNoType(B)
+      handleClassExtends(null, 1)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+      endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+    endClassDeclaration(class, })
+  endTopLevelDeclaration(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(Foo, classOrMixinDeclaration)
+    handleNoTypeVariables(extends)
+    beginClassDeclaration(class, null, Foo)
+      handleIdentifier(A, typeReference)
+      handleNoTypeArguments(,)
+      handleType(A, null)
+      handleRecoverableError(MultipleExtends, ,, ,)
+      handleIdentifier(B, typeReference)
+      handleNoTypeArguments({)
+      handleType(B, null)
+      handleClassExtends(extends, 2)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+        beginMetadataStar(Foo)
+        endMetadataStar(0)
+        beginMember()
+          beginMethod(null, null, null, null, null, Foo)
+            handleNoType({)
+            handleIdentifier(Foo, methodDeclaration)
+            handleNoTypeVariables(()
+            beginFormalParameters((, MemberKind.NonStaticMethod)
+            endFormalParameters(0, (, ), MemberKind.NonStaticMethod)
+            handleNoInitializers()
+            handleAsyncModifier(null, null)
+            beginBlockFunctionBody({)
+            endBlockFunctionBody(0, {, })
+          endClassConstructor(null, Foo, (, null, })
+        endMember()
+      endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+    endClassDeclaration(class, })
+  endTopLevelDeclaration(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(Bar, classOrMixinDeclaration)
+    handleNoTypeVariables(extend)
+    beginClassDeclaration(class, null, Bar)
+      handleNoType(Bar)
+      handleClassExtends(null, 1)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      handleRecoverableError(Message[ExpectedInstead, Expected 'extends' instead of this., null, {string: extends}], extend, extend)
+      handleIdentifier(A, typeReference)
+      handleNoTypeArguments(,)
+      handleType(A, null)
+      handleRecoverableError(MultipleExtends, ,, ,)
+      handleIdentifier(B, typeReference)
+      handleNoTypeArguments({)
+      handleType(B, null)
+      handleClassExtends(extend, 2)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleRecoverClassHeader()
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+        beginMetadataStar(Bar)
+        endMetadataStar(0)
+        beginMember()
+          beginMethod(null, null, null, null, null, Bar)
+            handleNoType({)
+            handleIdentifier(Bar, methodDeclaration)
+            handleNoTypeVariables(()
+            beginFormalParameters((, MemberKind.NonStaticMethod)
+            endFormalParameters(0, (, ), MemberKind.NonStaticMethod)
+            handleNoInitializers()
+            handleAsyncModifier(null, null)
+            beginBlockFunctionBody({)
+            endBlockFunctionBody(0, {, })
+          endClassConstructor(null, Bar, (, null, })
+        endMember()
+      endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+    endClassDeclaration(class, })
+  endTopLevelDeclaration(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(Baz, classOrMixinDeclaration)
+    handleNoTypeVariables(on)
+    beginClassDeclaration(class, null, Baz)
+      handleNoType(Baz)
+      handleClassExtends(null, 1)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      handleRecoverableError(Message[ExpectedInstead, Expected 'extends' instead of this., null, {string: extends}], on, on)
+      handleIdentifier(A, typeReference)
+      handleNoTypeArguments(,)
+      handleType(A, null)
+      handleRecoverableError(MultipleExtends, ,, ,)
+      handleIdentifier(B, typeReference)
+      handleNoTypeArguments({)
+      handleType(B, null)
+      handleClassExtends(on, 2)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleRecoverClassHeader()
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+        beginMetadataStar(Baz)
+        endMetadataStar(0)
+        beginMember()
+          beginMethod(null, null, null, null, null, Baz)
+            handleNoType({)
+            handleIdentifier(Baz, methodDeclaration)
+            handleNoTypeVariables(()
+            beginFormalParameters((, MemberKind.NonStaticMethod)
+            endFormalParameters(0, (, ), MemberKind.NonStaticMethod)
+            handleNoInitializers()
+            handleAsyncModifier(null, null)
+            beginBlockFunctionBody({)
+            endBlockFunctionBody(0, {, })
+          endClassConstructor(null, Baz, (, null, })
+        endMember()
+      endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+    endClassDeclaration(class, })
+  endTopLevelDeclaration()
+endCompilationUnit(5, )
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_22313.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/issue_22313.dart.intertwined.expect
new file mode 100644
index 0000000..f7a6a40
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_22313.dart.intertwined.expect
@@ -0,0 +1,295 @@
+parseUnit(class)
+  skipErrorTokens(class)
+  listener: beginCompilationUnit(class)
+  syntheticPreviousToken(class)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(class)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(, class, Instance of 'DirectiveContext')
+      parseClassDeclarationModifiers(, class)
+      parseClassOrNamedMixinApplication(null, class)
+        listener: beginClassOrNamedMixinApplicationPrelude(class)
+        ensureIdentifier(class, classOrMixinDeclaration)
+          listener: handleIdentifier(A, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, A)
+        parseClass(A, class, class, A)
+          parseClassHeaderOpt(A, class, class)
+            parseClassExtendsOpt(A)
+              listener: handleNoType(A)
+              listener: handleClassExtends(null, 1)
+            parseWithClauseOpt(A)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(A)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(A, DeclarationKind.Class, A)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration(class)
+  parseTopLevelDeclarationImpl(}, Instance of 'DirectiveContext')
+    parseMetadataStar(})
+      listener: beginMetadataStar(class)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(}, class, Instance of 'DirectiveContext')
+      parseClassDeclarationModifiers(}, class)
+      parseClassOrNamedMixinApplication(null, class)
+        listener: beginClassOrNamedMixinApplicationPrelude(class)
+        ensureIdentifier(class, classOrMixinDeclaration)
+          listener: handleIdentifier(B, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, B)
+        parseClass(B, class, class, B)
+          parseClassHeaderOpt(B, class, class)
+            parseClassExtendsOpt(B)
+              listener: handleNoType(B)
+              listener: handleClassExtends(null, 1)
+            parseWithClauseOpt(B)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(B)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(B, DeclarationKind.Class, B)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration(class)
+  parseTopLevelDeclarationImpl(}, Instance of 'DirectiveContext')
+    parseMetadataStar(})
+      listener: beginMetadataStar(class)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(}, class, Instance of 'DirectiveContext')
+      parseClassDeclarationModifiers(}, class)
+      parseClassOrNamedMixinApplication(null, class)
+        listener: beginClassOrNamedMixinApplicationPrelude(class)
+        ensureIdentifier(class, classOrMixinDeclaration)
+          listener: handleIdentifier(Foo, classOrMixinDeclaration)
+        listener: handleNoTypeVariables(extends)
+        listener: beginClassDeclaration(class, null, Foo)
+        parseClass(Foo, class, class, Foo)
+          parseClassHeaderOpt(Foo, class, class)
+            parseClassExtendsOpt(Foo)
+              listener: handleIdentifier(A, typeReference)
+              listener: handleNoTypeArguments(,)
+              listener: handleType(A, null)
+              reportRecoverableError(,, MultipleExtends)
+                listener: handleRecoverableError(MultipleExtends, ,, ,)
+              listener: handleIdentifier(B, typeReference)
+              listener: handleNoTypeArguments({)
+              listener: handleType(B, null)
+              listener: handleClassExtends(extends, 2)
+            parseWithClauseOpt(B)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(B)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(B, DeclarationKind.Class, Foo)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, Foo)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, Foo)
+              parseMetadataStar({)
+                listener: beginMetadataStar(Foo)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              isReservedKeyword(()
+              parseMethod({, null, null, null, null, null, null, {, Instance of 'NoType', null, Foo, DeclarationKind.Class, Foo, false)
+                listener: beginMethod(null, null, null, null, null, Foo)
+                listener: handleNoType({)
+                ensureIdentifierPotentiallyRecovered({, methodDeclaration, false)
+                  listener: handleIdentifier(Foo, methodDeclaration)
+                parseQualifiedRestOpt(Foo, methodDeclarationContinuation)
+                parseMethodTypeVar(Foo)
+                  listener: handleNoTypeVariables(()
+                parseGetterOrFormalParameters(Foo, Foo, false, MemberKind.NonStaticMethod)
+                  parseFormalParameters(Foo, MemberKind.NonStaticMethod)
+                    parseFormalParametersRest((, MemberKind.NonStaticMethod)
+                      listener: beginFormalParameters((, MemberKind.NonStaticMethod)
+                      listener: endFormalParameters(0, (, ), MemberKind.NonStaticMethod)
+                parseInitializersOpt())
+                  listener: handleNoInitializers()
+                parseAsyncModifierOpt())
+                  listener: handleAsyncModifier(null, null)
+                  inPlainSync()
+                inPlainSync()
+                parseFunctionBody(), false, true)
+                  listener: beginBlockFunctionBody({)
+                  notEofOrValue(}, })
+                  listener: endBlockFunctionBody(0, {, })
+                listener: endClassConstructor(null, Foo, (, null, })
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration(class)
+  parseTopLevelDeclarationImpl(}, Instance of 'DirectiveContext')
+    parseMetadataStar(})
+      listener: beginMetadataStar(class)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(}, class, Instance of 'DirectiveContext')
+      parseClassDeclarationModifiers(}, class)
+      parseClassOrNamedMixinApplication(null, class)
+        listener: beginClassOrNamedMixinApplicationPrelude(class)
+        ensureIdentifier(class, classOrMixinDeclaration)
+          listener: handleIdentifier(Bar, classOrMixinDeclaration)
+        listener: handleNoTypeVariables(extend)
+        listener: beginClassDeclaration(class, null, Bar)
+        parseClass(Bar, class, class, Bar)
+          parseClassHeaderOpt(Bar, class, class)
+            parseClassExtendsOpt(Bar)
+              listener: handleNoType(Bar)
+              listener: handleClassExtends(null, 1)
+            parseWithClauseOpt(Bar)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(Bar)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassHeaderRecovery(Bar, class, class)
+            parseClassHeaderOpt(Bar, class, class)
+              parseClassExtendsOpt(Bar)
+              parseWithClauseOpt(Bar)
+              parseClassOrMixinImplementsOpt(Bar)
+            skipUnexpectedTokenOpt(Bar, [extends, with, implements, {])
+            reportRecoverableError(extend, Message[ExpectedInstead, Expected 'extends' instead of this., null, {string: extends}])
+              listener: handleRecoverableError(Message[ExpectedInstead, Expected 'extends' instead of this., null, {string: extends}], extend, extend)
+            listener: handleIdentifier(A, typeReference)
+            listener: handleNoTypeArguments(,)
+            listener: handleType(A, null)
+            reportRecoverableError(,, MultipleExtends)
+              listener: handleRecoverableError(MultipleExtends, ,, ,)
+            listener: handleIdentifier(B, typeReference)
+            listener: handleNoTypeArguments({)
+            listener: handleType(B, null)
+            listener: handleClassExtends(extend, 2)
+            parseWithClauseOpt(B)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(B)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleRecoverClassHeader()
+          ensureBlock(B, null, class declaration)
+          parseClassOrMixinOrExtensionBody(B, DeclarationKind.Class, Bar)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, Bar)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, Bar)
+              parseMetadataStar({)
+                listener: beginMetadataStar(Bar)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              isReservedKeyword(()
+              parseMethod({, null, null, null, null, null, null, {, Instance of 'NoType', null, Bar, DeclarationKind.Class, Bar, false)
+                listener: beginMethod(null, null, null, null, null, Bar)
+                listener: handleNoType({)
+                ensureIdentifierPotentiallyRecovered({, methodDeclaration, false)
+                  listener: handleIdentifier(Bar, methodDeclaration)
+                parseQualifiedRestOpt(Bar, methodDeclarationContinuation)
+                parseMethodTypeVar(Bar)
+                  listener: handleNoTypeVariables(()
+                parseGetterOrFormalParameters(Bar, Bar, false, MemberKind.NonStaticMethod)
+                  parseFormalParameters(Bar, MemberKind.NonStaticMethod)
+                    parseFormalParametersRest((, MemberKind.NonStaticMethod)
+                      listener: beginFormalParameters((, MemberKind.NonStaticMethod)
+                      listener: endFormalParameters(0, (, ), MemberKind.NonStaticMethod)
+                parseInitializersOpt())
+                  listener: handleNoInitializers()
+                parseAsyncModifierOpt())
+                  listener: handleAsyncModifier(null, null)
+                  inPlainSync()
+                inPlainSync()
+                parseFunctionBody(), false, true)
+                  listener: beginBlockFunctionBody({)
+                  notEofOrValue(}, })
+                  listener: endBlockFunctionBody(0, {, })
+                listener: endClassConstructor(null, Bar, (, null, })
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration(class)
+  parseTopLevelDeclarationImpl(}, Instance of 'DirectiveContext')
+    parseMetadataStar(})
+      listener: beginMetadataStar(class)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(}, class, Instance of 'DirectiveContext')
+      parseClassDeclarationModifiers(}, class)
+      parseClassOrNamedMixinApplication(null, class)
+        listener: beginClassOrNamedMixinApplicationPrelude(class)
+        ensureIdentifier(class, classOrMixinDeclaration)
+          listener: handleIdentifier(Baz, classOrMixinDeclaration)
+        listener: handleNoTypeVariables(on)
+        listener: beginClassDeclaration(class, null, Baz)
+        parseClass(Baz, class, class, Baz)
+          parseClassHeaderOpt(Baz, class, class)
+            parseClassExtendsOpt(Baz)
+              listener: handleNoType(Baz)
+              listener: handleClassExtends(null, 1)
+            parseWithClauseOpt(Baz)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(Baz)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassHeaderRecovery(Baz, class, class)
+            parseClassHeaderOpt(Baz, class, class)
+              parseClassExtendsOpt(Baz)
+              parseWithClauseOpt(Baz)
+              parseClassOrMixinImplementsOpt(Baz)
+            skipUnexpectedTokenOpt(Baz, [extends, with, implements, {])
+            reportRecoverableError(on, Message[ExpectedInstead, Expected 'extends' instead of this., null, {string: extends}])
+              listener: handleRecoverableError(Message[ExpectedInstead, Expected 'extends' instead of this., null, {string: extends}], on, on)
+            listener: handleIdentifier(A, typeReference)
+            listener: handleNoTypeArguments(,)
+            listener: handleType(A, null)
+            reportRecoverableError(,, MultipleExtends)
+              listener: handleRecoverableError(MultipleExtends, ,, ,)
+            listener: handleIdentifier(B, typeReference)
+            listener: handleNoTypeArguments({)
+            listener: handleType(B, null)
+            listener: handleClassExtends(on, 2)
+            parseWithClauseOpt(B)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(B)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleRecoverClassHeader()
+          ensureBlock(B, null, class declaration)
+          parseClassOrMixinOrExtensionBody(B, DeclarationKind.Class, Baz)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, Baz)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, Baz)
+              parseMetadataStar({)
+                listener: beginMetadataStar(Baz)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              isReservedKeyword(()
+              parseMethod({, null, null, null, null, null, null, {, Instance of 'NoType', null, Baz, DeclarationKind.Class, Baz, false)
+                listener: beginMethod(null, null, null, null, null, Baz)
+                listener: handleNoType({)
+                ensureIdentifierPotentiallyRecovered({, methodDeclaration, false)
+                  listener: handleIdentifier(Baz, methodDeclaration)
+                parseQualifiedRestOpt(Baz, methodDeclarationContinuation)
+                parseMethodTypeVar(Baz)
+                  listener: handleNoTypeVariables(()
+                parseGetterOrFormalParameters(Baz, Baz, false, MemberKind.NonStaticMethod)
+                  parseFormalParameters(Baz, MemberKind.NonStaticMethod)
+                    parseFormalParametersRest((, MemberKind.NonStaticMethod)
+                      listener: beginFormalParameters((, MemberKind.NonStaticMethod)
+                      listener: endFormalParameters(0, (, ), MemberKind.NonStaticMethod)
+                parseInitializersOpt())
+                  listener: handleNoInitializers()
+                parseAsyncModifierOpt())
+                  listener: handleAsyncModifier(null, null)
+                  inPlainSync()
+                inPlainSync()
+                parseFunctionBody(), false, true)
+                  listener: beginBlockFunctionBody({)
+                  notEofOrValue(}, })
+                  listener: endBlockFunctionBody(0, {, })
+                listener: endClassConstructor(null, Baz, (, null, })
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(class)
+  listener: endCompilationUnit(5, )
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_22313.dart.parser.expect b/pkg/front_end/parser_testcases/error_recovery/issue_22313.dart.parser.expect
new file mode 100644
index 0000000..ebddffb
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_22313.dart.parser.expect
@@ -0,0 +1,33 @@
+class A { }
+
+class B { }
+
+class Foo extends A, B {
+Foo() { }
+}
+
+class Bar extend A, B {
+Bar() { }
+}
+
+class Baz on A, B {
+Baz() { }
+}
+
+
+class[KeywordToken] A[StringToken] {[BeginToken] }[SimpleToken]
+
+class[KeywordToken] B[StringToken] {[BeginToken] }[SimpleToken]
+
+class[KeywordToken] Foo[StringToken] extends[KeywordToken] A[StringToken],[SimpleToken] B[StringToken] {[BeginToken]
+Foo[StringToken]([BeginToken])[SimpleToken] {[BeginToken] }[SimpleToken]
+}[SimpleToken]
+
+class[KeywordToken] Bar[StringToken] extend[StringToken] A[StringToken],[SimpleToken] B[StringToken] {[BeginToken]
+Bar[StringToken]([BeginToken])[SimpleToken] {[BeginToken] }[SimpleToken]
+}[SimpleToken]
+
+class[KeywordToken] Baz[StringToken] on[KeywordToken] A[StringToken],[SimpleToken] B[StringToken] {[BeginToken]
+Baz[StringToken]([BeginToken])[SimpleToken] {[BeginToken] }[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_22313.dart.scanner.expect b/pkg/front_end/parser_testcases/error_recovery/issue_22313.dart.scanner.expect
new file mode 100644
index 0000000..ebddffb
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_22313.dart.scanner.expect
@@ -0,0 +1,33 @@
+class A { }
+
+class B { }
+
+class Foo extends A, B {
+Foo() { }
+}
+
+class Bar extend A, B {
+Bar() { }
+}
+
+class Baz on A, B {
+Baz() { }
+}
+
+
+class[KeywordToken] A[StringToken] {[BeginToken] }[SimpleToken]
+
+class[KeywordToken] B[StringToken] {[BeginToken] }[SimpleToken]
+
+class[KeywordToken] Foo[StringToken] extends[KeywordToken] A[StringToken],[SimpleToken] B[StringToken] {[BeginToken]
+Foo[StringToken]([BeginToken])[SimpleToken] {[BeginToken] }[SimpleToken]
+}[SimpleToken]
+
+class[KeywordToken] Bar[StringToken] extend[StringToken] A[StringToken],[SimpleToken] B[StringToken] {[BeginToken]
+Bar[StringToken]([BeginToken])[SimpleToken] {[BeginToken] }[SimpleToken]
+}[SimpleToken]
+
+class[KeywordToken] Baz[StringToken] on[KeywordToken] A[StringToken],[SimpleToken] B[StringToken] {[BeginToken]
+Baz[StringToken]([BeginToken])[SimpleToken] {[BeginToken] }[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_39026.crash_dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_39026.crash_dart.expect
index 0f4b8c9..2ae2a55 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_39026.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_39026.crash_dart.expect
@@ -16,7 +16,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, A)
       handleNoType(A)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_39026.crash_dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/issue_39026.crash_dart.intertwined.expect
index 740482c..6a32cbd 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_39026.crash_dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_39026.crash_dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(A, class, class)
             parseClassExtendsOpt(A)
               listener: handleNoType(A)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(A)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(A)
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_39026_prime.crash_dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_39026_prime.crash_dart.expect
index ada43dbc..36cbb74 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_39026_prime.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_39026_prime.crash_dart.expect
@@ -12,7 +12,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, A)
       handleNoType(A)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_39026_prime.crash_dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/issue_39026_prime.crash_dart.intertwined.expect
index cb81bba..cecf6e2 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_39026_prime.crash_dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_39026_prime.crash_dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(A, class, class)
             parseClassExtendsOpt(A)
               listener: handleNoType(A)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(A)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(A)
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_39230.crash_dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_39230.crash_dart.expect
index 1c9e85a..ee6d967 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_39230.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_39230.crash_dart.expect
@@ -24,7 +24,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, C)
       handleNoType(C)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_39230.crash_dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/issue_39230.crash_dart.intertwined.expect
index 3784f8cb..f3f8e88 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_39230.crash_dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_39230.crash_dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(C, class, class)
             parseClassExtendsOpt(C)
               listener: handleNoType(C)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(C)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(C)
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_41265.crash_dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_41265.crash_dart.expect
index 885081b..fe48acf 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_41265.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_41265.crash_dart.expect
@@ -20,7 +20,7 @@
     endTypeVariables(<, >)
     beginClassDeclaration(class, null, A)
       handleNoType(>)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
@@ -58,7 +58,7 @@
       handleIdentifier(Object, typeReference)
       handleNoTypeArguments(with)
       handleType(Object, null)
-      handleClassExtends(extends)
+      handleClassExtends(extends, 1)
       beginTypeList(M)
         beginFunctionType(M)
           handleNoTypeVariables(()
@@ -78,7 +78,7 @@
       handleClassHeader(class, class, null)
       handleRecoverableError(Message[UnexpectedToken, Unexpected token '>'., null, {token: >}], >, >)
       handleNoType(>)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleRecoverClassHeader()
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_41265.crash_dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/issue_41265.crash_dart.intertwined.expect
index bceda2e..ae6d79e 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_41265.crash_dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_41265.crash_dart.intertwined.expect
@@ -26,7 +26,7 @@
           parseClassHeaderOpt(>, class, class)
             parseClassExtendsOpt(>)
               listener: handleNoType(>)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(>)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(>)
@@ -88,7 +88,7 @@
               listener: handleIdentifier(Object, typeReference)
               listener: handleNoTypeArguments(with)
               listener: handleType(Object, null)
-              listener: handleClassExtends(extends)
+              listener: handleClassExtends(extends, 1)
             parseWithClauseOpt(Object)
               parseTypeList(with)
                 listener: beginTypeList(M)
@@ -126,7 +126,7 @@
                 listener: handleRecoverableError(Message[UnexpectedToken, Unexpected token '>'., null, {token: >}], >, >)
             parseClassExtendsOpt(>)
               listener: handleNoType(>)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(>)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(>)
diff --git a/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_fields.dart.expect b/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_fields.dart.expect
index c905844..29dba13 100644
--- a/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_fields.dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_fields.dart.expect
@@ -140,7 +140,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, WrapperClass)
       handleNoType(WrapperClass)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_fields.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_fields.dart.intertwined.expect
index 8235cd1..baabede 100644
--- a/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_fields.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_fields.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(WrapperClass, class, class)
             parseClassExtendsOpt(WrapperClass)
               listener: handleNoType(WrapperClass)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(WrapperClass)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(WrapperClass)
diff --git a/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_methods.dart.expect b/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_methods.dart.expect
index c19c42d..256ca6c 100644
--- a/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_methods.dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_methods.dart.expect
@@ -480,7 +480,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, WrapperClass)
       handleNoType(WrapperClass)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_methods.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_methods.dart.intertwined.expect
index 561f3c5..d61d8a2 100644
--- a/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_methods.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/keyword_named_class_methods.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(WrapperClass, class, class)
             parseClassExtendsOpt(WrapperClass)
               listener: handleNoType(WrapperClass)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(WrapperClass)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(WrapperClass)
diff --git a/pkg/front_end/parser_testcases/error_recovery/method_called_with.dart.expect b/pkg/front_end/parser_testcases/error_recovery/method_called_with.dart.expect
index 78a35b1..18cdecd 100644
--- a/pkg/front_end/parser_testcases/error_recovery/method_called_with.dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/method_called_with.dart.expect
@@ -32,7 +32,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, C)
       handleNoType(C)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/error_recovery/method_called_with.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/method_called_with.dart.intertwined.expect
index ac132e0..5086644 100644
--- a/pkg/front_end/parser_testcases/error_recovery/method_called_with.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/method_called_with.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(C, class, class)
             parseClassExtendsOpt(C)
               listener: handleNoType(C)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(C)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(C)
diff --git a/pkg/front_end/parser_testcases/error_recovery/method_called_with_prime.dart.expect b/pkg/front_end/parser_testcases/error_recovery/method_called_with_prime.dart.expect
index aba18fb..efaa895 100644
--- a/pkg/front_end/parser_testcases/error_recovery/method_called_with_prime.dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/method_called_with_prime.dart.expect
@@ -6,7 +6,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, C)
       handleNoType(C)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/error_recovery/method_called_with_prime.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/method_called_with_prime.dart.intertwined.expect
index 07e7ab5..cf0e350 100644
--- a/pkg/front_end/parser_testcases/error_recovery/method_called_with_prime.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/method_called_with_prime.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(C, class, class)
             parseClassExtendsOpt(C)
               listener: handleNoType(C)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(C)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(C)
diff --git a/pkg/front_end/parser_testcases/error_recovery/method_called_with_prime2.dart.expect b/pkg/front_end/parser_testcases/error_recovery/method_called_with_prime2.dart.expect
index 662eec3..b8be769 100644
--- a/pkg/front_end/parser_testcases/error_recovery/method_called_with_prime2.dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/method_called_with_prime2.dart.expect
@@ -28,7 +28,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, B)
       handleNoType(B)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
@@ -53,7 +53,7 @@
   handleNoTypeVariables({)
   beginClassDeclaration(class, null, M1)
     handleNoType(M1)
-    handleClassExtends(null)
+    handleClassExtends(null, 1)
     handleClassNoWithClause()
     handleClassOrMixinImplements(null, 0)
     handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/error_recovery/method_called_with_prime2.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/method_called_with_prime2.dart.intertwined.expect
index 1b4821c..d6a21e4 100644
--- a/pkg/front_end/parser_testcases/error_recovery/method_called_with_prime2.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/method_called_with_prime2.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(B, class, class)
             parseClassExtendsOpt(B)
               listener: handleNoType(B)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(B)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(B)
@@ -68,7 +68,7 @@
           parseClassHeaderOpt(M1, class, class)
             parseClassExtendsOpt(M1)
               listener: handleNoType(M1)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(M1)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(M1)
diff --git a/pkg/front_end/parser_testcases/extensions/covariant.dart.expect b/pkg/front_end/parser_testcases/extensions/covariant.dart.expect
index c797564..0b1d80d 100644
--- a/pkg/front_end/parser_testcases/extensions/covariant.dart.expect
+++ b/pkg/front_end/parser_testcases/extensions/covariant.dart.expect
@@ -12,7 +12,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, A)
       handleNoType(A)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
@@ -29,7 +29,7 @@
       handleIdentifier(A, typeReference)
       handleNoTypeArguments({)
       handleType(A, null)
-      handleClassExtends(extends)
+      handleClassExtends(extends, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/extensions/covariant.dart.intertwined.expect b/pkg/front_end/parser_testcases/extensions/covariant.dart.intertwined.expect
index a6bfc1c..2c95ee7 100644
--- a/pkg/front_end/parser_testcases/extensions/covariant.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/extensions/covariant.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(A, class, class)
             parseClassExtendsOpt(A)
               listener: handleNoType(A)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(A)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(A)
@@ -48,7 +48,7 @@
               listener: handleIdentifier(A, typeReference)
               listener: handleNoTypeArguments({)
               listener: handleType(A, null)
-              listener: handleClassExtends(extends)
+              listener: handleClassExtends(extends, 1)
             parseWithClauseOpt(A)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(A)
diff --git a/pkg/front_end/parser_testcases/extensions/not_covariant.dart.expect b/pkg/front_end/parser_testcases/extensions/not_covariant.dart.expect
index 53bb150..4bdbe33 100644
--- a/pkg/front_end/parser_testcases/extensions/not_covariant.dart.expect
+++ b/pkg/front_end/parser_testcases/extensions/not_covariant.dart.expect
@@ -6,7 +6,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, A)
       handleNoType(A)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
@@ -23,7 +23,7 @@
       handleIdentifier(A, typeReference)
       handleNoTypeArguments({)
       handleType(A, null)
-      handleClassExtends(extends)
+      handleClassExtends(extends, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/extensions/not_covariant.dart.intertwined.expect b/pkg/front_end/parser_testcases/extensions/not_covariant.dart.intertwined.expect
index 9bfe405..79a28b8 100644
--- a/pkg/front_end/parser_testcases/extensions/not_covariant.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/extensions/not_covariant.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(A, class, class)
             parseClassExtendsOpt(A)
               listener: handleNoType(A)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(A)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(A)
@@ -48,7 +48,7 @@
               listener: handleIdentifier(A, typeReference)
               listener: handleNoTypeArguments({)
               listener: handleType(A, null)
-              listener: handleClassExtends(extends)
+              listener: handleClassExtends(extends, 1)
             parseWithClauseOpt(A)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(A)
diff --git a/pkg/front_end/parser_testcases/extensions/static.dart.expect b/pkg/front_end/parser_testcases/extensions/static.dart.expect
index 2552e83..9579c65 100644
--- a/pkg/front_end/parser_testcases/extensions/static.dart.expect
+++ b/pkg/front_end/parser_testcases/extensions/static.dart.expect
@@ -6,7 +6,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, A)
       handleNoType(A)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
@@ -23,7 +23,7 @@
       handleIdentifier(A, typeReference)
       handleNoTypeArguments({)
       handleType(A, null)
-      handleClassExtends(extends)
+      handleClassExtends(extends, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/extensions/static.dart.intertwined.expect b/pkg/front_end/parser_testcases/extensions/static.dart.intertwined.expect
index cd427ab..6811d6a 100644
--- a/pkg/front_end/parser_testcases/extensions/static.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/extensions/static.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(A, class, class)
             parseClassExtendsOpt(A)
               listener: handleNoType(A)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(A)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(A)
@@ -48,7 +48,7 @@
               listener: handleIdentifier(A, typeReference)
               listener: handleNoTypeArguments({)
               listener: handleType(A, null)
-              listener: handleClassExtends(extends)
+              listener: handleClassExtends(extends, 1)
             parseWithClauseOpt(A)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(A)
diff --git a/pkg/front_end/parser_testcases/extensions/static_covariant.dart.expect b/pkg/front_end/parser_testcases/extensions/static_covariant.dart.expect
index 1468b4e..160198b 100644
--- a/pkg/front_end/parser_testcases/extensions/static_covariant.dart.expect
+++ b/pkg/front_end/parser_testcases/extensions/static_covariant.dart.expect
@@ -12,7 +12,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, A)
       handleNoType(A)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
@@ -29,7 +29,7 @@
       handleIdentifier(A, typeReference)
       handleNoTypeArguments({)
       handleType(A, null)
-      handleClassExtends(extends)
+      handleClassExtends(extends, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/extensions/static_covariant.dart.intertwined.expect b/pkg/front_end/parser_testcases/extensions/static_covariant.dart.intertwined.expect
index ff30f70..43700a3 100644
--- a/pkg/front_end/parser_testcases/extensions/static_covariant.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/extensions/static_covariant.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(A, class, class)
             parseClassExtendsOpt(A)
               listener: handleNoType(A)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(A)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(A)
@@ -48,7 +48,7 @@
               listener: handleIdentifier(A, typeReference)
               listener: handleNoTypeArguments({)
               listener: handleType(A, null)
-              listener: handleClassExtends(extends)
+              listener: handleClassExtends(extends, 1)
             parseWithClauseOpt(A)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(A)
diff --git a/pkg/front_end/parser_testcases/general/built_in_identifier_class_fields.dart.expect b/pkg/front_end/parser_testcases/general/built_in_identifier_class_fields.dart.expect
index 12a9f7e..b92e229 100644
--- a/pkg/front_end/parser_testcases/general/built_in_identifier_class_fields.dart.expect
+++ b/pkg/front_end/parser_testcases/general/built_in_identifier_class_fields.dart.expect
@@ -6,7 +6,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, WrapperClass)
       handleNoType(WrapperClass)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/general/built_in_identifier_class_fields.dart.intertwined.expect b/pkg/front_end/parser_testcases/general/built_in_identifier_class_fields.dart.intertwined.expect
index 5a37e7f..768939b 100644
--- a/pkg/front_end/parser_testcases/general/built_in_identifier_class_fields.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/general/built_in_identifier_class_fields.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(WrapperClass, class, class)
             parseClassExtendsOpt(WrapperClass)
               listener: handleNoType(WrapperClass)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(WrapperClass)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(WrapperClass)
diff --git a/pkg/front_end/parser_testcases/general/built_in_identifier_class_methods.dart.expect b/pkg/front_end/parser_testcases/general/built_in_identifier_class_methods.dart.expect
index 4e94eac..fcefd36 100644
--- a/pkg/front_end/parser_testcases/general/built_in_identifier_class_methods.dart.expect
+++ b/pkg/front_end/parser_testcases/general/built_in_identifier_class_methods.dart.expect
@@ -6,7 +6,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, WrapperClass)
       handleNoType(WrapperClass)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/general/built_in_identifier_class_methods.dart.intertwined.expect b/pkg/front_end/parser_testcases/general/built_in_identifier_class_methods.dart.intertwined.expect
index b7770f9..5c01063 100644
--- a/pkg/front_end/parser_testcases/general/built_in_identifier_class_methods.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/general/built_in_identifier_class_methods.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(WrapperClass, class, class)
             parseClassExtendsOpt(WrapperClass)
               listener: handleNoType(WrapperClass)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(WrapperClass)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(WrapperClass)
diff --git a/pkg/front_end/parser_testcases/general/issue_41121.dart.expect b/pkg/front_end/parser_testcases/general/issue_41121.dart.expect
index bda3eda..9c8e9bd 100644
--- a/pkg/front_end/parser_testcases/general/issue_41121.dart.expect
+++ b/pkg/front_end/parser_testcases/general/issue_41121.dart.expect
@@ -48,7 +48,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, ConfigurationService)
       handleNoType(ConfigurationService)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
@@ -276,7 +276,7 @@
   handleNoTypeVariables({)
   beginClassDeclaration(class, null, Configuration)
     handleNoType(Configuration)
-    handleClassExtends(null)
+    handleClassExtends(null, 1)
     handleClassNoWithClause()
     handleClassOrMixinImplements(null, 0)
     handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/general/issue_41121.dart.intertwined.expect b/pkg/front_end/parser_testcases/general/issue_41121.dart.intertwined.expect
index 3adc87e..2f233a3 100644
--- a/pkg/front_end/parser_testcases/general/issue_41121.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/general/issue_41121.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(ConfigurationService, class, class)
             parseClassExtendsOpt(ConfigurationService)
               listener: handleNoType(ConfigurationService)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(ConfigurationService)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(ConfigurationService)
@@ -509,7 +509,7 @@
           parseClassHeaderOpt(Configuration, class, class)
             parseClassExtendsOpt(Configuration)
               listener: handleNoType(Configuration)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Configuration)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Configuration)
diff --git a/pkg/front_end/parser_testcases/general/operator_hat_class.crash_dart.expect b/pkg/front_end/parser_testcases/general/operator_hat_class.crash_dart.expect
index 448f507..d5836cb 100644
--- a/pkg/front_end/parser_testcases/general/operator_hat_class.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/general/operator_hat_class.crash_dart.expect
@@ -13,7 +13,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, operator)
       handleNoType(operator)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/general/operator_hat_class.crash_dart.intertwined.expect b/pkg/front_end/parser_testcases/general/operator_hat_class.crash_dart.intertwined.expect
index beab6b7..5926593 100644
--- a/pkg/front_end/parser_testcases/general/operator_hat_class.crash_dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/general/operator_hat_class.crash_dart.intertwined.expect
@@ -20,7 +20,7 @@
           parseClassHeaderOpt(operator, class, class)
             parseClassExtendsOpt(operator)
               listener: handleNoType(operator)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(operator)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(operator)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39723.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_39723.dart.expect
index 27c1185..7296a62 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_39723.dart.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39723.dart.expect
@@ -6,7 +6,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, A)
       handleNoType(A)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39723.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_39723.dart.intertwined.expect
index 1b89b04..9d5ceaf 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_39723.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39723.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(A, class, class)
             parseClassExtendsOpt(A)
               listener: handleNoType(A)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(A)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(A)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39723_prime.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_39723_prime.dart.expect
index c08e774..6fd348f 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_39723_prime.dart.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39723_prime.dart.expect
@@ -6,7 +6,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, A)
       handleNoType(A)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39723_prime.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_39723_prime.dart.intertwined.expect
index 4ef31d6..39b35af 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_39723_prime.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39723_prime.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(A, class, class)
             parseClassExtendsOpt(A)
               listener: handleNoType(A)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(A)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(A)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.expect
index 20f0ebf..7679ad7 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.expect
@@ -32,7 +32,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, X)
       handleNoType(X)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.intertwined.expect
index 32130fd..e830646 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(X, class, class)
             parseClassExtendsOpt(X)
               listener: handleNoType(X)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(X)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(X)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.expect
index af2a1c3..69d129c 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.expect
@@ -6,7 +6,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, X)
       handleNoType(X)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.intertwined.expect
index 11a7f1d..45d8491 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(X, class, class)
             parseClassExtendsOpt(X)
               listener: handleNoType(X)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(X)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(X)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40805_01.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_40805_01.dart.expect
index 839d117..7c818a2 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40805_01.dart.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40805_01.dart.expect
@@ -6,7 +6,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, C)
       handleNoType(C)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40805_01.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_40805_01.dart.intertwined.expect
index c2748ff9..9c4a02e 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40805_01.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40805_01.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(C, class, class)
             parseClassExtendsOpt(C)
               listener: handleNoType(C)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(C)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(C)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40805_02.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_40805_02.dart.expect
index 15a8d14..f228d46 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40805_02.dart.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40805_02.dart.expect
@@ -12,7 +12,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, C)
       handleNoType(C)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40805_02.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_40805_02.dart.intertwined.expect
index f654dbd..4d308f2 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40805_02.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40805_02.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(C, class, class)
             parseClassExtendsOpt(C)
               listener: handleNoType(C)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(C)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(C)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40805_03.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_40805_03.dart.expect
index 5d46ab3..25f761d 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40805_03.dart.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40805_03.dart.expect
@@ -12,7 +12,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, C)
       handleNoType(C)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40805_03.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_40805_03.dart.intertwined.expect
index 97b6f75..dc89a35 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40805_03.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40805_03.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(C, class, class)
             parseClassExtendsOpt(C)
               listener: handleNoType(C)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(C)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(C)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40834_01.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_40834_01.dart.expect
index 8427048..1c8b158 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40834_01.dart.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40834_01.dart.expect
@@ -6,7 +6,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Foo)
       handleNoType(Foo)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40834_01.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_40834_01.dart.intertwined.expect
index 1dc1fd0..8c591ce 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40834_01.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40834_01.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(Foo, class, class)
             parseClassExtendsOpt(Foo)
               listener: handleNoType(Foo)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Foo)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Foo)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40834_02.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_40834_02.dart.expect
index 2302dd7..44a6b48 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40834_02.dart.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40834_02.dart.expect
@@ -6,7 +6,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Foo)
       handleNoType(Foo)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40834_02.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_40834_02.dart.intertwined.expect
index 8d144f8..5edc2bf 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40834_02.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40834_02.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(Foo, class, class)
             parseClassExtendsOpt(Foo)
               listener: handleNoType(Foo)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Foo)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Foo)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40834_03.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_40834_03.dart.expect
index 9aac61a..aa81a89 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40834_03.dart.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40834_03.dart.expect
@@ -6,7 +6,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Foo)
       handleNoType(Foo)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40834_03.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_40834_03.dart.intertwined.expect
index c80682c..4a96eb21 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40834_03.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40834_03.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(Foo, class, class)
             parseClassExtendsOpt(Foo)
               listener: handleNoType(Foo)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Foo)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Foo)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_41597.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_41597.dart.expect
index 9f7ec29..e2450db 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_41597.dart.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_41597.dart.expect
@@ -72,7 +72,7 @@
 handleNoTypeVariables({)
 beginClassDeclaration(class, null, C)
   handleNoType(C)
-  handleClassExtends(null)
+  handleClassExtends(null, 1)
   handleClassNoWithClause()
   handleClassOrMixinImplements(null, 0)
   handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_41597.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_41597.dart.intertwined.expect
index c37975a..bb28e5b 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_41597.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_41597.dart.intertwined.expect
@@ -190,7 +190,7 @@
           parseClassHeaderOpt(C, class, class)
             parseClassExtendsOpt(C)
               listener: handleNoType(C)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(C)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(C)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_42621.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_42621.dart.expect
index 533eec5..c9fe677 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_42621.dart.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_42621.dart.expect
@@ -310,7 +310,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Order)
       handleNoType(Order)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_42621.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_42621.dart.intertwined.expect
index 15743a9..c196fb5 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_42621.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_42621.dart.intertwined.expect
@@ -628,7 +628,7 @@
           parseClassHeaderOpt(Order, class, class)
             parseClassExtendsOpt(Order)
               listener: handleNoType(Order)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Order)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Order)
diff --git a/pkg/front_end/parser_testcases/nnbd/late_member.dart.expect b/pkg/front_end/parser_testcases/nnbd/late_member.dart.expect
index 1a7d7f8..a13f528 100644
--- a/pkg/front_end/parser_testcases/nnbd/late_member.dart.expect
+++ b/pkg/front_end/parser_testcases/nnbd/late_member.dart.expect
@@ -125,7 +125,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, X)
       handleNoType(X)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
@@ -163,7 +163,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Y)
       handleNoType(Y)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/nnbd/late_member.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/late_member.dart.intertwined.expect
index f6800aa..5eea6a8 100644
--- a/pkg/front_end/parser_testcases/nnbd/late_member.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/late_member.dart.intertwined.expect
@@ -327,7 +327,7 @@
           parseClassHeaderOpt(X, class, class)
             parseClassExtendsOpt(X)
               listener: handleNoType(X)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(X)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(X)
@@ -418,7 +418,7 @@
           parseClassHeaderOpt(Y, class, class)
             parseClassExtendsOpt(Y)
               listener: handleNoType(Y)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Y)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Y)
diff --git a/pkg/front_end/parser_testcases/nnbd/late_modifier.dart.expect b/pkg/front_end/parser_testcases/nnbd/late_modifier.dart.expect
index 50fcc6a..c8f987c 100644
--- a/pkg/front_end/parser_testcases/nnbd/late_modifier.dart.expect
+++ b/pkg/front_end/parser_testcases/nnbd/late_modifier.dart.expect
@@ -143,7 +143,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, X)
       handleNoType(X)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
@@ -181,7 +181,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Y)
       handleNoType(Y)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/nnbd/late_modifier.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/late_modifier.dart.intertwined.expect
index 275889e..8e0a141 100644
--- a/pkg/front_end/parser_testcases/nnbd/late_modifier.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/late_modifier.dart.intertwined.expect
@@ -375,7 +375,7 @@
           parseClassHeaderOpt(X, class, class)
             parseClassExtendsOpt(X)
               listener: handleNoType(X)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(X)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(X)
@@ -466,7 +466,7 @@
           parseClassHeaderOpt(Y, class, class)
             parseClassExtendsOpt(Y)
               listener: handleNoType(Y)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Y)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Y)
diff --git a/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.expect b/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.expect
index f9edc0e..939cdb7 100644
--- a/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.expect
+++ b/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.expect
@@ -6,7 +6,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Class1)
       handleNoType(Class1)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.intertwined.expect
index 39fda9b..89f7fa9 100644
--- a/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(Class1, class, class)
             parseClassExtendsOpt(Class1)
               listener: handleNoType(Class1)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Class1)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Class1)
diff --git a/pkg/front_end/parser_testcases/nnbd/required_member.dart.expect b/pkg/front_end/parser_testcases/nnbd/required_member.dart.expect
index aa7af99..2258220 100644
--- a/pkg/front_end/parser_testcases/nnbd/required_member.dart.expect
+++ b/pkg/front_end/parser_testcases/nnbd/required_member.dart.expect
@@ -125,7 +125,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, X)
       handleNoType(X)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
@@ -163,7 +163,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Y)
       handleNoType(Y)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/nnbd/required_member.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/required_member.dart.intertwined.expect
index 1cacfb4..d9fa92e 100644
--- a/pkg/front_end/parser_testcases/nnbd/required_member.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/required_member.dart.intertwined.expect
@@ -327,7 +327,7 @@
           parseClassHeaderOpt(X, class, class)
             parseClassExtendsOpt(X)
               listener: handleNoType(X)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(X)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(X)
@@ -418,7 +418,7 @@
           parseClassHeaderOpt(Y, class, class)
             parseClassExtendsOpt(Y)
               listener: handleNoType(Y)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Y)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Y)
diff --git a/pkg/front_end/parser_testcases/nnbd/required_modifier.dart.expect b/pkg/front_end/parser_testcases/nnbd/required_modifier.dart.expect
index ea95318..31a989f 100644
--- a/pkg/front_end/parser_testcases/nnbd/required_modifier.dart.expect
+++ b/pkg/front_end/parser_testcases/nnbd/required_modifier.dart.expect
@@ -136,7 +136,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, X)
       handleNoType(X)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
@@ -174,7 +174,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Y)
       handleNoType(Y)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/nnbd/required_modifier.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/required_modifier.dart.intertwined.expect
index 6d72b6d..3acf91c 100644
--- a/pkg/front_end/parser_testcases/nnbd/required_modifier.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/required_modifier.dart.intertwined.expect
@@ -343,7 +343,7 @@
           parseClassHeaderOpt(X, class, class)
             parseClassExtendsOpt(X)
               listener: handleNoType(X)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(X)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(X)
@@ -434,7 +434,7 @@
           parseClassHeaderOpt(Y, class, class)
             parseClassExtendsOpt(Y)
               listener: handleNoType(Y)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Y)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Y)
diff --git a/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.expect b/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.expect
index 80a4e35..da71b09 100644
--- a/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.expect
+++ b/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.expect
@@ -6,7 +6,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, late)
       handleNoType(late)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
@@ -37,7 +37,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, required)
       handleNoType(required)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
@@ -68,7 +68,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, C)
       handleNoType(C)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.intertwined.expect b/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.intertwined.expect
index 686b0f5..00d7363 100644
--- a/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(late, class, class)
             parseClassExtendsOpt(late)
               listener: handleNoType(late)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(late)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(late)
@@ -83,7 +83,7 @@
           parseClassHeaderOpt(required, class, class)
             parseClassExtendsOpt(required)
               listener: handleNoType(required)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(required)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(required)
@@ -148,7 +148,7 @@
           parseClassHeaderOpt(C, class, class)
             parseClassExtendsOpt(C)
               listener: handleNoType(C)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(C)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(C)
diff --git a/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.expect b/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.expect
index ea0ece2..6a706d5 100644
--- a/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.expect
+++ b/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.expect
@@ -6,7 +6,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Xlate)
       handleNoType(Xlate)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
@@ -37,7 +37,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, Xrequired)
       handleNoType(Xrequired)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
@@ -68,7 +68,7 @@
     handleNoTypeVariables({)
     beginClassDeclaration(class, null, C)
       handleNoType(C)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
diff --git a/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.intertwined.expect b/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.intertwined.expect
index 66943ef..b8149b9 100644
--- a/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.intertwined.expect
@@ -18,7 +18,7 @@
           parseClassHeaderOpt(Xlate, class, class)
             parseClassExtendsOpt(Xlate)
               listener: handleNoType(Xlate)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Xlate)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Xlate)
@@ -83,7 +83,7 @@
           parseClassHeaderOpt(Xrequired, class, class)
             parseClassExtendsOpt(Xrequired)
               listener: handleNoType(Xrequired)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(Xrequired)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(Xrequired)
@@ -148,7 +148,7 @@
           parseClassHeaderOpt(C, class, class)
             parseClassExtendsOpt(C)
               listener: handleNoType(C)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(C)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(C)
diff --git a/pkg/front_end/parser_testcases/non-nnbd/nullable_type_argument.dart.expect b/pkg/front_end/parser_testcases/non-nnbd/nullable_type_argument.dart.expect
index 3222c32..bc75d92 100644
--- a/pkg/front_end/parser_testcases/non-nnbd/nullable_type_argument.dart.expect
+++ b/pkg/front_end/parser_testcases/non-nnbd/nullable_type_argument.dart.expect
@@ -14,7 +14,7 @@
     endTypeVariables(<, >)
     beginClassDeclaration(class, null, A)
       handleNoType(>)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleClassOrMixinImplements(null, 0)
       handleClassHeader(class, class, null)
@@ -29,7 +29,7 @@
     handleNoTypeVariables(implements)
     beginClassDeclaration(class, null, B)
       handleNoType(B)
-      handleClassExtends(null)
+      handleClassExtends(null, 1)
       handleClassNoWithClause()
       handleIdentifier(A, typeReference)
       beginTypeArguments(<)
diff --git a/pkg/front_end/parser_testcases/non-nnbd/nullable_type_argument.dart.intertwined.expect b/pkg/front_end/parser_testcases/non-nnbd/nullable_type_argument.dart.intertwined.expect
index 85abfa4..9baf74c 100644
--- a/pkg/front_end/parser_testcases/non-nnbd/nullable_type_argument.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/non-nnbd/nullable_type_argument.dart.intertwined.expect
@@ -26,7 +26,7 @@
           parseClassHeaderOpt(>, class, class)
             parseClassExtendsOpt(>)
               listener: handleNoType(>)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(>)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(>)
@@ -54,7 +54,7 @@
           parseClassHeaderOpt(B, class, class)
             parseClassExtendsOpt(B)
               listener: handleNoType(B)
-              listener: handleClassExtends(null)
+              listener: handleClassExtends(null, 1)
             parseWithClauseOpt(B)
               listener: handleClassNoWithClause()
             parseClassOrMixinImplementsOpt(B)
diff --git a/pkg/front_end/test/fasta/textual_outline_suite.dart b/pkg/front_end/test/fasta/textual_outline_suite.dart
index fa98bdb..f13c047 100644
--- a/pkg/front_end/test/fasta/textual_outline_suite.dart
+++ b/pkg/front_end/test/fasta/textual_outline_suite.dart
@@ -88,7 +88,7 @@
       result = sb.toString().trim();
 
       // Try to format.
-      Exception formatterException;
+      dynamic formatterException;
       StackTrace formatterExceptionSt;
       try {
         result = new DartFormatter().format(result);
diff --git a/pkg/front_end/test/parser_test_listener.dart b/pkg/front_end/test/parser_test_listener.dart
index f49b00a..cfccc6a 100644
--- a/pkg/front_end/test/parser_test_listener.dart
+++ b/pkg/front_end/test/parser_test_listener.dart
@@ -192,9 +192,9 @@
     indent++;
   }
 
-  void handleClassExtends(Token extendsKeyword) {
+  void handleClassExtends(Token extendsKeyword, int typeCount) {
     seen(extendsKeyword);
-    doPrint('handleClassExtends(' '$extendsKeyword)');
+    doPrint('handleClassExtends(' '$extendsKeyword, ' '$typeCount)');
   }
 
   void handleClassOrMixinImplements(
diff --git a/pkg/front_end/testcases/general/error_recovery/issue_22313.dart b/pkg/front_end/testcases/general/error_recovery/issue_22313.dart
new file mode 100644
index 0000000..c1b9282
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_recovery/issue_22313.dart
@@ -0,0 +1,17 @@
+class A { }
+
+class B { }
+
+class Foo extends A, B {
+  Foo() { }
+}
+
+class Bar extend A, B {
+  Bar() { }
+}
+
+class Baz on A, B {
+  Baz() { }
+}
+
+main() {}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/general/error_recovery/issue_22313.dart.outline.expect b/pkg/front_end/testcases/general/error_recovery/issue_22313.dart.outline.expect
new file mode 100644
index 0000000..531e339
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_recovery/issue_22313.dart.outline.expect
@@ -0,0 +1,92 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/error_recovery/issue_22313.dart:5:20: Error: Each class definition can have at most one extends clause.
+// Try choosing one superclass and define your class to implement (or mix in) the others.
+// class Foo extends A, B {
+//                    ^
+//
+// pkg/front_end/testcases/general/error_recovery/issue_22313.dart:9:11: Error: Expected 'extends' instead of this.
+// class Bar extend A, B {
+//           ^^^^^^
+//
+// pkg/front_end/testcases/general/error_recovery/issue_22313.dart:9:19: Error: Each class definition can have at most one extends clause.
+// Try choosing one superclass and define your class to implement (or mix in) the others.
+// class Bar extend A, B {
+//                   ^
+//
+// pkg/front_end/testcases/general/error_recovery/issue_22313.dart:13:11: Error: Expected 'extends' instead of this.
+// class Baz on A, B {
+//           ^^
+//
+// pkg/front_end/testcases/general/error_recovery/issue_22313.dart:13:15: Error: Each class definition can have at most one extends clause.
+// Try choosing one superclass and define your class to implement (or mix in) the others.
+// class Baz on A, B {
+//               ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    ;
+  abstract member-signature get _identityHashCode() → core::int*;
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
+  abstract member-signature operator ==(dynamic other) → core::bool*;
+  abstract member-signature get hashCode() → core::int*;
+  abstract member-signature method toString() → core::String*;
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
+  abstract member-signature get runtimeType() → core::Type*;
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B*
+    ;
+  abstract member-signature get _identityHashCode() → core::int*;
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
+  abstract member-signature operator ==(dynamic other) → core::bool*;
+  abstract member-signature get hashCode() → core::int*;
+  abstract member-signature method toString() → core::String*;
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
+  abstract member-signature get runtimeType() → core::Type*;
+}
+class Foo extends self::A {
+  constructor •() → self::Foo*
+    ;
+}
+class Bar extends core::Object {
+  constructor •() → self::Bar*
+    ;
+  abstract member-signature get _identityHashCode() → core::int*;
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
+  abstract member-signature operator ==(dynamic other) → core::bool*;
+  abstract member-signature get hashCode() → core::int*;
+  abstract member-signature method toString() → core::String*;
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
+  abstract member-signature get runtimeType() → core::Type*;
+}
+class Baz extends core::Object {
+  constructor •() → self::Baz*
+    ;
+  abstract member-signature get _identityHashCode() → core::int*;
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
+  abstract member-signature operator ==(dynamic other) → core::bool*;
+  abstract member-signature get hashCode() → core::int*;
+  abstract member-signature method toString() → core::String*;
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
+  abstract member-signature get runtimeType() → core::Type*;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/error_recovery/issue_22313.dart.strong.expect b/pkg/front_end/testcases/general/error_recovery/issue_22313.dart.strong.expect
new file mode 100644
index 0000000..f1f9cb0
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_recovery/issue_22313.dart.strong.expect
@@ -0,0 +1,93 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/error_recovery/issue_22313.dart:5:20: Error: Each class definition can have at most one extends clause.
+// Try choosing one superclass and define your class to implement (or mix in) the others.
+// class Foo extends A, B {
+//                    ^
+//
+// pkg/front_end/testcases/general/error_recovery/issue_22313.dart:9:11: Error: Expected 'extends' instead of this.
+// class Bar extend A, B {
+//           ^^^^^^
+//
+// pkg/front_end/testcases/general/error_recovery/issue_22313.dart:9:19: Error: Each class definition can have at most one extends clause.
+// Try choosing one superclass and define your class to implement (or mix in) the others.
+// class Bar extend A, B {
+//                   ^
+//
+// pkg/front_end/testcases/general/error_recovery/issue_22313.dart:13:11: Error: Expected 'extends' instead of this.
+// class Baz on A, B {
+//           ^^
+//
+// pkg/front_end/testcases/general/error_recovery/issue_22313.dart:13:15: Error: Each class definition can have at most one extends clause.
+// Try choosing one superclass and define your class to implement (or mix in) the others.
+// class Baz on A, B {
+//               ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+  abstract member-signature get _identityHashCode() → core::int*;
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
+  abstract member-signature operator ==(dynamic other) → core::bool*;
+  abstract member-signature get hashCode() → core::int*;
+  abstract member-signature method toString() → core::String*;
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
+  abstract member-signature get runtimeType() → core::Type*;
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B*
+    : super core::Object::•()
+    ;
+  abstract member-signature get _identityHashCode() → core::int*;
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
+  abstract member-signature operator ==(dynamic other) → core::bool*;
+  abstract member-signature get hashCode() → core::int*;
+  abstract member-signature method toString() → core::String*;
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
+  abstract member-signature get runtimeType() → core::Type*;
+}
+class Foo extends self::A {
+  constructor •() → self::Foo*
+    : super self::A::•() {}
+}
+class Bar extends core::Object {
+  constructor •() → self::Bar*
+    : super core::Object::•() {}
+  abstract member-signature get _identityHashCode() → core::int*;
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
+  abstract member-signature operator ==(dynamic other) → core::bool*;
+  abstract member-signature get hashCode() → core::int*;
+  abstract member-signature method toString() → core::String*;
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
+  abstract member-signature get runtimeType() → core::Type*;
+}
+class Baz extends core::Object {
+  constructor •() → self::Baz*
+    : super core::Object::•() {}
+  abstract member-signature get _identityHashCode() → core::int*;
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
+  abstract member-signature operator ==(dynamic other) → core::bool*;
+  abstract member-signature get hashCode() → core::int*;
+  abstract member-signature method toString() → core::String*;
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
+  abstract member-signature get runtimeType() → core::Type*;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/error_recovery/issue_22313.dart.strong.transformed.expect b/pkg/front_end/testcases/general/error_recovery/issue_22313.dart.strong.transformed.expect
new file mode 100644
index 0000000..f1f9cb0
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_recovery/issue_22313.dart.strong.transformed.expect
@@ -0,0 +1,93 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/error_recovery/issue_22313.dart:5:20: Error: Each class definition can have at most one extends clause.
+// Try choosing one superclass and define your class to implement (or mix in) the others.
+// class Foo extends A, B {
+//                    ^
+//
+// pkg/front_end/testcases/general/error_recovery/issue_22313.dart:9:11: Error: Expected 'extends' instead of this.
+// class Bar extend A, B {
+//           ^^^^^^
+//
+// pkg/front_end/testcases/general/error_recovery/issue_22313.dart:9:19: Error: Each class definition can have at most one extends clause.
+// Try choosing one superclass and define your class to implement (or mix in) the others.
+// class Bar extend A, B {
+//                   ^
+//
+// pkg/front_end/testcases/general/error_recovery/issue_22313.dart:13:11: Error: Expected 'extends' instead of this.
+// class Baz on A, B {
+//           ^^
+//
+// pkg/front_end/testcases/general/error_recovery/issue_22313.dart:13:15: Error: Each class definition can have at most one extends clause.
+// Try choosing one superclass and define your class to implement (or mix in) the others.
+// class Baz on A, B {
+//               ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+  abstract member-signature get _identityHashCode() → core::int*;
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
+  abstract member-signature operator ==(dynamic other) → core::bool*;
+  abstract member-signature get hashCode() → core::int*;
+  abstract member-signature method toString() → core::String*;
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
+  abstract member-signature get runtimeType() → core::Type*;
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B*
+    : super core::Object::•()
+    ;
+  abstract member-signature get _identityHashCode() → core::int*;
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
+  abstract member-signature operator ==(dynamic other) → core::bool*;
+  abstract member-signature get hashCode() → core::int*;
+  abstract member-signature method toString() → core::String*;
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
+  abstract member-signature get runtimeType() → core::Type*;
+}
+class Foo extends self::A {
+  constructor •() → self::Foo*
+    : super self::A::•() {}
+}
+class Bar extends core::Object {
+  constructor •() → self::Bar*
+    : super core::Object::•() {}
+  abstract member-signature get _identityHashCode() → core::int*;
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
+  abstract member-signature operator ==(dynamic other) → core::bool*;
+  abstract member-signature get hashCode() → core::int*;
+  abstract member-signature method toString() → core::String*;
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
+  abstract member-signature get runtimeType() → core::Type*;
+}
+class Baz extends core::Object {
+  constructor •() → self::Baz*
+    : super core::Object::•() {}
+  abstract member-signature get _identityHashCode() → core::int*;
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
+  abstract member-signature operator ==(dynamic other) → core::bool*;
+  abstract member-signature get hashCode() → core::int*;
+  abstract member-signature method toString() → core::String*;
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
+  abstract member-signature get runtimeType() → core::Type*;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/error_recovery/issue_22313.dart.textual_outline.expect b/pkg/front_end/testcases/general/error_recovery/issue_22313.dart.textual_outline.expect
new file mode 100644
index 0000000..f3f3b60
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_recovery/issue_22313.dart.textual_outline.expect
@@ -0,0 +1,14 @@
+class A {
+}
+class B {
+}
+class Foo extends A, B {
+  Foo() { }
+}
+class Bar extend A, B {
+  Bar() { }
+}
+class Baz on A, B {
+  Baz() { }
+}
+main() { }
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index f05e3ba..6603dc9 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -109,6 +109,7 @@
 general/error_recovery/constructor_recovery_operator.crash: FormatterCrash
 general/error_recovery/constructor_recovery_return_type: FormatterCrash
 general/error_recovery/constructor_recovery_set: FormatterCrash
+general/error_recovery/issue_22313: FormatterCrash
 general/error_recovery/issue_39033.crash: FormatterCrash
 general/error_recovery/issue_39058_prime.crash: FormatterCrash
 general/error_recovery/issue_39202.crash: FormatterCrash