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! _statement{
103    ($pos:literal, $stmt:expr, $infcx:expr, $env:expr, $span:expr, $checker:expr) => {{
104        if let Some(level) = config::dump_checker_trace() && level <= tracing::Level::INFO {
105          let rcx = $infcx.cursor();
106          let ck = $checker;
107          let genv = ck.genv;
108          let local_names = &ck.body.local_names;
109          let local_decls = &ck.body.local_decls;
110          let rcx_json = RefineCtxtTrace::new(genv, rcx);
111          let env_json = TypeEnvTrace::new(genv, local_names, local_decls, $env);
112          let span_json = SpanTrace::new(genv.tcx(), $span);
113          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)
114        }
115    }};
116}
117pub use crate::_statement as statement;
118
119#[macro_export]
120macro_rules! _terminator{
121    ($pos:literal, $terminator:expr, $rcx:expr, $env:expr) => {{
122        tracing::debug!(event = concat!("terminator_", $pos), terminator = ?$terminator, rcx = ?$rcx, env = ?$env)
123    }};
124}
125pub use crate::_terminator as terminator;
126
127#[macro_export]
128macro_rules! _refine_goto {
129    ($target:expr, $rcx:expr, $env:expr, $bb_env:expr) => {{
130        tracing::debug!(event = "refine_goto", target = ?$target, rcx = ?$rcx, env = ?$env, bb_env = ?$bb_env)
131    }};
132}
133pub use crate::_refine_goto as refine_goto;
134
135#[macro_export]
136macro_rules! _shape_goto_enter {
137    ($target:expr, $env:expr, $bb_env:expr) => {{
138        if let Some(bb_env) = &$bb_env {
139            tracing::debug!(event = "shape_goto_enter", target = ?$target, env = ?&$env, ?bb_env)
140        } else {
141            tracing::debug!(event = "shape_goto_enter", target = ?$target, env = ?&$env, bb_env = "empty")
142        }
143    }};
144}
145pub use crate::_shape_goto_enter as shape_goto_enter;
146
147#[macro_export]
148macro_rules! _shape_goto_exit {
149    ($target:expr, $bb_env:expr) => {{
150        tracing::debug!(event = "shape_goto_exit", target = ?$target, bb_env = ?&$bb_env)
151    }};
152}
153pub use crate::_shape_goto_exit as shape_goto_exit;
154
155#[macro_export]
156macro_rules! _hyperlink {
157    ($tcx:expr, $src_span:expr, $dst_span:expr) => {{
158       let src_json = SpanTrace::new($tcx, $src_span);
159       let dst_json = SpanTrace::new($tcx, $dst_span);
160       tracing::warn!(event = "hyperlink", src_span = ?src_json, dst_span = ?dst_json)
161    }};
162}
163pub use crate::_hyperlink as hyperlink;
164
165fn dump_base_name(tcx: TyCtxt, def_id: DefId, ext: impl AsRef<str>) -> String {
166    let crate_name = tcx.crate_name(def_id.krate);
167    let item_name = tcx.def_path(def_id).to_filename_friendly_no_crate();
168    format!("{crate_name}.{item_name}.{}", ext.as_ref())
169}
170
171#[macro_export]
172macro_rules! _debug_assert_eq3 {
173    ($e1:expr, $e2:expr, $e3:expr) => {{
174        debug_assert!($e1 == $e2 && $e2 == $e3, "{:?} != {:?} != {:?}", $e1, $e2, $e3);
175    }};
176}
177pub use crate::_debug_assert_eq3 as debug_assert_eq3;