mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
First pass at erased function layouts
This commit is contained in:
parent
6e5a308557
commit
a9e3f967a8
3 changed files with 39 additions and 36 deletions
|
@ -5,8 +5,7 @@ use crate::ir::literal::{make_num_literal, IntOrFloatValue};
|
||||||
use crate::layout::{
|
use crate::layout::{
|
||||||
self, Builtin, ClosureCallOptions, ClosureRepresentation, EnumDispatch, InLayout, LambdaName,
|
self, Builtin, ClosureCallOptions, ClosureRepresentation, EnumDispatch, InLayout, LambdaName,
|
||||||
LambdaSet, Layout, LayoutCache, LayoutInterner, LayoutProblem, LayoutRepr, Niche,
|
LambdaSet, Layout, LayoutCache, LayoutInterner, LayoutProblem, LayoutRepr, Niche,
|
||||||
OpaqueFunctionData, RawFunctionLayout, TLLayoutInterner, TagIdIntType, UnionLayout,
|
RawFunctionLayout, TLLayoutInterner, TagIdIntType, UnionLayout, WrappedVariant,
|
||||||
WrappedVariant,
|
|
||||||
};
|
};
|
||||||
use bumpalo::collections::{CollectIn, Vec};
|
use bumpalo::collections::{CollectIn, Vec};
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
@ -3196,18 +3195,8 @@ fn generate_runtime_error_function<'a>(
|
||||||
|
|
||||||
(args.into_bump_slice(), ret_layout)
|
(args.into_bump_slice(), ret_layout)
|
||||||
}
|
}
|
||||||
RawFunctionLayout::ErasedFunction(arg_layouts, closure_data, ret_layout) => {
|
RawFunctionLayout::ErasedFunction(..) => {
|
||||||
let mut args = Vec::with_capacity_in(arg_layouts.len() + 1, env.arena);
|
todo_lambda_erasure!()
|
||||||
for arg in arg_layouts {
|
|
||||||
args.push((*arg, env.unique_symbol()));
|
|
||||||
}
|
|
||||||
if let OpaqueFunctionData::Capturing { .. } = closure_data {
|
|
||||||
// TODO(erased-lambdas) we want a void* here, but is a boxed pointer always
|
|
||||||
// correct?
|
|
||||||
args.push((Layout::OPAQUE_PTR, Symbol::ARG_CLOSURE));
|
|
||||||
}
|
|
||||||
|
|
||||||
(args.into_bump_slice(), ret_layout)
|
|
||||||
}
|
}
|
||||||
RawFunctionLayout::ZeroArgumentThunk(ret_layout) => (&[] as &[_], ret_layout),
|
RawFunctionLayout::ZeroArgumentThunk(ret_layout) => (&[] as &[_], ret_layout),
|
||||||
};
|
};
|
||||||
|
@ -4845,7 +4834,7 @@ pub fn with_hole<'a>(
|
||||||
hole,
|
hole,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
RawFunctionLayout::ErasedFunction(_, _, _) => todo_lambda_erasure!(),
|
RawFunctionLayout::ErasedFunction(_, _) => todo_lambda_erasure!(),
|
||||||
RawFunctionLayout::ZeroArgumentThunk(_) => unreachable!(),
|
RawFunctionLayout::ZeroArgumentThunk(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -481,24 +481,10 @@ impl From<LayoutProblem> for RuntimeError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When we do not kind functions, we type-erase functions to opaque pointers.
|
|
||||||
/// The erased function definition, however, continues to hold data about how the erased function
|
|
||||||
/// behaves.
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
|
||||||
pub enum OpaqueFunctionData<'a> {
|
|
||||||
/// This function is not capturing, and needs no extra data regarding closures.
|
|
||||||
Null,
|
|
||||||
/// This function is capturing.
|
|
||||||
Capturing {
|
|
||||||
/// The concrete type of the closure data expected by a call to the function.
|
|
||||||
closure_data_layout: InLayout<'a>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum RawFunctionLayout<'a> {
|
pub enum RawFunctionLayout<'a> {
|
||||||
Function(&'a [InLayout<'a>], LambdaSet<'a>, InLayout<'a>),
|
Function(&'a [InLayout<'a>], LambdaSet<'a>, InLayout<'a>),
|
||||||
ErasedFunction(&'a [InLayout<'a>], OpaqueFunctionData<'a>, InLayout<'a>),
|
ErasedFunction(&'a [InLayout<'a>], InLayout<'a>),
|
||||||
ZeroArgumentThunk(InLayout<'a>),
|
ZeroArgumentThunk(InLayout<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -620,13 +606,17 @@ impl<'a> RawFunctionLayout<'a> {
|
||||||
|
|
||||||
let fn_args = fn_args.into_bump_slice();
|
let fn_args = fn_args.into_bump_slice();
|
||||||
|
|
||||||
let lambda_set = cached!(
|
let closure_data = build_function_closure_data(env, args, closure_var, ret_var);
|
||||||
LambdaSet::from_var(env, args, closure_var, ret_var),
|
let closure_data = cached!(closure_data, cache_criteria, env.subs);
|
||||||
cache_criteria,
|
|
||||||
env.subs
|
|
||||||
);
|
|
||||||
|
|
||||||
Cacheable(Ok(Self::Function(fn_args, lambda_set, ret)), cache_criteria)
|
let function_layout = match closure_data {
|
||||||
|
ClosureDataKind::LambdaSet(lambda_set) => {
|
||||||
|
Self::Function(fn_args, lambda_set, ret)
|
||||||
|
}
|
||||||
|
ClosureDataKind::Erased => Self::ErasedFunction(fn_args, ret),
|
||||||
|
};
|
||||||
|
|
||||||
|
Cacheable(Ok(function_layout), cache_criteria)
|
||||||
}
|
}
|
||||||
TagUnion(tags, ext) if tags.is_newtype_wrapper(env.subs) => {
|
TagUnion(tags, ext) if tags.is_newtype_wrapper(env.subs) => {
|
||||||
debug_assert!(ext_var_is_empty_tag_union(env.subs, ext));
|
debug_assert!(ext_var_is_empty_tag_union(env.subs, ext));
|
||||||
|
@ -1359,6 +1349,27 @@ impl<'a> LambdaName<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Closure data for a function
|
||||||
|
enum ClosureDataKind<'a> {
|
||||||
|
/// The function is compiled with lambda sets.
|
||||||
|
LambdaSet(LambdaSet<'a>),
|
||||||
|
/// The function is compiled as type-erased.
|
||||||
|
Erased,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_function_closure_data<'a>(
|
||||||
|
env: &mut Env<'a, '_>,
|
||||||
|
args: VariableSubsSlice,
|
||||||
|
closure_var: Variable,
|
||||||
|
ret_var: Variable,
|
||||||
|
) -> Cacheable<Result<ClosureDataKind<'a>, LayoutProblem>> {
|
||||||
|
match env.subs.get_content_without_compacting(closure_var) {
|
||||||
|
Content::ErasedLambda => cacheable(Ok(ClosureDataKind::Erased)),
|
||||||
|
_ => LambdaSet::from_var(env, args, closure_var, ret_var)
|
||||||
|
.map(|result| result.map(ClosureDataKind::LambdaSet)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub struct LambdaSet<'a> {
|
pub struct LambdaSet<'a> {
|
||||||
pub(crate) args: &'a &'a [InLayout<'a>],
|
pub(crate) args: &'a &'a [InLayout<'a>],
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# +set function_kind=erased
|
# +set function_kind=erased
|
||||||
|
# +emit:mono
|
||||||
app "test" provides [main] to "./platform"
|
app "test" provides [main] to "./platform"
|
||||||
|
|
||||||
f = \s ->
|
f = \s ->
|
||||||
|
@ -10,3 +11,5 @@ f = \s ->
|
||||||
|
|
||||||
main = (f "") {}
|
main = (f "") {}
|
||||||
# ^^^^ {} -?-> Str
|
# ^^^^ {} -?-> Str
|
||||||
|
|
||||||
|
# -emit:mono
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue