use HostSpecializations from file.rs

This commit is contained in:
Folkert 2021-11-19 22:20:50 +01:00
parent 5d9d2b7fea
commit 74f073b3c6
2 changed files with 13 additions and 143 deletions

View file

@ -19,8 +19,7 @@ use roc_module::symbol::{
Symbol, Symbol,
}; };
use roc_mono::ir::{ use roc_mono::ir::{
CapturedSymbols, EntryPoint, ExternalSpecializations, PartialProc, PendingSpecialization, Proc, CapturedSymbols, EntryPoint, ExternalSpecializations, PartialProc, Proc, ProcLayout, Procs,
ProcLayout, Procs,
}; };
use roc_mono::layout::{Layout, LayoutCache, LayoutProblem}; use roc_mono::layout::{Layout, LayoutCache, LayoutProblem};
use roc_parse::ast::{self, StrLiteral, TypeAnnotation}; use roc_parse::ast::{self, StrLiteral, TypeAnnotation};
@ -3957,7 +3956,7 @@ fn make_specializations<'a>(
&mut mono_env, &mut mono_env,
procs, procs,
specializations_we_must_make, specializations_we_must_make,
procs_base.specializations_for_host, procs_base.host_specializations,
&mut layout_cache, &mut layout_cache,
); );
@ -3989,27 +3988,11 @@ struct ProcsBase<'a> {
partial_procs: BumpMap<Symbol, PartialProc<'a>>, partial_procs: BumpMap<Symbol, PartialProc<'a>>,
module_thunks: &'a [Symbol], module_thunks: &'a [Symbol],
/// A host-exposed function must be specialized; it's a seed for subsequent specializations /// A host-exposed function must be specialized; it's a seed for subsequent specializations
specializations_for_host: BumpMap<Symbol, MutMap<ProcLayout<'a>, PendingSpecialization<'a>>>, host_specializations: roc_mono::ir::HostSpecializations,
runtime_errors: BumpMap<Symbol, &'a str>, runtime_errors: BumpMap<Symbol, &'a str>,
imported_module_thunks: &'a [Symbol], imported_module_thunks: &'a [Symbol],
} }
impl<'a> ProcsBase<'a> {
fn add_specialization_for_host(
&mut self,
symbol: Symbol,
layout: ProcLayout<'a>,
pending: PendingSpecialization<'a>,
) {
let all_pending = self
.specializations_for_host
.entry(symbol)
.or_insert_with(|| HashMap::with_capacity_and_hasher(1, default_hasher()));
all_pending.insert(layout, pending);
}
}
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn build_pending_specializations<'a>( fn build_pending_specializations<'a>(
arena: &'a Bump, arena: &'a Bump,
@ -4031,7 +4014,7 @@ fn build_pending_specializations<'a>(
let mut procs_base = ProcsBase { let mut procs_base = ProcsBase {
partial_procs: BumpMap::default(), partial_procs: BumpMap::default(),
module_thunks: &[], module_thunks: &[],
specializations_for_host: BumpMap::default(), host_specializations: roc_mono::ir::HostSpecializations::new(),
runtime_errors: BumpMap::default(), runtime_errors: BumpMap::default(),
imported_module_thunks, imported_module_thunks,
}; };
@ -4138,41 +4121,12 @@ fn add_def_to_module<'a>(
// never gets called by Roc code, it will never // never gets called by Roc code, it will never
// get specialized! // get specialized!
if is_exposed { if is_exposed {
let layout = match layout_cache.raw_from_var( procs.host_specializations.insert_host_exposed(
mono_env.arena,
annotation,
mono_env.subs,
) {
Ok(l) => l,
Err(LayoutProblem::Erroneous) => {
let message = "top level function has erroneous type";
procs.runtime_errors.insert(symbol, message);
return;
}
Err(LayoutProblem::UnresolvedTypeVar(v)) => {
let message = format!(
"top level function has unresolved type variable {:?}",
v
);
procs
.runtime_errors
.insert(symbol, mono_env.arena.alloc(message));
return;
}
};
let pending = PendingSpecialization::from_exposed_function(
mono_env.arena,
mono_env.subs, mono_env.subs,
symbol,
def.annotation, def.annotation,
annotation, annotation,
); );
procs.add_specialization_for_host(
symbol,
ProcLayout::from_raw(mono_env.arena, layout),
pending,
);
} }
let partial_proc = PartialProc::from_named_function( let partial_proc = PartialProc::from_named_function(
@ -4192,51 +4146,23 @@ fn add_def_to_module<'a>(
// mark this symbols as a top-level thunk before any other work on the procs // mark this symbols as a top-level thunk before any other work on the procs
module_thunks.push(symbol); module_thunks.push(symbol);
let annotation = def.expr_var;
// If this is an exposed symbol, we need to // If this is an exposed symbol, we need to
// register it as such. Otherwise, since it // register it as such. Otherwise, since it
// never gets called by Roc code, it will never // never gets called by Roc code, it will never
// get specialized! // get specialized!
if is_exposed { if is_exposed {
let annotation = def.expr_var; procs.host_specializations.insert_host_exposed(
let top_level = match layout_cache.from_var(
mono_env.arena,
annotation,
mono_env.subs,
) {
Ok(l) => {
// remember, this is a 0-argument thunk
ProcLayout::new(mono_env.arena, &[], l)
}
Err(LayoutProblem::Erroneous) => {
let message = "top level function has erroneous type";
procs.runtime_errors.insert(symbol, message);
return;
}
Err(LayoutProblem::UnresolvedTypeVar(v)) => {
let message = format!(
"top level function has unresolved type variable {:?}",
v
);
procs
.runtime_errors
.insert(symbol, mono_env.arena.alloc(message));
return;
}
};
let pending = PendingSpecialization::from_exposed_function(
mono_env.arena,
mono_env.subs, mono_env.subs,
symbol,
def.annotation, def.annotation,
annotation, annotation,
); );
procs.add_specialization_for_host(symbol, top_level, pending);
} }
let proc = PartialProc { let proc = PartialProc {
annotation: def.expr_var, annotation,
// This is a 0-arity thunk, so it has no arguments. // This is a 0-arity thunk, so it has no arguments.
pattern_symbols: &[], pattern_symbols: &[],
// This is a top-level definition, so it cannot capture anything // This is a top-level definition, so it cannot capture anything

View file

@ -2057,7 +2057,7 @@ pub fn specialize_all<'a>(
env: &mut Env<'a, '_>, env: &mut Env<'a, '_>,
mut procs: Procs<'a>, mut procs: Procs<'a>,
externals_others_need: std::vec::Vec<ExternalSpecializations<'a>>, externals_others_need: std::vec::Vec<ExternalSpecializations<'a>>,
specializations_for_host: BumpMap<Symbol, MutMap<ProcLayout<'a>, PendingSpecialization<'a>>>, specializations_for_host: HostSpecializations,
layout_cache: &mut LayoutCache<'a>, layout_cache: &mut LayoutCache<'a>,
) -> Procs<'a> { ) -> Procs<'a> {
specialize_externals_others_need(env, &mut procs, externals_others_need, layout_cache); specialize_externals_others_need(env, &mut procs, externals_others_need, layout_cache);
@ -2076,63 +2076,7 @@ pub fn specialize_all<'a>(
} }
} }
let it = specializations_for_host.into_iter(); specialize_host_specializations(env, &mut procs, layout_cache, specializations_for_host);
for (name, by_layout) in it {
for (outside_layout, pending) in by_layout.into_iter() {
// If we've already seen this (Symbol, Layout) combination before,
// don't try to specialize it again. If we do, we'll loop forever!
let partial_proc = if procs.specialized.is_specialized(name, &outside_layout) {
// already specialized, just continue
continue;
} else {
match procs.partial_procs.symbol_to_id(name) {
Some(v) => {
// Mark this proc as in-progress, so if we're dealing with
// mutually recursive functions, we don't loop forever.
// (We had a bug around this before this system existed!)
procs.specialized.mark_in_progress(name, outside_layout);
v
}
None => {
// TODO this assumes the specialization is done by another module
// make sure this does not become a problem down the road!
continue;
}
}
};
match specialize(env, &mut procs, name, layout_cache, pending, partial_proc) {
Ok((proc, layout)) => {
// TODO thiscode is duplicated elsewhere
let top_level = ProcLayout::from_raw(env.arena, layout);
if procs.is_module_thunk(proc.name) {
debug_assert!(
top_level.arguments.is_empty(),
"{:?} from {:?}",
name,
layout
);
}
debug_assert_eq!(outside_layout, top_level, " in {:?}", name);
procs.specialized.insert_specialized(name, top_level, proc);
}
Err(SpecializeFailure {
attempted_layout, ..
}) => {
let proc = generate_runtime_error_function(env, name, attempted_layout);
let top_level = ProcLayout::from_raw(env.arena, attempted_layout);
procs.specialized.insert_specialized(name, top_level, proc);
}
}
}
}
procs procs
} }