2

I've run into a specific lifetime issue in Rust that I cannot wrap my head around, after taking a look at this post, this post, and several other similar ones. In particular, I have these structs & associated implementations:

use std::collections::hash_map::HashMap;
use std::mem;

pub struct JsVar {
    binding: String,
}

pub struct Scope<'a> {
    pub vars: Vec<JsVar>,
    locals: HashMap<String, &'a JsVar>,
}

impl<'a> Scope<'a> {
    pub fn new() -> Scope<'a> {
        Scope {
            vars: Vec::new(),
            locals: HashMap::new(),
        }
    }

    pub fn rebind_var(&'a mut self, var: JsVar) {
        self.vars.push(var);
        let var_ref: &'a JsVar = match self.vars.last() {
            Some(var) => var,
            None => unreachable!(),
        };
        self.locals.insert(var_ref.binding.clone(), var_ref);
    }
}

pub struct ScopeManager<'a> {
    scopes: Vec<Scope<'a>>,
}

impl<'a> ScopeManager<'a> {
    pub fn pop_scope(&'a mut self, gc_yield: bool) -> Result<(), String> {
        if let Some(mut scope) = self.scopes.pop() {
            // Actual code snipped for brevity; this is the relevant operation.
            let mut vars = mem::replace(&mut scope.vars, Vec::new());
            let mut parent: &mut Scope<'a> = self.scopes.last_mut().unwrap();
            while let Some(var) = vars.pop() {
                parent.rebind_var(var);
            }
            Ok(())
        } else {
            Err(String::from("Bad Scope"))
        }
    }
}

Playpen Link

The compiler complains

cannot borrow *parent as mutable more than once at a time

on the line that reads parent.rebind_var(var), which I think is due to the 'a lifetime annotation on self in the method definition, which causes parent to be borrowed for the length of the entire method. However, if I remove the 'a, then the compiler is unable to infer an appropriate lifetime for self.scopes on the line where parent is bound. Based on this information, I don't understand

  1. how to make parent not bound to the lifetime of self and
  2. still be able to bind parent such that its lifetime is correct.
Community
  • 1
  • 1
  • Updated above, sorry about that! – doctor_haifisch Mar 16 '16 at 01:28
  • You are [trying to store a `String` and a reference to that `String` in the same struct](http://stackoverflow.com/q/32300132/155423). Likely a duplicate. – Shepmaster Mar 16 '16 at 01:49
  • I'm cloning the `String` before storing it, so the `String` inside the struct is not referenced. Unless you're talking about different code from `self.locals.insert(var_ref.binding.clone(), var_ref);`? – doctor_haifisch Mar 16 '16 at 02:04
  • Yes, from `self.locals.insert(var_ref.binding.clone(), var_ref)`, as `var_ref` is a reference into `self.vars`. That's what drives the requirement of `&'a mut self` which is then causing the other problems. – Shepmaster Mar 16 '16 at 02:05
  • Duh. I was just talking to someone about how you can't do this, and went and did it myself. – doctor_haifisch Mar 16 '16 at 02:09
  • 1
    You can mark this as a duplicate yourself if you think the other question is useful enough, or you can wait for someone who isn't half-asleep to give a real answer instead of comments, or you can self-answer; up to you! – Shepmaster Mar 16 '16 at 02:15

0 Answers0