Skip to content

Commit 94b8a35

Browse files
committed
[libSyntax] Fix parsing for KeyPath
1 parent 28973f2 commit 94b8a35

File tree

4 files changed

+22
-11
lines changed

4 files changed

+22
-11
lines changed

lib/Parse/ParseDecl.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3131,12 +3131,9 @@ ParserStatus Parser::parseDeclItem(bool &PreviousHadSemi,
31313131
ParserResult<Decl> Result;
31323132
SyntaxParsingContext DeclContext(SyntaxContext,
31333133
SyntaxKind::MemberDeclListItem);
3134-
{
3135-
SyntaxParsingContext DeclContext(SyntaxContext, SyntaxContextKind::Decl);
3136-
Result = parseDecl(Options, handler);
3137-
if (Result.isParseError())
3138-
skipUntilDeclRBrace(tok::semi, tok::pound_endif);
3139-
}
3134+
Result = parseDecl(Options, handler);
3135+
if (Result.isParseError())
3136+
skipUntilDeclRBrace(tok::semi, tok::pound_endif);
31403137
SourceLoc SemiLoc;
31413138
PreviousHadSemi = consumeIf(tok::semi, SemiLoc);
31423139
if (PreviousHadSemi && Result.isNonNull())

lib/Parse/ParseExpr.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,6 @@ ParserResult<Expr> Parser::parseExprKeyPath() {
582582
// Consume '\'.
583583
SourceLoc backslashLoc = consumeToken(tok::backslash);
584584
llvm::SaveAndRestore<SourceLoc> slashLoc(SwiftKeyPathSlashLoc, backslashLoc);
585-
SyntaxParsingContext ExprCtx(SyntaxContext, SyntaxContextKind::Expr);
586585

587586
// FIXME: diagnostics
588587
ParserResult<Expr> rootResult, pathResult;
@@ -598,14 +597,19 @@ ParserResult<Expr> Parser::parseExprKeyPath() {
598597
if (startsWithSymbol(Tok, '.')) {
599598
llvm::SaveAndRestore<Expr*> S(SwiftKeyPathRoot, rootResult.getPtrOrNull());
600599

600+
SyntaxParsingContext ExprContext(SyntaxContext, SyntaxContextKind::Expr);
601+
601602
auto dotLoc = Tok.getLoc();
602603
// For uniformity, \.foo is parsed as if it were MAGIC.foo, so we need to
603604
// make sure the . is there, but parsing the ? in \.? as .? doesn't make
604605
// sense. This is all made more complicated by .?. being considered an
605606
// operator token, and a single one at that (which means
606607
// peekToken().is(tok::identifier) is incorrect: it is true for .?.foo).
607-
if (Tok.getLength() != 1 || !peekToken().is(tok::identifier))
608+
if (Tok.getLength() != 1 || !peekToken().is(tok::identifier)) {
609+
SyntaxParsingContext KeyPathBaseContext(SyntaxContext,
610+
SyntaxKind::KeyPathBaseExpr);
608611
consumeStartingCharacterOfCurrentToken(tok::period);
612+
}
609613

610614
auto inner = makeParserResult(new (Context) KeyPathDotExpr(dotLoc));
611615
bool unusedHasBindOptional = false;

test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -437,10 +437,10 @@ func foo<FunctionSignature><ParameterClause>() </ParameterClause></FunctionSigna
437437
}</CodeBlock></FunctionDecl><FunctionDecl>
438438

439439
func keypath<FunctionSignature><ParameterClause>() </ParameterClause></FunctionSignature><CodeBlock>{<SequenceExpr><DiscardAssignmentExpr>
440-
_ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><KeyPathExpr>\<IdentifierExpr>a</IdentifierExpr>.?.b</KeyPathExpr></SequenceExpr><SequenceExpr><DiscardAssignmentExpr>
440+
_ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><KeyPathExpr>\<IdentifierExpr>a</IdentifierExpr><MemberAccessExpr><OptionalChainingExpr><KeyPathBaseExpr>.</KeyPathBaseExpr>?</OptionalChainingExpr>.b</MemberAccessExpr></KeyPathExpr></SequenceExpr><SequenceExpr><DiscardAssignmentExpr>
441441
_ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><KeyPathExpr>\<MemberAccessExpr><MemberAccessExpr><IdentifierExpr>a</IdentifierExpr>.b</MemberAccessExpr>.c</MemberAccessExpr></KeyPathExpr></SequenceExpr><SequenceExpr><DiscardAssignmentExpr>
442442
_ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><KeyPathExpr>\<SubscriptExpr><MemberAccessExpr><IdentifierExpr>a</IdentifierExpr>.b</MemberAccessExpr>[<FunctionCallArgument><IntegerLiteralExpr>1</IntegerLiteralExpr></FunctionCallArgument>]</SubscriptExpr></KeyPathExpr></SequenceExpr><SequenceExpr><DiscardAssignmentExpr>
443-
_ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><KeyPathExpr>\<MemberAccessExpr>.a.b</MemberAccessExpr></KeyPathExpr></SequenceExpr><SequenceExpr><DiscardAssignmentExpr>
443+
_ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><KeyPathExpr>\<MemberAccessExpr><MemberAccessExpr>.a</MemberAccessExpr>.b</MemberAccessExpr></KeyPathExpr></SequenceExpr><SequenceExpr><DiscardAssignmentExpr>
444444
_ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><ObjcKeyPathExpr>#keyPath(<ObjcNamePiece>a.</ObjcNamePiece><ObjcNamePiece>b.</ObjcNamePiece><ObjcNamePiece>c</ObjcNamePiece>)</ObjcKeyPathExpr></SequenceExpr>
445445
}</CodeBlock></FunctionDecl><FunctionDecl>
446446
func objcSelector<FunctionSignature><ParameterClause>() </ParameterClause></FunctionSignature><CodeBlock>{<SequenceExpr><DiscardAssignmentExpr>

utils/gyb_syntax_support/ExprNodes.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,9 @@
300300
# a.b
301301
Node('MemberAccessExpr', kind='Expr',
302302
children=[
303-
Child("Base", kind='Expr'),
303+
# The base needs to be optional to parse expressions in key paths
304+
# like \.a
305+
Child("Base", kind='Expr', is_optional=True),
304306
Child("Dot", kind='PeriodToken'),
305307
Child("Name", kind='Token'),
306308
Child('DeclNameArguments', kind='DeclNameArguments',
@@ -496,9 +498,17 @@
496498
Node('KeyPathExpr', kind='Expr',
497499
children=[
498500
Child('Backslash', kind='BackslashToken'),
501+
Child('RootExpr', kind='IdentifierExpr', is_optional=True),
499502
Child('Expression', kind='Expr'),
500503
]),
501504

505+
# The period in the key path serves as the base on which the
506+
# right-hand-side of the key path is evaluated
507+
Node('KeyPathBaseExpr', kind='Expr',
508+
children=[
509+
Child('Period', kind='PeriodToken'),
510+
]),
511+
502512
# e.g. "a." or "a"
503513
Node('ObjcNamePiece', kind='Syntax',
504514
children=[

0 commit comments

Comments
 (0)