Bound Lifetime Parameter vs Concrete Lifetime


#1

I’m having issues dealing with lifetimes in a function that takes a function as an argument.

The function that gets passed into my function comes from the Nom parser combinator library.

enum ParserError<'a> {
   FailedParse(&'a str),
 }

 type ParseResult<'a, T> = Result<T, ParserError<'a>>;

 fn parse<'a, T, NomParser>(input: &'a str, parser: NomParser) -> ParseResult<'a, T> where NomParser: Fn(&[u8]) -> IResult<&[u8], T> {                  
   unimplemented!()
 }

I get the following error:

src/lib.rs:105:18: 105:23 error: type mismatch resolving `for<'r> <fn(&[u8]) -> nom::internal::IResult<&[u8], Expression<'_>> {parser} as core::ops::FnOnce<(&'r [u8],)>>::Output == nom::internal::IResult<&'r [u8], _>`:
 expected bound lifetime parameter ,
    found concrete lifetime [E0271]
src/lib.rs:105     let actual = parse(input, parser);
                                ^~~~~
src/lib.rs:105:18: 105:23 help: run `rustc --explain E0271` to see a detailed explanation
src/lib.rs:105:18: 105:23 note: required by `parse`

It seems to be because T in this particular invocation of parse has an associated lifetime (i.e. T is Expression<'a> in this case).

I’m not quite sure how to solve this issue. Any help would be greatly appreciated.


#2

You didn’t include some of the relevant code, but I’m guessing a full testcase looks something like this:

struct Expression<'a>(&'a i32);

fn parse<'a, T, NomParser>(input: &'a str, parser: NomParser) where NomParser: Fn(&[u8]) -> Result<&[u8], T> {                  
    unimplemented!();
}

// Lifetimes explicitly written here; maybe implicit in your code
fn parser<'a>(x: &'a [u8]) -> Result<&'a [u8], Expression<'a>> {
    unimplemented!();
}

fn main() {
    parse("asdf", parser);
}

The problem is the lifetime of Expression: the parser function needs to match Fn(&[u8]) -> Result<&[u8], T>, but T is independent of the lifetime of the input string.

Maybe you want fn parse<'a, T, NomParser>(input: &'a str, parser: NomParser) -> ParseResult<'a, T> where NomParser: Fn(&'a [u8]) -> IResult<&[u8], T> {? That forces all the relevant lifetimes to be tied to the lifetime of the input string.


#3

Thanks! That works. I somehow missed the extra lifetime annotation that makes everything line up. I appreciate your help!