// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking -parse-as-library) | %FileCheck %s --dump-input=always // REQUIRES: executable_test // REQUIRES: concurrency // REQUIRES: concurrency_runtime // UNSUPPORTED: back_deployment_runtime // UNSUPPORTED: freestanding // FIXME: enable discarding taskgroup on windows; rdar://104762037 // UNSUPPORTED: OS=windows-msvc actor Waiter { let until: Int var count: Int var cc: CheckedContinuation? init(until: Int) { self.until = until self.count = 0 } func increment() { self.count += 1 if self.until <= self.count { if let cc = self.cc { cc.resume(returning: self.count) } } } func wait() async -> Int { if self.until <= self.count { return self.count } return await withCheckedContinuation { cc in self.cc = cc } } } func test_discardingTaskGroup_neverConsume() async { print(">>> \(#function)") let until = 100 let waiter = Waiter(until: until) print("Start tasks: \(until)") let allTasks = await withDiscardingTaskGroup() { group in for n in 1...until { group.addTask { try? await Task.sleep(until: .now + .milliseconds(100), clock: .continuous) await waiter.increment() } } return until } // CHECK: all tasks: 100 print("all tasks: \(allTasks)") } func test_discardingTaskGroup_neverConsume(sleepBeforeGroupWaitAll: Duration) async { print(">>> \(#function)") let until = 100 let waiter = Waiter(until: until) print("Start tasks: \(until)") let allTasks = await withDiscardingTaskGroup() { group in for n in 1...until { group.addTask { try? await Task.sleep(until: .now + .milliseconds(100), clock: .continuous) await waiter.increment() } } // wait a little bit, so some tasks complete before we hit the implicit "wait at end of task group scope" try? await Task.sleep(until: .now + sleepBeforeGroupWaitAll, clock: .continuous) return until } // CHECK: all tasks: 100 print("all tasks: \(allTasks)") } func test_discardingTaskGroup_bigReturn() async { print(">>> \(#function)") // Test returning a very large value to ensure we don't overflow memory. let array = await withDiscardingTaskGroup { group in group.addTask {} try? await Task.sleep(until: .now + .milliseconds(100), clock: .continuous) // InlineArray.init(repeating:) uses a lot of stack space with optimizations // disabled, so set one up in a less friendly but less stack-consuming way. let ptr = UnsafeMutablePointer>.allocate(capacity: 1) ptr.withMemoryRebound(to: Int.self, capacity: 32768) { $0.initialize(repeating: 12345, count: 32768) } // Deliberately leak `ptr` to avoid needing to save any temporaries. return ptr.pointee } // CHECK: Huge return value produced: 12345 12345 print("Huge return value produced:", array[0], array[32767]) } @main struct Main { static func main() async { await test_discardingTaskGroup_neverConsume() await test_discardingTaskGroup_neverConsume(sleepBeforeGroupWaitAll: .milliseconds(500)) await test_discardingTaskGroup_bigReturn() } }