Description
I'm experimenting with a parser combinator and ran into an issue with closure lifetime inference.
This might be a duplicate of #39943, since it uses a similar (but simpler) mechanism to produce the same error message. However, in the code below the error is potentially a lot further away, and since I need to return values from the closure I'm having trouble finding any way to make it work by explicitly specifying a signature. Since it involves more moving parts, I'm also not sure how to confirm if the underlying issue is the same.
I removed all parts that aren't involved in triggering the error message (the original use case has trait methods with related return types).
It comes down to the following error message:
rustc 1.16.0 (30cf806ef 2017-03-10)
error: `content` does not live long enough
--> <anon>:64:1
|
62 | let _ = apply(&content, parser);
| ------- borrow occurs here
63 | };
64 | }
| ^ `content` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
error: aborting due to previous error
And here is the triggering code:
trait Parse<'input> {
type Output;
}
// needs one parser which has its Output depending on the input
struct AnyParser;
impl<'input> Parse<'input>
for AnyParser {
type Output = &'input str;
}
// also needs another parser taking a closure that takes a subparsers
// result
fn fold<P, I, F>(parser: P, init: I, fold: F) -> Fold<P, I, F>
{
Fold {
parser: parser,
init: init,
fold: fold,
}
}
struct Fold<P, I, F> {
parser: P,
init: I,
fold: F,
}
impl<'input, P, I, F, T> Parse<'input>
for Fold<P, I, F>
where
P: Parse<'input>,
I: Fn() -> T,
F: Fn(T, P::Output) -> T,
{
type Output = T;
}
// taking the content and the parser together
fn apply<'input, P>(input: &'input str, parser: P)
where
P: Parse<'input>,
{
unimplemented!();
}
fn main() {
let parser = fold(
AnyParser,
// these closures seems to make it think the parser holds on to
// the AnyParser result (which is part of the input)
|| None,
|_, v| Some(v),
);
// rustc says this must outlive the parser, which is unfortunate
let content: String = "foo".into();
{
let _ = apply(&content, parser);
};
}