This commit is contained in:
Folkert 2021-11-27 16:36:43 +01:00
parent a1fd34feef
commit 79d5c82dfb
12 changed files with 186 additions and 70 deletions

View file

@ -55,7 +55,7 @@ pub fn func_name_bytes_help<'a, I>(
return_layout: &Layout<'a>,
) -> [u8; SIZE]
where
I: Iterator<Item = Layout<'a>>,
I: IntoIterator<Item = Layout<'a>>,
{
let mut name_bytes = [0u8; SIZE];
@ -166,8 +166,8 @@ where
host_exposed_functions.push((bytes, top_level.arguments));
}
RawFunctionLayout::ZeroArgumentThunk(_) => {
let it = std::iter::once(Layout::Struct(&[]));
let bytes = func_name_bytes_help(*symbol, it, &top_level.result);
let bytes =
func_name_bytes_help(*symbol, [Layout::UNIT], &top_level.result);
host_exposed_functions.push((bytes, top_level.arguments));
}
@ -578,18 +578,25 @@ impl KeepResult {
#[derive(Clone, Copy)]
enum ResultRepr<'a> {
Int1,
NonRecursive { err: Layout<'a>, ok: Layout<'a> },
/// This is basically a `Result * whatever` or `Result [] whatever` (in keepOks, arguments flipped for keepErrs).
/// Such a `Result` gets a `Bool` layout at currently. We model the `*` or `[]` as a unit
/// (empty tuple) in morphic, otherwise we run into trouble when we need to crate a value of
/// type void
ResultStarStar,
ResultConcrete {
err: Layout<'a>,
ok: Layout<'a>,
},
}
impl<'a> ResultRepr<'a> {
fn from_layout(layout: &Layout<'a>) -> Self {
match layout {
Layout::Union(UnionLayout::NonRecursive(tags)) => ResultRepr::NonRecursive {
Layout::Union(UnionLayout::NonRecursive(tags)) => ResultRepr::ResultConcrete {
err: tags[ERR_TAG_ID as usize][0],
ok: tags[OK_TAG_ID as usize][0],
},
Layout::Builtin(Builtin::Bool) => ResultRepr::Int1,
Layout::Builtin(Builtin::Bool) => ResultRepr::ResultStarStar,
other => unreachable!("unexpected layout: {:?}", other),
}
}
@ -602,12 +609,16 @@ impl<'a> ResultRepr<'a> {
keep_tag_id: u32,
) -> Result<ValueId> {
match self {
ResultRepr::NonRecursive { .. } => {
ResultRepr::ResultConcrete { .. } => {
let unwrapped = builder.add_unwrap_union(block, err_or_ok, keep_tag_id)?;
builder.add_get_tuple_field(block, unwrapped, 0)
}
ResultRepr::Int1 => builder.add_make_tuple(block, &[]),
ResultRepr::ResultStarStar => {
// Void/EmptyTagUnion is represented as a unit value in morphic
// using `union {}` runs into trouble where we have to crate a value of that type
builder.add_make_tuple(block, &[])
}
}
}
}
@ -1010,9 +1021,14 @@ fn call_spec(
let result_repr = ResultRepr::from_layout(ret_layout);
let output_element_layout = match (keep_result, result_repr) {
(KeepResult::Errs, ResultRepr::NonRecursive { err, .. }) => err,
(KeepResult::Oks, ResultRepr::NonRecursive { ok, .. }) => ok,
(_, ResultRepr::Int1) => Layout::Struct(&[]),
(KeepResult::Errs, ResultRepr::ResultConcrete { err, .. }) => err,
(KeepResult::Oks, ResultRepr::ResultConcrete { ok, .. }) => ok,
(_, ResultRepr::ResultStarStar) => {
// we represent this case as Unit, while Void is maybe more natural
// but using Void we'd need to crate values of type Void, which is not
// possible
Layout::UNIT
}
};
let loop_body = |builder: &mut FuncDefBuilder, block, state| {
@ -1661,6 +1677,12 @@ fn layout_spec_help(
let variant_types = build_variant_types(builder, union_layout)?;
match union_layout {
UnionLayout::NonRecursive(&[]) => {
// must model Void as Unit, otherwise we run into problems where
// we have to construct values of the void type,
// which is of course not possible
builder.add_tuple_type(&[])
}
UnionLayout::NonRecursive(_) => builder.add_union_type(&variant_types),
UnionLayout::Recursive(_)
| UnionLayout::NullableUnwrapped { .. }