Skip to content

Enable test: discarding task group making sure we deinit confidently #67417

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 20, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 74 additions & 19 deletions test/Concurrency/Runtime/async_taskgroup_discarding.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking -parse-as-library) | %FileCheck %s
// TODO: move to target-run-simple-leaks-swift once CI is using at least Xcode 14.3

// rdar://110025115 - Temporarily disable this test
// REQUIRES: rdar110025115

// REQUIRES: concurrency
// REQUIRES: executable_test
// REQUIRES: concurrency_runtime
Expand All @@ -19,29 +16,75 @@ import _Concurrency
final class PayloadFirst {}
final class PayloadSecond {}

actor SimpleCountDownLatch {
let from: Int
var count: Int

var continuation: CheckedContinuation<Void, Never>?

init(from: Int) {
self.from = from
self.count = from
}

func hit() {
defer { count -= 1 }
print("hit @ \(count)")
if count == 0 {
fatalError("Counted down more times than expected! (From: \(from))")
} else if count == 1 {
print("hit resume")
continuation?.resume()
}
}

func wait() async {
guard self.count > 0 else {
return // we're done
}

return await withCheckedContinuation { cc in
self.continuation = cc
}
}
}

final class ErrorFirst: Error {
let first: PayloadFirst
let id: String
let latch: SimpleCountDownLatch

init(file: String = #fileID, line: UInt = #line) {
init(latch: SimpleCountDownLatch, file: String = #fileID, line: UInt = #line) {
self.latch = latch
self.id = "\(file):\(line)"
first = .init()
print("init \(self) id:\(id)")
}
deinit {
print("deinit \(self)")
print("deinit \(self) id:\(id)")
Task { [latch] in await latch.hit() }
}
}

// Should not really matter that different types, but want to make really sure
final class ErrorSecond: Error {
let second: PayloadSecond
let first: PayloadFirst
let id: String
let latch: SimpleCountDownLatch

init(file: String = #fileID, line: UInt = #line) {
second = .init()
init(latch: SimpleCountDownLatch, file: String = #fileID, line: UInt = #line) {
self.latch = latch
self.id = "\(file):\(line)"
first = .init()
print("init \(self) id:\(id)")
}

deinit {
print("deinit \(self)")
print("deinit \(self) id:\(id)")
Task { [latch] in await latch.hit() }
}
}


func shouldStartWith(_ lhs: Any, _ rhs: Any) {
let l = "\(lhs)"
let r = "\(rhs)"
Expand All @@ -50,20 +93,25 @@ func shouldStartWith(_ lhs: Any, _ rhs: Any) {

// NOTE: Not as StdlibUnittest/TestSuite since these types of tests are unreasonably slow to load/debug.

@discardableResult
func one() -> Int {
1
}

@main struct Main {
static func main() async {
let latch = SimpleCountDownLatch(from: 6)
do {

let got = try await withThrowingDiscardingTaskGroup() { group in
group.addTask {
1
}
group.addTask {
throw ErrorFirst()
}
group.addTask { one() }
group.addTask { throw ErrorFirst(latch: latch) }
group.addTask { throw ErrorFirst(latch: latch) }
group.addTask { throw ErrorFirst(latch: latch) }

group.addTask {
throw ErrorSecond()
}
group.addTask { throw ErrorSecond(latch: latch) }
group.addTask { throw ErrorSecond(latch: latch) }
group.addTask { throw ErrorSecond(latch: latch) }

return 12
}
Expand All @@ -73,5 +121,12 @@ func shouldStartWith(_ lhs: Any, _ rhs: Any) {
}
// CHECK: deinit main.Error
// CHECK: deinit main.Error
// CHECK: deinit main.Error

// CHECK: deinit main.Error
// CHECK: deinit main.Error
// CHECK: deinit main.Error
await latch.wait()
print("done") // CHECK: done
}
}