diff --git a/crates/compiler/alias_analysis/src/lib.rs b/crates/compiler/alias_analysis/src/lib.rs index e84f3f3b71..b180e15d93 100644 --- a/crates/compiler/alias_analysis/src/lib.rs +++ b/crates/compiler/alias_analysis/src/lib.rs @@ -611,6 +611,7 @@ fn stmt_spec<'a>( builder.add_choice(block, &cases) } + Dbg { remainder, .. } => stmt_spec(builder, interner, env, block, layout, remainder), Expect { remainder, .. } => stmt_spec(builder, interner, env, block, layout, remainder), ExpectFx { remainder, .. } => stmt_spec(builder, interner, env, block, layout, remainder), Ret(symbol) => Ok(env.symbols[symbol]), diff --git a/crates/compiler/gen_dev/src/lib.rs b/crates/compiler/gen_dev/src/lib.rs index 03c32d23e7..40ce349ec2 100644 --- a/crates/compiler/gen_dev/src/lib.rs +++ b/crates/compiler/gen_dev/src/lib.rs @@ -1107,6 +1107,7 @@ trait Backend<'a> { } } + Stmt::Dbg { .. } => todo!("dbg not implemented in the dev backend"), Stmt::Expect { .. } => todo!("expect is not implemented in the dev backend"), Stmt::ExpectFx { .. } => todo!("expect-fx is not implemented in the dev backend"), diff --git a/crates/compiler/gen_llvm/src/llvm/build.rs b/crates/compiler/gen_llvm/src/llvm/build.rs index d3e9fabe47..fbb55a5f72 100644 --- a/crates/compiler/gen_llvm/src/llvm/build.rs +++ b/crates/compiler/gen_llvm/src/llvm/build.rs @@ -2661,6 +2661,39 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( } } + Dbg { + symbol, + variable: specialized_var, + remainder, + } => { + if env.mode.runs_expects() { + let shared_memory = crate::llvm::expect::SharedMemoryPointer::get(env); + let region = unsafe { std::mem::transmute::<_, roc_region::all::Region>(*symbol) }; + + crate::llvm::expect::clone_to_shared_memory( + env, + scope, + layout_ids, + &shared_memory, + *symbol, + region, + &[*symbol], + &[*specialized_var], + ); + + crate::llvm::expect::notify_parent_dbg(env, &shared_memory); + } + + build_exp_stmt( + env, + layout_ids, + func_spec_solutions, + scope, + parent, + remainder, + ) + } + Expect { condition: cond_symbol, region, diff --git a/crates/compiler/gen_wasm/src/backend.rs b/crates/compiler/gen_wasm/src/backend.rs index 9d9aaf3297..6cb0836fd5 100644 --- a/crates/compiler/gen_wasm/src/backend.rs +++ b/crates/compiler/gen_wasm/src/backend.rs @@ -714,6 +714,7 @@ impl<'a> WasmBackend<'a> { Stmt::Refcounting(modify, following) => self.stmt_refcounting(modify, following), + Stmt::Dbg { .. } => todo!("dbg is not implemented in the wasm backend"), Stmt::Expect { .. } => todo!("expect is not implemented in the wasm backend"), Stmt::ExpectFx { .. } => todo!("expect-fx is not implemented in the wasm backend"), diff --git a/crates/compiler/mono/src/borrow.rs b/crates/compiler/mono/src/borrow.rs index e591a2c8e4..271a02a5d2 100644 --- a/crates/compiler/mono/src/borrow.rs +++ b/crates/compiler/mono/src/borrow.rs @@ -314,6 +314,7 @@ impl<'a> ParamMap<'a> { stack.push(cont); } + Dbg { remainder, .. } => stack.push(remainder), Expect { remainder, .. } => stack.push(remainder), ExpectFx { remainder, .. } => stack.push(remainder), @@ -823,6 +824,10 @@ impl<'a> BorrowInfState<'a> { self.collect_stmt(param_map, default_branch.1); } + Dbg { remainder, .. } => { + self.collect_stmt(param_map, remainder); + } + Expect { remainder, .. } => { self.collect_stmt(param_map, remainder); } @@ -1007,6 +1012,7 @@ fn call_info_stmt<'a>(arena: &'a Bump, stmt: &Stmt<'a>, info: &mut CallInfo<'a>) stack.push(default_branch.1); } + Dbg { remainder, .. } => stack.push(remainder), Expect { remainder, .. } => stack.push(remainder), ExpectFx { remainder, .. } => stack.push(remainder), diff --git a/crates/compiler/mono/src/debug/checker.rs b/crates/compiler/mono/src/debug/checker.rs index e4e3b82734..26471b63a9 100644 --- a/crates/compiler/mono/src/debug/checker.rs +++ b/crates/compiler/mono/src/debug/checker.rs @@ -305,6 +305,9 @@ impl<'a, 'r> Ctx<'a, 'r> { self.check_modify_rc(rc); self.check_stmt(rest); } + &Stmt::Dbg { remainder, .. } => { + self.check_stmt(remainder); + } &Stmt::Expect { condition, region: _, diff --git a/crates/compiler/mono/src/inc_dec.rs b/crates/compiler/mono/src/inc_dec.rs index 02d282ddfc..88b1b256af 100644 --- a/crates/compiler/mono/src/inc_dec.rs +++ b/crates/compiler/mono/src/inc_dec.rs @@ -108,6 +108,13 @@ pub fn occurring_variables(stmt: &Stmt<'_>) -> (MutSet, MutSet) stack.push(cont); } + Dbg { + symbol, remainder, .. + } => { + result.insert(*symbol); + stack.push(remainder); + } + Expect { condition, remainder, @@ -1200,6 +1207,26 @@ impl<'a, 'i> Context<'a, 'i> { (switch, case_live_vars) } + Dbg { + symbol, + variable, + remainder, + } => { + let (b, mut b_live_vars) = self.visit_stmt(codegen, remainder); + + let expect = self.arena.alloc(Stmt::Dbg { + symbol: *symbol, + variable: *variable, + remainder: b, + }); + + let expect = self.add_inc_before_consume_all(&[*symbol], expect, &b_live_vars); + + b_live_vars.extend([symbol]); + + (expect, b_live_vars) + } + Expect { remainder, condition, @@ -1364,6 +1391,13 @@ pub fn collect_stmt( collect_stmt(cont, jp_live_vars, vars) } + Dbg { + symbol, remainder, .. + } => { + vars.insert(*symbol); + collect_stmt(remainder, jp_live_vars, vars) + } + Expect { condition, remainder, diff --git a/crates/compiler/mono/src/ir.rs b/crates/compiler/mono/src/ir.rs index 321adb8977..f400496344 100644 --- a/crates/compiler/mono/src/ir.rs +++ b/crates/compiler/mono/src/ir.rs @@ -27,7 +27,7 @@ use roc_late_solve::storage::{ExternalModuleStorage, ExternalModuleStorageSnapsh use roc_late_solve::{resolve_ability_specialization, AbilitiesView, Resolved, UnificationFailed}; use roc_module::ident::{ForeignSymbol, Lowercase, TagName}; use roc_module::low_level::LowLevel; -use roc_module::symbol::{IdentId, IdentIds, ModuleId, Symbol}; +use roc_module::symbol::{IdentIds, ModuleId, Symbol}; use roc_problem::can::{RuntimeError, ShadowKind}; use roc_region::all::{Loc, Region}; use roc_std::RocDec; @@ -1640,6 +1640,14 @@ pub enum Stmt<'a> { /// what happens after the expect remainder: &'a Stmt<'a>, }, + Dbg { + /// The expression we're displaying + symbol: Symbol, + /// The specialized variable of the expression + variable: Variable, + /// What happens after the dbg + remainder: &'a Stmt<'a>, + }, /// a join point `join f = in remainder` Join { id: JoinPointId, @@ -2230,6 +2238,15 @@ impl<'a> Stmt<'a> { .append(alloc.hardline()) .append(cont.to_doc(alloc, interner, pretty)), + Dbg { + symbol, remainder, .. + } => alloc + .text("dbg ") + .append(symbol_to_doc(alloc, *symbol, pretty)) + .append(";") + .append(alloc.hardline()) + .append(remainder.to_doc(alloc, interner, pretty)), + Expect { condition, remainder, @@ -6716,26 +6733,16 @@ pub fn from_can<'a>( .as_mut() .unwrap() .fresh_unnamed_flex_var(); - // HACK(dbg-spec-var): pass the specialized type variable along injected into a fake symbol - let dbg_spec_var_symbol = Symbol::new(ModuleId::ATTR, unsafe { - IdentId::from_index(spec_var.index()) - }); - // TODO: need to store the specialized variable of this dbg in the expectation_subs - let call = crate::ir::Call { - call_type: CallType::LowLevel { - op: LowLevel::Dbg, - update_mode: env.next_update_mode_id(), - }, - arguments: env.arena.alloc([dbg_symbol, dbg_spec_var_symbol]), + let dbg_stmt = Stmt::Dbg { + symbol: dbg_symbol, + variable: spec_var, + remainder: env.arena.alloc(rest), }; - let dbg_layout = layout_cache - .from_var(env.arena, variable, env.subs) - .expect("invalid dbg_layout"); - - let expr = Expr::Call(call); - let mut stmt = Stmt::Let(dbg_symbol, expr, dbg_layout, env.arena.alloc(rest)); + // Now that the dbg value has been specialized, export its specialized type into the + // expectations subs. + store_specialized_expectation_lookups(env, [variable], &[spec_var]); let symbol_is_reused = matches!( can_reuse_symbol(env, procs, &loc_condition.value, variable), @@ -6743,23 +6750,19 @@ pub fn from_can<'a>( ); // skip evaluating the condition if it's just a symbol - if !symbol_is_reused { - stmt = with_hole( + if symbol_is_reused { + dbg_stmt + } else { + with_hole( env, loc_condition.value, variable, procs, layout_cache, dbg_symbol, - env.arena.alloc(stmt), - ); + env.arena.alloc(dbg_stmt), + ) } - - // Now that the dbg value has been specialized, export its specialized type into the - // expectations subs. - store_specialized_expectation_lookups(env, [variable], &[spec_var]); - - stmt } LetRec(defs, cont, _cycle_mark) => { @@ -7138,6 +7141,23 @@ fn substitute_in_stmt_help<'a>( } } + Dbg { + symbol, + variable, + remainder, + } => { + let new_remainder = + substitute_in_stmt_help(arena, remainder, subs).unwrap_or(remainder); + + let expect = Dbg { + symbol: substitute(subs, *symbol).unwrap_or(*symbol), + variable: *variable, + remainder: new_remainder, + }; + + Some(arena.alloc(expect)) + } + Expect { condition, region, diff --git a/crates/compiler/mono/src/reset_reuse.rs b/crates/compiler/mono/src/reset_reuse.rs index a32a45520b..52957f4eb0 100644 --- a/crates/compiler/mono/src/reset_reuse.rs +++ b/crates/compiler/mono/src/reset_reuse.rs @@ -191,6 +191,27 @@ fn function_s<'a, 'i>( } } + Dbg { + symbol, + variable, + remainder, + } => { + let continuation: &Stmt = remainder; + let new_continuation = function_s(env, w, c, continuation); + + if std::ptr::eq(continuation, new_continuation) || continuation == new_continuation { + stmt + } else { + let new_refcounting = Dbg { + symbol: *symbol, + variable: *variable, + remainder: new_continuation, + }; + + arena.alloc(new_refcounting) + } + } + Expect { condition, region, @@ -438,6 +459,34 @@ fn function_d_main<'a, 'i>( } } + Dbg { + symbol, + variable, + remainder, + } => { + let (b, found) = function_d_main(env, x, c, remainder); + + if found || *symbol != x { + let refcounting = Dbg { + symbol: *symbol, + variable: *variable, + remainder: b, + }; + + (arena.alloc(refcounting), found) + } else { + let b = try_function_s(env, x, c, b); + + let refcounting = Dbg { + symbol: *symbol, + variable: *variable, + remainder: b, + }; + + (arena.alloc(refcounting), found) + } + } + Expect { condition, region, @@ -656,6 +705,22 @@ fn function_r<'a, 'i>(env: &mut Env<'a, 'i>, stmt: &'a Stmt<'a>) -> &'a Stmt<'a> arena.alloc(Refcounting(*modify_rc, b)) } + Dbg { + symbol, + variable, + remainder, + } => { + let b = function_r(env, remainder); + + let expect = Dbg { + symbol: *symbol, + variable: *variable, + remainder: b, + }; + + arena.alloc(expect) + } + Expect { condition, region, @@ -726,6 +791,9 @@ fn has_live_var<'a>(jp_live_vars: &JPLiveVarMap, stmt: &'a Stmt<'a>, needle: Sym Refcounting(modify_rc, cont) => { modify_rc.get_symbol() == needle || has_live_var(jp_live_vars, cont, needle) } + Dbg { + symbol, remainder, .. + } => *symbol == needle || has_live_var(jp_live_vars, remainder, needle), Expect { condition, remainder, diff --git a/crates/compiler/mono/src/tail_recursion.rs b/crates/compiler/mono/src/tail_recursion.rs index 64e1553e50..9a322b6834 100644 --- a/crates/compiler/mono/src/tail_recursion.rs +++ b/crates/compiler/mono/src/tail_recursion.rs @@ -249,6 +249,26 @@ fn insert_jumps<'a>( } } + Dbg { + symbol, + variable, + remainder, + } => match insert_jumps( + arena, + remainder, + goal_id, + needle, + needle_arguments, + needle_result, + ) { + Some(cont) => Some(arena.alloc(Dbg { + symbol: *symbol, + variable: *variable, + remainder: cont, + })), + None => None, + }, + Expect { condition, region,