Skip to content

Commit 74a33eb

Browse files
committed
Improve 'shouldOnlyWarn' logic
1 parent 3fcc5a8 commit 74a33eb

File tree

3 files changed

+51
-43
lines changed

3 files changed

+51
-43
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 24 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1659,15 +1659,22 @@ static void diagRecursivePropertyAccess(const Expr *E, const DeclContext *DC) {
16591659
const_cast<Expr *>(E)->walk(walker);
16601660
}
16611661

1662-
/// Whether or not this closure captures self weakly
1663-
static bool closureHasWeakSelfCapture(const AbstractClosureExpr *ACE) {
1662+
/// The `weak self` capture of this closure if present
1663+
static VarDecl *weakSelfCapture(const AbstractClosureExpr *ACE) {
16641664
if (auto closureExpr = dyn_cast<ClosureExpr>(ACE)) {
16651665
if (auto selfDecl = closureExpr->getCapturedSelfDecl()) {
1666-
return selfDecl->getInterfaceType()->is<WeakStorageType>();
1666+
if (selfDecl->getInterfaceType()->is<WeakStorageType>()) {
1667+
return selfDecl;
1668+
}
16671669
}
16681670
}
16691671

1670-
return false;
1672+
return nullptr;
1673+
}
1674+
1675+
/// Whether or not this closure captures self weakly
1676+
static bool closureHasWeakSelfCapture(const AbstractClosureExpr *ACE) {
1677+
return weakSelfCapture(ACE) != nullptr;
16711678
}
16721679

16731680
// Returns true if this is an implicit self expr
@@ -1713,7 +1720,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
17131720
return true;
17141721
}
17151722

1716-
auto *DRE = dyn_cast<DeclRefExpr>(E);
1723+
auto *DRE = cast<DeclRefExpr>(E);
17171724

17181725
// Defensive check for type. If the expression doesn't have type here, it
17191726
// should have been diagnosed somewhere else.
@@ -1943,24 +1950,17 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
19431950
}
19441951

19451952
return parentClosureDisallowingImplicitSelf(
1946-
outerSelfDecl, captureType, outerClosure);
1953+
outerSelfDecl, captureType, outerClosure,
1954+
/*validateOutermostCapture:*/ validateOutermostCapture);
19471955
}
19481956

19491957
// Optionally validate this intermediate closure before continuing
19501958
// to search upwards. Since we're already validating the chain of
19511959
// parent closures, we don't need to do that separate for this closure.
19521960
if (validateIntermediateParents) {
1953-
// If the self decl is defined in a `let self = self` unwrapping
1954-
// condition, only validate that condition once we reach the weak
1955-
// closure that actually contains the condition. This makes sure
1956-
// that we ultimately return that parent closure as invalid, instead
1957-
// of this closure that could itself be valid.
1958-
auto validateSelfRebindings = closureHasWeakSelfCapture(outerClosure);
1959-
1960-
if (!selfDeclAllowsImplicitSelf(
1961-
selfDecl, captureType, outerClosure,
1962-
/*validateParentClosures*/ false,
1963-
/*validateSelfRebindings*/ validateSelfRebindings)) {
1961+
if (!selfDeclAllowsImplicitSelf(selfDecl, captureType, outerClosure,
1962+
/*validateParentClosures*/ false,
1963+
/*validateSelfRebindings*/ false)) {
19641964
return outerClosure;
19651965
}
19661966
}
@@ -2152,7 +2152,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
21522152
// If this implicit self decl is from a closure that captured self
21532153
// weakly, then we should always emit an error, since implicit self was
21542154
// only allowed starting in Swift 5.8 and later.
2155-
if (closureHasWeakSelfCapture(ACE)) {
2155+
if (auto weakSelfDecl = weakSelfCapture(ACE)) {
21562156
// However implicit self was incorrectly permitted for weak self
21572157
// captures in non-escaping closures in Swift 5.7, so in that case we
21582158
// can only warn until Swift 6.
@@ -2164,13 +2164,8 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
21642164
// If this is a capture like `[weak self = somethingElse]`,
21652165
// this unintentionally permitted implicit self in Swift 5.8 - 5.10,
21662166
// so we have to only warn until Swift 6.
2167-
if (auto closureExpr = dyn_cast<ClosureExpr>(ACE)) {
2168-
if (auto capturedSelfDecl = closureExpr->getCapturedSelfDecl()) {
2169-
if (closureHasWeakSelfCapture(closureExpr) &&
2170-
!isSimpleSelfCapture(capturedSelfDecl)) {
2171-
return true;
2172-
}
2173-
}
2167+
if (!isSimpleSelfCapture(weakSelfDecl)) {
2168+
return true;
21742169
}
21752170

21762171
if (auto conditionalStmt = parentConditionalStmt(selfDecl)) {
@@ -2202,18 +2197,6 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
22022197
}
22032198
}
22042199

2205-
// If this is a closure nested in a closure with a `[weak self]`
2206-
// capture, then there is no source-compatibility requirement
2207-
// to avoid an error.
2208-
if (auto parentContext = ACE->getParent()) {
2209-
if (auto parentClosure = dyn_cast_or_null<ClosureExpr>(
2210-
parentContext->getInnermostClosureForSelfCapture())) {
2211-
if (closureHasWeakSelfCapture(parentClosure)) {
2212-
return false;
2213-
}
2214-
}
2215-
}
2216-
22172200
// If the self decl refers to a weak self unwrapping
22182201
// condition in some parent closure, then there is no
22192202
// source-compatibility requirement to avoid an error.
@@ -2226,6 +2209,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
22262209
// is no source-compatibility requirement to avoid an error,
22272210
// unless this is something like a nonescaping closure that
22282211
// didn't have this layer of validation in Swift 5 mode.
2212+
// This doesn't apply to autoclosures.
22292213
if (auto invalidParentClosure =
22302214
parentClosureDisallowingImplicitSelf(selfDecl, ty, ACE)) {
22312215
auto invalidParentClosureExcludingOutermostCapture =
@@ -2240,7 +2224,9 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
22402224
return true;
22412225
}
22422226

2243-
return false;
2227+
if (!isa<AutoClosureExpr>(ACE)) {
2228+
return false;
2229+
}
22442230
}
22452231

22462232
bool closureHasExplicitSelfCapture = false;

test/expr/closure/closures.swift

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,7 +1229,7 @@ class TestGithubIssue70089 {
12291229
x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}}
12301230
}
12311231

1232-
doVoidStuff { [self = TestGithubIssue70089()] 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'}}
1232+
doVoidStuff { [self = TestGithubIssue70089()] 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'}}
12331233
x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
12341234
self.x += 1
12351235

@@ -1347,6 +1347,14 @@ class TestGithubIssue69911 {
13471347
self.x += 1
13481348
}
13491349
}
1350+
1351+
doVoidStuffNonEscaping { [weak self] in
1352+
doVoidStuffNonEscaping { // expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}}
1353+
guard let self else { return }
1354+
x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}}
1355+
self.x += 1
1356+
}
1357+
}
13501358

13511359
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'}}
13521360
x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
@@ -1441,7 +1449,7 @@ final class AutoclosureTests {
14411449
withEscapingAutoclosure(bar()) // expected-warning {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}}
14421450

14431451
doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}}
1444-
withNonEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}}
1452+
withNonEscapingAutoclosure(bar()) // expected-warning {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}}
14451453
}
14461454

14471455
doVoidStuff { [self] in
@@ -1457,7 +1465,7 @@ final class AutoclosureTests {
14571465
}
14581466

14591467
doVoidStuff {
1460-
withEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}}
1468+
withEscapingAutoclosure(bar()) // expected-warning {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}}
14611469
}
14621470

14631471
doVoidStuffNonEscaping {
@@ -1607,6 +1615,20 @@ class TestInvalidRebindingOutsideOfClosure {
16071615
guard let self else { return }
16081616
method() // expected-warning{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit; this is an error in the Swift 6 language mode}}
16091617
}
1618+
1619+
doVoidStuff { [weak self] in
1620+
guard let self = self else { return }
1621+
doVoidStuff { [self] in
1622+
method() // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}}
1623+
}
1624+
}
1625+
1626+
doVoidStuffNonEscaping { [weak self] in
1627+
guard let self = self else { return }
1628+
doVoidStuffNonEscaping { [self] in
1629+
method() // expected-warning {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit; this is an error in the Swift 6 language mode}}
1630+
}
1631+
}
16101632
}
16111633

16121634
func testInvalidSelfWithBackticks() {

test/expr/closure/closures_swift6.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ class TestGithubIssue70089 {
368368
x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}}
369369
}
370370

371-
doVoidStuff { [self = TestGithubIssue70089()] 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'}}
371+
doVoidStuff { [self = TestGithubIssue70089()] 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'}}
372372
x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
373373
self.x += 1
374374

@@ -477,7 +477,7 @@ class TestGithubIssue69911 {
477477
}
478478
}
479479

480-
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'}}
480+
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'}}
481481
x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
482482
self.x += 1
483483

0 commit comments

Comments
 (0)