mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
Use LayoutCache to avoid recomputing layouts
This commit is contained in:
parent
efa486251e
commit
510ab36f51
6 changed files with 238 additions and 168 deletions
|
@ -1,4 +1,4 @@
|
|||
use crate::layout::{Builtin, Layout};
|
||||
use crate::layout::{Builtin, Layout, LayoutCache};
|
||||
use crate::pattern::{Ctor, Guard, RenderAs, TagId};
|
||||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
|
@ -65,6 +65,7 @@ impl<'a> Procs<'a> {
|
|||
loc_args: std::vec::Vec<(Variable, Located<roc_can::pattern::Pattern>)>,
|
||||
loc_body: Located<roc_can::expr::Expr>,
|
||||
ret_var: Variable,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
) {
|
||||
let (arg_vars, arg_symbols, body) = patterns_to_when(env, loc_args, ret_var, loc_body);
|
||||
|
||||
|
@ -81,6 +82,7 @@ impl<'a> Procs<'a> {
|
|||
&arg_symbols,
|
||||
annotation,
|
||||
body.value,
|
||||
layout_cache,
|
||||
)
|
||||
.ok();
|
||||
|
||||
|
@ -248,7 +250,9 @@ impl<'a> Expr<'a> {
|
|||
can_expr: roc_can::expr::Expr,
|
||||
procs: &mut Procs<'a>,
|
||||
) -> Self {
|
||||
from_can(env, can_expr, procs, None)
|
||||
let mut layout_cache = LayoutCache::default();
|
||||
|
||||
from_can(env, can_expr, procs, &mut layout_cache, None)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -448,6 +452,7 @@ fn from_can<'a>(
|
|||
env: &mut Env<'a, '_>,
|
||||
can_expr: roc_can::expr::Expr,
|
||||
procs: &mut Procs<'a>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
name: Option<Symbol>,
|
||||
) -> Expr<'a> {
|
||||
use roc_can::expr::Expr::*;
|
||||
|
@ -467,13 +472,23 @@ fn from_can<'a>(
|
|||
let ret_var = partial_proc.annotation;
|
||||
|
||||
// This is a top-level declaration, which will code gen to a 0-arity thunk.
|
||||
call_by_name(env, procs, fn_var, ret_var, symbol, std::vec::Vec::new())
|
||||
call_by_name(
|
||||
env,
|
||||
procs,
|
||||
fn_var,
|
||||
ret_var,
|
||||
symbol,
|
||||
std::vec::Vec::new(),
|
||||
layout_cache,
|
||||
)
|
||||
} else {
|
||||
Expr::Load(symbol)
|
||||
}
|
||||
}
|
||||
LetRec(defs, ret_expr, _, _) => from_can_defs(env, defs, *ret_expr, procs),
|
||||
LetNonRec(def, ret_expr, _, _) => from_can_defs(env, vec![*def], *ret_expr, procs),
|
||||
LetRec(defs, ret_expr, _, _) => from_can_defs(env, defs, *ret_expr, layout_cache, procs),
|
||||
LetNonRec(def, ret_expr, _, _) => {
|
||||
from_can_defs(env, vec![*def], *ret_expr, layout_cache, procs)
|
||||
}
|
||||
|
||||
Closure(ann, original_name, _, loc_args, boxed_body) => {
|
||||
let (loc_body, ret_var) = *boxed_body;
|
||||
|
@ -484,7 +499,15 @@ fn from_can<'a>(
|
|||
symbol
|
||||
}
|
||||
None => {
|
||||
procs.insert_anonymous(env, original_name, ann, loc_args, loc_body, ret_var);
|
||||
procs.insert_anonymous(
|
||||
env,
|
||||
original_name,
|
||||
ann,
|
||||
loc_args,
|
||||
loc_body,
|
||||
ret_var,
|
||||
layout_cache,
|
||||
);
|
||||
|
||||
original_name
|
||||
}
|
||||
|
@ -494,96 +517,19 @@ fn from_can<'a>(
|
|||
}
|
||||
|
||||
Call(boxed, loc_args, _) => {
|
||||
use IntOrFloat::*;
|
||||
|
||||
let (fn_var, loc_expr, ret_var) = *boxed;
|
||||
|
||||
let specialize_builtin_functions = {
|
||||
|env: &mut Env<'a, '_>, symbol: Symbol| {
|
||||
if !symbol.module_id().is_builtin() {
|
||||
// return unchanged
|
||||
symbol
|
||||
} else {
|
||||
match symbol {
|
||||
Symbol::NUM_ADD => match num_to_int_or_float(env.subs, ret_var) {
|
||||
FloatType => Symbol::FLOAT_ADD,
|
||||
IntType => Symbol::INT_ADD,
|
||||
},
|
||||
Symbol::NUM_SUB => match num_to_int_or_float(env.subs, ret_var) {
|
||||
FloatType => Symbol::FLOAT_SUB,
|
||||
IntType => Symbol::INT_SUB,
|
||||
},
|
||||
Symbol::NUM_LTE => match num_to_int_or_float(env.subs, loc_args[0].0) {
|
||||
FloatType => Symbol::FLOAT_LTE,
|
||||
IntType => Symbol::INT_LTE,
|
||||
},
|
||||
Symbol::NUM_LT => match num_to_int_or_float(env.subs, loc_args[0].0) {
|
||||
FloatType => Symbol::FLOAT_LT,
|
||||
IntType => Symbol::INT_LT,
|
||||
},
|
||||
Symbol::NUM_GTE => match num_to_int_or_float(env.subs, loc_args[0].0) {
|
||||
FloatType => Symbol::FLOAT_GTE,
|
||||
IntType => Symbol::INT_GTE,
|
||||
},
|
||||
Symbol::NUM_GT => match num_to_int_or_float(env.subs, loc_args[0].0) {
|
||||
FloatType => Symbol::FLOAT_GT,
|
||||
IntType => Symbol::INT_GT,
|
||||
},
|
||||
// TODO make this work for more than just int/float
|
||||
Symbol::BOOL_EQ => {
|
||||
match Layout::from_var(
|
||||
env.arena,
|
||||
loc_args[0].0,
|
||||
env.subs,
|
||||
env.pointer_size,
|
||||
) {
|
||||
Ok(Layout::Builtin(builtin)) => match builtin {
|
||||
Builtin::Int64 => Symbol::INT_EQ_I64,
|
||||
Builtin::Float64 => Symbol::FLOAT_EQ,
|
||||
Builtin::Bool => Symbol::INT_EQ_I1,
|
||||
Builtin::Byte => Symbol::INT_EQ_I8,
|
||||
_ => panic!("Equality not implemented for {:?}", builtin),
|
||||
},
|
||||
Ok(complex) => panic!(
|
||||
"TODO support equality on complex layouts like {:?}",
|
||||
complex
|
||||
),
|
||||
Err(()) => panic!("Invalid layout"),
|
||||
}
|
||||
}
|
||||
Symbol::BOOL_NEQ => {
|
||||
match Layout::from_var(
|
||||
env.arena,
|
||||
loc_args[0].0,
|
||||
env.subs,
|
||||
env.pointer_size,
|
||||
) {
|
||||
Ok(Layout::Builtin(builtin)) => match builtin {
|
||||
Builtin::Int64 => Symbol::INT_NEQ_I64,
|
||||
Builtin::Bool => Symbol::INT_NEQ_I1,
|
||||
Builtin::Byte => Symbol::INT_NEQ_I8,
|
||||
_ => {
|
||||
panic!("Not-Equality not implemented for {:?}", builtin)
|
||||
}
|
||||
},
|
||||
Ok(complex) => panic!(
|
||||
"TODO support equality on complex layouts like {:?}",
|
||||
complex
|
||||
),
|
||||
Err(()) => panic!("Invalid layout"),
|
||||
}
|
||||
}
|
||||
_ => symbol,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match from_can(env, loc_expr.value, procs, None) {
|
||||
match from_can(env, loc_expr.value, procs, layout_cache, None) {
|
||||
Expr::Load(proc_name) => {
|
||||
// Some functions can potentially mutate in-place.
|
||||
// If we have one of those, switch to the in-place version if appropriate.
|
||||
match specialize_builtin_functions(env, proc_name) {
|
||||
match specialize_builtin_functions(
|
||||
env,
|
||||
proc_name,
|
||||
loc_args.as_slice(),
|
||||
ret_var,
|
||||
layout_cache,
|
||||
) {
|
||||
Symbol::LIST_SET => {
|
||||
let subs = &env.subs;
|
||||
// The first arg is the one with the List in it.
|
||||
|
@ -610,9 +556,25 @@ fn from_can<'a>(
|
|||
Symbol::LIST_SET
|
||||
};
|
||||
|
||||
call_by_name(env, procs, fn_var, ret_var, new_name, loc_args)
|
||||
call_by_name(
|
||||
env,
|
||||
procs,
|
||||
fn_var,
|
||||
ret_var,
|
||||
new_name,
|
||||
loc_args,
|
||||
layout_cache,
|
||||
)
|
||||
}
|
||||
_ => call_by_name(env, procs, fn_var, ret_var, proc_name, loc_args),
|
||||
_ => call_by_name(
|
||||
env,
|
||||
procs,
|
||||
fn_var,
|
||||
ret_var,
|
||||
proc_name,
|
||||
loc_args,
|
||||
layout_cache,
|
||||
),
|
||||
}
|
||||
}
|
||||
specialized_proc_symbol => call_by_name(
|
||||
|
@ -622,6 +584,7 @@ fn from_can<'a>(
|
|||
ret_var,
|
||||
specialized_proc_symbol,
|
||||
loc_args,
|
||||
layout_cache,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -640,10 +603,11 @@ fn from_can<'a>(
|
|||
let mut args = Vec::with_capacity_in(loc_args.len(), env.arena);
|
||||
|
||||
for (_, loc_arg) in loc_args {
|
||||
args.push(from_can(env, loc_arg.value, procs, None));
|
||||
args.push(from_can(env, loc_arg.value, procs, layout_cache, None));
|
||||
}
|
||||
|
||||
let layout = Layout::from_var(env.arena, fn_var, env.subs, env.pointer_size)
|
||||
let layout = layout_cache
|
||||
.from_var(env.arena, fn_var, env.subs, env.pointer_size)
|
||||
.unwrap_or_else(|err| {
|
||||
panic!("TODO turn fn_var into a RuntimeError {:?}", err)
|
||||
});
|
||||
|
@ -658,7 +622,16 @@ fn from_can<'a>(
|
|||
region,
|
||||
loc_cond,
|
||||
branches,
|
||||
} => from_can_when(env, cond_var, expr_var, region, *loc_cond, branches, procs),
|
||||
} => from_can_when(
|
||||
env,
|
||||
cond_var,
|
||||
expr_var,
|
||||
region,
|
||||
*loc_cond,
|
||||
branches,
|
||||
layout_cache,
|
||||
procs,
|
||||
),
|
||||
|
||||
If {
|
||||
cond_var,
|
||||
|
@ -666,16 +639,18 @@ fn from_can<'a>(
|
|||
branches,
|
||||
final_else,
|
||||
} => {
|
||||
let mut expr = from_can(env, final_else.value, procs, None);
|
||||
let mut expr = from_can(env, final_else.value, procs, layout_cache, None);
|
||||
|
||||
let ret_layout = Layout::from_var(env.arena, branch_var, env.subs, env.pointer_size)
|
||||
let ret_layout = layout_cache
|
||||
.from_var(env.arena, branch_var, env.subs, env.pointer_size)
|
||||
.expect("invalid ret_layout");
|
||||
let cond_layout = Layout::from_var(env.arena, cond_var, env.subs, env.pointer_size)
|
||||
let cond_layout = layout_cache
|
||||
.from_var(env.arena, cond_var, env.subs, env.pointer_size)
|
||||
.expect("invalid cond_layout");
|
||||
|
||||
for (loc_cond, loc_then) in branches.into_iter().rev() {
|
||||
let cond = from_can(env, loc_cond.value, procs, None);
|
||||
let then = from_can(env, loc_then.value, procs, None);
|
||||
let cond = from_can(env, loc_cond.value, procs, layout_cache, None);
|
||||
let then = from_can(env, loc_then.value, procs, layout_cache, None);
|
||||
|
||||
let branch_symbol = env.unique_symbol();
|
||||
|
||||
|
@ -716,7 +691,7 @@ fn from_can<'a>(
|
|||
|
||||
for (label, layout) in btree {
|
||||
let field = fields.remove(&label).unwrap();
|
||||
let expr = from_can(env, field.loc_expr.value, procs, None);
|
||||
let expr = from_can(env, field.loc_expr.value, procs, layout_cache, None);
|
||||
|
||||
field_tuples.push((expr, layout));
|
||||
}
|
||||
|
@ -757,7 +732,7 @@ fn from_can<'a>(
|
|||
Unwrapped(field_layouts) => {
|
||||
let field_exprs = args
|
||||
.into_iter()
|
||||
.map(|(_, arg)| from_can(env, arg.value, procs, None));
|
||||
.map(|(_, arg)| from_can(env, arg.value, procs, layout_cache, None));
|
||||
|
||||
let mut field_tuples = Vec::with_capacity_in(field_layouts.len(), arena);
|
||||
|
||||
|
@ -779,7 +754,7 @@ fn from_can<'a>(
|
|||
|
||||
let it = std::iter::once(Expr::Int(tag_id as i64)).chain(
|
||||
args.into_iter()
|
||||
.map(|(_, arg)| from_can(env, arg.value, procs, None)),
|
||||
.map(|(_, arg)| from_can(env, arg.value, procs, layout_cache, None)),
|
||||
);
|
||||
|
||||
for (arg_layout, arg_expr) in argument_layouts.iter().zip(it) {
|
||||
|
@ -832,7 +807,7 @@ fn from_can<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
let record = arena.alloc(from_can(env, loc_expr.value, procs, None));
|
||||
let record = arena.alloc(from_can(env, loc_expr.value, procs, layout_cache, None));
|
||||
|
||||
Expr::AccessAtIndex {
|
||||
index: index.expect("field not in its own type") as u64,
|
||||
|
@ -853,8 +828,8 @@ fn from_can<'a>(
|
|||
// We have to special-case the empty list, because trying to
|
||||
// compute a layout for an unbound var won't work.
|
||||
Content::FlexVar(_) => Layout::Builtin(Builtin::EmptyList),
|
||||
content => match Layout::from_content(arena, content, env.subs, env.pointer_size) {
|
||||
Ok(layout) => layout,
|
||||
_ => match layout_cache.from_var(arena, elem_var, env.subs, env.pointer_size) {
|
||||
Ok(layout) => layout.clone(),
|
||||
Err(()) => {
|
||||
panic!("TODO gracefully handle List with invalid element layout");
|
||||
}
|
||||
|
@ -864,7 +839,7 @@ fn from_can<'a>(
|
|||
let mut elems = Vec::with_capacity_in(loc_elems.len(), arena);
|
||||
|
||||
for loc_elem in loc_elems {
|
||||
elems.push(from_can(env, loc_elem.value, procs, None));
|
||||
elems.push(from_can(env, loc_elem.value, procs, layout_cache, None));
|
||||
}
|
||||
|
||||
Expr::Array {
|
||||
|
@ -1022,6 +997,7 @@ fn from_can_defs<'a>(
|
|||
env: &mut Env<'a, '_>,
|
||||
defs: std::vec::Vec<roc_can::def::Def>,
|
||||
ret_expr: Located<roc_can::expr::Expr>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
procs: &mut Procs<'a>,
|
||||
) -> Expr<'a> {
|
||||
use roc_can::expr::Expr::*;
|
||||
|
@ -1049,7 +1025,7 @@ fn from_can_defs<'a>(
|
|||
if let Closure(_, _, _, _, _) = &loc_expr.value {
|
||||
// Extract Procs, but discard the resulting Expr::Load.
|
||||
// That Load looks up the pointer, which we won't use here!
|
||||
from_can(env, loc_expr.value, procs, Some(*symbol));
|
||||
from_can(env, loc_expr.value, procs, layout_cache, Some(*symbol));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -1058,7 +1034,8 @@ fn from_can_defs<'a>(
|
|||
// If it wasn't specifically an Identifier & Closure, proceed as normal.
|
||||
let mono_pattern = from_can_pattern(env, &loc_pattern.value);
|
||||
|
||||
let layout = Layout::from_var(env.arena, def.expr_var, env.subs, env.pointer_size)
|
||||
let layout = layout_cache
|
||||
.from_var(env.arena, def.expr_var, env.subs, env.pointer_size)
|
||||
.expect("invalid layout");
|
||||
|
||||
match &mono_pattern {
|
||||
|
@ -1066,7 +1043,7 @@ fn from_can_defs<'a>(
|
|||
stored.push((
|
||||
*symbol,
|
||||
layout.clone(),
|
||||
from_can(env, loc_expr.value, procs, None),
|
||||
from_can(env, loc_expr.value, procs, layout_cache, None),
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
|
@ -1093,7 +1070,7 @@ fn from_can_defs<'a>(
|
|||
stored.push((
|
||||
symbol,
|
||||
layout.clone(),
|
||||
from_can(env, loc_expr.value, procs, None),
|
||||
from_can(env, loc_expr.value, procs, layout_cache, None),
|
||||
));
|
||||
|
||||
match store_pattern(env, &mono_pattern, symbol, layout, &mut stored) {
|
||||
|
@ -1108,7 +1085,7 @@ fn from_can_defs<'a>(
|
|||
}
|
||||
// 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!
|
||||
let ret = from_can(env, ret_expr.value, procs, None);
|
||||
let ret = from_can(env, ret_expr.value, procs, layout_cache, None);
|
||||
|
||||
if stored.is_empty() {
|
||||
ret
|
||||
|
@ -1124,6 +1101,7 @@ fn from_can_when<'a>(
|
|||
region: Region,
|
||||
loc_cond: Located<roc_can::expr::Expr>,
|
||||
mut branches: std::vec::Vec<roc_can::expr::WhenBranch>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
procs: &mut Procs<'a>,
|
||||
) -> Expr<'a> {
|
||||
if branches.is_empty() {
|
||||
|
@ -1168,32 +1146,34 @@ fn from_can_when<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
let cond_layout = Layout::from_var(env.arena, cond_var, env.subs, env.pointer_size)
|
||||
let cond_layout = layout_cache
|
||||
.from_var(env.arena, cond_var, env.subs, env.pointer_size)
|
||||
.unwrap_or_else(|err| panic!("TODO turn this into a RuntimeError {:?}", err));
|
||||
let cond_symbol = env.unique_symbol();
|
||||
let cond = from_can(env, loc_cond.value, procs, None);
|
||||
let cond = from_can(env, loc_cond.value, procs, layout_cache, None);
|
||||
stored.push((cond_symbol, cond_layout.clone(), cond));
|
||||
|
||||
// NOTE this will still store shadowed names.
|
||||
// that's fine: the branch throws a runtime error anyway
|
||||
let ret = match store_pattern(env, &mono_pattern, cond_symbol, cond_layout, &mut stored) {
|
||||
Ok(_) => from_can(env, first.value.value, procs, None),
|
||||
Ok(_) => from_can(env, first.value.value, procs, layout_cache, None),
|
||||
Err(message) => Expr::RuntimeError(env.arena.alloc(message)),
|
||||
};
|
||||
|
||||
Expr::Store(stored.into_bump_slice(), arena.alloc(ret))
|
||||
} else {
|
||||
let cond_layout = Layout::from_var(env.arena, cond_var, env.subs, env.pointer_size)
|
||||
let cond_layout = layout_cache
|
||||
.from_var(env.arena, cond_var, env.subs, env.pointer_size)
|
||||
.unwrap_or_else(|err| panic!("TODO turn this into a RuntimeError {:?}", err));
|
||||
|
||||
let cond = from_can(env, loc_cond.value, procs, None);
|
||||
let cond = from_can(env, loc_cond.value, procs, layout_cache, None);
|
||||
let cond_symbol = env.unique_symbol();
|
||||
|
||||
let mut loc_branches = std::vec::Vec::new();
|
||||
let mut opt_branches = std::vec::Vec::new();
|
||||
|
||||
for when_branch in branches {
|
||||
let mono_expr = from_can(env, when_branch.value.value, procs, None);
|
||||
let mono_expr = from_can(env, when_branch.value.value, procs, layout_cache, None);
|
||||
|
||||
let exhaustive_guard = if when_branch.guard.is_some() {
|
||||
Guard::HasGuard
|
||||
|
@ -1226,7 +1206,7 @@ fn from_can_when<'a>(
|
|||
//
|
||||
// otherwise, we modify the branch's expression to include the stores
|
||||
if let Some(loc_guard) = when_branch.guard.clone() {
|
||||
let expr = from_can(env, loc_guard.value, procs, None);
|
||||
let expr = from_can(env, loc_guard.value, procs, layout_cache, None);
|
||||
(
|
||||
crate::decision_tree::Guard::Guard {
|
||||
stores: stores.into_bump_slice(),
|
||||
|
@ -1306,7 +1286,8 @@ fn from_can_when<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
let ret_layout = Layout::from_var(env.arena, expr_var, env.subs, env.pointer_size)
|
||||
let ret_layout = layout_cache
|
||||
.from_var(env.arena, expr_var, env.subs, env.pointer_size)
|
||||
.unwrap_or_else(|err| panic!("TODO turn this into a RuntimeError {:?}", err));
|
||||
|
||||
let branching = crate::decision_tree::optimize_when(
|
||||
|
@ -1330,6 +1311,7 @@ fn call_by_name<'a>(
|
|||
ret_var: Variable,
|
||||
proc_name: Symbol,
|
||||
loc_args: std::vec::Vec<(Variable, Located<roc_can::expr::Expr>)>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
) -> Expr<'a> {
|
||||
// create specialized procedure to call
|
||||
|
||||
|
@ -1395,6 +1377,7 @@ fn call_by_name<'a>(
|
|||
&loc_patterns,
|
||||
annotation,
|
||||
body,
|
||||
layout_cache,
|
||||
)
|
||||
.ok();
|
||||
|
||||
|
@ -1405,10 +1388,14 @@ fn call_by_name<'a>(
|
|||
let mut args = Vec::with_capacity_in(loc_args.len(), env.arena);
|
||||
|
||||
for (var, loc_arg) in loc_args {
|
||||
let layout = Layout::from_var(&env.arena, var, &env.subs, env.pointer_size)
|
||||
let layout = layout_cache
|
||||
.from_var(&env.arena, var, &env.subs, env.pointer_size)
|
||||
.unwrap_or_else(|err| panic!("TODO gracefully handle bad layout: {:?}", err));
|
||||
|
||||
args.push((from_can(env, loc_arg.value, procs, None), layout));
|
||||
args.push((
|
||||
from_can(env, loc_arg.value, procs, layout_cache, None),
|
||||
layout,
|
||||
));
|
||||
}
|
||||
|
||||
Expr::CallByName(specialized_proc_name, args.into_bump_slice())
|
||||
|
@ -1425,23 +1412,26 @@ fn specialize_proc_body<'a>(
|
|||
pattern_symbols: &[Symbol],
|
||||
annotation: Variable,
|
||||
body: roc_can::expr::Expr,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
) -> Result<Proc<'a>, ()> {
|
||||
// unify the called function with the specialized signature, then specialize the function body
|
||||
let snapshot = env.subs.snapshot();
|
||||
let unified = roc_unify::unify::unify(env.subs, annotation, fn_var);
|
||||
debug_assert!(matches!(unified, roc_unify::unify::Unified::Success(_)));
|
||||
let specialized_body = from_can(env, body, procs, None);
|
||||
let specialized_body = from_can(env, body, procs, layout_cache, None);
|
||||
// reset subs, so we don't get type errors when specializing for a different signature
|
||||
env.subs.rollback_to(snapshot);
|
||||
|
||||
let mut proc_args = Vec::with_capacity_in(loc_args.len(), &env.arena);
|
||||
|
||||
for (arg_var, arg_name) in loc_args.iter().zip(pattern_symbols.iter()) {
|
||||
let layout = Layout::from_var(&env.arena, *arg_var, env.subs, env.pointer_size)?;
|
||||
let layout = layout_cache.from_var(&env.arena, *arg_var, env.subs, env.pointer_size)?;
|
||||
|
||||
proc_args.push((layout, *arg_name));
|
||||
}
|
||||
|
||||
let ret_layout = Layout::from_var(&env.arena, ret_var, env.subs, env.pointer_size)
|
||||
let ret_layout = layout_cache
|
||||
.from_var(&env.arena, ret_var, env.subs, env.pointer_size)
|
||||
.unwrap_or_else(|err| panic!("TODO handle invalid function {:?}", err));
|
||||
|
||||
let proc = Proc {
|
||||
|
@ -1768,3 +1758,78 @@ pub fn specialize_equality<'a>(
|
|||
arena.alloc([(lhs, layout.clone()), (rhs, layout.clone())]),
|
||||
)
|
||||
}
|
||||
|
||||
fn specialize_builtin_functions<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
symbol: Symbol,
|
||||
loc_args: &[(Variable, Located<roc_can::expr::Expr>)],
|
||||
ret_var: Variable,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
) -> Symbol {
|
||||
use IntOrFloat::*;
|
||||
|
||||
if !symbol.is_builtin() {
|
||||
// return unchanged
|
||||
symbol
|
||||
} else {
|
||||
match symbol {
|
||||
Symbol::NUM_ADD => match num_to_int_or_float(env.subs, ret_var) {
|
||||
FloatType => Symbol::FLOAT_ADD,
|
||||
IntType => Symbol::INT_ADD,
|
||||
},
|
||||
Symbol::NUM_SUB => match num_to_int_or_float(env.subs, ret_var) {
|
||||
FloatType => Symbol::FLOAT_SUB,
|
||||
IntType => Symbol::INT_SUB,
|
||||
},
|
||||
Symbol::NUM_LTE => match num_to_int_or_float(env.subs, loc_args[0].0) {
|
||||
FloatType => Symbol::FLOAT_LTE,
|
||||
IntType => Symbol::INT_LTE,
|
||||
},
|
||||
Symbol::NUM_LT => match num_to_int_or_float(env.subs, loc_args[0].0) {
|
||||
FloatType => Symbol::FLOAT_LT,
|
||||
IntType => Symbol::INT_LT,
|
||||
},
|
||||
Symbol::NUM_GTE => match num_to_int_or_float(env.subs, loc_args[0].0) {
|
||||
FloatType => Symbol::FLOAT_GTE,
|
||||
IntType => Symbol::INT_GTE,
|
||||
},
|
||||
Symbol::NUM_GT => match num_to_int_or_float(env.subs, loc_args[0].0) {
|
||||
FloatType => Symbol::FLOAT_GT,
|
||||
IntType => Symbol::INT_GT,
|
||||
},
|
||||
// TODO make this work for more than just int/float
|
||||
Symbol::BOOL_EQ => {
|
||||
match layout_cache.from_var(env.arena, loc_args[0].0, env.subs, env.pointer_size) {
|
||||
Ok(Layout::Builtin(builtin)) => match builtin {
|
||||
Builtin::Int64 => Symbol::INT_EQ_I64,
|
||||
Builtin::Float64 => Symbol::FLOAT_EQ,
|
||||
Builtin::Bool => Symbol::INT_EQ_I1,
|
||||
Builtin::Byte => Symbol::INT_EQ_I8,
|
||||
_ => panic!("Equality not implemented for {:?}", builtin),
|
||||
},
|
||||
Ok(complex) => panic!(
|
||||
"TODO support equality on complex layouts like {:?}",
|
||||
complex
|
||||
),
|
||||
Err(()) => panic!("Invalid layout"),
|
||||
}
|
||||
}
|
||||
Symbol::BOOL_NEQ => {
|
||||
match layout_cache.from_var(env.arena, loc_args[0].0, env.subs, env.pointer_size) {
|
||||
Ok(Layout::Builtin(builtin)) => match builtin {
|
||||
Builtin::Int64 => Symbol::INT_NEQ_I64,
|
||||
Builtin::Bool => Symbol::INT_NEQ_I1,
|
||||
Builtin::Byte => Symbol::INT_NEQ_I8,
|
||||
_ => panic!("Not-Equality not implemented for {:?}", builtin),
|
||||
},
|
||||
Ok(complex) => panic!(
|
||||
"TODO support equality on complex layouts like {:?}",
|
||||
complex
|
||||
),
|
||||
Err(()) => panic!("Invalid layout"),
|
||||
}
|
||||
}
|
||||
_ => symbol,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue