This is a question, but maybe also a bug report.
At my employer, we use a combination of swift_task_enqueueGlobal_hook and Task priorities to manage the order that jobs are executed in. A coworker was recently examining a test harness that uses this strategy, and decided to see what would happen if he removed our task_enqueue hook (which moves everything to MainActor). He was surprised to discover that the code immediately crashed in Task.init.
We later narrowed the problem down the following reproducer:
await withTaskGroup { group in
group.addTask {
Task(
priority: .init(rawValue: 28)
) {} // crashes in `dispatch_async_swift_job
}
}
In the Swift 5 language mode, this code also causes the same crash:
Task(
priority: .init(rawValue: 28)
) {}
But it doesn't happen in Swift 6. I'm not clear on why.
A "fix" for these is to only use "official" built in values like .low, .high, or .userInitiated. Another "fix" is to mark the Task as @MainActor, implying that how this function behaves is down to the implementation of the executor that's in use.
We went looking for an explanation and were surprised to discover that it uses some part of MacOS/iOS that isn't part of the Swift project. Not sure if this function is open source or not.
Another oddity: there seems to be a hard limit on how high the job priorities can go: a value of 240 crashes with the error **invalid job priority 0xf0** thrown.
So my question is: what's the deal? Why does this crash? Is it legitimate for actors to choose a range of values they accept for priority and crash if they receive the wrong value? Is the current behavior expected or intended?