Merge pull request #85341 from mikeash/fix-complex-equality-executor-bitcast

[Concurrency] Fix asSerialExecutor() for complex equality.
This commit is contained in:
Mike Ash
2025-11-07 22:45:09 -05:00
committed by GitHub
2 changed files with 12 additions and 1 deletions

View File

@@ -808,7 +808,13 @@ public struct UnownedSerialExecutor: Sendable {
@available(StdlibDeploymentTarget 6.2, *)
public func asSerialExecutor() -> (any SerialExecutor)? {
return unsafe unsafeBitCast(executor, to: (any SerialExecutor)?.self)
// The low bits of the witness table are used to encode the executor kind.
// any SerialExecutor needs a raw witness table pointer, so mask off the low
// bits, knowing the witness table pointer is aligned to the pointer size.
let rawExecutorData = unsafe unsafeBitCast(executor, to: (UInt, UInt).self)
let mask = ~(UInt(MemoryLayout<UnsafeRawPointer>.alignment) - 1)
let alignedExecutor = unsafe (rawExecutorData.0, rawExecutorData.1 & mask)
return unsafe unsafeBitCast(alignedExecutor, to: (any SerialExecutor)?.self)
}
}

View File

@@ -66,6 +66,11 @@ actor MyActor {
func test(expectedExecutor: NaiveQueueExecutor, expectedQueue: DispatchQueue) {
expectedExecutor.preconditionIsolated("Expected deep equality to trigger for \(expectedExecutor) and our \(self.executor)")
// Ensure we get a usable value from asSerialExecutor() when the executor
// has complex equality.
_ = expectedExecutor.asUnownedSerialExecutor().asSerialExecutor()!.asUnownedSerialExecutor()
print("\(Self.self): [\(self.executor.name)] on same context as [\(expectedExecutor.name)]")
}
}