Skip to content

hidden type for impl ... captures lifetime that does not appear in bounds #147529

Description

@eopb

Code

This is how far I've got trying to minimise things:

#![allow(unreachable_code, unused_variables, dead_code)]

use std::collections::HashMap;
use std::pin::Pin;
use std::sync::Arc;

pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;

struct BrokerAction;
struct HandlerError;

impl From<()> for BrokerAction {
    fn from((): ()) -> Self {
        BrokerAction
    }
}

impl From<Error> for HandlerError {
    fn from(Error: Error) -> Self {
        HandlerError
    }
}

trait AsyncClosure<'a, Context>: Send + Sync + 'static {
    type Output: Future<Output = Result<Self::Action, Self::Err>> + Send + 'a;
    type Action: Into<BrokerAction> + 'static;
    type Err: Into<HandlerError> + 'static;
    fn call(&'a self, incoming: Incoming<'a, Context>) -> Self::Output;
}

impl<'a, F, Fut, Err, Context, Action> AsyncClosure<'a, Context> for F
where
    Context: 'static,
    F: Send + Sync + 'static + Fn(Incoming<'a, Context>) -> Fut,
    Fut: Future<Output = Result<Action, Err>> + Send + 'a,
    Action: Into<BrokerAction> + 'static,
    Err: Into<HandlerError> + 'static,
{
    type Err = Err;
    type Action = Action;
    type Output = Fut;

    fn call(&'a self, incoming: Incoming<'a, Context>) -> Self::Output {
        (self)(incoming)
    }
}

fn handler(
    handlers: impl IntoIterator<Item = (&'static str, MessageHandler)>,
) -> impl 'static + for<'a> AsyncClosure<'a, ApplicationContext> {
    let handlers: Arc<HashMap<&str, MessageHandler>> = Arc::new(handlers.into_iter().collect());

    move |incoming: Incoming<'_, ApplicationContext>| {
        let handlers = Arc::clone(&handlers);

        let kind: &str = todo!();

        let content_type = todo!();

        let data = incoming.message.data.clone();
        let context = incoming.context;

        async move {
            let kind = kind;
            let content_type = content_type;

            let handler = handlers.get(kind).unwrap();

            handler(&data, context).await
        }
    }
}

type MessageHandler = Box<
    dyn for<'a> Fn(&'a [u8], Arc<ApplicationContext>) -> BoxFuture<'a, Result<(), Error>>
        + Sync
        + Send,
>;

struct ApplicationContext;
struct Error;

struct Incoming<'d, C> {
    context: Arc<C>,
    message: &'d Delivery,
}

#[derive(Debug, PartialEq)]
struct Delivery {
    data: Vec<u8>,
}

This code compiles on stable, but fails on nightly and beta.

Version it worked on

The most recent I've tested was: cargo 1.90.0 (840b83a10 2025-07-30):

: cargo +stable c
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.09s

Version with regression

The most recent I've tested was: cargo 1.92.0-nightly (801d9b498 2025-10-04):

: cargo +nightly-2025-10-08 c
    Checking regress v0.1.0 (/private/var/folders/9d/tqvdlqrd6fz7t8746q0jdjzr0000gp/T/tmp.xBu0LdwlmB/regress)
error[E0700]: hidden type for `impl AsyncClosure<'a, ...>` captures lifetime that does not appear in bounds
  --> src/lib.rs:53:5
   |
50 |   ) -> impl 'static + for<'a> AsyncClosure<'a, ApplicationContext> {
   |        ----------------------------------------------------------- opaque type defined here
...
53 | /     move |incoming: Incoming<'_, ApplicationContext>| {
54 | |         let handlers = Arc::clone(&handlers);
55 | |
56 | |         let kind: &str = todo!();
...  |
71 | |     }
   | |_____^
   |
   = note: hidden type `{closure@src/lib.rs:53:5: 53:54}` captures the static lifetime
   = note: the full name for the type has been written to '/private/var/folders/9d/tqvdlqrd6fz7t8746q0jdjzr0000gp/T/tmp.xBu0LdwlmB/regress/target/debug/deps/regress-494a0fda5fa8247a.long-type-5522052737140525087.txt'
   = note: consider using `--verbose` to print the full type name to the console

For more information about this error, try `rustc --explain E0700`.
error: could not compile `regress` (lib) due to 1 previous error

cc @lcnr since we spoke about this at EuroRust

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

C-bugCategory: This is a bug.P-criticalCritical priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-betaPerformance or correctness regression from stable to beta.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions