mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 22:34:45 +00:00
Merge pull request #2977 from rtfeldman/debug_flags
Factor bespoke debug variables into debug_flags crate
This commit is contained in:
commit
3197cd97ce
13 changed files with 167 additions and 70 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -3540,6 +3540,10 @@ dependencies = [
|
|||
"roc_types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roc_debug_flags"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "roc_docs"
|
||||
version = "0.1.0"
|
||||
|
@ -3765,6 +3769,7 @@ dependencies = [
|
|||
"roc_can",
|
||||
"roc_collections",
|
||||
"roc_constrain",
|
||||
"roc_debug_flags",
|
||||
"roc_error_macros",
|
||||
"roc_module",
|
||||
"roc_mono",
|
||||
|
@ -3806,6 +3811,7 @@ dependencies = [
|
|||
"roc_builtins",
|
||||
"roc_can",
|
||||
"roc_collections",
|
||||
"roc_debug_flags",
|
||||
"roc_error_macros",
|
||||
"roc_exhaustive",
|
||||
"roc_module",
|
||||
|
@ -4004,6 +4010,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"bumpalo",
|
||||
"roc_collections",
|
||||
"roc_debug_flags",
|
||||
"roc_error_macros",
|
||||
"roc_module",
|
||||
"roc_region",
|
||||
|
@ -4017,6 +4024,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"bitflags",
|
||||
"roc_collections",
|
||||
"roc_debug_flags",
|
||||
"roc_error_macros",
|
||||
"roc_module",
|
||||
"roc_types",
|
||||
|
|
|
@ -26,6 +26,7 @@ members = [
|
|||
"compiler/arena_pool",
|
||||
"compiler/test_gen",
|
||||
"compiler/roc_target",
|
||||
"compiler/debug_flags",
|
||||
"vendor/ena",
|
||||
"vendor/inkwell",
|
||||
"vendor/pathfinding",
|
||||
|
|
|
@ -165,23 +165,19 @@ The compiler is invoked from the CLI via `build_file` in cli/src/build.rs
|
|||
|
||||
For a more detailed understanding of the compilation phases, see the `Phase`, `BuildTask`, and `Msg` enums in `load/src/file.rs`.
|
||||
|
||||
## Debugging intermediate representations
|
||||
## Debugging the compiler
|
||||
|
||||
### Debugging the typechecker
|
||||
Please see the [debug flags](./debug_flags/src/lib.rs) for information on how to
|
||||
ask the compiler to emit debug information during various stages of compilation.
|
||||
|
||||
Setting the following environment variables:
|
||||
There are some goals for more sophisticated debugging tools:
|
||||
|
||||
- `ROC_PRINT_UNIFICATIONS` prints all type unifications that are done,
|
||||
before and after the unification.
|
||||
- `ROC_PRINT_MISMATCHES` prints all type mismatches hit during unification.
|
||||
- `ROC_PRETTY_PRINT_ALIAS_CONTENTS` expands the contents of aliases during
|
||||
pretty-printing of types.
|
||||
- A nicer unification debugger, see https://github.com/rtfeldman/roc/issues/2486.
|
||||
Any interest in helping out here is greatly appreciated.
|
||||
|
||||
Note that this is only relevant during debug builds. Eventually we should have
|
||||
some better debugging tools here, see https://github.com/rtfeldman/roc/issues/2486
|
||||
for one.
|
||||
### General Tips
|
||||
|
||||
### The mono IR
|
||||
#### Miscompilations
|
||||
|
||||
If you observe a miscomplication, you may first want to check the generated mono
|
||||
IR for your code - maybe there was a problem during specialization or layout
|
||||
|
@ -189,13 +185,16 @@ generation. One way to do this is to add a test to `test_mono/src/tests.rs`
|
|||
and run the tests with `cargo test -p test_mono`; this will write the mono
|
||||
IR to a file.
|
||||
|
||||
You may also want to set some or all of the following environment variables:
|
||||
#### Typechecking errors
|
||||
|
||||
- `PRINT_IR_AFTER_SPECIALIZATION=1` prints the mono IR after function
|
||||
specialization to stdout
|
||||
- `PRINT_IR_AFTER_RESET_REUSE=1` prints the mono IR after insertion of
|
||||
reset/reuse isntructions to stdout
|
||||
- `PRINT_IR_AFTER_REFCOUNT=1` prints the mono IR after insertion of reference
|
||||
counting instructions to stdout
|
||||
- `PRETTY_PRINT_IR_SYMBOLS=1` instructs the pretty printer to dump all the
|
||||
information it knows about the mono IR whenever it is printed
|
||||
First, try to minimize your reproduction into a test that fits in
|
||||
[`solve_expr`](./solve/tests/solve_expr.rs).
|
||||
|
||||
Once you've done this, check out the `ROC_PRINT_UNIFICATIONS` debug flag. It
|
||||
will show you where type unification went right and wrong. This is usually
|
||||
enough to figure out a fix for the bug.
|
||||
|
||||
If that doesn't work and you know your error has something to do with ranks,
|
||||
you may want to instrument `deep_copy_var_help` in [solve](./solve/src/solve.rs).
|
||||
|
||||
If that doesn't work, chatting on Zulip is always a good strategy.
|
||||
|
|
6
compiler/debug_flags/Cargo.toml
Normal file
6
compiler/debug_flags/Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "roc_debug_flags"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
79
compiler/debug_flags/src/lib.rs
Normal file
79
compiler/debug_flags/src/lib.rs
Normal file
|
@ -0,0 +1,79 @@
|
|||
//! Flags for debugging the Roc compiler.
|
||||
//!
|
||||
//! Lists environment variable flags that can be enabled for verbose debugging features in debug
|
||||
//! builds of the compiler.
|
||||
//!
|
||||
//! For example, I might define the following alias to run cargo with all unifications and
|
||||
//! expanded type aliases printed:
|
||||
//!
|
||||
//! ```bash
|
||||
//! alias cargo="\
|
||||
//! ROC_PRINT_UNIFICATIONS=1 \
|
||||
//! ROC_PRETTY_PRINT_ALIAS_CONTENTS=1 \
|
||||
//! cargo"
|
||||
//! ```
|
||||
//!
|
||||
//! More generally, I have the following:
|
||||
//!
|
||||
//! ```bash
|
||||
//! alias cargo="\
|
||||
//! ROC_PRETTY_PRINT_ALIAS_CONTENTS=0 \
|
||||
//! ROC_PRINT_UNIFICATIONS=0 \
|
||||
//! ROC_PRINT_MISMATCHES=0 \
|
||||
//! ROC_PRINT_IR_AFTER_SPECIALIZATION=0 \
|
||||
//! ROC_PRINT_IR_AFTER_RESET_REUSE=0 \
|
||||
//! ROC_PRINT_IR_AFTER_REFCOUNT=0 \
|
||||
//! ROC_PRETTY_PRINT_IR_SYMBOLS=0 \
|
||||
//! cargo"
|
||||
//! ```
|
||||
//!
|
||||
//! Now you can turn debug flags on and off as you like.
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! dbg_do {
|
||||
($flag:path, $expr:expr) => {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
if std::env::var($flag).unwrap_or("0".to_string()) != "0" {
|
||||
$expr
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! flags {
|
||||
($($(#[doc = $doc:expr])+ $flag:ident)*) => {$(
|
||||
$(#[doc = $doc])+
|
||||
pub static $flag: &str = stringify!($flag);
|
||||
)*};
|
||||
}
|
||||
|
||||
flags! {
|
||||
// ===Types===
|
||||
|
||||
/// Expands the contents of aliases during pretty-printing of types.
|
||||
ROC_PRETTY_PRINT_ALIAS_CONTENTS
|
||||
|
||||
// ===Solve===
|
||||
|
||||
/// Prints type unifications, before and after they happen.
|
||||
ROC_PRINT_UNIFICATIONS
|
||||
|
||||
/// Prints all type mismatches hit during type unification.
|
||||
ROC_PRINT_MISMATCHES
|
||||
|
||||
// ===Mono===
|
||||
|
||||
/// Writes the mono IR to stderr after function specialization
|
||||
ROC_PRINT_IR_AFTER_SPECIALIZATION
|
||||
|
||||
/// Writes the mono IR to stderr after insertion of reset/reuse instructions
|
||||
ROC_PRINT_IR_AFTER_RESET_REUSE
|
||||
|
||||
/// Writes the mono IR to stderr after insertion of refcount instructions
|
||||
ROC_PRINT_IR_AFTER_REFCOUNT
|
||||
|
||||
/// Instructs the mono IR pretty printer to dump pretty symbols and verbose
|
||||
/// layout information
|
||||
ROC_PRETTY_PRINT_IR_SYMBOLS
|
||||
}
|
|
@ -21,6 +21,7 @@ roc_solve = { path = "../solve" }
|
|||
roc_mono = { path = "../mono" }
|
||||
roc_target = { path = "../roc_target" }
|
||||
roc_reporting = { path = "../../reporting" }
|
||||
roc_debug_flags = { path = "../debug_flags" }
|
||||
morphic_lib = { path = "../../vendor/morphic_lib" }
|
||||
ven_pretty = { path = "../../vendor/pretty" }
|
||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||
|
|
|
@ -15,6 +15,10 @@ use roc_constrain::module::{
|
|||
constrain_builtin_imports, constrain_module, ExposedByModule, ExposedForModule,
|
||||
ExposedModuleTypes,
|
||||
};
|
||||
use roc_debug_flags::{
|
||||
dbg_do, ROC_PRINT_IR_AFTER_REFCOUNT, ROC_PRINT_IR_AFTER_RESET_REUSE,
|
||||
ROC_PRINT_IR_AFTER_SPECIALIZATION,
|
||||
};
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::ident::{Ident, ModuleName, QualifiedModuleName};
|
||||
use roc_module::symbol::{
|
||||
|
@ -1627,13 +1631,10 @@ fn start_tasks<'a>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
fn debug_print_ir(state: &State, flag: &str) {
|
||||
if env::var(flag) != Ok("1".into()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let procs_string = state
|
||||
macro_rules! debug_print_ir {
|
||||
($state:expr, $flag:path) => {
|
||||
dbg_do!($flag, {
|
||||
let procs_string = $state
|
||||
.procedures
|
||||
.values()
|
||||
.map(|proc| proc.to_pretty(200))
|
||||
|
@ -1641,7 +1642,9 @@ fn debug_print_ir(state: &State, flag: &str) {
|
|||
|
||||
let result = procs_string.join("\n");
|
||||
|
||||
println!("{}", result);
|
||||
eprintln!("{}", result);
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
/// Report modules that are imported, but from which nothing is used
|
||||
|
@ -2181,8 +2184,7 @@ fn update<'a>(
|
|||
&& state.dependencies.solved_all()
|
||||
&& state.goal_phase == Phase::MakeSpecializations
|
||||
{
|
||||
#[cfg(debug_assertions)]
|
||||
debug_print_ir(&state, "PRINT_IR_AFTER_SPECIALIZATION");
|
||||
debug_print_ir!(state, ROC_PRINT_IR_AFTER_SPECIALIZATION);
|
||||
|
||||
Proc::insert_reset_reuse_operations(
|
||||
arena,
|
||||
|
@ -2192,13 +2194,11 @@ fn update<'a>(
|
|||
&mut state.procedures,
|
||||
);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
debug_print_ir(&state, "PRINT_IR_AFTER_RESET_REUSE");
|
||||
debug_print_ir!(state, ROC_PRINT_IR_AFTER_RESET_REUSE);
|
||||
|
||||
Proc::insert_refcount_operations(arena, &mut state.procedures);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
debug_print_ir(&state, "PRINT_IR_AFTER_REFCOUNT");
|
||||
debug_print_ir!(state, ROC_PRINT_IR_AFTER_REFCOUNT);
|
||||
|
||||
// This is not safe with the new non-recursive RC updates that we do for tag unions
|
||||
//
|
||||
|
|
|
@ -19,6 +19,7 @@ roc_problem = { path = "../problem" }
|
|||
roc_builtins = { path = "../builtins" }
|
||||
roc_target = { path = "../roc_target" }
|
||||
roc_error_macros = {path="../../error_macros"}
|
||||
roc_debug_flags = {path="../debug_flags"}
|
||||
ven_pretty = { path = "../../vendor/pretty" }
|
||||
morphic_lib = { path = "../../vendor/morphic_lib" }
|
||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||
|
|
|
@ -10,6 +10,7 @@ use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
|||
use roc_can::abilities::AbilitiesStore;
|
||||
use roc_can::expr::{AnnotatedMark, ClosureData, IntValue};
|
||||
use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap};
|
||||
use roc_debug_flags::{dbg_do, ROC_PRETTY_PRINT_IR_SYMBOLS};
|
||||
use roc_exhaustive::{Ctor, CtorName, Guard, RenderAs, TagId};
|
||||
use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
|
||||
use roc_module::low_level::LowLevel;
|
||||
|
@ -25,11 +26,11 @@ use roc_types::subs::{
|
|||
use std::collections::HashMap;
|
||||
use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder};
|
||||
|
||||
#[inline(always)]
|
||||
pub fn pretty_print_ir_symbols() -> bool {
|
||||
#[cfg(debug_assertions)]
|
||||
if std::env::var("PRETTY_PRINT_IR_SYMBOLS") == Ok("1".into()) {
|
||||
dbg_do!(ROC_PRETTY_PRINT_IR_SYMBOLS, {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
false
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ roc_collections = { path = "../collections" }
|
|||
roc_region = { path = "../region" }
|
||||
roc_module = { path = "../module" }
|
||||
roc_error_macros = {path="../../error_macros"}
|
||||
roc_debug_flags = {path="../debug_flags"}
|
||||
ven_ena = { path = "../../vendor/ena" }
|
||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||
static_assertions = "1.1.0"
|
||||
|
|
|
@ -449,15 +449,12 @@ fn write_content<'a>(
|
|||
);
|
||||
}
|
||||
|
||||
// useful for debugging
|
||||
if cfg!(debug_assertions)
|
||||
&& std::env::var("ROC_PRETTY_PRINT_ALIAS_CONTENTS").is_ok()
|
||||
{
|
||||
roc_debug_flags::dbg_do!(roc_debug_flags::ROC_PRETTY_PRINT_ALIAS_CONTENTS, {
|
||||
buf.push_str("[[ but really ");
|
||||
let content = subs.get_content_without_compacting(*_actual);
|
||||
write_content(env, ctx, content, subs, buf, parens);
|
||||
buf.push_str("]]");
|
||||
}
|
||||
});
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,3 +19,6 @@ path = "../module"
|
|||
|
||||
[dependencies.roc_types]
|
||||
path = "../types"
|
||||
|
||||
[dependencies.roc_debug_flags]
|
||||
path = "../debug_flags"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use bitflags::bitflags;
|
||||
use roc_debug_flags::{dbg_do, ROC_PRINT_MISMATCHES, ROC_PRINT_UNIFICATIONS};
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::ident::{Lowercase, TagName};
|
||||
use roc_module::symbol::Symbol;
|
||||
|
@ -11,14 +12,14 @@ use roc_types::types::{AliasKind, DoesNotImplementAbility, ErrorType, Mismatch,
|
|||
|
||||
macro_rules! mismatch {
|
||||
() => {{
|
||||
if cfg!(debug_assertions) && std::env::var("ROC_PRINT_MISMATCHES").is_ok() {
|
||||
println!(
|
||||
dbg_do!(ROC_PRINT_MISMATCHES, {
|
||||
eprintln!(
|
||||
"Mismatch in {} Line {} Column {}",
|
||||
file!(),
|
||||
line!(),
|
||||
column!()
|
||||
);
|
||||
}
|
||||
})
|
||||
|
||||
Outcome {
|
||||
mismatches: vec![Mismatch::TypeMismatch],
|
||||
|
@ -26,17 +27,16 @@ macro_rules! mismatch {
|
|||
}
|
||||
}};
|
||||
($msg:expr) => {{
|
||||
if cfg!(debug_assertions) && std::env::var("ROC_PRINT_MISMATCHES").is_ok() {
|
||||
println!(
|
||||
dbg_do!(ROC_PRINT_MISMATCHES, {
|
||||
eprintln!(
|
||||
"Mismatch in {} Line {} Column {}",
|
||||
file!(),
|
||||
line!(),
|
||||
column!()
|
||||
);
|
||||
println!($msg);
|
||||
println!("");
|
||||
}
|
||||
|
||||
eprintln!($msg);
|
||||
eprintln!("");
|
||||
});
|
||||
|
||||
Outcome {
|
||||
mismatches: vec![Mismatch::TypeMismatch],
|
||||
|
@ -47,16 +47,16 @@ macro_rules! mismatch {
|
|||
mismatch!($msg)
|
||||
}};
|
||||
($msg:expr, $($arg:tt)*) => {{
|
||||
if cfg!(debug_assertions) && std::env::var("ROC_PRINT_MISMATCHES").is_ok() {
|
||||
println!(
|
||||
dbg_do!(ROC_PRINT_MISMATCHES, {
|
||||
eprintln!(
|
||||
"Mismatch in {} Line {} Column {}",
|
||||
file!(),
|
||||
line!(),
|
||||
column!()
|
||||
);
|
||||
println!($msg, $($arg)*);
|
||||
println!("");
|
||||
}
|
||||
eprintln!($msg, $($arg)*);
|
||||
eprintln!("");
|
||||
});
|
||||
|
||||
Outcome {
|
||||
mismatches: vec![Mismatch::TypeMismatch],
|
||||
|
@ -64,16 +64,16 @@ macro_rules! mismatch {
|
|||
}
|
||||
}};
|
||||
(%not_able, $var:expr, $ability:expr, $msg:expr, $($arg:tt)*) => {{
|
||||
if cfg!(debug_assertions) && std::env::var("ROC_PRINT_MISMATCHES").is_ok() {
|
||||
println!(
|
||||
dbg_do!(ROC_PRINT_MISMATCHES, {
|
||||
eprintln!(
|
||||
"Mismatch in {} Line {} Column {}",
|
||||
file!(),
|
||||
line!(),
|
||||
column!()
|
||||
);
|
||||
println!($msg, $($arg)*);
|
||||
println!("");
|
||||
}
|
||||
eprintln!($msg, $($arg)*);
|
||||
eprintln!("");
|
||||
});
|
||||
|
||||
Outcome {
|
||||
mismatches: vec![Mismatch::TypeMismatch, Mismatch::DoesNotImplementAbiity($var, $ability)],
|
||||
|
@ -298,7 +298,7 @@ fn debug_print_unified_types(subs: &mut Subs, ctx: &Context, opt_outcome: Option
|
|||
|
||||
static mut UNIFICATION_DEPTH: usize = 0;
|
||||
|
||||
if std::env::var("ROC_PRINT_UNIFICATIONS").is_ok() {
|
||||
dbg_do!(ROC_PRINT_UNIFICATIONS, {
|
||||
let prefix = match opt_outcome {
|
||||
None => "❔",
|
||||
Some(outcome) if outcome.mismatches.is_empty() => "✅",
|
||||
|
@ -340,7 +340,7 @@ fn debug_print_unified_types(subs: &mut Subs, ctx: &Context, opt_outcome: Option
|
|||
);
|
||||
|
||||
unsafe { UNIFICATION_DEPTH = new_depth };
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn unify_context(subs: &mut Subs, pool: &mut Pool, ctx: Context) -> Outcome {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue