Fix inlining and test

This commit is contained in:
Richard Feldman 2020-07-03 23:16:32 -04:00
parent 3e5627689f
commit 1926adb543
2 changed files with 108 additions and 18 deletions

View file

@ -1,4 +1,5 @@
use crate::annotation::IntroducedVariables; use crate::annotation::IntroducedVariables;
use crate::builtins::builtin_defs;
use crate::def::{can_defs_with_return, Def}; use crate::def::{can_defs_with_return, Def};
use crate::env::Env; use crate::env::Env;
use crate::num::{ use crate::num::{
@ -1192,9 +1193,62 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
let (fn_var, loc_expr, expr_var) = *boxed_tuple; let (fn_var, loc_expr, expr_var) = *boxed_tuple;
match loc_expr.value { match loc_expr.value {
Var(symbol) if symbol.is_builtin() => { Var(symbol) if symbol.is_builtin() => match builtin_defs(var_store).get(&symbol) {
todo!("Inline this builtin: {:?}", symbol); Some(Closure(_var, _, recursive, params, boxed_body)) => {
debug_assert_eq!(*recursive, Recursive::NotRecursive);
// Since this is a canonicalized Expr, we should have
// already detected any arity mismatches and replaced this
// with a RuntimeError if there was a mismatch.
debug_assert_eq!(params.len(), args.len());
// Start with the function's body as the answer.
let (mut loc_answer, _body_var) = *boxed_body.clone();
// Wrap the body in one LetNonRec for each argument,
// such that at the end we have all the arguments in
// scope with the values the caller provided.
for ((_param_var, loc_pattern), (expr_var, loc_expr)) in
params.iter().cloned().zip(args.into_iter()).rev()
{
// TODO get the correct vars into here.
// Not sure if param_var should be involved.
let pattern_vars = SendMap::default();
// TODO get the actual correct aliases
let aliases = SendMap::default();
let def = Def {
loc_pattern,
loc_expr,
expr_var,
pattern_vars,
annotation: None,
};
loc_answer = Located {
region: Region::zero(),
value: LetNonRec(
Box::new(def),
Box::new(loc_answer),
var_store.fresh(),
aliases,
),
};
} }
loc_answer.value
}
Some(_) => {
unreachable!("Tried to inline a non-function");
}
None => {
unreachable!(
"Tried to inline a builtin that wasn't registered: {:?}",
symbol
);
}
},
_ => { _ => {
// For now, we only inline calls to builtins. Leave this alone! // For now, we only inline calls to builtins. Leave this alone!
Call(Box::new((fn_var, loc_expr, expr_var)), args, called_via) Call(Box::new((fn_var, loc_expr, expr_var)), args, called_via)

View file

@ -14,13 +14,16 @@ mod helpers;
mod can_inline { mod can_inline {
use crate::helpers::{can_expr_with, test_home}; use crate::helpers::{can_expr_with, test_home};
use bumpalo::Bump; use bumpalo::Bump;
use roc_can::def::Def;
use roc_can::expr::inline_calls; use roc_can::expr::inline_calls;
use roc_can::expr::Expr::{self, *}; use roc_can::expr::Expr::{self, *};
use roc_can::pattern::Pattern;
use roc_can::scope::Scope; use roc_can::scope::Scope;
use roc_collections::all::SendMap;
use roc_module::operator::CalledVia; use roc_module::operator::CalledVia;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_region::all::{Located, Region}; use roc_region::all::{Located, Region};
use roc_types::subs::VarStore; use roc_types::subs::{VarStore, Variable};
fn assert_inlines_to(input: &str, expected: Expr, var_store: &mut VarStore) { fn assert_inlines_to(input: &str, expected: Expr, var_store: &mut VarStore) {
let arena = Bump::new(); let arena = Bump::new();
@ -34,6 +37,7 @@ mod can_inline {
#[test] #[test]
fn inline_list_len() { fn inline_list_len() {
let var_store = &mut VarStore::default(); let var_store = &mut VarStore::default();
let aliases = SendMap::default();
assert_inlines_to( assert_inlines_to(
indoc!( indoc!(
@ -41,24 +45,56 @@ mod can_inline {
Int.isZero 5 Int.isZero 5
"# "#
), ),
Expr::Call( LetNonRec(
Box::new(Def {
loc_pattern: Located {
region: Region::zero(),
value: Pattern::Identifier(Symbol::INT_IS_ZERO_ARG),
},
pattern_vars: SendMap::default(),
loc_expr: Located {
region: Region::new(0, 0, 11, 12),
value: Num(unsafe { Variable::unsafe_test_debug_variable(7) }, 5),
},
expr_var: unsafe { Variable::unsafe_test_debug_variable(8) },
annotation: None,
}),
Box::new(Located {
region: Region::zero(),
value: Expr::Call(
Box::new(( Box::new((
var_store.fresh(), unsafe { Variable::unsafe_test_debug_variable(138) },
Located { Located {
region: Region::zero(), region: Region::zero(),
value: Expr::Var(Symbol::FLOAT_EQ), value: Expr::Var(Symbol::INT_EQ_I64),
}, },
var_store.fresh(), unsafe { Variable::unsafe_test_debug_variable(139) },
)), )),
vec![( vec![
var_store.fresh(), (
unsafe { Variable::unsafe_test_debug_variable(140) },
Located { Located {
region: Region::zero(), region: Region::zero(),
value: Int(var_store.fresh(), 5), value: Var(Symbol::INT_IS_ZERO_ARG),
}, },
)], ),
(
unsafe { Variable::unsafe_test_debug_variable(141) },
Located {
region: Region::zero(),
value: Int(
unsafe { Variable::unsafe_test_debug_variable(137) },
0,
),
},
),
],
CalledVia::Space, CalledVia::Space,
), ),
}),
unsafe { Variable::unsafe_test_debug_variable(198) },
aliases,
),
var_store, var_store,
) )
} }