Report error for invalid this/super in initializer
Fix https://github.com/dart-lang/sdk/issues/36262
Change-Id: I20b0997f58a2835b87869952f186fbe83bfe5e3b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97404
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Dan Rubel <danrubel@google.com>
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index acf4711..1fc81eb 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -525,8 +525,10 @@
ParserErrorCode.STATIC_OPERATOR,
ParserErrorCode.STATIC_SETTER_WITHOUT_BODY,
ParserErrorCode.STATIC_TOP_LEVEL_DECLARATION,
+ ParserErrorCode.SUPER_AS_EXPRESSION,
ParserErrorCode.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE,
ParserErrorCode.SWITCH_HAS_MULTIPLE_DEFAULT_CASES,
+ ParserErrorCode.THIS_ACCESS_FROM_INITIALIZER,
ParserErrorCode.TOP_LEVEL_OPERATOR,
ParserErrorCode.TYPEDEF_IN_CLASS,
ParserErrorCode.TYPE_ARGUMENTS_ON_TYPE_VARIABLE,
diff --git a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
index 62e8d17..b5adf19 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
@@ -676,12 +676,17 @@
"Top-level declarations can't be declared to be static.",
correction: "Try removing the keyword 'static'.");
+ static const ParserErrorCode SUPER_AS_EXPRESSION = _SUPER_AS_EXPRESSION;
+
static const ParserErrorCode SWITCH_HAS_CASE_AFTER_DEFAULT_CASE =
_SWITCH_HAS_CASE_AFTER_DEFAULT_CASE;
static const ParserErrorCode SWITCH_HAS_MULTIPLE_DEFAULT_CASES =
_SWITCH_HAS_MULTIPLE_DEFAULT_CASES;
+ static const ParserErrorCode THIS_ACCESS_FROM_INITIALIZER =
+ _THIS_ACCESS_FROM_INITIALIZER;
+
static const ParserErrorCode TOP_LEVEL_OPERATOR = _TOP_LEVEL_OPERATOR;
static const ParserErrorCode TYPE_ARGUMENTS_ON_TYPE_VARIABLE =
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 fd3008b..0bf0763 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
@@ -102,6 +102,8 @@
_MISSING_CATCH_OR_FINALLY,
_EXPERIMENT_NOT_ENABLED,
_EXPECTED_ELSE_OR_COMMA,
+ _SUPER_AS_EXPRESSION,
+ _THIS_ACCESS_FROM_INITIALIZER,
];
const ParserErrorCode _ABSTRACT_CLASS_MEMBER = const ParserErrorCode(
@@ -515,6 +517,11 @@
'STATIC_OPERATOR', r"Operators can't be static.",
correction: "Try removing the keyword 'static'.");
+const ParserErrorCode _SUPER_AS_EXPRESSION = const ParserErrorCode(
+ 'SUPER_AS_EXPRESSION', r"Can't use 'super' as an expression.",
+ correction:
+ "To delegate a constructor to a super constructor, put the super call as an initializer.");
+
const ParserErrorCode _SWITCH_HAS_CASE_AFTER_DEFAULT_CASE =
const ParserErrorCode('SWITCH_HAS_CASE_AFTER_DEFAULT_CASE',
r"The default case should be the last case in a switch statement.",
@@ -526,6 +533,9 @@
r"The 'default' case can only be declared once.",
correction: "Try removing all but one default case.");
+const ParserErrorCode _THIS_ACCESS_FROM_INITIALIZER = const ParserErrorCode(
+ 'THIS_ACCESS_FROM_INITIALIZER', r"Can't access 'this' in an initializer.");
+
const ParserErrorCode _TOP_LEVEL_OPERATOR = const ParserErrorCode(
'TOP_LEVEL_OPERATOR', r"Operators must be declared within a class.",
correction:
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 99eec8c..32bfec5 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -32,6 +32,8 @@
messageMissingAssignableSelector,
messageNativeClauseShouldBeAnnotation,
messageStaticConstructor,
+ messageSuperAsExpression,
+ messageThisAccessInInitializer,
messageTypedefNotFunction,
templateDuplicateLabelInSwitchStatement,
templateExpectedButGot,
@@ -1123,8 +1125,25 @@
initializerObject.methodName,
initializerObject.argumentList));
} else {
- // Invalid initializer
- // TODO(danrubel): Capture this in the AST.
+ // Recovery: Invalid initializer
+ if (target is FunctionExpressionInvocation) {
+ var targetFunct = target.function;
+ if (targetFunct is SuperExpression) {
+ initializers.add(ast.superConstructorInvocation(
+ targetFunct.superKeyword, null, null, target.argumentList));
+ // TODO(danrubel): Consider generating this error in the parser
+ // This error is also reported in the body builder
+ handleRecoverableError(messageSuperAsExpression,
+ targetFunct.superKeyword, targetFunct.superKeyword);
+ } else if (targetFunct is ThisExpression) {
+ initializers.add(ast.redirectingConstructorInvocation(
+ targetFunct.thisKeyword, null, null, target.argumentList));
+ // TODO(danrubel): Consider generating this error in the parser
+ // This error is also reported in the body builder
+ handleRecoverableError(messageThisAccessInInitializer,
+ targetFunct.thisKeyword, targetFunct.thisKeyword);
+ }
+ }
}
} else if (initializerObject is AssignmentExpression) {
Token thisKeyword;
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index ed6c776..d416886 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -803,16 +803,6 @@
@reflectiveTest
class ErrorParserTest_Fasta extends FastaParserTestCase
with ErrorParserTestMixin {
- void test_await_missing_async_issue36048() {
- parseCompilationUnit('''
-main() { // missing async
- await foo();
-}
-''', errors: [
- expectedError(CompileTimeErrorCode.AWAIT_IN_WRONG_CONTEXT, 28, 5)
- ]);
- }
-
void test_await_missing_async2_issue36048() {
parseCompilationUnit('''
main() { // missing async
@@ -843,6 +833,33 @@
]);
}
+ void test_await_missing_async_issue36048() {
+ parseCompilationUnit('''
+main() { // missing async
+ await foo();
+}
+''', errors: [
+ expectedError(CompileTimeErrorCode.AWAIT_IN_WRONG_CONTEXT, 28, 5)
+ ]);
+ }
+
+ void test_constructor_super_asExpression() {
+ // https://github.com/dart-lang/sdk/issues/36262
+ // https://github.com/dart-lang/sdk/issues/31198
+ parseCompilationUnit('class B extends A { B(): super().foo() {} }',
+ errors: [
+ expectedError(ParserErrorCode.SUPER_AS_EXPRESSION, 25, 5),
+ ]);
+ }
+
+ void test_constructor_this_invalid() {
+ // https://github.com/dart-lang/sdk/issues/36262
+ // https://github.com/dart-lang/sdk/issues/31198
+ parseCompilationUnit('class B extends A { B(): this().foo(); }', errors: [
+ expectedError(ParserErrorCode.THIS_ACCESS_FROM_INITIALIZER, 25, 4),
+ ]);
+ }
+
@override
void test_expectedListOrMapLiteral() {
// The fasta parser returns an 'IntegerLiteralImpl' when parsing '1'.
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
index 7dd32d8..b26fdac 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
@@ -8554,7 +8554,7 @@
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageSuperAsExpression = const MessageCode(
"SuperAsExpression",
- analyzerCodes: <String>["SUPER_AS_EXPRESSION"],
+ index: 95,
message: r"""Can't use 'super' as an expression.""",
tip:
r"""To delegate a constructor to a super constructor, put the super call as an initializer.""");
@@ -8880,7 +8880,7 @@
const Code<Message Function(String name)> codeThisAccessInFieldInitializer =
const Code<Message Function(String name)>(
"ThisAccessInFieldInitializer", templateThisAccessInFieldInitializer,
- analyzerCodes: <String>["THIS_ACCESS_FROM_INITIALIZER"]);
+ analyzerCodes: <String>["THIS_ACCESS_FROM_FIELD_INITIALIZER"]);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsThisAccessInFieldInitializer(String name) {
@@ -8893,6 +8893,15 @@
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeThisAccessInInitializer = messageThisAccessInInitializer;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageThisAccessInInitializer = const MessageCode(
+ "ThisAccessInInitializer",
+ index: 96,
+ message: r"""Can't access 'this' in an initializer.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeThisAsIdentifier = messageThisAsIdentifier;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 88cbda7..2140750 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -371,6 +371,7 @@
SwitchCaseFallThrough/example: Fail
SyntheticToken/example: Fail # Can't be tested, used to recover from other errors.
ThisAccessInFieldInitializer/example: Fail
+ThisAccessInInitializer/example: Fail
ThisAsIdentifier/example: Fail
ThisOrSuperAccessInFieldInitializer/example: Fail
TooFewArguments/example: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 304ad72..4d4737d 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -2510,9 +2510,14 @@
template: "SDK libraries specification not found: #uri."
tip: "Normally, the specification is a file named 'libraries.json' in the Dart SDK install location."
+ThisAccessInInitializer:
+ index: 96
+ template: "Can't access 'this' in an initializer."
+ analyzerCode: ParserErrorCode.THIS_ACCESS_FROM_INITIALIZER
+
ThisAccessInFieldInitializer:
template: "Can't access 'this' in a field initializer to read '#name'."
- analyzerCode: THIS_ACCESS_FROM_INITIALIZER
+ analyzerCode: THIS_ACCESS_FROM_FIELD_INITIALIZER
ThisOrSuperAccessInFieldInitializer:
template: "Can't access '#string' in a field initializer."
@@ -2527,9 +2532,10 @@
analyzerCode: SUPER_AS_EXPRESSION
SuperAsExpression:
+ index: 95
template: "Can't use 'super' as an expression."
tip: "To delegate a constructor to a super constructor, put the super call as an initializer."
- analyzerCode: SUPER_AS_EXPRESSION
+ analyzerCode: ParserErrorCode.SUPER_AS_EXPRESSION
SwitchExpressionNotAssignable:
template: "Type '#type' of the switch expression isn't assignable to the type '#type2' of this case expression."