Lifetime error: coercion requires that xxx is borrowed for 'static

Hi all,

I have a lifetime issue that I just cannot solve. AI was of no help so far. Here’s a minimal-ish example (also available on the Playground):

// a tradeable instrument, e.g. a stock symbol
#[derive(Debug)]
struct Instrument {
    symbol: String,
}

// the price of an instrument
#[derive(Debug)]
struct Price<'i> {
    instr: &'i Instrument,
    price: f64,
}

// an enum for possible events
enum Event<'i> {
    PriceEvent(Price<'i>),
    // ... more events, e.g. trades, orders, ...
}

enum Sources<'i> {
    GenericSource(Box<dyn Iterator<Item = Event<'i>> + 'i>),
    // ... more sources
}

// a price source that we can iterate over to receive prices
struct PriceSource<'i> {
    items: Vec<Price<'i>>,
    index: usize,
}

impl<'i> Iterator for PriceSource<'i> {
    type Item = Event<'i>;

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}

fn main() {
    // build a price source
    let instr = Instrument { symbol: "AAPL".to_string() };
    let prices = vec![Price { instr: &instr, price: 42.42 }];
    //                               ^^^^^^ borrowed value does not live long enough
    let price_source = PriceSource { items: prices, index: 0 };
    let boxed_price_source = Box::new(price_source) as Box<dyn Iterator<Item = Event<'_>> + '_>;
    let mut generic_event_source: Sources<'_> = Sources::GenericSource(boxed_price_source);

    // try to inspect the price source
    if let Sources::GenericSource(boxed_src) = &mut generic_event_source {
        let boxed_src_any = boxed_src as &mut (dyn std::any::Any + '_);
        if let Some(concrete_src) = boxed_src_any.downcast_mut::<PriceSource<'_>>() {
            for price in &concrete_src.items {
                println!("Fond price: {:?}", price);
            }
        }
    }
}

This produces the following compiler error:

error[E0597]: `instr` does not live long enough
  --> backtest\src\main.rs:42:38
   |
41 |     let instr = Instrument { symbol: "AAPL".to_string() };
   |         ----- binding `instr` declared here
42 |     let prices = vec![Price { instr: &instr, price: 42.42 }];
   |                                      ^^^^^^ borrowed value does not live long enough
...
46 |     let mut generic_event_source: Sources<'_> = Sources::GenericSource(boxed_price_source);
   |                                                                        ------------------ coercion requires that `instr` is borrowed for `'static`
...
57 | }
   | - `instr` dropped here while still borrowed
   |
   = note: due to object lifetime defaults, `Box<dyn Iterator<Item = Event<'_>>>` actually means `Box<(dyn Iterator<Item = Event<'_>> + 'static)>`

I don’t understand why the compiler is claiming that I have specified Box<dyn Iterator<Item = Event<'_>>> when clearly I have used Box<dyn Iterator<Item = Event<'_>> + '_>, i.e., a non-static lifetime?

Does anyone have a good insight into how to fix this?

Any implies 'static. When you cast to &mut (dyn std::any::Any + '_) that 'static requirement propagates backwards until it conflicts with something.

You cannot use Any downcasting with lifetime-bearing types. You will need either to avoid lifetimes, or avoid downcasting.

1 Like

@snooper77 I recommend reading this very good explaination from @quinedot's guide.

1 Like

Thank you @kpreid and @keks993!

Does this mean that downcasting references is essentially impossible (unless they have a static lifetime, which is rare) and thus downcasting is really only meant for smart pointers?

I don't know if I would phrase it as "meant for", but it is true that TypeId based downcasting only works with types that meet a 'static bound. If references are involved, you're generally downcasting the thing behind the reference. (Though there are exceptions like &'static str in a type-erased error, say.)

struct Price<'i> {
    instr: &'i Instrument,
    price: f64,
}

By the way, Rust references are generally for short-term borrows, not long-lived data structures. You ultimately probably want one of

// Exclusive ownership
struct Price {
    instr: Instrument,
    price: f64,
}

// Shared ownership
struct Price {
    // Or `Rc<Instrument>`
    instr: Arc<Instrument>,
    price: f64,
}
1 Like

@quinedot Got it, thanks!