fix for when C has to return an empty tag union

This commit is contained in:
Folkert 2023-02-15 15:17:29 +01:00
parent b6bae82913
commit edf557e480
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
2 changed files with 24 additions and 7 deletions

View file

@ -3959,22 +3959,35 @@ fn expose_function_to_host_help_c_abi_v2<'a, 'ctx, 'env>(
(RocReturn::ByPointer, CCReturn::Return) => {
// Roc currently puts the return pointer at the end of the argument list.
// As such, we drop the last element here instead of the first.
(&params[..], &param_types[..param_types.len() - 1])
(
&params[..],
&param_types[..param_types.len().saturating_sub(1)],
)
}
// Drop the return pointer the other way, if the C function returns by pointer but Roc
// doesn't
(RocReturn::Return, CCReturn::ByPointer) => (&params[1..], &param_types[..]),
(RocReturn::ByPointer, CCReturn::ByPointer) => {
// Both return by pointer but Roc puts it at the end and C puts it at the beginning
(&params[1..], &param_types[..param_types.len() - 1])
(
&params[1..],
&param_types[..param_types.len().saturating_sub(1)],
)
}
(RocReturn::Return | RocReturn::ByPointer, CCReturn::Void) => {
// the roc function returns a unit value. like `{}` or `{ { {}, {} }, {} }`.
// In C, this is modelled as a function returning void
(
&params[..],
&param_types[..param_types.len().saturating_sub(1)],
)
}
_ => (&params[..], &param_types[..]),
};
dbg!(&params, &param_types);
debug_assert!(
params.len() == param_types.len(),
debug_assert_eq!(
params.len(),
param_types.len(),
"when exposing a function to the host, params.len() was {}, but param_types.len() was {}",
params.len(),
param_types.len()
@ -5729,6 +5742,8 @@ impl<'ctx> FunctionSpec<'ctx> {
(return_type.unwrap().fn_type(&arguments, false), None)
}
CCReturn::Void => {
// NOTE: there may be a valid return type, but it is zero-sized.
// for instance just `{}` or something more complex like `{ { {}, {} }, {} }`
let arguments = function_arguments(env, argument_types);
(env.context.void_type().fn_type(&arguments, false), None)
}

View file

@ -65,6 +65,7 @@ pub fn struct_type_from_union_layout<'a, 'ctx, 'env>(
use UnionLayout::*;
match union_layout {
NonRecursive([]) => env.context.struct_type(&[], false),
NonRecursive(tags) => {
RocUnion::tagged_from_slices(layout_interner, env.context, tags, env.target_info)
.struct_type()
@ -300,7 +301,8 @@ impl<'ctx> RocUnion<'ctx> {
target_info: TargetInfo,
) -> Self {
let tag_type = match layouts.len() {
0..=255 => TagType::I8,
0 => unreachable!("zero-element tag union is not represented as a RocUnion"),
1..=255 => TagType::I8,
_ => TagType::I16,
};