Expr::FunctionPointer

This commit is contained in:
Ayaz Hafiz 2023-06-25 18:46:08 -05:00
parent 55fa8098d3
commit cf30f02e01
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
11 changed files with 176 additions and 5 deletions

View file

@ -1521,6 +1521,7 @@ fn expr_spec<'a>(
let value = with_new_heap_cell(builder, block, union_data)?;
builder.add_make_named(block, MOD_APP, type_name, value)
}
FunctionPointer { .. } => todo_lambda_erasure!(),
RuntimeErrorFunction(_) => {
let type_id = layout_spec(env, builder, interner, interner.get_repr(layout))?;

View file

@ -176,6 +176,7 @@ impl<'a> LastSeenMap<'a> {
Expr::Reset { symbol, .. } | Expr::ResetRef { symbol, .. } => {
self.set_last_seen(*symbol, stmt);
}
Expr::FunctionPointer { .. } => todo_lambda_erasure!(),
Expr::EmptyArray => {}
Expr::RuntimeErrorFunction(_) => {}
}
@ -844,6 +845,17 @@ trait Backend<'a> {
Expr::NullPointer => {
self.load_literal_i64(sym, 0);
}
Expr::FunctionPointer { .. } => todo_lambda_erasure!(),
Expr::Reuse {
tag_layout,
tag_id,
symbol: reused,
arguments,
..
} => {
self.load_literal_symbols(arguments);
self.tag(sym, arguments, tag_layout, *tag_id, Some(*reused));
}
Expr::Reset { symbol, .. } => {
let layout = *self.layout_map().get(symbol).unwrap();

View file

@ -1090,6 +1090,44 @@ pub(crate) fn build_exp_expr<'a, 'ctx>(
)
}
ExprBox { symbol } => {
let (value, layout) = scope.load_symbol_and_layout(symbol);
let basic_type =
basic_type_from_layout(env, layout_interner, layout_interner.get_repr(layout));
let allocation = reserve_with_refcount_help(
env,
basic_type,
layout_interner.stack_size(layout),
layout_interner.alignment_bytes(layout),
);
store_roc_value(
env,
layout_interner,
layout_interner.get_repr(layout),
allocation,
value,
);
allocation.into()
}
ExprUnbox { symbol } => {
let value = scope.load_symbol(symbol);
debug_assert!(value.is_pointer_value());
load_roc_value(
env,
layout_interner,
layout_interner.get_repr(layout),
value.into_pointer_value(),
"load_boxed_value",
)
}
FunctionPointer { .. } => todo_lambda_erasure!(),
Reset {
symbol,
update_mode,

View file

@ -1136,6 +1136,20 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
storage,
),
Expr::ExprBox { symbol: arg_sym } => self.expr_box(sym, *arg_sym, layout, storage),
Expr::ExprUnbox { symbol: arg_sym } => self.expr_unbox(sym, *arg_sym),
Expr::FunctionPointer { .. } => todo_lambda_erasure!(),
Expr::Reuse {
tag_layout,
tag_id,
arguments,
symbol: reused,
..
} => self.expr_tag(tag_layout, *tag_id, arguments, sym, storage, Some(*reused)),
Expr::Reset { symbol: arg, .. } => self.expr_reset(*arg, sym, storage),
Expr::ResetRef { symbol: arg, .. } => self.expr_resetref(*arg, sym, storage),

View file

@ -719,7 +719,7 @@ impl<'a> BorrowInfState<'a> {
Call(call) => self.collect_call(interner, param_map, z, call),
Literal(_) | NullPointer | RuntimeErrorFunction(_) => {}
Literal(_) | NullPointer | RuntimeErrorFunction(_) | FunctionPointer { .. } => {}
StructAtIndex { structure: x, .. } => {
// if the structure (record/tag/array) is owned, the extracted value is

View file

@ -70,6 +70,9 @@ pub enum ProblemKind<'a> {
proc_layout: ProcLayout<'a>,
similar: Vec<ProcLayout<'a>>,
},
PtrToUndefinedProc {
symbol: Symbol,
},
DuplicateCallSpecId {
old_call_line: usize,
},
@ -464,6 +467,49 @@ impl<'a, 'r> Ctx<'a, 'r> {
// TODO don't know what the element layout is
None
}
&Expr::ExprBox { symbol } => self.with_sym_layout(symbol, |ctx, _def_line, layout| {
let inner = layout;
Some(
ctx.interner
.insert_direct_no_semantic(LayoutRepr::Boxed(inner)),
)
}),
&Expr::ExprUnbox { symbol } => self.with_sym_layout(symbol, |ctx, def_line, layout| {
let layout = ctx.resolve(layout);
match ctx.interner.get_repr(layout) {
LayoutRepr::Boxed(inner) => Some(inner),
_ => {
ctx.problem(ProblemKind::UnboxNotABox { symbol, def_line });
None
}
}
}),
&Expr::FunctionPointer { lambda_name } => {
let lambda_symbol = lambda_name.name();
if !self.procs.iter().any(|((name, proc), _)| {
*name == lambda_symbol && proc.niche == lambda_name.niche()
}) {
self.problem(ProblemKind::PtrToUndefinedProc {
symbol: lambda_symbol,
});
}
Some(Layout::OPAQUE_PTR)
}
&Expr::Reuse {
symbol,
update_tag_id: _,
update_mode: _,
tag_layout,
tag_id: _,
arguments: _,
} => {
let union = self
.interner
.insert_direct_no_semantic(LayoutRepr::Union(tag_layout));
self.check_sym_layout(symbol, union, UseKind::TagReuse);
// TODO also check update arguments
Some(union)
}
&Expr::Reset {
symbol,
update_mode: _,

View file

@ -265,6 +265,15 @@ where
};
stack(f, [no_spec_doc, similar_doc])
}
ProblemKind::PtrToUndefinedProc { symbol } => {
title = "PROC SPECIALIZATION NOT DEFINED";
docs_before = vec![];
f.concat([
f.reflow("The proc "),
format_symbol(f, interns, symbol),
f.reflow(" is not defined"),
])
}
ProblemKind::DuplicateCallSpecId { old_call_line } => {
title = "DUPLICATE CALL SPEC ID";
docs_before = vec![(old_call_line, f.reflow("This call has a specialization ID"))];

View file

@ -229,8 +229,11 @@ fn specialize_drops_stmt<'a, 'i>(
}
}
Reset { .. } | Expr::ResetRef { .. } => { /* do nothing */ }
RuntimeErrorFunction(_) | GetTagId { .. } | EmptyArray | NullPointer => { /* do nothing */
}
RuntimeErrorFunction(_)
| FunctionPointer { .. }
| GetTagId { .. }
| EmptyArray
| NullPointer => { /* do nothing */ }
}
// now store the let binding for later

View file

@ -872,7 +872,11 @@ fn insert_refcount_operations_binding<'a>(
}
match expr {
Expr::Literal(_) | Expr::NullPointer | Expr::EmptyArray | Expr::RuntimeErrorFunction(_) => {
Expr::Literal(_)
| Expr::NullPointer
| Expr::FunctionPointer { .. }
| Expr::EmptyArray
| Expr::RuntimeErrorFunction(_) => {
// Literals, empty arrays, and runtime errors are not (and have nothing) reference counted.
new_let!(stmt)
}

View file

@ -1885,6 +1885,28 @@ pub enum Expr<'a> {
},
EmptyArray,
ExprBox {
symbol: Symbol,
},
ExprUnbox {
symbol: Symbol,
},
/// Returns a pointer to the given function.
FunctionPointer {
lambda_name: LambdaName<'a>,
},
Reuse {
symbol: Symbol,
update_tag_id: bool,
update_mode: UpdateModeId,
// normal Tag fields
tag_layout: UnionLayout<'a>,
tag_id: TagIdIntType,
arguments: &'a [Symbol],
},
Reset {
symbol: Symbol,
update_mode: UpdateModeId,
@ -2066,6 +2088,18 @@ impl<'a> Expr<'a> {
.text("GetTagId ")
.append(symbol_to_doc(alloc, *structure, pretty)),
ExprBox { symbol, .. } => alloc
.text("Box ")
.append(symbol_to_doc(alloc, *symbol, pretty)),
ExprUnbox { symbol, .. } => alloc
.text("Unbox ")
.append(symbol_to_doc(alloc, *symbol, pretty)),
FunctionPointer { lambda_name } => alloc
.text("FunctionPointer ")
.append(symbol_to_doc(alloc, lambda_name.name(), pretty)),
UnionAtIndex {
tag_id,
structure,
@ -7706,6 +7740,16 @@ fn substitute_in_expr<'a>(
}
}
ExprBox { symbol } => {
substitute(subs, *symbol).map(|new_symbol| ExprBox { symbol: new_symbol })
}
ExprUnbox { symbol } => {
substitute(subs, *symbol).map(|new_symbol| ExprUnbox { symbol: new_symbol })
}
FunctionPointer { .. } => None,
StructAtIndex {
index,
structure,

View file

@ -1097,7 +1097,7 @@ fn expr_contains_symbol(expr: &Expr, needle: Symbol) -> bool {
Some(ru) => ru.symbol == needle || arguments.contains(&needle),
},
Expr::Struct(fields) => fields.contains(&needle),
Expr::NullPointer => false,
Expr::NullPointer | Expr::FunctionPointer { .. } => false,
Expr::StructAtIndex { structure, .. }
| Expr::GetTagId { structure, .. }
| Expr::UnionAtIndex { structure, .. }