Fix patterns parsing when EOF encountered during potential pattern variable declaration.

Fixes #50563.

Bug: https://github.com/dart-lang/sdk/issues/50563
Change-Id: Icc1e38c0775bd1fab7ed717f24932dea47dd2990
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/272342
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
This commit is contained in:
Paul Berry
2022-11-28 16:36:08 +00:00
committed by Commit Queue
parent 4f925105cf
commit f22c4580e4
7 changed files with 174 additions and 1 deletions
@@ -9803,7 +9803,8 @@ class Parser {
// Record or parenthesized pattern
return next.endGroup;
}
throw new UnimplementedError('TODO(paulberry)');
// Not an outer pattern
return null;
}
/// Tries to advance through an object pattern, where [token] is the last
@@ -6734,6 +6734,18 @@ ListPattern
''');
}
test_skipOuterPattern_eof() {
// See https://github.com/dart-lang/sdk/issues/50563
_parse('''
main() {
int var = 0;
''', errors: [
error(ParserErrorCode.EXPECTED_TOKEN, 11, 3),
error(ParserErrorCode.MISSING_IDENTIFIER, 19, 1),
error(ScannerErrorCode.EXPECTED_TOKEN, 24, 1),
]);
}
test_switchExpression_empty() {
// Even though an empty switch expression is illegal (because it's not
// exhaustive), it should be accepted by the parser to enable analyzer code
@@ -0,0 +1,2 @@
main() {
int var = 0;
@@ -0,0 +1,50 @@
Problems reported:
parser/patterns/skipOuterPattern_eof:2:3: Expected ';' after this.
int var = 0;
^^^
parser/patterns/skipOuterPattern_eof:2:11: Expected an identifier, but got '='.
int var = 0;
^
parser/patterns/skipOuterPattern_eof:1:8: Can't find '}' to match '{'.
main() {
^
beginCompilationUnit(main)
beginMetadataStar(main)
endMetadataStar(0)
beginTopLevelMember(main)
beginTopLevelMethod(UnmatchedToken({), null, null)
handleNoType(UnmatchedToken({))
handleIdentifier(main, topLevelFunctionDeclaration)
handleNoTypeVariables(()
beginFormalParameters((, MemberKind.TopLevelMethod)
endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
handleAsyncModifier(null, null)
beginBlockFunctionBody({)
handleIdentifier(int, expression)
handleNoTypeArguments(var)
handleNoArguments(var)
handleSend(int, var)
handleRecoverableError(Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}], int, int)
handleExpressionStatement(;)
beginMetadataStar(var)
endMetadataStar(0)
handleNoType(var)
beginVariablesDeclaration(=, null, var)
handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got '='., Try inserting an identifier before '='., {lexeme: =}], =, =)
handleIdentifier(, localVariableDeclaration)
beginInitializedIdentifier()
beginVariableInitializer(=)
handleLiteralInt(0)
endVariableInitializer(=)
endInitializedIdentifier()
endVariablesDeclaration(1, ;)
endBlockFunctionBody(2, {, })
endTopLevelMethod(main, null, })
endTopLevelDeclaration()
handleErrorToken(UnmatchedToken({))
handleRecoverableError(Message[UnmatchedToken, Can't find '}' to match '{'., null, {string: }, lexeme: {}], UnmatchedToken({), UnmatchedToken({))
endCompilationUnit(1, )
@@ -0,0 +1,92 @@
parseUnit(UnmatchedToken({))
skipErrorTokens(UnmatchedToken({))
listener: beginCompilationUnit(main)
syntheticPreviousToken(main)
parseTopLevelDeclarationImpl(UnmatchedToken({), Instance of 'DirectiveContext')
parseMetadataStar(UnmatchedToken({))
listener: beginMetadataStar(main)
listener: endMetadataStar(0)
parseTopLevelMemberImpl(UnmatchedToken({))
listener: beginTopLevelMember(main)
isReservedKeyword(()
parseTopLevelMethod(UnmatchedToken({), null, null, UnmatchedToken({), Instance of 'NoType', null, main, false)
listener: beginTopLevelMethod(UnmatchedToken({), null, null)
listener: handleNoType(UnmatchedToken({))
ensureIdentifierPotentiallyRecovered(UnmatchedToken({), topLevelFunctionDeclaration, false)
listener: handleIdentifier(main, topLevelFunctionDeclaration)
parseMethodTypeVar(main)
listener: handleNoTypeVariables(()
parseGetterOrFormalParameters(main, main, false, MemberKind.TopLevelMethod)
parseFormalParameters(main, MemberKind.TopLevelMethod)
parseFormalParametersRest((, MemberKind.TopLevelMethod)
listener: beginFormalParameters((, MemberKind.TopLevelMethod)
listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
parseAsyncModifierOpt())
listener: handleAsyncModifier(null, null)
inPlainSync()
parseFunctionBody(), false, false)
listener: beginBlockFunctionBody({)
notEofOrValue(}, int)
parseStatement({)
parseStatementX({)
parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
looksLikeLocalFunction(int)
parseExpressionStatement({)
parseExpression({)
parsePrecedenceExpression({, 1, true)
parseUnaryExpression({, true)
parsePrimary({, expression)
parseSendOrFunctionLiteral({, expression)
parseSend({, expression)
isNextIdentifier({)
ensureIdentifier({, expression)
listener: handleIdentifier(int, expression)
listener: handleNoTypeArguments(var)
parseArgumentsOpt(int)
listener: handleNoArguments(var)
listener: handleSend(int, var)
ensureSemicolon(int)
reportRecoverableError(int, Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}])
listener: handleRecoverableError(Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}], int, int)
rewriter()
listener: handleExpressionStatement(;)
notEofOrValue(}, var)
parseStatement(;)
parseStatementX(;)
parseExpressionStatementOrDeclarationAfterModifiers(var, ;, null, var, null, false)
looksLikePatternVariableDeclaration(var)
skipOuterPattern(var)
looksLikeLocalFunction(=)
listener: beginMetadataStar(var)
listener: endMetadataStar(0)
listener: handleNoType(var)
listener: beginVariablesDeclaration(=, null, var)
parseVariablesDeclarationRest(var, true)
parseOptionallyInitializedIdentifier(var)
ensureIdentifier(var, localVariableDeclaration)
insertSyntheticIdentifier(var, localVariableDeclaration, message: Message[ExpectedIdentifier, Expected an identifier, but got '='., Try inserting an identifier before '='., {lexeme: =}], messageOnToken: null)
reportRecoverableError(=, Message[ExpectedIdentifier, Expected an identifier, but got '='., Try inserting an identifier before '='., {lexeme: =}])
listener: handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got '='., Try inserting an identifier before '='., {lexeme: =}], =, =)
rewriter()
listener: handleIdentifier(, localVariableDeclaration)
listener: beginInitializedIdentifier()
parseVariableInitializerOpt()
listener: beginVariableInitializer(=)
parseExpression(=)
parsePrecedenceExpression(=, 1, true)
parseUnaryExpression(=, true)
parsePrimary(=, expression)
parseLiteralInt(=)
listener: handleLiteralInt(0)
listener: endVariableInitializer(=)
listener: endInitializedIdentifier()
ensureSemicolon(0)
listener: endVariablesDeclaration(1, ;)
notEofOrValue(}, })
listener: endBlockFunctionBody(2, {, })
listener: endTopLevelMethod(main, null, })
listener: endTopLevelDeclaration()
reportAllErrorTokens(UnmatchedToken({))
listener: handleErrorToken(UnmatchedToken({))
listener: handleRecoverableError(Message[UnmatchedToken, Can't find '}' to match '{'., null, {string: }, lexeme: {}], UnmatchedToken({), UnmatchedToken({))
listener: endCompilationUnit(1, )
@@ -0,0 +1,9 @@
NOTICE: Stream was rewritten by parser!
main() {
int ;var *synthetic*= 0;
}
[UnmatchedToken]main[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
int[StringToken] ;[SyntheticToken]var[KeywordToken] [SyntheticStringToken]=[SimpleToken] 0[StringToken];[SimpleToken]
}[SyntheticToken][SimpleToken]
@@ -0,0 +1,7 @@
main() {
int var = 0;
}
[UnmatchedToken]main[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
int[StringToken] var[KeywordToken] =[SimpleToken] 0[StringToken];[SimpleToken]
}[SyntheticToken][SimpleToken]