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:
@@ -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]
|
||||
Reference in New Issue
Block a user