mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 06:14:46 +00:00
cleanup
This commit is contained in:
parent
eb793b2b44
commit
d784f62cd3
5 changed files with 661 additions and 532 deletions
|
@ -36,6 +36,38 @@ pub struct Proc<'a> {
|
||||||
pub ret_layout: Layout<'a>,
|
pub ret_layout: Layout<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> Proc<'a> {
|
||||||
|
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D, parens: bool) -> DocBuilder<'b, D, A>
|
||||||
|
where
|
||||||
|
D: DocAllocator<'b, A>,
|
||||||
|
D::Doc: Clone,
|
||||||
|
A: Clone,
|
||||||
|
{
|
||||||
|
let args_doc = self
|
||||||
|
.args
|
||||||
|
.iter()
|
||||||
|
.map(|(_, symbol)| alloc.text(format!("{}", symbol)));
|
||||||
|
|
||||||
|
alloc
|
||||||
|
.text(format!("procedure {} (", self.name))
|
||||||
|
.append(alloc.intersperse(args_doc, ", "))
|
||||||
|
.append("):")
|
||||||
|
.append(alloc.hardline())
|
||||||
|
.append(self.body.to_doc(alloc, false).indent(4))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_pretty(&self, width: usize) -> String {
|
||||||
|
let allocator = BoxAllocator;
|
||||||
|
let mut w = std::vec::Vec::new();
|
||||||
|
self.to_doc::<_, ()>(&allocator, false)
|
||||||
|
.1
|
||||||
|
.render(width, &mut w)
|
||||||
|
.unwrap();
|
||||||
|
w.push(b'\n');
|
||||||
|
String::from_utf8(w).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Default)]
|
#[derive(Clone, Debug, PartialEq, Default)]
|
||||||
pub struct Procs<'a> {
|
pub struct Procs<'a> {
|
||||||
pub partial_procs: MutMap<Symbol, PartialProc<'a>>,
|
pub partial_procs: MutMap<Symbol, PartialProc<'a>>,
|
||||||
|
@ -368,433 +400,6 @@ pub enum Expr<'a> {
|
||||||
RuntimeError(&'a str),
|
RuntimeError(&'a str),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_r<'a>(env: &mut Env<'a, '_>, body: &'a Expr<'a>) -> Expr<'a> {
|
|
||||||
use Expr::*;
|
|
||||||
|
|
||||||
match body {
|
|
||||||
Switch {
|
|
||||||
cond_symbol,
|
|
||||||
branches,
|
|
||||||
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() {
|
|
||||||
let new_branch = function_d(env, *cond_symbol, stack_size as _, branch);
|
|
||||||
|
|
||||||
new_branches.push((*tag, *stores, new_branch));
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_default_branch = (
|
|
||||||
default_branch.0,
|
|
||||||
&*env.arena.alloc(function_d(
|
|
||||||
env,
|
|
||||||
*cond_symbol,
|
|
||||||
stack_size as _,
|
|
||||||
default_branch.1,
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
|
|
||||||
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(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 = (
|
|
||||||
pass.0,
|
|
||||||
&*env
|
|
||||||
.arena
|
|
||||||
.alloc(function_d(env, *cond_symbol, stack_size as _, pass.1)),
|
|
||||||
);
|
|
||||||
|
|
||||||
let new_fail = (
|
|
||||||
fail.0,
|
|
||||||
&*env
|
|
||||||
.arena
|
|
||||||
.alloc(function_d(env, *cond_symbol, stack_size as _, fail.1)),
|
|
||||||
);
|
|
||||||
|
|
||||||
Cond {
|
|
||||||
cond_symbol: *cond_symbol,
|
|
||||||
cond_layout: cond_layout.clone(),
|
|
||||||
branching_symbol: *branching_symbol,
|
|
||||||
branching_layout: branching_layout.clone(),
|
|
||||||
ret_layout: ret_layout.clone(),
|
|
||||||
pass: new_pass,
|
|
||||||
fail: new_fail,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Store(stores, body) => {
|
|
||||||
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
|
|
||||||
| LoadWithoutIncrement(_)
|
|
||||||
| FunctionPointer(_, _)
|
|
||||||
| RuntimeError(_)
|
|
||||||
| RuntimeErrorFunction(_) => body.clone(),
|
|
||||||
|
|
||||||
Reset(_, _) | Reuse(_, _) => unreachable!("reset/reuse should not have been inserted yet!"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn function_d<'a>(
|
|
||||||
env: &mut Env<'a, '_>,
|
|
||||||
z: Symbol,
|
|
||||||
stack_size: usize,
|
|
||||||
body: &'a Expr<'a>,
|
|
||||||
) -> Expr<'a> {
|
|
||||||
let symbols = symbols_in_expr(body);
|
|
||||||
if symbols.contains(&z) {
|
|
||||||
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>(
|
|
||||||
env: &mut Env<'a, '_>,
|
|
||||||
w: Symbol,
|
|
||||||
stack_size: usize,
|
|
||||||
body: &'a Expr<'a>,
|
|
||||||
) -> Result<&'a Expr<'a>, &'a Expr<'a>> {
|
|
||||||
use Expr::*;
|
|
||||||
|
|
||||||
match body {
|
|
||||||
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(_) => {
|
|
||||||
// TODO
|
|
||||||
Err(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
Switch {
|
|
||||||
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 = (
|
|
||||||
default_branch.0,
|
|
||||||
match function_s(env, *cond_symbol, stack_size, default_branch.1) {
|
|
||||||
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 {
|
|
||||||
Ok(result)
|
|
||||||
} else {
|
|
||||||
Err(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Cond {
|
|
||||||
cond_symbol,
|
|
||||||
cond_layout,
|
|
||||||
branching_symbol,
|
|
||||||
branching_layout,
|
|
||||||
pass,
|
|
||||||
fail,
|
|
||||||
ret_layout,
|
|
||||||
} => {
|
|
||||||
let mut has_been_reused = false;
|
|
||||||
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 = (
|
|
||||||
fail.0,
|
|
||||||
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 {
|
|
||||||
cond_symbol: *cond_symbol,
|
|
||||||
cond_layout: cond_layout.clone(),
|
|
||||||
branching_symbol: *branching_symbol,
|
|
||||||
branching_layout: branching_layout.clone(),
|
|
||||||
ret_layout: ret_layout.clone(),
|
|
||||||
pass: new_pass,
|
|
||||||
fail: new_fail,
|
|
||||||
});
|
|
||||||
|
|
||||||
if has_been_reused {
|
|
||||||
Ok(result)
|
|
||||||
} else {
|
|
||||||
Err(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DecAfter(symbol, expr) => {
|
|
||||||
let new_expr = function_s(env, w, stack_size, expr)?;
|
|
||||||
|
|
||||||
Ok(env.arena.alloc(DecAfter(*symbol, new_expr)))
|
|
||||||
}
|
|
||||||
|
|
||||||
Store(stores, expr) => {
|
|
||||||
let new_expr = function_s(env, w, stack_size, expr)?;
|
|
||||||
|
|
||||||
Ok(env.arena.alloc(Store(*stores, new_expr)))
|
|
||||||
}
|
|
||||||
|
|
||||||
CallByName { .. } | CallByPointer(_, _, _) | RunLowLevel(_, _) | AccessAtIndex { .. } => {
|
|
||||||
// TODO
|
|
||||||
// how often are `Tag` expressions in one of the above?
|
|
||||||
Err(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
Int(_)
|
|
||||||
| Float(_)
|
|
||||||
| Str(_)
|
|
||||||
| Bool(_)
|
|
||||||
| Byte(_)
|
|
||||||
| Load(_)
|
|
||||||
| EmptyArray
|
|
||||||
| LoadWithoutIncrement(_)
|
|
||||||
| FunctionPointer(_, _)
|
|
||||||
| RuntimeError(_)
|
|
||||||
| RuntimeErrorFunction(_) => Err(body),
|
|
||||||
|
|
||||||
Reset(_, _) | Reuse(_, _) => {
|
|
||||||
unreachable!("reset/reuse should not have been introduced yet")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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, _) | LoadWithoutIncrement(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) => {
|
|
||||||
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 (expr, _) in arguments.iter() {
|
|
||||||
stack.push(expr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum MonoProblem {
|
pub enum MonoProblem {
|
||||||
PatternProblem(crate::pattern::Error),
|
PatternProblem(crate::pattern::Error),
|
||||||
|
@ -806,10 +411,12 @@ impl<'a> Expr<'a> {
|
||||||
can_expr: roc_can::expr::Expr,
|
can_expr: roc_can::expr::Expr,
|
||||||
procs: &mut Procs<'a>,
|
procs: &mut Procs<'a>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
use crate::reset_reuse;
|
||||||
|
|
||||||
let mut layout_cache = LayoutCache::default();
|
let mut layout_cache = LayoutCache::default();
|
||||||
|
|
||||||
let result = from_can(env, can_expr, procs, &mut layout_cache);
|
let result = from_can(env, can_expr, procs, &mut layout_cache);
|
||||||
function_r(env, env.arena.alloc(result))
|
reset_reuse::function_r(env, env.arena.alloc(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D, parens: bool) -> DocBuilder<'b, D, A>
|
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D, parens: bool) -> DocBuilder<'b, D, A>
|
||||||
|
@ -923,6 +530,15 @@ impl<'a> Expr<'a> {
|
||||||
|
|
||||||
alloc.intersperse(it, alloc.space())
|
alloc.intersperse(it, alloc.space())
|
||||||
}
|
}
|
||||||
|
Array { elems, .. } if elems.is_empty() => alloc.text("[]"),
|
||||||
|
Array { elems, .. } => {
|
||||||
|
let it = elems.iter().map(|expr| expr.to_doc(alloc, true));
|
||||||
|
|
||||||
|
alloc
|
||||||
|
.text("[ ")
|
||||||
|
.append(alloc.intersperse(it, ", "))
|
||||||
|
.append(" ]")
|
||||||
|
}
|
||||||
AccessAtIndex { index, expr, .. } if parens => alloc
|
AccessAtIndex { index, expr, .. } if parens => alloc
|
||||||
.text(format!("(Access @{} ", index))
|
.text(format!("(Access @{} ", index))
|
||||||
.append(expr.to_doc(alloc, false))
|
.append(expr.to_doc(alloc, false))
|
||||||
|
@ -1208,11 +824,6 @@ fn from_can<'a>(
|
||||||
let symbols = roc_can::pattern::symbols_from_pattern(&def.loc_pattern.value);
|
let symbols = roc_can::pattern::symbols_from_pattern(&def.loc_pattern.value);
|
||||||
let mut result = from_can_defs(env, vec![*def], *ret_expr, layout_cache, procs);
|
let mut result = from_can_defs(env, vec![*def], *ret_expr, layout_cache, procs);
|
||||||
|
|
||||||
// TODO is order important here?
|
|
||||||
for symbol in symbols {
|
|
||||||
result = decrement_refcount(env, symbol, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1802,11 +1413,16 @@ fn from_can_defs<'a>(
|
||||||
}
|
}
|
||||||
// At this point, it's safe to assume we aren't assigning a Closure to a def.
|
// At this point, it's safe to assume we aren't assigning a Closure to a def.
|
||||||
// Extract Procs from the def body and the ret expression, and return the result!
|
// Extract Procs from the def body and the ret expression, and return the result!
|
||||||
let ret = from_can(env, ret_expr.value, procs, layout_cache);
|
let mut ret = from_can(env, ret_expr.value, procs, layout_cache);
|
||||||
|
|
||||||
if stored.is_empty() {
|
if stored.is_empty() {
|
||||||
ret
|
ret
|
||||||
} else {
|
} else {
|
||||||
|
// NOTE for scoping reasons, it's important that the refcount decrement is inside of the
|
||||||
|
// Store, not outside it.
|
||||||
|
for (symbol, _, _) in stored.iter() {
|
||||||
|
ret = decrement_refcount(env, *symbol, ret);
|
||||||
|
}
|
||||||
Expr::Store(stored.into_bump_slice(), arena.alloc(ret))
|
Expr::Store(stored.into_bump_slice(), arena.alloc(ret))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -346,8 +346,8 @@ fn layout_from_flat_type<'a>(
|
||||||
|
|
||||||
Ok(layout_from_tag_union(arena, tags, subs, pointer_size))
|
Ok(layout_from_tag_union(arena, tags, subs, pointer_size))
|
||||||
}
|
}
|
||||||
RecursiveTagUnion(_, _, _) => {
|
RecursiveTagUnion(_rec_var, _tags, _ext_var) => {
|
||||||
panic!("TODO make Layout for non-empty Tag Union");
|
panic!("TODO make Layout for empty RecursiveTagUnion");
|
||||||
}
|
}
|
||||||
EmptyTagUnion => {
|
EmptyTagUnion => {
|
||||||
panic!("TODO make Layout for empty Tag Union");
|
panic!("TODO make Layout for empty Tag Union");
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
pub mod expr;
|
pub mod expr;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
|
pub mod reset_reuse;
|
||||||
|
|
||||||
// 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.
|
||||||
// For now, following this warning's advice will lead to nasty type inference errors.
|
// For now, following this warning's advice will lead to nasty type inference errors.
|
||||||
|
|
482
compiler/mono/src/reset_reuse.rs
Normal file
482
compiler/mono/src/reset_reuse.rs
Normal file
|
@ -0,0 +1,482 @@
|
||||||
|
use crate::expr::Env;
|
||||||
|
use crate::expr::Expr;
|
||||||
|
|
||||||
|
use crate::layout::{Builtin, Layout};
|
||||||
|
use bumpalo::collections::Vec;
|
||||||
|
use bumpalo::Bump;
|
||||||
|
use roc_collections::all::{MutMap, MutSet};
|
||||||
|
use roc_module::ident::{Ident, Lowercase, TagName};
|
||||||
|
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
||||||
|
use roc_region::all::{Located, Region};
|
||||||
|
|
||||||
|
use Expr::*;
|
||||||
|
/*
|
||||||
|
R : FnBodypure → FnBodyRC
|
||||||
|
R(let x = e; F ) = let x = e; R(F )
|
||||||
|
R(ret x) = ret x
|
||||||
|
R(case x of F ) = case x of D(x,ni
|
||||||
|
, R(Fi))
|
||||||
|
where ni = #fields of x in i-th branch
|
||||||
|
D : Var × N × FnBodyRC → FnBodyRC
|
||||||
|
D(z,n, case x of F ) = case x of D(z,n, F )
|
||||||
|
D(z,n, ret x) = ret x
|
||||||
|
D(z,n, let x = e; F ) = let x = e; D(z,n, F )
|
||||||
|
if z ∈ e or z ∈ F
|
||||||
|
D(z,n, F ) = let w = reset z; S(w,n, F )
|
||||||
|
otherwise, if S(w,n, F ) , F for a fresh w
|
||||||
|
D(z,n, F ) = F otherwise
|
||||||
|
S : Var × N × FnBodyRC → FnBodyRC
|
||||||
|
S(w,n, let x = ctori y; F ) = let x = reuse w in ctori y; F
|
||||||
|
if | y |= n
|
||||||
|
S(w,n, let x = e; F ) = let x = e; S(w,n, F ) otherwise
|
||||||
|
S(w,n, ret x) = ret x
|
||||||
|
S(w,n, case x of F ) = case x of S(w,n, F )
|
||||||
|
|
||||||
|
|
||||||
|
Maybe a : [ Nothing, Just a ]
|
||||||
|
|
||||||
|
map : Maybe a -> (a -> b) -> Maybe b
|
||||||
|
map = \maybe f ->
|
||||||
|
when maybe is
|
||||||
|
Nothing -> Nothing
|
||||||
|
Just x -> Just (f x)
|
||||||
|
|
||||||
|
|
||||||
|
map : Maybe a -> (a -> b) -> Maybe b
|
||||||
|
map = \maybe f ->
|
||||||
|
when maybe is
|
||||||
|
Nothing ->
|
||||||
|
let w = reset maybe
|
||||||
|
let r = reuse w in AppliedTag("Nothing", vec![])
|
||||||
|
Just x ->
|
||||||
|
let v = f x
|
||||||
|
let w = reset maybe
|
||||||
|
let r = reuse w in AppliedTag("Just", vec![v])
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub fn function_r<'a>(env: &mut Env<'a, '_>, body: &'a Expr<'a>) -> Expr<'a> {
|
||||||
|
use Expr::*;
|
||||||
|
|
||||||
|
match body {
|
||||||
|
Switch {
|
||||||
|
cond_symbol,
|
||||||
|
branches,
|
||||||
|
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() {
|
||||||
|
let new_branch = function_d(env, *cond_symbol, stack_size as _, branch);
|
||||||
|
|
||||||
|
new_branches.push((*tag, *stores, new_branch));
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_default_branch = (
|
||||||
|
default_branch.0,
|
||||||
|
&*env.arena.alloc(function_d(
|
||||||
|
env,
|
||||||
|
*cond_symbol,
|
||||||
|
stack_size as _,
|
||||||
|
default_branch.1,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 = (
|
||||||
|
pass.0,
|
||||||
|
&*env
|
||||||
|
.arena
|
||||||
|
.alloc(function_d(env, *cond_symbol, stack_size as _, pass.1)),
|
||||||
|
);
|
||||||
|
|
||||||
|
let new_fail = (
|
||||||
|
fail.0,
|
||||||
|
&*env
|
||||||
|
.arena
|
||||||
|
.alloc(function_d(env, *cond_symbol, stack_size as _, fail.1)),
|
||||||
|
);
|
||||||
|
|
||||||
|
Cond {
|
||||||
|
cond_symbol: *cond_symbol,
|
||||||
|
cond_layout: cond_layout.clone(),
|
||||||
|
branching_symbol: *branching_symbol,
|
||||||
|
branching_layout: branching_layout.clone(),
|
||||||
|
ret_layout: ret_layout.clone(),
|
||||||
|
pass: new_pass,
|
||||||
|
fail: new_fail,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Store(stores, body) => {
|
||||||
|
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
|
||||||
|
| LoadWithoutIncrement(_)
|
||||||
|
| FunctionPointer(_, _)
|
||||||
|
| RuntimeError(_)
|
||||||
|
| RuntimeErrorFunction(_) => body.clone(),
|
||||||
|
|
||||||
|
Reset(_, _) | Reuse(_, _) => unreachable!("reset/reuse should not have been inserted yet!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn function_d<'a>(
|
||||||
|
env: &mut Env<'a, '_>,
|
||||||
|
z: Symbol,
|
||||||
|
stack_size: usize,
|
||||||
|
body: &'a Expr<'a>,
|
||||||
|
) -> Expr<'a> {
|
||||||
|
let symbols = symbols_in_expr(body);
|
||||||
|
if symbols.contains(&z) {
|
||||||
|
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>(
|
||||||
|
env: &mut Env<'a, '_>,
|
||||||
|
w: Symbol,
|
||||||
|
stack_size: usize,
|
||||||
|
body: &'a Expr<'a>,
|
||||||
|
) -> Result<&'a Expr<'a>, &'a Expr<'a>> {
|
||||||
|
use Expr::*;
|
||||||
|
|
||||||
|
match body {
|
||||||
|
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(_) => {
|
||||||
|
// TODO
|
||||||
|
Err(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
Switch {
|
||||||
|
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 = (
|
||||||
|
default_branch.0,
|
||||||
|
match function_s(env, *cond_symbol, stack_size, default_branch.1) {
|
||||||
|
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 {
|
||||||
|
Ok(result)
|
||||||
|
} else {
|
||||||
|
Err(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Cond {
|
||||||
|
cond_symbol,
|
||||||
|
cond_layout,
|
||||||
|
branching_symbol,
|
||||||
|
branching_layout,
|
||||||
|
pass,
|
||||||
|
fail,
|
||||||
|
ret_layout,
|
||||||
|
} => {
|
||||||
|
let mut has_been_reused = false;
|
||||||
|
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 = (
|
||||||
|
fail.0,
|
||||||
|
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 {
|
||||||
|
cond_symbol: *cond_symbol,
|
||||||
|
cond_layout: cond_layout.clone(),
|
||||||
|
branching_symbol: *branching_symbol,
|
||||||
|
branching_layout: branching_layout.clone(),
|
||||||
|
ret_layout: ret_layout.clone(),
|
||||||
|
pass: new_pass,
|
||||||
|
fail: new_fail,
|
||||||
|
});
|
||||||
|
|
||||||
|
if has_been_reused {
|
||||||
|
Ok(result)
|
||||||
|
} else {
|
||||||
|
Err(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Store(stores, expr) => {
|
||||||
|
let new_expr = function_s(env, w, stack_size, expr)?;
|
||||||
|
|
||||||
|
Ok(env.arena.alloc(Store(*stores, new_expr)))
|
||||||
|
}
|
||||||
|
|
||||||
|
DecAfter(symbol, expr) => {
|
||||||
|
let new_expr = function_s(env, w, stack_size, expr)?;
|
||||||
|
|
||||||
|
Ok(env.arena.alloc(DecAfter(*symbol, new_expr)))
|
||||||
|
}
|
||||||
|
|
||||||
|
CallByName { .. } | CallByPointer(_, _, _) | RunLowLevel(_, _) | AccessAtIndex { .. } => {
|
||||||
|
// TODO
|
||||||
|
// how often are `Tag` expressions in one of the above?
|
||||||
|
Err(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
Int(_)
|
||||||
|
| Float(_)
|
||||||
|
| Str(_)
|
||||||
|
| Bool(_)
|
||||||
|
| Byte(_)
|
||||||
|
| Load(_)
|
||||||
|
| EmptyArray
|
||||||
|
| LoadWithoutIncrement(_)
|
||||||
|
| FunctionPointer(_, _)
|
||||||
|
| RuntimeError(_)
|
||||||
|
| RuntimeErrorFunction(_) => Err(body),
|
||||||
|
|
||||||
|
Reset(_, _) | Reuse(_, _) => {
|
||||||
|
unreachable!("reset/reuse should not have been introduced yet")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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, _) | LoadWithoutIncrement(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) => {
|
||||||
|
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 (expr, _) in arguments.iter() {
|
||||||
|
stack.push(expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ mod test_mono {
|
||||||
use roc_module::ident::TagName;
|
use roc_module::ident::TagName;
|
||||||
use roc_module::symbol::{Interns, Symbol};
|
use roc_module::symbol::{Interns, Symbol};
|
||||||
use roc_mono::expr::Expr::{self, *};
|
use roc_mono::expr::Expr::{self, *};
|
||||||
use roc_mono::expr::Procs;
|
use roc_mono::expr::{InProgressProc, Procs};
|
||||||
use roc_mono::layout;
|
use roc_mono::layout;
|
||||||
use roc_mono::layout::{Builtin, Layout, LayoutCache};
|
use roc_mono::layout::{Builtin, Layout, LayoutCache};
|
||||||
use roc_types::subs::Subs;
|
use roc_types::subs::Subs;
|
||||||
|
@ -129,7 +129,21 @@ mod test_mono {
|
||||||
// Put this module's ident_ids back in the interns
|
// Put this module's ident_ids back in the interns
|
||||||
interns.all_ident_ids.insert(home, ident_ids);
|
interns.all_ident_ids.insert(home, ident_ids);
|
||||||
|
|
||||||
let result = mono_expr.to_pretty(200);
|
let mut procs_string = procs
|
||||||
|
.specialized
|
||||||
|
.iter()
|
||||||
|
.map(|(_, value)| {
|
||||||
|
if let InProgressProc::Done(proc) = value {
|
||||||
|
proc.to_pretty(200)
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
procs_string.push(mono_expr.to_pretty(200));
|
||||||
|
|
||||||
|
let result = procs_string.join("\n");
|
||||||
|
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
}
|
}
|
||||||
|
@ -221,33 +235,30 @@ mod test_mono {
|
||||||
let home = test_home();
|
let home = test_home();
|
||||||
let gen_symbol_0 = Interns::from_index(home, 0);
|
let gen_symbol_0 = Interns::from_index(home, 0);
|
||||||
|
|
||||||
DecAfter(
|
Struct(&[
|
||||||
gen_symbol_0,
|
(
|
||||||
&Struct(&[
|
CallByName {
|
||||||
(
|
name: gen_symbol_0,
|
||||||
CallByName {
|
layout: Layout::FunctionPointer(
|
||||||
name: gen_symbol_0,
|
&[Layout::Builtin(Builtin::Int64)],
|
||||||
layout: Layout::FunctionPointer(
|
&Layout::Builtin(Builtin::Int64),
|
||||||
&[Layout::Builtin(Builtin::Int64)],
|
),
|
||||||
&Layout::Builtin(Builtin::Int64),
|
args: &[(Int(4), Layout::Builtin(Int64))],
|
||||||
),
|
},
|
||||||
args: &[(Int(4), Layout::Builtin(Int64))],
|
Layout::Builtin(Int64),
|
||||||
},
|
),
|
||||||
Layout::Builtin(Int64),
|
(
|
||||||
),
|
CallByName {
|
||||||
(
|
name: gen_symbol_0,
|
||||||
CallByName {
|
layout: Layout::FunctionPointer(
|
||||||
name: gen_symbol_0,
|
&[Layout::Builtin(Builtin::Float64)],
|
||||||
layout: Layout::FunctionPointer(
|
&Layout::Builtin(Builtin::Float64),
|
||||||
&[Layout::Builtin(Builtin::Float64)],
|
),
|
||||||
&Layout::Builtin(Builtin::Float64),
|
args: &[(Float(3.14), Layout::Builtin(Float64))],
|
||||||
),
|
},
|
||||||
args: &[(Float(3.14), Layout::Builtin(Float64))],
|
Layout::Builtin(Float64),
|
||||||
},
|
),
|
||||||
Layout::Builtin(Float64),
|
])
|
||||||
),
|
|
||||||
]),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -360,31 +371,28 @@ mod test_mono {
|
||||||
let gen_symbol_0 = Interns::from_index(home, 1);
|
let gen_symbol_0 = Interns::from_index(home, 1);
|
||||||
let symbol_x = Interns::from_index(home, 0);
|
let symbol_x = Interns::from_index(home, 0);
|
||||||
|
|
||||||
DecAfter(
|
Store(
|
||||||
symbol_x,
|
&[(
|
||||||
&Store(
|
symbol_x,
|
||||||
&[(
|
Builtin(Str),
|
||||||
symbol_x,
|
Store(
|
||||||
Builtin(Str),
|
&[(
|
||||||
Store(
|
gen_symbol_0,
|
||||||
&[(
|
Layout::Builtin(layout::Builtin::Int1),
|
||||||
gen_symbol_0,
|
Expr::Bool(true),
|
||||||
Layout::Builtin(layout::Builtin::Int1),
|
)],
|
||||||
Expr::Bool(true),
|
&Cond {
|
||||||
)],
|
cond_symbol: gen_symbol_0,
|
||||||
&Cond {
|
branching_symbol: gen_symbol_0,
|
||||||
cond_symbol: gen_symbol_0,
|
cond_layout: Builtin(Int1),
|
||||||
branching_symbol: gen_symbol_0,
|
branching_layout: Builtin(Int1),
|
||||||
cond_layout: Builtin(Int1),
|
pass: (&[] as &[_], &Expr::Str("bar")),
|
||||||
branching_layout: Builtin(Int1),
|
fail: (&[] as &[_], &Expr::Str("foo")),
|
||||||
pass: (&[] as &[_], &Expr::Str("bar")),
|
ret_layout: Builtin(Str),
|
||||||
fail: (&[] as &[_], &Expr::Str("foo")),
|
},
|
||||||
ret_layout: Builtin(Str),
|
),
|
||||||
},
|
)],
|
||||||
),
|
&DecAfter(symbol_x, &Load(symbol_x)),
|
||||||
)],
|
|
||||||
&Load(symbol_x),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -424,30 +432,27 @@ mod test_mono {
|
||||||
let gen_symbol_0 = Interns::from_index(home, 0);
|
let gen_symbol_0 = Interns::from_index(home, 0);
|
||||||
let struct_layout = Layout::Struct(&[I64_LAYOUT, F64_LAYOUT]);
|
let struct_layout = Layout::Struct(&[I64_LAYOUT, F64_LAYOUT]);
|
||||||
|
|
||||||
DecAfter(
|
CallByName {
|
||||||
gen_symbol_0,
|
name: gen_symbol_0,
|
||||||
&CallByName {
|
layout: Layout::FunctionPointer(
|
||||||
name: gen_symbol_0,
|
&[struct_layout.clone()],
|
||||||
layout: Layout::FunctionPointer(
|
&struct_layout.clone(),
|
||||||
&[struct_layout.clone()],
|
),
|
||||||
&struct_layout.clone(),
|
args: &[(
|
||||||
),
|
Struct(&[
|
||||||
args: &[(
|
(
|
||||||
Struct(&[
|
CallByName {
|
||||||
(
|
name: gen_symbol_0,
|
||||||
CallByName {
|
layout: Layout::FunctionPointer(&[I64_LAYOUT], &I64_LAYOUT),
|
||||||
name: gen_symbol_0,
|
args: &[(Int(4), I64_LAYOUT)],
|
||||||
layout: Layout::FunctionPointer(&[I64_LAYOUT], &I64_LAYOUT),
|
},
|
||||||
args: &[(Int(4), I64_LAYOUT)],
|
I64_LAYOUT,
|
||||||
},
|
),
|
||||||
I64_LAYOUT,
|
(Float(0.1), F64_LAYOUT),
|
||||||
),
|
]),
|
||||||
(Float(0.1), F64_LAYOUT),
|
struct_layout,
|
||||||
]),
|
)],
|
||||||
struct_layout,
|
}
|
||||||
)],
|
|
||||||
},
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -561,9 +566,9 @@ mod test_mono {
|
||||||
|
|
||||||
let load = Load(var_x);
|
let load = Load(var_x);
|
||||||
|
|
||||||
let store = Store(arena.alloc(stores), arena.alloc(load));
|
let dec = DecAfter(var_x, arena.alloc(load));
|
||||||
|
|
||||||
DecAfter(var_x, arena.alloc(store))
|
Store(arena.alloc(stores), arena.alloc(dec))
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -587,9 +592,9 @@ mod test_mono {
|
||||||
|
|
||||||
let load = Load(var_x);
|
let load = Load(var_x);
|
||||||
|
|
||||||
let store = Store(arena.alloc(stores), arena.alloc(load));
|
let dec = DecAfter(var_x, arena.alloc(load));
|
||||||
|
|
||||||
DecAfter(var_x, arena.alloc(store))
|
Store(arena.alloc(stores), arena.alloc(dec))
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -615,9 +620,8 @@ mod test_mono {
|
||||||
|
|
||||||
let load = Load(var_x);
|
let load = Load(var_x);
|
||||||
|
|
||||||
let store = Store(arena.alloc(stores), arena.alloc(load));
|
let dec = DecAfter(var_x, arena.alloc(load));
|
||||||
|
Store(arena.alloc(stores), arena.alloc(dec))
|
||||||
DecAfter(var_x, arena.alloc(store))
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -843,8 +847,10 @@ mod test_mono {
|
||||||
fn maybe_map_to_string() {
|
fn maybe_map_to_string() {
|
||||||
compiles_to_string(
|
compiles_to_string(
|
||||||
r#"
|
r#"
|
||||||
maybe : [ Nothing, Just Int ]
|
Maybe a : [ Nothing, Just a ]
|
||||||
maybe = Just 3
|
|
||||||
|
maybe : Maybe Int
|
||||||
|
maybe = Just 0x3
|
||||||
|
|
||||||
when maybe is
|
when maybe is
|
||||||
Just x -> Just (x + 1)
|
Just x -> Just (x + 1)
|
||||||
|
@ -852,19 +858,22 @@ mod test_mono {
|
||||||
"#,
|
"#,
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
Store Test.0: Just 0i64 3i64
|
procedure Num.14 (#Attr.2, #Attr.3):
|
||||||
Store Test.0: Load Test.0
|
Lowlevel.NumAdd (Load #Attr.2) (Load #Attr.3)
|
||||||
Store Test.2: Lowlevel.And (Lowlevel.Eq 0i64 (Access @0 Load Test.0)) true
|
|
||||||
|
|
||||||
if Test.2 then
|
Store Test.1: Just 0i64 3i64
|
||||||
Reset Test.0
|
Store Test.1: Load Test.1
|
||||||
Reuse Test.0
|
Store Test.3: Lowlevel.And (Lowlevel.Eq 0i64 (Access @0 Load Test.1)) true
|
||||||
|
|
||||||
|
if Test.3 then
|
||||||
|
Reset Test.1
|
||||||
|
Reuse Test.1
|
||||||
Just 0i64 *magic*
|
Just 0i64 *magic*
|
||||||
else
|
else
|
||||||
Reset Test.0
|
Reset Test.1
|
||||||
Reuse Test.0
|
Reuse Test.1
|
||||||
Nothing 1i64
|
Nothing 1i64
|
||||||
Dec Test.0
|
Dec Test.1
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -946,4 +955,25 @@ mod test_mono {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_length() {
|
||||||
|
compiles_to_string(
|
||||||
|
r#"
|
||||||
|
x = [ 1,2,3 ]
|
||||||
|
|
||||||
|
List.len x
|
||||||
|
"#,
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
procedure List.7 (#Attr.2):
|
||||||
|
Lowlevel.ListLen (Load #Attr.2)
|
||||||
|
|
||||||
|
Store Test.0: [ 1i64, 2i64, 3i64 ]
|
||||||
|
*magic*
|
||||||
|
Dec Test.0
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue