8d2b2a197d
In rare circumstances involving syntax errors, the `parsePattern` method inserts a synthetic token but does not consume any tokens. Usually when this happens it's not a problem, because whatever method is calling `parsePattern` consumes some tokens, so the parser always makes progress. However, when parsing list patterns, after calling `parsePattern`, the parser would look for a `,`, and if it didn't find one, it would supply a synthetic `,` and call `parsePattern` again, resulting in an infinite loop. A similar situation happened with map patterns, though the situation was more complex because in between the calls to `parsePattern`, the parser would also create synthetic key expressions and `:`s. To fix the problem, when parsing a list or map pattern, after the call to `parsePattern`, the parser checks whether any tokens were consumed. If no tokens were consumed, it ignores the next token from the input stream in order to make progress. I also investigated whether there were similar issues with parenthesized/record patterns and switch expressions, since those constructs also consist of a sequence of patterns separated by tokens and other things that could in principle be supplied synthetically. Fortunately, parser recovery doesn't get into an infinite loop in those cases, so I didn't make any further changes. But I did include test cases to make sure. Fixes #52352. Bug: https://github.com/dart-lang/sdk/issues/52352 Change-Id: Idc8140236f6054deb1fd3c862036fe47dd84f30b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/302803 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
71 lines
3.1 KiB
Plaintext
71 lines
3.1 KiB
Plaintext
Problems reported:
|
|
|
|
parser/patterns/syntheticIdentifier_insideSwitchExpression:1:34: Expected an identifier, but got 'if'.
|
|
void f(Object? x) => switch (x) {if};
|
|
^^
|
|
|
|
parser/patterns/syntheticIdentifier_insideSwitchExpression:1:34: Expected '=>' before this.
|
|
void f(Object? x) => switch (x) {if};
|
|
^^
|
|
|
|
parser/patterns/syntheticIdentifier_insideSwitchExpression:1:34: Expected an identifier, but got 'if'.
|
|
void f(Object? x) => switch (x) {if};
|
|
^^
|
|
|
|
parser/patterns/syntheticIdentifier_insideSwitchExpression:1:34: Expected '}' before this.
|
|
void f(Object? x) => switch (x) {if};
|
|
^^
|
|
|
|
beginCompilationUnit(void)
|
|
beginMetadataStar(void)
|
|
endMetadataStar(0)
|
|
beginTopLevelMember(void)
|
|
beginTopLevelMethod(, null, null)
|
|
handleVoidKeyword(void)
|
|
handleIdentifier(f, topLevelFunctionDeclaration)
|
|
handleNoTypeVariables(()
|
|
beginFormalParameters((, MemberKind.TopLevelMethod)
|
|
beginMetadataStar(Object)
|
|
endMetadataStar(0)
|
|
beginFormalParameter(Object, MemberKind.TopLevelMethod, null, null, null)
|
|
handleIdentifier(Object, typeReference)
|
|
handleNoTypeArguments(?)
|
|
handleType(Object, ?)
|
|
handleIdentifier(x, formalParameterDeclaration)
|
|
handleFormalParameterWithoutValue())
|
|
endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
|
|
endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
|
|
handleAsyncModifier(null, null)
|
|
beginSwitchExpression(switch)
|
|
handleIdentifier(x, expression)
|
|
handleNoTypeArguments())
|
|
handleNoArguments())
|
|
handleSend(x, ))
|
|
handleParenthesizedCondition((, null, null)
|
|
beginSwitchExpressionBlock({)
|
|
beginSwitchExpressionCase()
|
|
beginPattern({)
|
|
beginConstantPattern(null)
|
|
handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got 'if'., Try inserting an identifier before 'if'., {lexeme: if}], if, if)
|
|
handleIdentifier(, expression)
|
|
handleNoTypeArguments(if)
|
|
handleNoArguments(if)
|
|
handleSend(, if)
|
|
endConstantPattern(null)
|
|
endPattern()
|
|
handleSwitchExpressionCasePattern()
|
|
handleRecoverableError(Message[ExpectedButGot, Expected '=>' before this., null, {string: =>}], if, if)
|
|
handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got 'if'., Try inserting an identifier before 'if'., {lexeme: if}], if, if)
|
|
handleIdentifier(, expression)
|
|
handleNoTypeArguments(if)
|
|
handleNoArguments(if)
|
|
handleSend(, if)
|
|
endSwitchExpressionCase(null, =>, )
|
|
handleRecoverableError(Message[ExpectedButGot, Expected '}' before this., null, {string: }}], if, if)
|
|
endSwitchExpressionBlock(1, {, })
|
|
endSwitchExpression(switch, })
|
|
handleExpressionFunctionBody(=>, ;)
|
|
endTopLevelMethod(void, null, ;)
|
|
endTopLevelDeclaration()
|
|
endCompilationUnit(1, )
|