Are concurrent methods on isolated conformances actually safe?

I did more experiments on this issue. Below is my summary.

TLDR: the behavior is inconsistent between Swift 6.3.3 and nightly; changing code slightly causes inconsistent behaviors in nightly too.

(Note: I didn't use 6.4 because it's not available on compiler explorer).

The setup:

protocol AsyncRequirement {
  @concurrent func work() async
}

@MainActor
class ConformingType: @MainActor AsyncRequirement {
  func work() async {
  }
}

func test1() -> some AsyncRequirement {
  ConformingType()
}

func test2() {
  let value: some AsyncRequirement = ConformingType()
  _ = value
}

@MainActor
func test3() {
  let value: some AsyncRequirement = ConformingType()
  _ = value
}

nonisolated(nonsending)
func test4() async {
  let value: some AsyncRequirement = ConformingType()
  _ = value
}

nonisolated(nonsending)
func test5() async {
  let value: some AsyncRequirement = ConformingType()
  await value.work()
}

Test results:

  1. test3 compiles in all Swift versions. This is as expected.

  2. Swift 6.3.3: All tests except test3 fail to compile and ouput the same error.

    error: main actor-isolated conformance of 'ConformingType' to 'AsyncRequirement' cannot be used in caller isolation ... context [#IsolatedConformances]
    

    I think the behavior is simple, consistent, and easy to understand.

  3. Nightly: tests have different behaviors

    • test1 and test2: fail with the same error as in Swift 6.3.3.
    • test4: it compiles. No warning or error.
    • test5: it compiles with a warning (the one @mattie mentioned in the original post)

    I probably understand the different behaviors of test4 and test5. It appears that isolated conformance implementation in recent releases is different from what's proposed in the original proposal. Compiler produces diagnostic only when the code would actually call methods of isolated confomrance in a different isolation (see my earlier question about this). But if test4 compiles, I think test1 and test2 should compile too?

Another test. It does the same as test5 but uses generic function. It fails to compile in nightly. Note the "cannot satisfy conformance requirement for a 'Sendable' type parameter" part in the error message. I don't quite understand what it meant.

nonisolated(nonsending) func useThem<T: AsyncRequirement & Sendable>(value: T) async {
  await value.work()
}

nonisolated(nonsending) func test6() async {
    useThem(value: ConformingType()) // error: main actor-isolated conformance of 'ConformingType' to 'AsyncRequirement' cannot satisfy conformance requirement for a 'Sendable' type parameter  [#IsolatedConformances]
}

I'd appreciate if anyone in Swift team can clarify if the behaviors in nightly is by design or a regression.

1 Like