Files
swift-mirror/test/Concurrency/sending_continuation.swift
Daniel Rodríguez Troitiño d2d830fc0e [test] Warning about Swift features that do not exist (#77542)
Sometimes features are removed from `Features.def`, but they are not
removed from the test files. The compiler ignores every feature that
does not exist. This leads to removed features still being tested, and
with the introduction of #76740, `REQUIRED:`.

Modify the code that generates the active feature set for testing to
also generate the set of existing features, and pass this list of
existing features to the verifier script. If a feature is trying to be
activated and does not exist, the verifier will warn the user.

- `SwiftParser` feature was renamed `ParserASTGen`, but some tests were
  using both spellings. Remove the mentions of `SwiftParser` in the
  tests.
- `ImportObjcForwardDeclarations` was spelled with upper case `C` in
  a couple of tests. Fix it so the matching is easier.
- `TransferringArgsAndResults` was an experimental feature that was
  removed.
- Ignore the usage of inexisting feature in `swift-export-as.swift`
  because it seems to be what the test is actually testing.
- Ignore the test `availability_define.swift` because it tests the
  pseudo-feature `AvailabilityMacro=` which is not part of
  `Features.def`.
2024-11-12 08:58:53 -08:00

250 lines
8.8 KiB
Swift

// RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -parse-as-library
// REQUIRES: concurrency
////////////////////////
// MARK: Declarations //
////////////////////////
class NonSendableKlass {}
func useValue<T>(_ t: T) {}
func useValueAsync<T>(_ t: T) async {}
/////////////////
// MARK: Tests //
/////////////////
@MainActor
func withCheckedContinuation_1() async -> NonSendableKlass {
await withCheckedContinuation { continuation in
continuation.resume(returning: NonSendableKlass())
}
}
func withCheckedContinuation_1a() async -> NonSendableKlass {
await withCheckedContinuation { continuation in
continuation.resume(returning: NonSendableKlass())
}
}
@MainActor
func withCheckedContinuation_2() async -> NonSendableKlass {
await withCheckedContinuation { continuation in
let x = NonSendableKlass()
continuation.resume(returning: x)
// expected-error @-1 {{sending 'x' risks causing data races}}
// expected-note @-2 {{'x' used after being passed as a 'sending' parameter}}
useValue(x) // expected-note {{access can happen concurrently}}
}
}
func withCheckedContinuation_2a() async -> NonSendableKlass {
await withCheckedContinuation { continuation in
let x = NonSendableKlass()
continuation.resume(returning: x)
// expected-error @-1 {{sending 'x' risks causing data races}}
// expected-note @-2 {{'x' used after being passed as a 'sending' parameter}}
useValue(x) // expected-note {{access can happen concurrently}}
}
}
@MainActor
func withCheckedContinuation_3() async {
// x is main actor isolated since withCheckedContinuation is #isolated.
let x = await withCheckedContinuation { continuation in
let x = NonSendableKlass()
continuation.resume(returning: x)
// expected-error @-1 {{sending 'x' risks causing data races}}
// expected-note @-2 {{'x' used after being passed as a 'sending' parameter}}
useValue(x) // expected-note {{access can happen concurrently}}
}
// Since x is returned as sending from withCheckedContinuation, we can send it
// further.
await useValueAsync(x)
}
func withCheckedContinuation_3a() async {
let x = await withCheckedContinuation { continuation in
let x = NonSendableKlass()
continuation.resume(returning: x)
// expected-error @-1 {{sending 'x' risks causing data races}}
// expected-note @-2 {{'x' used after being passed as a 'sending' parameter}}
useValue(x) // expected-note {{access can happen concurrently}}
}
// This is ok since x is disconnected.
await useValueAsync(x)
}
@MainActor
func withCheckedContinuation_4() async {
// x is main actor isolated since withCheckedContinuation is #isolated.
let y = NonSendableKlass()
let x = await withCheckedContinuation { continuation in
continuation.resume(returning: y)
// expected-error @-1 {{sending 'y' risks causing data races}}
// expected-note @-2 {{main actor-isolated 'y' is passed as a 'sending' parameter}}
useValue(y)
}
// Since withCheckedContinuation returns value as sending, we can call
// useValueAsync since it is disconnected.
await useValueAsync(x)
}
func withCheckedContinuation_4a() async {
// x is main actor isolated since withCheckedContinuation is #isolated.
let y = NonSendableKlass()
let x = await withCheckedContinuation { continuation in
continuation.resume(returning: y)
// expected-error @-1 {{sending 'y' risks causing data races}}
// expected-note @-2 {{task-isolated 'y' is passed as a 'sending' parameter}}
useValue(y)
}
await useValueAsync(x)
}
@MainActor func testAsyncStream() {
let (_, continuation) = AsyncStream.makeStream(of: NonSendableKlass.self)
continuation.yield(NonSendableKlass())
let x = NonSendableKlass()
continuation.yield(x) // expected-error {{sending 'x' risks causing data races}}
// expected-note @-1 {{'x' used after being passed as a 'sending' parameter; Later uses could race}}
useValue(x) // expected-note {{access can happen concurrently}}
}
@MainActor func testAsyncStreamContinuation() {
let _ = AsyncStream(NonSendableKlass.self) { continuation in
continuation.yield(NonSendableKlass())
let x = NonSendableKlass()
continuation.yield(x) // expected-error {{sending 'x' risks causing data races}}
// expected-note @-1 {{'x' used after being passed as a 'sending' parameter; Later uses could race}}
useValue(x) // expected-note {{access can happen concurrently}}
}
}
@MainActor func testAsyncThrowingStream() {
let (_, continuation) = AsyncThrowingStream.makeStream(of: NonSendableKlass.self)
continuation.yield(NonSendableKlass())
let x = NonSendableKlass()
continuation.yield(x) // expected-error {{sending 'x' risks causing data races}}
// expected-note @-1 {{'x' used after being passed as a 'sending' parameter; Later uses could race}}
useValue(x) // expected-note {{access can happen concurrently}}
}
@MainActor func testAsyncThrowingStreamContinuation() {
let _ = AsyncThrowingStream(NonSendableKlass.self) { continuation in
continuation.yield(NonSendableKlass())
let x = NonSendableKlass()
continuation.yield(x) // expected-error {{sending 'x' risks causing data races}}
// expected-note @-1 {{'x' used after being passed as a 'sending' parameter; Later uses could race}}
useValue(x) // expected-note {{access can happen concurrently}}
}
}
@MainActor
func withUnsafeContinuation_1() async -> NonSendableKlass {
await withUnsafeContinuation { continuation in
continuation.resume(returning: NonSendableKlass())
}
}
func withUnsafeContinuation_1a() async -> NonSendableKlass {
await withUnsafeContinuation { continuation in
continuation.resume(returning: NonSendableKlass())
}
}
@MainActor
func withUnsafeContinuation_2() async -> NonSendableKlass {
await withUnsafeContinuation { continuation in
let x = NonSendableKlass()
continuation.resume(returning: x)
// expected-error @-1 {{sending 'x' risks causing data races}}
// expected-note @-2 {{'x' used after being passed as a 'sending' parameter}}
useValue(x) // expected-note {{access can happen concurrently}}
}
}
func withUnsafeContinuation_2a() async -> NonSendableKlass {
await withUnsafeContinuation { continuation in
let x = NonSendableKlass()
continuation.resume(returning: x)
// expected-error @-1 {{sending 'x' risks causing data races}}
// expected-note @-2 {{'x' used after being passed as a 'sending' parameter}}
useValue(x) // expected-note {{access can happen concurrently}}
}
}
@MainActor
func withUnsafeContinuation_3() async {
// x is main actor isolated since withUnsafeContinuation is #isolated.
let x = await withUnsafeContinuation { continuation in
let x = NonSendableKlass()
continuation.resume(returning: x)
// expected-error @-1 {{sending 'x' risks causing data races}}
// expected-note @-2 {{'x' used after being passed as a 'sending' parameter}}
useValue(x) // expected-note {{access can happen concurrently}}
}
// withUnsafeContinuation returns x as sending, so we can pass it to a
// nonisolated function.
await useValueAsync(x)
}
func withUnsafeContinuation_3a() async {
let x = await withUnsafeContinuation { continuation in
let x = NonSendableKlass()
continuation.resume(returning: x)
// expected-error @-1 {{sending 'x' risks causing data races}}
// expected-note @-2 {{'x' used after being passed as a 'sending' parameter}}
useValue(x) // expected-note {{access can happen concurrently}}
}
await useValueAsync(x)
}
@MainActor
func withUnsafeContinuation_4() async {
// x is main actor isolated since withUnsafeContinuation is #isolated.
let y = NonSendableKlass()
let x = await withUnsafeContinuation { continuation in
continuation.resume(returning: y)
// expected-error @-1 {{sending 'y' risks causing data races}}
// expected-note @-2 {{main actor-isolated 'y' is passed as a 'sending' parameter}}
useValue(y)
}
// Since withUnsafeContinuation returns x as sending, we can use it in a
// nonisolated function.
await useValueAsync(x)
}
func withUnsafeContinuation_4a() async {
// x is main actor isolated since withUnsafeContinuation is #isolated.
let y = NonSendableKlass()
let x = await withUnsafeContinuation { continuation in
continuation.resume(returning: y)
// expected-error @-1 {{sending 'y' risks causing data races}}
// expected-note @-2 {{task-isolated 'y' is passed as a 'sending' parameter}}
useValue(y)
}
await useValueAsync(x)
}
public actor WithCheckedThrowingContinuationErrorAvoidance {
nonisolated func handle(reply: (Int) -> Void) {}
// make sure that we do not emit any errors on the following code.
func noError() async throws -> Int {
return try await withCheckedThrowingContinuation { continuation in
handle { result in
continuation.resume(returning: result)
}
}
}
}