Writing a simple interpreter has lead me to this battle with the borrow checker.
#[derive(Clone, Debug)]
struct Context<'a> {
    display_name: &'a str,
    parent: Option<Box<Context<'a>>>,
    parent_entry_pos: Position<'a>,
}
// --snip--
#[derive(Copy, Clone, Debug)]
pub enum BASICVal<'a> {
    Float(f64, Position<'a>, Position<'a>, &'a Context<'a>),
    Int(i64, Position<'a>, Position<'a>, &'a Context<'a>),
    Nothing(Position<'a>, Position<'a>, &'a Context<'a>),
}
// --snip--
pub fn run<'a>(text: &'a String, filename: &'a String) -> Result<(Context<'a>, BASICVal<'a>), BASICError<'a>> {
    // generate tokens
    let mut lexer = Lexer::new(text, filename);
    let tokens = lexer.make_tokens()?;
    // parse program to AST
    let mut parser = Parser::new(tokens);
    let ast = parser.parse();
    // run the program
    let context: Context<'static> = Context {
        display_name: "<program>",
        parent: None,
        parent_entry_pos: Position::default(),
    };
    Ok((context, interpreter_visit(&ast?, &context)?))
}
The error is "cannot return value referencing local variable `context`" and (secondary) the "borrow of moved value: `context`":
error[E0515]: cannot return value referencing local variable `context`
   --> src\basic.rs:732:2
    |
732 |     Ok((context, interpreter_visit(&ast?, &context)?))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------^^^^
    |     |                                     |
    |     |                                     `context` is borrowed here
    |     returns a value referencing data owned by the current function
error[E0382]: borrow of moved value: `context`
   --> src\basic.rs:732:40
    |
727 |     let context: Context<'static> = Context {
    |         ------- move occurs because `context` has type `basic::Context<'_>`, which does not implement the `Copy` trait
...
732 |     Ok((context, interpreter_visit(&ast?, &context)?))
    |         ------- value moved here          ^^^^^^^^ value borrowed here after move
As far as I understand it: The context references several lifetime-dependent structs. The values of these structs are static in this case, as I can see by explicitly setting the lifetime parameter to 'static and the compiler not complaining. The interpreter_visit function needs to borrow the context because it gets passed to several independent functions, including itself recursively. In addition, the interpreter_visit returns BASICVals that reference the context themselves. For this reason, the context needs to outlive the run return. I try to achieve that by passing the context itself as part of the return value, thereby giving the caller control over its life. But now, I move the context to the return value before actually using it? This makes no sense. I should be able to reference one part of the return value in another part of the return value because both values make it out of the function "alive". I have tried:
- boxing the context, thereby forcing it off the stack onto the heap, but that seems to only complicate things.
- switching the order of the tuple, but that doesn't help.
- storing interpreter_visit's result in an intermediate variable, which as expected doesn't help.
- cloning the interpreter_visit result or the context itself
The issue may lie with the result and the error. The error doesn't reference a context but giving it a separate lifetime in interpreter_visit breaks the entire careful balance I have been able to achieve until now.
