mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
back to a working state
This commit is contained in:
parent
5b14dc73f6
commit
40f0588696
7 changed files with 147 additions and 190 deletions
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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!(
|
||||||
"{:?} {:?} ~ {:?} {:?}",
|
"{:?} {:?} ~ {:?} {:?}",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue