diff --git a/crates/compiler/can/src/debug/pretty_print.rs b/crates/compiler/can/src/debug/pretty_print.rs index b5a704d9be..b4b7a5a9cd 100644 --- a/crates/compiler/can/src/debug/pretty_print.rs +++ b/crates/compiler/can/src/debug/pretty_print.rs @@ -62,7 +62,6 @@ fn print_declarations_help<'a>( toplevel_function(c, f, symbol, function_def, &body.value) } DeclarationTag::Expectation => todo!(), - DeclarationTag::ExpectationFx => todo!(), DeclarationTag::Destructure(_) => todo!(), DeclarationTag::MutualRecursion { .. } => { // the defs will be printed next diff --git a/crates/compiler/can/src/def.rs b/crates/compiler/can/src/def.rs index 13fa4021c1..dce1e4d658 100644 --- a/crates/compiler/can/src/def.rs +++ b/crates/compiler/can/src/def.rs @@ -342,7 +342,6 @@ pub enum Declaration { DeclareRec(Vec, IllegalCycleMark), Builtin(Def), Expects(ExpectsOrDbgs), - ExpectsFx(ExpectsOrDbgs), /// If we know a cycle is illegal during canonicalization. /// Otherwise we will try to detect this during solving; see [`IllegalCycleMark`]. InvalidCycle(Vec), @@ -357,7 +356,6 @@ impl Declaration { InvalidCycle { .. } => 0, Builtin(_) => 0, Expects(_) => 0, - ExpectsFx(_) => 0, } } @@ -373,7 +371,7 @@ impl Declaration { &cycles.first().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.last().unwrap(), ), @@ -2835,10 +2833,6 @@ fn decl_to_let(decl: Declaration, loc_ret: Loc) -> Loc { loc_ret } - Declaration::ExpectsFx(expects) => { - // Expects should only be added to top-level decls, not to let-exprs! - unreachable!("{:?}", &expects) - } } } diff --git a/crates/compiler/can/src/expr.rs b/crates/compiler/can/src/expr.rs index 2d5f0d71b6..4ce73f8f95 100644 --- a/crates/compiler/can/src/expr.rs +++ b/crates/compiler/can/src/expr.rs @@ -3241,12 +3241,6 @@ impl Declarations { 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 { Value, Expectation, - ExpectationFx, Function(Index>), Recursive(Index>), TailRecursive(Index>), @@ -3283,7 +3276,7 @@ impl DeclarationTag { match self { Function(_) | Recursive(_) | TailRecursive(_) => 1, Value => 1, - Expectation | ExpectationFx => 1, + Expectation => 1, Destructure(_) => 1, MutualRecursion { length, .. } => length as usize + 1, } @@ -3484,15 +3477,7 @@ pub(crate) fn get_lookup_symbols(expr: &Expr) -> Vec { /// This is supposed to happen just before monomorphization: /// 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 -pub fn toplevel_expect_to_inline_expect_pure(loc_expr: Loc) -> Loc { - toplevel_expect_to_inline_expect_help(loc_expr, false) -} - -pub fn toplevel_expect_to_inline_expect_fx(loc_expr: Loc) -> Loc { - toplevel_expect_to_inline_expect_help(loc_expr, true) -} - -fn toplevel_expect_to_inline_expect_help(mut loc_expr: Loc, has_effects: bool) -> Loc { +pub fn toplevel_expect_to_inline_expect_pure(mut loc_expr: Loc) -> Loc { enum StoredDef { NonRecursive(Region, Box), Recursive(Region, Vec, IllegalCycleMark), @@ -3530,7 +3515,6 @@ fn toplevel_expect_to_inline_expect_help(mut loc_expr: Loc, has_effects: b } let expect_region = loc_expr.region; - assert!(!has_effects); let expect = Expr::Expect { loc_condition: Box::new(loc_expr), loc_continuation: Box::new(Loc::at_zero(Expr::EmptyRecord)), diff --git a/crates/compiler/can/src/module.rs b/crates/compiler/can/src/module.rs index 9679a17bc9..39c5bfae16 100644 --- a/crates/compiler/can/src/module.rs +++ b/crates/compiler/can/src/module.rs @@ -609,7 +609,6 @@ pub fn canonicalize_module_defs<'a>( // the declarations of this group will be treaded individually by later iterations } Expectation => { /* ignore */ } - ExpectationFx => { /* ignore */ } } } @@ -747,14 +746,6 @@ pub fn canonicalize_module_defs<'a>( &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, - ); - } } } diff --git a/crates/compiler/can/src/traverse.rs b/crates/compiler/can/src/traverse.rs index 4290067842..6939718c7c 100644 --- a/crates/compiler/can/src/traverse.rs +++ b/crates/compiler/can/src/traverse.rs @@ -107,7 +107,7 @@ pub fn walk_decls(visitor: &mut V, decls: &Declarations) { annotation: decls.annotations[index].as_ref(), } } - Expectation | ExpectationFx => { + Expectation => { let loc_condition = &decls.expressions[index]; DeclarationInfo::Expectation { loc_condition } diff --git a/crates/compiler/constrain/src/expr.rs b/crates/compiler/constrain/src/expr.rs index 88c6708d86..670f761577 100644 --- a/crates/compiler/constrain/src/expr.rs +++ b/crates/compiler/constrain/src/expr.rs @@ -2738,34 +2738,6 @@ pub fn constrain_decls( 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( [], [], diff --git a/crates/compiler/load_internal/src/file.rs b/crates/compiler/load_internal/src/file.rs index 585ff0a3c6..ff7ce3a50c 100644 --- a/crates/compiler/load_internal/src/file.rs +++ b/crates/compiler/load_internal/src/file.rs @@ -2657,7 +2657,7 @@ fn update<'a>( 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); } @@ -6010,78 +6010,6 @@ fn build_pending_specializations<'a>( toplevel_expects.pure.insert(symbol, region); 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); - } } } diff --git a/crates/compiler/load_internal/src/module.rs b/crates/compiler/load_internal/src/module.rs index baeb25aab8..d1b730d882 100644 --- a/crates/compiler/load_internal/src/module.rs +++ b/crates/compiler/load_internal/src/module.rs @@ -167,7 +167,6 @@ pub(crate) struct LateSpecializationsModule<'a> { #[derive(Debug, Default)] pub struct ToplevelExpects { pub pure: VecMap, - pub fx: VecMap, } #[derive(Debug)] diff --git a/crates/compiler/load_internal/tests/test_load.rs b/crates/compiler/load_internal/tests/test_load.rs index 5dd24b3fa0..b95d931990 100644 --- a/crates/compiler/load_internal/tests/test_load.rs +++ b/crates/compiler/load_internal/tests/test_load.rs @@ -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 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; } MutualRecursion { .. } => { /* do nothing, not a def */ } - Expectation | ExpectationFx => { /* do nothing, not a def */ } + Expectation => { /* do nothing, not a def */ } } } diff --git a/crates/compiler/lower_params/src/lower.rs b/crates/compiler/lower_params/src/lower.rs index 5fa23f8668..48cf17dd40 100644 --- a/crates/compiler/lower_params/src/lower.rs +++ b/crates/compiler/lower_params/src/lower.rs @@ -101,7 +101,7 @@ impl<'a> LowerParams<'a> { self.lower_expr(&mut decls.expressions[index].value); } - Destructure(_) | Expectation | ExpectationFx => { + Destructure(_) | Expectation => { self.lower_expr(&mut decls.expressions[index].value); } MutualRecursion { .. } => {} diff --git a/crates/repl_expect/src/run.rs b/crates/repl_expect/src/run.rs index aa8b0afdd2..a88708fb39 100644 --- a/crates/repl_expect/src/run.rs +++ b/crates/repl_expect/src/run.rs @@ -1,9 +1,6 @@ -use std::{ - os::unix::process::parent_id, - sync::{ - atomic::{AtomicBool, AtomicU32}, - Arc, - }, +use std::sync::{ + atomic::{AtomicBool, AtomicU32}, + Arc, }; use bumpalo::collections::Vec as BumpVec; @@ -32,7 +29,6 @@ use roc_types::subs::Subs; pub struct ExpectMemory<'a> { ptr: *mut u8, length: usize, - shm_name: Option, _marker: std::marker::PhantomData<&'a ()>, } @@ -44,7 +40,6 @@ impl<'a> ExpectMemory<'a> { Self { ptr: slice.as_mut_ptr(), length: slice.len(), - shm_name: None, _marker: std::marker::PhantomData, } } @@ -54,11 +49,6 @@ impl<'a> ExpectMemory<'a> { Self::mmap_help(cstring, libc::O_RDWR | libc::O_CREAT) } - fn reuse_mmap(&mut self) -> Option { - 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 { let ptr = unsafe { let shared_fd = libc::shm_open(cstring.as_ptr().cast(), shm_flags, 0o666); @@ -102,7 +92,6 @@ impl<'a> ExpectMemory<'a> { Self { ptr: ptr.cast(), length: Self::SHM_SIZE, - shm_name: Some(cstring), _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, - 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)] pub fn run_toplevel_expects<'a, W: std::io::Write>( 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 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); 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, - parent_memory: &mut ExpectMemory, - expect: ToplevelExpect<'_>, -) -> std::io::Result { - 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>( writer: &mut impl std::io::Write, arena: &'a Bump, @@ -607,7 +449,6 @@ pub struct ToplevelExpect<'a> { #[derive(Debug)] pub struct ExpectFunctions<'a> { pub pure: BumpVec<'a, ToplevelExpect<'a>>, - pub fx: BumpVec<'a, ToplevelExpect<'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)| { ( *module_id, - bumpalo::collections::Vec::from_iter_in( - expects - .pure - .keys() - .copied() - .chain(expects.fx.keys().copied()), - env.arena, - ), + bumpalo::collections::Vec::from_iter_in(expects.pure.keys().copied(), env.arena), ) }) .collect(); @@ -693,19 +527,6 @@ pub fn expect_mono_module_to_dylib<'a>( for (module_id, expects) in toplevel_expects.into_iter() { 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 = bumpalo::collections::Vec::from_iter_in( expects.pure.into_iter().zip(expect_names.iter()).map( @@ -718,10 +539,7 @@ pub fn expect_mono_module_to_dylib<'a>( env.arena, ); - let expect_funs = ExpectFunctions { - pure: expects_pure, - fx: expects_fx, - }; + let expect_funs = ExpectFunctions { pure: expects_pure }; modules_expects.insert(module_id, expect_funs); }