Skip to content

Commit 1886b4a

Browse files
authored
[Fixit] Add a fixit for converting non-trailing closures to trailing closures (#3317)
* [Fixit] Add a fixit for converting non-trailing closures to trailing closures. * [test] Update test to reflect the added note about converting to trailing closures.
1 parent 2c53476 commit 1886b4a

File tree

15 files changed

+235
-39
lines changed

15 files changed

+235
-39
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2082,6 +2082,10 @@ ERROR(string_literal_broken_proto,none,
20822082
ERROR(bool_type_broken,none,
20832083
"could not find a Bool type defined for 'is'", ())
20842084

2085+
NOTE(convert_to_trailing_closure,none,
2086+
"use trailing closure to simplify arguments", ())
2087+
2088+
20852089
// Array literals
20862090
ERROR(array_protocol_broken,none,
20872091
"ArrayLiteralConvertible protocol definition is broken", ())

lib/Sema/MiscDiagnostics.cpp

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1984,6 +1984,141 @@ static void diagAvailability(TypeChecker &TC, const Expr *E,
19841984
const_cast<Expr*>(E)->walk(walker);
19851985
}
19861986

1987+
namespace {
1988+
1989+
static ClosureExpr* getLastArgAsClosure(Expr* Arg) {
1990+
if (auto Paren = dyn_cast<ParenExpr>(Arg)) {
1991+
1992+
// If the argument is paren expression, get the sub expression as closure.
1993+
if (!Paren->hasTrailingClosure())
1994+
return dyn_cast_or_null<ClosureExpr>(Paren->getSubExpr());
1995+
} else if (auto Tuple = dyn_cast<TupleExpr>(Arg)) {
1996+
1997+
// If the argument is tuple expression, get the last expression in the tuple
1998+
// as closure.
1999+
if (!Tuple->hasTrailingClosure() && Tuple->getNumElements() > 0)
2000+
return dyn_cast<ClosureExpr>(Tuple->getElement(Tuple->getNumElements() - 1));
2001+
}
2002+
return nullptr;
2003+
}
2004+
2005+
static bool areIdentifiersSame(Identifier Left, Identifier Right) {
2006+
2007+
// If both are anonymous, returns true.
2008+
if (Left.empty() && Right.empty())
2009+
return true;
2010+
2011+
// If one is anonymous and the other is not, returns false.
2012+
if (Left.empty() || Right.empty())
2013+
return false;
2014+
2015+
// If both are not anonymous, compare the content.
2016+
return Left.str() == Right.str();
2017+
}
2018+
2019+
static bool willCauseAmbiguity(TypeChecker &TC, FuncDecl *SelectedFD) {
2020+
auto SelectedArgNames = SelectedFD->getEffectiveFullName().getArgumentNames();
2021+
auto SelectedArgNameExcludingClosure = SelectedArgNames.slice(0,
2022+
SelectedArgNames.size() - 1);
2023+
2024+
// Consider all decls from the same context with the simple
2025+
// identifier with SelectedFD.
2026+
for (ValueDecl *VD : TC.lookupUnqualified(SelectedFD->getDeclContext(),
2027+
SelectedFD->getName(), SourceLoc())) {
2028+
2029+
// Make sure the overload is not the selected function.
2030+
if (VD == SelectedFD)
2031+
continue;
2032+
2033+
// Make sure the overload is a function.
2034+
FuncDecl *FD = dyn_cast<FuncDecl>(VD);
2035+
if (!FD)
2036+
continue;
2037+
auto ArgNames = FD->getEffectiveFullName().getArgumentNames();
2038+
2039+
// If the overload requires more arguments than the selected; there are no
2040+
// chance of conflicts.
2041+
if (ArgNames.size() < SelectedArgNames.size())
2042+
continue;
2043+
2044+
// Assuming there is a conflict.
2045+
bool Conflict = true;
2046+
for (unsigned I = 0; I < SelectedArgNameExcludingClosure.size(); I ++) {
2047+
if (!areIdentifiersSame(ArgNames[I], SelectedArgNameExcludingClosure[I])) {
2048+
// Different argument names disprove our assumption.
2049+
Conflict = false;
2050+
}
2051+
}
2052+
if (Conflict)
2053+
return true;
2054+
}
2055+
return false;
2056+
}
2057+
2058+
static FuncDecl* digForFuncDecl(Expr *Fn) {
2059+
auto FD = dyn_cast_or_null<FuncDecl>(Fn->getReferencedDecl().getDecl());
2060+
if (FD)
2061+
return FD;
2062+
if (auto DE = dyn_cast<DotSyntaxCallExpr>(Fn)) {
2063+
return digForFuncDecl(DE->getFn());
2064+
}
2065+
return nullptr;
2066+
}
2067+
2068+
static void
2069+
applyConvertToTrailingClosureFixit(TypeChecker &TC, SourceManager &SM,
2070+
ClosureExpr *Closure, Expr *Arg) {
2071+
if (auto *Paren = dyn_cast<ParenExpr>(Arg)) {
2072+
SourceRange LRemove(Paren->getLParenLoc(),
2073+
Paren->getLParenLoc().getAdvancedLoc(1));
2074+
SourceRange RRemove(Paren->getRParenLoc(),
2075+
Paren->getRParenLoc().getAdvancedLoc(1));
2076+
2077+
// Remove the left and right paren.
2078+
TC.diagnose(Closure->getStartLoc(), diag::convert_to_trailing_closure).
2079+
fixItRemove(LRemove).fixItRemove(RRemove);
2080+
} else if (auto *Tuple = dyn_cast<TupleExpr>(Arg)) {
2081+
if (Tuple->getNumElements() > 1) {
2082+
SourceLoc ReplaceStart = Lexer::getLocForEndOfToken(SM,
2083+
Tuple->getElement(Tuple->getNumElements() - 2)->getEndLoc());
2084+
SourceRange Replace(ReplaceStart, Closure->getStartLoc());
2085+
SourceRange ToRemove(Tuple->getRParenLoc(),
2086+
Tuple->getRParenLoc().getAdvancedLoc(1));
2087+
2088+
// Closing the tuple before the closure; and remove the right paren after the
2089+
// closure.
2090+
TC.diagnose(Closure->getStartLoc(), diag::convert_to_trailing_closure).
2091+
fixItReplace(Replace, ") ").fixItRemove(ToRemove);
2092+
} else {
2093+
SourceRange LRemove(Tuple->getLParenLoc(), Closure->getStartLoc());
2094+
SourceRange RRemove(Lexer::getLocForEndOfToken(SM,Closure->getEndLoc()),
2095+
Lexer::getLocForEndOfToken(SM, Tuple->getEndLoc()));
2096+
TC.diagnose(Closure->getStartLoc(), diag::convert_to_trailing_closure).
2097+
fixItRemove(LRemove).fixItRemove(RRemove);
2098+
}
2099+
}
2100+
}
2101+
}
2102+
2103+
static void diagConvertToTrailingClosure(TypeChecker &TC, const Expr *E,
2104+
DeclContext *DC) {
2105+
auto* AE = dyn_cast<ApplyExpr>(E);
2106+
if (!AE)
2107+
return;
2108+
2109+
auto* Closure = getLastArgAsClosure(AE->getArg());
2110+
if (!Closure)
2111+
return;
2112+
if (auto* FD = digForFuncDecl(AE->getFn())) {
2113+
// Check the condition whether converting will cause ambiguity.
2114+
if (!willCauseAmbiguity(TC, FD))
2115+
// Without ambiguity, we can proceed to fix.
2116+
applyConvertToTrailingClosureFixit(TC, DC->getASTContext().SourceMgr,
2117+
Closure, AE->getArg());
2118+
}
2119+
}
2120+
2121+
19872122
//===----------------------------------------------------------------------===//
19882123
// Per func/init diagnostics
19892124
//===----------------------------------------------------------------------===//
@@ -3210,6 +3345,7 @@ void swift::performSyntacticExprDiagnostics(TypeChecker &TC, const Expr *E,
32103345
diagRecursivePropertyAccess(TC, E, DC);
32113346
diagnoseImplicitSelfUseInClosure(TC, E, DC);
32123347
diagAvailability(TC, E, const_cast<DeclContext*>(DC));
3348+
diagConvertToTrailingClosure(TC, E, const_cast<DeclContext*>(DC));
32133349
if (TC.Context.LangOpts.EnableObjCInterop)
32143350
diagDeprecatedObjCSelectors(TC, DC, E);
32153351
}

test/ClangModules/blocks_parse.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ func useString(_ s: String) {}
1111
accepts_block { }
1212
someNSString.enumerateLines {(s:String?) in }
1313
someNSString.enumerateLines {s in }
14-
someNSString.enumerateLines({ useString($0) })
14+
someNSString.enumerateLines({ useString($0) }) // expected-note {{use trailing closure to simplify arguments}}
1515

1616
accepts_block(/*not a block=*/()) // expected-error{{cannot convert value of type '()' to expected argument type 'my_block_t' (aka '() -> ()'}}
1717

test/Misc/single_expr_closure_conversion.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class C {
4545
var a = A()
4646

4747
func act() {
48-
a.dispatch({() -> Void in
48+
a.dispatch({() -> Void in // expected-note {{use trailing closure to simplify arguments}}
4949
self.prop // expected-warning {{expression of type 'Int' is unused}}
5050
})
5151
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// RUN: %target-parse-verify-swift
2+
3+
func bar(v : Int, c1 : () ->Void) {}
4+
func bar1(_ v : () ->Void) {}
5+
func bar2(v : Int, c1 : () ->Void) {}
6+
func bar2(v : Int, c2 : () ->Void) {}
7+
func bar3(v1 : Int, c1 : (Int) ->Void) {}
8+
func bar3(v2 : Int, c1 : (Int) ->Void) {}
9+
func bar4(c1 : (Int, Int, Int) ->Void) {}
10+
func bar4(c2: (Int, Int, Int) ->Void) {}
11+
func bar5(c1: (Int, Int, Int) ->Void) {}
12+
func bar6(c1 : () ->Void, v : Int) {}
13+
14+
class C {
15+
func bar(v : Int, c1 : () ->Void) {}
16+
func bar1(_ v : () ->Void) {}
17+
func bar2(v : Int, c1 : () ->Void) {}
18+
func bar2(v : Int, c2 : () ->Void) {}
19+
func bar3(v1 : Int, c1 : (Int) ->Void) {}
20+
func bar3(v2 : Int, c1 : (Int) ->Void) {}
21+
}
22+
23+
struct S {
24+
func bar(v : Int, c1 : () ->Void) {}
25+
func bar1(_ v : () ->Void) {}
26+
func bar2(v : Int, c1 : () ->Void) {}
27+
func bar2(v : Int, c2 : () ->Void) {}
28+
func bar3(v1 : Int, c1 : (Int) ->Void) {}
29+
func bar3(v2 : Int, c1 : (Int) ->Void) {}
30+
}
31+
32+
func foo(c : C, s : S) {
33+
bar(v : 3, c1: {}) // expected-note {{use trailing closure to simplify arguments}} {{12-19=) }} {{20-110=}}
34+
bar1 ({}) // expected-note {{use trailing closure to simplify arguments}} {{8-10=}} {{11-97=}}
35+
bar2(v : 3, c1: {}) // {{none}}
36+
bar2(v : 3, c2: {}) // {{none}}
37+
bar3(v1: 3, c1 : { (i) in }) // expected-note {{use trailing closure to simplify arguments}} {{13-21=) }} {{30-120=}}
38+
bar3(v2: 3, c1 : { (i) in }) // expected-note {{use trailing closure to simplify arguments}} {{13-21=) }} {{30-120=}}
39+
bar4(c1 : { (i, j, k) in }) // {{none}}
40+
bar5(c1 : { (i, j, k) in }) // expected-note {{use trailing closure to simplify arguments}} {{7-14=}} {{29-116=}}
41+
bar6(c1: {}, v: 3) // {{none}}
42+
43+
c.bar(v : 3, c1: {}) // expected-note {{use trailing closure to simplify arguments}} {{14-21=) }} {{22-112=}}
44+
c.bar1({}) // expected-note {{use trailing closure to simplify arguments}} {{9-11=}} {{12-98=}}
45+
c.bar2(v : 3, c1: {}) // {{none}}
46+
c.bar2(v : 3, c2: {}) // {{none}}
47+
c.bar3(v1: 3, c1 : { (i) in }) // expected-note {{use trailing closure to simplify arguments}} {{15-23=) }} {{32-122=}}
48+
c.bar3(v2: 3, c1 : { (i) in }) // expected-note {{use trailing closure to simplify arguments}} {{15-23=) }} {{32-122=}}
49+
50+
s.bar(v : 3, c1: {}) // expected-note {{use trailing closure to simplify arguments}} {{14-21=) }} {{22-112=}}
51+
s.bar1({}) // expected-note {{use trailing closure to simplify arguments}} {{9-11=}} {{12-98=}}
52+
s.bar2(v : 3, c1: {}) // {{none}}
53+
s.bar2(v : 3, c2: {}) // {{none}}
54+
s.bar3(v1: 3, c1 : { (i) in }) // expected-note {{use trailing closure to simplify arguments}} {{15-23=) }} {{32-122=}}
55+
s.bar3(v2: 3, c1 : { (i) in }) // expected-note {{use trailing closure to simplify arguments}} {{15-23=) }} {{32-122=}}
56+
}

test/TypeCoercion/subtyping.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ func protocolConformance(ac1: @autoclosure () -> CustomStringConvertible,
3434
f2 = f1 // expected-error{{cannot assign value of type '(fp: FormattedPrintable) -> CustomStringConvertible' to type '(p: CustomStringConvertible) -> FormattedPrintable'}}
3535

3636
accept_creates_Printable(ac1)
37-
accept_creates_Printable({ ac2() })
38-
accept_creates_Printable({ ip1() })
37+
accept_creates_Printable({ ac2() }) // expected-note {{use trailing closure to simplify arguments}}
38+
accept_creates_Printable({ ip1() }) // expected-note {{use trailing closure to simplify arguments}}
3939
accept_creates_FormattedPrintable(ac1) // expected-error{{cannot convert value of type '@autoclosure () -> CustomStringConvertible' to expected argument type '@noescape () -> FormattedPrintable'}}
4040
accept_creates_FormattedPrintable(ac2)
4141
accept_creates_FormattedPrintable(ip1) // expected-error{{cannot convert value of type '@autoclosure () -> IsPrintable1' to expected argument type '@noescape () -> FormattedPrintable'}}

test/attr/attr_availability.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -709,40 +709,40 @@ func closure_UU_LU_ne(_ x: Int, _ y: @noescape () -> Int) {} // expected-note 2
709709

710710
func testTrailingClosure() {
711711
closure_U_L { 0 } // expected-error {{'closure_U_L' has been renamed to 'after(fn:)'}} {{3-14=after}} {{none}}
712-
closure_U_L() { 0 } // expected-error {{'closure_U_L' has been renamed to 'after(fn:)'}} {{3-14=after}} {{none}}
713-
closure_U_L({ 0 }) // expected-error {{'closure_U_L' has been renamed to 'after(fn:)'}} {{3-14=after}} {{15-15=fn: }} {{none}}
712+
closure_U_L() { 0 } // expected-error {{'closure_U_L' has been renamed to 'after(fn:)'}} {{3-14=after}} {{none}}
713+
closure_U_L({ 0 }) // expected-error {{'closure_U_L' has been renamed to 'after(fn:)'}} {{3-14=after}} {{15-15=fn: }} {{none}} // expected-note {{use trailing closure to simplify arguments}}
714714

715715
closure_L_L { 0 } // expected-error {{'closure_L_L(x:)' has been renamed to 'after(fn:)'}} {{3-14=after}} {{none}}
716716
closure_L_L() { 0 } // expected-error {{'closure_L_L(x:)' has been renamed to 'after(fn:)'}} {{3-14=after}} {{none}}
717-
closure_L_L(x: { 0 }) // expected-error {{'closure_L_L(x:)' has been renamed to 'after(fn:)'}} {{3-14=after}} {{15-16=fn}} {{none}}
717+
closure_L_L(x: { 0 }) // expected-error {{'closure_L_L(x:)' has been renamed to 'after(fn:)'}} {{3-14=after}} {{15-16=fn}} {{none}} // expected-note {{use trailing closure to simplify arguments}}
718718

719719
closure_L_U { 0 } // expected-error {{'closure_L_U(x:)' has been renamed to 'after(_:)'}} {{3-14=after}} {{none}}
720720
closure_L_U() { 0 } // expected-error {{'closure_L_U(x:)' has been renamed to 'after(_:)'}} {{3-14=after}} {{none}}
721-
closure_L_U(x: { 0 }) // expected-error {{'closure_L_U(x:)' has been renamed to 'after(_:)'}} {{3-14=after}} {{15-18=}} {{none}}
721+
closure_L_U(x: { 0 }) // expected-error {{'closure_L_U(x:)' has been renamed to 'after(_:)'}} {{3-14=after}} {{15-18=}} {{none}} // expected-note {{use trailing closure to simplify arguments}}
722722

723723
closure_UU_LL(0) { 0 } // expected-error {{'closure_UU_LL' has been renamed to 'after(arg:fn:)'}} {{3-16=after}} {{17-17=arg: }} {{none}}
724-
closure_UU_LL(0, { 0 }) // expected-error {{'closure_UU_LL' has been renamed to 'after(arg:fn:)'}} {{3-16=after}} {{17-17=arg: }} {{20-20=fn: }} {{none}}
724+
closure_UU_LL(0, { 0 }) // expected-error {{'closure_UU_LL' has been renamed to 'after(arg:fn:)'}} {{3-16=after}} {{17-17=arg: }} {{20-20=fn: }} {{none}} // expected-note {{use trailing closure to simplify arguments}}
725725

726726
closure_LU_LL(x: 0) { 0 } // expected-error {{'closure_LU_LL(x:_:)' has been renamed to 'after(arg:fn:)'}} {{3-16=after}} {{17-18=arg}} {{none}}
727-
closure_LU_LL(x: 0, { 0 }) // expected-error {{'closure_LU_LL(x:_:)' has been renamed to 'after(arg:fn:)'}} {{3-16=after}} {{17-18=arg}} {{23-23=fn: }} {{none}}
727+
closure_LU_LL(x: 0, { 0 }) // expected-error {{'closure_LU_LL(x:_:)' has been renamed to 'after(arg:fn:)'}} {{3-16=after}} {{17-18=arg}} {{23-23=fn: }} {{none}} // expected-note {{use trailing closure to simplify arguments}}
728728

729729
closure_LL_LL(x: 1) { 1 } // expected-error {{'closure_LL_LL(x:y:)' has been renamed to 'after(arg:fn:)'}} {{3-16=after}} {{17-18=arg}} {{none}}
730-
closure_LL_LL(x: 1, y: { 0 }) // expected-error {{'closure_LL_LL(x:y:)' has been renamed to 'after(arg:fn:)'}} {{3-16=after}} {{17-18=arg}} {{23-24=fn}} {{none}}
730+
closure_LL_LL(x: 1, y: { 0 }) // expected-error {{'closure_LL_LL(x:y:)' has been renamed to 'after(arg:fn:)'}} {{3-16=after}} {{17-18=arg}} {{23-24=fn}} {{none}} // expected-note {{use trailing closure to simplify arguments}}
731731

732732
closure_UU_LL_ne(1) { 1 } // expected-error {{'closure_UU_LL_ne' has been renamed to 'after(arg:fn:)'}} {{3-19=after}} {{20-20=arg: }} {{none}}
733-
closure_UU_LL_ne(1, { 0 }) // expected-error {{'closure_UU_LL_ne' has been renamed to 'after(arg:fn:)'}} {{3-19=after}} {{20-20=arg: }} {{23-23=fn: }} {{none}}
733+
closure_UU_LL_ne(1, { 0 }) // expected-error {{'closure_UU_LL_ne' has been renamed to 'after(arg:fn:)'}} {{3-19=after}} {{20-20=arg: }} {{23-23=fn: }} {{none}} // expected-note {{use trailing closure to simplify arguments}}
734734

735735
closure_UU_LU(0) { 0 } // expected-error {{'closure_UU_LU' has been renamed to 'after(arg:_:)'}} {{3-16=after}} {{17-17=arg: }} {{none}}
736-
closure_UU_LU(0, { 0 }) // expected-error {{'closure_UU_LU' has been renamed to 'after(arg:_:)'}} {{3-16=after}} {{17-17=arg: }} {{none}}
736+
closure_UU_LU(0, { 0 }) // expected-error {{'closure_UU_LU' has been renamed to 'after(arg:_:)'}} {{3-16=after}} {{17-17=arg: }} {{none}} // expected-note {{use trailing closure to simplify arguments}}
737737

738738
closure_LU_LU(x: 0) { 0 } // expected-error {{'closure_LU_LU(x:_:)' has been renamed to 'after(arg:_:)'}} {{3-16=after}} {{17-18=arg}} {{none}}
739-
closure_LU_LU(x: 0, { 0 }) // expected-error {{'closure_LU_LU(x:_:)' has been renamed to 'after(arg:_:)'}} {{3-16=after}} {{17-18=arg}} {{none}}
739+
closure_LU_LU(x: 0, { 0 }) // expected-error {{'closure_LU_LU(x:_:)' has been renamed to 'after(arg:_:)'}} {{3-16=after}} {{17-18=arg}} {{none}} // expected-note {{use trailing closure to simplify arguments}}
740740

741741
closure_LL_LU(x: 1) { 1 } // expected-error {{'closure_LL_LU(x:y:)' has been renamed to 'after(arg:_:)'}} {{3-16=after}} {{17-18=arg}} {{none}}
742-
closure_LL_LU(x: 1, y: { 0 }) // expected-error {{'closure_LL_LU(x:y:)' has been renamed to 'after(arg:_:)'}} {{3-16=after}} {{17-18=arg}} {{23-26=}} {{none}}
742+
closure_LL_LU(x: 1, y: { 0 }) // expected-error {{'closure_LL_LU(x:y:)' has been renamed to 'after(arg:_:)'}} {{3-16=after}} {{17-18=arg}} {{23-26=}} {{none}} // expected-note {{use trailing closure to simplify arguments}}
743743

744744
closure_UU_LU_ne(1) { 1 } // expected-error {{'closure_UU_LU_ne' has been renamed to 'after(arg:_:)'}} {{3-19=after}} {{20-20=arg: }} {{none}}
745-
closure_UU_LU_ne(1, { 0 }) // expected-error {{'closure_UU_LU_ne' has been renamed to 'after(arg:_:)'}} {{3-19=after}} {{20-20=arg: }} {{none}}
745+
closure_UU_LU_ne(1, { 0 }) // expected-error {{'closure_UU_LU_ne' has been renamed to 'after(arg:_:)'}} {{3-19=after}} {{20-20=arg: }} {{none}} // expected-note {{use trailing closure to simplify arguments}}
746746
}
747747

748748
@available(*, unavailable, renamed: "after(x:y:)")

test/decl/func/vararg.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ f2(1,2)
1313
f2(1,2,3)
1414

1515
func f3(_ a: (String) -> Void) { }
16-
f3({ print($0) })
16+
f3({ print($0) }) // expected-note {{use trailing closure to simplify arguments}}
1717

1818

1919
func f4(_ a: Int..., b: Int) { }

test/decl/subscript/subscripting.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ func subscript_rvalue_materialize(_ i: inout Int) {
207207

208208
func subscript_coerce(_ fn: ([UnicodeScalar], [UnicodeScalar]) -> Bool) {}
209209
func test_subscript_coerce() {
210-
subscript_coerce({ $0[$0.count-1] < $1[$1.count-1] })
210+
subscript_coerce({ $0[$0.count-1] < $1[$1.count-1] }) // expected-note {{use trailing closure to simplify arguments}}
211211
}
212212

213213
struct no_index {

test/decl/var/properties.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -831,7 +831,7 @@ struct WillSetDidSetDisambiguate2Attr {
831831
// No need to disambiguate -- this is clearly a function call.
832832
func willSet(_: () -> Int) {}
833833
struct WillSetDidSetDisambiguate3 {
834-
var x: Int = takeTrailingClosure({
834+
var x: Int = takeTrailingClosure({ // expected-note {{use trailing closure to simplify arguments}}
835835
willSet { 42 }
836836
})
837837
}

0 commit comments

Comments
 (0)