Hah, I forgot to conform Never to the executor huh -- thanks for the reminder @FranzBusch 
Yeah so that's viable then:
struct UnstructuredTaskExecutorPreference<Ex: TaskExecutor>: Hashable {
enum _Storage {
case taskExecutor(Ex)
case defaultExecutor
}
var storage: _Storage
private init(storage: _Storage) {
self.storage = storage
}
init(_ ex: Ex) {
self.storage = .taskExecutor(ex)
}
static func taskExecutor(_ ex: Ex) -> Self {
.init(storage: .taskExecutor(ex))
}
static var defaultExecutor: Preference<Never> {
.init(storage: .defaultExecutor)
}
}
class Never: TaskExecutor {
func enqueue(_ job: consuming ExecutorJob) {}
}
func take<Ex: TaskExecutor>(_: Preference<Ex>) {}
func test(ex: some Executor) {
take(.taskExecutor(ex))
take(.defaultExecutor)
}
I think this would be okey. Would we still want a plain Task(on: taskExecutor) overload or how would we want these APIs to be spelled..
Task(on: .taskExecutor())
Task(on: .defaultExecutor)
On the explicit omission of Task(preferred executor) 
I should mention though that we casually just added the
Task(on: .preferredExecutor) // this is actually the dangerous API
during this discussion here but this API is rather dangerous and NOT present in the proposal at this point (!). The reason is the lifetime of executors.
We on purpose do not offer this API to automatically inherit the preferred executor into an unstructured task in this proposal.
The reason is executor lifetime is NOT guaranteed by tasks that run on it. So the following code is safe because we only inherit the preferred executor in structured tasks:
let executor: MyTaskExecutor = ...
defer { executor.shutdown() }
await withTaskExecutor(executor) {
async let x = ... // uses the task executor
Task {} // does NOT use the task executor
}
// executor is deinitialized here (!!!)
this is by design in order to allow the executor to be lifecycle managed using structured programming: we know that if we have finished this block of code, we will release this executor.
If we just inherited it into unstructured concurrency magically, we lost this guarantee.
You can still use the UnsafeCurrentTask to compare your expected task executor with the current one, and hop if you want to. But this is an advanced pattern, accessible only via the unsafe APIs.
enum-like executor preference style API
So... the API would have to be split between UnstructuredTaskExecutorPreference and ChildTaskExecutorPreference, and would have to take the following shape:
// used in `Task(on:)`
struct UnstructuredTaskExecutorPreference<Ex: TaskExecutor>: Hashable {
static func taskExecutor(_ ex: Ex) -> Self
static var defaultExecutor: Preference<Never> // aka. "ignore preferred"; same as not passing a value to `Task()`
}
/// used in `withTaskExecutor` and `group.addTask`
struct ChildTaskExecutorPreference<Ex: TaskExecutor>: Hashable {
static func taskExecutor(_ ex: Ex) -> Self
static var defaultExecutor: Preference<Never> // aka. "ignore preferred"
static var preferredExecutor: Preference<Never> // same as not passing a value to `addTask()`
}
I do think this clearly communicates the capabilities and does not lead to unsafe code, so this would be okey I believe.