mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-02 19:32:17 +00:00
Cleanup after #7227
This commit is contained in:
parent
64cd70c1da
commit
a18232bd8b
11 changed files with 12 additions and 331 deletions
|
@ -62,7 +62,6 @@ fn print_declarations_help<'a>(
|
||||||
toplevel_function(c, f, symbol, function_def, &body.value)
|
toplevel_function(c, f, symbol, function_def, &body.value)
|
||||||
}
|
}
|
||||||
DeclarationTag::Expectation => todo!(),
|
DeclarationTag::Expectation => todo!(),
|
||||||
DeclarationTag::ExpectationFx => todo!(),
|
|
||||||
DeclarationTag::Destructure(_) => todo!(),
|
DeclarationTag::Destructure(_) => todo!(),
|
||||||
DeclarationTag::MutualRecursion { .. } => {
|
DeclarationTag::MutualRecursion { .. } => {
|
||||||
// the defs will be printed next
|
// the defs will be printed next
|
||||||
|
|
|
@ -342,7 +342,6 @@ pub enum Declaration {
|
||||||
DeclareRec(Vec<Def>, IllegalCycleMark),
|
DeclareRec(Vec<Def>, IllegalCycleMark),
|
||||||
Builtin(Def),
|
Builtin(Def),
|
||||||
Expects(ExpectsOrDbgs),
|
Expects(ExpectsOrDbgs),
|
||||||
ExpectsFx(ExpectsOrDbgs),
|
|
||||||
/// If we know a cycle is illegal during canonicalization.
|
/// If we know a cycle is illegal during canonicalization.
|
||||||
/// Otherwise we will try to detect this during solving; see [`IllegalCycleMark`].
|
/// Otherwise we will try to detect this during solving; see [`IllegalCycleMark`].
|
||||||
InvalidCycle(Vec<CycleEntry>),
|
InvalidCycle(Vec<CycleEntry>),
|
||||||
|
@ -357,7 +356,6 @@ impl Declaration {
|
||||||
InvalidCycle { .. } => 0,
|
InvalidCycle { .. } => 0,
|
||||||
Builtin(_) => 0,
|
Builtin(_) => 0,
|
||||||
Expects(_) => 0,
|
Expects(_) => 0,
|
||||||
ExpectsFx(_) => 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,7 +371,7 @@ impl Declaration {
|
||||||
&cycles.first().unwrap().expr_region,
|
&cycles.first().unwrap().expr_region,
|
||||||
&cycles.last().unwrap().expr_region,
|
&cycles.last().unwrap().expr_region,
|
||||||
),
|
),
|
||||||
Declaration::Expects(expects) | Declaration::ExpectsFx(expects) => Region::span_across(
|
Declaration::Expects(expects) => Region::span_across(
|
||||||
expects.regions.first().unwrap(),
|
expects.regions.first().unwrap(),
|
||||||
expects.regions.last().unwrap(),
|
expects.regions.last().unwrap(),
|
||||||
),
|
),
|
||||||
|
@ -2835,10 +2833,6 @@ fn decl_to_let(decl: Declaration, loc_ret: Loc<Expr>) -> Loc<Expr> {
|
||||||
|
|
||||||
loc_ret
|
loc_ret
|
||||||
}
|
}
|
||||||
Declaration::ExpectsFx(expects) => {
|
|
||||||
// Expects should only be added to top-level decls, not to let-exprs!
|
|
||||||
unreachable!("{:?}", &expects)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3241,12 +3241,6 @@ impl Declarations {
|
||||||
|
|
||||||
collector.visit_expr(&loc_expr.value, loc_expr.region, var);
|
collector.visit_expr(&loc_expr.value, loc_expr.region, var);
|
||||||
}
|
}
|
||||||
ExpectationFx => {
|
|
||||||
let loc_expr =
|
|
||||||
toplevel_expect_to_inline_expect_fx(self.expressions[index].clone());
|
|
||||||
|
|
||||||
collector.visit_expr(&loc_expr.value, loc_expr.region, var);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3265,7 +3259,6 @@ roc_error_macros::assert_sizeof_default!(DeclarationTag, 8);
|
||||||
pub enum DeclarationTag {
|
pub enum DeclarationTag {
|
||||||
Value,
|
Value,
|
||||||
Expectation,
|
Expectation,
|
||||||
ExpectationFx,
|
|
||||||
Function(Index<Loc<FunctionDef>>),
|
Function(Index<Loc<FunctionDef>>),
|
||||||
Recursive(Index<Loc<FunctionDef>>),
|
Recursive(Index<Loc<FunctionDef>>),
|
||||||
TailRecursive(Index<Loc<FunctionDef>>),
|
TailRecursive(Index<Loc<FunctionDef>>),
|
||||||
|
@ -3283,7 +3276,7 @@ impl DeclarationTag {
|
||||||
match self {
|
match self {
|
||||||
Function(_) | Recursive(_) | TailRecursive(_) => 1,
|
Function(_) | Recursive(_) | TailRecursive(_) => 1,
|
||||||
Value => 1,
|
Value => 1,
|
||||||
Expectation | ExpectationFx => 1,
|
Expectation => 1,
|
||||||
Destructure(_) => 1,
|
Destructure(_) => 1,
|
||||||
MutualRecursion { length, .. } => length as usize + 1,
|
MutualRecursion { length, .. } => length as usize + 1,
|
||||||
}
|
}
|
||||||
|
@ -3484,15 +3477,7 @@ pub(crate) fn get_lookup_symbols(expr: &Expr) -> Vec<ExpectLookup> {
|
||||||
/// This is supposed to happen just before monomorphization:
|
/// This is supposed to happen just before monomorphization:
|
||||||
/// all type errors and such are generated from the user source,
|
/// all type errors and such are generated from the user source,
|
||||||
/// but this transformation means that we don't need special codegen for toplevel expects
|
/// but this transformation means that we don't need special codegen for toplevel expects
|
||||||
pub fn toplevel_expect_to_inline_expect_pure(loc_expr: Loc<Expr>) -> Loc<Expr> {
|
pub fn toplevel_expect_to_inline_expect_pure(mut loc_expr: Loc<Expr>) -> Loc<Expr> {
|
||||||
toplevel_expect_to_inline_expect_help(loc_expr, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn toplevel_expect_to_inline_expect_fx(loc_expr: Loc<Expr>) -> Loc<Expr> {
|
|
||||||
toplevel_expect_to_inline_expect_help(loc_expr, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn toplevel_expect_to_inline_expect_help(mut loc_expr: Loc<Expr>, has_effects: bool) -> Loc<Expr> {
|
|
||||||
enum StoredDef {
|
enum StoredDef {
|
||||||
NonRecursive(Region, Box<Def>),
|
NonRecursive(Region, Box<Def>),
|
||||||
Recursive(Region, Vec<Def>, IllegalCycleMark),
|
Recursive(Region, Vec<Def>, IllegalCycleMark),
|
||||||
|
@ -3530,7 +3515,6 @@ fn toplevel_expect_to_inline_expect_help(mut loc_expr: Loc<Expr>, has_effects: b
|
||||||
}
|
}
|
||||||
|
|
||||||
let expect_region = loc_expr.region;
|
let expect_region = loc_expr.region;
|
||||||
assert!(!has_effects);
|
|
||||||
let expect = Expr::Expect {
|
let expect = Expr::Expect {
|
||||||
loc_condition: Box::new(loc_expr),
|
loc_condition: Box::new(loc_expr),
|
||||||
loc_continuation: Box::new(Loc::at_zero(Expr::EmptyRecord)),
|
loc_continuation: Box::new(Loc::at_zero(Expr::EmptyRecord)),
|
||||||
|
|
|
@ -609,7 +609,6 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
// the declarations of this group will be treaded individually by later iterations
|
// the declarations of this group will be treaded individually by later iterations
|
||||||
}
|
}
|
||||||
Expectation => { /* ignore */ }
|
Expectation => { /* ignore */ }
|
||||||
ExpectationFx => { /* ignore */ }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -747,14 +746,6 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
&mut fix_closures_closure_captures,
|
&mut fix_closures_closure_captures,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ExpectationFx => {
|
|
||||||
let loc_expr = &mut declarations.expressions[index];
|
|
||||||
fix_values_captured_in_closure_expr(
|
|
||||||
&mut loc_expr.value,
|
|
||||||
&mut fix_closures_no_capture_symbols,
|
|
||||||
&mut fix_closures_closure_captures,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@ pub fn walk_decls<V: Visitor>(visitor: &mut V, decls: &Declarations) {
|
||||||
annotation: decls.annotations[index].as_ref(),
|
annotation: decls.annotations[index].as_ref(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expectation | ExpectationFx => {
|
Expectation => {
|
||||||
let loc_condition = &decls.expressions[index];
|
let loc_condition = &decls.expressions[index];
|
||||||
|
|
||||||
DeclarationInfo::Expectation { loc_condition }
|
DeclarationInfo::Expectation { loc_condition }
|
||||||
|
|
|
@ -2738,34 +2738,6 @@ pub fn constrain_decls(
|
||||||
expected,
|
expected,
|
||||||
);
|
);
|
||||||
|
|
||||||
constraint = constraints.let_constraint(
|
|
||||||
[],
|
|
||||||
[],
|
|
||||||
[],
|
|
||||||
expect_constraint,
|
|
||||||
constraint,
|
|
||||||
Generalizable(false),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ExpectationFx => {
|
|
||||||
let loc_expr = &declarations.expressions[index];
|
|
||||||
|
|
||||||
let bool_type = constraints.push_variable(Variable::BOOL);
|
|
||||||
let expected = constraints.push_expected_type(Expected::ForReason(
|
|
||||||
Reason::ExpectCondition,
|
|
||||||
bool_type,
|
|
||||||
loc_expr.region,
|
|
||||||
));
|
|
||||||
|
|
||||||
let expect_constraint = constrain_expr(
|
|
||||||
types,
|
|
||||||
constraints,
|
|
||||||
&mut env,
|
|
||||||
loc_expr.region,
|
|
||||||
&loc_expr.value,
|
|
||||||
expected,
|
|
||||||
);
|
|
||||||
|
|
||||||
constraint = constraints.let_constraint(
|
constraint = constraints.let_constraint(
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
|
|
@ -2657,7 +2657,7 @@ fn update<'a>(
|
||||||
|
|
||||||
let subs = solved_subs.into_inner();
|
let subs = solved_subs.into_inner();
|
||||||
|
|
||||||
if !toplevel_expects.pure.is_empty() || !toplevel_expects.fx.is_empty() {
|
if !toplevel_expects.pure.is_empty() {
|
||||||
state.toplevel_expects.insert(module_id, toplevel_expects);
|
state.toplevel_expects.insert(module_id, toplevel_expects);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6010,78 +6010,6 @@ fn build_pending_specializations<'a>(
|
||||||
toplevel_expects.pure.insert(symbol, region);
|
toplevel_expects.pure.insert(symbol, region);
|
||||||
procs_base.partial_procs.insert(symbol, proc);
|
procs_base.partial_procs.insert(symbol, proc);
|
||||||
}
|
}
|
||||||
ExpectationFx => {
|
|
||||||
// skip expectations if we're not going to run them
|
|
||||||
if !build_expects {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// mark this symbol as a top-level thunk before any other work on the procs
|
|
||||||
module_thunks.push(symbol);
|
|
||||||
|
|
||||||
let expr_var = Variable::EMPTY_RECORD;
|
|
||||||
|
|
||||||
let is_host_exposed = true;
|
|
||||||
|
|
||||||
// If this is an exposed symbol, we need to
|
|
||||||
// register it as such. Otherwise, since it
|
|
||||||
// never gets called by Roc code, it will never
|
|
||||||
// get specialized!
|
|
||||||
if is_host_exposed {
|
|
||||||
let layout_result =
|
|
||||||
layout_cache.raw_from_var(mono_env.arena, expr_var, mono_env.subs);
|
|
||||||
|
|
||||||
// cannot specialize when e.g. main's type contains type variables
|
|
||||||
if let Err(e) = layout_result {
|
|
||||||
match e {
|
|
||||||
LayoutProblem::Erroneous => {
|
|
||||||
let message = "top level function has erroneous type";
|
|
||||||
procs_base.runtime_errors.insert(symbol, message);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
LayoutProblem::UnresolvedTypeVar(v) => {
|
|
||||||
let message = format!(
|
|
||||||
"top level function has unresolved type variable {v:?}"
|
|
||||||
);
|
|
||||||
procs_base
|
|
||||||
.runtime_errors
|
|
||||||
.insert(symbol, mono_env.arena.alloc(message));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
procs_base.host_specializations.insert_host_exposed(
|
|
||||||
mono_env.subs,
|
|
||||||
LambdaName::no_niche(symbol),
|
|
||||||
None,
|
|
||||||
expr_var,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let body = roc_can::expr::toplevel_expect_to_inline_expect_fx(body);
|
|
||||||
|
|
||||||
let proc = PartialProc {
|
|
||||||
annotation: expr_var,
|
|
||||||
// This is a 0-arity thunk, so it has no arguments.
|
|
||||||
pattern_symbols: &[],
|
|
||||||
// This is a top-level definition, so it cannot capture anything
|
|
||||||
captured_symbols: CapturedSymbols::None,
|
|
||||||
body: body.value,
|
|
||||||
body_var: expr_var,
|
|
||||||
// This is a 0-arity thunk, so it cannot be recursive
|
|
||||||
is_self_recursive: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
// extend the region of the expect expression with the region of the preceding
|
|
||||||
// comment, so it is shown in failure/panic messages
|
|
||||||
let name_region = declarations.symbols[index].region;
|
|
||||||
let expr_region = declarations.expressions[index].region;
|
|
||||||
let region = Region::span_across(&name_region, &expr_region);
|
|
||||||
|
|
||||||
toplevel_expects.fx.insert(symbol, region);
|
|
||||||
procs_base.partial_procs.insert(symbol, proc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -167,7 +167,6 @@ pub(crate) struct LateSpecializationsModule<'a> {
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct ToplevelExpects {
|
pub struct ToplevelExpects {
|
||||||
pub pure: VecMap<Symbol, Region>,
|
pub pure: VecMap<Symbol, Region>,
|
||||||
pub fx: VecMap<Symbol, Region>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -359,10 +359,6 @@ fn expect_types(mut loaded_module: LoadedModule, mut expected_types: HashMap<&st
|
||||||
// at least at the moment this does not happen
|
// at least at the moment this does not happen
|
||||||
panic!("Unexpected expectation in module declarations");
|
panic!("Unexpected expectation in module declarations");
|
||||||
}
|
}
|
||||||
ExpectationFx => {
|
|
||||||
// at least at the moment this does not happen
|
|
||||||
panic!("Unexpected expectation in module declarations");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,7 +458,7 @@ fn module_with_deps() {
|
||||||
def_count += 1;
|
def_count += 1;
|
||||||
}
|
}
|
||||||
MutualRecursion { .. } => { /* do nothing, not a def */ }
|
MutualRecursion { .. } => { /* do nothing, not a def */ }
|
||||||
Expectation | ExpectationFx => { /* do nothing, not a def */ }
|
Expectation => { /* do nothing, not a def */ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,7 @@ impl<'a> LowerParams<'a> {
|
||||||
self.lower_expr(&mut decls.expressions[index].value);
|
self.lower_expr(&mut decls.expressions[index].value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Destructure(_) | Expectation | ExpectationFx => {
|
Destructure(_) | Expectation => {
|
||||||
self.lower_expr(&mut decls.expressions[index].value);
|
self.lower_expr(&mut decls.expressions[index].value);
|
||||||
}
|
}
|
||||||
MutualRecursion { .. } => {}
|
MutualRecursion { .. } => {}
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
use std::{
|
use std::sync::{
|
||||||
os::unix::process::parent_id,
|
atomic::{AtomicBool, AtomicU32},
|
||||||
sync::{
|
Arc,
|
||||||
atomic::{AtomicBool, AtomicU32},
|
|
||||||
Arc,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use bumpalo::collections::Vec as BumpVec;
|
use bumpalo::collections::Vec as BumpVec;
|
||||||
|
@ -32,7 +29,6 @@ use roc_types::subs::Subs;
|
||||||
pub struct ExpectMemory<'a> {
|
pub struct ExpectMemory<'a> {
|
||||||
ptr: *mut u8,
|
ptr: *mut u8,
|
||||||
length: usize,
|
length: usize,
|
||||||
shm_name: Option<std::ffi::CString>,
|
|
||||||
_marker: std::marker::PhantomData<&'a ()>,
|
_marker: std::marker::PhantomData<&'a ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +40,6 @@ impl<'a> ExpectMemory<'a> {
|
||||||
Self {
|
Self {
|
||||||
ptr: slice.as_mut_ptr(),
|
ptr: slice.as_mut_ptr(),
|
||||||
length: slice.len(),
|
length: slice.len(),
|
||||||
shm_name: None,
|
|
||||||
_marker: std::marker::PhantomData,
|
_marker: std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,11 +49,6 @@ impl<'a> ExpectMemory<'a> {
|
||||||
Self::mmap_help(cstring, libc::O_RDWR | libc::O_CREAT)
|
Self::mmap_help(cstring, libc::O_RDWR | libc::O_CREAT)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reuse_mmap(&mut self) -> Option<Self> {
|
|
||||||
let shm_name = self.shm_name.as_ref()?.clone();
|
|
||||||
Some(Self::mmap_help(shm_name, libc::O_RDWR))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mmap_help(cstring: std::ffi::CString, shm_flags: i32) -> Self {
|
fn mmap_help(cstring: std::ffi::CString, shm_flags: i32) -> Self {
|
||||||
let ptr = unsafe {
|
let ptr = unsafe {
|
||||||
let shared_fd = libc::shm_open(cstring.as_ptr().cast(), shm_flags, 0o666);
|
let shared_fd = libc::shm_open(cstring.as_ptr().cast(), shm_flags, 0o666);
|
||||||
|
@ -102,7 +92,6 @@ impl<'a> ExpectMemory<'a> {
|
||||||
Self {
|
Self {
|
||||||
ptr: ptr.cast(),
|
ptr: ptr.cast(),
|
||||||
length: Self::SHM_SIZE,
|
length: Self::SHM_SIZE,
|
||||||
shm_name: Some(cstring),
|
|
||||||
_marker: std::marker::PhantomData,
|
_marker: std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,33 +113,6 @@ impl<'a> ExpectMemory<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub fn run_inline_expects<'a, W: std::io::Write>(
|
|
||||||
writer: &mut W,
|
|
||||||
render_target: RenderTarget,
|
|
||||||
arena: &'a Bump,
|
|
||||||
interns: &'a Interns,
|
|
||||||
layout_interner: &GlobalLayoutInterner<'a>,
|
|
||||||
lib: &libloading::Library,
|
|
||||||
expectations: &mut VecMap<ModuleId, Expectations>,
|
|
||||||
expects: ExpectFunctions<'_>,
|
|
||||||
) -> std::io::Result<(usize, usize)> {
|
|
||||||
let shm_name = format!("/roc_expect_buffer_{}", std::process::id());
|
|
||||||
let mut memory = ExpectMemory::create_or_reuse_mmap(&shm_name);
|
|
||||||
|
|
||||||
run_expects_with_memory(
|
|
||||||
writer,
|
|
||||||
render_target,
|
|
||||||
arena,
|
|
||||||
interns,
|
|
||||||
layout_interner,
|
|
||||||
lib,
|
|
||||||
expectations,
|
|
||||||
expects,
|
|
||||||
&mut memory,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn run_toplevel_expects<'a, W: std::io::Write>(
|
pub fn run_toplevel_expects<'a, W: std::io::Write>(
|
||||||
writer: &mut W,
|
writer: &mut W,
|
||||||
|
@ -193,25 +155,6 @@ pub(crate) fn run_expects_with_memory<'a, W: std::io::Write>(
|
||||||
let mut failed = 0;
|
let mut failed = 0;
|
||||||
let mut passed = 0;
|
let mut passed = 0;
|
||||||
|
|
||||||
for expect in expects.fx {
|
|
||||||
let result = run_expect_fx(
|
|
||||||
writer,
|
|
||||||
render_target,
|
|
||||||
arena,
|
|
||||||
interns,
|
|
||||||
layout_interner,
|
|
||||||
lib,
|
|
||||||
expectations,
|
|
||||||
memory,
|
|
||||||
expect,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
match result {
|
|
||||||
true => passed += 1,
|
|
||||||
false => failed += 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memory.set_shared_buffer(lib);
|
memory.set_shared_buffer(lib);
|
||||||
|
|
||||||
for expect in expects.pure {
|
for expect in expects.pure {
|
||||||
|
@ -294,107 +237,6 @@ fn run_expect_pure<'a, W: std::io::Write>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
fn run_expect_fx<'a, W: std::io::Write>(
|
|
||||||
writer: &mut W,
|
|
||||||
render_target: RenderTarget,
|
|
||||||
arena: &'a Bump,
|
|
||||||
interns: &'a Interns,
|
|
||||||
layout_interner: &GlobalLayoutInterner<'a>,
|
|
||||||
lib: &libloading::Library,
|
|
||||||
expectations: &mut VecMap<ModuleId, Expectations>,
|
|
||||||
parent_memory: &mut ExpectMemory,
|
|
||||||
expect: ToplevelExpect<'_>,
|
|
||||||
) -> std::io::Result<bool> {
|
|
||||||
use signal_hook::{consts::signal::SIGCHLD, consts::signal::SIGUSR1, iterator::Signals};
|
|
||||||
|
|
||||||
let mut signals = Signals::new([SIGCHLD, SIGUSR1]).unwrap();
|
|
||||||
|
|
||||||
match unsafe { libc::fork() } {
|
|
||||||
0 => unsafe {
|
|
||||||
// we are the child
|
|
||||||
|
|
||||||
use roc_gen_llvm::try_run_jit_function;
|
|
||||||
|
|
||||||
let mut child_memory = parent_memory.reuse_mmap().unwrap();
|
|
||||||
|
|
||||||
let sequence = ExpectSequence::new(child_memory.ptr);
|
|
||||||
|
|
||||||
child_memory.set_shared_buffer(lib);
|
|
||||||
|
|
||||||
let result: Result<(), (String, _)> =
|
|
||||||
try_run_jit_function!(lib, expect.name, (), |v: ()| v);
|
|
||||||
|
|
||||||
if let Err((msg, _)) = result {
|
|
||||||
internal_error!("roc panic {msg}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if sequence.count_failures() > 0 {
|
|
||||||
libc::kill(parent_id() as _, SIGUSR1);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::process::exit(0)
|
|
||||||
},
|
|
||||||
-1 => {
|
|
||||||
// something failed
|
|
||||||
|
|
||||||
// Display a human-friendly error message
|
|
||||||
println!("Error {:?}", std::io::Error::last_os_error());
|
|
||||||
|
|
||||||
std::process::exit(1)
|
|
||||||
}
|
|
||||||
1.. => {
|
|
||||||
let mut has_succeeded = true;
|
|
||||||
|
|
||||||
for sig in &mut signals {
|
|
||||||
match sig {
|
|
||||||
SIGCHLD => {
|
|
||||||
// done!
|
|
||||||
return Ok(has_succeeded);
|
|
||||||
}
|
|
||||||
SIGUSR1 => {
|
|
||||||
// this is the signal we use for an expect failure. Let's see what the child told us
|
|
||||||
has_succeeded = false;
|
|
||||||
|
|
||||||
let frame =
|
|
||||||
ExpectFrame::at_offset(parent_memory.ptr, ExpectSequence::START_OFFSET);
|
|
||||||
let module_id = frame.module_id;
|
|
||||||
|
|
||||||
let data = expectations.get_mut(&module_id).unwrap();
|
|
||||||
let filename = data.path.to_owned();
|
|
||||||
let source = std::fs::read_to_string(&data.path).unwrap();
|
|
||||||
|
|
||||||
let renderer = Renderer::new(
|
|
||||||
arena,
|
|
||||||
interns,
|
|
||||||
render_target,
|
|
||||||
module_id,
|
|
||||||
filename,
|
|
||||||
&source,
|
|
||||||
);
|
|
||||||
|
|
||||||
render_expect_failure(
|
|
||||||
writer,
|
|
||||||
&renderer,
|
|
||||||
arena,
|
|
||||||
None,
|
|
||||||
expectations,
|
|
||||||
interns,
|
|
||||||
layout_interner,
|
|
||||||
parent_memory.ptr,
|
|
||||||
ExpectSequence::START_OFFSET,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
_ => println!("received signal {sig}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render_expects_in_memory<'a>(
|
pub fn render_expects_in_memory<'a>(
|
||||||
writer: &mut impl std::io::Write,
|
writer: &mut impl std::io::Write,
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
|
@ -607,7 +449,6 @@ pub struct ToplevelExpect<'a> {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ExpectFunctions<'a> {
|
pub struct ExpectFunctions<'a> {
|
||||||
pub pure: BumpVec<'a, ToplevelExpect<'a>>,
|
pub pure: BumpVec<'a, ToplevelExpect<'a>>,
|
||||||
pub fx: BumpVec<'a, ToplevelExpect<'a>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_mono_module_to_dylib<'a>(
|
pub fn expect_mono_module_to_dylib<'a>(
|
||||||
|
@ -668,14 +509,7 @@ pub fn expect_mono_module_to_dylib<'a>(
|
||||||
.map(|(module_id, expects)| {
|
.map(|(module_id, expects)| {
|
||||||
(
|
(
|
||||||
*module_id,
|
*module_id,
|
||||||
bumpalo::collections::Vec::from_iter_in(
|
bumpalo::collections::Vec::from_iter_in(expects.pure.keys().copied(), env.arena),
|
||||||
expects
|
|
||||||
.pure
|
|
||||||
.keys()
|
|
||||||
.copied()
|
|
||||||
.chain(expects.fx.keys().copied()),
|
|
||||||
env.arena,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -693,19 +527,6 @@ pub fn expect_mono_module_to_dylib<'a>(
|
||||||
for (module_id, expects) in toplevel_expects.into_iter() {
|
for (module_id, expects) in toplevel_expects.into_iter() {
|
||||||
let expect_names = expect_names.get(&module_id).unwrap();
|
let expect_names = expect_names.get(&module_id).unwrap();
|
||||||
|
|
||||||
let expects_fx = bumpalo::collections::Vec::from_iter_in(
|
|
||||||
expects
|
|
||||||
.fx
|
|
||||||
.into_iter()
|
|
||||||
.zip(expect_names.iter().skip(expects.pure.len()))
|
|
||||||
.map(|((symbol, region), name)| ToplevelExpect {
|
|
||||||
symbol,
|
|
||||||
region,
|
|
||||||
name,
|
|
||||||
}),
|
|
||||||
env.arena,
|
|
||||||
);
|
|
||||||
|
|
||||||
let expects_pure =
|
let expects_pure =
|
||||||
bumpalo::collections::Vec::from_iter_in(
|
bumpalo::collections::Vec::from_iter_in(
|
||||||
expects.pure.into_iter().zip(expect_names.iter()).map(
|
expects.pure.into_iter().zip(expect_names.iter()).map(
|
||||||
|
@ -718,10 +539,7 @@ pub fn expect_mono_module_to_dylib<'a>(
|
||||||
env.arena,
|
env.arena,
|
||||||
);
|
);
|
||||||
|
|
||||||
let expect_funs = ExpectFunctions {
|
let expect_funs = ExpectFunctions { pure: expects_pure };
|
||||||
pure: expects_pure,
|
|
||||||
fx: expects_fx,
|
|
||||||
};
|
|
||||||
|
|
||||||
modules_expects.insert(module_id, expect_funs);
|
modules_expects.insert(module_id, expect_funs);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue