Skip to content

Commit 28dacef

Browse files
committed
[Parse] Fix excessive skipping of '}'
* Don't skip r-brace in paren or square brackets * Don't skip '}' when finding '{' on the same line rdar://problem/65891507
1 parent 4b6641f commit 28dacef

File tree

5 files changed

+31
-15
lines changed

5 files changed

+31
-15
lines changed

include/swift/Parse/Parser.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ class Parser {
660660
/// \returns true if there is an instance of \c T1 on the current line (this
661661
/// avoids the foot-gun of not considering T1 starting the next line for a
662662
/// plain Tok.is(T1) check).
663-
bool skipUntilTokenOrEndOfLine(tok T1);
663+
bool skipUntilTokenOrEndOfLine(tok T1, tok T2 = tok::NUM_TOKENS);
664664

665665
/// Skip a braced block (e.g. function body). The current token must be '{'.
666666
/// Returns \c true if the parser hit the eof before finding matched '}'.

lib/Parse/ParseStmt.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,8 @@ ParserResult<BraceStmt> Parser::parseBraceItemList(Diag<> ID) {
658658
diagnose(Tok, ID);
659659

660660
// Attempt to recover by looking for a left brace on the same line
661-
if (!skipUntilTokenOrEndOfLine(tok::l_brace))
661+
if (!skipUntilTokenOrEndOfLine(tok::l_brace, tok::r_brace) ||
662+
!Tok.is(tok::l_brace))
662663
return nullptr;
663664
}
664665
SyntaxParsingContext LocalContext(SyntaxContext, SyntaxKind::CodeBlock);
@@ -1699,7 +1700,8 @@ ParserResult<Stmt> Parser::parseStmtIf(LabeledStmtInfo LabelInfo,
16991700
// got a problem. If the last bit is 'else ... {' on one line, let's
17001701
// assume they've forgotten the 'if'.
17011702
BacktrackingScope backtrack(*this);
1702-
implicitlyInsertIf = skipUntilTokenOrEndOfLine(tok::l_brace);
1703+
if (skipUntilTokenOrEndOfLine(tok::l_brace, tok::r_brace))
1704+
implicitlyInsertIf = Tok.is(tok::l_brace);
17031705
}
17041706

17051707
if (Tok.is(tok::kw_if) || implicitlyInsertIf) {

lib/Parse/Parser.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ void Parser::skipSingle() {
660660
switch (Tok.getKind()) {
661661
case tok::l_paren:
662662
consumeToken();
663-
skipUntil(tok::r_paren);
663+
skipUntil(tok::r_paren, tok::r_brace);
664664
consumeIf(tok::r_paren);
665665
break;
666666
case tok::l_brace:
@@ -670,7 +670,7 @@ void Parser::skipSingle() {
670670
break;
671671
case tok::l_square:
672672
consumeToken();
673-
skipUntil(tok::r_square);
673+
skipUntil(tok::r_square, tok::r_brace);
674674
consumeIf(tok::r_square);
675675
break;
676676
case tok::pound_if:
@@ -825,11 +825,11 @@ void Parser::skipUntilConditionalBlockClose() {
825825
}
826826
}
827827

828-
bool Parser::skipUntilTokenOrEndOfLine(tok T1) {
829-
while (Tok.isNot(tok::eof, T1) && !Tok.isAtStartOfLine())
828+
bool Parser::skipUntilTokenOrEndOfLine(tok T1, tok T2) {
829+
while (Tok.isNot(tok::eof, T1, T2) && !Tok.isAtStartOfLine())
830830
skipSingle();
831831

832-
return Tok.is(T1) && !Tok.isAtStartOfLine();
832+
return Tok.isAny(T1, T2) && !Tok.isAtStartOfLine();
833833
}
834834

835835
bool Parser::loadCurrentSyntaxNodeFromCache() {

test/Parse/recovery.swift

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -679,12 +679,13 @@ func a(s: S[{{g) -> Int {} // expected-note {{to match this opening '['}}
679679
}}} // expected-error {{expected ']' in array type}}
680680
#endif
681681

682-
683-
684682
// rdar://19605567
685-
// expected-error@+3{{expected '(' for initializer parameters}}
686-
// expected-error@+2{{initializers may only be declared within a type}}
687-
// expected-error@+1{{expected an identifier to name generic parameter}}
683+
// expected-error@+6{{expected '(' for initializer parameters}}
684+
// expected-error@+5{{initializers may only be declared within a type}}
685+
// expected-error@+4{{expected an identifier to name generic parameter}}
686+
// expected-error@+3{{consecutive statements on a line must be separated by ';'}}
687+
// expected-error@+2{{expected expression}}
688+
// expected-error@+1{{extraneous '}' at top level}}
688689
func F() { init<( } )} // expected-note 2{{did you mean 'F'?}}
689690

690691
struct InitializerWithName {
@@ -859,3 +860,16 @@ func SR11006(a: Int == 0) {}
859860
// rdar://38225184
860861
extension Collection where Element == Int && Index == Int {}
861862
// expected-error@-1 {{expected ',' to separate the requirements of this 'where' clause}} {{43-45=,}}
863+
864+
func testSkipUnbalancedParen() {
865+
?( // expected-error {{expected expression}}
866+
}
867+
func testSkipToFindOpenBrace1() {
868+
// expected-error@+3 {{expected pattern}}
869+
// expected-error@+2 {{variable binding in a condition requires an initializer}}
870+
// expected-error@+1 {{expected '{' after 'if' condition}}
871+
do { if case }
872+
}
873+
func testSkipToFindOpenBrace2() {
874+
do { if true {} else false } // expected-error {{expected '{' or 'if' after 'else'}}
875+
}

test/expr/unary/keypath/keypath.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,7 +1013,7 @@ func testMemberAccessOnOptionalKeyPathComponent() {
10131013
// expected-error@-1 {{value of optional type 'String?' must be unwrapped to refer to member 'count' of wrapped base type 'String'}}
10141014
}
10151015

1016-
func testSyntaxErrors() { // expected-note{{}}
1016+
func testSyntaxErrors() {
10171017
_ = \. ; // expected-error{{expected member name following '.'}}
10181018
_ = \.a ;
10191019
_ = \[a ;
@@ -1045,4 +1045,4 @@ func testSyntaxErrors() { // expected-note{{}}
10451045
_ = \A[a];
10461046
_ = \A.a?;
10471047
_ = \A.a!;
1048-
} // expected-error@+1{{}}
1048+
}

0 commit comments

Comments
 (0)