Skip to content

Commit 8d16c1d

Browse files
stereotype441Commit Queue
authored and
Commit Queue
committed
Patterns parsing: improve error recovery for late in patternVariableDeclaration.
Bug: #50035 Change-Id: Id706ff0afab3f14d817fbf99112f772d1f1f7817 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/292800 Commit-Queue: Paul Berry <[email protected]> Reviewed-by: Johnni Winther <[email protected]>
1 parent d947cd6 commit 8d16c1d

20 files changed

+337
-337
lines changed

pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8345,6 +8345,18 @@ Message _withArgumentsLateDefinitelyUnassignedError(String name) {
83458345
arguments: {'name': name});
83468346
}
83478347

8348+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
8349+
const Code<Null> codeLatePatternVariableDeclaration =
8350+
messageLatePatternVariableDeclaration;
8351+
8352+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
8353+
const MessageCode messageLatePatternVariableDeclaration = const MessageCode(
8354+
"LatePatternVariableDeclaration",
8355+
index: 151,
8356+
problemMessage:
8357+
r"""A pattern variable declaration may not use the `late` keyword.""",
8358+
correctionMessage: r"""Try removing the keyword `late`.""");
8359+
83488360
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
83498361
const Code<Null> codeLibraryDirectiveNotFirst = messageLibraryDirectiveNotFirst;
83508362

pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7792,10 +7792,7 @@ class Parser {
77927792
varFinalOrConst = context.varFinalOrConst;
77937793
}
77947794

7795-
// TODO(paulberry): maybe some of the conditions in this `if` test should be
7796-
// removed to allow for better error recovery.
77977795
if (allowPatterns &&
7798-
lateToken == null &&
77997796
varFinalOrConst != null &&
78007797
(optional('var', varFinalOrConst) ||
78017798
optional('final', varFinalOrConst))) {
@@ -7804,6 +7801,10 @@ class Parser {
78047801
(optional('=', afterOuterPattern.next!) ||
78057802
(forPartsContext != null &&
78067803
optional('in', afterOuterPattern.next!)))) {
7804+
if (lateToken != null) {
7805+
reportRecoverableError(
7806+
lateToken, codes.messageLatePatternVariableDeclaration);
7807+
}
78077808
// If there was any metadata, then the caller was responsible for
78087809
// parsing it; if not, then we need to let the listener know there
78097810
// wasn't any.

pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2530,6 +2530,8 @@ ParserErrorCode.INVALID_UNICODE_ESCAPE_U_STARTED:
25302530
status: needsEvaluation
25312531
ParserErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION:
25322532
status: needsEvaluation
2533+
ParserErrorCode.LATE_PATTERN_VARIABLE_DECLARATION:
2534+
status: needsEvaluation
25332535
ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST:
25342536
status: needsEvaluation
25352537
ParserErrorCode.LITERAL_WITH_CLASS_AND_NEW:

pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ final fastaAnalyzerErrorCodes = <ErrorCode?>[
165165
ParserErrorCode.SEALED_MIXIN,
166166
ParserErrorCode.VARIABLE_PATTERN_KEYWORD_IN_DECLARATION_CONTEXT,
167167
ParserErrorCode.INVALID_INSIDE_UNARY_PATTERN,
168+
ParserErrorCode.LATE_PATTERN_VARIABLE_DECLARATION,
168169
];
169170

170171
class ParserErrorCode extends ErrorCode {
@@ -1128,6 +1129,14 @@ class ParserErrorCode extends ErrorCode {
11281129
hasPublishedDocs: true,
11291130
);
11301131

1132+
/// No parameters.
1133+
static const ParserErrorCode LATE_PATTERN_VARIABLE_DECLARATION =
1134+
ParserErrorCode(
1135+
'LATE_PATTERN_VARIABLE_DECLARATION',
1136+
"A pattern variable declaration may not use the `late` keyword.",
1137+
correctionMessage: "Try removing the keyword `late`.",
1138+
);
1139+
11311140
static const ParserErrorCode LIBRARY_DIRECTIVE_NOT_FIRST = ParserErrorCode(
11321141
'LIBRARY_DIRECTIVE_NOT_FIRST',
11331142
"The library directive must appear before all other directives.",

pkg/analyzer/lib/src/error/error_code_values.g.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,7 @@ const List<ErrorCode> errorCodeValues = [
754754
ParserErrorCode.INVALID_UNICODE_ESCAPE_U_NO_BRACKET,
755755
ParserErrorCode.INVALID_UNICODE_ESCAPE_U_STARTED,
756756
ParserErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION,
757+
ParserErrorCode.LATE_PATTERN_VARIABLE_DECLARATION,
757758
ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST,
758759
ParserErrorCode.LITERAL_WITH_CLASS,
759760
ParserErrorCode.LITERAL_WITH_CLASS_AND_NEW,

pkg/analyzer/test/generated/patterns_parser_test.dart

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7538,20 +7538,43 @@ ForStatement
75387538
''');
75397539
}
75407540

7541-
test_patternVariableDeclarationStatement_disallowsLate() {
7541+
test_patternVariableDeclarationStatement_disallowsConst() {
75427542
// TODO(paulberry): do better error recovery.
75437543
_parse('''
7544+
f(x) {
7545+
const (_) = x;
7546+
}
7547+
''', errors: [
7548+
error(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 9, 9),
7549+
error(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 9, 9),
7550+
error(ParserErrorCode.RECORD_LITERAL_ONE_POSITIONAL_NO_TRAILING_COMMA, 17,
7551+
1),
7552+
]);
7553+
}
7554+
7555+
test_patternVariableDeclarationStatement_disallowsLate() {
7556+
_parse('''
75447557
f(x) {
75457558
late var (_) = x;
75467559
}
75477560
''', errors: [
7548-
error(ParserErrorCode.MISSING_IDENTIFIER, 18, 1),
7549-
error(ParserErrorCode.EXPECTED_TOKEN, 18, 1),
7550-
error(ParserErrorCode.EXPECTED_TOKEN, 19, 1),
7551-
error(ParserErrorCode.MISSING_IDENTIFIER, 20, 1),
7552-
error(ParserErrorCode.UNEXPECTED_TOKEN, 20, 1),
7553-
error(ParserErrorCode.MISSING_IDENTIFIER, 22, 1),
7561+
error(ParserErrorCode.LATE_PATTERN_VARIABLE_DECLARATION, 9, 4),
75547562
]);
7563+
var node = findNode.patternVariableDeclarationStatement('= x');
7564+
assertParsedNodeText(node, r'''
7565+
PatternVariableDeclarationStatement
7566+
declaration: PatternVariableDeclaration
7567+
keyword: var
7568+
pattern: ParenthesizedPattern
7569+
leftParenthesis: (
7570+
pattern: WildcardPattern
7571+
name: _
7572+
rightParenthesis: )
7573+
equals: =
7574+
expression: SimpleIdentifier
7575+
token: x
7576+
semicolon: ;
7577+
''');
75557578
}
75567579

75577580
test_patternVariableDeclarationStatement_noMetadata_final_extractor() {

pkg/front_end/messages.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6720,6 +6720,18 @@ InvalidInsideUnaryPattern:
67206720
if (x case _ as int as num) {}
67216721
}
67226722
6723+
LatePatternVariableDeclaration:
6724+
problemMessage: A pattern variable declaration may not use the `late` keyword.
6725+
correctionMessage: Try removing the keyword `late`.
6726+
analyzerCode: ParserErrorCode.LATE_PATTERN_VARIABLE_DECLARATION
6727+
index: 151
6728+
experiments: patterns
6729+
comment: No parameters.
6730+
script: |
6731+
void f(x) {
6732+
late var (y, z) = x;
6733+
}
6734+
67236735
WeakReferenceNotStatic:
67246736
problemMessage: "Weak reference pragma can be used on a static method only."
67256737

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
f(x) {
2+
const (_) = x;
3+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
Problems reported:
2+
3+
parser/patterns/patternVariableDeclarationStatement_disallowsConst:2:11: A record literal with exactly one positional field requires a trailing comma.
4+
const (_) = x;
5+
^
6+
7+
beginCompilationUnit(f)
8+
beginMetadataStar(f)
9+
endMetadataStar(0)
10+
beginTopLevelMember(f)
11+
beginTopLevelMethod(, null, null)
12+
handleNoType()
13+
handleIdentifier(f, topLevelFunctionDeclaration)
14+
handleNoTypeVariables(()
15+
beginFormalParameters((, MemberKind.TopLevelMethod)
16+
beginMetadataStar(x)
17+
endMetadataStar(0)
18+
beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
19+
handleNoType(()
20+
handleIdentifier(x, formalParameterDeclaration)
21+
handleFormalParameterWithoutValue())
22+
endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
23+
endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
24+
handleAsyncModifier(null, null)
25+
beginBlockFunctionBody({)
26+
beginConstLiteral(()
27+
beginParenthesizedExpressionOrRecordLiteral(()
28+
handleIdentifier(_, expression)
29+
handleNoTypeArguments())
30+
handleNoArguments())
31+
handleSend(_, ))
32+
handleRecoverableError(RecordLiteralOnePositionalFieldNoTrailingComma, ), ))
33+
endRecordLiteral((, 1, const)
34+
endConstLiteral(=)
35+
handleIdentifier(x, expression)
36+
handleNoTypeArguments(;)
37+
handleNoArguments(;)
38+
handleSend(x, ;)
39+
handleAssignmentExpression(=)
40+
handleExpressionStatement(;)
41+
endBlockFunctionBody(1, {, })
42+
endTopLevelMethod(f, null, })
43+
endTopLevelDeclaration()
44+
endCompilationUnit(1, )
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
parseUnit(f)
2+
skipErrorTokens(f)
3+
listener: beginCompilationUnit(f)
4+
syntheticPreviousToken(f)
5+
parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
6+
parseMetadataStar()
7+
listener: beginMetadataStar(f)
8+
listener: endMetadataStar(0)
9+
parseTopLevelMemberImpl()
10+
listener: beginTopLevelMember(f)
11+
isReservedKeyword(()
12+
parseTopLevelMethod(, null, null, , Instance of 'NoType', null, f, false)
13+
listener: beginTopLevelMethod(, null, null)
14+
listener: handleNoType()
15+
ensureIdentifierPotentiallyRecovered(, topLevelFunctionDeclaration, false)
16+
listener: handleIdentifier(f, topLevelFunctionDeclaration)
17+
parseMethodTypeVar(f)
18+
listener: handleNoTypeVariables(()
19+
parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
20+
parseFormalParameters(f, MemberKind.TopLevelMethod)
21+
parseFormalParametersRest((, MemberKind.TopLevelMethod)
22+
listener: beginFormalParameters((, MemberKind.TopLevelMethod)
23+
parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
24+
parseMetadataStar(()
25+
listener: beginMetadataStar(x)
26+
listener: endMetadataStar(0)
27+
listener: beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
28+
listener: handleNoType(()
29+
ensureIdentifier((, formalParameterDeclaration)
30+
listener: handleIdentifier(x, formalParameterDeclaration)
31+
listener: handleFormalParameterWithoutValue())
32+
listener: endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
33+
listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
34+
parseAsyncModifierOpt())
35+
listener: handleAsyncModifier(null, null)
36+
inPlainSync()
37+
parseFunctionBody(), false, false)
38+
listener: beginBlockFunctionBody({)
39+
notEofOrValue(}, const)
40+
parseStatement({)
41+
parseStatementX({)
42+
parseExpressionStatementOrConstDeclaration({)
43+
parseExpressionStatement({)
44+
parseExpression({)
45+
looksLikeOuterPatternEquals({)
46+
skipOuterPattern({)
47+
parsePrecedenceExpression({, 1, true, ConstantPatternContext.none)
48+
parseUnaryExpression({, true, ConstantPatternContext.none)
49+
parsePrimary({, expression, ConstantPatternContext.none)
50+
parseConstExpression({)
51+
listener: beginConstLiteral(()
52+
parseParenthesizedExpressionOrRecordLiteral(const, const, ConstantPatternContext.none)
53+
listener: beginParenthesizedExpressionOrRecordLiteral(()
54+
parseExpression(()
55+
looksLikeOuterPatternEquals(()
56+
skipOuterPattern(()
57+
skipObjectPatternRest(_)
58+
parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
59+
parseUnaryExpression((, true, ConstantPatternContext.none)
60+
parsePrimary((, expression, ConstantPatternContext.none)
61+
parseSendOrFunctionLiteral((, expression, ConstantPatternContext.none)
62+
parseSend((, expression, ConstantPatternContext.none)
63+
isNextIdentifier(()
64+
ensureIdentifier((, expression)
65+
listener: handleIdentifier(_, expression)
66+
listener: handleNoTypeArguments())
67+
parseArgumentsOpt(_)
68+
listener: handleNoArguments())
69+
listener: handleSend(_, ))
70+
ensureCloseParen(_, ()
71+
reportRecoverableError(), RecordLiteralOnePositionalFieldNoTrailingComma)
72+
listener: handleRecoverableError(RecordLiteralOnePositionalFieldNoTrailingComma, ), ))
73+
listener: endRecordLiteral((, 1, const)
74+
listener: endConstLiteral(=)
75+
parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none)
76+
parseUnaryExpression(=, true, ConstantPatternContext.none)
77+
parsePrimary(=, expression, ConstantPatternContext.none)
78+
parseSendOrFunctionLiteral(=, expression, ConstantPatternContext.none)
79+
parseSend(=, expression, ConstantPatternContext.none)
80+
isNextIdentifier(=)
81+
ensureIdentifier(=, expression)
82+
listener: handleIdentifier(x, expression)
83+
listener: handleNoTypeArguments(;)
84+
parseArgumentsOpt(x)
85+
listener: handleNoArguments(;)
86+
listener: handleSend(x, ;)
87+
listener: handleAssignmentExpression(=)
88+
ensureSemicolon(x)
89+
listener: handleExpressionStatement(;)
90+
notEofOrValue(}, })
91+
listener: endBlockFunctionBody(1, {, })
92+
listener: endTopLevelMethod(f, null, })
93+
listener: endTopLevelDeclaration()
94+
reportAllErrorTokens(f)
95+
listener: endCompilationUnit(1, )
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
f(x) {
2+
const (_) = x;
3+
}
4+
5+
6+
f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
7+
const[KeywordToken] ([BeginToken]_[StringToken])[SimpleToken] =[SimpleToken] x[StringToken];[SimpleToken]
8+
}[SimpleToken]
9+
[SimpleToken]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
f(x) {
2+
const (_) = x;
3+
}
4+
5+
6+
f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
7+
const[KeywordToken] ([BeginToken]_[StringToken])[SimpleToken] =[SimpleToken] x[StringToken];[SimpleToken]
8+
}[SimpleToken]
9+
[SimpleToken]

0 commit comments

Comments
 (0)