mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
This will ensure that we do not break anyone who has adopted APIs like
CheckedContinuation.resume that now have sending parameters.
An example of where this can come up is shown by the ProcessType in SwiftToolsCore:
```swift
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
@discardableResult
public func waitUntilExit() async throws -> ProcessResult {
try await withCheckedThrowingContinuation { continuation in
DispatchQueue.processConcurrent.async {
self.waitUntilExit(continuation.resume(with:))
}
}
}
```
This fails to compile since self.waitUntilExit doesn't expect a function that
takes a sending parameter. We want to give people time to fix such issues.
112 lines
6.2 KiB
Swift
112 lines
6.2 KiB
Swift
// RUN: %target-typecheck-verify-swift -swift-version 6
|
|
|
|
// READ THIS! This file only contains tests that validate that the relevant
|
|
// function subtyping rules for sending work. Please do not put other tests in
|
|
// the file!
|
|
|
|
// REQUIRES: concurrency
|
|
// REQUIRES: asserts
|
|
|
|
////////////////////////
|
|
// MARK: Declarations //
|
|
////////////////////////
|
|
|
|
class NonSendableKlass {}
|
|
|
|
protocol ProtocolWithSendingReqs {
|
|
func sendingResult() -> sending NonSendableKlass // expected-note {{}}
|
|
func nonSendingParam(_ x: NonSendableKlass) // expected-note {{}}
|
|
}
|
|
|
|
protocol ProtocolWithMixedReqs {
|
|
func nonSendingParamAndSendingResult(_ x: NonSendableKlass) -> sending NonSendableKlass // expected-note 4{{}}
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// MARK: Normal Function Tests //
|
|
/////////////////////////////////
|
|
|
|
func functionWithSendingResult() -> sending NonSendableKlass { fatalError() }
|
|
func functionWithoutSendingResult() -> NonSendableKlass { fatalError() }
|
|
func functionWithSendingParameter(_ x: sending NonSendableKlass) { fatalError() }
|
|
func functionWithoutSendingParameter(_ x: NonSendableKlass) { fatalError() }
|
|
|
|
func takeFnWithSendingResult(_ fn: () -> sending NonSendableKlass) {}
|
|
func takeFnWithoutSendingResult(_ fn: () -> NonSendableKlass) {}
|
|
func takeFnWithSendingParam(_ fn: (sending NonSendableKlass) -> ()) {}
|
|
func takeFnWithoutSendingParam(_ fn: (NonSendableKlass) -> ()) {}
|
|
|
|
func testFunctionMatching() {
|
|
let _: (NonSendableKlass) -> () = functionWithSendingParameter
|
|
// expected-error @-1 {{converting a value of type '@Sendable (sending NonSendableKlass) -> ()' to type '(NonSendableKlass) -> ()' risks causing data races}}
|
|
// expected-note @-2 {{converting a function typed value with a sending parameter to one without risks allowing actor-isolated values to escape their isolation domain as an argument to an invocation of value}}
|
|
let _: (sending NonSendableKlass) -> () = functionWithSendingParameter
|
|
|
|
let _: (NonSendableKlass) -> () = functionWithoutSendingParameter
|
|
let _: (sending NonSendableKlass) -> () = functionWithoutSendingParameter
|
|
|
|
takeFnWithSendingParam(functionWithSendingParameter)
|
|
takeFnWithoutSendingParam(functionWithSendingParameter)
|
|
// expected-error @-1 {{converting a value of type '@Sendable (sending NonSendableKlass) -> ()' to type '(NonSendableKlass) -> ()' risks causing data races}}
|
|
// expected-note @-2 {{converting a function typed value with a sending parameter to one without risks allowing actor-isolated values to escape their isolation domain as an argument to an invocation of value}}
|
|
takeFnWithSendingParam(functionWithoutSendingParameter)
|
|
takeFnWithoutSendingParam(functionWithoutSendingParameter)
|
|
}
|
|
|
|
func testReturnValueMatching() {
|
|
let _: () -> NonSendableKlass = functionWithSendingResult
|
|
let _: () -> sending NonSendableKlass = functionWithSendingResult
|
|
let _: () -> NonSendableKlass = functionWithoutSendingResult
|
|
let _: () -> sending NonSendableKlass = functionWithoutSendingResult
|
|
// expected-error @-1 {{converting a value of type '@Sendable () -> NonSendableKlass' to type '() -> sending NonSendableKlass' risks causing data races}}
|
|
// expected-note @-2 {{converting a function typed value without a sending result as one with risks allowing actor-isolated values to escape their isolation domain through a result of an invocation of value}}
|
|
|
|
takeFnWithSendingResult(functionWithSendingResult)
|
|
takeFnWithSendingResult(functionWithoutSendingResult)
|
|
// expected-error @-1 {{converting a value of type '@Sendable () -> NonSendableKlass' to type '() -> sending NonSendableKlass' risks causing data races}}
|
|
// expected-note @-2 {{converting a function typed value without a sending result as one with risks allowing actor-isolated values to escape their isolation domain through a result of an invocation of value}}
|
|
let x: () -> NonSendableKlass = { fatalError() }
|
|
takeFnWithSendingResult(x)
|
|
// expected-error @-1 {{converting a value of type '() -> NonSendableKlass' to type '() -> sending NonSendableKlass' risks causing data races}}
|
|
// expected-note @-2 {{converting a function typed value without a sending result as one with risks allowing actor-isolated values to escape their isolation domain through a result of an invocation of value}}
|
|
|
|
takeFnWithoutSendingResult(functionWithSendingResult)
|
|
takeFnWithoutSendingResult(functionWithoutSendingResult)
|
|
takeFnWithoutSendingResult(x)
|
|
}
|
|
|
|
//////////////////////////
|
|
// MARK: Protocol Tests //
|
|
//////////////////////////
|
|
|
|
struct MatchSuccess : ProtocolWithSendingReqs, ProtocolWithMixedReqs {
|
|
func sendingResult() -> sending NonSendableKlass { fatalError() }
|
|
func nonSendingParam(_ x: NonSendableKlass) -> () { fatalError() }
|
|
func nonSendingParamAndSendingResult(_ x: NonSendableKlass) -> sending NonSendableKlass { fatalError() }
|
|
}
|
|
|
|
struct FailToMatch : ProtocolWithSendingReqs, ProtocolWithMixedReqs { // expected-error 2{{}}
|
|
func sendingResult() -> NonSendableKlass { fatalError() }
|
|
// expected-note @-1 {{candidate has non-matching type '() -> NonSendableKlass'}}
|
|
func nonSendingParam(_ x: sending NonSendableKlass) -> () { fatalError() }
|
|
// expected-note @-1 {{candidate has non-matching type '(sending NonSendableKlass) -> ()'}}
|
|
func nonSendingParamAndSendingResult(_ x: sending NonSendableKlass) -> NonSendableKlass { fatalError() }
|
|
// expected-note @-1 {{candidate has non-matching type '(sending NonSendableKlass) -> NonSendableKlass'}}
|
|
}
|
|
|
|
struct FailToMatch2 : ProtocolWithMixedReqs { // expected-error {{}}
|
|
func nonSendingParamAndSendingResult(_ x: sending NonSendableKlass) -> NonSendableKlass { fatalError() }
|
|
// expected-note @-1 {{candidate has non-matching type '(sending NonSendableKlass) -> NonSendableKlass'}}
|
|
}
|
|
|
|
struct FailToMatch3 : ProtocolWithMixedReqs { // expected-error {{}}
|
|
func nonSendingParamAndSendingResult(_ x: NonSendableKlass) -> NonSendableKlass { fatalError() }
|
|
// expected-note @-1 {{candidate has non-matching type '(NonSendableKlass) -> NonSendableKlass'}}
|
|
}
|
|
|
|
struct FailToMatch4 : ProtocolWithMixedReqs { // expected-error {{}}
|
|
func nonSendingParamAndSendingResult(_ x: sending NonSendableKlass) -> sending NonSendableKlass { fatalError() }
|
|
// expected-note @-1 {{candidate has non-matching type '(sending NonSendableKlass) -> sending NonSendableKlass'}}
|
|
}
|
|
|