Skip to content

Commit ff8e3e3

Browse files
authored
Merge pull request #25863 from apple/revert-25165-improve_trailing_closure_in_condition_diag
2 parents 79c909d + e3a6b67 commit ff8e3e3

File tree

3 files changed

+21
-126
lines changed

3 files changed

+21
-126
lines changed

lib/Parse/ParseExpr.cpp

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -984,40 +984,23 @@ static bool isValidTrailingClosure(bool isExprBasic, Parser &P){
984984
// the token after the { is on the same line as the {.
985985
if (P.peekToken().isAtStartOfLine())
986986
return false;
987-
987+
988+
988989
// Determine if the {} goes with the expression by eating it, and looking
989-
// to see if it is immediately followed by a token which indicates we should
990-
// consider it part of the preceding expression
990+
// to see if it is immediately followed by '{', 'where', or comma. If so,
991+
// we consider it to be part of the proceeding expression.
991992
Parser::BacktrackingScope backtrack(P);
992993
P.consumeToken(tok::l_brace);
993994
P.skipUntil(tok::r_brace);
994995
SourceLoc endLoc;
995-
if (!P.consumeIf(tok::r_brace, endLoc))
996-
return false;
997-
998-
switch (P.Tok.getKind()) {
999-
case tok::l_brace:
1000-
case tok::kw_where:
1001-
case tok::comma:
1002-
return true;
1003-
case tok::l_square:
1004-
case tok::l_paren:
1005-
case tok::period:
1006-
case tok::period_prefix:
1007-
case tok::kw_is:
1008-
case tok::kw_as:
1009-
case tok::question_postfix:
1010-
case tok::question_infix:
1011-
case tok::exclaim_postfix:
1012-
case tok::colon:
1013-
case tok::equal:
1014-
case tok::oper_postfix:
1015-
case tok::oper_binary_spaced:
1016-
case tok::oper_binary_unspaced:
1017-
return !P.Tok.isAtStartOfLine();
1018-
default:
996+
if (!P.consumeIf(tok::r_brace, endLoc) ||
997+
P.Tok.isNot(tok::l_brace, tok::kw_where, tok::comma)) {
1019998
return false;
1020999
}
1000+
1001+
// Recoverable case. Just return true here and Sema will emit a diagnostic
1002+
// later. see: Sema/MiscDiagnostics.cpp#checkStmtConditionTrailingClosure
1003+
return true;
10211004
}
10221005

10231006

lib/Sema/MiscDiagnostics.cpp

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2963,7 +2963,7 @@ void swift::fixItEncloseTrailingClosure(TypeChecker &TC,
29632963
static void checkStmtConditionTrailingClosure(TypeChecker &TC, const Expr *E) {
29642964
if (E == nullptr || isa<ErrorExpr>(E)) return;
29652965

2966-
// Walk into expressions which might have invalid trailing closures
2966+
// Shallow walker. just dig into implicit expression.
29672967
class DiagnoseWalker : public ASTWalker {
29682968
TypeChecker &TC;
29692969

@@ -2998,22 +2998,13 @@ static void checkStmtConditionTrailingClosure(TypeChecker &TC, const Expr *E) {
29982998
bool shouldWalkIntoNonSingleExpressionClosure() override { return false; }
29992999

30003000
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
3001-
switch (E->getKind()) {
3002-
case ExprKind::Paren:
3003-
case ExprKind::Tuple:
3004-
case ExprKind::Array:
3005-
case ExprKind::Dictionary:
3006-
case ExprKind::InterpolatedStringLiteral:
3007-
// If a trailing closure appears as a child of one of these types of
3008-
// expression, don't diagnose it as there is no ambiguity.
3009-
return {E->isImplicit(), E};
3010-
case ExprKind::Call:
3011-
diagnoseIt(cast<CallExpr>(E));
3012-
break;
3013-
default:
3014-
break;
3015-
}
3016-
return {true, E};
3001+
// Dig into implicit expression.
3002+
if (E->isImplicit()) return { true, E };
3003+
// Diagnose call expression.
3004+
if (auto CE = dyn_cast<CallExpr>(E))
3005+
diagnoseIt(CE);
3006+
// Don't dig any further.
3007+
return { false, E };
30173008
}
30183009
};
30193010

@@ -3033,12 +3024,9 @@ static void checkStmtConditionTrailingClosure(TypeChecker &TC, const Expr *E) {
30333024
static void checkStmtConditionTrailingClosure(TypeChecker &TC, const Stmt *S) {
30343025
if (auto LCS = dyn_cast<LabeledConditionalStmt>(S)) {
30353026
for (auto elt : LCS->getCond()) {
3036-
if (elt.getKind() == StmtConditionElement::CK_PatternBinding) {
3027+
if (elt.getKind() == StmtConditionElement::CK_PatternBinding)
30373028
checkStmtConditionTrailingClosure(TC, elt.getInitializer());
3038-
if (auto *exprPattern = dyn_cast<ExprPattern>(elt.getPattern())) {
3039-
checkStmtConditionTrailingClosure(TC, exprPattern->getMatchExpr());
3040-
}
3041-
} else if (elt.getKind() == StmtConditionElement::CK_Boolean)
3029+
else if (elt.getKind() == StmtConditionElement::CK_Boolean)
30423030
checkStmtConditionTrailingClosure(TC, elt.getBoolean());
30433031
// No trailing closure for CK_Availability: e.g. `if #available() {}`.
30443032
}

test/expr/closure/trailing.swift

Lines changed: 1 addition & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,6 @@ limitXY(someInt, toGamut: intArray) {} // expected-error{{cannot invoke 'limitX
138138
// <rdar://problem/23036383> QoI: Invalid trailing closures in stmt-conditions produce lowsy diagnostics
139139
func retBool(x: () -> Int) -> Bool {}
140140
func maybeInt(_: () -> Int) -> Int? {}
141-
func twoClosureArgs(_:()->Void, _:()->Void) -> Bool {}
142141
class Foo23036383 {
143142
init() {}
144143
func map(_: (Int) -> Int) -> Int? {}
@@ -203,82 +202,7 @@ func r23036383(foo: Foo23036383?, obj: Foo23036383) {
203202

204203
if let _ = maybeInt { 1 }, retBool { 1 } { }
205204
// expected-error@-1 {{trailing closure requires parentheses for disambiguation in this context}} {{22-23=(}} {{28-28=)}}
206-
// expected-error@-2 {{trailing closure requires parentheses for disambiguation in this context}} {{37-38=(x: }} {{43-43=)}}
207-
208-
if let _ = foo?.map {$0+1}.map {$0+1} {} // expected-error {{trailing closure requires parentheses for disambiguation in this context}} {{33-34=(}} {{40-40=)}}
209-
// expected-error@-1 {{trailing closure requires parentheses for disambiguation in this context}} {{22-23=(}} {{29-29=)}}
210-
211-
if let _ = foo?.map {$0+1}.map({$0+1}) {} // expected-error {{trailing closure requires parentheses for disambiguation in this context}} {{22-23=(}} {{29-29=)}}
212-
213-
if let _ = foo?.map {$0+1}.map({$0+1}).map{$0+1} {} // expected-error {{trailing closure requires parentheses for disambiguation in this context}} {{45-45=(}} {{51-51=)}}
214-
// expected-error@-1 {{trailing closure requires parentheses for disambiguation in this context}} {{22-23=(}} {{29-29=)}}
215-
216-
if twoClosureArgs({}) {} {} // expected-error {{trailing closure requires parentheses for disambiguation in this context}} {{23-25=, }} {{27-27=)}}
217-
218-
if let _ = (foo?.map {$0+1}.map({$0+1}).map{$0+1}) {} // OK
219-
220-
if let _ = (foo?.map {$0+1}.map({$0+1})).map({$0+1}) {} // OK
221-
}
222-
223-
func id<T>(fn: () -> T) -> T { return fn() }
224-
func any<T>(fn: () -> T) -> Any { return fn() }
225-
226-
func testSR8736() {
227-
if !id { true } { return } // expected-error {{trailing closure requires parentheses for disambiguation in this context}}
228-
229-
if id { true } == true { return } // expected-error {{trailing closure requires parentheses for disambiguation in this context}}
230-
231-
if true == id { true } { return } // expected-error {{trailing closure requires parentheses for disambiguation in this context}}
232-
233-
if id { true } ? true : false { return } // expected-error {{trailing closure requires parentheses for disambiguation in this context}}
234-
235-
if true ? id { true } : false { return } // expected-error {{trailing closure requires parentheses for disambiguation in this context}}
236-
237-
if true ? true : id { false } { return } // expected-error {{trailing closure requires parentheses for disambiguation in this context}}
238-
239-
if id { [false,true] }[0] { return } // expected-error {{trailing closure requires parentheses for disambiguation in this context}}
240-
241-
if id { { true } } () { return } // expected-error {{trailing closure requires parentheses for disambiguation in this context}}
242-
243-
if any { true } as! Bool { return } // expected-error {{trailing closure requires parentheses for disambiguation in this context}}
244-
245-
if let _ = any { "test" } as? Int { return } // expected-error {{trailing closure requires parentheses for disambiguation in this context}}
246-
247-
if any { "test" } is Int { return } // expected-error {{trailing closure requires parentheses for disambiguation in this context}}
248-
249-
if let _ = id { [] as [Int]? }?.first { return } // expected-error {{trailing closure requires parentheses for disambiguation in this context}}
250-
251-
if id { true as Bool? }! { return } // expected-error {{trailing closure requires parentheses for disambiguation in this context}}
252-
253-
if case id { 1 } = 1 { return } // expected-error {{trailing closure requires parentheses for disambiguation in this context}}
254-
255-
if case 1 = id { 1 } { return } // expected-error {{trailing closure requires parentheses for disambiguation in this context}}
256-
257-
if case 1 = id { 1 } /*comment*/ { return } // expected-error {{trailing closure requires parentheses for disambiguation in this context}}
258-
259-
if case (id { 1 }) = 1 { return } // OK
260-
261-
if case 1 = (id { 1 }) { return } // OK
262-
263-
if [id { true }].count == 0 { return } // OK
264-
265-
if [id { true } : "test"].keys.count == 0 { return } // OK
266-
267-
if "\(id { true })" == "foo" { return } // OK
268-
269-
if (id { true }) { return } // OK
270-
271-
if (id { true }) { }
272-
[1, 2, 3].count // expected-warning {{expression of type 'Int' is unused}}
273-
274-
if true { }
275-
() // OK
276-
277-
if true
278-
{
279-
280-
}
281-
() // OK
205+
// expected-error@-2 {{trailing closure requires parentheses for disambiguation in this context}} {{37-38=(x: }} {{43-43=)}}
282206
}
283207

284208
func overloadOnLabel(a: () -> Void) {}

0 commit comments

Comments
 (0)