I have a setup where an actor (a database) has a method returning non-sendable types using the sending keyword. I need to call that method from elsewhere (inside a transaction struct) which is always run on the actor (database). I've been using assumeIsolated in the Swift 5 language mode, but that is now an error in Swift 6 because the type returned by the actor is not Sendable. I believe this would be resolved if assumeIsolated adopts sending. I'd be happy to get a pull request going if this makes sense.
Is there a workaround I can use in the meantime? I tried using nonisolated(unsafe) in various places but that didn't seem to work.
class Nonsendable { }
actor Actor {
func newNonsendable() -> sending NonSendable {
NonSendable()
}
}
let myActor = Actor()
func alwaysCalledFromActor() -> NonSendable {
myActor.assumeIsolated { // Type 'Nonsendable' does not conform to the 'Sendable' protocol
$0.newNonsendable()
}
}
I wonder if I can propagate isolation statically somehow โ the setup is an actor (the database) which has a transaction method that looks roughly like this:
TransactionContext has a reference to the database actor to provide read access inside the transaction closure. Since a transaction is only ever run on the database actor, Iโve been using assumeIsolated inside TransactionContext to provide synchronous access to the database.
You can have a look at that, using it you could express things { [isolated something] in ... } in closures. It may need even more flexibility to achieve the kind of thing you're asking for ("know that context is always on some of it's member, which is an actor" etc), but that's certainly a step towards more control over isolation of closures.
That proposal didn't make it into Swift 6.0 though, but keep an eye out for it.