1

I have reduced my actual code to this minimal example:

trait Producer<P> where P: Something {
    fn produce(&self) -> Box<P>;
}

struct P1 {}

impl Producer<B1> for P1 {
    fn produce(&self) -> Box<B1> {
        Box::new(B1 {})
    }
}

trait Something {}

trait Borrower<'b> {
    type B: std::fmt::Display;
    
    fn borrow(&'b self) -> Self::B;
}

struct B1 {}

impl Something for B1 {}

impl<'b> Borrower<'b> for B1 {
    type B = Borrowing1<'b>;
    
    fn borrow(&'b self) -> Self::B {
        Borrowing1 { _b: &self }
    }
}

struct Borrowing1<'b> {
    _b: &'b B1,
}

impl<'b> std::fmt::Display for Borrowing1<'b> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Borrowing1")
    }
}

fn perform<'b, P, B>(producer: P) where P: Producer<B>, B: Something + Borrower<'b> + 'static {
    for _ in 0..1 {
        let b = producer.produce();
        let s = b.borrow().to_string();
        eprintln!("{}", s);
    }
}

fn main() {
   let p1 = P1 {};
   perform(p1);
}

I have a Producer type that creates Something. And that something can implement Borrower<'b>, which introduces a lifetime. Then, I want to restrict a function perform to receive producers that produce Something with the trait Borrower<'b>. However, since I can't prevent introducing a lifetime in perform the function thinks that all produced items must live for the entire function execution. Actually, they are static objects that just implement Borrower<'b>. But I struggle finding the correct bounds.

The error message reflects that:

error[E0597]: `*b` does not live long enough
  --> src/main.rs:46:17
   |
43 | fn perform<'b, P, B>(producer: P) where P: Producer<B>, B: Something + Borrower<'b> + 'static {
   |            -- lifetime `'b` defined here
...
46 |         let s = b.borrow().to_string();
   |                 ^---------
   |                 |
   |                 borrowed value does not live long enough
   |                 argument requires that `*b` is borrowed for `'b`
47 |         eprintln!("{}", s);
48 |     }
   |     - `*b` dropped here while still borrowed

Maybe you can help me with that.

vallentin
  • 23,478
  • 6
  • 59
  • 81
fyaa
  • 646
  • 1
  • 7
  • 25
  • 1
    Using GAT in nightly it is surprisingly easy to do: [playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=4d2156040c803d54c857587c586bc390). I don't know of an easy workaround, though. – rodrigo Dec 13 '20 at 19:11
  • This kinda sounds like an [XY Problem](https://xyproblem.info/). Can you please explain what actual problem you're trying to solve? – pretzelhammer Dec 13 '20 at 19:21

1 Answers1

2

This can be solved using higher-rank trait bounds:

You don't have to pass a lifetime to function here. Instead you need to define a lifetime on the go when borrow() is called. Following should solve the issue:

fn perform<P, B>(producer: P)
where
    P: Producer<B>,
    for<'b> B: Something + Borrower<'b> + 'static,
{
    for _ in 0..1 {
        let b = producer.produce();
        let u = b.borrow();
        let s = u.to_string();
        eprintln!("{}", s);
    }
}

Playground

Higher-rank trait bounds are explained pretty nicely here:
How does for<> syntax differ from a regular lifetime bound?

vallentin
  • 23,478
  • 6
  • 59
  • 81
Mihir Luthra
  • 6,059
  • 3
  • 14
  • 39
  • 1
    That's exactly it, thank you very much. I thought higher-rank trait bounds were unstable. – fyaa Dec 14 '20 at 15:08