mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 04:08:19 +00:00
WIP
This commit is contained in:
parent
b412765972
commit
ee99ae2372
5 changed files with 176 additions and 126 deletions
|
@ -3403,16 +3403,18 @@ fn finish_specialization<'a>(
|
|||
layout,
|
||||
);
|
||||
|
||||
glue_getters.extend(all_glue_procs.iter().flat_map(|(_, glue_procs)| {
|
||||
glue_getters.extend(all_glue_procs.getters.iter().flat_map(|(_, glue_procs)| {
|
||||
glue_procs
|
||||
.iter()
|
||||
.map(|glue_proc| (glue_proc.name, glue_proc.proc_layout))
|
||||
}));
|
||||
procedures.extend(all_glue_procs.into_iter().flat_map(|(_, glue_procs)| {
|
||||
glue_procs.into_iter().map(|glue_proc| {
|
||||
(((glue_proc.name), glue_proc.proc_layout), glue_proc.proc)
|
||||
})
|
||||
}));
|
||||
procedures.extend(all_glue_procs.getters.into_iter().flat_map(
|
||||
|(_, glue_procs)| {
|
||||
glue_procs.into_iter().map(|glue_proc| {
|
||||
(((glue_proc.name), glue_proc.proc_layout), glue_proc.proc)
|
||||
})
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3271,6 +3271,107 @@ fn rollback_typestate(
|
|||
}
|
||||
}
|
||||
|
||||
struct HostExposedProc<'a> {
|
||||
proc: Proc<'a>,
|
||||
top_level: ProcLayout<'a>,
|
||||
}
|
||||
|
||||
impl<'a> HostExposedProc<'a> {
|
||||
fn new(
|
||||
env: &mut Env<'a, '_>,
|
||||
procs: &mut Procs<'a>,
|
||||
lambda_name: LambdaName<'a>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
name: Symbol,
|
||||
layout: RawFunctionLayout<'a>,
|
||||
) -> Self {
|
||||
match layout {
|
||||
RawFunctionLayout::Function(argument_layouts, lambda_set, return_layout) => {
|
||||
let assigned = env.unique_symbol();
|
||||
|
||||
let mut argument_symbols = Vec::with_capacity_in(argument_layouts.len(), env.arena);
|
||||
let mut proc_arguments =
|
||||
Vec::with_capacity_in(argument_layouts.len() + 1, env.arena);
|
||||
let mut top_level_arguments =
|
||||
Vec::with_capacity_in(argument_layouts.len() + 1, env.arena);
|
||||
|
||||
for layout in argument_layouts {
|
||||
let symbol = env.unique_symbol();
|
||||
|
||||
proc_arguments.push((*layout, symbol));
|
||||
|
||||
argument_symbols.push(symbol);
|
||||
top_level_arguments.push(*layout);
|
||||
}
|
||||
|
||||
// the proc needs to take an extra closure argument
|
||||
let lambda_set_layout = Layout::LambdaSet(lambda_set);
|
||||
proc_arguments.push((lambda_set_layout, Symbol::ARG_CLOSURE));
|
||||
|
||||
// this should also be reflected in the TopLevel signature
|
||||
top_level_arguments.push(lambda_set_layout);
|
||||
|
||||
let hole = env.arena.alloc(Stmt::Ret(assigned));
|
||||
|
||||
let body = match_on_lambda_set(
|
||||
env,
|
||||
layout_cache,
|
||||
procs,
|
||||
lambda_set,
|
||||
Symbol::ARG_CLOSURE,
|
||||
argument_symbols.into_bump_slice(),
|
||||
argument_layouts,
|
||||
return_layout,
|
||||
assigned,
|
||||
hole,
|
||||
);
|
||||
|
||||
let proc = Proc {
|
||||
name: LambdaName::no_niche(name),
|
||||
args: proc_arguments.into_bump_slice(),
|
||||
body,
|
||||
closure_data_layout: None,
|
||||
ret_layout: *return_layout,
|
||||
is_self_recursive: SelfRecursive::NotSelfRecursive,
|
||||
must_own_arguments: false,
|
||||
host_exposed_layouts: HostExposedLayouts::NotHostExposed,
|
||||
};
|
||||
|
||||
let top_level = ProcLayout::new(
|
||||
env.arena,
|
||||
top_level_arguments.into_bump_slice(),
|
||||
Niche::NONE,
|
||||
*return_layout,
|
||||
);
|
||||
|
||||
Self { proc, top_level }
|
||||
}
|
||||
|
||||
RawFunctionLayout::ZeroArgumentThunk(result) => {
|
||||
let assigned = env.unique_symbol();
|
||||
let hole = env.arena.alloc(Stmt::Ret(assigned));
|
||||
let forced = force_thunk(env, lambda_name.name(), result, assigned, hole);
|
||||
|
||||
let lambda_name = LambdaName::no_niche(name);
|
||||
let proc = Proc {
|
||||
name: lambda_name,
|
||||
args: &[],
|
||||
body: forced,
|
||||
closure_data_layout: None,
|
||||
ret_layout: result,
|
||||
is_self_recursive: SelfRecursive::NotSelfRecursive,
|
||||
must_own_arguments: false,
|
||||
host_exposed_layouts: HostExposedLayouts::NotHostExposed,
|
||||
};
|
||||
|
||||
let top_level = ProcLayout::from_raw_named(env.arena, lambda_name, layout);
|
||||
|
||||
Self { proc, top_level }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Specialize a single proc.
|
||||
///
|
||||
/// The caller should snapshot and rollback the type state before and after calling this function,
|
||||
|
@ -3329,107 +3430,19 @@ fn specialize_proc_help<'a>(
|
|||
let mut aliases = BumpMap::new_in(env.arena);
|
||||
|
||||
for (symbol, variable) in host_exposed_variables {
|
||||
let layout = layout_cache
|
||||
let raw_layout = layout_cache
|
||||
.raw_from_var(env.arena, *variable, env.subs)
|
||||
.unwrap();
|
||||
|
||||
let name = env.unique_symbol();
|
||||
|
||||
match layout {
|
||||
RawFunctionLayout::Function(argument_layouts, lambda_set, return_layout) => {
|
||||
let assigned = env.unique_symbol();
|
||||
let HostExposedProc {
|
||||
proc, top_level, ..
|
||||
} = HostExposedProc::new(env, procs, lambda_name, layout_cache, name, raw_layout);
|
||||
|
||||
let mut argument_symbols =
|
||||
Vec::with_capacity_in(argument_layouts.len(), env.arena);
|
||||
let mut proc_arguments =
|
||||
Vec::with_capacity_in(argument_layouts.len() + 1, env.arena);
|
||||
let mut top_level_arguments =
|
||||
Vec::with_capacity_in(argument_layouts.len() + 1, env.arena);
|
||||
procs.specialized.insert_specialized(name, top_level, proc);
|
||||
|
||||
for layout in argument_layouts {
|
||||
let symbol = env.unique_symbol();
|
||||
|
||||
proc_arguments.push((*layout, symbol));
|
||||
|
||||
argument_symbols.push(symbol);
|
||||
top_level_arguments.push(*layout);
|
||||
}
|
||||
|
||||
// the proc needs to take an extra closure argument
|
||||
let lambda_set_layout = Layout::LambdaSet(lambda_set);
|
||||
proc_arguments.push((lambda_set_layout, Symbol::ARG_CLOSURE));
|
||||
|
||||
// this should also be reflected in the TopLevel signature
|
||||
top_level_arguments.push(lambda_set_layout);
|
||||
|
||||
let hole = env.arena.alloc(Stmt::Ret(assigned));
|
||||
|
||||
let body = match_on_lambda_set(
|
||||
env,
|
||||
layout_cache,
|
||||
procs,
|
||||
lambda_set,
|
||||
Symbol::ARG_CLOSURE,
|
||||
argument_symbols.into_bump_slice(),
|
||||
argument_layouts,
|
||||
return_layout,
|
||||
assigned,
|
||||
hole,
|
||||
);
|
||||
|
||||
let proc = Proc {
|
||||
name: LambdaName::no_niche(name),
|
||||
args: proc_arguments.into_bump_slice(),
|
||||
body,
|
||||
closure_data_layout: None,
|
||||
ret_layout: *return_layout,
|
||||
is_self_recursive: SelfRecursive::NotSelfRecursive,
|
||||
must_own_arguments: false,
|
||||
host_exposed_layouts: HostExposedLayouts::NotHostExposed,
|
||||
};
|
||||
|
||||
let top_level = ProcLayout::new(
|
||||
env.arena,
|
||||
top_level_arguments.into_bump_slice(),
|
||||
Niche::NONE,
|
||||
*return_layout,
|
||||
);
|
||||
|
||||
procs.specialized.insert_specialized(name, top_level, proc);
|
||||
|
||||
aliases.insert(*symbol, (name, top_level, layout));
|
||||
}
|
||||
RawFunctionLayout::ZeroArgumentThunk(result) => {
|
||||
let assigned = env.unique_symbol();
|
||||
let hole = env.arena.alloc(Stmt::Ret(assigned));
|
||||
let forced = force_thunk(env, lambda_name.name(), result, assigned, hole);
|
||||
|
||||
let lambda_name = LambdaName::no_niche(name);
|
||||
let proc = Proc {
|
||||
name: lambda_name,
|
||||
args: &[],
|
||||
body: forced,
|
||||
closure_data_layout: None,
|
||||
ret_layout: result,
|
||||
is_self_recursive: SelfRecursive::NotSelfRecursive,
|
||||
must_own_arguments: false,
|
||||
host_exposed_layouts: HostExposedLayouts::NotHostExposed,
|
||||
};
|
||||
|
||||
let top_level = ProcLayout::from_raw_named(env.arena, lambda_name, layout);
|
||||
|
||||
procs.specialized.insert_specialized(name, top_level, proc);
|
||||
|
||||
aliases.insert(
|
||||
*symbol,
|
||||
(
|
||||
name,
|
||||
ProcLayout::new(env.arena, &[], Niche::NONE, result),
|
||||
layout,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
aliases.insert(*symbol, (name, top_level, raw_layout));
|
||||
}
|
||||
|
||||
HostExposedLayouts::HostExposed {
|
||||
|
@ -10902,16 +10915,26 @@ pub struct GlueProc<'a> {
|
|||
pub proc: Proc<'a>,
|
||||
}
|
||||
|
||||
pub struct GlueProcs<'a> {
|
||||
pub getters: Vec<'a, (Layout<'a>, Vec<'a, GlueProc<'a>>)>,
|
||||
pub extern_names: Vec<'a, (LambdaSet<'a>, String)>,
|
||||
}
|
||||
|
||||
pub fn generate_glue_procs<'a, I: Interner<'a, Layout<'a>>>(
|
||||
home: ModuleId,
|
||||
interns: &mut Interns,
|
||||
arena: &'a Bump,
|
||||
layout_interner: &mut I,
|
||||
layout: &'a Layout<'a>,
|
||||
) -> Vec<'a, (Layout<'a>, Vec<'a, GlueProc<'a>>)> {
|
||||
let mut answer: Vec<'a, (Layout<'a>, Vec<'a, GlueProc<'a>>)> = Vec::new_in(arena);
|
||||
) -> GlueProcs<'a> {
|
||||
let mut answer = GlueProcs {
|
||||
getters: Vec::new_in(arena),
|
||||
extern_names: Vec::new_in(arena),
|
||||
};
|
||||
|
||||
let mut stack: Vec<'a, Layout<'a>> = Vec::from_iter_in([*layout], arena);
|
||||
let mut next_unique_id = 0;
|
||||
let mut next_extern_id = 0;
|
||||
|
||||
macro_rules! handle_struct_field_layouts {
|
||||
($field_layouts: expr) => {{
|
||||
|
@ -10929,7 +10952,7 @@ pub fn generate_glue_procs<'a, I: Interner<'a, Layout<'a>>>(
|
|||
$field_layouts,
|
||||
);
|
||||
|
||||
answer.push((*layout, procs));
|
||||
answer.getters.push((*layout, procs));
|
||||
}
|
||||
|
||||
stack.extend($field_layouts.iter().copied());
|
||||
|
@ -10954,7 +10977,7 @@ pub fn generate_glue_procs<'a, I: Interner<'a, Layout<'a>>>(
|
|||
$field_layouts,
|
||||
);
|
||||
|
||||
answer.push((*layout, procs));
|
||||
answer.getters.push((*layout, procs));
|
||||
}
|
||||
|
||||
stack.extend($field_layouts.iter().copied());
|
||||
|
@ -10999,6 +11022,10 @@ pub fn generate_glue_procs<'a, I: Interner<'a, Layout<'a>>>(
|
|||
}
|
||||
},
|
||||
Layout::LambdaSet(lambda_set) => {
|
||||
let symbol = unique_glue_symbol(arena, &mut next_unique_id, home, interns);
|
||||
let string = String::from(symbol.as_str(interns));
|
||||
answer.extern_names.push((lambda_set, string));
|
||||
|
||||
// TODO generate closure caller
|
||||
stack.push(lambda_set.runtime_representation(layout_interner))
|
||||
}
|
||||
|
|
|
@ -156,6 +156,7 @@ pub fn load_types(
|
|||
};
|
||||
let mut layout_cache = LayoutCache::new(layout_interner.fork(), target_info);
|
||||
let mut glue_procs_by_layout = MutMap::default();
|
||||
let mut extern_names = MutMap::default();
|
||||
|
||||
// Populate glue getters/setters for all relevant variables
|
||||
for var in variables.clone() {
|
||||
|
@ -172,10 +173,12 @@ pub fn load_types(
|
|||
arena.alloc(layout),
|
||||
);
|
||||
|
||||
extern_names.extend(answer.extern_names);
|
||||
|
||||
// Even though generate_glue_procs does more work than we need it to,
|
||||
// it's important that we use it in order to make sure we get exactly
|
||||
// the same names that mono::ir did for code gen!
|
||||
for (layout, glue_procs) in answer {
|
||||
for (layout, glue_procs) in answer.getters {
|
||||
let mut names =
|
||||
bumpalo::collections::Vec::with_capacity_in(glue_procs.len(), arena);
|
||||
|
||||
|
@ -189,7 +192,7 @@ pub fn load_types(
|
|||
// the structs and fields.
|
||||
//
|
||||
// Store them as strings, because symbols won't be useful to glue generators!
|
||||
names.push(dbg!(name.as_str(&interns)).to_string());
|
||||
names.push(name.as_str(&interns).to_string());
|
||||
}
|
||||
|
||||
glue_procs_by_layout.insert(layout, names.into_bump_slice());
|
||||
|
@ -203,6 +206,7 @@ pub fn load_types(
|
|||
variables.clone(),
|
||||
arena.alloc(interns),
|
||||
glue_procs_by_layout,
|
||||
extern_names,
|
||||
layout_cache,
|
||||
target_info,
|
||||
);
|
||||
|
|
|
@ -12,8 +12,8 @@ use roc_module::{
|
|||
symbol::{Interns, Symbol},
|
||||
};
|
||||
use roc_mono::layout::{
|
||||
cmp_fields, ext_var_is_empty_tag_union, round_up_to_alignment, Builtin, Discriminant, Layout,
|
||||
LayoutCache, LayoutInterner, UnionLayout,
|
||||
cmp_fields, ext_var_is_empty_tag_union, round_up_to_alignment, Builtin, Discriminant,
|
||||
LambdaSet, Layout, LayoutCache, LayoutInterner, UnionLayout,
|
||||
};
|
||||
use roc_target::TargetInfo;
|
||||
use roc_types::{
|
||||
|
@ -67,12 +67,14 @@ impl Types {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new<'a, I: Iterator<Item = Variable>>(
|
||||
arena: &'a Bump,
|
||||
subs: &'a Subs,
|
||||
variables: I,
|
||||
interns: &'a Interns,
|
||||
glue_procs_by_layout: MutMap<Layout<'a>, &'a [String]>,
|
||||
extern_names: MutMap<LambdaSet<'a>, String>,
|
||||
layout_cache: LayoutCache<'a>,
|
||||
target: TargetInfo,
|
||||
) -> Self {
|
||||
|
@ -83,6 +85,7 @@ impl Types {
|
|||
interns,
|
||||
layout_cache,
|
||||
glue_procs_by_layout,
|
||||
extern_names,
|
||||
target,
|
||||
);
|
||||
|
||||
|
@ -818,6 +821,7 @@ struct Env<'a> {
|
|||
subs: &'a Subs,
|
||||
layout_cache: LayoutCache<'a>,
|
||||
glue_procs_by_layout: MutMap<Layout<'a>, &'a [String]>,
|
||||
extern_names: MutMap<LambdaSet<'a>, String>,
|
||||
interns: &'a Interns,
|
||||
struct_names: Structs,
|
||||
enum_names: Enums,
|
||||
|
@ -833,6 +837,7 @@ impl<'a> Env<'a> {
|
|||
interns: &'a Interns,
|
||||
layout_cache: LayoutCache<'a>,
|
||||
glue_procs_by_layout: MutMap<Layout<'a>, &'a [String]>,
|
||||
extern_names: MutMap<LambdaSet<'a>, String>,
|
||||
target: TargetInfo,
|
||||
) -> Self {
|
||||
Env {
|
||||
|
@ -844,6 +849,7 @@ impl<'a> Env<'a> {
|
|||
pending_recursive_types: Default::default(),
|
||||
known_recursive_types: Default::default(),
|
||||
glue_procs_by_layout,
|
||||
extern_names,
|
||||
layout_cache,
|
||||
target,
|
||||
}
|
||||
|
@ -967,23 +973,36 @@ fn add_type_help<'a>(
|
|||
let args = env.subs.get_subs_slice(*args);
|
||||
let mut arg_type_ids = Vec::with_capacity(args.len());
|
||||
|
||||
let name = format!("RocFunction_{:?}", closure_var);
|
||||
|
||||
let lambda_set_layout = env
|
||||
.layout_cache
|
||||
.from_var(env.arena, *closure_var, env.subs)
|
||||
.expect("Something weird ended up in the content");
|
||||
|
||||
let lambda_set = match lambda_set_layout {
|
||||
Layout::LambdaSet(lambda_set) => lambda_set,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// String::from("roc__mainForHost_1__Fx2_caller");
|
||||
let extern_name = env.extern_names.get(&lambda_set).cloned().unwrap();
|
||||
|
||||
dbg!(&extern_name, &name);
|
||||
|
||||
for arg_var in args {
|
||||
let arg_layout = env
|
||||
.layout_cache
|
||||
.from_var(env.arena, *arg_var, env.subs)
|
||||
.expect("Something weird ended up in the content");
|
||||
|
||||
dbg!(&arg_layout);
|
||||
|
||||
arg_type_ids.push(add_type_help(env, arg_layout, *arg_var, None, types));
|
||||
}
|
||||
|
||||
let lambda_set_type_id = {
|
||||
let lambda_set_layout = env
|
||||
.layout_cache
|
||||
.from_var(env.arena, *closure_var, env.subs)
|
||||
.expect("Something weird ended up in the content");
|
||||
|
||||
add_type_help(env, lambda_set_layout, *closure_var, None, types)
|
||||
};
|
||||
let lambda_set_type_id =
|
||||
add_type_help(env, lambda_set_layout, *closure_var, None, types);
|
||||
|
||||
let ret_type_id = {
|
||||
let ret_layout = env
|
||||
|
@ -991,13 +1010,11 @@ fn add_type_help<'a>(
|
|||
.from_var(env.arena, *ret_var, env.subs)
|
||||
.expect("Something weird ended up in the content");
|
||||
|
||||
dbg!(ret_layout);
|
||||
|
||||
add_type_help(env, ret_layout, *ret_var, None, types)
|
||||
};
|
||||
|
||||
let name = format!("RocFunction_{:?}", closure_var);
|
||||
|
||||
let extern_name = String::from("roc__mainForHost_1__Fx2_caller");
|
||||
|
||||
let fn_type_id = add_function(env, name, types, layout, |name| {
|
||||
RocType::Function(RocFn {
|
||||
function_name: name,
|
||||
|
@ -1654,7 +1671,7 @@ fn tag_union_type_from_layout<'a>(
|
|||
|
||||
RocTagUnion::SingleTagStruct {
|
||||
name: name.clone(),
|
||||
tag_name: tag_name.to_string(),
|
||||
tag_name,
|
||||
payload,
|
||||
}
|
||||
}
|
||||
|
@ -1670,7 +1687,7 @@ fn tag_union_type_from_layout<'a>(
|
|||
|
||||
RocTagUnion::SingleTagStruct {
|
||||
name: name.clone(),
|
||||
tag_name: tag_name.to_string(),
|
||||
tag_name,
|
||||
payload: RocSingleTagPayload::HasNoClosure {
|
||||
// Builtins have no closures
|
||||
payload_fields: vec![type_id],
|
||||
|
|
|
@ -102,11 +102,11 @@ pub struct RocFunction_65 {
|
|||
impl RocFunction_65 {
|
||||
pub fn force_thunk(self, ) -> Op {
|
||||
extern "C" {
|
||||
fn roc__mainForHost_1__Fx2_caller(output: *mut Op, );
|
||||
fn roc__getter__5(output: *mut Op, );
|
||||
}
|
||||
|
||||
let mut output = std::mem::MaybeUninit::uninit();
|
||||
unsafe { roc__mainForHost_1__Fx2_caller(output.as_mut_ptr(), ) };
|
||||
unsafe { roc__getter__5(output.as_mut_ptr(), ) };
|
||||
unsafe { output.assume_init() }
|
||||
}
|
||||
}
|
||||
|
@ -127,11 +127,11 @@ pub struct RocFunction_67 {
|
|||
impl RocFunction_67 {
|
||||
pub fn force_thunk(self, ) -> Op {
|
||||
extern "C" {
|
||||
fn roc__mainForHost_1__Fx2_caller(output: *mut Op, );
|
||||
fn roc__getter__5(output: *mut Op, );
|
||||
}
|
||||
|
||||
let mut output = std::mem::MaybeUninit::uninit();
|
||||
unsafe { roc__mainForHost_1__Fx2_caller(output.as_mut_ptr(), ) };
|
||||
unsafe { roc__getter__5(output.as_mut_ptr(), ) };
|
||||
unsafe { output.assume_init() }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue