[parser] Give errors when 'abstract' comes in wrong order

Fixes https://github.com/dart-lang/sdk/issues/43855
Fixes https://github.com/dart-lang/sdk/issues/43856
Fixes https://github.com/dart-lang/sdk/issues/43857

Change-Id: I83ee716288741d2d84a1993e9743ad4b82af22ba
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/168646
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Jens Johansen <jensj@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/modifier_context.dart b/pkg/_fe_analyzer_shared/lib/src/parser/modifier_context.dart
index 904871b..fbd360f 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/modifier_context.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/modifier_context.dart
@@ -220,6 +220,12 @@
     assert(optional('abstract', next));
     if (abstractToken == null) {
       abstractToken = next;
+
+      if (varFinalOrConst != null) {
+        reportModifierOutOfOrder(next, varFinalOrConst.lexeme);
+      } else if (covariantToken != null) {
+        reportModifierOutOfOrder(next, covariantToken.lexeme);
+      }
       return next;
     }
 
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 30cf0bb..555f531 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -281,6 +281,8 @@
 ExtraneousModifier/part_wrapped_script3: Fail
 ExtraneousModifier/part_wrapped_script4: Fail
 ExtraneousModifier/part_wrapped_script5: Fail
+ExtraneousModifier/part_wrapped_script6: Fail # Fails because two errors are given. Only one should be given though.
+ExtraneousModifier/script6: Fail # Fails because two errors are given. Only one should be given though.
 ExtraneousModifier/part_wrapped_script7: Fail
 ExtraneousModifier/part_wrapped_script8: Fail
 ExtraneousModifier/part_wrapped_script9: Fail
diff --git a/pkg/front_end/parser_testcases/nnbd/error_recovery/abstract_placement.dart b/pkg/front_end/parser_testcases/nnbd/error_recovery/abstract_placement.dart
new file mode 100644
index 0000000..03e4492
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/error_recovery/abstract_placement.dart
@@ -0,0 +1,21 @@
+// https://github.com/dart-lang/sdk/issues/43855
+// https://github.com/dart-lang/sdk/issues/43856
+// https://github.com/dart-lang/sdk/issues/43857
+
+abstract class C {
+  final abstract int i1;
+  final abstract i2;
+  covariant abstract num i3;
+  covariant abstract var i4;
+  final abstract i5;
+  var abstract i6;
+  C abstract i7;
+}
+
+// This currently give 2 errors which is hardly ideal.
+var abstract foo;
+
+abstract class Bar {
+  // This currently give 2 errors which is hardly ideal.
+  covariant required x;
+}
\ No newline at end of file
diff --git a/pkg/front_end/parser_testcases/nnbd/error_recovery/abstract_placement.dart.expect b/pkg/front_end/parser_testcases/nnbd/error_recovery/abstract_placement.dart.expect
new file mode 100644
index 0000000..12e6b31
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/error_recovery/abstract_placement.dart.expect
@@ -0,0 +1,195 @@
+Problems reported:
+
+parser/nnbd/error_recovery/abstract_placement:6:9: The modifier 'abstract' should be before the modifier 'final'.
+  final abstract int i1;
+        ^^^^^^^^
+
+parser/nnbd/error_recovery/abstract_placement:7:9: The modifier 'abstract' should be before the modifier 'final'.
+  final abstract i2;
+        ^^^^^^^^
+
+parser/nnbd/error_recovery/abstract_placement:8:13: The modifier 'abstract' should be before the modifier 'covariant'.
+  covariant abstract num i3;
+            ^^^^^^^^
+
+parser/nnbd/error_recovery/abstract_placement:9:13: The modifier 'abstract' should be before the modifier 'covariant'.
+  covariant abstract var i4;
+            ^^^^^^^^
+
+parser/nnbd/error_recovery/abstract_placement:10:9: The modifier 'abstract' should be before the modifier 'final'.
+  final abstract i5;
+        ^^^^^^^^
+
+parser/nnbd/error_recovery/abstract_placement:11:7: The modifier 'abstract' should be before the modifier 'var'.
+  var abstract i6;
+      ^^^^^^^^
+
+parser/nnbd/error_recovery/abstract_placement:12:5: Expected ';' after this.
+  C abstract i7;
+    ^^^^^^^^
+
+parser/nnbd/error_recovery/abstract_placement:12:14: Variables must be declared using the keywords 'const', 'final', 'var' or a type name.
+  C abstract i7;
+             ^^
+
+parser/nnbd/error_recovery/abstract_placement:16:5: The modifier 'abstract' should be before the modifier 'var'.
+var abstract foo;
+    ^^^^^^^^
+
+parser/nnbd/error_recovery/abstract_placement:16:5: Can't have modifier 'abstract' here.
+var abstract foo;
+    ^^^^^^^^
+
+parser/nnbd/error_recovery/abstract_placement:20:13: The modifier 'required' should be before the modifier 'covariant'.
+  covariant required x;
+            ^^^^^^^^
+
+parser/nnbd/error_recovery/abstract_placement:20:13: Can't have modifier 'required' here.
+  covariant required x;
+            ^^^^^^^^
+
+parser/nnbd/error_recovery/abstract_placement:20:22: Variables must be declared using the keywords 'const', 'final', 'var' or a type name.
+  covariant required x;
+                     ^
+
+beginCompilationUnit(abstract)
+  beginMetadataStar(abstract)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(abstract)
+    handleIdentifier(C, classOrMixinDeclaration)
+    handleNoTypeVariables({)
+    beginClassDeclaration(abstract, abstract, C)
+      handleNoType(C)
+      handleClassExtends(null, 1)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(abstract, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+        beginMetadataStar(final)
+        endMetadataStar(0)
+        handleRecoverableError(Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'final'., Try re-ordering the modifiers., {string: abstract, string2: final}], abstract, abstract)
+        beginMember()
+          beginFields({)
+            handleIdentifier(int, typeReference)
+            handleNoTypeArguments(i1)
+            handleType(int, null)
+            handleIdentifier(i1, fieldDeclaration)
+            handleNoFieldInitializer(;)
+          endClassFields(abstract, null, null, null, null, final, 1, final, ;)
+        endMember()
+        beginMetadataStar(final)
+        endMetadataStar(0)
+        handleRecoverableError(Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'final'., Try re-ordering the modifiers., {string: abstract, string2: final}], abstract, abstract)
+        beginMember()
+          beginFields(;)
+            handleNoType(abstract)
+            handleIdentifier(i2, fieldDeclaration)
+            handleNoFieldInitializer(;)
+          endClassFields(abstract, null, null, null, null, final, 1, final, ;)
+        endMember()
+        beginMetadataStar(covariant)
+        endMetadataStar(0)
+        handleRecoverableError(Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'covariant'., Try re-ordering the modifiers., {string: abstract, string2: covariant}], abstract, abstract)
+        beginMember()
+          beginFields(;)
+            handleIdentifier(num, typeReference)
+            handleNoTypeArguments(i3)
+            handleType(num, null)
+            handleIdentifier(i3, fieldDeclaration)
+            handleNoFieldInitializer(;)
+          endClassFields(abstract, null, null, covariant, null, null, 1, covariant, ;)
+        endMember()
+        beginMetadataStar(covariant)
+        endMetadataStar(0)
+        handleRecoverableError(Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'covariant'., Try re-ordering the modifiers., {string: abstract, string2: covariant}], abstract, abstract)
+        beginMember()
+          beginFields(;)
+            handleNoType(var)
+            handleIdentifier(i4, fieldDeclaration)
+            handleNoFieldInitializer(;)
+          endClassFields(abstract, null, null, covariant, null, var, 1, covariant, ;)
+        endMember()
+        beginMetadataStar(final)
+        endMetadataStar(0)
+        handleRecoverableError(Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'final'., Try re-ordering the modifiers., {string: abstract, string2: final}], abstract, abstract)
+        beginMember()
+          beginFields(;)
+            handleNoType(abstract)
+            handleIdentifier(i5, fieldDeclaration)
+            handleNoFieldInitializer(;)
+          endClassFields(abstract, null, null, null, null, final, 1, final, ;)
+        endMember()
+        beginMetadataStar(var)
+        endMetadataStar(0)
+        handleRecoverableError(Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'var'., Try re-ordering the modifiers., {string: abstract, string2: var}], abstract, abstract)
+        beginMember()
+          beginFields(;)
+            handleNoType(abstract)
+            handleIdentifier(i6, fieldDeclaration)
+            handleNoFieldInitializer(;)
+          endClassFields(abstract, null, null, null, null, var, 1, var, ;)
+        endMember()
+        beginMetadataStar(C)
+        endMetadataStar(0)
+        beginMember()
+          beginFields(;)
+            handleIdentifier(C, typeReference)
+            handleNoTypeArguments(abstract)
+            handleType(C, null)
+            handleIdentifier(abstract, fieldDeclaration)
+            handleNoFieldInitializer(i7)
+            handleRecoverableError(Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}], abstract, abstract)
+          endClassFields(null, null, null, null, null, null, 1, C, ;)
+        endMember()
+        beginMetadataStar(i7)
+        endMetadataStar(0)
+        beginMember()
+          beginFields(;)
+            handleRecoverableError(MissingConstFinalVarOrType, i7, i7)
+            handleNoType(;)
+            handleIdentifier(i7, fieldDeclaration)
+            handleNoFieldInitializer(;)
+          endClassFields(null, null, null, null, null, null, 1, i7, ;)
+        endMember()
+      endClassOrMixinBody(DeclarationKind.Class, 8, {, })
+    endClassDeclaration(abstract, })
+  endTopLevelDeclaration(var)
+  beginMetadataStar(var)
+  endMetadataStar(0)
+  beginTopLevelMember(var)
+    handleRecoverableError(Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'var'., Try re-ordering the modifiers., {string: abstract, string2: var}], abstract, abstract)
+    handleRecoverableError(Message[ExtraneousModifier, Can't have modifier 'abstract' here., Try removing 'abstract'., {token: abstract}], abstract, abstract)
+    beginFields(})
+      handleNoType(abstract)
+      handleIdentifier(foo, topLevelVariableDeclaration)
+      handleNoFieldInitializer(;)
+    endTopLevelFields(null, null, null, null, var, 1, var, ;)
+  endTopLevelDeclaration(abstract)
+  beginMetadataStar(abstract)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(abstract)
+    handleIdentifier(Bar, classOrMixinDeclaration)
+    handleNoTypeVariables({)
+    beginClassDeclaration(abstract, abstract, Bar)
+      handleNoType(Bar)
+      handleClassExtends(null, 1)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(abstract, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+        beginMetadataStar(covariant)
+        endMetadataStar(0)
+        handleRecoverableError(Message[ModifierOutOfOrder, The modifier 'required' should be before the modifier 'covariant'., Try re-ordering the modifiers., {string: required, string2: covariant}], required, required)
+        handleRecoverableError(Message[ExtraneousModifier, Can't have modifier 'required' here., Try removing 'required'., {token: required}], required, required)
+        beginMember()
+          beginFields({)
+            handleRecoverableError(MissingConstFinalVarOrType, x, x)
+            handleNoType(required)
+            handleIdentifier(x, fieldDeclaration)
+            handleNoFieldInitializer(;)
+          endClassFields(null, null, null, covariant, null, null, 1, covariant, ;)
+        endMember()
+      endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+    endClassDeclaration(abstract, })
+  endTopLevelDeclaration()
+endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/nnbd/error_recovery/abstract_placement.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/error_recovery/abstract_placement.dart.intertwined.expect
new file mode 100644
index 0000000..0ce64ff
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/error_recovery/abstract_placement.dart.intertwined.expect
@@ -0,0 +1,250 @@
+parseUnit(abstract)
+  skipErrorTokens(abstract)
+  listener: beginCompilationUnit(abstract)
+  syntheticPreviousToken(abstract)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(abstract)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(, class, Instance of 'DirectiveContext')
+      parseClassDeclarationModifiers(, class)
+        parseTopLevelKeywordModifiers(abstract, class)
+      parseClassOrNamedMixinApplication(abstract, class)
+        listener: beginClassOrNamedMixinApplicationPrelude(abstract)
+        ensureIdentifier(class, classOrMixinDeclaration)
+          listener: handleIdentifier(C, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(abstract, abstract, C)
+        parseClass(C, abstract, class, C)
+          parseClassHeaderOpt(C, abstract, class)
+            parseClassExtendsOpt(C)
+              listener: handleNoType(C)
+              listener: handleClassExtends(null, 1)
+            parseWithClauseOpt(C)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(C)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(abstract, class, null)
+          parseClassOrMixinOrExtensionBody(C, DeclarationKind.Class, C)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, final)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, C)
+              parseMetadataStar({)
+                listener: beginMetadataStar(final)
+                listener: endMetadataStar(0)
+              reportRecoverableError(abstract, Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'final'., Try re-ordering the modifiers., {string: abstract, string2: final}])
+                listener: handleRecoverableError(Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'final'., Try re-ordering the modifiers., {string: abstract, string2: final}], abstract, abstract)
+              listener: beginMember()
+              parseFields({, abstract, null, null, null, null, final, abstract, Instance of 'SimpleType', i1, DeclarationKind.Class, C, false)
+                listener: beginFields({)
+                listener: handleIdentifier(int, typeReference)
+                listener: handleNoTypeArguments(i1)
+                listener: handleType(int, null)
+                ensureIdentifierPotentiallyRecovered(int, fieldDeclaration, false)
+                  listener: handleIdentifier(i1, fieldDeclaration)
+                parseFieldInitializerOpt(i1, i1, null, abstract, null, final, DeclarationKind.Class, C)
+                  listener: handleNoFieldInitializer(;)
+                listener: endClassFields(abstract, null, null, null, null, final, 1, final, ;)
+              listener: endMember()
+            notEofOrValue(}, final)
+            parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, C)
+              parseMetadataStar(;)
+                listener: beginMetadataStar(final)
+                listener: endMetadataStar(0)
+              reportRecoverableError(abstract, Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'final'., Try re-ordering the modifiers., {string: abstract, string2: final}])
+                listener: handleRecoverableError(Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'final'., Try re-ordering the modifiers., {string: abstract, string2: final}], abstract, abstract)
+              listener: beginMember()
+              parseFields(;, abstract, null, null, null, null, final, abstract, Instance of 'NoType', i2, DeclarationKind.Class, C, false)
+                listener: beginFields(;)
+                listener: handleNoType(abstract)
+                ensureIdentifierPotentiallyRecovered(abstract, fieldDeclaration, false)
+                  listener: handleIdentifier(i2, fieldDeclaration)
+                parseFieldInitializerOpt(i2, i2, null, abstract, null, final, DeclarationKind.Class, C)
+                  listener: handleNoFieldInitializer(;)
+                listener: endClassFields(abstract, null, null, null, null, final, 1, final, ;)
+              listener: endMember()
+            notEofOrValue(}, covariant)
+            parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, C)
+              parseMetadataStar(;)
+                listener: beginMetadataStar(covariant)
+                listener: endMetadataStar(0)
+              reportRecoverableError(abstract, Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'covariant'., Try re-ordering the modifiers., {string: abstract, string2: covariant}])
+                listener: handleRecoverableError(Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'covariant'., Try re-ordering the modifiers., {string: abstract, string2: covariant}], abstract, abstract)
+              listener: beginMember()
+              parseFields(;, abstract, null, null, covariant, null, null, abstract, Instance of 'SimpleType', i3, DeclarationKind.Class, C, false)
+                listener: beginFields(;)
+                listener: handleIdentifier(num, typeReference)
+                listener: handleNoTypeArguments(i3)
+                listener: handleType(num, null)
+                ensureIdentifierPotentiallyRecovered(num, fieldDeclaration, false)
+                  listener: handleIdentifier(i3, fieldDeclaration)
+                parseFieldInitializerOpt(i3, i3, null, abstract, null, null, DeclarationKind.Class, C)
+                  listener: handleNoFieldInitializer(;)
+                listener: endClassFields(abstract, null, null, covariant, null, null, 1, covariant, ;)
+              listener: endMember()
+            notEofOrValue(}, covariant)
+            parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, C)
+              parseMetadataStar(;)
+                listener: beginMetadataStar(covariant)
+                listener: endMetadataStar(0)
+              reportRecoverableError(abstract, Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'covariant'., Try re-ordering the modifiers., {string: abstract, string2: covariant}])
+                listener: handleRecoverableError(Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'covariant'., Try re-ordering the modifiers., {string: abstract, string2: covariant}], abstract, abstract)
+              listener: beginMember()
+              parseFields(;, abstract, null, null, covariant, null, var, var, Instance of 'NoType', i4, DeclarationKind.Class, C, false)
+                listener: beginFields(;)
+                listener: handleNoType(var)
+                ensureIdentifierPotentiallyRecovered(var, fieldDeclaration, false)
+                  listener: handleIdentifier(i4, fieldDeclaration)
+                parseFieldInitializerOpt(i4, i4, null, abstract, null, var, DeclarationKind.Class, C)
+                  listener: handleNoFieldInitializer(;)
+                listener: endClassFields(abstract, null, null, covariant, null, var, 1, covariant, ;)
+              listener: endMember()
+            notEofOrValue(}, final)
+            parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, C)
+              parseMetadataStar(;)
+                listener: beginMetadataStar(final)
+                listener: endMetadataStar(0)
+              reportRecoverableError(abstract, Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'final'., Try re-ordering the modifiers., {string: abstract, string2: final}])
+                listener: handleRecoverableError(Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'final'., Try re-ordering the modifiers., {string: abstract, string2: final}], abstract, abstract)
+              listener: beginMember()
+              parseFields(;, abstract, null, null, null, null, final, abstract, Instance of 'NoType', i5, DeclarationKind.Class, C, false)
+                listener: beginFields(;)
+                listener: handleNoType(abstract)
+                ensureIdentifierPotentiallyRecovered(abstract, fieldDeclaration, false)
+                  listener: handleIdentifier(i5, fieldDeclaration)
+                parseFieldInitializerOpt(i5, i5, null, abstract, null, final, DeclarationKind.Class, C)
+                  listener: handleNoFieldInitializer(;)
+                listener: endClassFields(abstract, null, null, null, null, final, 1, final, ;)
+              listener: endMember()
+            notEofOrValue(}, var)
+            parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, C)
+              parseMetadataStar(;)
+                listener: beginMetadataStar(var)
+                listener: endMetadataStar(0)
+              reportRecoverableError(abstract, Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'var'., Try re-ordering the modifiers., {string: abstract, string2: var}])
+                listener: handleRecoverableError(Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'var'., Try re-ordering the modifiers., {string: abstract, string2: var}], abstract, abstract)
+              listener: beginMember()
+              parseFields(;, abstract, null, null, null, null, var, abstract, Instance of 'NoType', i6, DeclarationKind.Class, C, false)
+                listener: beginFields(;)
+                listener: handleNoType(abstract)
+                ensureIdentifierPotentiallyRecovered(abstract, fieldDeclaration, false)
+                  listener: handleIdentifier(i6, fieldDeclaration)
+                parseFieldInitializerOpt(i6, i6, null, abstract, null, var, DeclarationKind.Class, C)
+                  listener: handleNoFieldInitializer(;)
+                listener: endClassFields(abstract, null, null, null, null, var, 1, var, ;)
+              listener: endMember()
+            notEofOrValue(}, C)
+            parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, C)
+              parseMetadataStar(;)
+                listener: beginMetadataStar(C)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseFields(;, null, null, null, null, null, null, ;, Instance of 'SimpleType', abstract, DeclarationKind.Class, C, false)
+                listener: beginFields(;)
+                listener: handleIdentifier(C, typeReference)
+                listener: handleNoTypeArguments(abstract)
+                listener: handleType(C, null)
+                ensureIdentifierPotentiallyRecovered(C, fieldDeclaration, false)
+                  listener: handleIdentifier(abstract, fieldDeclaration)
+                parseFieldInitializerOpt(abstract, abstract, null, null, null, null, DeclarationKind.Class, C)
+                  listener: handleNoFieldInitializer(i7)
+                ensureSemicolon(abstract)
+                  reportRecoverableError(abstract, Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}])
+                    listener: handleRecoverableError(Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}], abstract, abstract)
+                  rewriter()
+                listener: endClassFields(null, null, null, null, null, null, 1, C, ;)
+              listener: endMember()
+            notEofOrValue(}, i7)
+            parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, C)
+              parseMetadataStar(;)
+                listener: beginMetadataStar(i7)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              isReservedKeyword(;)
+              parseFields(;, null, null, null, null, null, null, ;, Instance of 'NoType', i7, DeclarationKind.Class, C, false)
+                listener: beginFields(;)
+                reportRecoverableError(i7, MissingConstFinalVarOrType)
+                  listener: handleRecoverableError(MissingConstFinalVarOrType, i7, i7)
+                listener: handleNoType(;)
+                ensureIdentifierPotentiallyRecovered(;, fieldDeclaration, false)
+                  listener: handleIdentifier(i7, fieldDeclaration)
+                parseFieldInitializerOpt(i7, i7, null, null, null, null, DeclarationKind.Class, C)
+                  listener: handleNoFieldInitializer(;)
+                listener: endClassFields(null, null, null, null, null, null, 1, i7, ;)
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 8, {, })
+          listener: endClassDeclaration(abstract, })
+  listener: endTopLevelDeclaration(var)
+  parseTopLevelDeclarationImpl(}, Instance of 'DirectiveContext')
+    parseMetadataStar(})
+      listener: beginMetadataStar(var)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl(})
+      listener: beginTopLevelMember(var)
+      reportRecoverableError(abstract, Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'var'., Try re-ordering the modifiers., {string: abstract, string2: var}])
+        listener: handleRecoverableError(Message[ModifierOutOfOrder, The modifier 'abstract' should be before the modifier 'var'., Try re-ordering the modifiers., {string: abstract, string2: var}], abstract, abstract)
+      reportRecoverableErrorWithToken(abstract, Instance of 'Template<(Token) => Message>')
+        listener: handleRecoverableError(Message[ExtraneousModifier, Can't have modifier 'abstract' here., Try removing 'abstract'., {token: abstract}], abstract, abstract)
+      parseFields(}, null, null, null, null, null, var, abstract, Instance of 'NoType', foo, DeclarationKind.TopLevel, null, false)
+        listener: beginFields(})
+        listener: handleNoType(abstract)
+        ensureIdentifierPotentiallyRecovered(abstract, topLevelVariableDeclaration, false)
+          listener: handleIdentifier(foo, topLevelVariableDeclaration)
+        parseFieldInitializerOpt(foo, foo, null, null, null, var, DeclarationKind.TopLevel, null)
+          listener: handleNoFieldInitializer(;)
+        listener: endTopLevelFields(null, null, null, null, var, 1, var, ;)
+  listener: endTopLevelDeclaration(abstract)
+  parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+    parseMetadataStar(;)
+      listener: beginMetadataStar(abstract)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(;, class, Instance of 'DirectiveContext')
+      parseClassDeclarationModifiers(;, class)
+        parseTopLevelKeywordModifiers(abstract, class)
+      parseClassOrNamedMixinApplication(abstract, class)
+        listener: beginClassOrNamedMixinApplicationPrelude(abstract)
+        ensureIdentifier(class, classOrMixinDeclaration)
+          listener: handleIdentifier(Bar, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(abstract, abstract, Bar)
+        parseClass(Bar, abstract, class, Bar)
+          parseClassHeaderOpt(Bar, abstract, class)
+            parseClassExtendsOpt(Bar)
+              listener: handleNoType(Bar)
+              listener: handleClassExtends(null, 1)
+            parseWithClauseOpt(Bar)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(Bar)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(abstract, class, null)
+          parseClassOrMixinOrExtensionBody(Bar, DeclarationKind.Class, Bar)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, covariant)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, Bar)
+              parseMetadataStar({)
+                listener: beginMetadataStar(covariant)
+                listener: endMetadataStar(0)
+              reportRecoverableError(required, Message[ModifierOutOfOrder, The modifier 'required' should be before the modifier 'covariant'., Try re-ordering the modifiers., {string: required, string2: covariant}])
+                listener: handleRecoverableError(Message[ModifierOutOfOrder, The modifier 'required' should be before the modifier 'covariant'., Try re-ordering the modifiers., {string: required, string2: covariant}], required, required)
+              reportRecoverableErrorWithToken(required, Instance of 'Template<(Token) => Message>')
+                listener: handleRecoverableError(Message[ExtraneousModifier, Can't have modifier 'required' here., Try removing 'required'., {token: required}], required, required)
+              listener: beginMember()
+              isReservedKeyword(;)
+              parseFields({, null, null, null, covariant, null, null, required, Instance of 'NoType', x, DeclarationKind.Class, Bar, false)
+                listener: beginFields({)
+                reportRecoverableError(x, MissingConstFinalVarOrType)
+                  listener: handleRecoverableError(MissingConstFinalVarOrType, x, x)
+                listener: handleNoType(required)
+                ensureIdentifierPotentiallyRecovered(required, fieldDeclaration, false)
+                  listener: handleIdentifier(x, fieldDeclaration)
+                parseFieldInitializerOpt(x, x, null, null, null, null, DeclarationKind.Class, Bar)
+                  listener: handleNoFieldInitializer(;)
+                listener: endClassFields(null, null, null, covariant, null, null, 1, covariant, ;)
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+          listener: endClassDeclaration(abstract, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(abstract)
+  listener: endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/nnbd/error_recovery/abstract_placement.dart.parser.expect b/pkg/front_end/parser_testcases/nnbd/error_recovery/abstract_placement.dart.parser.expect
new file mode 100644
index 0000000..3a6fad5
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/error_recovery/abstract_placement.dart.parser.expect
@@ -0,0 +1,37 @@
+NOTICE: Stream was rewritten by parser!
+
+abstract class C {
+final abstract int i1;
+final abstract i2;
+covariant abstract num i3;
+covariant abstract var i4;
+final abstract i5;
+var abstract i6;
+C abstract ;i7;
+}
+
+
+var abstract foo;
+
+abstract class Bar {
+
+covariant required x;
+}
+
+abstract[KeywordToken] class[KeywordToken] C[StringToken] {[BeginToken]
+final[KeywordToken] abstract[KeywordToken] int[StringToken] i1[StringToken];[SimpleToken]
+final[KeywordToken] abstract[KeywordToken] i2[StringToken];[SimpleToken]
+covariant[KeywordToken] abstract[KeywordToken] num[StringToken] i3[StringToken];[SimpleToken]
+covariant[KeywordToken] abstract[KeywordToken] var[KeywordToken] i4[StringToken];[SimpleToken]
+final[KeywordToken] abstract[KeywordToken] i5[StringToken];[SimpleToken]
+var[KeywordToken] abstract[KeywordToken] i6[StringToken];[SimpleToken]
+C[StringToken] abstract[KeywordToken] ;[SyntheticToken]i7[StringToken];[SimpleToken]
+}[SimpleToken]
+
+
+var[KeywordToken] abstract[KeywordToken] foo[StringToken];[SimpleToken]
+
+abstract[KeywordToken] class[KeywordToken] Bar[StringToken] {[BeginToken]
+
+covariant[KeywordToken] required[KeywordToken] x[StringToken];[SimpleToken]
+}[SimpleToken][SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/error_recovery/abstract_placement.dart.scanner.expect b/pkg/front_end/parser_testcases/nnbd/error_recovery/abstract_placement.dart.scanner.expect
new file mode 100644
index 0000000..602f1128
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/error_recovery/abstract_placement.dart.scanner.expect
@@ -0,0 +1,35 @@
+abstract class C {
+final abstract int i1;
+final abstract i2;
+covariant abstract num i3;
+covariant abstract var i4;
+final abstract i5;
+var abstract i6;
+C abstract i7;
+}
+
+
+var abstract foo;
+
+abstract class Bar {
+
+covariant required x;
+}
+
+abstract[KeywordToken] class[KeywordToken] C[StringToken] {[BeginToken]
+final[KeywordToken] abstract[KeywordToken] int[StringToken] i1[StringToken];[SimpleToken]
+final[KeywordToken] abstract[KeywordToken] i2[StringToken];[SimpleToken]
+covariant[KeywordToken] abstract[KeywordToken] num[StringToken] i3[StringToken];[SimpleToken]
+covariant[KeywordToken] abstract[KeywordToken] var[KeywordToken] i4[StringToken];[SimpleToken]
+final[KeywordToken] abstract[KeywordToken] i5[StringToken];[SimpleToken]
+var[KeywordToken] abstract[KeywordToken] i6[StringToken];[SimpleToken]
+C[StringToken] abstract[KeywordToken] i7[StringToken];[SimpleToken]
+}[SimpleToken]
+
+
+var[KeywordToken] abstract[KeywordToken] foo[StringToken];[SimpleToken]
+
+abstract[KeywordToken] class[KeywordToken] Bar[StringToken] {[BeginToken]
+
+covariant[KeywordToken] required[KeywordToken] x[StringToken];[SimpleToken]
+}[SimpleToken][SimpleToken]
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index 8022b92..d50f907 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -310,6 +310,7 @@
 gulp
 gunk
 hackish
+hardly
 helper2
 hest
 heuristics
@@ -326,6 +327,7 @@
 hurray
 i'm
 ia
+ideal
 idle
 ikg
 illustrate