swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.58k stars 10.36k forks source link

[Concurrency][SE-0434] Treat captured local globally-isolated functions as `Sendable` #73562

Open simanerush opened 6 months ago

simanerush commented 6 months ago

Description

No response

Reproduction

func test() {
  @MainActor func f() {} // ⚠️
  Task {
    await f() // ⚠️
  }
}

Expected behavior

The above should compile under SE-0434, because f is globally-isolated.

Environment

Swift version 6.0-dev (LLVM ceb203a206ed550, Swift a5fdf158dc4292a)

Additional information

No response

simanerush commented 2 months ago

Update: the code in this issue already works, but the following (reduced from #75799) doesn't:

func usesFunction(_ block: @escaping @Sendable () -> Void) {}

func test () {
  let closure: @MainActor () -> Void = {}
  @MainActor func f() {}

    usesFunction {
        Task {
            await closure() // ⚠️
            await f() // ⚠️
        }
    }
}
swhitty commented 2 months ago

I guess this is the same issue I'm seeing with this reproduction;

public struct Bar {
    @MainActor func bar() { }
}

func append(_ body: @MainActor () -> Void) { }

append(Bar().bar) // ⚠️ Converting non-sendable function value to '@MainActor @Sendable () -> Void' may introduce data races

If I mark Bar: Sendable (or internal so its inferred) then it's fine

or jump through another closure that must infer @Sendable

append { Bar().bar() }  ✅