Files
swift-mirror/test/Sema/moveonly_sendable.swift
Michael Gottesman 3b8e384218 Fix another test.
Importantly since this test had a typechecker error within it, we do not get
return value diagnostics anymore since that occurs now at SIL time.
2024-12-02 16:54:13 -05:00

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 {}