report multiple expect failures

This commit is contained in:
Folkert 2022-07-23 20:14:35 +02:00
parent 29a260a4b3
commit 93005cf2d0
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
3 changed files with 148 additions and 73 deletions

View file

@ -424,16 +424,20 @@ pub fn test(matches: &ArgMatches, triple: Triple) -> io::Result<i32> {
); );
for expect in expects { for expect in expects {
// clear the state
libc::memset(shared_ptr.cast(), 0, SHM_SIZE as _); libc::memset(shared_ptr.cast(), 0, SHM_SIZE as _);
*((shared_ptr as *mut usize).add(1)) = 16;
let result: Result<(), String> = try_run_jit_function!(lib, expect.name, (), |v: ()| v); let result: Result<(), String> = try_run_jit_function!(lib, expect.name, (), |v: ()| v);
let shared_memory_ptr: *const u8 = shared_ptr.cast(); let shared_memory_ptr: *const u8 = shared_ptr.cast();
let buffer = std::slice::from_raw_parts(shared_memory_ptr, SHM_SIZE as _); let buffer =
std::slice::from_raw_parts(shared_memory_ptr.add(16), SHM_SIZE as usize - 16);
if let Err(roc_panic_message) = result { if let Err(roc_panic_message) = result {
failed += 1; failed += 1;
render_expect_panic( render_expect_panic(
arena, arena,
expect, expect,
@ -444,14 +448,21 @@ pub fn test(matches: &ArgMatches, triple: Triple) -> io::Result<i32> {
println!(); println!();
} else if buffer.iter().any(|b| *b != 0) { } else if buffer.iter().any(|b| *b != 0) {
failed += 1; failed += 1;
render_expect_failure(
arena, let count = *(shared_ptr as *const usize).add(0);
Some(expect), let mut offset = 16;
&mut expectations,
interns, for _ in 0..count {
shared_memory_ptr, offset += render_expect_failure(
); arena,
println!(); Some(expect),
&mut expectations,
interns,
shared_memory_ptr.add(offset),
);
println!();
}
} else { } else {
passed += 1; passed += 1;
} }
@ -1097,7 +1108,7 @@ fn render_expect_failure<'a>(
expectations: &mut VecMap<ModuleId, Expectations>, expectations: &mut VecMap<ModuleId, Expectations>,
interns: &'a Interns, interns: &'a Interns,
start: *const u8, start: *const u8,
) { ) -> usize {
use roc_reporting::report::Report; use roc_reporting::report::Report;
use roc_reporting::report::RocDocAllocator; use roc_reporting::report::RocDocAllocator;
use ven_pretty::DocAllocator; use ven_pretty::DocAllocator;
@ -1112,8 +1123,6 @@ fn render_expect_failure<'a>(
let module_id: ModuleId = unsafe { std::mem::transmute(module_id_bytes) }; let module_id: ModuleId = unsafe { std::mem::transmute(module_id_bytes) };
let data = expectations.get_mut(&module_id).unwrap(); let data = expectations.get_mut(&module_id).unwrap();
let current = data.expectations.get(&region).unwrap();
let subs = arena.alloc(&mut data.subs);
// TODO cache these line offsets? // TODO cache these line offsets?
let path = &data.path; let path = &data.path;
@ -1123,7 +1132,15 @@ fn render_expect_failure<'a>(
let line_info = roc_region::all::LineInfo::new(&file_string); let line_info = roc_region::all::LineInfo::new(&file_string);
let display_region = match expect { let display_region = match expect {
Some(expect) => Region::span_across(&expect.region, &region), Some(expect) => {
if !expect.region.contains(&region) {
// this is an expect outside of a toplevel expect,
// likely in some function we called
region
} else {
Region::across_all([&expect.region, &region])
}
}
None => region, None => region,
}; };
let line_col_region = line_info.convert_region(display_region); let line_col_region = line_info.convert_region(display_region);
@ -1133,6 +1150,15 @@ fn render_expect_failure<'a>(
// 8 bytes for region, 4 for module id // 8 bytes for region, 4 for module id
let start_offset = 12; let start_offset = 12;
let current = match data.expectations.get(&region) {
None => {
invalid_regions(alloc, filename, line_info, region);
return 0;
}
Some(current) => current,
};
let subs = arena.alloc(&mut data.subs);
let (symbols, variables): (Vec<_>, Vec<_>) = current.iter().map(|(a, b)| (*a, *b)).unzip(); let (symbols, variables): (Vec<_>, Vec<_>) = current.iter().map(|(a, b)| (*a, *b)).unzip();
let error_types: Vec<_> = variables let error_types: Vec<_> = variables
@ -1143,7 +1169,7 @@ fn render_expect_failure<'a>(
}) })
.collect(); .collect();
let expressions = roc_repl_expect::get_values( let (offset, expressions) = roc_repl_expect::get_values(
target_info, target_info,
arena, arena,
subs, subs,
@ -1209,6 +1235,44 @@ fn render_expect_failure<'a>(
); );
println!("{}", buf); println!("{}", buf);
offset
}
fn invalid_regions(
alloc: roc_reporting::report::RocDocAllocator,
filename: PathBuf,
line_info: roc_region::all::LineInfo,
region: Region,
) {
use ven_pretty::DocAllocator;
let line_col_region = line_info.convert_region(region);
let doc = alloc.stack([
alloc.text("Internal expect failure"),
alloc.region(line_col_region),
]);
let report = roc_reporting::report::Report {
title: "EXPECT FAILED".into(),
doc,
filename,
severity: roc_reporting::report::Severity::RuntimeError,
};
let mut buf = String::new();
report.render(
roc_reporting::report::RenderTarget::ColorTerminal,
&mut buf,
&alloc,
&roc_reporting::report::DEFAULT_PALETTE,
);
println!("{}", buf);
panic!();
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]

View file

@ -21,6 +21,68 @@ fn pointer_at_offset<'ctx>(
unsafe { bd.build_gep(ptr, &[offset], "offset_ptr") } unsafe { bd.build_gep(ptr, &[offset], "offset_ptr") }
} }
/// Writes the module and region into the buffer
fn write_header<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
ptr: PointerValue<'ctx>,
mut offset: IntValue<'ctx>,
condition: Symbol,
region: Region,
) -> IntValue<'ctx> {
let region_start = env
.context
.i32_type()
.const_int(region.start().offset as _, false);
let region_end = env
.context
.i32_type()
.const_int(region.end().offset as _, false);
let module_id: u32 = unsafe { std::mem::transmute(condition.module_id()) };
let module_id = env.context.i32_type().const_int(module_id as _, false);
offset = build_copy(env, ptr, offset, region_start.into());
offset = build_copy(env, ptr, offset, region_end.into());
offset = build_copy(env, ptr, offset, module_id.into());
offset
}
/// Read the first two 32-bit values from the shared memory,
/// representing the total number of expect frames and the next free position
fn read_state<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
ptr: PointerValue<'ctx>,
) -> (IntValue<'ctx>, IntValue<'ctx>) {
let ptr_type = env.ptr_int().ptr_type(AddressSpace::Generic);
let ptr = env.builder.build_pointer_cast(ptr, ptr_type, "");
let one = env.ptr_int().const_int(1, false);
let offset_ptr = pointer_at_offset(env.builder, ptr, one);
let count = env.builder.build_load(ptr, "load_count");
let offset = env.builder.build_load(offset_ptr, "load_offset");
(count.into_int_value(), offset.into_int_value())
}
fn write_state<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
ptr: PointerValue<'ctx>,
count: IntValue<'ctx>,
offset: IntValue<'ctx>,
) {
let ptr_type = env.ptr_int().ptr_type(AddressSpace::Generic);
let ptr = env.builder.build_pointer_cast(ptr, ptr_type, "");
let one = env.ptr_int().const_int(1, false);
let offset_ptr = pointer_at_offset(env.builder, ptr, one);
env.builder.build_store(ptr, count);
env.builder.build_store(offset_ptr, offset);
}
pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>( pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'a, 'ctx>, scope: &Scope<'a, 'ctx>,
@ -44,64 +106,9 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
.unwrap() .unwrap()
.into_pointer_value(); .into_pointer_value();
let mut ptr = original_ptr; let (count, mut offset) = read_state(env, original_ptr);
{ offset = write_header(env, original_ptr, offset, condition, region);
let value = env
.context
.i32_type()
.const_int(region.start().offset as _, false);
let cast_ptr = env.builder.build_pointer_cast(
ptr,
value.get_type().ptr_type(AddressSpace::Generic),
"to_store_pointer",
);
env.builder.build_store(cast_ptr, value);
// let increment = layout.stack_size(env.target_info);
let increment = 4;
let increment = env.ptr_int().const_int(increment as _, false);
ptr = unsafe { env.builder.build_gep(ptr, &[increment], "increment_ptr") };
}
{
let value = env
.context
.i32_type()
.const_int(region.end().offset as _, false);
let cast_ptr = env.builder.build_pointer_cast(
ptr,
value.get_type().ptr_type(AddressSpace::Generic),
"to_store_pointer",
);
env.builder.build_store(cast_ptr, value);
// let increment = layout.stack_size(env.target_info);
let increment = 4;
let increment = env.ptr_int().const_int(increment as _, false);
ptr = unsafe { env.builder.build_gep(ptr, &[increment], "increment_ptr") };
}
{
let region_bytes: u32 = unsafe { std::mem::transmute(condition.module_id()) };
let value = env.context.i32_type().const_int(region_bytes as _, false);
let cast_ptr = env.builder.build_pointer_cast(
ptr,
value.get_type().ptr_type(AddressSpace::Generic),
"to_store_pointer",
);
env.builder.build_store(cast_ptr, value);
}
let mut offset = env.ptr_int().const_int(12, false);
for lookup in lookups.iter() { for lookup in lookups.iter() {
let (value, layout) = load_symbol_and_layout(scope, lookup); let (value, layout) = load_symbol_and_layout(scope, lookup);
@ -116,6 +123,10 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
WhenRecursive::Unreachable, WhenRecursive::Unreachable,
); );
} }
let one = env.ptr_int().const_int(1, false);
let new_count = env.builder.build_int_add(count, one, "inc");
write_state(env, original_ptr, new_count, offset)
} }
#[derive(Clone, Debug, Copy)] #[derive(Clone, Debug, Copy)]

View file

@ -23,7 +23,7 @@ pub fn get_values<'a>(
start: *const u8, start: *const u8,
start_offset: usize, start_offset: usize,
variables: &[Variable], variables: &[Variable],
) -> Result<Vec<Expr<'a>>, ToAstProblem> { ) -> Result<(usize, Vec<Expr<'a>>), ToAstProblem> {
let mut result = Vec::with_capacity(variables.len()); let mut result = Vec::with_capacity(variables.len());
let memory = ExpectMemory { let memory = ExpectMemory {
@ -70,7 +70,7 @@ pub fn get_values<'a>(
result.push(expr); result.push(expr);
} }
Ok(result) Ok((app.offset, result))
} }
struct ExpectMemory { struct ExpectMemory {