mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This matches send non sendable but importantly also makes it clear that we are talking about something that doesn't conform to the Sendable protocol which is capitalized. rdar://151802975
159 lines
6.3 KiB
Swift
159 lines
6.3 KiB
Swift
// RUN: %target-typecheck-verify-swift -strict-concurrency=complete -target %target-swift-5.1-abi-triple
|
|
|
|
// REQUIRES: concurrency
|
|
// REQUIRES: asserts
|
|
|
|
|
|
struct CopyableStruct {}
|
|
class Ref { var x = 0 } // expected-note 3{{class 'Ref' does not conform to the 'Sendable' protocol}}
|
|
|
|
struct FileDescriptor: Sendable, ~Copyable {
|
|
var id = 0
|
|
}
|
|
|
|
enum MaybeFile: ~Copyable { // should implicitly conform
|
|
case available(FileDescriptor)
|
|
case closed
|
|
}
|
|
|
|
struct NotSendableMO: ~Copyable {
|
|
var ref: Ref
|
|
}
|
|
|
|
// expect no warnings about sendable conformance when crossing actor boundaries:
|
|
func invalidFile() async -> FileDescriptor {
|
|
return FileDescriptor(id: -1)
|
|
}
|
|
|
|
func takeNotSendable(_ nsmo: borrowing NotSendableMO) async {}
|
|
|
|
actor A {
|
|
init(_ t: __owned FileDescriptor) {}
|
|
init (_ t: __owned MaybeFile) {}
|
|
func takeFileDescriptor(_ fd: __owned FileDescriptor) {}
|
|
func takeMaybeFile(_ mfd: __owned MaybeFile) {}
|
|
func giveFileDescriptor() -> MaybeFile {
|
|
return .closed
|
|
}
|
|
|
|
func getRef() -> NotSendableMO { return NotSendableMO(ref: Ref()) }
|
|
}
|
|
|
|
@MainActor
|
|
func processFiles(_ a: A, _ anotherFile: borrowing FileDescriptor) async {
|
|
let file = await invalidFile()
|
|
await a.takeFileDescriptor(file)
|
|
|
|
await a.takeMaybeFile(.available(anotherFile))
|
|
_ = A(.available(anotherFile))
|
|
|
|
let ns = await a.getRef()
|
|
await takeNotSendable(ns)
|
|
|
|
switch (await a.giveFileDescriptor()) {
|
|
case let .available(fd):
|
|
await a.takeFileDescriptor(fd)
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
func caller() async {
|
|
await processFiles(A(invalidFile()), invalidFile())
|
|
}
|
|
|
|
// now make sure you can't form a Sendable existential from a move-only type.
|
|
|
|
struct RefPair: Sendable, ~Copyable {
|
|
var left: Ref // expected-warning {{stored property 'left' of 'Sendable'-conforming struct 'RefPair' has non-Sendable type 'Ref'}}
|
|
var right: Ref // expected-warning {{stored property 'right' of 'Sendable'-conforming struct 'RefPair' has non-Sendable type 'Ref'}}
|
|
}
|
|
|
|
enum MaybeRef: Sendable, ~Copyable {
|
|
case ref(Ref) // expected-warning {{associated value 'ref' of 'Sendable'-conforming enum 'MaybeRef' has non-Sendable type 'Ref'}}
|
|
case null
|
|
}
|
|
|
|
enum OK_NoncopyableOption<T: Sendable> : Sendable, ~Copyable {
|
|
case some(T)
|
|
case none
|
|
}
|
|
|
|
enum Wrong_NoncopyableOption<T> : Sendable, ~Copyable { // expected-note {{consider making generic parameter 'T' conform to the 'Sendable' protocol}}
|
|
case some(T) // expected-warning {{associated value 'some' of 'Sendable'-conforming generic enum 'Wrong_NoncopyableOption' has non-Sendable type 'T'}}
|
|
case none
|
|
}
|
|
|
|
func takeAnySendable(_ s: any Sendable) {}
|
|
func takeSomeSendable(_ s: some Sendable) {} // expected-note {{'some Sendable & Copyable' is implicit here}}
|
|
|
|
protocol Munchable: ~Copyable {}
|
|
struct Chips: ~Copyable, Sendable, Munchable {}
|
|
func takeSomeMunchySendable(_ s: some Sendable & Munchable) {} // expected-note {{'some Sendable & Munchable & Copyable' is implicit here}}
|
|
|
|
// expected-error@+1 {{return expression of type 'FileDescriptor' does not conform to 'Copyable'}}
|
|
func mkSendable() -> Sendable { return FileDescriptor(id: 0) }
|
|
|
|
func tryToCastIt(_ fd: borrowing FileDescriptor) {
|
|
let _: any Sendable = fd // expected-error {{value of type 'FileDescriptor' does not conform to specified type 'Copyable'}}
|
|
let _: Sendable = fd // expected-error {{value of type 'FileDescriptor' does not conform to specified type 'Copyable'}}
|
|
|
|
takeAnySendable(fd) // expected-error {{argument type 'FileDescriptor' does not conform to expected type 'Copyable'}}
|
|
takeSomeSendable(fd) // expected-error {{global function 'takeSomeSendable' requires that 'FileDescriptor' conform to 'Copyable'}}
|
|
takeSomeMunchySendable(Chips()) // expected-error {{global function 'takeSomeMunchySendable' requires that 'Chips' conform to 'Copyable'}}
|
|
|
|
let _ = fd as Sendable // expected-error {{cannot convert value of type 'FileDescriptor' to type 'any Sendable' in coercion}}
|
|
|
|
let _ = fd as? Sendable // expected-warning {{cast from 'FileDescriptor' to unrelated type 'any Sendable' always fails}}
|
|
// expected-error@-1 {{noncopyable types cannot be conditionally cast}}
|
|
|
|
let _ = fd as! Sendable // expected-warning {{cast from 'FileDescriptor' to unrelated type 'any Sendable' always fails}}
|
|
// expected-error@-1 {{noncopyable types cannot be conditionally cast}}
|
|
|
|
let _ = fd is Sendable // expected-warning {{cast from 'FileDescriptor' to unrelated type 'any Sendable' always fails}}
|
|
// expected-error@-1 {{noncopyable types cannot be conditionally cast}}
|
|
|
|
let sendy = mkSendable()
|
|
let _ = sendy as FileDescriptor // expected-error {{cannot convert value of type 'any Sendable' to type 'FileDescriptor' in coercion}}
|
|
let _ = sendy is FileDescriptor // expected-warning {{cast from 'any Sendable' to unrelated type 'FileDescriptor' always fails}}
|
|
// expected-error@-1 {{noncopyable types cannot be conditionally cast}}
|
|
let _ = sendy as! FileDescriptor // expected-warning {{cast from 'any Sendable' to unrelated type 'FileDescriptor' always fails}}
|
|
// expected-error@-1 {{noncopyable types cannot be conditionally cast}}
|
|
let _ = sendy as? FileDescriptor// expected-warning {{cast from 'any Sendable' to unrelated type 'FileDescriptor' always fails}}
|
|
// expected-error@-1 {{noncopyable types cannot be conditionally cast}}
|
|
}
|
|
|
|
protocol GiveSendable<T> {
|
|
associatedtype T: Sendable // expected-note {{protocol requires nested type 'T'}}
|
|
func give() -> T
|
|
}
|
|
|
|
// make sure witnessing associatedtypes is still prevented, even though we meet the explicit constraint.
|
|
class Bad: GiveSendable {
|
|
// expected-error@-1 {{type 'Bad' does not conform to protocol 'GiveSendable'}}
|
|
// expected-note@-2 {{add stubs for conformance}}
|
|
typealias T = FileDescriptor // expected-note {{possibly intended match 'Bad.T' (aka 'FileDescriptor') does not conform to 'Copyable'}}
|
|
func give() -> FileDescriptor { return FileDescriptor(id: -1) }
|
|
}
|
|
|
|
class Ok: GiveSendable {
|
|
typealias T = CopyableStruct
|
|
func give() -> CopyableStruct { return CopyableStruct() }
|
|
}
|
|
|
|
class Container<T> where T:Sendable {
|
|
var elm: T
|
|
init(_ t: T) { self.elm = t }
|
|
}
|
|
|
|
func createContainer(_ fd: borrowing FileDescriptor) {
|
|
let _: Container<Sendable> = Container(fd) // expected-error {{argument type 'FileDescriptor' does not conform to expected type 'Copyable'}}
|
|
let _: Container<Sendable> = Container(CopyableStruct())
|
|
}
|
|
|
|
struct PaperAirplaneFile: ~Copyable {
|
|
var fd: FileDescriptor
|
|
}
|
|
|
|
extension PaperAirplaneFile: Sendable {}
|