reset reuse stuff

This commit is contained in:
Folkert 2020-09-04 23:07:45 +02:00
parent f02d907f17
commit b849a3019f
5 changed files with 265 additions and 599 deletions

View file

@ -292,6 +292,19 @@ impl<'a> BorrowInfState<'a> {
// the function must take it as an owned parameter // the function must take it as an owned parameter
self.own_args_if_param(xs); self.own_args_if_param(xs);
} }
Reset(x) => {
self.own_var(z);
self.own_var(*x);
}
Reuse {
symbol: x,
arguments: ys,
..
} => {
self.own_var(z);
self.own_var(*x);
self.own_args_if_param(ys);
}
EmptyArray => { EmptyArray => {
self.own_var(z); self.own_var(z);
} }

View file

@ -113,7 +113,15 @@ pub fn occuring_variables_expr(expr: &Expr<'_>, result: &mut MutSet<Symbol>) {
} => { } => {
result.extend(arguments.iter().copied()); result.extend(arguments.iter().copied());
} }
Reuse {
symbol, arguments, ..
} => {
result.extend(arguments.iter().copied());
result.insert(*symbol);
}
Reset(x) => {
result.insert(*x);
}
RunLowLevel(_, args) => { RunLowLevel(_, args) => {
result.extend(args.iter()); result.extend(args.iter());
} }
@ -413,12 +421,14 @@ impl<'a> Context<'a> {
live_vars.remove(&z); live_vars.remove(&z);
let new_b = match v { let new_b = match v {
Tag { arguments: ys, .. } | Struct(ys) | Array { elems: ys, .. } => self Reuse { arguments: ys, .. }
.add_inc_before_consume_all( | Tag { arguments: ys, .. }
ys, | Struct(ys)
self.arena.alloc(Stmt::Let(z, v, l, b)), | Array { elems: ys, .. } => self.add_inc_before_consume_all(
&b_live_vars, ys,
), self.arena.alloc(Stmt::Let(z, v, l, b)),
&b_live_vars,
),
AccessAtIndex { structure: x, .. } => { AccessAtIndex { structure: x, .. } => {
let b = self.add_dec_if_needed(x, b, b_live_vars); let b = self.add_dec_if_needed(x, b, b_live_vars);
let info_x = self.get_var_info(x); let info_x = self.get_var_info(x);
@ -464,7 +474,11 @@ impl<'a> Context<'a> {
self.add_inc_before(ys, ps, b, b_live_vars) self.add_inc_before(ys, ps, b, b_live_vars)
} }
EmptyArray | FunctionPointer(_, _) | Literal(_) | RuntimeErrorFunction(_) => { EmptyArray
| FunctionPointer(_, _)
| Literal(_)
| Reset(_)
| RuntimeErrorFunction(_) => {
// EmptyArray is always stack-allocated // EmptyArray is always stack-allocated
// function pointers are persistent // function pointers are persistent
self.arena.alloc(Stmt::Let(z, v, l, b)) self.arena.alloc(Stmt::Let(z, v, l, b))
@ -749,7 +763,7 @@ impl<'a> Context<'a> {
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
struct LocalContext<'a> { pub struct LocalContext<'a> {
join_points: MutMap<JoinPointId, (&'a [Param<'a>], &'a Stmt<'a>)>, join_points: MutMap<JoinPointId, (&'a [Param<'a>], &'a Stmt<'a>)>,
} }

View file

@ -569,6 +569,14 @@ pub enum Expr<'a> {
}, },
EmptyArray, EmptyArray,
Reuse {
symbol: Symbol,
tag_name: TagName,
tag_id: u8,
arguments: &'a [Symbol],
},
Reset(Symbol),
RuntimeErrorFunction(&'a str), RuntimeErrorFunction(&'a str),
} }
@ -666,6 +674,28 @@ impl<'a> Expr<'a> {
.append(alloc.space()) .append(alloc.space())
.append(alloc.intersperse(it, " ")) .append(alloc.intersperse(it, " "))
} }
Reuse {
symbol,
tag_name,
arguments,
..
} => {
let doc_tag = match tag_name {
TagName::Global(s) => alloc.text(s.as_str()),
TagName::Private(s) => alloc.text(format!("{}", s)),
};
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s));
alloc
.text("Reuse ")
.append(symbol_to_doc(alloc, *symbol))
.append(doc_tag)
.append(alloc.space())
.append(alloc.intersperse(it, " "))
}
Reset(symbol) => alloc.text("Reuse ").append(symbol_to_doc(alloc, *symbol)),
Struct(args) => { Struct(args) => {
let it = args.iter().map(|s| symbol_to_doc(alloc, *s)); let it = args.iter().map(|s| symbol_to_doc(alloc, *s));
@ -2728,6 +2758,9 @@ fn substitute_in_expr<'a>(
None None
} }
} }
Reuse { .. } | Reset(_) => unreachable!("reset/reuse have not been introduced yet"),
Struct(args) => { Struct(args) => {
let mut did_change = false; let mut did_change = false;
let new_args = Vec::from_iter_in( let new_args = Vec::from_iter_in(

View file

@ -15,6 +15,8 @@ pub mod borrow;
pub mod inc_dec; pub mod inc_dec;
pub mod ir; pub mod ir;
pub mod layout; pub mod layout;
pub mod live_vars;
pub mod reset_reuse;
pub mod tail_recursion; pub mod tail_recursion;
// Temporary, while we can build up test cases and optimize the exhaustiveness checking. // Temporary, while we can build up test cases and optimize the exhaustiveness checking.

View file

@ -1,220 +1,188 @@
use crate::expr::Env; use crate::inc_dec::LocalContext;
use crate::expr::Expr; use crate::ir::{Expr, Literal, Stmt};
use crate::layout::{Builtin, Layout};
use crate::live_vars;
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
use bumpalo::Bump;
use roc_collections::all::MutSet; use roc_collections::all::MutSet;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
pub fn function_r<'a>(env: &mut Env<'a, '_>, body: &'a Expr<'a>) -> Expr<'a> { struct Env<'a, 'b> {
use Expr::*; env: crate::ir::Env<'a, 'b>,
ctx: LocalContext<'a>,
}
match body { fn may_reuse<'a>(x: Layout<'a>, y: Layout<'a>) -> bool {
Switch { // a heuristic; we really only want the same "type" to be reused.
cond_symbol, // we could also compare actual stack size.
branches, x == y
cond, }
cond_layout,
default_branch,
ret_layout,
} => {
let stack_size = cond_layout.stack_size(env.pointer_size);
let mut new_branches = Vec::with_capacity_in(branches.len(), env.arena);
for (tag, stores, branch) in branches.iter() { fn try_function_s<'a>(
let new_branch = function_d(env, *cond_symbol, stack_size as _, branch); env: &mut Env<'a, '_>,
x: Symbol,
layout: Layout<'a>,
stmt: &'a Stmt<'a>,
) -> &'a Stmt<'a> {
let arena = env.env.arena;
new_branches.push((*tag, *stores, new_branch)); let w = env.env.unique_symbol();
}
let new_default_branch = ( match function_s(env, w, stmt) {
default_branch.0, None => stmt,
&*env.arena.alloc(function_d( Some(new) => arena.alloc(Stmt::Let(w, Expr::Reset(x), layout, new)),
env, }
*cond_symbol, }
stack_size as _,
default_branch.1,
)),
);
fn function_s<'a>(env: &mut Env<'a, '_>, w: Symbol, stmt: &'a Stmt<'a>) -> Option<&'a Stmt<'a>> {
use Stmt::*;
let arena = env.env.arena;
match stmt {
_ => todo!(),
}
}
fn function_d_main<'a>(
env: &mut Env<'a, '_>,
x: Symbol,
layout: Layout<'a>,
stmt: &'a Stmt<'a>,
) -> (Option<&'a Stmt<'a>>, bool) {
/*
let c = layout;
use Stmt::*;
let arena = env.env.arena;
match stmt {
Switch { Switch {
cond_symbol: *cond_symbol, cond_symbol,
branches: new_branches.into_bump_slice(), cond_layout,
default_branch: new_default_branch, branches,
ret_layout: ret_layout.clone(), default_branch,
cond: *cond, ret_layout,
cond_layout: cond_layout.clone(), } => {
// TODO only conditionally re-build the expression
let live = live_vars::collect_stmt(stmt, env.ctx)
let branches = Vec::from_iter_in(
branches.iter().map(|(label, branch)| {
let branch = function_r(env, branch).unwrap_or(branch);
let branch = function_d(env, *cond_symbol, cond_layout.clone(), branch)
.unwrap_or(branch);
(*label, branch.clone())
}),
arena,
)
.into_bump_slice();
let default_branch = function_r(env, default_branch).unwrap_or(default_branch);
let default_branch = function_d(env, *cond_symbol, cond_layout.clone(), default_branch)
.unwrap_or(default_branch);
let switch = Switch {
cond_symbol: *cond_symbol,
branches,
default_branch,
cond_layout: cond_layout.clone(),
ret_layout: ret_layout.clone(),
};
Some(arena.alloc(switch))
} }
}
Cond {
cond_symbol,
cond_layout,
branching_symbol,
branching_layout,
pass,
fail,
ret_layout,
} => {
let stack_size = cond_layout.stack_size(env.pointer_size);
let new_pass = ( Join { .. } => todo!(),
pass.0,
&*env
.arena
.alloc(function_d(env, *cond_symbol, stack_size as _, pass.1)),
);
let new_fail = ( Ret(_) | Jump(_, _) | RuntimeError(_) => None,
fail.0,
&*env Inc(x, b) => match function_r(env, b) {
.arena None => None,
.alloc(function_d(env, *cond_symbol, stack_size as _, fail.1)), Some(new_b) => Some(arena.alloc(Inc(*x, new_b))),
); },
Dec(x, b) => match function_r(env, b) {
None => None,
Some(new_b) => Some(arena.alloc(Dec(*x, new_b))),
},
Let(x, v, l, b) => match function_r(env, b) {
None => None,
Some(new_b) => Some(arena.alloc(Let(*x, v.clone(), l.clone(), new_b))),
},
Cond { Cond {
cond_symbol: *cond_symbol, cond_symbol,
cond_layout: cond_layout.clone(), cond_layout,
branching_symbol: *branching_symbol, branching_symbol,
branching_layout: branching_layout.clone(), branching_layout,
ret_layout: ret_layout.clone(), pass,
pass: new_pass, fail,
fail: new_fail, ret_layout,
} => {
// TODO only conditionally re-build the expression
let pass = function_r(env, pass).unwrap_or(pass);
let pass = function_d(env, *cond_symbol, cond_layout.clone(), pass).unwrap_or(pass);
let fail = function_r(env, fail).unwrap_or(fail);
let fail = function_d(env, *cond_symbol, cond_layout.clone(), fail).unwrap_or(fail);
let stmt = Cond {
cond_symbol: *cond_symbol,
cond_layout: cond_layout.clone(),
branching_symbol: *branching_symbol,
branching_layout: branching_layout.clone(),
pass,
fail,
ret_layout: ret_layout.clone(),
};
Some(arena.alloc(stmt))
} }
} }
*/
Store(stores, body) => { panic!();
let new_body = function_r(env, body);
Store(stores, env.arena.alloc(new_body))
}
DecAfter(symbol, body) => {
let new_body = function_r(env, body);
DecAfter(*symbol, env.arena.alloc(new_body))
}
CallByName { .. }
| CallByPointer(_, _, _)
| RunLowLevel(_, _)
| Tag { .. }
| Struct(_)
| Array { .. }
| AccessAtIndex { .. } => {
// TODO
// how often are `when` expressions in one of the above?
body.clone()
}
Int(_)
| Float(_)
| Str(_)
| Bool(_)
| Byte(_)
| Load(_)
| EmptyArray
| Inc(_, _)
| FunctionPointer(_, _)
| RuntimeError(_)
| RuntimeErrorFunction(_) => body.clone(),
Reset(_, _) | Reuse(_, _) => unreachable!("reset/reuse should not have been inserted yet!"),
}
} }
fn function_d<'a>( fn function_d<'a>(
env: &mut Env<'a, '_>, env: &mut Env<'a, '_>,
z: Symbol, x: Symbol,
stack_size: usize, layout: Layout<'a>,
body: &'a Expr<'a>, stmt: &'a Stmt<'a>,
) -> Expr<'a> { ) -> Option<&'a Stmt<'a>> {
let symbols = symbols_in_expr(body); let c = layout;
if symbols.contains(&z) { todo!();
return body.clone();
}
if let Ok(reused) = function_s(env, z, stack_size, body) {
Expr::Reset(z, env.arena.alloc(reused))
} else {
body.clone()
}
/*
match body {
Expr::Tag { .. } => Some(env.arena.alloc(Expr::Reuse(w, body))),
_ => None,
}
*/
} }
fn function_s<'a>( fn function_r<'a>(env: &mut Env<'a, '_>, stmt: &'a Stmt<'a>) -> Option<&'a Stmt<'a>> {
env: &mut Env<'a, '_>, use Stmt::*;
w: Symbol,
stack_size: usize,
body: &'a Expr<'a>,
) -> Result<&'a Expr<'a>, &'a Expr<'a>> {
use Expr::*;
match body { let arena = env.env.arena;
Tag { tag_layout, .. } => {
if tag_layout.stack_size(env.pointer_size) as usize <= stack_size {
Ok(env.arena.alloc(Expr::Reuse(w, body)))
} else {
Err(body)
}
}
Array { .. } | Struct(_) => { match stmt {
// TODO Join { .. } => todo!(),
Err(body)
}
Switch { Ret(_) | Jump(_, _) | RuntimeError(_) => None,
cond_symbol,
branches,
cond,
cond_layout,
default_branch,
ret_layout,
} => {
// we can re-use `w` in each branch
let mut has_been_reused = false;
let mut new_branches = Vec::with_capacity_in(branches.len(), env.arena);
for (tag, stores, branch) in branches.iter() {
match function_s(env, *cond_symbol, stack_size as _, branch) {
Ok(new_branch) => {
has_been_reused = true;
new_branches.push((*tag, *stores, new_branch.clone()));
}
Err(new_branch) => {
new_branches.push((*tag, *stores, new_branch.clone()));
}
}
}
let new_default_branch = ( Inc(x, b) => match function_r(env, b) {
default_branch.0, None => None,
match function_s(env, *cond_symbol, stack_size, default_branch.1) { Some(new_b) => Some(arena.alloc(Inc(*x, new_b))),
Ok(new) => { },
has_been_reused = true;
new
}
Err(new) => new,
},
);
let result = env.arena.alloc(Switch {
cond_symbol: *cond_symbol,
branches: new_branches.into_bump_slice(),
default_branch: new_default_branch,
ret_layout: ret_layout.clone(),
cond: *cond,
cond_layout: cond_layout.clone(),
});
if has_been_reused { Dec(x, b) => match function_r(env, b) {
Ok(result) None => None,
} else { Some(new_b) => Some(arena.alloc(Dec(*x, new_b))),
Err(result) },
}
} Let(x, v, l, b) => match function_r(env, b) {
None => None,
Some(new_b) => Some(arena.alloc(Let(*x, v.clone(), l.clone(), new_b))),
},
Cond { Cond {
cond_symbol, cond_symbol,
@ -225,424 +193,60 @@ fn function_s<'a>(
fail, fail,
ret_layout, ret_layout,
} => { } => {
let mut has_been_reused = false; // TODO only conditionally re-build the expression
let new_pass = (
pass.0,
match function_s(env, *cond_symbol, stack_size, pass.1) {
Ok(new) => {
has_been_reused = true;
new
}
Err(new) => new,
},
);
let new_fail = ( let pass = function_r(env, pass).unwrap_or(pass);
fail.0, let pass = function_d(env, *cond_symbol, cond_layout.clone(), pass).unwrap_or(pass);
match function_s(env, *cond_symbol, stack_size, fail.1) {
Ok(new) => {
has_been_reused = true;
new
}
Err(new) => new,
},
);
let result = env.arena.alloc(Cond { let fail = function_r(env, fail).unwrap_or(fail);
let fail = function_d(env, *cond_symbol, cond_layout.clone(), fail).unwrap_or(fail);
let stmt = Cond {
cond_symbol: *cond_symbol, cond_symbol: *cond_symbol,
cond_layout: cond_layout.clone(), cond_layout: cond_layout.clone(),
branching_symbol: *branching_symbol, branching_symbol: *branching_symbol,
branching_layout: branching_layout.clone(), branching_layout: branching_layout.clone(),
pass,
fail,
ret_layout: ret_layout.clone(), ret_layout: ret_layout.clone(),
pass: new_pass, };
fail: new_fail,
});
if has_been_reused { Some(arena.alloc(stmt))
Ok(result)
} else {
Err(result)
}
} }
Switch {
cond_symbol,
cond_layout,
branches,
default_branch,
ret_layout,
} => {
// TODO only conditionally re-build the expression
Store(stores, expr) => { let branches = Vec::from_iter_in(
let new_expr = function_s(env, w, stack_size, expr)?; branches.iter().map(|(label, branch)| {
let branch = function_r(env, branch).unwrap_or(branch);
let branch = function_d(env, *cond_symbol, cond_layout.clone(), branch)
.unwrap_or(branch);
Ok(env.arena.alloc(Store(*stores, new_expr))) (*label, branch.clone())
} }),
arena,
)
.into_bump_slice();
DecAfter(symbol, expr) => { let default_branch = function_r(env, default_branch).unwrap_or(default_branch);
let new_expr = function_s(env, w, stack_size, expr)?; let default_branch = function_d(env, *cond_symbol, cond_layout.clone(), default_branch)
.unwrap_or(default_branch);
Ok(env.arena.alloc(DecAfter(*symbol, new_expr))) let switch = Switch {
} cond_symbol: *cond_symbol,
CallByName { .. } | CallByPointer(_, _, _) | RunLowLevel(_, _) | AccessAtIndex { .. } => {
// TODO
// how often are `Tag` expressions in one of the above?
Err(body)
}
Int(_)
| Float(_)
| Str(_)
| Bool(_)
| Byte(_)
| Load(_)
| EmptyArray
| Inc(_, _)
| FunctionPointer(_, _)
| RuntimeError(_)
| RuntimeErrorFunction(_) => Err(body),
Reset(_, _) | Reuse(_, _) => {
unreachable!("reset/reuse should not have been introduced yet")
}
}
}
fn free_variables<'a>(initial: &Expr<'a>) -> MutSet<Symbol> {
use Expr::*;
let mut seen = MutSet::default();
let mut bound = MutSet::default();
let mut stack = vec![initial];
// in other words, variables that are referenced, but not stored
while let Some(expr) = stack.pop() {
match expr {
FunctionPointer(symbol, _) | Load(symbol) => {
seen.insert(*symbol);
}
Reset(symbol, expr) | Reuse(symbol, expr) => {
seen.insert(*symbol);
stack.push(expr)
}
Cond {
cond_symbol,
branching_symbol,
pass,
fail,
..
} => {
seen.insert(*cond_symbol);
seen.insert(*branching_symbol);
for (symbol, _, expr) in pass.0.iter() {
seen.insert(*symbol);
stack.push(expr)
}
for (symbol, _, expr) in fail.0.iter() {
seen.insert(*symbol);
stack.push(expr)
}
}
Switch {
cond,
cond_symbol,
branches, branches,
default_branch, default_branch,
.. cond_layout: cond_layout.clone(),
} => { ret_layout: ret_layout.clone(),
stack.push(cond); };
seen.insert(*cond_symbol);
for (_, stores, expr) in branches.iter() { Some(arena.alloc(switch))
stack.push(expr);
for (symbol, _, expr) in stores.iter() {
bound.insert(*symbol);
stack.push(expr)
}
}
stack.push(default_branch.1);
for (symbol, _, expr) in default_branch.0.iter() {
seen.insert(*symbol);
stack.push(expr)
}
}
Store(stores, body) => {
for (symbol, _, expr) in stores.iter() {
bound.insert(*symbol);
stack.push(&expr)
}
stack.push(body)
}
DecAfter(symbol, body) | Inc(symbol, body) => {
seen.insert(*symbol);
stack.push(body);
}
CallByName { name, args, .. } => {
seen.insert(*name);
for (expr, _) in args.iter() {
stack.push(expr);
}
}
CallByPointer(function, args, _) => {
stack.push(function);
stack.extend(args.iter());
}
RunLowLevel(_, args) => {
for (expr, _) in args.iter() {
stack.push(expr);
}
}
Tag { arguments, .. } => {
for (symbol, _) in arguments.iter() {
seen.insert(*symbol);
}
}
Struct(arguments) => {
for (expr, _) in arguments.iter() {
stack.push(expr);
}
}
Array { elems, .. } => {
for expr in elems.iter() {
stack.push(expr);
}
}
AccessAtIndex { expr, .. } => {
stack.push(expr);
}
Int(_)
| Float(_)
| Str(_)
| Bool(_)
| Byte(_)
| EmptyArray
| RuntimeError(_)
| RuntimeErrorFunction(_) => {}
} }
} }
for symbol in bound.iter() {
seen.remove(symbol);
}
seen
}
fn symbols_in_expr<'a>(initial: &Expr<'a>) -> MutSet<Symbol> {
use Expr::*;
let mut result = MutSet::default();
let mut stack = vec![initial];
while let Some(expr) = stack.pop() {
match expr {
FunctionPointer(symbol, _) | Load(symbol) => {
result.insert(*symbol);
}
Reset(symbol, expr) | Reuse(symbol, expr) => {
result.insert(*symbol);
stack.push(expr)
}
Cond {
cond_symbol,
branching_symbol,
pass,
fail,
..
} => {
result.insert(*cond_symbol);
result.insert(*branching_symbol);
for (symbol, _, expr) in pass.0.iter() {
result.insert(*symbol);
stack.push(expr)
}
for (symbol, _, expr) in fail.0.iter() {
result.insert(*symbol);
stack.push(expr)
}
}
Switch {
cond,
cond_symbol,
branches,
default_branch,
..
} => {
stack.push(cond);
result.insert(*cond_symbol);
for (_, stores, expr) in branches.iter() {
stack.push(expr);
for (symbol, _, expr) in stores.iter() {
result.insert(*symbol);
stack.push(expr)
}
}
stack.push(default_branch.1);
for (symbol, _, expr) in default_branch.0.iter() {
result.insert(*symbol);
stack.push(expr)
}
}
Store(stores, body) => {
for (symbol, _, expr) in stores.iter() {
result.insert(*symbol);
stack.push(&expr)
}
stack.push(body)
}
DecAfter(symbol, body) | Inc(symbol, body) => {
result.insert(*symbol);
stack.push(body);
}
CallByName { name, args, .. } => {
result.insert(*name);
for (expr, _) in args.iter() {
stack.push(expr);
}
}
CallByPointer(function, args, _) => {
stack.push(function);
stack.extend(args.iter());
}
RunLowLevel(_, args) => {
for (expr, _) in args.iter() {
stack.push(expr);
}
}
Tag { arguments, .. } => {
for (symbol, _) in arguments.iter() {
result.insert(*symbol);
}
}
Struct(arguments) => {
for (expr, _) in arguments.iter() {
stack.push(expr);
}
}
Array { elems, .. } => {
for expr in elems.iter() {
stack.push(expr);
}
}
AccessAtIndex { expr, .. } => {
stack.push(expr);
}
Int(_)
| Float(_)
| Str(_)
| Bool(_)
| Byte(_)
| EmptyArray
| RuntimeError(_)
| RuntimeErrorFunction(_) => {}
}
}
result
}
pub fn function_c<'a>(env: &mut Env<'a, '_>, body: Expr<'a>) -> Expr<'a> {
let fv = free_variables(&body);
function_c_help(env, body, fv)
}
pub fn function_c_help<'a>(env: &mut Env<'a, '_>, body: Expr<'a>, fv: MutSet<Symbol>) -> Expr<'a> {
use Expr::*;
match body {
Tag { arguments, .. } => {
let symbols = arguments
.iter()
.map(|(x, _)| x)
.copied()
.collect::<std::vec::Vec<_>>();
function_c_app(env, &symbols, &fv, body)
}
_ => body,
}
}
fn function_c_app<'a>(
env: &mut Env<'a, '_>,
arguments: &[Symbol],
orig_fv: &MutSet<Symbol>,
mut application: Expr<'a>,
) -> Expr<'a> {
// in the future, this will need to be a check
let is_owned = true;
for (i, y) in arguments.iter().rev().enumerate() {
if is_owned {
let mut fv = orig_fv.clone();
fv.extend(arguments[i..].iter().copied());
application = insert_increment(env, *y, fv, application)
} else {
unimplemented!("owned references are not implemented yet")
}
}
application
}
fn insert_increment<'a>(
env: &mut Env<'a, '_>,
symbol: Symbol,
live_variables: MutSet<Symbol>,
body: Expr<'a>,
) -> Expr<'a> {
// in the future, this will need to be a check
let is_owned = true;
if is_owned && !live_variables.contains(&symbol) {
body
} else {
Expr::Inc(symbol, env.arena.alloc(body))
}
}
fn insert_decrement<'a>(env: &mut Env<'a, '_>, symbols: &[Symbol], mut body: Expr<'a>) -> Expr<'a> {
// in the future, this will need to be a check
let is_owned = true;
let fv = free_variables(&body);
for symbol in symbols.iter() {
let is_dead = !fv.contains(&symbol);
if is_owned && is_dead {
body = Expr::DecAfter(*symbol, env.arena.alloc(body));
}
}
body
} }