Repository: apple/swift-nio
File: Sources/NIOCore/EventLoopFuture.swift (Swift)

Code before:
    /// - Parameter to: The `EventLoopPromise` that should fail with the error of this `EventLoopFuture`.
    @inlinable
    public func cascadeFailure<NewValue>(to promise: EventLoopPromise<NewValue>?) {
        guard let promise = promise else { return }
        self.whenFailure { promise.fail($0) }
    }
}

// MARK: wait

extension EventLoopFuture {
    #if swift(>=5.7)
    /// Wait for the resolution of this `EventLoopFuture` by blocking the current thread until it
    /// resolves.
    ///
    /// If the `EventLoopFuture` resolves with a value, that value is returned from `wait()`. If
    /// the `EventLoopFuture` resolves with an error, that error will be thrown instead.
    /// `wait()` will block whatever thread it is called on, so it must not be called on event loop
    /// threads: it is primarily useful for testing, or for building interfaces between blocking
    /// and non-blocking code.
    ///
    /// This is also forbidden in async contexts: prefer ``EventLoopFuture/get``.
    ///
    /// - returns: The value of the `EventLoopFuture` when it completes.
    /// - throws: The error value of the `EventLoopFuture` if it errors.
    @available(*, noasync, message: "threads can change between suspension points and therefore the thread specific value too")
    @inlinable
    public func wait(file: StaticString = #file, line: UInt = #line) throws -> Value {
        return try self._wait(file: file, line: line)
    }
    #else
    /// Wait for the resolution of this `EventLoopFuture` by blocking the current thread until it
    /// resolves.
    ///
    /// If the `EventLoopFuture` resolves with a value, that value is returned from `wait()`. If
    /// the `EventLoopFuture` resolves with an error, that error will be thrown instead.
    /// `wait()` will block whatever thread it is called on, so it must not be called on event loop
    /// threads: it is primarily useful for testing, or for building interfaces between blocking
    /// and non-blocking code.
    ///
    /// This is also forbidden in async contexts: prefer ``EventLoopFuture/get``.
    ///
    /// - returns: The value of the `EventLoopFuture` when it completes.
    /// - throws: The error value of the `EventLoopFuture` if it errors.
    @inlinable
    public func wait(file: StaticString = #file, line: UInt = #line) throws -> Value {
        return try self._wait(file: file, line: line)
    }
    #endif

    @inlinable

Review comment (bug):
```suggestion
    @available(*, noasync, message: "threads can change between suspension points and therefore the thread specific value too", renamed: "get()")
```
This will produce a fixit that will allow users to easily replace it with `.get()`
```
warning: instance method 'wait' is unavailable from asynchronous contexts; threads can change between suspension points and therefore the thread specific value too; this is an error in Swift 6
    try future.wait()
               ^~~~
               get
```
Users still need to add `await` infront but the compiler will nicely provide a fixit for that too.
```
error: expression is 'async' but is not marked with 'await'
    try future.get()
    ^~~~~~~~~~~~~~~~
        await 
```

---

 I understand that we want to encourage users to use `get()` but I'm not sure I quite understand the `message`:

> threads can change between suspension points and therefore the thread specific value too
 
`wait()` doesn't use any thread specific value and AFAIK it is "safe" to use in an async context (except deadlocks) but is just not performant.

Code after:
    /// - Parameter to: The `EventLoopPromise` that should fail with the error of this `EventLoopFuture`.
    @inlinable
    public func cascadeFailure<NewValue>(to promise: EventLoopPromise<NewValue>?) {
        guard let promise = promise else { return }
        self.whenFailure { promise.fail($0) }
    }
}

// MARK: wait

extension EventLoopFuture {
    #if swift(>=5.7)
    /// Wait for the resolution of this `EventLoopFuture` by blocking the current thread until it
    /// resolves.
    ///
    /// If the `EventLoopFuture` resolves with a value, that value is returned from `wait()`. If
    /// the `EventLoopFuture` resolves with an error, that error will be thrown instead.
    /// `wait()` will block whatever thread it is called on, so it must not be called on event loop
    /// threads: it is primarily useful for testing, or for building interfaces between blocking
    /// and non-blocking code.
    ///
    /// This is also forbidden in async contexts: prefer ``EventLoopFuture/get``.
    ///
    /// - returns: The value of the `EventLoopFuture` when it completes.
    /// - throws: The error value of the `EventLoopFuture` if it errors.
    @available(*, noasync, message: "wait() can block indefinitely, prefer get()", renamed: "get()")
    @inlinable
    public func wait(file: StaticString = #file, line: UInt = #line) throws -> Value {
        return try self._wait(file: file, line: line)
    }
    #else
    /// Wait for the resolution of this `EventLoopFuture` by blocking the current thread until it
    /// resolves.
    ///
    /// If the `EventLoopFuture` resolves with a value, that value is returned from `wait()`. If
    /// the `EventLoopFuture` resolves with an error, that error will be thrown instead.
    /// `wait()` will block whatever thread it is called on, so it must not be called on event loop
    /// threads: it is primarily useful for testing, or for building interfaces between blocking
    /// and non-blocking code.
    ///
    /// This is also forbidden in async contexts: prefer ``EventLoopFuture/get``.
    ///
    /// - returns: The value of the `EventLoopFuture` when it completes.
    /// - throws: The error value of the `EventLoopFuture` if it errors.
    @inlinable
    public func wait(file: StaticString = #file, line: UInt = #line) throws -> Value {
        return try self._wait(file: file, line: line)
    }
    #endif

    @inlinable