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."