Skip to content

Commit 42c5fe7

Browse files
jensjohaCommit Queue
authored andcommitted
[parser] Fix crash in _attemptPrecedenceLevelRecovery
`_recoverAtPrecedenceLevel` being set to `true` was carried over from `parsePattern` to `_parsePrecedenceExpressionLoop` which caused it to crash. Fixes #61239. Change-Id: I61eec96ebd403bf2167fed11703a2fac03cfc9b3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/445260 Commit-Queue: Jens Johansen <[email protected]> Reviewed-by: Johnni Winther <[email protected]>
1 parent cf8cb78 commit 42c5fe7

File tree

7 files changed

+269
-2
lines changed

7 files changed

+269
-2
lines changed

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6938,7 +6938,11 @@ class Parser {
69386938
) {
69396939
// Attempt recovery.
69406940
_recoverAtPrecedenceLevel = false;
6941-
assert(_tokenRecoveryReplacements.containsKey(token.next!.lexeme));
6941+
if (!_tokenRecoveryReplacements.containsKey(token.next!.lexeme)) {
6942+
// This shouldn't happen. But if it does we don't want to crash.
6943+
assert(false, "Faulty logic for _recoverAtPrecedenceLevel");
6944+
return false;
6945+
}
69426946
List<TokenType> replacements =
69436947
_tokenRecoveryReplacements[token.next!.lexeme]!;
69446948
for (int i = 0; i < replacements.length; i++) {
@@ -7002,6 +7006,7 @@ class Parser {
70027006

70037007
// Undo all changes and reset.
70047008
_currentlyRecovering = false;
7009+
_recoverAtPrecedenceLevel = false;
70057010
undoableTokenStreamRewriter.undo();
70067011
listener = originalListener;
70077012
cachedRewriter = originalRewriter;
@@ -7076,7 +7081,8 @@ class Parser {
70767081
} else if (identical(type, TokenType.IDENTIFIER)) {
70777082
// An identifier at this point is not right. So some recovery is going to
70787083
// happen soon. The question is, if we can do a better recovery here.
7079-
if (!_currentlyRecovering &&
7084+
if (!forPattern &&
7085+
!_currentlyRecovering &&
70807086
_tokenRecoveryReplacements.containsKey(token.lexeme)) {
70817087
_recoverAtPrecedenceLevel = true;
70827088
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
void f(x) {
2+
return switch(x) {
3+
42 xor => 42,
4+
_ => 0,
5+
}
6+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
Problems reported:
2+
3+
parser/patterns/issue_61239.crash:3:8: Expected '=>' before this.
4+
42 xor => 42,
5+
^^^
6+
7+
parser/patterns/issue_61239.crash:3:12: Expected ',' before this.
8+
42 xor => 42,
9+
^^
10+
11+
parser/patterns/issue_61239.crash:5:3: Expected ';' after this.
12+
}
13+
^
14+
15+
beginCompilationUnit(void)
16+
beginMetadataStar(void)
17+
endMetadataStar(0)
18+
beginTopLevelMember(void)
19+
beginTopLevelMethod(, null, null)
20+
handleVoidKeyword(void)
21+
handleIdentifier(f, topLevelFunctionDeclaration)
22+
handleNoTypeVariables(()
23+
beginFormalParameters((, MemberKind.TopLevelMethod)
24+
beginMetadataStar(x)
25+
endMetadataStar(0)
26+
beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
27+
handleNoType(()
28+
handleIdentifier(x, formalParameterDeclaration)
29+
handleFormalParameterWithoutValue())
30+
endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
31+
endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
32+
handleAsyncModifier(null, null)
33+
beginBlockFunctionBody({)
34+
beginReturnStatement(return)
35+
beginSwitchExpression(switch)
36+
handleIdentifier(x, expression)
37+
handleNoTypeArguments())
38+
handleNoArguments())
39+
handleSend(x, x)
40+
handleParenthesizedCondition((, null, null)
41+
beginSwitchExpressionBlock({)
42+
beginSwitchExpressionCase()
43+
beginPattern({)
44+
beginConstantPattern(null)
45+
handleLiteralInt(42)
46+
endConstantPattern(null)
47+
endPattern(42)
48+
handleSwitchExpressionCasePattern(42)
49+
handleRecoverableError(Message[Template(ExpectedButGot), Expected '=>' before this., null, {string: =>}], xor, xor)
50+
handleIdentifier(xor, expression)
51+
handleNoTypeArguments(=>)
52+
handleNoArguments(=>)
53+
handleSend(xor, xor)
54+
endSwitchExpressionCase(42, null, =>, xor)
55+
handleRecoverableError(Message[Template(ExpectedButGot), Expected ',' before this., null, {string: ,}], =>, =>)
56+
beginSwitchExpressionCase()
57+
beginPattern(,)
58+
handleNoType(_)
59+
handleWildcardPattern(null, _)
60+
endPattern(_)
61+
handleSwitchExpressionCasePattern(_)
62+
handleLiteralInt(0)
63+
endSwitchExpressionCase(_, null, =>, 0)
64+
endSwitchExpressionBlock(2, {, })
65+
endSwitchExpression(switch, })
66+
handleRecoverableError(Message[Template(ExpectedAfterButGot), Expected ';' after this., null, {string: ;}], }, })
67+
endReturnStatement(true, return, ;)
68+
endBlockFunctionBody(1, {, })
69+
endTopLevelMethod(void, null, })
70+
endTopLevelDeclaration(})
71+
endCompilationUnit(1, )
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
parseUnit(void)
2+
skipErrorTokens(void)
3+
listener: beginCompilationUnit(void)
4+
syntheticPreviousToken(void)
5+
parseTopLevelDeclarationImpl(, DirectiveContext(DirectiveState.Unknown))
6+
parseMetadataStar()
7+
listener: beginMetadataStar(void)
8+
listener: endMetadataStar(0)
9+
parseTopLevelMemberImpl()
10+
listener: beginTopLevelMember(void)
11+
parseTopLevelMethod(, null, null, , VoidType(), null, f, false)
12+
listener: beginTopLevelMethod(, null, null)
13+
listener: handleVoidKeyword(void)
14+
ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
15+
listener: handleIdentifier(f, topLevelFunctionDeclaration)
16+
parseMethodTypeVar(f)
17+
listener: handleNoTypeVariables(()
18+
parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
19+
parseFormalParameters(f, MemberKind.TopLevelMethod)
20+
parseFormalParametersRest((, MemberKind.TopLevelMethod)
21+
listener: beginFormalParameters((, MemberKind.TopLevelMethod)
22+
parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
23+
parseMetadataStar(()
24+
listener: beginMetadataStar(x)
25+
listener: endMetadataStar(0)
26+
listener: beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
27+
listener: handleNoType(()
28+
ensureIdentifier((, formalParameterDeclaration)
29+
listener: handleIdentifier(x, formalParameterDeclaration)
30+
listener: handleFormalParameterWithoutValue())
31+
listener: endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
32+
listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
33+
parseAsyncModifierOpt())
34+
listener: handleAsyncModifier(null, null)
35+
inPlainSync()
36+
parseFunctionBody(), false, false)
37+
listener: beginBlockFunctionBody({)
38+
notEofOrType(CLOSE_CURLY_BRACKET, return)
39+
parseStatement({)
40+
parseStatementX({)
41+
parseReturnStatement({)
42+
listener: beginReturnStatement(return)
43+
parseExpression(return)
44+
looksLikeOuterPatternEquals(return)
45+
skipOuterPattern(return)
46+
parsePrecedenceExpression(return, 1, true, ConstantPatternContext.none)
47+
parseUnaryExpression(return, true, ConstantPatternContext.none)
48+
parsePrimary(return, expression, ConstantPatternContext.none)
49+
inPlainSync()
50+
parseSwitchExpression(return)
51+
listener: beginSwitchExpression(switch)
52+
ensureParenthesizedCondition(switch, allowCase: false)
53+
parseExpressionInParenthesisRest((, allowCase: false)
54+
parseExpression(()
55+
looksLikeOuterPatternEquals(()
56+
skipOuterPattern(()
57+
skipObjectPatternRest(x)
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+
ensureIdentifier((, expression)
64+
listener: handleIdentifier(x, expression)
65+
listener: handleNoTypeArguments())
66+
parseArgumentsOpt(x)
67+
listener: handleNoArguments())
68+
listener: handleSend(x, x)
69+
ensureCloseParen(x, ()
70+
listener: handleParenthesizedCondition((, null, null)
71+
ensureBlock(), BlockKind(switch expression))
72+
listener: beginSwitchExpressionBlock({)
73+
listener: beginSwitchExpressionCase()
74+
parsePattern({, PatternContext.matching, precedence: 1)
75+
listener: beginPattern({)
76+
parsePrimaryPattern({, PatternContext.matching)
77+
listener: beginConstantPattern(null)
78+
parsePrecedenceExpression({, 7, false, ConstantPatternContext.implicit)
79+
parseUnaryExpression({, false, ConstantPatternContext.implicit)
80+
parsePrimary({, expression, ConstantPatternContext.implicit)
81+
parseLiteralInt({)
82+
listener: handleLiteralInt(42)
83+
rewriter()
84+
parsePrecedenceExpression(^, 11, false, ConstantPatternContext.none)
85+
parseUnaryExpression(^, false, ConstantPatternContext.none)
86+
parsePrimary(^, expression, ConstantPatternContext.none)
87+
parseSend(^, expression, ConstantPatternContext.none)
88+
ensureIdentifier(^, expression)
89+
reportRecoverableErrorWithToken(=>, Template(ExpectedIdentifier))
90+
rewriter()
91+
parseArgumentsOpt()
92+
listener: endConstantPattern(null)
93+
listener: endPattern(42)
94+
listener: handleSwitchExpressionCasePattern(42)
95+
ensureFunctionArrow(42)
96+
rewriteAndRecover(42, Message[Template(ExpectedButGot), Expected '=>' before this., null, {string: =>}], =>)
97+
reportRecoverableError(xor, Message[Template(ExpectedButGot), Expected '=>' before this., null, {string: =>}])
98+
listener: handleRecoverableError(Message[Template(ExpectedButGot), Expected '=>' before this., null, {string: =>}], xor, xor)
99+
rewriter()
100+
parseExpression(=>)
101+
looksLikeOuterPatternEquals(=>)
102+
skipOuterPattern(=>)
103+
skipObjectPatternRest(xor)
104+
parsePrecedenceExpression(=>, 1, true, ConstantPatternContext.none)
105+
parseUnaryExpression(=>, true, ConstantPatternContext.none)
106+
parsePrimary(=>, expression, ConstantPatternContext.none)
107+
parseSendOrFunctionLiteral(=>, expression, ConstantPatternContext.none)
108+
parseSend(=>, expression, ConstantPatternContext.none)
109+
ensureIdentifier(=>, expression)
110+
listener: handleIdentifier(xor, expression)
111+
listener: handleNoTypeArguments(=>)
112+
parseArgumentsOpt(xor)
113+
listener: handleNoArguments(=>)
114+
listener: handleSend(xor, xor)
115+
listener: endSwitchExpressionCase(42, null, =>, xor)
116+
findNextCommaOrSemicolon(=>, })
117+
reportRecoverableError(=>, Message[Template(ExpectedButGot), Expected ',' before this., null, {string: ,}])
118+
listener: handleRecoverableError(Message[Template(ExpectedButGot), Expected ',' before this., null, {string: ,}], =>, =>)
119+
listener: beginSwitchExpressionCase()
120+
parsePattern(,, PatternContext.matching, precedence: 1)
121+
listener: beginPattern(,)
122+
parsePrimaryPattern(,, PatternContext.matching)
123+
parseVariablePattern(,, PatternContext.matching, typeInfo: NoType())
124+
listener: handleNoType(_)
125+
listener: handleWildcardPattern(null, _)
126+
listener: endPattern(_)
127+
listener: handleSwitchExpressionCasePattern(_)
128+
ensureFunctionArrow(_)
129+
parseExpression(=>)
130+
looksLikeOuterPatternEquals(=>)
131+
skipOuterPattern(=>)
132+
parsePrecedenceExpression(=>, 1, true, ConstantPatternContext.none)
133+
parseUnaryExpression(=>, true, ConstantPatternContext.none)
134+
parsePrimary(=>, expression, ConstantPatternContext.none)
135+
parseLiteralInt(=>)
136+
listener: handleLiteralInt(0)
137+
listener: endSwitchExpressionCase(_, null, =>, 0)
138+
listener: endSwitchExpressionBlock(2, {, })
139+
listener: endSwitchExpression(switch, })
140+
ensureSemicolon(})
141+
reportRecoverableError(}, Message[Template(ExpectedAfterButGot), Expected ';' after this., null, {string: ;}])
142+
listener: handleRecoverableError(Message[Template(ExpectedAfterButGot), Expected ';' after this., null, {string: ;}], }, })
143+
rewriter()
144+
listener: endReturnStatement(true, return, ;)
145+
inGenerator()
146+
notEofOrType(CLOSE_CURLY_BRACKET, })
147+
listener: endBlockFunctionBody(1, {, })
148+
listener: endTopLevelMethod(void, null, })
149+
listener: endTopLevelDeclaration(})
150+
reportAllErrorTokens(void)
151+
listener: endCompilationUnit(1, )
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
NOTICE: Stream was rewritten by parser!
2+
3+
void f(x) {
4+
return switch(x) {
5+
42 =>xor => 42,
6+
_ => 0,
7+
}
8+
;}
9+
10+
11+
void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
12+
return[KeywordToken] switch[KeywordToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
13+
42[StringToken] =>[SyntheticToken]xor[StringToken] =>[SimpleToken] 42[StringToken],[SimpleToken]
14+
_[StringToken] =>[SimpleToken] 0[StringToken],[SimpleToken]
15+
}[SimpleToken]
16+
;[SyntheticToken]}[SimpleToken]
17+
[SimpleToken]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
void f(x) {
2+
return switch(x) {
3+
42 xor => 42,
4+
_ => 0,
5+
}
6+
}
7+
8+
9+
void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
10+
return[KeywordToken] switch[KeywordToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
11+
42[StringToken] xor[StringToken] =>[SimpleToken] 42[StringToken],[SimpleToken]
12+
_[StringToken] =>[SimpleToken] 0[StringToken],[SimpleToken]
13+
}[SimpleToken]
14+
}[SimpleToken]
15+
[SimpleToken]

pkg/front_end/test/spell_checking_list_code.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,7 @@ fairly
664664
falsity
665665
fangorn
666666
fasta
667+
faulty
667668
favored
668669
favoring
669670
fc

0 commit comments

Comments
 (0)