diff --git a/crates/compiler/builtins/bitcode/src/expect.zig b/crates/compiler/builtins/bitcode/src/expect.zig deleted file mode 100644 index cc111b7005..0000000000 --- a/crates/compiler/builtins/bitcode/src/expect.zig +++ /dev/null @@ -1,134 +0,0 @@ -const std = @import("std"); -const utils = @import("utils.zig"); -const CSlice = utils.CSlice; -const always_inline = std.builtin.CallOptions.Modifier.always_inline; - -const Failure = struct { - start_line: u32, - end_line: u32, - start_col: u16, - end_col: u16, -}; - -// BEGIN FAILURES GLOBALS /////////////////// -var failures_mutex = std.Thread.Mutex{}; -var failures: [*]Failure = undefined; -var failure_length: usize = 0; -var failure_capacity: usize = 0; -// END FAILURES GLOBALS ///////////////////// - -pub fn expectFailed( - start_line: u32, - end_line: u32, - start_col: u16, - end_col: u16, -) void { - const new_failure = Failure{ .start_line = start_line, .end_line = end_line, .start_col = start_col, .end_col = end_col }; - - // Lock the failures mutex before reading from any of the failures globals, - // and then release the lock once we're done modifying things. - failures_mutex.lock(); - defer failures_mutex.unlock(); - - // If we don't have enough capacity to add a failure, allocate a new failures pointer. - if (failure_length >= failure_capacity) { - if (failure_capacity > 0) { - // We already had previous failures allocated, so try to realloc in order - // to grow the size in-place without having to memcpy bytes over. - const old_pointer = failures; - const old_bytes = failure_capacity * @sizeOf(Failure); - - failure_capacity *= 2; - - const new_bytes = failure_capacity * @sizeOf(Failure); - const failures_u8 = @ptrCast([*]u8, @alignCast(@alignOf(Failure), failures)); - const raw_pointer = utils.realloc(failures_u8, new_bytes, old_bytes, @alignOf(Failure)); - - failures = @ptrCast([*]Failure, @alignCast(@alignOf(Failure), raw_pointer)); - - // If realloc wasn't able to expand in-place (that is, it returned a different pointer), - // then copy the data into the new pointer and dealloc the old one. - if (failures != old_pointer) { - const old_pointer_u8 = @ptrCast([*]u8, old_pointer); - utils.memcpy(@ptrCast([*]u8, failures), old_pointer_u8, old_bytes); - utils.dealloc(old_pointer_u8, @alignOf(Failure)); - } - } else { - // We've never had any failures before, so allocate the failures for the first time. - failure_capacity = 10; - - const raw_pointer = utils.alloc(failure_capacity * @sizeOf(Failure), @alignOf(Failure)); - - failures = @ptrCast([*]Failure, @alignCast(@alignOf(Failure), raw_pointer)); - } - } - - failures[failure_length] = new_failure; - failure_length += 1; -} - -pub fn expectFailedC( - start_line: u32, - end_line: u32, - start_col: u16, - end_col: u16, -) callconv(.C) void { - return @call(.{ .modifier = always_inline }, expectFailed, .{ start_line, end_line, start_col, end_col }); -} - -pub fn getExpectFailures() []Failure { - failures_mutex.lock(); - defer failures_mutex.unlock(); - - if (failure_length > 0) { - // defensively clone failures, in case someone modifies the originals after the mutex has been released. - const num_bytes = failure_length * @sizeOf(Failure); - // TODO handle the possibility of alloc failing - const raw_clones = utils.alloc(num_bytes, @alignOf(Failure)) orelse unreachable; - - utils.memcpy(raw_clones, @ptrCast([*]u8, failures), num_bytes); - - const clones = @ptrCast([*]Failure, @alignCast(@alignOf(Failure), raw_clones)); - - return clones[0..failure_length]; - } else { - return failures[0..0]; - } -} - -pub fn getExpectFailuresC() callconv(.C) CSlice { - var bytes = @ptrCast(*anyopaque, failures); - - return .{ .pointer = bytes, .len = failure_length }; -} - -pub fn deinitFailures() void { - failures_mutex.lock(); - defer failures_mutex.unlock(); - - utils.dealloc(@ptrCast([*]u8, failures), @alignOf(Failure)); - failure_length = 0; -} - -pub fn deinitFailuresC() callconv(.C) void { - return @call(.{ .modifier = always_inline }, deinitFailures, .{}); -} - -test "expectFailure does something" { - defer deinitFailures(); - - var fails = getExpectFailures(); - try std.testing.expectEqual(fails.len, 0); - - expectFailed(1, 2, 3, 4); - - fails = getExpectFailures(); - try std.testing.expectEqual(fails.len, 1); - utils.dealloc(@ptrCast([*]u8, fails.ptr), @alignOf([*]Failure)); - - const what_it_should_look_like = Failure{ .start_line = 1, .end_line = 2, .start_col = 3, .end_col = 4 }; - - fails = getExpectFailures(); - try std.testing.expectEqual(fails[0], what_it_should_look_like); - utils.dealloc(@ptrCast([*]u8, fails.ptr), @alignOf([*]Failure)); -} diff --git a/crates/compiler/builtins/bitcode/src/main.zig b/crates/compiler/builtins/bitcode/src/main.zig index 3b7c1cab3b..e02645ffae 100644 --- a/crates/compiler/builtins/bitcode/src/main.zig +++ b/crates/compiler/builtins/bitcode/src/main.zig @@ -2,7 +2,6 @@ const std = @import("std"); const builtin = @import("builtin"); const math = std.math; const utils = @import("utils.zig"); -const expect = @import("expect.zig"); const ROC_BUILTINS = "roc_builtins"; const NUM = "num"; @@ -184,9 +183,6 @@ comptime { exportUtilsFn(utils.decrefC, "decref"); exportUtilsFn(utils.decrefCheckNullC, "decref_check_null"); exportUtilsFn(utils.allocateWithRefcountC, "allocate_with_refcount"); - exportExpectFn(expect.expectFailedC, "expect_failed"); - exportExpectFn(expect.getExpectFailuresC, "get_expect_failures"); - exportExpectFn(expect.deinitFailuresC, "deinit_failures"); @export(utils.panic, .{ .name = "roc_builtins.utils." ++ "panic", .linkage = .Weak }); @@ -240,10 +236,6 @@ fn exportUtilsFn(comptime func: anytype, comptime func_name: []const u8) void { exportBuiltinFn(func, "utils." ++ func_name); } -fn exportExpectFn(comptime func: anytype, comptime func_name: []const u8) void { - exportBuiltinFn(func, "expect." ++ func_name); -} - // Custom panic function, as builtin Zig version errors during LLVM verification pub fn panic(message: []const u8, stacktrace: ?*std.builtin.StackTrace) noreturn { if (builtin.is_test) { diff --git a/crates/compiler/builtins/src/bitcode.rs b/crates/compiler/builtins/src/bitcode.rs index bb137e5419..bb863b94b5 100644 --- a/crates/compiler/builtins/src/bitcode.rs +++ b/crates/compiler/builtins/src/bitcode.rs @@ -392,9 +392,6 @@ pub const UTILS_ALLOCATE_WITH_REFCOUNT: &str = "roc_builtins.utils.allocate_with pub const UTILS_INCREF: &str = "roc_builtins.utils.incref"; pub const UTILS_DECREF: &str = "roc_builtins.utils.decref"; pub const UTILS_DECREF_CHECK_NULL: &str = "roc_builtins.utils.decref_check_null"; -pub const UTILS_EXPECT_FAILED: &str = "roc_builtins.expect.expect_failed"; -pub const UTILS_GET_EXPECT_FAILURES: &str = "roc_builtins.expect.get_expect_failures"; -pub const UTILS_DEINIT_FAILURES: &str = "roc_builtins.expect.deinit_failures"; pub const UTILS_LONGJMP: &str = "longjmp"; pub const UTILS_SETJMP: &str = "setjmp"; diff --git a/crates/compiler/gen_llvm/src/llvm/build.rs b/crates/compiler/gen_llvm/src/llvm/build.rs index f940fb0d5e..2e20cb6180 100644 --- a/crates/compiler/gen_llvm/src/llvm/build.rs +++ b/crates/compiler/gen_llvm/src/llvm/build.rs @@ -39,7 +39,7 @@ use inkwell::types::{ }; use inkwell::values::BasicValueEnum::{self, *}; use inkwell::values::{ - BasicMetadataValueEnum, BasicValue, CallSiteValue, CallableValue, FloatValue, FunctionValue, + BasicMetadataValueEnum, BasicValue, CallSiteValue, FloatValue, FunctionValue, InstructionOpcode, InstructionValue, IntValue, PhiValue, PointerValue, StructValue, }; use inkwell::OptimizationLevel; @@ -65,7 +65,7 @@ use roc_mono::layout::{ }; use roc_std::RocDec; use roc_target::{PtrWidth, TargetInfo}; -use std::convert::{TryFrom, TryInto}; +use std::convert::TryInto; use std::path::Path; use target_lexicon::{Architecture, OperatingSystem, Triple}; @@ -2779,30 +2779,8 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( match env.target_info.ptr_width() { roc_target::PtrWidth::Bytes8 => { - let func = env - .module - .get_function(bitcode::UTILS_EXPECT_FAILED) - .unwrap(); - // TODO get the actual line info instead of - // hardcoding as zero! - let callable = CallableValue::try_from(func).unwrap(); - let start_line = context.i32_type().const_int(0, false); - let end_line = context.i32_type().const_int(0, false); - let start_col = context.i16_type().const_int(0, false); - let end_col = context.i16_type().const_int(0, false); - - bd.build_call( - callable, - &[ - start_line.into(), - end_line.into(), - start_col.into(), - end_col.into(), - ], - "call_expect_failed", - ); - - bd.build_unconditional_branch(then_block); + // temporary native implementation + throw_exception(env, "An expectation failed!"); } roc_target::PtrWidth::Bytes4 => { // temporary WASM implementation diff --git a/crates/compiler/gen_llvm/src/llvm/build_list.rs b/crates/compiler/gen_llvm/src/llvm/build_list.rs index fcd4ff9761..4f0816bbae 100644 --- a/crates/compiler/gen_llvm/src/llvm/build_list.rs +++ b/crates/compiler/gen_llvm/src/llvm/build_list.rs @@ -807,6 +807,15 @@ pub fn store_list<'a, 'ctx, 'env>( .build_insert_value(struct_val, len, Builtin::WRAPPER_LEN, "insert_len") .unwrap(); + struct_val = builder + .build_insert_value( + struct_val, + len, + Builtin::WRAPPER_CAPACITY, + "insert_capacity", + ) + .unwrap(); + builder.build_bitcast( struct_val.into_struct_value(), super::convert::zig_list_type(env), diff --git a/crates/compiler/gen_llvm/src/llvm/externs.rs b/crates/compiler/gen_llvm/src/llvm/externs.rs index b3c428958b..ed8986f0ee 100644 --- a/crates/compiler/gen_llvm/src/llvm/externs.rs +++ b/crates/compiler/gen_llvm/src/llvm/externs.rs @@ -47,43 +47,6 @@ pub fn add_default_roc_externs(env: &Env<'_, '_, '_>) { } } - // roc_memcpy - { - // The type of this function (but not the implementation) should have - // already been defined by the builtins, which rely on it. - let fn_val = module.get_function("roc_memcpy").unwrap(); - let mut params = fn_val.get_param_iter(); - let dest_arg = params.next().unwrap(); - let dest_alignment = 1; - let src_arg = params.next().unwrap(); - let src_alignment = 1; - let bytes_arg = params.next().unwrap(); - - debug_assert!(params.next().is_none()); - - // Add a basic block for the entry point - let entry = ctx.append_basic_block(fn_val, "entry"); - - builder.position_at_end(entry); - - // Call libc memcpy() - let _retval = builder - .build_memcpy( - dest_arg.into_pointer_value(), - dest_alignment, - src_arg.into_pointer_value(), - src_alignment, - bytes_arg.into_int_value(), - ) - .unwrap(); - - builder.build_return(None); - - if cfg!(debug_assertions) { - crate::llvm::build::verify_fn(fn_val); - } - } - // roc_realloc { let libc_realloc_val = { diff --git a/crates/compiler/gen_llvm/src/run_roc.rs b/crates/compiler/gen_llvm/src/run_roc.rs index 7de8cbaebc..cb35c864b0 100644 --- a/crates/compiler/gen_llvm/src/run_roc.rs +++ b/crates/compiler/gen_llvm/src/run_roc.rs @@ -89,15 +89,6 @@ macro_rules! run_jit_function { use roc_gen_llvm::run_roc::RocCallResult; use std::mem::MaybeUninit; - #[derive(Debug, Copy, Clone)] - #[repr(C)] - struct Failure { - start_line: u32, - end_line: u32, - start_col: u16, - end_col: u16, - } - unsafe { let main: libloading::Symbol)> = $lib .get($main_fn_name.as_bytes()) @@ -105,48 +96,8 @@ macro_rules! run_jit_function { .ok_or(format!("Unable to JIT compile `{}`", $main_fn_name)) .expect("errored"); - #[repr(C)] - struct Failures { - failures: *const Failure, - count: usize, - } - - impl Drop for Failures { - fn drop(&mut self) { - use std::alloc::{dealloc, Layout}; - use std::mem; - - unsafe { - let layout = Layout::from_size_align_unchecked( - mem::size_of::(), - mem::align_of::(), - ); - - dealloc(self.failures as *mut u8, layout); - } - } - } - - let get_expect_failures: libloading::Symbol Failures> = $lib - .get(bitcode::UTILS_GET_EXPECT_FAILURES.as_bytes()) - .ok() - .ok_or(format!( - "Unable to JIT compile `{}`", - bitcode::UTILS_GET_EXPECT_FAILURES - )) - .expect("errored"); let mut main_result = MaybeUninit::uninit(); - main(main_result.as_mut_ptr()); - let failures = get_expect_failures(); - - if failures.count > 0 { - // TODO tell the user about the failures! - let failures = - unsafe { core::slice::from_raw_parts(failures.failures, failures.count) }; - - panic!("Failed with {} failures. Failures: ", failures.len()); - } match main_result.assume_init().into() { Ok(success) => { diff --git a/crates/compiler/test_gen/src/gen_tags.rs b/crates/compiler/test_gen/src/gen_tags.rs index 50ade390da..a654b754e8 100644 --- a/crates/compiler/test_gen/src/gen_tags.rs +++ b/crates/compiler/test_gen/src/gen_tags.rs @@ -1431,8 +1431,9 @@ fn issue_2365_monomorphize_tag_with_non_empty_ext_var_wrapped() { main = compound {} "# ), - 2, // C - u8 + (0, 2), // Err, C + ([u8; std::mem::size_of::()], u8), + |(err_tag, wrap_tag): ([u8; std::mem::size_of::()], u8)| (wrap_tag, err_tag[0]) ) } @@ -1460,8 +1461,9 @@ fn issue_2365_monomorphize_tag_with_non_empty_ext_var_wrapped_nested() { compound {} "# ), - 2, // C - u8 + (0, 2), // Err, C + ([u8; std::mem::size_of::()], u8), + |(err_tag, wrap_tag): ([u8; std::mem::size_of::()], u8)| (wrap_tag, err_tag[0]) ) }