I'm writing my own interpreter for a DSL we use at work and ran into a funny problem when implementing nested stack frames.
The general idea is each stack frame has a reference to it's parent (Option<&'a mut Frame<'a>>
), with the root frame being stack-allocated and having the type Frame<'static>
, then every time the interpreter reaches a call instruction it'll allocate a frame on the (rust) stack, give it a mutable reference to it's parent, then recurse.
I feel like this should be sound and that the lifetimes line up correctly, but the compiler keeps saying these two types are declared with different lifetimes... but data from `frame` flows into `frame` here
and points to a non-existent error code (rustc --explain E0623
).
Does anyone know where my logic went wrong?
TL;DR:
struct Frame<'a> {
parent: Option<&'a mut Frame<'a>>,
}
fn execute(frame: &mut Frame<'_>, i: usize) {
if i > 0 {
println!("Call {}", i);
let child_frame = Frame {
parent: Some(frame),
};
execute(&mut child_frame, i - 1);
}
}
fn main() {
let mut root = Frame { parent: None };
execute(&mut root, 5);
}
The above errors with the output:
Compiling playground v0.0.1 (/playground)
error[E0623]: lifetime mismatch
--> src/main.rs:9:26
|
5 | fn execute(frame: &mut Frame<'_>, i: usize) {
| --------------
| |
| these two types are declared with different lifetimes...
...
9 | parent: Some(frame),
| ^^^^^ ...but data from `frame` flows into `frame` here
error: aborting due to previous error
For more information about this error, try `rustc --explain E0623`.
error: Could not compile `playground`.