coriolinus
coriolinus

Reputation: 939

Where does the static requirement come from?

I have a very small repo which currently does not compile, with the following error:

error[E0597]: `line` does not live long enough
  --> src/main.rs:19:20
   |
19 |         let line = line.trim();
   |                    ^^^^-------
   |                    |
   |                    borrowed value does not live long enough
   |                    argument requires that `line` is borrowed for `'static`
...
22 |     }
   |     - `line` dropped here while still borrowed

I've had trouble producing a minimal example demoing the problem: this (playground) works as expected, despite that fn main is identical to the one which fails, as are the signatures of ItemParser::parse and Item::pretty_to.

Inlining a section of fn main, and some signatures:

    let parser = ItemParser::new();

    let stdin = stdin();
    let reader = stdin.lock();
    let reader = BufReader::new(reader);

    let stdout = stdout();
    let mut writer = stdout.lock();
    for line in reader.lines() {
        let line = line?;
        let line = line.trim();
        let item = parser.parse(line)?;
        item.pretty_to(&mut writer)?;
    }

The same issue persists when I comment out item.pretty_to(&mut writer)?;, so I believe that that isn't the problem.

I can't show the actual code for ItemParser as it's generated by LALRPOP, but the signature as reported by rustdoc is

pub struct ItemParser { /* fields omitted */ }

pub fn parse<'input>(
    &self,
    input: &'input str
) -> Result<Item<'input>, ParseError<usize, Token<'input>, &'static str>>

Unlike this issue, nothing in this crate explicitly requires a 'static lifetime.

My expectation is that at the head of the for loop, item has type io::Result<String>. After we discard the error and trim the edges, it should have type &'a str, where 'a is the lifetime scoped to this iteration of the for loop. In that case, parsing the line should produce an Item<'a> with the same lifetime. It drops before the lifetime ends, in appropriate sequence. As nothing visibly requests a 'static lifetime, I don't know where that requirement is coming from.

Upvotes: 4

Views: 258

Answers (2)

kmdreko
kmdreko

Reputation: 60082

On error, parser.parse() yields a type that is bounded to the lifetime of the input.

Result<Item<'input>, ParseError<usize, Token<'input>, &'static str>>
                                    // ^^^^^^^^^^^^^

You're using ? to return the error from main (not "discard" it), which by necessity will outlive the loop, and therefore line.

You can handle the error immediately via match or if let, or do something like parser.parse().map_err(...)? to transform the error into something not bounded to the lifetime of line.


Answering the title specifically, The 'static requirement is from using eyre::Result which is an alias for Result<T, E = Report>. Report can be created from any Error type (which ParseError is), but is constrained to be 'static. It is a shame the compiler doesn't bring this up though.

Upvotes: 2

Locke
Locke

Reputation: 8954

Since str is a sort of slice, it can not outlive its parent. The result on trim is really just a slice the original string.

pub fn trim(&self) -> &str

// Now with the implicit lifetimes
pub fn trim<'a, 'b: 'a>(&'b self) -> &'a str

Since none of the lifetimes of the function arguments would not make appropriate bounds for the lifetime of the function output, it must have a different lifetime and the only appropriate lifetime for an unconstrained reference is 'static.

Its basically the equivalent to returning a reference to data you just freed in c.

Foo *data_to_return = &foo->bar;
free(foo);
return data_to_return;

But it's kinda a moot point anyway because the function would never work in the first place. The lifetime is more of a symptom of your issue than the cause. Just ignore the lifetime for now since it sounds like its holding you up from actually fixing the issue. Once you fix your code, the 'static bound will go away.

Upvotes: -1

Related Questions