Skip to content

Missing diagnostic when capturing self in deinit Task #72893

Closed
@rnapier

Description

@rnapier

Description

While there are many valid reasons to pass self as a parameter in deinit, it is never valid to capture it in a Task. This is discussed by @mikeash in #62191 (comment):

But capturing self with a Task or async dispatch is pretty much guaranteed to be wrong, so a warning should be doable for those specific cases.

Doing so should generate a warning.

Reproduction

@MainActor class Service {
    func doThings() {}
}

@MainActor class Controller {
    let service: Service

    init(service: Service) { self.service = service }

    func printMe() { print("Controller lives") }

    deinit {
        print("Controller deinit")
        Task { @MainActor in
            service.doThings()
        }
    }
}

let service = Service()

do {
    let controller = Controller(service: service)
    controller.printMe()
}

Expected behavior

As written, this code will crash, but no diagnostic will be printed in the deinit. If a [service] capture is added to the Task, then this code is fine. It is tricky for developers to understand this subtle difference (self does not even appear in deinit).

An ideal diagnostic would guide them to the proper capture. If no such capture can solve this, then the diagnostic should still indicate the problem.

Environment

swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
Target: arm64-apple-macosx14.0

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugA deviation from expected or documented behavior. Also: expected but undesirable behavior.concurrencyFeature: umbrella label for concurrency language features

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions