Misleading "Never be executed" warning

In the following minimal example, the Swift compiler emits a warning Will never be executed pointing to the await in line 2.

func wait(for task: Task<Never, any Error>) async throws -> Never {
    try await task.value
}

I think the warning is not correct: Obviously the task can't return normally, but the idea is to wait for (and rethrow) an error.

Is there a better way to write this code? Am I missing something? Or shall I file a bug?

In my real code I have a lot of nested calls to withTaskCancellationHandler and similar with-style functions. They all get the warning at their try await. Anyway, the code works as intended.

I have tested this with Xcode 26.2 as well as the current nightly toolchain.

2 Likes

I am tempted to agree that the warning is incorrect, but Never is kind of special with regards to compiler behavior…

Unless you have a strong motivation to use Never I think I would write the same code simply using Void instead of Never.

That said I think you could get rid of the warning by writing it like this (untested code!)

extension Task where Success == Never {
    var waitForError: Never {
        get async throws {
            guard let error = await self.result.error else {
                fatalError("A never task can not return without throwing an error")
            }
            throw error
        }
    }
}

func wait(for task: Task<Never, any Error>) async throws -> Never {
   return try await task.waitForError
}

What I don’t get here is why waitForError does not show the same “Will never be executed” warning as your original code.

1 Like

To make this work you would need to use case let:

extension Task where Success == Never {
    var waitForError: Never {
        get async throws {
            guard case let .failure(error) = await result else {
                fatalError("A never task can not return without throwing an error")
            }

            throw error
        }
    }
}

or

extension Result where Success == Never {
    consuming func getError() throws -> Never {
        if case let .failure(error) = self {
            throw error
        } else {
            fatalError("A never task can not return without throwing an error")
        }
    }
}
1 Like

you could get rid of the warning by writing it like this

Thanks for the workaround! I had to adopt the code a bit, as for me Result lacks the error property. Interestingly, this compiles:

extension Task where Success == Never {
    var waitForThrow: Never {
        get async throws {
            switch await result {
            case .failure(let error):
                throw error
            }
        }
    }
}

The compiler (and me) likes the single case switch :slight_smile:

1 Like

Unless you have a strong motivation to use Never I think I would write the same code simply using Void instead of Never.

I did not want to derail the discussion about the sense of a Task<Never, any Error>, but I think it is a very useful abstraction (and I'm using it a lot). As an example, a task would:

  1. Connect to some service
  2. Setup various protocols
  3. Handle IO
  4. On error: disconnect and tear down all resources belonging to the connection

Whenever the application decides it wants to close the connection, it just cancels the Task. The code in the Task would then throw a CancellationError.

This results in a very nice interface that makes sure that there are no resources on open connections left behind.

So generally: An ongoing operation that has no defined end, but will only terminate on some kind of irregular situation.

1 Like

Still, this is just a workaround. I'm concerned that the warning is misleading and should not be there in the first place.

It is also popping up in other places, for example:

func wait(for task: Task<Never, any Error>) async throws -> Never {
    try await withTaskCancellationHandler { // Will never be executed
        try await task.waitForThrow
    } onCancel: {
        task.cancel()
    }
}

Now it is on the first await in line 2.

Using value instead of waitForThrow results in two warnings.

I'm going to guess that the never-returning logic neglects to consider the throwing path. Worth a bug report, for sure :slight_smile:

2 Likes

Filed

3 Likes

Semantically, what’s the advantage of modeling this with Never instead of ()? The type of do { } while someBool doesn’t change just because someBool is statically known to be true.

If you ever want to make it possible to tear down and restart this connection, you’re going to have a heck of a refactoring on your hands.

Semantically, what’s the advantage of modeling this with Never instead of () ?

When all your (deeply nested) functions return Never the compiler helps you to catch accidental returns that you did not handle correctly.

Here's an example:

extension Connection {
    func withConnection(_ operation: (IOHandle) async throws -> Void) async throws -> Never {
        do {
            let handle = try await self.connect()
            try await operation(handle)
        } catch {
            try? await self.tearDown()
            throw error
        }
    }
}

For me it's not easy to spot the error. But the compiler helpfully emits a warning: "Instance method with uninhabited return type 'Never' is missing call to another never-returning function on all paths". Ah: I need to make the closure -> Never. Otherwise the connection would not be torn down when the closure returns normally.

If you ever want to make it possible to tear down and restart this connection...

This is simple: Just cancel the task that is currently connected. It will disconnect, remove other resources and finally terminate with a CancellationError.

This design has the advantage that the active connection is scoped to the call of withConnection, which stacks very well with Structured Concurrency. It's nice to be sure that, when your function returns, all resources have been torn down. Local Reasoning™️ ftw.

1 Like

Interesting. I’m not sold on the ergonomics of having to disambiguate any real error from a CancellationError, but I appreciate the novelty of the experiment.

1 Like