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: