mirror of
https://github.com/apple/swift.git
synced 2026-10-12 14:50:47 +02:00
Follow up to currently-reverted https://github.com/swiftlang/swift/pull/89416. On wasm32 the WebAssembly backend pads the `swiftself` and `swifterror` parameters, which left the indirect typed-error pointer and the `swiftself`/context slot at different LLVM-IR positions for Thin versus Thick async callers; caller and callee then disagreed on which trailing pointer held the typed-error slot and miscompiled async typed-throws calls (#89155: `Result.init(catching:) async` trapped in a value-witness copy on Wasm). With this change `SignatureExpansion::expandAsyncEntryType` now emits `addIndirectThrowingResult` before the `swiftself`/context slot, so the trailing pair is always `[ind_error, swiftself]` and Thin and Thick agree on the position regardless of parameter padding. The result-shape decision moves behind one gate, `hasTrailingAsyncErrorContextPair` (`GenCall.h`), consumed by the three sites that read these slots positionally: `AsyncCallEmission::setFromCallee`, `AsyncPartialApplicationForwarderEmission`, and `AsyncNativeCCEntryPointArgumentEmission::mapAsyncParameters` (the last also pre-extracts the witness-method Self/witness-table that trail the pair). Each consumer carries an assertion that fires if the gate ever diverges from the slots actually filled. Fixes #89320.
70 lines
1.3 KiB
Swift
70 lines
1.3 KiB
Swift
// RUN: %target-run-simple-swift(-target %target-swift-5.1-abi-triple)
|
|
// REQUIRES: executable_test
|
|
// REQUIRES: concurrency
|
|
// REQUIRES: concurrency_runtime
|
|
|
|
import StdlibUnittest
|
|
import Swift
|
|
|
|
let ResultAsyncInitTests = TestSuite("ResultAsyncInit")
|
|
|
|
fileprivate enum Err: Error, Equatable {
|
|
case err
|
|
case derr
|
|
}
|
|
|
|
fileprivate let string = "string"
|
|
|
|
fileprivate extension Result {
|
|
var success: Success? {
|
|
switch self {
|
|
case let .success(success):
|
|
return success
|
|
case .failure:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
var failure: Failure? {
|
|
switch self {
|
|
case .success:
|
|
return nil
|
|
case let .failure(failure):
|
|
return failure
|
|
}
|
|
}
|
|
}
|
|
|
|
ResultAsyncInitTests.test("Async Initialization") {
|
|
func asyncThrowing() async throws -> String {
|
|
throw Err.err
|
|
}
|
|
|
|
func asyncNotThrowing() async throws -> String {
|
|
return string
|
|
}
|
|
|
|
let result1 = await Result { try await asyncThrowing() }
|
|
let result2 = await Result { try await asyncNotThrowing() }
|
|
|
|
expectEqual(result1.failure as? Err, Err.err)
|
|
expectEqual(result2.success, string)
|
|
|
|
do {
|
|
_ = try result1.get()
|
|
} catch let error as Err {
|
|
expectEqual(error, Err.err)
|
|
} catch {
|
|
expectUnreachable()
|
|
}
|
|
|
|
do {
|
|
let unwrapped = try result2.get()
|
|
expectEqual(unwrapped, string)
|
|
} catch {
|
|
expectUnreachable()
|
|
}
|
|
}
|
|
|
|
await runAllTestsAsync()
|