Hello!
I'm trying to make a combinator parser library, very much inspired by nom
. I want to add the notion of combinators being able to express what they expect from the input, ideally by returning some formatter that builds this string later (as combinators tend to do a lot of trial-and-error, so this error information needs to be very cheaply available until it is presented to the user). But I'm running into some lifetime issues.
In particular, I'm working with nom's tag()
in the back of my mind, where the combinator itself depends on some external data (in this case a byte array) that influences what it expects. So I'd like my representation of a tag to return something like:
struct TagExpectsFormatter<'t> {
tag: &'t [u8],
}
which can then implement something like Display
to build the string later on.
However, this pattern gives me trouble when I try to write higher-order combinators, like pair()
. I wrote something like the following:
use std::fmt::Display;
trait Expects<'t> {
type Formatter: 't + Display;
fn expects(&self) -> Self::Formatter;
}
struct PairExpects<F1, F2> {
fmt1: F1,
fmt2: F2,
}
struct Pair<C1, C2>(C1, C2);
impl<'t1, 't2: 't1, C1: Expects<'t1>, C2: Expects<'t2>> Expects<'t1> for Pair<C1, C2> {
type Formatter = PairExpects<C1::Formatter, C2::Formatter>;
fn expects(&self) -> Self::Formatter {
PairExpects {
fmt1: self.0.expects(),
fmt2: self.1.expects(),
}
}
}
(playground, I took the lifetime bounds from this thread)
But this gives me the following error:
Compiling playground v0.0.1 (/playground)
error[E0207]: the lifetime parameter `'t2` is not constrained by the impl trait, self type, or predicates
--> src/main.rs:19:11
|
19 | impl<'t1, 't2: 't1, C1: Expects<'t1>, C2: Expects<'t2>> Expects<'t1> for Pair<C1, C2> {
| ^^^ unconstrained lifetime parameter
For more information about this error, try `rustc --explain E0207`.
error: could not compile `playground` (bin "playground") due to 1 previous error
Reading the rustc --explain E0207
that the compiler suggests, I guess that this has something do with unconstrained lifetimes being illegal if they occur in associated types of a trait, which seems to happen through the Expects::Formatter
(also see the RFC that text suggests).
I'm not sure how to fix this problem, though. Can someone help me make this pattern work? Or else suggest me some other pattern with which I can propagate these lifetimes of nested, generic combinators through higher-order ones?
Thanks,
Tim