Lifetime of associated function parameter may not live long enough error

Simplified, the situation is as follows:

struct Stream<'a>
{
    all : &'a str,
    current : &'a u8, // reference to a byte in `all`
}

impl<'a> Stream<'a> {
    fn advance(&self) {
        // ...
    }

    fn current(&self) -> &'a u8 {
        self.current
    }
}

trait Parse
{
    fn parse(input : &Stream) -> Self;
}

struct X<'a>(&'a u8);

impl Parse for X<'_> {
    fn parse(input : &Stream) -> Self {
        Self(input.current)
    }
}

The Stream type and the Parse trait are foreign, I cannot change them. When I try to compile this the compiler throws this error:

lifetime may not live long enough; associated function was supposed to return data with lifetime '2 but it is returning data with lifetime '1

I can't adjust the lifetimes in the signature of X's implementation of parse match the lifetime of X to that of input's lifetime parameter.

How do I fix this?

A reference to a byte? Who designs these APIs?! :man_facepalming:.

u8 implements Copy, so this should work:

impl Parse for X<'_> {
    fn parse(input : &Stream) -> Self {
        Self(&*input.current)
    }
}

u8 implements Copy , so this should work:

That won't work because Self needs a reference that lives as long as — well, the anonymous '_ lifetime declared.

The needed change here is to change X not to store a reference, but a copy of whatever data it needs. The definition of the Parse trait does not allow Self to borrow from the input.

5 Likes

For me, that still gives an error.

$ cargo check
    Checking foo v0.1.0 (/home/jean/tmp/foo)
error: lifetime may not live long enough
  --> src/main.rs:26:9
   |
25 |     fn parse(input : &Stream) -> Self {
   |              -----               ---- return type is X<'2>
   |              |
   |              has type `&Stream<'1>`
26 |         Self(&*input.current)
   |         ^^^^^^^^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`

error: could not compile `foo` (bin "foo") due to previous error

The way I understand it, the problem is essentially unsolvable. The Parse trait requires a function of signature

fn parse(input : &Stream) -> Self;

or with desugared lifetimes:

fn<'a, 'b> parse(input: &'a Stream<'b>) -> Self;

which requires you to be able to get a Self from a Stream with any lifetime for the inner data. You can't do that for X<'a> with a fixed lifetime 'a.

1 Like

A reference to a byte? Who designs these APIs?!

Like I said, the example is simplified.

In reality, I'm talking about the Parse trait from the syn crate. Here, input is a &ParseBuffer, and current is a Cursor. Cursor does not implement Copy.

Uh? Cursor in syn::buffer - Rust

Ah, I see. So the conflict is between the definition of X and the Parse trait.

Yeah, I missed the point of the definitions clashing. I need to stop trying to help while being half awake :rofl:

Okay, it does, but I still need a reference to the underlying buffer, I don't want to copy whatever Cursor is pointing to because that would defeat the purpose of using a reference/Cursor in the first place, which is: (1) to save memory by not having duplicate memory, (2) to save time by not copying that memory.

What are you trying to achieve? This really smells like an XY problem.

In syn, you use parsing to create ASTs through the Parse trait. However, for some parts of the input, I don't want to generate an entire syntax tree, I just want to check if that part of the TokenStream is indeed valid for what type I expect there to be. I want to store the cursor to those Tokens so that I can copy those parts of the input to the output of my macro, while the more complicated parts that I do want to change, are processed manually.

I want to store the cursor to those Tokens so that I can copy those parts of the input to the output of my macro

The definition of Parse prohibits that. Because the lifetime of the ParseStream<'_> is on the parse function, not the trait, you do not receive any guarantee that the data lasts longer than that single function call, and so borrowing it longer is not possible.

4 Likes

I see. Well, knowing it's impossible is better than trying to find a solution. Thank you!