Repository: HigherOrderCO/Bend
File: src/imp/gen_map_get.rs (Rust)

Code before:
        if let Some(nxt) = nxt {
          nxt.gen_map_get(id);
        }
      }
      Stmt::Return { term } => {
        let substitutions = term.substitute_map_gets(id);
        if !substitutions.is_empty() {
          *self = gen_get(self, substitutions);
        }
      }
      Stmt::Open { typ: _, var: _, nxt } => {
        nxt.gen_map_get(id);
      }
      Stmt::Use { nam: _, val: bod, nxt } => {
        nxt.gen_map_get(id);
        let substitutions = bod.substitute_map_gets(id);
        if !substitutions.is_empty() {
          *self = gen_get(self, substitutions);
        }
      }
      Stmt::Err => {}
    }
  }
}

type Substitutions = IndexMap<Name, (Name, Box<Expr>)>;

impl Expr {
  fn substitute_map_gets(&mut self, id: &mut usize) -> Substitutions {
    fn go(e: &mut Expr, substitutions: &mut Substitutions, id: &mut usize) {
      match e {
        Expr::MapGet { nam, key } => {
          go(key, substitutions, id);
          let new_var = gen_map_var(id);
          substitutions.insert(new_var.clone(), (nam.clone(), key.clone()));
          *e = Expr::Var { nam: new_var };
        }
        Expr::Call { fun, args, kwargs } => {
          go(fun, substitutions, id);
          for arg in args {
            go(arg, substitutions, id);
          }
          for (_, arg) in kwargs {
            go(arg, substitutions, id);
          }
        }
        Expr::Lam { bod, .. } => {
          go(bod, substitutions, id);
        }
        Expr::Bin { lhs, rhs, .. } => {
          go(lhs, substitutions, id);

Review comment (suggestion):
If all we need is to do an rfold, we could have Substitutions be a simple `Vec<(Name, Name, Box<Expr>)>`

Code after:
        }
      }
      Stmt::Return { term } => {
        let substitutions = term.substitute_map_gets(id);
        if !substitutions.is_empty() {
          *self = gen_get(self, substitutions);
        }
      }
      Stmt::Open { typ: _, var: _, nxt } => {
        nxt.gen_map_get(id);
      }
      Stmt::Use { nam: _, val: bod, nxt } => {
        nxt.gen_map_get(id);
        let substitutions = bod.substitute_map_gets(id);
        if !substitutions.is_empty() {
          *self = gen_get(self, substitutions);
        }
      }
      Stmt::Err => {}
    }
  }
}

type Substitutions = Vec<(Name, Name, Box<Expr>)>;

impl Expr {
  fn substitute_map_gets(&mut self, id: &mut usize) -> Substitutions {
    fn go(e: &mut Expr, substitutions: &mut Substitutions, id: &mut usize) {
      match e {
        Expr::MapGet { nam, key } => {
          go(key, substitutions, id);
          let new_var = gen_map_var(id);
          substitutions.push((new_var.clone(), nam.clone(), key.clone()));
          *e = Expr::Var { nam: new_var };
        }
        Expr::Call { fun, args, kwargs } => {
          go(fun, substitutions, id);
          for arg in args {
            go(arg, substitutions, id);
          }
          for (_, arg) in kwargs {
            go(arg, substitutions, id);
          }
        }
        Expr::Lam { bod, .. } => {
          go(bod, substitutions, id);
        }
        Expr::Bin { lhs, rhs, .. } => {
          go(lhs, substitutions, id);
          go(rhs, substitutions, id);
        }