///|
// Clean environments, additive fields and manifestation own runtime frames.
// A tail call can remove the current frame only if tailstrict created it.
fn Vm::push_frame(self : Vm, loc : Location, trimmable : Bool) -> Unit raise {
  if self.frames.length() >= self.limits.stack {
    raise self.trace_problem(Limit, loc, "max stack frames exceeded.")
  }
  self.frames.push({ trimmable, trace: self.current_trace, })
  self.current_trace = None
}

///|
fn Vm::eval_frame(
  self : Vm,
  expr : Expr,
  env : Env,
  trimmable? : Bool = false,
) -> Value raise {
  self.push_frame(expr.loc, trimmable)
  let size = self.frames.length()
  // A tail call may already have removed this frame.
  defer (if self.frames.length() == size { self.pop_frame() })
  self.eval(expr, env, tail=true, preserve_binding=true)
}