Extension type. Issue 53736. Recover from wrong location of type parameters.

Bug: https://github.com/dart-lang/sdk/issues/53736
Change-Id: I27a054bd62d8ff4833395e78b6e6e5e65c7a2f78
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/330242
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 1bf2094..a16f4c1 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -2773,7 +2773,12 @@
   @override
   void endPrimaryConstructor(
       Token beginToken, Token? constKeyword, bool hasConstructorName) {
-    final formalParameterList = pop() as FormalParameterListImpl;
+    var formalParameterList = pop() as FormalParameterListImpl?;
+    if (formalParameterList == null) {
+      final extensionTypeName = beginToken.previous!;
+      formalParameterList = _syntheticFormalParameterList(extensionTypeName);
+    }
+
     final leftParenthesis = formalParameterList.leftParenthesis;
 
     RepresentationConstructorNameImpl? constructorName;
@@ -5813,11 +5818,8 @@
   }
 
   ArgumentListImpl _syntheticArgumentList(Token precedingToken) {
-    var syntheticOffset = precedingToken.end;
-    var left = SyntheticToken(TokenType.OPEN_PAREN, syntheticOffset)
-      ..previous = precedingToken;
-    var right = SyntheticToken(TokenType.CLOSE_PAREN, syntheticOffset)
-      ..previous = left;
+    final left = parser.rewriter.insertParens(precedingToken, false);
+    final right = left.endGroup!;
     return ArgumentListImpl(
       leftParenthesis: left,
       arguments: [],
@@ -5825,6 +5827,18 @@
     );
   }
 
+  FormalParameterListImpl _syntheticFormalParameterList(Token precedingToken) {
+    final left = parser.rewriter.insertParens(precedingToken, false);
+    final right = left.endGroup!;
+    return FormalParameterListImpl(
+      leftParenthesis: left,
+      parameters: [],
+      leftDelimiter: null,
+      rightDelimiter: null,
+      rightParenthesis: right,
+    );
+  }
+
   SimpleIdentifierImpl _tmpSimpleIdentifier() {
     return SimpleIdentifierImpl(
       StringToken(TokenType.STRING, '__tmp', -1),
diff --git a/pkg/analyzer/test/src/dart/parser/extension_type_test.dart b/pkg/analyzer/test/src/dart/parser/extension_type_test.dart
index 1821f7f..219cd54 100644
--- a/pkg/analyzer/test/src/dart/parser/extension_type_test.dart
+++ b/pkg/analyzer/test/src/dart/parser/extension_type_test.dart
@@ -240,6 +240,40 @@
 ''');
   }
 
+  test_error_typeParameters_afterConstructorName() {
+    final parseResult = parseStringWithErrors(r'''
+extension type A._<T>(T _) {}
+''');
+    parseResult.assertErrors([
+      error(ParserErrorCode.EXPECTED_REPRESENTATION_FIELD, 16, 0),
+      error(ParserErrorCode.MISSING_PRIMARY_CONSTRUCTOR_PARAMETERS, 17, 1),
+      error(ParserErrorCode.EXPECTED_EXTENSION_TYPE_BODY, 17, 1),
+      error(ParserErrorCode.EXPECTED_EXECUTABLE, 18, 1),
+      error(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 19, 1),
+      error(ParserErrorCode.EXPECTED_TOKEN, 19, 1),
+      error(ParserErrorCode.TOP_LEVEL_OPERATOR, 20, 1),
+    ]);
+
+    final node = parseResult.findNode.singleExtensionTypeDeclaration;
+    assertParsedNodeText(node, r'''
+ExtensionTypeDeclaration
+  extensionKeyword: extension
+  typeKeyword: type
+  name: A
+  representation: RepresentationDeclaration
+    constructorName: RepresentationConstructorName
+      period: .
+      name: _
+    leftParenthesis: ( <synthetic>
+    fieldType: NamedType
+      name: <empty> <synthetic>
+    fieldName: <empty> <synthetic>
+    rightParenthesis: ) <synthetic>
+  leftBracket: { <synthetic>
+  rightBracket: } <synthetic>
+''');
+  }
+
   test_featureNotEnabled() {
     final parseResult = parseStringWithErrors(r'''
 // @dart = 3.1