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