Estou migrando para o Swift 6 e recebo um erro enquanto o Swift 5 compila.
O envio de 'newElement' corre o risco de causar disputas de dados
Por que isso acontece e como posso corrigir?
actor AsyncStack<Element> {
private var storage = [Element]()
private var awaiters = [CheckedContinuation<Element,Error>]()
/// Push a new element onto the stack
/// - Parameter newElement: The element to push
/// - Returns: Void
public func push(_ newElement: Element) async -> Void {
if !awaiters.isEmpty {
let awaiter = awaiters.removeFirst()
awaiter.resume(returning: newElement) // ERROR in this line
} else {
storage.insert(newElement, at: 0)
}
}
/// Pop the element at the top of the stack or wait until an element becomes available
/// - Returns: The popped element
public func popOrWait() async throws -> Element {
if let element = storage.popLast() {
return element
}
return try await withCheckedThrowingContinuation { continuation in
awaiters.append(continuation)
}
}
}
Em
push
, você está essencialmente dandonewElement
para algum outro contexto de simultaneidade, enewElement
agora é compartilhado entre o contexto de onde veio, e o contexto para o qual é enviado. Obviamente, isso não é seguro seElement
não forSendable
. Imagine um cenário como este:Você pode marcar o
newElement
parâmetro comosending
Isso essencialmente move a verificação para o lado do chamador. Ao chamar
push
com um tipo não enviávelElement
, o compilador deve ser capaz de deduzir que o chamador nunca mais acessaránewElement
e, portanto, não será compartilhado entre dois contextos de simultaneidade.Ou você pode forçar
Element
a serSendable
: