-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Fix issue where implicit self was unexpectedly not allowed in nested weak self closure in Swift 6 mode #78738
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e6a2230
8557e23
f2cda5e
be0e68e
684c908
041c685
31528da
64fc43e
14632b7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -454,6 +454,92 @@ class TestGithubIssue70089 { | |
} | ||
} | ||
} | ||
|
||
func testClosuresInsideWeakSelfNotUnwrapped() { | ||
// https://forums.swift.org/t/nested-weak-capture-and-implicit-self-in-swift-6/77230/1 | ||
doVoidStuff { [weak self] in | ||
doVoidStuff { [weak self] in | ||
guard let self else { return } | ||
x += 1 | ||
} | ||
} | ||
|
||
doVoidStuff { [weak self] in | ||
doVoidStuff { [weak self] in | ||
doVoidStuff { [weak self] in | ||
guard let self else { return } | ||
doVoidStuff { [weak self] in | ||
doVoidStuff { [weak self] in | ||
guard let self else { return } | ||
x += 1 | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
doVoidStuff { [weak self] in | ||
doVoidStuff { [weak self] in | ||
guard let self else { return } | ||
doVoidStuff { [self] in | ||
doVoidStuff { [self] in | ||
doVoidStuff { [weak self] in | ||
guard let self else { return } | ||
x += 1 | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
doVoidStuff { [weak self] in | ||
guard let self = self ?? TestGithubIssue70089.staticOptional else { return } | ||
doVoidStuff { [weak self] in | ||
guard let self else { return } | ||
x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} | ||
} | ||
} | ||
|
||
doVoidStuff { [weak self] in | ||
doVoidStuff { [self] in | ||
x += 1 // expected-error {{explicit use of 'self' is required when 'self' is optional, to make control flow explicit}} expected-note{{reference 'self?.' explicitly}} | ||
} | ||
} | ||
|
||
doVoidStuff { [weak self] in | ||
doVoidStuff { [self] in | ||
self.x += 1 // expected-error {{value of optional type 'TestGithubIssue70089?' must be unwrapped to refer to member 'x' of wrapped base type 'TestGithubIssue70089'}} expected-note {{chain the optional using '?' to access member 'x' only for non-'nil' base values}} expected-note{{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} | ||
} | ||
} | ||
|
||
doVoidStuff { [weak self] in | ||
doVoidStuff { [self] in | ||
self?.x += 1 | ||
} | ||
} | ||
|
||
doVoidStuff { [weak self] in | ||
doVoidStuff { [self] in | ||
guard let self else { return } | ||
self.x += 1 | ||
} | ||
} | ||
|
||
doVoidStuff { [weak self] in | ||
doVoidStuff { [self] in | ||
guard let self else { return } | ||
x += 1 | ||
} | ||
} | ||
|
||
doVoidStuff { [weak self] in | ||
guard let self = self ?? TestGithubIssue70089.staticOptional else { return } | ||
doVoidStuff { [self] in | ||
guard let self else { return } // expected-error{{initializer for conditional binding must have Optional type, not 'TestGithubIssue70089'}} | ||
x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} | ||
} | ||
} | ||
} | ||
} | ||
|
||
class TestGithubIssue69911 { | ||
|
@@ -522,9 +608,9 @@ class TestGithubIssue69911 { | |
self.x += 1 | ||
} | ||
|
||
doVoidStuffNonEscaping { | ||
doVoidStuffNonEscaping { // expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} | ||
doVoidStuffNonEscaping { | ||
x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} | ||
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}} | ||
self.x += 1 | ||
} | ||
} | ||
|
@@ -670,7 +756,7 @@ final class AutoclosureTests { | |
doVoidStuff { [weak self] in | ||
doVoidStuff { [self] in | ||
guard let self else { return } | ||
method() // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The explicit self version of this has been supported since at least Swift 4.2 so it seems perfectly fine for the implicit self version to be supported There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah this seems reasonable to me, this is the case that came up last time |
||
method() | ||
} | ||
} | ||
|
||
|
@@ -702,13 +788,6 @@ final class AutoclosureTests { | |
} | ||
} | ||
|
||
doVoidStuff { [weak self] in | ||
doVoidStuff { [self] in | ||
guard let self else { return } | ||
method() // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} | ||
} | ||
} | ||
|
||
doVoidStuff { [weak self] in | ||
guard let self = self else { return } | ||
doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} | ||
|
@@ -844,3 +923,118 @@ class rdar129475277 { | |
} | ||
} | ||
} | ||
|
||
class TestExtensionOnOptionalSelf { | ||
init() {} | ||
func bar() {} | ||
} | ||
|
||
extension TestExtensionOnOptionalSelf? { | ||
func foo() { | ||
_ = { [weak self] in | ||
foo() // expected-error {{implicit use of 'self' in closure; use 'self.' to make capture semantics explicit}} | ||
} | ||
|
||
_ = { | ||
foo() | ||
self.foo() | ||
self?.bar() | ||
} | ||
|
||
_ = { [weak self] in | ||
_ = { | ||
foo() // expected-error {{implicit use of 'self' in closure; use 'self.' to make capture semantics explicit}} | ||
self.foo() | ||
self?.bar() | ||
} | ||
} | ||
|
||
_ = { [weak self] in | ||
_ = { [self] in | ||
foo() | ||
self.foo() | ||
self?.bar() | ||
} | ||
} | ||
} | ||
} | ||
|
||
// non-optional self in this extension, but on a type with members defined on optional self | ||
extension TestExtensionOnOptionalSelf { | ||
func foo() { | ||
_ = { [weak self] in | ||
foo() // expected-error {{implicit use of 'self' in closure; use 'self.' to make capture semantics explicit}} | ||
self.foo() | ||
self?.bar() | ||
} | ||
|
||
_ = { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} | ||
foo() // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} | ||
self.foo() | ||
} | ||
|
||
_ = { [weak self] in | ||
_ = { | ||
foo() // expected-error {{implicit use of 'self' in closure; use 'self.' to make capture semantics explicit}} | ||
self.foo() | ||
} | ||
} | ||
|
||
_ = { [weak self] in | ||
_ = { [self] in | ||
foo() | ||
self.foo() | ||
} | ||
} | ||
|
||
_ = { [weak self] in | ||
_ = { [self] in | ||
_ = { [self] in | ||
foo() | ||
self.foo() | ||
} | ||
} | ||
} | ||
|
||
_ = { [weak self] in | ||
doVoidStuffNonEscaping { | ||
_ = { [self] in | ||
foo() | ||
self.foo() | ||
} | ||
} | ||
} | ||
|
||
_ = { [weak self] in | ||
guard case let self = self else { return } | ||
_ = { [self] in | ||
foo() | ||
} | ||
} | ||
} | ||
} | ||
|
||
actor TestActor { | ||
func setUp() { | ||
doVoidStuff { [weak self] in | ||
Task { [weak self] in | ||
guard let self else { return } | ||
await test() | ||
} | ||
} | ||
} | ||
|
||
@MainActor | ||
func test() { } | ||
} | ||
Comment on lines
+1017
to
+1029
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here's a test case from another issue that was filed recently about this same bug: #79014 |
||
|
||
class C { | ||
func foo() { | ||
_ = { [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}} | ||
guard case let self = C() else { return } | ||
_ = { [self] in | ||
foo() // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks funny but has been allowed since at least Swift 4.2: https://swiftfiddle.com/irzj67qcezajlj7u5hyq4te2fq