back to a working state

This commit is contained in:
Folkert 2020-10-11 21:55:26 +02:00
parent 5b14dc73f6
commit 40f0588696
7 changed files with 147 additions and 190 deletions

View file

@ -136,13 +136,7 @@ pub fn gen(
todo!("TODO gracefully handle the situation where we expose a function to the host which doesn't have a valid layout (e.g. maybe the function wasn't monomorphic): {:?}", err) todo!("TODO gracefully handle the situation where we expose a function to the host which doesn't have a valid layout (e.g. maybe the function wasn't monomorphic): {:?}", err)
); );
procs.insert_exposed( procs.insert_exposed(symbol, layout, mono_env.subs, annotation);
symbol,
layout,
pattern_vars.into_bump_slice(),
annotation,
ret_var,
);
} }
procs.insert_named( procs.insert_named(
@ -171,31 +165,13 @@ pub fn gen(
// never gets called by Roc code, it will never // never gets called by Roc code, it will never
// get specialized! // get specialized!
if exposed_to_host.contains(&symbol) { if exposed_to_host.contains(&symbol) {
let pattern_vars = bumpalo::collections::Vec::new_in(arena);
let ret_layout = layout_cache.from_var(mono_env.arena, annotation, mono_env.subs).unwrap_or_else(|err| let ret_layout = layout_cache.from_var(mono_env.arena, annotation, mono_env.subs).unwrap_or_else(|err|
todo!("TODO gracefully handle the situation where we expose a function to the host which doesn't have a valid layout (e.g. maybe the function wasn't monomorphic): {:?}", err) todo!("TODO gracefully handle the situation where we expose a function to the host which doesn't have a valid layout (e.g. maybe the function wasn't monomorphic): {:?}", err)
); );
let layout = let layout =
Layout::FunctionPointer(&[], arena.alloc(ret_layout)); Layout::FunctionPointer(&[], arena.alloc(ret_layout));
procs.insert_exposed( procs.insert_exposed(symbol, layout, mono_env.subs, annotation);
symbol,
layout,
pattern_vars.into_bump_slice(),
// It seems brittle that we're passing
// annotation twice - especially since
// in both cases we're giving the
// annotation to the top-level value,
// not the thunk function it will code
// gen to. It seems to work, but that
// may only be because at present we
// only use the function annotation
// variable during specialization, and
// exposed values are never specialized
// because they must be monomorphic.
annotation,
annotation,
);
} }
procs.partial_procs.insert(symbol, proc); procs.partial_procs.insert(symbol, proc);
@ -307,7 +283,7 @@ pub fn gen(
#[allow(clippy::cognitive_complexity)] #[allow(clippy::cognitive_complexity)]
pub fn gen_from_mono_module( pub fn gen_from_mono_module(
arena: &Bump, arena: &Bump,
mut loaded: MonomorphizedModule, loaded: MonomorphizedModule,
filename: PathBuf, filename: PathBuf,
target: Triple, target: Triple,
dest_filename: &Path, dest_filename: &Path,
@ -372,7 +348,6 @@ pub fn gen_from_mono_module(
for ((symbol, layout), proc) in loaded.procedures { for ((symbol, layout), proc) in loaded.procedures {
let fn_val = build_proc_header(&env, &mut layout_ids, symbol, &layout, &proc); let fn_val = build_proc_header(&env, &mut layout_ids, symbol, &layout, &proc);
dbg!(&fn_val);
headers.push((proc, fn_val)); headers.push((proc, fn_val));
} }
@ -388,6 +363,8 @@ pub fn gen_from_mono_module(
if fn_val.verify(true) { if fn_val.verify(true) {
fpm.run_on(&fn_val); fpm.run_on(&fn_val);
} else { } else {
// fn_val.print_to_stderr();
// env.module.print_to_stderr();
// NOTE: If this fails, uncomment the above println to debug. // NOTE: If this fails, uncomment the above println to debug.
panic!( panic!(
"Non-main function failed LLVM verification. Uncomment the above println to debug!" "Non-main function failed LLVM verification. Uncomment the above println to debug!"
@ -396,7 +373,7 @@ pub fn gen_from_mono_module(
} }
// Uncomment this to see the module's optimized LLVM instruction output: // Uncomment this to see the module's optimized LLVM instruction output:
env.module.print_to_stderr(); // env.module.print_to_stderr();
mpm.run_on(module); mpm.run_on(module);

View file

@ -533,7 +533,7 @@ struct State<'a> {
/// pending specializations in the same thread. /// pending specializations in the same thread.
pub needs_specialization: MutSet<ModuleId>, pub needs_specialization: MutSet<ModuleId>,
pub all_pending_specializations: MutMap<Symbol, MutMap<Layout<'a>, PendingSpecialization<'a>>>, pub all_pending_specializations: MutMap<Symbol, MutMap<Layout<'a>, PendingSpecialization>>,
pub specializations_in_flight: u32, pub specializations_in_flight: u32,
@ -648,7 +648,7 @@ enum BuildTask<'a> {
decls: Vec<Declaration>, decls: Vec<Declaration>,
finished_info: FinishedInfo<'a>, finished_info: FinishedInfo<'a>,
// TODO remove? // TODO remove?
pending_specializations: MutMap<Symbol, MutMap<Layout<'a>, PendingSpecialization<'a>>>, pending_specializations: MutMap<Symbol, MutMap<Layout<'a>, PendingSpecialization>>,
}, },
MakeSpecializations { MakeSpecializations {
module_id: ModuleId, module_id: ModuleId,
@ -856,7 +856,7 @@ where
let mut worker_queues = bumpalo::collections::Vec::with_capacity_in(num_workers, arena); let mut worker_queues = bumpalo::collections::Vec::with_capacity_in(num_workers, arena);
let mut stealers = bumpalo::collections::Vec::with_capacity_in(num_workers, arena); let mut stealers = bumpalo::collections::Vec::with_capacity_in(num_workers, arena);
let mut it = worker_arenas.iter_mut(); let it = worker_arenas.iter_mut();
{ {
thread::scope(|thread_scope| { thread::scope(|thread_scope| {
@ -1062,7 +1062,7 @@ fn update<'a>(
msg_tx: MsgSender<'a>, msg_tx: MsgSender<'a>,
injector: &Injector<BuildTask<'a>>, injector: &Injector<BuildTask<'a>>,
worker_listeners: &'a [Sender<WorkerMsg>], worker_listeners: &'a [Sender<WorkerMsg>],
_arena: &'a Bump, arena: &'a Bump,
) -> Result<State<'a>, LoadingProblem> { ) -> Result<State<'a>, LoadingProblem> {
use self::Msg::*; use self::Msg::*;
@ -1247,7 +1247,7 @@ fn update<'a>(
if let Some(pending) = &procs.pending_specializations { if let Some(pending) = &procs.pending_specializations {
for (symbol, specs) in pending { for (symbol, specs) in pending {
let mut existing = match state.all_pending_specializations.entry(*symbol) { let existing = match state.all_pending_specializations.entry(*symbol) {
Vacant(entry) => entry.insert(MutMap::default()), Vacant(entry) => entry.insert(MutMap::default()),
Occupied(entry) => entry.into_mut(), Occupied(entry) => entry.into_mut(),
}; };
@ -1292,8 +1292,6 @@ fn update<'a>(
external_specializations_requested, external_specializations_requested,
.. ..
} => { } => {
println!("done specializing {:?}", module_id);
for (module_id, requested) in external_specializations_requested { for (module_id, requested) in external_specializations_requested {
let existing = match state let existing = match state
.module_cache .module_cache
@ -1321,6 +1319,8 @@ fn update<'a>(
{ {
// state.timings.insert(module_id, module_timing); // state.timings.insert(module_id, module_timing);
Proc::insert_refcount_operations(arena, &mut state.procedures);
msg_tx msg_tx
.send(Msg::FinishedAllSpecialization { .send(Msg::FinishedAllSpecialization {
subs, subs,
@ -2005,7 +2005,7 @@ fn build_pending_specializations<'a>(
_module_timing: ModuleTiming, _module_timing: ModuleTiming,
mut layout_cache: LayoutCache<'a>, mut layout_cache: LayoutCache<'a>,
// TODO remove // TODO remove
_pending_specializations: MutMap<Symbol, MutMap<Layout<'a>, PendingSpecialization<'a>>>, _pending_specializations: MutMap<Symbol, MutMap<Layout<'a>, PendingSpecialization>>,
finished_info: FinishedInfo<'a>, finished_info: FinishedInfo<'a>,
) -> Msg<'a> { ) -> Msg<'a> {
let mut procs = Procs::default(); let mut procs = Procs::default();
@ -2035,6 +2035,8 @@ fn build_pending_specializations<'a>(
.find(|(k, _)| *k == symbol) .find(|(k, _)| *k == symbol)
.is_some(); .is_some();
let is_exposed = is_exposed && !(format!("{:?}", home) == "Utils");
match def.loc_expr.value { match def.loc_expr.value {
Closure { Closure {
function_type: annotation, function_type: annotation,
@ -2059,17 +2061,19 @@ fn build_pending_specializations<'a>(
pattern_vars.push(*var); pattern_vars.push(*var);
} }
let layout = layout_cache.from_var(mono_env.arena, annotation, mono_env.subs).unwrap_or_else(|err| let layout = match layout_cache.from_var(
todo!("TODO gracefully handle the situation where we expose a function to the host which doesn't have a valid layout (e.g. maybe the function wasn't monomorphic): {:?}", err) mono_env.arena,
);
procs.insert_exposed(
symbol,
layout,
pattern_vars.into_bump_slice(),
annotation, annotation,
ret_var, mono_env.subs,
); ) {
Ok(l) => l,
Err(err) => {
// a host-exposed function is not monomorphized
todo!("The host-exposed function {:?} does not have a valid layout (e.g. maybe the function wasn't monomorphic): {:?}", symbol, err)
}
};
procs.insert_exposed(symbol, layout, mono_env.subs, annotation);
} }
procs.insert_named( procs.insert_named(
@ -2095,7 +2099,7 @@ fn build_pending_specializations<'a>(
todo!("TODO gracefully handle the situation where we expose a function to the host which doesn't have a valid layout (e.g. maybe the function wasn't monomorphic): {:?}", err) todo!("TODO gracefully handle the situation where we expose a function to the host which doesn't have a valid layout (e.g. maybe the function wasn't monomorphic): {:?}", err)
); );
procs.insert_exposed(symbol, layout, &[], annotation, ret_var); procs.insert_exposed(symbol, layout, mono_env.subs, annotation);
} }
let proc = PartialProc { let proc = PartialProc {

View file

@ -28,10 +28,15 @@ pub struct PartialProc<'a> {
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct PendingSpecialization<'a> { pub struct PendingSpecialization {
pub fn_var: Variable, solved_type: SolvedType,
pub ret_var: Variable, }
pub pattern_vars: &'a [Variable],
impl PendingSpecialization {
pub fn from_var(subs: &Subs, var: Variable) -> Self {
let solved_type = SolvedType::from_var(subs, var);
PendingSpecialization { solved_type }
}
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
@ -80,6 +85,17 @@ impl<'a> Proc<'a> {
w.push(b'\n'); w.push(b'\n');
String::from_utf8(w).unwrap() String::from_utf8(w).unwrap()
} }
pub fn insert_refcount_operations(
arena: &'a Bump,
procs: &mut MutMap<(Symbol, Layout<'a>), Proc<'a>>,
) {
let borrow_params = arena.alloc(crate::borrow::infer_borrow(arena, procs));
for (_, proc) in procs.iter_mut() {
crate::inc_dec::visit_proc(arena, borrow_params, proc);
}
}
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
@ -117,8 +133,7 @@ impl ExternalSpecializations {
pub struct Procs<'a> { pub struct Procs<'a> {
pub partial_procs: MutMap<Symbol, PartialProc<'a>>, pub partial_procs: MutMap<Symbol, PartialProc<'a>>,
pub module_thunks: MutSet<Symbol>, pub module_thunks: MutSet<Symbol>,
pub pending_specializations: pub pending_specializations: Option<MutMap<Symbol, MutMap<Layout<'a>, PendingSpecialization>>>,
Option<MutMap<Symbol, MutMap<Layout<'a>, PendingSpecialization<'a>>>>,
pub specialized: MutMap<(Symbol, Layout<'a>), InProgressProc<'a>>, pub specialized: MutMap<(Symbol, Layout<'a>), InProgressProc<'a>>,
pub runtime_errors: MutMap<Symbol, &'a str>, pub runtime_errors: MutMap<Symbol, &'a str>,
pub externals_others_need: ExternalSpecializations, pub externals_others_need: ExternalSpecializations,
@ -208,7 +223,7 @@ impl<'a> Procs<'a> {
let borrow_params = arena.alloc(crate::borrow::infer_borrow(arena, &result)); let borrow_params = arena.alloc(crate::borrow::infer_borrow(arena, &result));
for (_, proc) in result.iter_mut() { for (_, proc) in result.iter_mut() {
crate::inc_dec::visit_proc(arena, borrow_params, proc); // crate::inc_dec::visit_proc(arena, borrow_params, proc);
} }
result result
@ -248,7 +263,7 @@ impl<'a> Procs<'a> {
let borrow_params = arena.alloc(crate::borrow::infer_borrow(arena, &result)); let borrow_params = arena.alloc(crate::borrow::infer_borrow(arena, &result));
for (_, proc) in result.iter_mut() { for (_, proc) in result.iter_mut() {
crate::inc_dec::visit_proc(arena, borrow_params, proc); // crate::inc_dec::visit_proc(arena, borrow_params, proc);
} }
(result, borrow_params) (result, borrow_params)
@ -335,11 +350,8 @@ impl<'a> Procs<'a> {
// Changing it to use .entry() would necessarily make it incorrect. // Changing it to use .entry() would necessarily make it incorrect.
#[allow(clippy::map_entry)] #[allow(clippy::map_entry)]
if !already_specialized { if !already_specialized {
let pending = PendingSpecialization { let solved_type = SolvedType::from_var(env.subs, annotation);
ret_var, let pending = PendingSpecialization { solved_type };
fn_var: annotation,
pattern_vars: pattern_vars.into_bump_slice(),
};
let pattern_symbols = pattern_symbols.into_bump_slice(); let pattern_symbols = pattern_symbols.into_bump_slice();
match &mut self.pending_specializations { match &mut self.pending_specializations {
@ -376,9 +388,8 @@ impl<'a> Procs<'a> {
match specialize(env, self, symbol, layout_cache, pending, partial_proc) match specialize(env, self, symbol, layout_cache, pending, partial_proc)
{ {
Ok(proc) => { Ok((proc, layout)) => {
self.specialized self.specialized.insert((symbol, layout), Done(proc));
.insert((symbol, layout.clone()), Done(proc));
} }
Err(error) => { Err(error) => {
let error_msg = format!( let error_msg = format!(
@ -404,9 +415,8 @@ impl<'a> Procs<'a> {
&mut self, &mut self,
name: Symbol, name: Symbol,
layout: Layout<'a>, layout: Layout<'a>,
pattern_vars: &'a [Variable], subs: &Subs,
fn_var: Variable, fn_var: Variable,
ret_var: Variable,
) { ) {
let tuple = (name, layout); let tuple = (name, layout);
@ -417,11 +427,7 @@ impl<'a> Procs<'a> {
// We're done with that tuple, so move layout back out to avoid cloning it. // We're done with that tuple, so move layout back out to avoid cloning it.
let (name, layout) = tuple; let (name, layout) = tuple;
let pending = PendingSpecialization { let pending = PendingSpecialization::from_var(subs, fn_var);
pattern_vars,
ret_var,
fn_var,
};
// This should only be called when pending_specializations is Some. // This should only be called when pending_specializations is Some.
// Otherwise, it's being called in the wrong pass! // Otherwise, it's being called in the wrong pass!
@ -458,11 +464,7 @@ impl<'a> Procs<'a> {
Some((pattern_vars, ret_var)) => { Some((pattern_vars, ret_var)) => {
let pattern_vars = let pattern_vars =
Vec::from_iter_in(pattern_vars.into_iter(), env.arena).into_bump_slice(); Vec::from_iter_in(pattern_vars.into_iter(), env.arena).into_bump_slice();
let pending = PendingSpecialization { let pending = PendingSpecialization::from_var(env.subs, fn_var);
pattern_vars,
ret_var,
fn_var,
};
// This should only be called when pending_specializations is Some. // This should only be called when pending_specializations is Some.
// Otherwise, it's being called in the wrong pass! // Otherwise, it's being called in the wrong pass!
@ -484,9 +486,8 @@ impl<'a> Procs<'a> {
.insert((symbol, layout.clone()), InProgress); .insert((symbol, layout.clone()), InProgress);
match specialize(env, self, symbol, layout_cache, pending, partial_proc) { match specialize(env, self, symbol, layout_cache, pending, partial_proc) {
Ok(proc) => { Ok((proc, layout)) => {
self.specialized self.specialized.insert((symbol, layout), Done(proc));
.insert((symbol, layout.clone()), Done(proc));
} }
Err(error) => { Err(error) => {
let error_msg = let error_msg =
@ -522,10 +523,10 @@ fn get_args_ret_var(subs: &Subs, var: Variable) -> Option<(std::vec::Vec<Variabl
} }
fn add_pending<'a>( fn add_pending<'a>(
pending_specializations: &mut MutMap<Symbol, MutMap<Layout<'a>, PendingSpecialization<'a>>>, pending_specializations: &mut MutMap<Symbol, MutMap<Layout<'a>, PendingSpecialization>>,
symbol: Symbol, symbol: Symbol,
layout: Layout<'a>, layout: Layout<'a>,
pending: PendingSpecialization<'a>, pending: PendingSpecialization,
) { ) {
let all_pending = pending_specializations let all_pending = pending_specializations
.entry(symbol) .entry(symbol)
@ -1250,37 +1251,22 @@ pub fn specialize_all<'a>(
.map(|(symbol, solved_types)| solved_types.into_iter().map(move |s| (symbol, s))) .map(|(symbol, solved_types)| solved_types.into_iter().map(move |s| (symbol, s)))
.flatten(); .flatten();
for (name, solved_type) in it.into_iter() { for (name, solved_type) in it.into_iter() {
let snapshot = env.subs.snapshot(); let partial_proc = match procs.partial_procs.get(&name) {
let mut free_vars = FreeVars::default();
let mut var_store = VarStore::new_from_subs(env.subs);
let normal_type = to_type(&solved_type, &mut free_vars, &mut var_store);
dbg!(name, &normal_type);
let next = var_store.fresh().index();
let variables_introduced = next as usize - (env.subs.len() - 1);
env.subs.extend_by(variables_introduced);
let fn_var = insert_type_into_subs(env.subs, &normal_type);
let layout = layout_cache
.from_var(&env.arena, fn_var, env.subs)
.unwrap_or_else(|err| panic!("TODO handle invalid function {:?}", err));
let mut partial_proc = match procs.partial_procs.get(&name) {
Some(v) => v.clone(), Some(v) => v.clone(),
None => { None => {
unreachable!("now this is an error"); unreachable!("now this is an error");
} }
}; };
partial_proc.annotation = unsafe_copy_var_help(env.subs, partial_proc.annotation); match specialize_solved_type(
env,
match specialize_external(env, &mut procs, name, layout_cache, fn_var, partial_proc) { &mut procs,
Ok(proc) => { name,
dbg!(name, &layout); layout_cache,
solved_type,
partial_proc,
) {
Ok((proc, layout)) => {
procs.specialized.insert((name, layout), Done(proc)); procs.specialized.insert((name, layout), Done(proc));
} }
Err(error) => { Err(error) => {
@ -1292,8 +1278,6 @@ pub fn specialize_all<'a>(
procs.runtime_errors.insert(name, error_msg); procs.runtime_errors.insert(name, error_msg);
} }
} }
env.subs.rollback_to(snapshot);
} }
let mut pending_specializations = procs.pending_specializations.unwrap_or_default(); let mut pending_specializations = procs.pending_specializations.unwrap_or_default();
@ -1327,16 +1311,17 @@ pub fn specialize_all<'a>(
procs.specialized.insert((name, layout.clone()), InProgress); procs.specialized.insert((name, layout.clone()), InProgress);
match specialize(env, &mut procs, name, layout_cache, pending, partial_proc) { match specialize(env, &mut procs, name, layout_cache, pending, partial_proc) {
Ok(proc) => { Ok((proc, layout)) => {
procs.specialized.insert((name, layout), Done(proc)); procs.specialized.insert((name, layout), Done(proc));
} }
Err(error) => { Err(error) => {
let error_msg = env.arena.alloc(format!( panic!("failed to specialize {:?}", name);
"TODO generate a RuntimeError message for {:?}", // let error_msg = env.arena.alloc(format!(
error // "TODO generate a RuntimeError message for {:?}",
)); // error
// ));
procs.runtime_errors.insert(name, error_msg); //
// procs.runtime_errors.insert(name, error_msg);
} }
} }
} }
@ -1363,6 +1348,7 @@ fn specialize_external<'a>(
// unify the called function with the specialized signature, then specialize the function body // unify the called function with the specialized signature, then specialize the function body
let snapshot = env.subs.snapshot(); let snapshot = env.subs.snapshot();
let unified = roc_unify::unify::unify(env.subs, annotation, fn_var); let unified = roc_unify::unify::unify(env.subs, annotation, fn_var);
debug_assert!(matches!(unified, roc_unify::unify::Unified::Success(_))); debug_assert!(matches!(unified, roc_unify::unify::Unified::Success(_)));
@ -1455,72 +1441,60 @@ fn specialize<'a>(
procs: &mut Procs<'a>, procs: &mut Procs<'a>,
proc_name: Symbol, proc_name: Symbol,
layout_cache: &mut LayoutCache<'a>, layout_cache: &mut LayoutCache<'a>,
pending: PendingSpecialization<'a>, pending: PendingSpecialization,
partial_proc: PartialProc<'a>, partial_proc: PartialProc<'a>,
) -> Result<Proc<'a>, LayoutProblem> { ) -> Result<(Proc<'a>, Layout<'a>), LayoutProblem> {
let PendingSpecialization { let PendingSpecialization { solved_type } = pending;
ret_var, specialize_solved_type(
fn_var, env,
pattern_vars, procs,
} = pending; proc_name,
layout_cache,
solved_type,
partial_proc,
)
}
let PartialProc { fn specialize_solved_type<'a>(
annotation, env: &mut Env<'a, '_>,
pattern_symbols, procs: &mut Procs<'a>,
body, proc_name: Symbol,
is_self_recursive, layout_cache: &mut LayoutCache<'a>,
} = partial_proc; solved_type: SolvedType,
partial_proc: PartialProc<'a>,
) -> Result<(Proc<'a>, Layout<'a>), LayoutProblem> {
// add the specializations that other modules require of us
use roc_constrain::module::{to_type, FreeVars};
use roc_solve::solve::insert_type_into_subs;
use roc_types::subs::VarStore;
// unify the called function with the specialized signature, then specialize the function body
let snapshot = env.subs.snapshot(); 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 mut free_vars = FreeVars::default();
let mut var_store = VarStore::new_from_subs(env.subs);
let specialized_body = from_can(env, body, procs, layout_cache); let normal_type = to_type(&solved_type, &mut free_vars, &mut var_store);
// reset subs, so we don't get type errors when specializing for a different signature let variables_introduced = var_store.peek() as usize - (env.subs.len() - 1);
env.subs.rollback_to(snapshot);
let mut proc_args = Vec::with_capacity_in(pattern_vars.len(), &env.arena); env.subs.extend_by(variables_introduced);
debug_assert_eq!( let fn_var = insert_type_into_subs(env.subs, &normal_type);
&pattern_vars.len(),
&pattern_symbols.len(),
"Tried to zip two vecs with different lengths!"
);
for (arg_var, arg_name) in pattern_vars.iter().zip(pattern_symbols.iter()) { let layout = layout_cache
let layout = layout_cache.from_var(&env.arena, *arg_var, env.subs)?; .from_var(&env.arena, fn_var, env.subs)
proc_args.push((layout, *arg_name));
}
let proc_args = proc_args.into_bump_slice();
let ret_layout = layout_cache
.from_var(&env.arena, ret_var, env.subs)
.unwrap_or_else(|err| panic!("TODO handle invalid function {:?}", err)); .unwrap_or_else(|err| panic!("TODO handle invalid function {:?}", err));
// TODO WRONG match specialize_external(env, procs, proc_name, layout_cache, fn_var, partial_proc) {
let closes_over_layout = Layout::Struct(&[]); Ok(proc) => {
env.subs.rollback_to(snapshot);
let recursivity = if is_self_recursive { Ok((proc, layout))
SelfRecursive::SelfRecursive(JoinPointId(env.unique_symbol())) }
} else { Err(error) => {
SelfRecursive::NotSelfRecursive env.subs.rollback_to(snapshot);
}; Err(error)
}
let proc = Proc { }
name: proc_name,
args: proc_args,
body: specialized_body,
closes_over: closes_over_layout,
ret_layout,
is_self_recursive: recursivity,
};
Ok(proc)
} }
pub fn with_hole<'a>( pub fn with_hole<'a>(
@ -2593,6 +2567,7 @@ pub fn from_can<'a>(
.from_var(env.arena, cond_var, env.subs) .from_var(env.arena, cond_var, env.subs)
.expect("invalid cond_layout"); .expect("invalid cond_layout");
dbg!("in an if");
let mut stmt = from_can(env, final_else.value, procs, layout_cache); let mut stmt = from_can(env, final_else.value, procs, layout_cache);
for (loc_cond, loc_then) in branches.into_iter().rev() { for (loc_cond, loc_then) in branches.into_iter().rev() {
@ -3593,6 +3568,8 @@ fn call_by_name<'a>(
assigned: Symbol, assigned: Symbol,
hole: &'a Stmt<'a>, hole: &'a Stmt<'a>,
) -> Stmt<'a> { ) -> Stmt<'a> {
let original_fn_var = fn_var;
// Register a pending_specialization for this function // Register a pending_specialization for this function
match layout_cache.from_var(env.arena, fn_var, env.subs) { match layout_cache.from_var(env.arena, fn_var, env.subs) {
Ok(layout) => { Ok(layout) => {
@ -3649,11 +3626,7 @@ fn call_by_name<'a>(
let iter = loc_args.into_iter().rev().zip(field_symbols.iter().rev()); let iter = loc_args.into_iter().rev().zip(field_symbols.iter().rev());
assign_to_symbols(env, procs, layout_cache, iter, result) assign_to_symbols(env, procs, layout_cache, iter, result)
} else { } else {
let pending = PendingSpecialization { let pending = PendingSpecialization::from_var(env.subs, fn_var);
pattern_vars: pattern_vars.into_bump_slice(),
ret_var,
fn_var,
};
// When requested (that is, when procs.pending_specializations is `Some`), // When requested (that is, when procs.pending_specializations is `Some`),
// store a pending specialization rather than specializing immediately. // store a pending specialization rather than specializing immediately.
@ -3712,7 +3685,7 @@ fn call_by_name<'a>(
pending, pending,
partial_proc, partial_proc,
) { ) {
Ok(proc) => { Ok((proc, _layout)) => {
procs procs
.specialized .specialized
.insert((proc_name, full_layout.clone()), Done(proc)); .insert((proc_name, full_layout.clone()), Done(proc));
@ -3749,6 +3722,8 @@ fn call_by_name<'a>(
} }
None if assigned.module_id() != proc_name.module_id() => { None if assigned.module_id() != proc_name.module_id() => {
let fn_var = original_fn_var;
// call of a function that is not not in this module // call of a function that is not not in this module
use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::hash_map::Entry::{Occupied, Vacant};
@ -3760,10 +3735,8 @@ fn call_by_name<'a>(
Occupied(entry) => entry.into_mut(), Occupied(entry) => entry.into_mut(),
}; };
existing.insert( let solved_type = SolvedType::from_var(env.subs, fn_var);
proc_name, existing.insert(proc_name, solved_type);
SolvedType::from_var(env.subs, pending.fn_var),
);
let call = Expr::FunctionCall { let call = Expr::FunctionCall {
call_type: CallType::ByName(proc_name), call_type: CallType::ByName(proc_name),

View file

@ -226,7 +226,7 @@ impl SolvedType {
Apply(symbol, args) => { Apply(symbol, args) => {
let mut new_args = Vec::with_capacity(args.len()); let mut new_args = Vec::with_capacity(args.len());
for var in args { for var in args.iter().copied() {
new_args.push(Self::from_var(subs, var)); new_args.push(Self::from_var(subs, var));
} }

View file

@ -73,13 +73,16 @@ impl VarStore {
} }
pub fn new_from_subs(subs: &Subs) -> Self { pub fn new_from_subs(subs: &Subs) -> Self {
// TODO why -2, are we not overwriting something here? let next_var = (subs.utable.len()) as u32;
let next_var = (subs.utable.len() - 1) as u32;
debug_assert!(next_var >= Variable::FIRST_USER_SPACE_VAR.0); debug_assert!(next_var >= Variable::FIRST_USER_SPACE_VAR.0);
VarStore { next: next_var } VarStore { next: next_var }
} }
pub fn peek(&mut self) -> u32 {
self.next
}
pub fn fresh(&mut self) -> Variable { pub fn fresh(&mut self) -> Variable {
// Increment the counter and return the value it had before it was incremented. // Increment the counter and return the value it had before it was incremented.
let answer = self.next; let answer = self.next;
@ -268,7 +271,7 @@ impl Subs {
} }
pub fn extend_by(&mut self, entries: usize) { pub fn extend_by(&mut self, entries: usize) {
for _ in self.len()..entries { for _ in 0..entries {
self.utable.new_key(flex_var_descriptor()); self.utable.new_key(flex_var_descriptor());
} }
} }

View file

@ -203,7 +203,7 @@ impl fmt::Debug for Type {
} }
// Sometimes it's useful to see the expansion of the alias // Sometimes it's useful to see the expansion of the alias
// write!(f, "[ but actually {:?} ]", _actual)?; write!(f, "[ but actually {:?} ]", _actual)?;
Ok(()) Ok(())
} }

View file

@ -133,12 +133,12 @@ fn unify_context(subs: &mut Subs, pool: &mut Pool, ctx: Context) -> Outcome {
// NOTE: names are generated here (when creating an error type) and that modifies names // NOTE: names are generated here (when creating an error type) and that modifies names
// generated by pretty_print.rs. So many test will fail with changes in variable names when // generated by pretty_print.rs. So many test will fail with changes in variable names when
// this block runs. // this block runs.
let (type1, _problems1) = subs.var_to_error_type(ctx.first); // let (type1, _problems1) = subs.var_to_error_type(ctx.first);
let (type2, _problems2) = subs.var_to_error_type(ctx.second); // let (type2, _problems2) = subs.var_to_error_type(ctx.second);
println!("\n --------------- \n"); // println!("\n --------------- \n");
dbg!(ctx.first, type1); // dbg!(ctx.first, type1);
println!("\n --- \n"); // println!("\n --- \n");
dbg!(ctx.second, type2); // dbg!(ctx.second, type2);
println!("\n --------------- \n"); println!("\n --------------- \n");
println!( println!(
"{:?} {:?} ~ {:?} {:?}", "{:?} {:?} ~ {:?} {:?}",