Skip to content

Inconsistent behavior between sending parameter and captured variableΒ #85231

@rayx

Description

@rayx

Description

A sending parameter can be passed down through arbitrary levels of function calls. For example, in this code the first doStuff1 call passes ns to the second doStuff1 call and it compiles. It also compiles if we add the third and more doStuff1 calls.

class NonSendable {}

func doStuff1(_ ns: sending NonSendable, _ fn: sending (sending NonSendable) -> Void) {
    fn(ns)
}

func test1() {
    let ns = NonSendable()
    doStuff1(ns) { ns in 
        doStuff1(ns) { _ in } // This compiles
    }
}

However, this isn't true for captured variables. The following code fails to compile.

func doStuff2(_ fn: sending () -> Void) {
    fn()
}

func test2() {
    let ns = NonSendable()
    doStuff2 {
        doStuff2 {
            print(ns) // error: closure captures 'ns' which is accessible to code in the current task
        }
    }
}

I wonder if there is any fundamental reason why the two behaviors are inconsistent?

Reproduction

See above

Expected behavior

I expect the second example in the report should compile too.

Environment

I used x86-64 swiftc nightly on godbolt and enabled "-swift-version 6" setting.

Additional information

No response

Metadata

Metadata

Assignees

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