Skip to content

Commit 7e95f9b

Browse files
committed
Fix unexpected error by simplifying outermost capture validation
1 parent e4e8078 commit 7e95f9b

File tree

2 files changed

+85
-55
lines changed

2 files changed

+85
-55
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 42 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2135,19 +2135,19 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
21352135
if (!DRE) {
21362136
return false;
21372137
}
2138-
2138+
21392139
auto selfDecl = dyn_cast_or_null<VarDecl>(DRE->getDecl());
21402140
auto ty = DRE->getType();
21412141
if (!selfDecl || !ty) {
21422142
return false;
21432143
}
2144-
2144+
21452145
// Implicit self was always allowed in structs and metadata types
21462146
// even if the self capture was invalid.
21472147
if (!ty->hasReferenceSemantics() || ty->is<MetatypeType>()) {
21482148
return true;
21492149
}
2150-
2150+
21512151
// If this implicit self decl is from a closure that captured self
21522152
// weakly, then we should always emit an error, since implicit self was
21532153
// only allowed starting in Swift 5.8 and later.
@@ -2156,21 +2156,21 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
21562156
// captures in non-escaping closures in Swift 5.7, so in that case we
21572157
// can only warn until Swift 6.
21582158
if (AnyFunctionRef(const_cast<AbstractClosureExpr *>(ACE))
2159-
.isKnownNoEscape()) {
2160-
return true;
2161-
}
2162-
2159+
.isKnownNoEscape()) {
2160+
return true;
2161+
}
2162+
21632163
// If this is a capture like `[weak self = somethingElse]`,
21642164
// this unintentionally permitted implicit self in Swift 5.8 - 5.10,
21652165
// so we have to only warn until Swift 6.
21662166
if (!isSimpleSelfCapture(weakSelfDecl)) {
21672167
return true;
21682168
}
2169-
2169+
21702170
if (auto conditionalStmt = parentConditionalStmt(selfDecl)) {
21712171
auto isValidSelfRebinding =
2172-
hasValidSelfRebinding(conditionalStmt, ACE);
2173-
2172+
hasValidSelfRebinding(conditionalStmt, ACE);
2173+
21742174
if (isValidSelfRebinding) {
21752175
// In Swift 5.8 - 5.10 we unintentionally permitted implicit
21762176
// self without validating any parent closures. To preserve
@@ -2179,62 +2179,45 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
21792179
return true;
21802180
}
21812181
}
2182-
2182+
21832183
// In Swift 5.8 - 5.10 we used `requiresLoadExpr` instead
21842184
// of `requiresCaptureListRef` to validate self unwrap
21852185
// conditions. For source compatibility, if the legacy check
21862186
// succeeds but the current check fails, we should only warn
21872187
// until Swift 6.
21882188
auto legacyRebindsSelfResult =
2189-
conditionalStmt->rebindsSelf(ACE->getASTContext(),
2190-
/*requiresCaptureListRef*/ false,
2191-
/*requiresLoadExpr*/ true);
2192-
2189+
conditionalStmt->rebindsSelf(ACE->getASTContext(),
2190+
/*requiresCaptureListRef*/ false,
2191+
/*requiresLoadExpr*/ true);
2192+
21932193
if (!isValidSelfRebinding && legacyRebindsSelfResult) {
21942194
return true;
21952195
}
21962196
}
21972197
}
2198-
2198+
21992199
// If the self decl refers to a weak self unwrapping
22002200
// condition in some parent closure, then there is no
22012201
// source-compatibility requirement to avoid an error.
22022202
if (hasValidSelfRebinding(parentConditionalStmt(selfDecl), ACE)) {
22032203
return false;
22042204
}
2205-
2206-
// If implicit self was specifically disallowed because of the
2207-
// `implicitSelfDisallowedDueToInvalidParent` check, then there
2208-
// is no source-compatibility requirement to avoid an error,
2209-
// unless this is something like a nonescaping closure that
2210-
// didn't have this layer of validation in Swift 5 mode.
2211-
// This doesn't apply to autoclosures.
2212-
if (!isa<AutoClosureExpr>(ACE)) {
2213-
if (auto invalidParentClosure =
2214-
parentClosureDisallowingImplicitSelf(selfDecl, ty, ACE)) {
2215-
auto invalidParentClosureExcludingOutermostCapture =
2216-
parentClosureDisallowingImplicitSelf(
2217-
selfDecl, ty, ACE, /*validateOutermostCapture:*/ false);
2218-
2219-
// In Swift 5 mode we didn't validate the outermost capture in
2220-
// nonescaping closures, so in that case we only warn.
2221-
if (!isClosureRequiringSelfQualification(ACE, Ctx) &&
2222-
(invalidParentClosureExcludingOutermostCapture !=
2223-
invalidParentClosure)) {
2205+
2206+
// In Swift 5 mode we didn't validate the outermost capture in
2207+
// nonescaping closures, so if only the outermost capture is invalid
2208+
// then we must only warn.
2209+
if (!isClosureRequiringSelfQualification(ACE, Ctx)) {
2210+
auto invalidParentClosure = parentClosureDisallowingImplicitSelf(selfDecl, ty, ACE);
2211+
2212+
if (invalidParentClosure) {
2213+
auto excludingOutermostCapture = parentClosureDisallowingImplicitSelf(selfDecl, ty, ACE, /*validateOutermostCapture:*/ false);
2214+
2215+
if (invalidParentClosure != excludingOutermostCapture) {
22242216
return true;
22252217
}
2226-
2227-
return false;
2228-
}
2229-
}
2230-
2231-
bool closureHasExplicitSelfCapture = false;
2232-
if (auto closureExpr = dyn_cast<ClosureExpr>(ACE)) {
2233-
if (closureExpr->getCapturedSelfDecl()) {
2234-
closureHasExplicitSelfCapture = true;
22352218
}
22362219
}
2237-
2220+
22382221
// Implicit self was accidentially allowed in examples like this
22392222
// in Swift 5.3-5.5, so check for this case and emit a warning
22402223
// instead of an error:
@@ -2245,7 +2228,20 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
22452228
// }
22462229
// }
22472230
//
2248-
return !selfDecl->isSelfParameter() && !closureHasExplicitSelfCapture;
2231+
bool isEscapingClosureWithExplicitSelfCapture = false;
2232+
if (isClosureRequiringSelfQualification(ACE, Ctx)) {
2233+
if (auto closureExpr = dyn_cast<ClosureExpr>(ACE)) {
2234+
if (closureExpr->getCapturedSelfDecl()) {
2235+
isEscapingClosureWithExplicitSelfCapture = true;
2236+
}
2237+
}
2238+
}
2239+
2240+
if (!selfDecl->isSelfParameter() && !isEscapingClosureWithExplicitSelfCapture) {
2241+
return true;
2242+
}
2243+
2244+
return false;
22492245
};
22502246

22512247
SourceLoc memberLoc = SourceLoc();

test/expr/closure/closures.swift

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,7 +1234,7 @@ class TestGithubIssue70089 {
12341234
self.x += 1
12351235

12361236
doVoidStuff {
1237-
x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
1237+
x += 1 // expected-warning {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
12381238
self.x += 1
12391239
}
12401240

@@ -1300,7 +1300,7 @@ class TestGithubIssue70089 {
13001300
}
13011301

13021302
doVoidStuffNonEscaping {
1303-
x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
1303+
x += 1 // expected-warning {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
13041304
self.x += 1
13051305
}
13061306
}
@@ -1311,6 +1311,24 @@ class TestGithubIssue70089 {
13111311
self.x += 1
13121312
}
13131313
}
1314+
1315+
doVoidStuff { [self] in
1316+
doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}}
1317+
doVoidStuff {
1318+
x += 1 // expected-warning {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}}
1319+
self.x += 1
1320+
}
1321+
}
1322+
}
1323+
1324+
doVoidStuffNonEscaping { [self] in
1325+
doVoidStuffNonEscaping {
1326+
doVoidStuffNonEscaping {
1327+
x += 1
1328+
self.x += 1
1329+
}
1330+
}
1331+
}
13141332
}
13151333
}
13161334

@@ -1357,7 +1375,7 @@ class TestGithubIssue69911 {
13571375
}
13581376

13591377
doVoidStuffNonEscaping { [self = TestGithubIssue69911()] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}}
1360-
x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
1378+
x += 1 // expected-warning {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
13611379
self.x += 1
13621380

13631381
doVoidStuff { [self] in
@@ -1366,7 +1384,7 @@ class TestGithubIssue69911 {
13661384
}
13671385

13681386
doVoidStuffNonEscaping {
1369-
x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
1387+
x += 1 // expected-warning{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
13701388
self.x += 1
13711389
}
13721390
}
@@ -1382,33 +1400,33 @@ class TestGithubIssue69911 {
13821400
guard let self = self ?? TestGithubIssue69911.staticOptional else { return }
13831401

13841402
doVoidStuffNonEscaping {
1385-
x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
1403+
x += 1 // expected-warning{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
13861404
self.x += 1
13871405
}
13881406

13891407
doVoidStuffNonEscaping {
13901408
doVoidStuffNonEscaping {
1391-
x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
1409+
x += 1 // expected-warning{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
13921410
self.x += 1
13931411
}
13941412
}
13951413

13961414
doVoidStuff { [self] in
13971415
doVoidStuffNonEscaping {
1398-
x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
1416+
x += 1 // expected-warning{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
13991417
self.x += 1
14001418
}
14011419
}
14021420

14031421
doVoidStuffNonEscaping { [self] in
14041422
doVoidStuffNonEscaping { [self] in
1405-
x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
1423+
x += 1 // expected-warning{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
14061424
self.x += 1
14071425
}
14081426
}
14091427

14101428
doVoidStuffNonEscaping { [self = TestGithubIssue69911()] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}}
1411-
x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
1429+
x += 1 // expected-warning{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
14121430
self.x += 1
14131431
}
14141432

@@ -1417,6 +1435,13 @@ class TestGithubIssue69911 {
14171435
self?.x += 1
14181436
}
14191437

1438+
doVoidStuffNonEscaping { [self = TestGithubIssue69911()] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}}
1439+
doVoidStuffNonEscaping { [self] in
1440+
x += 1 // expected-warning {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
1441+
self.x += 1
1442+
}
1443+
}
1444+
14201445
doVoidStuff { [self] in
14211446
doVoidStuffNonEscaping {
14221447
doVoidStuffNonEscaping {
@@ -1699,4 +1724,13 @@ struct TestInvalidSelfCaptureInStruct {
16991724
self.method()
17001725
}
17011726
}
1727+
}
1728+
1729+
struct TestAsyncLet {
1730+
func bar() -> Int { 0 }
1731+
func foo() async {
1732+
let _ = {
1733+
async let _ = bar()
1734+
}
1735+
}
17021736
}

0 commit comments

Comments
 (0)