Skip to content

Unexpected static lifetime requirement for nested boxed closures with generic parameters #134835

@marmeladema

Description

@marmeladema

I tried this code:

type BoxedClosure<U> =
    Box<dyn for<'e> Fn(&'e Context<'e, U>) -> bool + Sync + Send + 'static>;

pub struct CompiledExpr<U>(BoxedClosure<U>);

impl<U> CompiledExpr<U> {
    pub fn new(
        closure: impl for<'e> Fn(&'e Context<'e, U>) -> bool + Sync + Send + 'static,
    ) -> Self {
        CompiledExpr(Box::new(closure))
    }
}

pub struct Context<'e, U> {
    data: &'e str,
    userdata: U,
}

pub fn compile1<U>() -> CompiledExpr<U> {
    CompiledExpr::new(|ctx| ctx.data == "rust")
}

pub fn compile2<U>() -> CompiledExpr<U> {
    let e = compile1::<U>();
    CompiledExpr::new(move |ctx| (e.0)(ctx))
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c96c451d36a64d657cdfecc7c5185f31

I expected to see this happen: successful compilation

Instead, this happened:

error[E0310]: the parameter type `U` may not live long enough
  --> src/lib.rs:25:5
   |
25 |     CompiledExpr::new(move |ctx| (e.0)(ctx))
   |     ^^^^^^^^^^^^^^^^^
   |     |
   |     the parameter type `U` must be valid for the static lifetime...
   |     ...so that the type `U` will meet its required lifetime bounds
   |
help: consider adding an explicit lifetime bound
   |
23 | pub fn compile2<U: 'static>() -> CompiledExpr<U> {
   |                  +++++++++

I am not exactly sure its a bug per say, but from my perspective, this is relatively surprising that this code fails to build.
The 'static bound is on the boxed dyn object itself and not on the parameters of the boxed closure.
Its not clear why U should be 'static when Context which holds U is not.

Meta

rustc --version --verbose:

rustc 1.83.0 (90b35a623 2024-11-26)
binary: rustc
commit-hash: 90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf
commit-date: 2024-11-26
host: x86_64-unknown-linux-gnu
release: 1.83.0
LLVM version: 19.1.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-discussionCategory: Discussion or questions that doesn't represent real issues.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions