diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 3fb3e81adf..f8a16ea1c6 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -3183,8 +3183,7 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>( builder.position_at_end(entry); - let elements = [Layout::Builtin(Builtin::Int64), return_layout]; - let wrapped_layout = Layout::Struct(&elements); + let wrapped_layout = roc_result_layout(env.arena, return_layout); call_roc_function(env, roc_function, &wrapped_layout, arguments_for_call) } else { call_roc_function(env, roc_function, &return_layout, arguments_for_call) @@ -3212,18 +3211,11 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>( return_layout: Layout<'a>, c_function_name: &str, ) -> FunctionValue<'ctx> { - let context = env.context; - // a tagged union to indicate to the test loader that a panic occurred. // especially when running 32-bit binaries on a 64-bit machine, there // does not seem to be a smarter solution - let wrapper_return_type = context.struct_type( - &[ - context.i64_type().into(), - roc_function.get_type().get_return_type().unwrap(), - ], - false, - ); + let wrapper_return_type = + roc_result_type(env, roc_function.get_type().get_return_type().unwrap()); let mut cc_argument_types = Vec::with_capacity_in(arguments.len(), env.arena); for layout in arguments { @@ -3346,8 +3338,6 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>( return_layout: Layout<'a>, c_function_name: &str, ) -> FunctionValue<'ctx> { - let context = env.context; - if env.is_gen_test { return expose_function_to_host_help_c_abi_gen_test( env, @@ -3369,15 +3359,7 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>( ); let wrapper_return_type = if env.is_gen_test { - context - .struct_type( - &[ - context.i64_type().into(), - roc_function.get_type().get_return_type().unwrap(), - ], - false, - ) - .into() + roc_result_type(env, roc_function.get_type().get_return_type().unwrap()).into() } else { roc_function.get_type().get_return_type().unwrap() }; @@ -3542,11 +3524,7 @@ where let context = env.context; let builder = env.builder; - let call_result_type = context.struct_type( - &[context.i64_type().into(), return_type.as_basic_type_enum()], - false, - ); - + let call_result_type = roc_result_type(env, return_type.as_basic_type_enum()); let result_alloca = builder.build_alloca(call_result_type, "result"); let then_block = context.append_basic_block(parent, "then_block"); @@ -3648,12 +3626,8 @@ where ptr_int }; - let u8_ptr = env.context.i8_type().ptr_type(AddressSpace::Generic); - let return_type = context.struct_type(&[context.i64_type().into(), u8_ptr.into()], false); - // let return_type = call_result_type; - let return_value = { - let v1 = return_type.const_zero(); + let v1 = call_result_type.const_zero(); // flag is non-zero, indicating failure let flag = context.i64_type().const_int(1, false); @@ -3668,17 +3642,7 @@ where v3 }; - // bitcast result alloca so we can store our concrete type { flag, error_msg } in there - let result_alloca_bitcast = builder - .build_bitcast( - result_alloca, - return_type.ptr_type(AddressSpace::Generic), - "result_alloca_bitcast", - ) - .into_pointer_value(); - - // store our return value - builder.build_store(result_alloca_bitcast, return_value); + builder.build_store(result_alloca, return_value); env.builder.build_unconditional_branch(cont_block); } @@ -3701,6 +3665,30 @@ fn make_exception_catcher<'a, 'ctx, 'env>( function_value } +fn roc_result_layout<'a>(arena: &'a Bump, return_layout: Layout<'a>) -> Layout<'a> { + let elements = [ + Layout::Builtin(Builtin::Int64), + Layout::Builtin(Builtin::Usize), + return_layout, + ]; + + Layout::Struct(arena.alloc(elements)) +} + +fn roc_result_type<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + return_type: BasicTypeEnum<'ctx>, +) -> StructType<'ctx> { + env.context.struct_type( + &[ + env.context.i64_type().into(), + env.context.i8_type().ptr_type(AddressSpace::Generic).into(), + return_type, + ], + false, + ) +} + fn make_good_roc_result<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, return_value: BasicValueEnum<'ctx>, @@ -3708,18 +3696,14 @@ fn make_good_roc_result<'a, 'ctx, 'env>( let context = env.context; let builder = env.builder; - let content_type = return_value.get_type(); - let wrapper_return_type = - context.struct_type(&[context.i64_type().into(), content_type], false); - - let v1 = wrapper_return_type.const_zero(); + let v1 = roc_result_type(env, return_value.get_type()).const_zero(); let v2 = builder .build_insert_value(v1, context.i64_type().const_zero(), 0, "set_no_error") .unwrap(); let v3 = builder - .build_insert_value(v2, return_value, 1, "set_call_result") + .build_insert_value(v2, return_value, 2, "set_call_result") .unwrap(); v3.into_struct_value().into() @@ -3738,13 +3722,8 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>( let roc_function_type = roc_function.get_type(); let argument_types = roc_function_type.get_param_types(); - let wrapper_return_type = context.struct_type( - &[ - context.i64_type().into(), - roc_function.get_type().get_return_type().unwrap(), - ], - false, - ); + let wrapper_return_type = + roc_result_type(env, roc_function.get_type().get_return_type().unwrap()); // argument_types.push(wrapper_return_type.ptr_type(AddressSpace::Generic).into()); diff --git a/compiler/gen_llvm/src/run_roc.rs b/compiler/gen_llvm/src/run_roc.rs index 884ef41fcc..cb877c6495 100644 --- a/compiler/gen_llvm/src/run_roc.rs +++ b/compiler/gen_llvm/src/run_roc.rs @@ -1,22 +1,23 @@ use std::ffi::CString; +use std::mem::MaybeUninit; use std::os::raw::c_char; -use RocCallResult::*; /// This must have the same size as the repr() of RocCallResult! pub const ROC_CALL_RESULT_DISCRIMINANT_SIZE: usize = std::mem::size_of::(); -#[repr(u64)] -pub enum RocCallResult { - Success(T), - Failure(*mut c_char), +#[repr(C)] +pub struct RocCallResult { + tag: u64, + error_msg: *mut c_char, + value: MaybeUninit, } impl From> for Result { fn from(call_result: RocCallResult) -> Self { - match call_result { - Success(value) => Ok(value), - Failure(failure) => Err({ - let raw = unsafe { CString::from_raw(failure) }; + match call_result.tag { + 0 => Ok(unsafe { call_result.value.assume_init() }), + _ => Err({ + let raw = unsafe { CString::from_raw(call_result.error_msg) }; let result = format!("{:?}", raw); diff --git a/compiler/test_gen/src/gen_list.rs b/compiler/test_gen/src/gen_list.rs index 521a96db84..5e0f737e72 100644 --- a/compiler/test_gen/src/gen_list.rs +++ b/compiler/test_gen/src/gen_list.rs @@ -2341,7 +2341,7 @@ fn list_any() { #[test] #[cfg(any(feature = "gen-llvm"))] -#[ignore] +#[should_panic(expected = r#"Roc failed with message: "UnresolvedTypeVar"#)] fn list_any_empty_with_unknown_element_type() { // Segfaults with invalid memory reference. Running this as a stand-alone // Roc program, generates the following error message: