This code compiles on 1.89 and then fails to compile with "higher-ranked lifetime error" starting in 1.90
I tried this code:
use hyper_util::rt::TokioIo;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio_rustls::{
TlsConnector,
rustls::pki_types::{IpAddr, ServerName},
};
use tonic::transport::{Endpoint, Uri};
pub trait AsyncStream: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static {}
impl<T: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static> AsyncStream for T {}
type BoxStream = Box<dyn AsyncStream>;
fn main() {
println!("Hello, world!");
}
fn bad_fn(
connector: TlsConnector,
endpoint: Endpoint,
) -> impl Future<Output = Result<tonic::transport::Channel, tonic::transport::Error>> + Send {
async move {
let rpc_channel = endpoint
.connect_with_connector(tower::service_fn(move |_: Uri| {
let connector = connector.clone();
let box_stream = get_box_stream();
async move {
connector
.connect(
// This Address does not matter. I am using an ip address as opposed to a hostname to avoid
// an attempt at using SNI.
ServerName::IpAddress(IpAddr::V4("127.0.0.1".try_into().unwrap())),
box_stream,
)
.await
.map(|stream| TokioIo::new(Box::new(stream) as BoxStream))
}
}))
.await?;
Ok(rpc_channel)
}
}
fn get_box_stream() -> BoxStream {
todo!()
}
I expected to see this happen: Anything which compiled before the upgrade I would expect to compile after
Instead, this happened: It doesn't
Meta
rustc --version --verbose:
rustc 1.90.0 (1159e78c4 2025-09-14)
binary: rustc
commit-hash: 1159e78c4747b02ef996e55082b704c09b970588
commit-date: 2025-09-14
host: x86_64-unknown-linux-gnu
release: 1.90.0
LLVM version: 20.1.8
Backtrace
dspyz@davids-desktop:~/mwe$ RUST_BACKTRACE=1 cargo check
Checking mwe v0.1.0 (/home/dspyz/mwe)
error: higher-ranked lifetime error
--> src/main.rs:21:5
|
21 | / async move {
22 | | let rpc_channel = endpoint
23 | | .connect_with_connector(tower::service_fn(move |_: Uri| {
24 | | let connector = connector.clone();
... |
39 | | Ok(rpc_channel)
40 | | }
| |_____^
error: could not compile `mwe` (bin "mwe") due to 1 previous error
git repo here
It gets even weirder. If I change it to a trait method, I get:
the type `TokioIo<Box<dyn AsyncStream>>` does not fulfill the required lifetime
TokioIo<Box<dyn AsyncStream>> is a fully static type so it should fulfill all lifetimes.
use hyper_util::rt::TokioIo;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio_rustls::{
TlsConnector,
rustls::pki_types::{IpAddr, ServerName},
};
use tonic::transport::{Endpoint, Uri};
pub trait AsyncStream: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static {}
impl<T: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static> AsyncStream for T {}
type BoxStream = Box<dyn AsyncStream>;
fn main() {
println!("Hello, world!");
}
trait BadTrait {
fn bad_fn(
connector: TlsConnector,
endpoint: Endpoint,
) -> impl Future<Output = Result<tonic::transport::Channel, tonic::transport::Error>> + Send;
}
impl BadTrait for () {
async fn bad_fn(
connector: TlsConnector,
endpoint: Endpoint,
) -> Result<tonic::transport::Channel, tonic::transport::Error> {
let rpc_channel = endpoint
.connect_with_connector(tower::service_fn(move |_: Uri| {
let connector = connector.clone();
let box_stream = get_box_stream();
async move {
connector
.connect(
// This Address does not matter. I am using an ip address as opposed to a hostname to avoid
// an attempt at using SNI.
ServerName::IpAddress(IpAddr::V4("127.0.0.1".try_into().unwrap())),
box_stream,
)
.await
.map(|stream| TokioIo::new(Box::new(stream) as BoxStream))
}
}))
.await?;
Ok(rpc_channel)
}
}
fn get_box_stream() -> BoxStream {
todo!()
}
error[E0477]: the type `TokioIo<Box<dyn AsyncStream>>` does not fulfill the required lifetime
--> src/main.rs:25:5
|
25 | / async fn bad_fn(
26 | | connector: TlsConnector,
27 | | endpoint: Endpoint,
28 | | ) -> Result<tonic::transport::Channel, tonic::transport::Error> {
| |___________________________________________________________________^
|
note: type must satisfy the static lifetime as required by this binding
--> src/main.rs:21:93
|
21 | ) -> impl Future<Output = Result<tonic::transport::Channel, tonic::transport::Error>> + Send;
| ^^^^
error[E0477]: the type `{async block@src/main.rs:33:17: 33:27}` does not fulfill the required lifetime
--> src/main.rs:25:5
|
25 | / async fn bad_fn(
26 | | connector: TlsConnector,
27 | | endpoint: Endpoint,
28 | | ) -> Result<tonic::transport::Channel, tonic::transport::Error> {
| |___________________________________________________________________^
|
note: type must satisfy the static lifetime as required by this binding
--> src/main.rs:21:93
|
21 | ) -> impl Future<Output = Result<tonic::transport::Channel, tonic::transport::Error>> + Send;
| ^^^^
This code compiles on 1.89 and then fails to compile with "higher-ranked lifetime error" starting in 1.90
I tried this code:
I expected to see this happen: Anything which compiled before the upgrade I would expect to compile after
Instead, this happened: It doesn't
Meta
rustc --version --verbose:Backtrace
git repo here
It gets even weirder. If I change it to a trait method, I get:
TokioIo<Box<dyn AsyncStream>>is a fully static type so it should fulfill all lifetimes.