Skip to content

impl Trait cannot work well with lifetime bounds #66551

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
oxalica opened this issue Nov 19, 2019 · 5 comments
Open

impl Trait cannot work well with lifetime bounds #66551

oxalica opened this issue Nov 19, 2019 · 5 comments
Labels
A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-lifetimes Area: Lifetimes / regions C-enhancement Category: An issue proposing an enhancement or a PR with one. T-lang Relevant to the language team

Comments

@oxalica
Copy link
Contributor

oxalica commented Nov 19, 2019

Playground

pub struct S<'t>(usize, &'t str);

impl<'t> S<'t> {
    // error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
    pub fn foo<'s>(&'s mut self) -> impl FnMut() + 's {
        move || self.0 += 1
    }
}

fn main() {
    let mut s = S(0, "hello");
    s.foo()();
    println!("{}", s.0);
}

The self: &'s mut S<'t> implies 't: 's, so the signature should be correct. But compiler still complain that 't is captured but does not appear in impl bounds.

I checked the error description of E0700 and tried impl FnMut() + 's where 't: 's and impl FnMut() + 's + 't, while it still fails.

Note that when using dyn Trait as pub fn foo<'s>(&'s mut self) -> Box<dyn FnMut() + 's>, it compiles.

@jonas-schievink jonas-schievink added A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-lifetimes Area: Lifetimes / regions C-bug Category: This is a bug. T-lang Relevant to the language team C-enhancement Category: An issue proposing an enhancement or a PR with one. and removed C-bug Category: This is a bug. labels Nov 19, 2019
@kennytm
Copy link
Member

kennytm commented May 17, 2020

You could workaround using the Captures trait.

pub trait Captures<U: ?Sized> {}
impl<U: ?Sized, T: ?Sized> Captures<U> for T {}

impl<'t> S<'t> {
    pub fn foo(&mut self) -> impl FnMut() + Captures<&'t str> + '_ {
        move || self.0 += 1
    }
}

@Nadrieril
Copy link
Member

Could the Captures trait make it into std so that rustc can suggest it? It's otherwise impossible to discover this trick but it's a very useful one.

@ssbr
Copy link
Contributor

ssbr commented Oct 18, 2024

The Captures trick is a builtin syntax use<..> in 1.82: https://blog.rust-lang.org/2024/10/17/Rust-1.82.0.html:

pub fn foo<'s>(&'s mut self) -> impl FnMut() + use<'s, 't> {
    move || self.0 += 1
}

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

And I think even that much gets erased in the 2024 edition, where it's implicit.

(I'm coming back to this old bug because my use of the Captures trait linked back to this issue, and I am joyfully replacing that usage. :])

@Dylan-DPC
Copy link
Member

Current output:

error[E0700]: hidden type for `impl FnMut() + 's` captures lifetime that does not appear in bounds
 --> src/main.rs:5:9
  |
3 | impl<'t> S<'t> {
  |      -- hidden type `{closure@src/main.rs:5:9: 5:16}` captures the lifetime `'t` as defined here
4 |     pub fn foo<'s>(&'s mut self) -> impl FnMut() + 's {
  |                                     ----------------- opaque type defined here
5 |         move || self.0 += 1
  |         ^^^^^^^^^^^^^^^^^^^
  |
help: add a `use<...>` bound to explicitly capture `'t`
  |
4 |     pub fn foo<'s>(&'s mut self) -> impl FnMut() + 's + use<'s, 't> {
  |                                                       +++++++++++++

@rami3l
Copy link
Member

rami3l commented Jan 4, 2025

I've been using the Captures<> hack (#66551 (comment)) since a long time ago, but since use<> has been a part of the language now, I guess the original problem has been resolved, and we should close this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-lifetimes Area: Lifetimes / regions C-enhancement Category: An issue proposing an enhancement or a PR with one. T-lang Relevant to the language team
Projects
None yet
Development

No branches or pull requests

7 participants