mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 05:49:08 +00:00
Allow direct packing, unpacking of erased types
This commit is contained in:
parent
1d1db83cc7
commit
cd64134b0a
6 changed files with 296 additions and 185 deletions
|
@ -29,6 +29,7 @@ pub enum UseKind {
|
||||||
ExpectLookup,
|
ExpectLookup,
|
||||||
ErasedMake(ErasedField),
|
ErasedMake(ErasedField),
|
||||||
Erased,
|
Erased,
|
||||||
|
FunctionPointer,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ProblemKind<'a> {
|
pub enum ProblemKind<'a> {
|
||||||
|
@ -119,6 +120,24 @@ pub enum ProblemKind<'a> {
|
||||||
num_needed: usize,
|
num_needed: usize,
|
||||||
num_given: usize,
|
num_given: usize,
|
||||||
},
|
},
|
||||||
|
ErasedMakeValueNotBoxed {
|
||||||
|
symbol: Symbol,
|
||||||
|
def_layout: InLayout<'a>,
|
||||||
|
def_line: usize,
|
||||||
|
},
|
||||||
|
ErasedMakeCalleeNotFunctionPointer {
|
||||||
|
symbol: Symbol,
|
||||||
|
def_layout: InLayout<'a>,
|
||||||
|
def_line: usize,
|
||||||
|
},
|
||||||
|
ErasedLoadValueNotBoxed {
|
||||||
|
symbol: Symbol,
|
||||||
|
target_layout: InLayout<'a>,
|
||||||
|
},
|
||||||
|
ErasedLoadCalleeNotFunctionPointer {
|
||||||
|
symbol: Symbol,
|
||||||
|
target_layout: InLayout<'a>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Problem<'a> {
|
pub struct Problem<'a> {
|
||||||
|
@ -276,7 +295,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
||||||
|
|
||||||
match body {
|
match body {
|
||||||
Stmt::Let(x, e, x_layout, rest) => {
|
Stmt::Let(x, e, x_layout, rest) => {
|
||||||
if let Some(e_layout) = self.check_expr(e) {
|
if let Some(e_layout) = self.check_expr(e, *x_layout) {
|
||||||
if self.not_equiv(e_layout, *x_layout) {
|
if self.not_equiv(e_layout, *x_layout) {
|
||||||
self.problem(ProblemKind::SymbolDefMismatch {
|
self.problem(ProblemKind::SymbolDefMismatch {
|
||||||
symbol: *x,
|
symbol: *x,
|
||||||
|
@ -393,7 +412,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_expr(&mut self, e: &Expr<'a>) -> Option<InLayout<'a>> {
|
fn check_expr(&mut self, e: &Expr<'a>, target_layout: InLayout<'a>) -> Option<InLayout<'a>> {
|
||||||
match e {
|
match e {
|
||||||
Expr::Literal(_) => None,
|
Expr::Literal(_) => None,
|
||||||
Expr::NullPointer => None,
|
Expr::NullPointer => None,
|
||||||
|
@ -486,11 +505,10 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
&Expr::ErasedMake { value, callee } => {
|
&Expr::ErasedMake { value, callee } => Some(self.check_erased_make(value, callee)),
|
||||||
self.check_erased_make(value, callee);
|
&Expr::ErasedLoad { symbol, field } => {
|
||||||
Some(Layout::ERASED)
|
Some(self.check_erased_load(symbol, field, target_layout))
|
||||||
}
|
}
|
||||||
&Expr::ErasedLoad { symbol, field } => Some(self.check_erased_load(symbol, field)),
|
|
||||||
&Expr::FunctionPointer { lambda_name } => {
|
&Expr::FunctionPointer { lambda_name } => {
|
||||||
let lambda_symbol = lambda_name.name();
|
let lambda_symbol = lambda_name.name();
|
||||||
if !self.procs.iter().any(|((name, proc), _)| {
|
if !self.procs.iter().any(|((name, proc), _)| {
|
||||||
|
@ -500,7 +518,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
||||||
symbol: lambda_symbol,
|
symbol: lambda_symbol,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Some(Layout::OPAQUE_PTR)
|
Some(target_layout)
|
||||||
}
|
}
|
||||||
&Expr::Reset {
|
&Expr::Reset {
|
||||||
symbol,
|
symbol,
|
||||||
|
@ -691,7 +709,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
||||||
args: arg_layouts,
|
args: arg_layouts,
|
||||||
ret: *ret_layout,
|
ret: *ret_layout,
|
||||||
}));
|
}));
|
||||||
self.check_sym_layout(*pointer, expected_layout, UseKind::SwitchCond);
|
self.check_sym_layout(*pointer, expected_layout, UseKind::FunctionPointer);
|
||||||
for (arg, wanted_layout) in arguments.iter().zip(arg_layouts.iter()) {
|
for (arg, wanted_layout) in arguments.iter().zip(arg_layouts.iter()) {
|
||||||
self.check_sym_layout(*arg, *wanted_layout, UseKind::CallArg);
|
self.check_sym_layout(*arg, *wanted_layout, UseKind::CallArg);
|
||||||
}
|
}
|
||||||
|
@ -756,28 +774,67 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_erased_make(&mut self, value: Option<Symbol>, callee: Symbol) {
|
fn check_erased_make(&mut self, value: Option<Symbol>, callee: Symbol) -> InLayout<'a> {
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
self.check_sym_layout(
|
self.with_sym_layout(value, |this, def_line, layout| {
|
||||||
value,
|
let repr = this.interner.get_repr(layout);
|
||||||
Layout::OPAQUE_PTR,
|
if !matches!(repr, LayoutRepr::Boxed(_)) {
|
||||||
UseKind::ErasedMake(ErasedField::Value),
|
this.problem(ProblemKind::ErasedMakeValueNotBoxed {
|
||||||
);
|
symbol: value,
|
||||||
|
def_layout: layout,
|
||||||
|
def_line,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Option::<()>::None
|
||||||
|
});
|
||||||
}
|
}
|
||||||
self.check_sym_layout(
|
self.with_sym_layout(callee, |this, def_line, layout| {
|
||||||
callee,
|
let repr = this.interner.get_repr(layout);
|
||||||
Layout::OPAQUE_PTR,
|
if !matches!(repr, LayoutRepr::FunctionPointer(_)) {
|
||||||
UseKind::ErasedMake(ErasedField::Callee),
|
this.problem(ProblemKind::ErasedMakeCalleeNotFunctionPointer {
|
||||||
);
|
symbol: callee,
|
||||||
|
def_layout: layout,
|
||||||
|
def_line,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Option::<()>::None
|
||||||
|
});
|
||||||
|
|
||||||
|
Layout::ERASED
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_erased_load(&mut self, symbol: Symbol, field: ErasedField) -> InLayout<'a> {
|
fn check_erased_load(
|
||||||
|
&mut self,
|
||||||
|
symbol: Symbol,
|
||||||
|
field: ErasedField,
|
||||||
|
target_layout: InLayout<'a>,
|
||||||
|
) -> InLayout<'a> {
|
||||||
self.check_sym_layout(symbol, Layout::ERASED, UseKind::Erased);
|
self.check_sym_layout(symbol, Layout::ERASED, UseKind::Erased);
|
||||||
|
|
||||||
match field {
|
match field {
|
||||||
ErasedField::Value => Layout::OPAQUE_PTR,
|
ErasedField::Value => {
|
||||||
ErasedField::Callee => Layout::OPAQUE_PTR,
|
let repr = self.interner.get_repr(target_layout);
|
||||||
|
if !matches!(repr, LayoutRepr::Boxed(_)) {
|
||||||
|
self.problem(ProblemKind::ErasedLoadValueNotBoxed {
|
||||||
|
symbol,
|
||||||
|
target_layout,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ErasedField::Callee => {
|
||||||
|
let repr = self.interner.get_repr(target_layout);
|
||||||
|
if !matches!(repr, LayoutRepr::FunctionPointer(_)) {
|
||||||
|
self.problem(ProblemKind::ErasedLoadCalleeNotFunctionPointer {
|
||||||
|
symbol,
|
||||||
|
target_layout,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
target_layout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -415,6 +415,74 @@ where
|
||||||
f.as_string(num_given),
|
f.as_string(num_given),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
ProblemKind::ErasedMakeValueNotBoxed {
|
||||||
|
symbol,
|
||||||
|
def_layout,
|
||||||
|
def_line,
|
||||||
|
} => {
|
||||||
|
title = "ERASED VALUE IS NOT BOXED";
|
||||||
|
docs_before = vec![(
|
||||||
|
def_line,
|
||||||
|
f.concat([
|
||||||
|
f.reflow("The value "),
|
||||||
|
format_symbol(f, interns, symbol),
|
||||||
|
f.reflow(" defined here"),
|
||||||
|
]),
|
||||||
|
)];
|
||||||
|
f.concat([
|
||||||
|
f.reflow("must be boxed in order to be erased, but has layout "),
|
||||||
|
interner.to_doc_top(def_layout, f),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
ProblemKind::ErasedMakeCalleeNotFunctionPointer {
|
||||||
|
symbol,
|
||||||
|
def_layout,
|
||||||
|
def_line,
|
||||||
|
} => {
|
||||||
|
title = "ERASED CALLEE IS NOT A FUNCTION POINTER";
|
||||||
|
docs_before = vec![(
|
||||||
|
def_line,
|
||||||
|
f.concat([
|
||||||
|
f.reflow("The value "),
|
||||||
|
format_symbol(f, interns, symbol),
|
||||||
|
f.reflow(" defined here"),
|
||||||
|
]),
|
||||||
|
)];
|
||||||
|
f.concat([
|
||||||
|
f.reflow(
|
||||||
|
"must be a function pointer in order to be an erasure callee, but has layout ",
|
||||||
|
),
|
||||||
|
interner.to_doc_top(def_layout, f),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
ProblemKind::ErasedLoadValueNotBoxed {
|
||||||
|
symbol,
|
||||||
|
target_layout,
|
||||||
|
} => {
|
||||||
|
title = "ERASED VALUE IS NOT BOXED";
|
||||||
|
docs_before = vec![];
|
||||||
|
f.concat([
|
||||||
|
f.reflow("The erased value load "),
|
||||||
|
format_symbol(f, interns, symbol),
|
||||||
|
f.reflow(" has layout "),
|
||||||
|
interner.to_doc_top(target_layout, f),
|
||||||
|
f.reflow(", but should be boxed!"),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
ProblemKind::ErasedLoadCalleeNotFunctionPointer {
|
||||||
|
symbol,
|
||||||
|
target_layout,
|
||||||
|
} => {
|
||||||
|
title = "ERASED CALLEE IS NOT A FUNCTION POINTER";
|
||||||
|
docs_before = vec![];
|
||||||
|
f.concat([
|
||||||
|
f.reflow("The erased callee load "),
|
||||||
|
format_symbol(f, interns, symbol),
|
||||||
|
f.reflow(" has layout "),
|
||||||
|
interner.to_doc_top(target_layout, f),
|
||||||
|
f.reflow(", but should be a function pointer!"),
|
||||||
|
])
|
||||||
|
}
|
||||||
};
|
};
|
||||||
(title, docs_before, doc)
|
(title, docs_before, doc)
|
||||||
}
|
}
|
||||||
|
@ -443,6 +511,7 @@ fn format_use_kind(use_kind: UseKind) -> &'static str {
|
||||||
ErasedField::Callee => "erased callee field",
|
ErasedField::Callee => "erased callee field",
|
||||||
},
|
},
|
||||||
UseKind::Erased => "erasure",
|
UseKind::Erased => "erasure",
|
||||||
|
UseKind::FunctionPointer => "function pointer",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5268,12 +5268,18 @@ pub fn with_hole<'a>(
|
||||||
RawFunctionLayout::ZeroArgumentThunk(_) => {
|
RawFunctionLayout::ZeroArgumentThunk(_) => {
|
||||||
unreachable!("a closure syntactically always must have at least one argument")
|
unreachable!("a closure syntactically always must have at least one argument")
|
||||||
}
|
}
|
||||||
RawFunctionLayout::ErasedFunction(_argument_layouts, _ret_layout) => {
|
RawFunctionLayout::ErasedFunction(argument_layouts, ret_layout) => {
|
||||||
let captured_symbols = Vec::from_iter_in(captured_symbols, env.arena);
|
let captured_symbols = Vec::from_iter_in(captured_symbols, env.arena);
|
||||||
let captured_symbols = captured_symbols.into_bump_slice();
|
let captured_symbols = captured_symbols.into_bump_slice();
|
||||||
let captured_symbols = CapturedSymbols::Captured(captured_symbols);
|
let captured_symbols = CapturedSymbols::Captured(captured_symbols);
|
||||||
let resolved_erased_lambda =
|
let resolved_erased_lambda = ResolvedErasedLambda::new(
|
||||||
ResolvedErasedLambda::new(env, layout_cache, name, captured_symbols);
|
env,
|
||||||
|
layout_cache,
|
||||||
|
name,
|
||||||
|
captured_symbols,
|
||||||
|
argument_layouts,
|
||||||
|
ret_layout,
|
||||||
|
);
|
||||||
|
|
||||||
let inserted = procs.insert_anonymous(
|
let inserted = procs.insert_anonymous(
|
||||||
env,
|
env,
|
||||||
|
@ -8340,9 +8346,15 @@ fn specialize_symbol<'a>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RawFunctionLayout::ErasedFunction(..) => {
|
RawFunctionLayout::ErasedFunction(argument_layouts, ret_layout) => {
|
||||||
let erased_lambda =
|
let erased_lambda = erased::ResolvedErasedLambda::new(
|
||||||
erased::ResolvedErasedLambda::new(env, layout_cache, original, captured);
|
env,
|
||||||
|
layout_cache,
|
||||||
|
original,
|
||||||
|
captured,
|
||||||
|
argument_layouts,
|
||||||
|
ret_layout,
|
||||||
|
);
|
||||||
let lambda_name = erased_lambda.lambda_name();
|
let lambda_name = erased_lambda.lambda_name();
|
||||||
|
|
||||||
let proc_layout =
|
let proc_layout =
|
||||||
|
|
|
@ -17,6 +17,7 @@ fn index_erased_function<'a>(
|
||||||
assign_to: Symbol,
|
assign_to: Symbol,
|
||||||
erased_function: Symbol,
|
erased_function: Symbol,
|
||||||
field: ErasedField,
|
field: ErasedField,
|
||||||
|
layout: InLayout<'a>,
|
||||||
) -> impl FnOnce(Stmt<'a>) -> Stmt<'a> {
|
) -> impl FnOnce(Stmt<'a>) -> Stmt<'a> {
|
||||||
move |rest| {
|
move |rest| {
|
||||||
Stmt::Let(
|
Stmt::Let(
|
||||||
|
@ -25,29 +26,7 @@ fn index_erased_function<'a>(
|
||||||
symbol: erased_function,
|
symbol: erased_function,
|
||||||
field,
|
field,
|
||||||
},
|
},
|
||||||
Layout::OPAQUE_PTR,
|
layout,
|
||||||
arena.alloc(rest),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cast_erased_callee<'a>(
|
|
||||||
arena: &'a Bump,
|
|
||||||
assign_to: Symbol,
|
|
||||||
erased_function: Symbol,
|
|
||||||
fn_ptr_layout: InLayout<'a>,
|
|
||||||
) -> impl FnOnce(Stmt<'a>) -> Stmt<'a> {
|
|
||||||
move |rest| {
|
|
||||||
Stmt::Let(
|
|
||||||
assign_to,
|
|
||||||
Expr::Call(Call {
|
|
||||||
call_type: CallType::LowLevel {
|
|
||||||
op: LowLevel::PtrCast,
|
|
||||||
update_mode: UpdateModeId::BACKEND_DUMMY,
|
|
||||||
},
|
|
||||||
arguments: arena.alloc([erased_function]),
|
|
||||||
}),
|
|
||||||
fn_ptr_layout,
|
|
||||||
arena.alloc(rest),
|
arena.alloc(rest),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -83,13 +62,14 @@ fn is_null<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
assign_to: Symbol,
|
assign_to: Symbol,
|
||||||
ptr_symbol: Symbol,
|
ptr_symbol: Symbol,
|
||||||
|
layout: InLayout<'a>,
|
||||||
) -> impl FnOnce(Stmt<'a>) -> Stmt<'a> {
|
) -> impl FnOnce(Stmt<'a>) -> Stmt<'a> {
|
||||||
let null_symbol = env.unique_symbol();
|
let null_symbol = env.unique_symbol();
|
||||||
move |rest| {
|
move |rest| {
|
||||||
Stmt::Let(
|
Stmt::Let(
|
||||||
null_symbol,
|
null_symbol,
|
||||||
Expr::NullPointer,
|
Expr::NullPointer,
|
||||||
Layout::OPAQUE_PTR,
|
layout,
|
||||||
arena.alloc(Stmt::Let(
|
arena.alloc(Stmt::Let(
|
||||||
assign_to,
|
assign_to,
|
||||||
Expr::Call(Call {
|
Expr::Call(Call {
|
||||||
|
@ -106,6 +86,39 @@ fn is_null<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct BuiltFunctionPointer<'a> {
|
||||||
|
function_pointer: InLayout<'a>,
|
||||||
|
reified_arguments: &'a [InLayout<'a>],
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_function_pointer<'a>(
|
||||||
|
arena: &'a Bump,
|
||||||
|
layout_cache: &mut LayoutCache<'a>,
|
||||||
|
argument_layouts: &'a [InLayout<'a>],
|
||||||
|
return_layout: InLayout<'a>,
|
||||||
|
pass_closure: bool,
|
||||||
|
) -> BuiltFunctionPointer<'a> {
|
||||||
|
let reified_arguments = if pass_closure {
|
||||||
|
let mut args = AVec::with_capacity_in(argument_layouts.len() + 1, arena);
|
||||||
|
args.extend(argument_layouts.iter().chain(&[Layout::ERASED]).copied());
|
||||||
|
args.into_bump_slice()
|
||||||
|
} else {
|
||||||
|
argument_layouts
|
||||||
|
};
|
||||||
|
|
||||||
|
let fn_ptr_layout = LayoutRepr::FunctionPointer(FunctionPointer {
|
||||||
|
args: reified_arguments,
|
||||||
|
ret: return_layout,
|
||||||
|
});
|
||||||
|
|
||||||
|
let function_pointer = layout_cache.put_in_direct_no_semantic(fn_ptr_layout);
|
||||||
|
|
||||||
|
BuiltFunctionPointer {
|
||||||
|
function_pointer,
|
||||||
|
reified_arguments,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Given
|
/// Given
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -118,7 +131,7 @@ fn is_null<'a>(
|
||||||
/// f = compile(f)
|
/// f = compile(f)
|
||||||
/// joinpoint join result:
|
/// joinpoint join result:
|
||||||
/// <hole>
|
/// <hole>
|
||||||
/// f_value: Ptr<[]> = ErasedLoad(f, .value)
|
/// f_value: Box<[]> = ErasedLoad(f, .value)
|
||||||
/// f_callee: Ptr<[]> = ErasedLoad(f, .callee)
|
/// f_callee: Ptr<[]> = ErasedLoad(f, .callee)
|
||||||
/// if (f_value != nullptr) {
|
/// if (f_value != nullptr) {
|
||||||
/// f_callee = Cast(f_callee, (..params, Erased) -> ret);
|
/// f_callee = Cast(f_callee, (..params, Erased) -> ret);
|
||||||
|
@ -151,55 +164,44 @@ pub fn call_erased_function<'a>(
|
||||||
|
|
||||||
// f_value = ErasedLoad(f, .value)
|
// f_value = ErasedLoad(f, .value)
|
||||||
let f_value = env.unique_symbol();
|
let f_value = env.unique_symbol();
|
||||||
let let_f_value = index_erased_function(arena, f_value, f, ErasedField::Value);
|
let let_f_value =
|
||||||
|
index_erased_function(arena, f_value, f, ErasedField::Value, Layout::OPAQUE_PTR);
|
||||||
// f_callee = ErasedLoad(f, .callee)
|
|
||||||
let f_callee = env.unique_symbol();
|
|
||||||
let let_f_callee = index_erased_function(arena, f_callee, f, ErasedField::Callee);
|
|
||||||
|
|
||||||
let mut build_closure_data_branch = |env: &mut Env, pass_closure| {
|
let mut build_closure_data_branch = |env: &mut Env, pass_closure| {
|
||||||
// f_callee = Cast(f_callee, (..params) -> ret);
|
// f_callee = Cast(f_callee, (..params) -> ret);
|
||||||
// result = f_callee ..args
|
// result = f_callee ..args
|
||||||
// jump join result
|
// jump join result
|
||||||
|
|
||||||
let (f_args, function_argument_symbols) = if pass_closure {
|
let BuiltFunctionPointer {
|
||||||
// f_args = ...args, f
|
function_pointer,
|
||||||
|
reified_arguments: f_args,
|
||||||
|
} = build_function_pointer(arena, layout_cache, f_args, f_ret, pass_closure);
|
||||||
|
|
||||||
|
// f_callee = ErasedLoad(f, .callee)
|
||||||
|
let f_callee = env.unique_symbol();
|
||||||
|
let let_f_callee =
|
||||||
|
index_erased_function(arena, f_callee, f, ErasedField::Callee, function_pointer);
|
||||||
|
|
||||||
|
let function_argument_symbols = if pass_closure {
|
||||||
// function_argument_symbols = ...args, f.value
|
// function_argument_symbols = ...args, f.value
|
||||||
let f_args = {
|
let mut args = AVec::with_capacity_in(function_argument_symbols.len() + 1, arena);
|
||||||
let mut args = AVec::with_capacity_in(f_args.len() + 1, arena);
|
args.extend(function_argument_symbols.iter().chain(&[f]));
|
||||||
args.extend(f_args.iter().chain(&[Layout::ERASED]).copied());
|
args.into_bump_slice()
|
||||||
args.into_bump_slice()
|
|
||||||
};
|
|
||||||
let function_argument_symbols = {
|
|
||||||
let mut args = AVec::with_capacity_in(function_argument_symbols.len() + 1, arena);
|
|
||||||
args.extend(function_argument_symbols.iter().chain(&[f]));
|
|
||||||
args.into_bump_slice()
|
|
||||||
};
|
|
||||||
(f_args, function_argument_symbols)
|
|
||||||
} else {
|
} else {
|
||||||
(f_args, function_argument_symbols)
|
function_argument_symbols
|
||||||
};
|
};
|
||||||
|
|
||||||
let fn_ptr_layout =
|
|
||||||
layout_cache.put_in_direct_no_semantic(LayoutRepr::FunctionPointer(FunctionPointer {
|
|
||||||
args: f_args,
|
|
||||||
ret: f_ret,
|
|
||||||
}));
|
|
||||||
|
|
||||||
let f_callee_cast = env.unique_symbol();
|
|
||||||
let let_f_callee_cast = cast_erased_callee(arena, f_callee_cast, f_callee, fn_ptr_layout);
|
|
||||||
|
|
||||||
let result = env.unique_symbol();
|
let result = env.unique_symbol();
|
||||||
let let_result = call_callee(
|
let let_result = call_callee(
|
||||||
arena,
|
arena,
|
||||||
result,
|
result,
|
||||||
f_ret,
|
f_ret,
|
||||||
f_callee_cast,
|
f_callee,
|
||||||
f_args,
|
f_args,
|
||||||
function_argument_symbols,
|
function_argument_symbols,
|
||||||
);
|
);
|
||||||
|
|
||||||
let_f_callee_cast(
|
let_f_callee(
|
||||||
//
|
//
|
||||||
let_result(
|
let_result(
|
||||||
//
|
//
|
||||||
|
@ -209,7 +211,7 @@ pub fn call_erased_function<'a>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let value_is_null = env.unique_symbol();
|
let value_is_null = env.unique_symbol();
|
||||||
let let_value_is_null = is_null(env, arena, value_is_null, f_value);
|
let let_value_is_null = is_null(env, arena, value_is_null, f_value, Layout::OPAQUE_PTR);
|
||||||
|
|
||||||
let call_and_jump_on_value = let_value_is_null(
|
let call_and_jump_on_value = let_value_is_null(
|
||||||
//
|
//
|
||||||
|
@ -234,14 +236,10 @@ pub fn call_erased_function<'a>(
|
||||||
ownership: Ownership::Owned,
|
ownership: Ownership::Owned,
|
||||||
};
|
};
|
||||||
|
|
||||||
let remainder =
|
let remainder = let_f_value(
|
||||||
// f_value = ErasedLoad(f, .value)
|
// f_value = ErasedLoad(f, .value)
|
||||||
let_f_value(
|
// <rest>
|
||||||
// f_callee = ErasedLoad(f, .callee)
|
call_and_jump_on_value,
|
||||||
let_f_callee(
|
|
||||||
//
|
|
||||||
call_and_jump_on_value,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Stmt::Join {
|
Stmt::Join {
|
||||||
|
@ -273,8 +271,7 @@ pub fn call_erased_function<'a>(
|
||||||
/// We generate
|
/// We generate
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// boxed_value = Expr::Box({s})
|
/// value = Expr::Box({s})
|
||||||
/// stack_value: Ptr<[]> = Cast(boxed_value, Ptr<[]>)
|
|
||||||
/// callee = Expr::FunctionPointer(f)
|
/// callee = Expr::FunctionPointer(f)
|
||||||
/// f = Expr::ErasedMake({ value, callee })
|
/// f = Expr::ErasedMake({ value, callee })
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -301,6 +298,8 @@ pub fn build_erased_function<'a>(
|
||||||
let ResolvedErasedLambda {
|
let ResolvedErasedLambda {
|
||||||
captures,
|
captures,
|
||||||
lambda_name,
|
lambda_name,
|
||||||
|
arguments,
|
||||||
|
ret,
|
||||||
} = resolved_lambda;
|
} = resolved_lambda;
|
||||||
|
|
||||||
let value = match captures {
|
let value = match captures {
|
||||||
|
@ -319,11 +318,16 @@ pub fn build_erased_function<'a>(
|
||||||
hole,
|
hole,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let BuiltFunctionPointer {
|
||||||
|
function_pointer,
|
||||||
|
reified_arguments: _,
|
||||||
|
} = build_function_pointer(env.arena, layout_cache, arguments, ret, captures.is_some());
|
||||||
|
|
||||||
// callee = Expr::FunctionPointer(f)
|
// callee = Expr::FunctionPointer(f)
|
||||||
let result = Stmt::Let(
|
let result = Stmt::Let(
|
||||||
callee,
|
callee,
|
||||||
Expr::FunctionPointer { lambda_name },
|
Expr::FunctionPointer { lambda_name },
|
||||||
Layout::OPAQUE_PTR,
|
function_pointer,
|
||||||
env.arena.alloc(result),
|
env.arena.alloc(result),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -340,25 +344,11 @@ pub fn build_erased_function<'a>(
|
||||||
let stack_captures_layout =
|
let stack_captures_layout =
|
||||||
layout_cache.put_in_direct_no_semantic(LayoutRepr::Struct(layouts));
|
layout_cache.put_in_direct_no_semantic(LayoutRepr::Struct(layouts));
|
||||||
|
|
||||||
let boxed_captures = env.unique_symbol();
|
|
||||||
let boxed_captures_layout =
|
let boxed_captures_layout =
|
||||||
layout_cache.put_in_direct_no_semantic(LayoutRepr::Boxed(stack_captures_layout));
|
layout_cache.put_in_direct_no_semantic(LayoutRepr::Boxed(stack_captures_layout));
|
||||||
|
|
||||||
let result = Stmt::Let(
|
let result = Stmt::Let(
|
||||||
value.unwrap(),
|
value.unwrap(),
|
||||||
Expr::Call(Call {
|
|
||||||
call_type: CallType::LowLevel {
|
|
||||||
op: LowLevel::PtrCast,
|
|
||||||
update_mode: UpdateModeId::BACKEND_DUMMY,
|
|
||||||
},
|
|
||||||
arguments: env.arena.alloc([boxed_captures]),
|
|
||||||
}),
|
|
||||||
Layout::OPAQUE_PTR,
|
|
||||||
env.arena.alloc(result),
|
|
||||||
);
|
|
||||||
|
|
||||||
let result = Stmt::Let(
|
|
||||||
boxed_captures,
|
|
||||||
Expr::ExprBox {
|
Expr::ExprBox {
|
||||||
symbol: stack_captures,
|
symbol: stack_captures,
|
||||||
},
|
},
|
||||||
|
@ -386,6 +376,8 @@ struct ResolvedErasedCaptures<'a> {
|
||||||
pub struct ResolvedErasedLambda<'a> {
|
pub struct ResolvedErasedLambda<'a> {
|
||||||
captures: Option<ResolvedErasedCaptures<'a>>,
|
captures: Option<ResolvedErasedCaptures<'a>>,
|
||||||
lambda_name: LambdaName<'a>,
|
lambda_name: LambdaName<'a>,
|
||||||
|
arguments: &'a [InLayout<'a>],
|
||||||
|
ret: InLayout<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ResolvedErasedLambda<'a> {
|
impl<'a> ResolvedErasedLambda<'a> {
|
||||||
|
@ -394,6 +386,8 @@ impl<'a> ResolvedErasedLambda<'a> {
|
||||||
layout_cache: &mut LayoutCache<'a>,
|
layout_cache: &mut LayoutCache<'a>,
|
||||||
lambda_symbol: Symbol,
|
lambda_symbol: Symbol,
|
||||||
captures: CapturedSymbols<'a>,
|
captures: CapturedSymbols<'a>,
|
||||||
|
arguments: &'a [InLayout<'a>],
|
||||||
|
ret: InLayout<'a>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let resolved_captures;
|
let resolved_captures;
|
||||||
let lambda_name;
|
let lambda_name;
|
||||||
|
@ -422,6 +416,8 @@ impl<'a> ResolvedErasedLambda<'a> {
|
||||||
Self {
|
Self {
|
||||||
captures: resolved_captures,
|
captures: resolved_captures,
|
||||||
lambda_name,
|
lambda_name,
|
||||||
|
arguments,
|
||||||
|
ret,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,7 +450,6 @@ pub fn unpack_closure_data<'a>(
|
||||||
captures: &[(Symbol, Variable)],
|
captures: &[(Symbol, Variable)],
|
||||||
mut hole: Stmt<'a>,
|
mut hole: Stmt<'a>,
|
||||||
) -> Stmt<'a> {
|
) -> Stmt<'a> {
|
||||||
let loaded_captures = env.unique_symbol();
|
|
||||||
let heap_captures = env.unique_symbol();
|
let heap_captures = env.unique_symbol();
|
||||||
let stack_captures = env.unique_symbol();
|
let stack_captures = env.unique_symbol();
|
||||||
|
|
||||||
|
@ -494,24 +489,12 @@ pub fn unpack_closure_data<'a>(
|
||||||
env.arena.alloc(hole),
|
env.arena.alloc(hole),
|
||||||
);
|
);
|
||||||
|
|
||||||
hole = Stmt::Let(
|
|
||||||
heap_captures,
|
|
||||||
Expr::Call(Call {
|
|
||||||
call_type: CallType::LowLevel {
|
|
||||||
op: LowLevel::PtrCast,
|
|
||||||
update_mode: UpdateModeId::BACKEND_DUMMY,
|
|
||||||
},
|
|
||||||
arguments: env.arena.alloc([captures_symbol]),
|
|
||||||
}),
|
|
||||||
heap_captures_layout,
|
|
||||||
env.arena.alloc(hole),
|
|
||||||
);
|
|
||||||
|
|
||||||
let let_loaded_captures = index_erased_function(
|
let let_loaded_captures = index_erased_function(
|
||||||
env.arena,
|
env.arena,
|
||||||
loaded_captures,
|
heap_captures,
|
||||||
captures_symbol,
|
captures_symbol,
|
||||||
ErasedField::Value,
|
ErasedField::Value,
|
||||||
|
heap_captures_layout,
|
||||||
);
|
);
|
||||||
|
|
||||||
let_loaded_captures(hole)
|
let_loaded_captures(hole)
|
||||||
|
|
|
@ -722,9 +722,9 @@ impl<'a> FunctionPointer<'a> {
|
||||||
let ret = interner.to_doc(ret, alloc, seen_rec, parens);
|
let ret = interner.to_doc(ret, alloc, seen_rec, parens);
|
||||||
|
|
||||||
alloc
|
alloc
|
||||||
.text("FunPtr(")
|
.text("FunPtr((")
|
||||||
.append(args)
|
.append(args)
|
||||||
.append(alloc.text(" -> "))
|
.append(alloc.text(") -> "))
|
||||||
.append(ret)
|
.append(ret)
|
||||||
.append(")")
|
.append(")")
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,92 +18,82 @@ procedure Bool.2 ():
|
||||||
ret Bool.23;
|
ret Bool.23;
|
||||||
|
|
||||||
procedure Test.1 (Test.2):
|
procedure Test.1 (Test.2):
|
||||||
let Test.38 : Int1 = CallByName Bool.2;
|
let Test.34 : Int1 = CallByName Bool.2;
|
||||||
if Test.38 then
|
if Test.34 then
|
||||||
dec Test.2;
|
dec Test.2;
|
||||||
let Test.44 : {} = Struct {};
|
let Test.40 : {} = Struct {};
|
||||||
let Test.45 : Boxed({}) = Box Test.44;
|
let Test.38 : Boxed({}) = Box Test.40;
|
||||||
let Test.42 : Boxed([]) = lowlevel PtrCast Test.45;
|
let Test.39 : FunPtr(({}, ?Erased) -> Str) = FunctionPointer Test.3;
|
||||||
let Test.43 : Boxed([]) = FunctionPointer Test.3;
|
let Test.35 : ?Erased = ErasedMake { value: Test.38, callee: Test.39 };
|
||||||
dec Test.43;
|
ret Test.35;
|
||||||
let Test.39 : ?Erased = ErasedMake { value: Test.42, callee: Test.43 };
|
|
||||||
ret Test.39;
|
|
||||||
else
|
else
|
||||||
let Test.36 : {Str} = Struct {Test.2};
|
let Test.33 : {Str} = Struct {Test.2};
|
||||||
let Test.37 : Boxed({Str}) = Box Test.36;
|
let Test.31 : Boxed({Str}) = Box Test.33;
|
||||||
let Test.34 : Boxed([]) = lowlevel PtrCast Test.37;
|
let Test.32 : FunPtr(({}, ?Erased) -> Str) = FunctionPointer Test.4;
|
||||||
let Test.35 : Boxed([]) = FunctionPointer Test.4;
|
let Test.26 : ?Erased = ErasedMake { value: Test.31, callee: Test.32 };
|
||||||
dec Test.35;
|
ret Test.26;
|
||||||
let Test.28 : ?Erased = ErasedMake { value: Test.34, callee: Test.35 };
|
|
||||||
ret Test.28;
|
|
||||||
|
|
||||||
procedure Test.3 (Test.40):
|
procedure Test.3 (Test.36):
|
||||||
let Test.41 : Str = "";
|
let Test.37 : Str = "";
|
||||||
ret Test.41;
|
ret Test.37;
|
||||||
|
|
||||||
procedure Test.4 (Test.29, #Attr.12):
|
procedure Test.4 (Test.27, #Attr.12):
|
||||||
inc #Attr.12;
|
let Test.29 : Boxed({Str}) = ErasedLoad #Attr.12 .Value;
|
||||||
let Test.31 : Boxed([]) = ErasedLoad #Attr.12 .Value;
|
let Test.30 : {Str} = Unbox Test.29;
|
||||||
dec Test.31;
|
|
||||||
let Test.32 : Boxed({Str}) = lowlevel PtrCast #Attr.12;
|
|
||||||
let Test.33 : {Str} = Unbox Test.32;
|
|
||||||
joinpoint #Derived_gen.0:
|
joinpoint #Derived_gen.0:
|
||||||
let Test.2 : Str = StructAtIndex 0 Test.33;
|
let Test.2 : Str = StructAtIndex 0 Test.30;
|
||||||
ret Test.2;
|
ret Test.2;
|
||||||
in
|
in
|
||||||
let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.32;
|
let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.29;
|
||||||
if #Derived_gen.1 then
|
if #Derived_gen.1 then
|
||||||
free Test.32;
|
free Test.29;
|
||||||
jump #Derived_gen.0;
|
jump #Derived_gen.0;
|
||||||
else
|
else
|
||||||
inc Test.33;
|
inc Test.30;
|
||||||
decref Test.32;
|
decref Test.29;
|
||||||
jump #Derived_gen.0;
|
jump #Derived_gen.0;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.6 : {} = Struct {};
|
let Test.6 : {} = Struct {};
|
||||||
let Test.17 : Str = "";
|
let Test.16 : Str = "";
|
||||||
let Test.46 : Boxed([]) = FunctionPointer Test.1;
|
let Test.41 : FunPtr((Str) -> ?Erased) = FunctionPointer Test.1;
|
||||||
dec Test.46;
|
let Test.17 : ?Erased = ErasedMake { value: <null>, callee: Test.41 };
|
||||||
let Test.18 : ?Erased = ErasedMake { value: <null>, callee: Test.46 };
|
joinpoint Test.18 Test.7:
|
||||||
joinpoint Test.19 Test.7:
|
|
||||||
joinpoint Test.8 Test.5:
|
joinpoint Test.8 Test.5:
|
||||||
ret Test.5;
|
ret Test.5;
|
||||||
in
|
in
|
||||||
let Test.9 : Boxed([]) = ErasedLoad Test.7 .Value;
|
let Test.9 : Boxed([]) = ErasedLoad Test.7 .Value;
|
||||||
let Test.10 : Boxed([]) = ErasedLoad Test.7 .Callee;
|
let Test.11 : Boxed([]) = NullPointer;
|
||||||
let Test.12 : Boxed([]) = NullPointer;
|
let Test.10 : Int1 = lowlevel Eq Test.9 Test.11;
|
||||||
let Test.11 : Int1 = lowlevel Eq Test.9 Test.12;
|
dec Test.11;
|
||||||
dec Test.12;
|
|
||||||
dec Test.9;
|
dec Test.9;
|
||||||
switch Test.11:
|
switch Test.10:
|
||||||
case 0:
|
case 0:
|
||||||
let Test.13 : FunPtr({} -> Str) = lowlevel PtrCast Test.10;
|
let Test.12 : FunPtr(({}) -> Str) = ErasedLoad Test.7 .Callee;
|
||||||
let Test.14 : Str = CallByPtr Test.13 Test.6;
|
let Test.13 : Str = CallByPtr Test.12 Test.6;
|
||||||
jump Test.8 Test.14;
|
jump Test.8 Test.13;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
inc Test.7;
|
inc Test.7;
|
||||||
let Test.15 : FunPtr({}, ?Erased -> Str) = lowlevel PtrCast Test.10;
|
let Test.14 : FunPtr(({}, ?Erased) -> Str) = ErasedLoad Test.7 .Callee;
|
||||||
let Test.16 : Str = CallByPtr Test.15 Test.6 Test.7;
|
let Test.15 : Str = CallByPtr Test.14 Test.6 Test.7;
|
||||||
jump Test.8 Test.16;
|
jump Test.8 Test.15;
|
||||||
|
|
||||||
in
|
in
|
||||||
let Test.20 : Boxed([]) = ErasedLoad Test.18 .Value;
|
let Test.19 : Boxed([]) = ErasedLoad Test.17 .Value;
|
||||||
let Test.21 : Boxed([]) = ErasedLoad Test.18 .Callee;
|
let Test.21 : Boxed([]) = NullPointer;
|
||||||
let Test.23 : Boxed([]) = NullPointer;
|
let Test.20 : Int1 = lowlevel Eq Test.19 Test.21;
|
||||||
let Test.22 : Int1 = lowlevel Eq Test.20 Test.23;
|
dec Test.21;
|
||||||
dec Test.20;
|
dec Test.19;
|
||||||
dec Test.23;
|
switch Test.20:
|
||||||
switch Test.22:
|
|
||||||
case 0:
|
case 0:
|
||||||
let Test.24 : FunPtr(Str -> ?Erased) = lowlevel PtrCast Test.21;
|
let Test.22 : FunPtr((Str) -> ?Erased) = ErasedLoad Test.17 .Callee;
|
||||||
let Test.25 : ?Erased = CallByPtr Test.24 Test.17;
|
let Test.23 : ?Erased = CallByPtr Test.22 Test.16;
|
||||||
jump Test.19 Test.25;
|
jump Test.18 Test.23;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
inc Test.18;
|
inc Test.17;
|
||||||
let Test.26 : FunPtr(Str, ?Erased -> ?Erased) = lowlevel PtrCast Test.21;
|
let Test.24 : FunPtr((Str, ?Erased) -> ?Erased) = ErasedLoad Test.17 .Callee;
|
||||||
let Test.27 : ?Erased = CallByPtr Test.26 Test.17 Test.18;
|
let Test.25 : ?Erased = CallByPtr Test.24 Test.16 Test.17;
|
||||||
jump Test.19 Test.27;
|
jump Test.18 Test.25;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue