Skip to content

Commit e6a2230

Browse files
committed
Fix issue where implicit self was unexpectedly not allowed in nested weak self closure in Swift 6 mode
1 parent 8ec8a12 commit e6a2230

File tree

2 files changed

+108
-12
lines changed

2 files changed

+108
-12
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,9 +1901,21 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
19011901
// If this closure has a `weak self` capture, require that the
19021902
// closure unwraps self. If not, implicit self is not allowed
19031903
// in this closure or in any nested closure.
1904-
if (closureHasWeakSelfCapture(inClosure) &&
1905-
!hasValidSelfRebinding(parentConditionalStmt(selfDecl), ctx)) {
1906-
return false;
1904+
if (closureHasWeakSelfCapture(inClosure)) {
1905+
// If a `guard let self` or `if let self` unbinding condition exists,
1906+
// then it must not be invalid.
1907+
if (auto condStmt = parentConditionalStmt(selfDecl)) {
1908+
if (!hasValidSelfRebinding(condStmt, ctx)) {
1909+
return false;
1910+
}
1911+
}
1912+
1913+
// If the self decl hasn't been unwrapped, then this closure is
1914+
// invalid unless non-unwrapped weak self is explicitly enabled
1915+
// in this situation.
1916+
else if (validateSelfRebindings) {
1917+
return false;
1918+
}
19071919
}
19081920

19091921
if (auto autoclosure = dyn_cast<AutoClosureExpr>(inClosure)) {
@@ -2050,10 +2062,15 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
20502062
// Check whether implicit self is disallowed due to this specific
20512063
// closure, or if its disallowed due to some parent of this closure,
20522064
// so we can return the specific closure that is invalid.
2065+
//
2066+
// If this is a `weak self` capture, we don't need to validate that
2067+
// that capture has been unwrapped in a `let self = self` binding
2068+
// within the parent closure. A self rebinding in this inner closure
2069+
// is sufficient to enable implicit self.
20532070
if (!selfDeclAllowsImplicitSelf(outerSelfDecl, captureType,
20542071
outerClosure,
20552072
/*validateParentClosures:*/ false,
2056-
/*validateSelfRebindings:*/ true)) {
2073+
/*validateSelfRebindings:*/ false)) {
20572074
return outerClosure;
20582075
}
20592076

test/expr/closure/closures_swift6.swift

Lines changed: 87 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,92 @@ class TestGithubIssue70089 {
454454
}
455455
}
456456
}
457+
458+
func testClosuresInsideWeakSelfNotUnwrapped() {
459+
// https://forums.swift.org/t/nested-weak-capture-and-implicit-self-in-swift-6/77230/1
460+
doVoidStuff { [weak self] in
461+
doVoidStuff { [weak self] in
462+
guard let self else { return }
463+
x += 1
464+
}
465+
}
466+
467+
doVoidStuff { [weak self] in
468+
doVoidStuff { [weak self] in
469+
doVoidStuff { [weak self] in
470+
guard let self else { return }
471+
doVoidStuff { [weak self] in
472+
doVoidStuff { [weak self] in
473+
guard let self else { return }
474+
x += 1
475+
}
476+
}
477+
}
478+
}
479+
}
480+
481+
doVoidStuff { [weak self] in
482+
doVoidStuff { [weak self] in
483+
guard let self else { return }
484+
doVoidStuff { [self] in
485+
doVoidStuff { [self] in
486+
doVoidStuff { [weak self] in
487+
guard let self else { return }
488+
x += 1
489+
}
490+
}
491+
}
492+
}
493+
}
494+
495+
doVoidStuff { [weak self] in
496+
guard let self = self ?? TestGithubIssue70089.staticOptional else { return }
497+
doVoidStuff { [weak self] in
498+
guard let self else { return }
499+
x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
500+
}
501+
}
502+
503+
doVoidStuff { [weak self] in
504+
doVoidStuff { [self] in
505+
x += 1 // expected-error@-1 {{value of optional type 'TestGithubIssue70089?' must be unwrapped to a value of type 'TestGithubIssue70089'}} expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} expected-note@-1 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}
506+
}
507+
}
508+
509+
doVoidStuff { [weak self] in
510+
doVoidStuff { [self] in //
511+
self.x += 1 // expected-error@-1 {{value of optional type 'TestGithubIssue70089?' must be unwrapped to a value of type 'TestGithubIssue70089'}} expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} expected-note@-1 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}
512+
}
513+
}
514+
515+
doVoidStuff { [weak self] in
516+
doVoidStuff { [self] in
517+
self?.x += 1
518+
}
519+
}
520+
521+
doVoidStuff { [weak self] in
522+
doVoidStuff { [self] in
523+
guard let self else { return }
524+
self.x += 1
525+
}
526+
}
527+
528+
doVoidStuff { [weak self] in
529+
doVoidStuff { [self] in
530+
guard let self else { return }
531+
x += 1
532+
}
533+
}
534+
535+
doVoidStuff { [weak self] in
536+
guard let self = self ?? TestGithubIssue70089.staticOptional else { return }
537+
doVoidStuff { [self] in
538+
guard let self else { return } // expected-error{{initializer for conditional binding must have Optional type, not 'TestGithubIssue70089'}}
539+
x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
540+
}
541+
}
542+
}
457543
}
458544

459545
class TestGithubIssue69911 {
@@ -670,7 +756,7 @@ final class AutoclosureTests {
670756
doVoidStuff { [weak self] in
671757
doVoidStuff { [self] in
672758
guard let self else { return }
673-
method() // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}}
759+
method()
674760
}
675761
}
676762

@@ -702,13 +788,6 @@ final class AutoclosureTests {
702788
}
703789
}
704790

705-
doVoidStuff { [weak self] in
706-
doVoidStuff { [self] in
707-
guard let self else { return }
708-
method() // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}}
709-
}
710-
}
711-
712791
doVoidStuff { [weak self] in
713792
guard let self = self else { return }
714793
doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}}

0 commit comments

Comments
 (0)