flux_common/
dbg.rs

1//! This file contains functions and macros to log debugging information meant for developers.
2use std::{
3    fmt, fs,
4    io::{self, Write},
5};
6
7use flux_config as config;
8use flux_macros::DebugAsJson;
9use rustc_hir::def_id::DefId;
10use rustc_middle::ty::TyCtxt;
11use rustc_span::Span;
12use serde::Serialize;
13
14#[derive(Serialize, DebugAsJson)]
15pub struct SpanTrace {
16    file: Option<String>,
17    start_line: usize,
18    start_col: usize,
19    end_line: usize,
20    end_col: usize,
21}
22
23impl SpanTrace {
24    fn span_file(tcx: TyCtxt, span: Span) -> Option<String> {
25        let sm = tcx.sess.source_map();
26        let current_dir = &tcx.sess.opts.working_dir;
27        let current_dir = current_dir.local_path()?;
28        if let rustc_span::FileName::Real(file_name) = sm.span_to_filename(span) {
29            let file_path = file_name.local_path()?;
30            let full_path = current_dir.join(file_path);
31            Some(full_path.display().to_string())
32        } else {
33            None
34        }
35    }
36    pub fn new(tcx: TyCtxt, span: Span) -> Self {
37        let sm = tcx.sess.source_map();
38        let (_, start_line, start_col, end_line, end_col) = sm.span_to_location_info(span);
39        let file = SpanTrace::span_file(tcx, span);
40        SpanTrace { file, start_line, start_col, end_line, end_col }
41    }
42}
43
44pub fn writer_for_item(
45    tcx: TyCtxt,
46    def_id: DefId,
47    ext: impl AsRef<str>,
48) -> io::Result<impl io::Write> {
49    fs::create_dir_all(config::log_dir())?;
50    let path = config::log_dir().join(dump_base_name(tcx, def_id, ext));
51    let file = fs::File::create(path)?;
52    let buf = std::io::BufWriter::new(file);
53    Ok(buf)
54}
55
56pub fn dump_item_info<T: fmt::Debug>(
57    tcx: TyCtxt,
58    def_id: impl Into<DefId>,
59    ext: impl AsRef<str>,
60    val: T,
61) -> io::Result<()> {
62    let mut writer = writer_for_item(tcx, def_id.into(), ext)?;
63    writeln!(writer, "{val:#?}")
64}
65
66#[macro_export]
67macro_rules! _shape_mode_span {
68    ($tcx:expr, $def_id:expr) => {{
69        let path = $tcx.def_path_str(rustc_hir::def_id::DefId::from($def_id));
70        tracing::info_span!("shape", def_id = path.as_str())
71    }};
72}
73pub use crate::_shape_mode_span as shape_mode_span;
74
75#[macro_export]
76macro_rules! _refine_mode_span {
77    ($tcx:expr, $def_id:expr, $bb_envs:expr) => {{
78        let path = $tcx.def_path_str(rustc_hir::def_id::DefId::from($def_id));
79        tracing::info_span!("refine", def_id = path.as_str(), bb_envs = ?$bb_envs)
80    }};
81}
82pub use crate::_refine_mode_span as refine_mode_span;
83
84#[macro_export]
85macro_rules! _check_fn_span {
86    ($tcx:expr, $def_id:expr) => {{
87        let path = $tcx.def_path_str(rustc_hir::def_id::DefId::from($def_id));
88        tracing::info_span!("check_fn", def_id = path.as_str())
89    }};
90}
91pub use crate::_check_fn_span as check_fn_span;
92
93#[macro_export]
94macro_rules! _basic_block_start {
95    ($bb:expr, $rcx:expr, $env:expr) => {{
96        tracing::debug!(event = "basic_block_start", bb = ?$bb, rcx = ?$rcx, env = ?$env)
97    }};
98}
99pub use crate::_basic_block_start as basic_block_start;
100
101#[macro_export]
102macro_rules! _solution {
103    ($genv:expr, $sol:expr, $span:expr) => {{
104        if config::dump_checker_trace_info() {
105          let genv = $genv;
106          let sol_json = SolutionTrace::new(genv, $sol);
107          let span_json = SpanTrace::new(genv.tcx(), $span);
108          tracing::info!(event = "solution", span = ?span_json, solution = ?sol_json)
109        }
110    }};
111}
112pub use crate::_solution as solution;
113
114#[macro_export]
115macro_rules! _statement{
116    ($pos:literal, $stmt:expr, $infcx:expr, $env:expr, $span:expr, $checker:expr) => {{
117        if config::dump_checker_trace_info() {
118          let rcx = $infcx.cursor();
119          let ck = $checker;
120          let genv = ck.genv;
121          let local_names = &ck.body.local_names;
122          let local_decls = &ck.body.local_decls;
123          let rcx_json = RefineCtxtTrace::new(genv, rcx);
124          let env_json = TypeEnvTrace::new(genv, local_names, local_decls, $env);
125          let span_json = SpanTrace::new(genv.tcx(), $span);
126          tracing::info!(event = concat!("statement_", $pos), stmt = ?$stmt, stmt_span = ?$span, rcx = ?rcx, env = ?$env, rcx_json = ?rcx_json, env_json = ?env_json, stmt_span_json = ?span_json)
127        }
128    }};
129}
130pub use crate::_statement as statement;
131
132#[macro_export]
133macro_rules! _terminator{
134    ($pos:literal, $terminator:expr, $rcx:expr, $env:expr) => {{
135        tracing::debug!(event = concat!("terminator_", $pos), terminator = ?$terminator, rcx = ?$rcx, env = ?$env)
136    }};
137}
138pub use crate::_terminator as terminator;
139
140#[macro_export]
141macro_rules! _refine_goto {
142    ($target:expr, $rcx:expr, $env:expr, $bb_env:expr) => {{
143        tracing::debug!(event = "refine_goto", target = ?$target, rcx = ?$rcx, env = ?$env, bb_env = ?$bb_env)
144    }};
145}
146pub use crate::_refine_goto as refine_goto;
147
148#[macro_export]
149macro_rules! _shape_goto_enter {
150    ($target:expr, $env:expr, $bb_env:expr) => {{
151        if let Some(bb_env) = &$bb_env {
152            tracing::debug!(event = "shape_goto_enter", target = ?$target, env = ?&$env, ?bb_env)
153        } else {
154            tracing::debug!(event = "shape_goto_enter", target = ?$target, env = ?&$env, bb_env = "empty")
155        }
156    }};
157}
158pub use crate::_shape_goto_enter as shape_goto_enter;
159
160#[macro_export]
161macro_rules! _shape_goto_exit {
162    ($target:expr, $bb_env:expr) => {{
163        tracing::debug!(event = "shape_goto_exit", target = ?$target, bb_env = ?&$bb_env)
164    }};
165}
166pub use crate::_shape_goto_exit as shape_goto_exit;
167
168#[macro_export]
169macro_rules! _hyperlink {
170    ($tcx:expr, $src_span:expr, $dst_span:expr) => {{
171       let src_json = SpanTrace::new($tcx, $src_span);
172       let dst_json = SpanTrace::new($tcx, $dst_span);
173       tracing::warn!(event = "hyperlink", src_span = ?src_json, dst_span = ?dst_json)
174    }};
175}
176pub use crate::_hyperlink as hyperlink;
177
178fn dump_base_name(tcx: TyCtxt, def_id: DefId, ext: impl AsRef<str>) -> String {
179    let crate_name = tcx.crate_name(def_id.krate);
180    let item_name = tcx.def_path(def_id).to_filename_friendly_no_crate();
181    format!("{crate_name}.{item_name}.{}", ext.as_ref())
182}
183
184#[macro_export]
185macro_rules! _debug_assert_eq3 {
186    ($e1:expr, $e2:expr, $e3:expr) => {{
187        debug_assert!($e1 == $e2 && $e2 == $e3, "{:?} != {:?} != {:?}", $e1, $e2, $e3);
188    }};
189}
190pub use crate::_debug_assert_eq3 as debug_assert_eq3;