External variable support: do not allow external variables to be late.

Although this error condition is not reported by the parser, the
language grammar does not it, so from a customer perspective it is a
parser error.  Accordingly, it has been assigned a ParserErrorCode and
is reported by the AstBuilder, as we do for other similar errors.

Change-Id: I22aad9b0acd27bf6e60dfb393837d48a49fc336b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/158365
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index e2285a0..fb49ebe 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -3273,6 +3273,7 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const MessageCode messageExternalLateField = const MessageCode(
     "ExternalLateField",
+    index: 109,
     message: r"""External fields cannot be late.""",
     tip: r"""Try removing the 'external' or 'late' keyword.""");
 
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index bf4ba72..095f89c 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -635,6 +635,7 @@
   ParserErrorCode.EXTERNAL_FACTORY_WITH_BODY,
   ParserErrorCode.EXTERNAL_FIELD,
   ParserErrorCode.EXTERNAL_GETTER_WITH_BODY,
+  ParserErrorCode.EXTERNAL_LATE_FIELD,
   ParserErrorCode.EXTERNAL_METHOD_WITH_BODY,
   ParserErrorCode.EXTERNAL_OPERATOR_WITH_BODY,
   ParserErrorCode.EXTERNAL_SETTER_WITH_BODY,
diff --git a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
index 57cc394..f55c540 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
@@ -303,6 +303,8 @@
       correction: "Try removing the body of the getter, or "
           "removing the keyword 'external'.");
 
+  static const ParserErrorCode EXTERNAL_LATE_FIELD = _EXTERNAL_LATE_FIELD;
+
   static const ParserErrorCode EXTERNAL_METHOD_WITH_BODY =
       _EXTERNAL_METHOD_WITH_BODY;
 
diff --git a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
index 748f18c..8c50c14 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
@@ -116,6 +116,7 @@
   _EXTERNAL_CONSTRUCTOR_WITH_INITIALIZER,
   _ABSTRACT_STATIC_FIELD,
   _ABSTRACT_LATE_FIELD,
+  _EXTERNAL_LATE_FIELD,
 ];
 
 const ParserErrorCode _ABSTRACT_CLASS_MEMBER = ParserErrorCode(
@@ -315,6 +316,10 @@
     correction:
         "Try removing the keyword 'external', or replacing the field by an external getter and/or setter.");
 
+const ParserErrorCode _EXTERNAL_LATE_FIELD = ParserErrorCode(
+    'EXTERNAL_LATE_FIELD', r"External fields cannot be late.",
+    correction: "Try removing the 'external' or 'late' keyword.");
+
 const ParserErrorCode _EXTERNAL_METHOD_WITH_BODY = ParserErrorCode(
     'EXTERNAL_METHOD_WITH_BODY',
     r"An external or native method can't have a body.");
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 8ababeb..839f9a6 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -15,6 +15,7 @@
         messageDirectiveAfterDeclaration,
         messageExpectedStatement,
         messageExternalField,
+        messageExternalLateField,
         messageFieldInitializerOutsideConstructor,
         messageIllegalAssignmentToNonAssignable,
         messageInterpolationInUri,
@@ -866,9 +867,14 @@
         }
       }
     }
-    if (externalToken != null && !enableNonNullable) {
-      handleRecoverableError(
-          messageExternalField, externalToken, externalToken);
+    if (externalToken != null) {
+      if (!enableNonNullable) {
+        handleRecoverableError(
+            messageExternalField, externalToken, externalToken);
+      } else if (lateToken != null) {
+        handleRecoverableError(
+            messageExternalLateField, externalToken, externalToken);
+      }
     }
 
     List<VariableDeclaration> variables = popTypedList(count);
@@ -2153,9 +2159,14 @@
     assert(optional(';', semicolon));
     debugEvent("TopLevelFields");
 
-    if (externalToken != null && !enableNonNullable) {
-      handleRecoverableError(
-          messageExternalField, externalToken, externalToken);
+    if (externalToken != null) {
+      if (!enableNonNullable) {
+        handleRecoverableError(
+            messageExternalField, externalToken, externalToken);
+      } else if (lateToken != null) {
+        handleRecoverableError(
+            messageExternalLateField, externalToken, externalToken);
+      }
     }
 
     List<VariableDeclaration> variables = popTypedList(count);
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index 7a398a2..6f27e07 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -254,6 +254,40 @@
     expect(field.externalKeyword, isNotNull);
   }
 
+  void test_parseField_external_late() {
+    createParser('external late int? i;', featureSet: nonNullable);
+    ClassMember member = parser.parseClassMember('C');
+    expect(member, isNotNull);
+    assertErrors(errors: [
+      expectedError(ParserErrorCode.EXTERNAL_LATE_FIELD, 0, 8),
+    ]);
+    expect(member, isFieldDeclaration);
+    FieldDeclaration field = member;
+    expect(field.externalKeyword, isNotNull);
+  }
+
+  void test_parseField_external_late_final() {
+    createParser('external late final int? i;', featureSet: nonNullable);
+    ClassMember member = parser.parseClassMember('C');
+    expect(member, isNotNull);
+    assertErrors(errors: [
+      expectedError(ParserErrorCode.EXTERNAL_LATE_FIELD, 0, 8),
+    ]);
+    expect(member, isFieldDeclaration);
+    FieldDeclaration field = member;
+    expect(field.externalKeyword, isNotNull);
+  }
+
+  void test_parseField_external_static() {
+    createParser('external static int? i;', featureSet: nonNullable);
+    ClassMember member = parser.parseClassMember('C');
+    expect(member, isNotNull);
+    assertNoErrors();
+    expect(member, isFieldDeclaration);
+    FieldDeclaration field = member;
+    expect(field.externalKeyword, isNotNull);
+  }
+
   void test_parseField_final_late() {
     createParser('final late T f;', featureSet: nonNullable);
     ClassMember member = parser.parseClassMember('C');
@@ -4627,6 +4661,26 @@
     expect(declaration.externalKeyword, isNotNull);
   }
 
+  void test_parseTopLevelVariable_external_late() {
+    var unit = parseCompilationUnit('external late int? i;',
+        featureSet: nonNullable,
+        errors: [
+          expectedError(ParserErrorCode.EXTERNAL_LATE_FIELD, 0, 8),
+        ]);
+    var declaration = unit.declarations[0] as TopLevelVariableDeclaration;
+    expect(declaration.externalKeyword, isNotNull);
+  }
+
+  void test_parseTopLevelVariable_external_late_final() {
+    var unit = parseCompilationUnit('external late final int? i;',
+        featureSet: nonNullable,
+        errors: [
+          expectedError(ParserErrorCode.EXTERNAL_LATE_FIELD, 0, 8),
+        ]);
+    var declaration = unit.declarations[0] as TopLevelVariableDeclaration;
+    expect(declaration.externalKeyword, isNotNull);
+  }
+
   void test_parseTopLevelVariable_final_late() {
     var unit = parseCompilationUnit('final late a;',
         featureSet: nonNullable,
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index affbc2f..04ff108 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -261,7 +261,6 @@
 ExternalFactoryWithBody/script1: Fail
 ExternalFieldConstructorInitializer/analyzerCode: Fail
 ExternalFieldInitializer/analyzerCode: Fail
-ExternalLateField/analyzerCode: Fail
 ExtraneousModifier/part_wrapped_script1: Fail
 ExtraneousModifier/part_wrapped_script10: Fail
 ExtraneousModifier/part_wrapped_script11: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 084b7c1..d41b3ac 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -805,7 +805,9 @@
     - "abstract class C {external var f; C() : this.f = 0;}"
 
 ExternalLateField:
+  index: 109
   template: "External fields cannot be late."
+  analyzerCode: ParserErrorCode.EXTERNAL_LATE_FIELD
   tip: "Try removing the 'external' or 'late' keyword."
   configuration: nnbd-strong
   script: