Skip to content

Commit 3708ef0

Browse files
committed
Add more test cases, simplify logic
1 parent f2cda5e commit 3708ef0

File tree

3 files changed

+132
-32
lines changed

3 files changed

+132
-32
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1841,15 +1841,15 @@ class ImplicitSelfUsageChecker : public BaseDiagnosticWalker {
18411841

18421842
return selfDeclAllowsImplicitSelf(DRE->getDecl(), ty, inClosure,
18431843
/*validateParentClosures:*/ true,
1844-
/*validateSelfRebindings:*/ true);
1844+
/*validatingNestedClosure:*/ false);
18451845
}
18461846

18471847
/// Whether or not implicit self is allowed for this implicit self decl
18481848
static bool selfDeclAllowsImplicitSelf(const ValueDecl *selfDecl,
18491849
const Type captureType,
18501850
const AbstractClosureExpr *inClosure,
18511851
bool validateParentClosures,
1852-
bool validateSelfRebindings) {
1852+
bool validatingNestedClosure) {
18531853
ASTContext &ctx = inClosure->getASTContext();
18541854

18551855
auto requiresSelfQualification =
@@ -1883,38 +1883,35 @@ class ImplicitSelfUsageChecker : public BaseDiagnosticWalker {
18831883
}
18841884
}
18851885

1886-
// If the self decl comes from a conditional statement, validate
1887-
// that it is an allowed `guard let self` or `if let self` condition.
1886+
// If the self decl refers to a `guard let self` / `if let self` conditon,
1887+
// we need to validate it.
1888+
auto selfDeclDefinedInConditionalStmt = false;
1889+
auto isInvalidSelfDeclRebinding = false;
1890+
if (auto condStmt = parentConditionalStmt(selfDecl)) {
1891+
selfDeclDefinedInConditionalStmt = true;
1892+
isInvalidSelfDeclRebinding = !hasValidSelfRebinding(condStmt, ctx);
1893+
}
1894+
1895+
// If the self decl refers to an invalid unwrapping conditon like
1896+
// `guard let self = somethingOtherThanSelf`, then implicit self is always
1897+
// disallowed.
18881898
// - Even if this closure doesn't have a `weak self` capture, it could
18891899
// be a closure nested in some parent closure with a `weak self`
18901900
// capture, so we should always validate the conditional statement
18911901
// that defines self if present.
1892-
if (validateSelfRebindings) {
1893-
if (auto conditionalStmt = parentConditionalStmt(selfDecl)) {
1894-
if (!hasValidSelfRebinding(conditionalStmt, ctx)) {
1895-
return false;
1896-
}
1897-
}
1902+
if (isInvalidSelfDeclRebinding) {
1903+
return false;
18981904
}
18991905

1900-
// If this closure has a `weak self` capture, require that the
1901-
// closure unwraps self. If not, implicit self is not allowed
1902-
// in this closure or in any nested closure.
1903-
if (closureHasWeakSelfCapture(inClosure)) {
1904-
// If a `guard let self` or `if let self` unbinding condition exists,
1905-
// then it must not be invalid.
1906-
if (auto condStmt = parentConditionalStmt(selfDecl)) {
1907-
if (!hasValidSelfRebinding(condStmt, ctx)) {
1908-
return false;
1909-
}
1910-
}
1911-
1912-
// If the self decl hasn't been unwrapped, then this closure is
1913-
// invalid unless non-unwrapped weak self is explicitly enabled
1914-
// in this situation.
1915-
else if (validateSelfRebindings) {
1916-
return false;
1917-
}
1906+
// Within a closure with a `[weak self]` capture, implicit self is only
1907+
// allowed if self has been unwrapped in a previous conditional statement.
1908+
// - When validating implicit self usage in a nested closure, it's not
1909+
// necessary for
1910+
// self to be unwrapped in this parent closure. If self isn't unwrapped
1911+
// correctly in the nested closure, we would have already noticed.
1912+
if (closureHasWeakSelfCapture(inClosure) &&
1913+
!selfDeclDefinedInConditionalStmt && !validatingNestedClosure) {
1914+
return false;
19181915
}
19191916

19201917
if (auto autoclosure = dyn_cast<AutoClosureExpr>(inClosure)) {
@@ -2068,7 +2065,7 @@ class ImplicitSelfUsageChecker : public BaseDiagnosticWalker {
20682065
if (!selfDeclAllowsImplicitSelf(outerSelfDecl, captureType,
20692066
outerClosure,
20702067
/*validateParentClosures:*/ false,
2071-
/*validateSelfRebindings:*/ false)) {
2068+
/*validatingNestedClosure:*/ true)) {
20722069
return outerClosure;
20732070
}
20742071

@@ -2082,7 +2079,7 @@ class ImplicitSelfUsageChecker : public BaseDiagnosticWalker {
20822079
if (validateIntermediateParents) {
20832080
if (!selfDeclAllowsImplicitSelf(selfDecl, captureType, outerClosure,
20842081
/*validateParentClosures*/ false,
2085-
/*validateSelfRebindings*/ false)) {
2082+
/*validatingNestedClosure*/ true)) {
20862083
return outerClosure;
20872084
}
20882085
}

test/expr/closure/closures.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,6 +1407,13 @@ class TestGithubIssue69911 {
14071407
}
14081408
}
14091409

1410+
doVoidStuff { [weak self] in
1411+
guard let self = self ?? TestGithubIssue69911.staticOptional else { return }
1412+
doVoidStuff { [self] in // expected-warning {{capture 'self' was never used}} expeced-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'}}
1413+
x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
1414+
}
1415+
}
1416+
14101417
doVoidStuff { [weak self] in
14111418
// Since this unwrapping is invalid, implicit self is disallowed in all nested closures:
14121419
guard let self = self ?? TestGithubIssue69911.staticOptional else { return }
@@ -1804,3 +1811,31 @@ class TestLazyLocal {
18041811
}
18051812
}
18061813
}
1814+
1815+
class TestExtensionOnOptionalSelf {
1816+
init() {}
1817+
}
1818+
1819+
extension TestExtensionOnOptionalSelf? {
1820+
func foo() {
1821+
_ = { [weak self] in // expected-warning {{variable 'self' was written to, but never read}}
1822+
foo() // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}}
1823+
}
1824+
1825+
_ = {
1826+
foo()
1827+
}
1828+
1829+
_ = { [weak self] in // expected-warning {{variable 'self' was written to, but never read}}
1830+
_ = {
1831+
foo()
1832+
}
1833+
}
1834+
1835+
_ = { [weak self] in
1836+
_ = { [self] in // expected-warning {{capture 'self' was never used}}
1837+
foo()
1838+
}
1839+
}
1840+
}
1841+
}

test/expr/closure/closures_swift6.swift

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -608,9 +608,9 @@ class TestGithubIssue69911 {
608608
self.x += 1
609609
}
610610

611-
doVoidStuffNonEscaping {
611+
doVoidStuffNonEscaping { // expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}}
612612
doVoidStuffNonEscaping {
613-
x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
613+
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}}
614614
self.x += 1
615615
}
616616
}
@@ -647,6 +647,12 @@ class TestGithubIssue69911 {
647647
}
648648
}
649649
}
650+
651+
doVoidStuff { [weak self] in
652+
doVoidStuff { [self] in // expected-error {{value of optional type 'TestGithubIssue69911?' must be unwrapped to a value of type 'TestGithubIssue69911'}} expected-note{{coalesce using '??' to provide a default when the optional value contains 'nil'}} expected-note{{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}
653+
x += 1
654+
}
655+
}
650656
}
651657
}
652658

@@ -923,3 +929,65 @@ class rdar129475277 {
923929
}
924930
}
925931
}
932+
933+
class TestExtensionOnOptionalSelf {
934+
init() {}
935+
func bar() {}
936+
}
937+
938+
extension TestExtensionOnOptionalSelf? {
939+
func foo() {
940+
_ = { [weak self] in
941+
foo() // expected-error {{implicit use of 'self' in closure; use 'self.' to make capture semantics explicit}}
942+
self.foo()
943+
self?.bar()
944+
}
945+
946+
_ = {
947+
foo()
948+
self.foo()
949+
self?.bar()
950+
}
951+
952+
_ = { [weak self] in
953+
_ = {
954+
foo()
955+
self.foo()
956+
self?.bar()
957+
}
958+
}
959+
960+
_ = { [weak self] in
961+
_ = { [self] in
962+
foo()
963+
self.foo()
964+
self?.bar()
965+
}
966+
}
967+
}
968+
}
969+
970+
actor TestActor {
971+
func setUp() {
972+
doVoidStuff { [weak self] in
973+
Task { [weak self] in
974+
guard let self else { return }
975+
await test()
976+
}
977+
}
978+
}
979+
980+
@MainActor
981+
func test() { }
982+
}
983+
984+
class C {
985+
func foo() {
986+
_ = { [self] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} expected-warning {{capture 'self' was never used}}
987+
guard case let self = C() else { return }
988+
_ = { [self] in
989+
foo() // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}}
990+
}
991+
}
992+
}
993+
}

0 commit comments

Comments
 (0)