Skip to main content

flux_middle/
pretty.rs

1use std::{cell::RefCell, fmt};
2
3use flux_arc_interner::{Internable, Interned};
4use flux_common::index::IndexGen;
5use flux_config as config;
6use rustc_abi::FieldIdx;
7use rustc_data_structures::unord::{UnordMap, UnordSet};
8use rustc_hir::def_id::DefId;
9use rustc_index::newtype_index;
10use rustc_middle::ty::TyCtxt;
11use rustc_span::{Pos, Span};
12use rustc_type_ir::{BoundVar, DebruijnIndex, INNERMOST};
13use serde::Serialize;
14
15#[macro_export]
16macro_rules! _with_cx {
17    ($cx:expr, $e:expr) => {
18        $crate::pretty::WithCx::new($cx, $e)
19    };
20}
21pub use crate::_with_cx as with_cx;
22use crate::def_id::{FluxDefId, FluxLocalDefId};
23
24#[macro_export]
25macro_rules! _format_args_cx {
26    ($cx:ident, $fmt:literal, $($args:tt)*) => {
27        $crate::_format_args_cx!(@go ($cx, $fmt; $($args)*) -> ())
28    };
29    ($cx:expr, $fmt:literal) => {
30        format_args!($fmt)
31    };
32    (@go ($cx:ident, $fmt:literal; ^$head:expr, $($tail:tt)*) -> ($($accum:tt)*)) => {
33        $crate::_format_args_cx!(@go ($cx, $fmt; $($tail)*) -> ($($accum)* $head,))
34    };
35    (@go ($cx:ident, $fmt:literal; $head:expr, $($tail:tt)*) -> ($($accum:tt)*)) => {
36        $crate::_format_args_cx!(@go ($cx, $fmt; $($tail)*) -> ($($accum)* $crate::pretty::with_cx!($cx, $head),))
37    };
38    (@go ($cx:ident, $fmt:literal; ^$head:expr) -> ($($accum:tt)*)) => {
39        $crate::_format_args_cx!(@as_expr format_args!($fmt, $($accum)* $head,))
40    };
41    (@go ($cx:ident, $fmt:literal; $head:expr) -> ($($accum:tt)*)) => {
42        $crate::_format_args_cx!(@as_expr format_args!($fmt, $($accum)* $crate::pretty::with_cx!($cx, $head),))
43    };
44    (@as_expr $e:expr) => { $e };
45}
46pub use crate::_format_args_cx as format_args_cx;
47
48#[macro_export]
49macro_rules! _format_cx {
50    ($($arg:tt)*) => {
51        std::fmt::format($crate::_format_args_cx!($($arg)*))
52    }
53}
54pub use crate::_format_cx as format_cx;
55
56#[macro_export]
57macro_rules! _w {
58    ($cx:expr, $f:expr, $fmt:literal, $($args:tt)*) => {{
59        #[allow(unused_variables)]
60        let cx = $cx;
61        $f.write_fmt($crate::_format_args_cx!(cx, $fmt, $($args)*))
62    }};
63    ($cx:expr, $f:expr, $fmt:literal) => {
64        $f.write_fmt($crate::_format_args_cx!($cx, $fmt))
65    };
66}
67pub use crate::_w as w;
68
69#[macro_export]
70macro_rules! _join {
71    ($sep:expr, $iter:expr) => {
72        $crate::pretty::Join::new($sep, $iter)
73    };
74}
75pub use crate::_join as join;
76
77#[macro_export]
78macro_rules! _parens {
79    ($val:expr, $parenthesize:expr) => {
80        $crate::pretty::Parens::new(&$val, $parenthesize)
81    };
82}
83pub use crate::_parens as parens;
84
85#[macro_export]
86macro_rules! _impl_debug_with_default_cx {
87    ($($ty:ty $(=> $key:literal)?),* $(,)?) => {$(
88        impl std::fmt::Debug for $ty  {
89            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90                #[allow(unused_mut, unused_assignments)]
91                let mut key = None;
92                $(
93                    key = Some($key);
94                )?
95                $crate::pretty::pprint_with_default_cx(f, self, key)
96            }
97        }
98    )*};
99}
100
101pub fn pprint_with_default_cx<T: Pretty>(
102    f: &mut std::fmt::Formatter<'_>,
103    t: &T,
104    cfg_key: Option<&'static str>,
105) -> std::fmt::Result {
106    rustc_middle::ty::tls::with(|tcx| {
107        #[allow(unused_mut)]
108        let mut cx = <T>::default_cx(tcx);
109
110        if let Some(pprint) = flux_config::CONFIG_FILE
111            .get("dev")
112            .and_then(|dev| dev.get("pprint"))
113        {
114            if let Some(opts) = pprint.get("default") {
115                cx.merge(opts);
116            }
117
118            if let Some(key) = cfg_key
119                && let Some(opts) = pprint.get(key)
120            {
121                cx.merge(opts);
122            }
123        }
124
125        if let Some(key) = cfg_key
126            && let Some(opts) = flux_config::CONFIG_FILE
127                .get("dev")
128                .and_then(|dev| dev.get("pprint"))
129                .and_then(|pprint| pprint.get(key))
130        {
131            cx.merge(opts);
132        }
133        Pretty::fmt(t, &cx, f)
134    })
135}
136
137pub use crate::_impl_debug_with_default_cx as impl_debug_with_default_cx;
138use crate::{
139    global_env::GlobalEnv,
140    rty::{
141        AdtSortDef, BoundReft, BoundReftKind, BoundVariableKind, BoundVariableKinds,
142        EarlyReftParam, Name, PrettyMap,
143    },
144};
145
146#[derive(Copy, Clone)]
147pub enum KVarArgs {
148    All,
149    SelfOnly,
150    Hide,
151}
152
153#[derive(Clone, Copy)]
154pub enum GenvOrTcx<'genv, 'tcx> {
155    Genv(GlobalEnv<'genv, 'tcx>),
156    Tcx(TyCtxt<'tcx>),
157}
158
159impl<'genv, 'tcx> GenvOrTcx<'genv, 'tcx> {
160    fn tcx(self) -> TyCtxt<'tcx> {
161        match self {
162            GenvOrTcx::Genv(genv) => genv.tcx(),
163            GenvOrTcx::Tcx(tcx) => tcx,
164        }
165    }
166
167    fn genv(self) -> Option<GlobalEnv<'genv, 'tcx>> {
168        match self {
169            GenvOrTcx::Genv(genv) => Some(genv),
170            GenvOrTcx::Tcx(_) => None,
171        }
172    }
173}
174
175impl<'tcx> From<TyCtxt<'tcx>> for GenvOrTcx<'_, 'tcx> {
176    fn from(v: TyCtxt<'tcx>) -> Self {
177        Self::Tcx(v)
178    }
179}
180
181impl<'genv, 'tcx> From<GlobalEnv<'genv, 'tcx>> for GenvOrTcx<'genv, 'tcx> {
182    fn from(v: GlobalEnv<'genv, 'tcx>) -> Self {
183        Self::Genv(v)
184    }
185}
186
187pub struct PrettyCx<'genv, 'tcx> {
188    pub cx: GenvOrTcx<'genv, 'tcx>,
189    pub kvar_args: KVarArgs,
190    pub fully_qualified_paths: bool,
191    pub simplify_exprs: bool,
192    pub tags: bool,
193    pub bindings_chain: bool,
194    pub preds_chain: bool,
195    pub full_spans: bool,
196    pub hide_uninit: bool,
197    pub hide_refinements: bool,
198    pub hide_regions: bool,
199    pub hide_sorts: bool,
200    pub hide_default_args: bool,
201    pub pretty_var_env: PrettyMap<Name>,
202    pub bvar_env: BoundVarEnv,
203    pub earlyparam_env: RefCell<Option<EarlyParamEnv>>,
204}
205
206macro_rules! set_opts {
207    ($cx:expr, $opts:expr, [$($opt:ident),+ $(,)?]) => {
208        $(
209        if let Some(val) = $opts.get(stringify!($opt)).and_then(|v| FromOpt::from_opt(v)) {
210            $cx.$opt = val;
211        }
212        )+
213    };
214}
215
216impl<'genv, 'tcx> PrettyCx<'genv, 'tcx> {
217    pub fn default(cx: impl Into<GenvOrTcx<'genv, 'tcx>>) -> Self {
218        PrettyCx {
219            cx: cx.into(),
220            kvar_args: KVarArgs::SelfOnly,
221            fully_qualified_paths: false,
222            simplify_exprs: true,
223            tags: true,
224            bindings_chain: true,
225            preds_chain: true,
226            full_spans: false,
227            hide_uninit: true,
228            hide_refinements: false,
229            hide_regions: false,
230            hide_sorts: true,
231            hide_default_args: true,
232            pretty_var_env: PrettyMap::new(),
233            bvar_env: BoundVarEnv::default(),
234            earlyparam_env: RefCell::new(None),
235        }
236    }
237
238    pub fn tcx(&self) -> TyCtxt<'tcx> {
239        self.cx.tcx()
240    }
241
242    pub fn genv(&self) -> Option<GlobalEnv<'genv, 'tcx>> {
243        self.cx.genv()
244    }
245
246    pub fn adt_sort_def_of(&self, def_id: DefId) -> Option<AdtSortDef> {
247        self.genv()
248            .and_then(|genv| genv.adt_sort_def_of(def_id).ok())
249    }
250
251    pub fn merge(&mut self, opts: &config::Value) {
252        set_opts!(
253            self,
254            opts,
255            [
256                kvar_args,
257                fully_qualified_paths,
258                simplify_exprs,
259                tags,
260                bindings_chain,
261                preds_chain,
262                full_spans,
263                hide_uninit,
264                hide_refinements,
265                hide_regions,
266                hide_sorts,
267                hide_default_args,
268            ]
269        );
270    }
271
272    pub fn with_bound_vars<R>(&self, vars: &[BoundVariableKind], f: impl FnOnce() -> R) -> R {
273        self.bvar_env.push_layer(vars, UnordSet::new(), None);
274        let r = f();
275        self.bvar_env.pop_layer();
276        r
277    }
278
279    pub fn with_bound_vars_removable<T>(
280        &self,
281        vars: &[BoundVariableKind],
282        vars_to_remove: UnordSet<BoundVar>,
283        fn_root_layer_type: Option<FnRootLayerType>,
284        fmt: impl FnOnce() -> Result<T, fmt::Error>,
285    ) -> Result<T, fmt::Error> {
286        self.bvar_env
287            .push_layer(vars, vars_to_remove, fn_root_layer_type);
288        // We need to be careful when rendering the vars to _not_
289        // refer to the `vars_to_remove` in the context since it'll
290        // still be there. If we remove the layer, then the vars
291        // won't render accurately.
292        //
293        // For now, this should be fine, though.
294        let r = fmt()?;
295        self.bvar_env.pop_layer();
296        Ok(r)
297    }
298
299    pub fn fmt_bound_vars(
300        &self,
301        print_infer_mode: bool,
302        left: &str,
303        vars: &[BoundVariableKind],
304        right: &str,
305        f: &mut impl fmt::Write,
306    ) -> fmt::Result {
307        w!(self, f, "{left}")?;
308        for (i, var) in vars.iter().enumerate() {
309            if i > 0 {
310                w!(self, f, ", ")?;
311            }
312            match var {
313                BoundVariableKind::Region(re) => w!(self, f, "{:?}", re)?,
314                BoundVariableKind::Refine(sort, mode, BoundReftKind::Named(name)) => {
315                    if print_infer_mode {
316                        w!(self, f, "{}", ^mode.prefix_str())?;
317                    }
318                    w!(self, f, "{}", ^name)?;
319                    if !self.hide_sorts {
320                        w!(self, f, ": {:?}", sort)?;
321                    }
322                }
323                BoundVariableKind::Refine(sort, mode, BoundReftKind::Anon) => {
324                    if print_infer_mode {
325                        w!(self, f, "{}", ^mode.prefix_str())?;
326                    }
327                    if let Some(name) = self.bvar_env.lookup(INNERMOST, BoundVar::from_usize(i)) {
328                        w!(self, f, "{:?}", ^name)?;
329                    } else {
330                        w!(self, f, "_")?;
331                    }
332                    if !self.hide_sorts {
333                        w!(self, f, ": {:?}", sort)?;
334                    }
335                }
336            }
337        }
338        w!(self, f, "{right}")
339    }
340
341    pub fn fmt_bound_reft(
342        &self,
343        debruijn: DebruijnIndex,
344        breft: BoundReft,
345        f: &mut fmt::Formatter<'_>,
346    ) -> fmt::Result {
347        match breft.kind {
348            BoundReftKind::Anon => {
349                if let Some(name) = self.bvar_env.lookup(debruijn, breft.var) {
350                    w!(self, f, "{name:?}")
351                } else {
352                    w!(self, f, "⭡{}/#{:?}", ^debruijn.as_usize(), ^breft.var)
353                }
354            }
355            BoundReftKind::Named(name) => {
356                w!(self, f, "{name}")
357            }
358        }
359    }
360
361    pub fn with_early_params<R>(&self, f: impl FnOnce() -> R) -> R {
362        assert!(self.earlyparam_env.borrow().is_none(), "Already in an early param env");
363        *self.earlyparam_env.borrow_mut() = Some(UnordSet::new());
364        let r = f();
365        *self.earlyparam_env.borrow_mut() = None;
366        r
367    }
368
369    pub fn kvar_args(self, kvar_args: KVarArgs) -> Self {
370        Self { kvar_args, ..self }
371    }
372
373    pub fn fully_qualified_paths(self, b: bool) -> Self {
374        Self { fully_qualified_paths: b, ..self }
375    }
376
377    pub fn hide_regions(self, b: bool) -> Self {
378        Self { hide_regions: b, ..self }
379    }
380
381    pub fn hide_sorts(self, b: bool) -> Self {
382        Self { hide_sorts: b, ..self }
383    }
384
385    pub fn hide_refinements(self, b: bool) -> Self {
386        Self { hide_refinements: b, ..self }
387    }
388
389    pub fn show_kvar_args(self) -> Self {
390        Self { kvar_args: KVarArgs::All, ..self }
391    }
392
393    pub fn nested_with_bound_vars(
394        &self,
395        left: &str,
396        vars: &[BoundVariableKind],
397        right: Option<String>,
398        f: impl FnOnce(String) -> Result<NestedString, fmt::Error>,
399    ) -> Result<NestedString, fmt::Error> {
400        let mut buffer = String::new();
401        self.with_bound_vars(vars, || {
402            if !vars.is_empty() {
403                let right = right.unwrap_or(". ".to_string());
404                self.fmt_bound_vars(false, left, vars, &right, &mut buffer)?;
405            }
406            f(buffer)
407        })
408    }
409}
410
411newtype_index! {
412    /// Name used during pretty printing to format anonymous bound variables
413    #[debug_format = "b{}"]
414    pub struct BoundVarName {}
415}
416
417#[derive(Copy, Clone)]
418pub enum FnRootLayerType {
419    FnArgs,
420    FnRet,
421}
422
423#[derive(Clone)]
424pub struct FnRootLayerMap {
425    pub name_map: UnordMap<BoundVar, BoundVarName>,
426    pub seen_vars: UnordSet<BoundVar>,
427    pub layer_type: FnRootLayerType,
428}
429
430#[derive(Clone)]
431pub struct BoundVarLayer {
432    pub layer_map: BoundVarLayerMap,
433    pub vars_to_remove: UnordSet<BoundVar>,
434    pub successfully_removed_vars: UnordSet<BoundVar>,
435}
436
437impl BoundVarLayer {
438    pub fn filter_vars(&self, vars: &BoundVariableKinds) -> Vec<BoundVariableKind> {
439        vars.into_iter()
440            .enumerate()
441            .filter_map(|(idx, var)| {
442                let bvar = BoundVar::from_usize(idx);
443
444                if !matches!(var, BoundVariableKind::Refine(..)) {
445                    return None;
446                }
447                if self.successfully_removed_vars.contains(&bvar) {
448                    return None;
449                }
450                if let BoundVarLayerMap::FnRootLayerMap(fn_root_layer) = &self.layer_map
451                    && fn_root_layer.seen_vars.contains(&bvar)
452                {
453                    return None;
454                }
455
456                Some(var.clone())
457            })
458            .collect()
459    }
460}
461
462#[derive(Clone)]
463pub enum BoundVarLayerMap {
464    LayerMap(UnordMap<BoundVar, BoundVarName>),
465    /// We treat vars at the function root differently. The UnordMap
466    /// functions the same as in a regular layer (i.e. giving names to
467    /// anonymous bound vars), but we additionally track a set of
468    /// boundvars that have been seen previously.
469    ///
470    /// This set is used to render a signature like
471    ///
472    ///     fn(usize[@n], usize[n]) -> usize[#m] ensures m > 0
473    ///
474    /// The first time we visit `n`, we'll add the `@`, but the second
475    /// time we'll track that we've seen it and won't.
476    ///
477    /// We do the same thing for `m` but with a different layer.
478    ///
479    /// This is a behavior we _only_ do for bound vars at the fn root level.
480    FnRootLayerMap(FnRootLayerMap),
481}
482
483impl BoundVarLayerMap {
484    fn get(&self, bvar: BoundVar) -> Option<BoundVarName> {
485        match self {
486            Self::LayerMap(name_map) => name_map,
487            Self::FnRootLayerMap(root_layer) => &root_layer.name_map,
488        }
489        .get(&bvar)
490        .copied()
491    }
492}
493
494#[derive(Default)]
495pub struct BoundVarEnv {
496    name_gen: IndexGen<BoundVarName>,
497    layers: RefCell<Vec<BoundVarLayer>>,
498}
499
500impl BoundVarEnv {
501    /// Checks if a variable is
502    /// 1. In the function root layer (`Some(..)` if so, `None` otherwise)
503    /// 2. Has been seen before (the `bool` inside of the `Some(..)`)
504    /// 3. At the args or ret layer type (the `FnRootLayerType` inside of the `Some(..)`)
505    ///
506    /// It updates the set of seen variables at the function root layer when it
507    /// does the check.
508    pub fn check_if_seen_fn_root_bvar(
509        &self,
510        debruijn: DebruijnIndex,
511        var: BoundVar,
512    ) -> Option<(bool, FnRootLayerType)> {
513        let num_layers = self.layers.borrow().len();
514        let mut layer = self.layers.borrow_mut();
515        match layer.get_mut(num_layers.checked_sub(debruijn.as_usize() + 1)?)? {
516            BoundVarLayer {
517                layer_map: BoundVarLayerMap::FnRootLayerMap(fn_root_layer), ..
518            } => Some((!fn_root_layer.seen_vars.insert(var), fn_root_layer.layer_type)),
519            _ => None,
520        }
521    }
522
523    pub fn should_remove_var(&self, debruijn: DebruijnIndex, var: BoundVar) -> Option<bool> {
524        let layers = self.layers.borrow();
525        Some(
526            layers
527                .get(layers.len().checked_sub(debruijn.as_usize() + 1)?)?
528                .vars_to_remove
529                .contains(&var),
530        )
531    }
532
533    pub fn mark_var_as_removed(&self, debruijn: DebruijnIndex, var: BoundVar) -> Option<bool> {
534        let mut layers = self.layers.borrow_mut();
535        let layer_index = layers.len().checked_sub(debruijn.as_usize() + 1)?;
536        Some(
537            layers
538                .get_mut(layer_index)?
539                .successfully_removed_vars
540                .insert(var),
541        )
542    }
543
544    fn lookup(&self, debruijn: DebruijnIndex, var: BoundVar) -> Option<BoundVarName> {
545        let layers = self.layers.borrow();
546        layers
547            .get(layers.len().checked_sub(debruijn.as_usize() + 1)?)?
548            .layer_map
549            .get(var)
550    }
551
552    fn push_layer(
553        &self,
554        vars: &[BoundVariableKind],
555        vars_to_remove: UnordSet<BoundVar>,
556        is_fn_root_layer: Option<FnRootLayerType>,
557    ) {
558        let mut name_map = UnordMap::default();
559        for (idx, var) in vars.iter().enumerate() {
560            if let BoundVariableKind::Refine(_, _, BoundReftKind::Anon) = var {
561                name_map.insert(BoundVar::from_usize(idx), self.name_gen.fresh());
562            }
563        }
564        let layer_map = if let Some(layer_type) = is_fn_root_layer {
565            BoundVarLayerMap::FnRootLayerMap(FnRootLayerMap {
566                name_map,
567                seen_vars: UnordSet::new(),
568                layer_type,
569            })
570        } else {
571            BoundVarLayerMap::LayerMap(name_map)
572        };
573        let layer =
574            BoundVarLayer { layer_map, vars_to_remove, successfully_removed_vars: UnordSet::new() };
575        self.layers.borrow_mut().push(layer);
576    }
577
578    pub fn peek_layer(&self) -> Option<BoundVarLayer> {
579        self.layers.borrow().last().cloned()
580    }
581
582    fn pop_layer(&self) -> Option<BoundVarLayer> {
583        self.layers.borrow_mut().pop()
584    }
585}
586
587type EarlyParamEnv = UnordSet<EarlyReftParam>;
588
589pub struct WithCx<'a, 'genv, 'tcx, T> {
590    data: T,
591    cx: &'a PrettyCx<'genv, 'tcx>,
592}
593
594pub struct Join<'a, I> {
595    sep: &'a str,
596    iter: RefCell<Option<I>>,
597}
598
599pub struct Parens<'a, T> {
600    val: &'a T,
601    parenthesize: bool,
602}
603
604pub trait Pretty {
605    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result;
606
607    fn default_cx(tcx: TyCtxt) -> PrettyCx {
608        PrettyCx::default(tcx)
609    }
610}
611
612impl Pretty for String {
613    fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
614        write!(f, "{self}")
615    }
616}
617
618impl<'a, I> Join<'a, I> {
619    pub fn new<T: IntoIterator<IntoIter = I>>(sep: &'a str, iter: T) -> Self {
620        Self { sep, iter: RefCell::new(Some(iter.into_iter())) }
621    }
622}
623
624impl<'a, T> Parens<'a, T> {
625    pub fn new(val: &'a T, parenthesize: bool) -> Self {
626        Self { val, parenthesize }
627    }
628}
629
630impl<'a, 'genv, 'tcx, T> WithCx<'a, 'genv, 'tcx, T> {
631    pub fn new(cx: &'a PrettyCx<'genv, 'tcx>, data: T) -> Self {
632        Self { data, cx }
633    }
634}
635
636impl<T: Pretty + ?Sized> Pretty for &'_ T {
637    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
638        <T as Pretty>::fmt(self, cx, f)
639    }
640}
641
642impl<T: Pretty + Internable> Pretty for Interned<T> {
643    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
644        <T as Pretty>::fmt(self, cx, f)
645    }
646}
647
648impl<T, I> fmt::Debug for Join<'_, I>
649where
650    T: fmt::Debug,
651    I: Iterator<Item = T>,
652{
653    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
654        let Some(iter) = self.iter.borrow_mut().take() else {
655            panic!("Join: was already formatted once")
656        };
657        for (i, item) in iter.enumerate() {
658            if i > 0 {
659                write!(f, "{}", self.sep)?;
660            }
661            <T as fmt::Debug>::fmt(&item, f)?;
662        }
663        Ok(())
664    }
665}
666
667impl<T, I> Pretty for Join<'_, I>
668where
669    T: Pretty,
670    I: Iterator<Item = T>,
671{
672    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
673        let Some(iter) = self.iter.borrow_mut().take() else {
674            panic!("Join: was already formatted once")
675        };
676        for (i, item) in iter.enumerate() {
677            if i > 0 {
678                write!(f, "{}", self.sep)?;
679            }
680            <T as Pretty>::fmt(&item, cx, f)?;
681        }
682        Ok(())
683    }
684}
685impl<T> Pretty for Parens<'_, T>
686where
687    T: Pretty,
688{
689    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
690        if self.parenthesize {
691            write!(f, "(")?;
692        }
693        <T as Pretty>::fmt(self.val, cx, f)?;
694        if self.parenthesize {
695            write!(f, ")")?;
696        }
697        Ok(())
698    }
699}
700
701impl<T: Pretty> fmt::Debug for WithCx<'_, '_, '_, T> {
702    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
703        <T as Pretty>::fmt(&self.data, self.cx, f)
704    }
705}
706
707impl Pretty for DefId {
708    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
709        if cx.fully_qualified_paths {
710            w!(cx, f, "{}", ^cx.tcx().def_path_str(self))
711        } else {
712            let path = cx.tcx().def_path(*self);
713            w!(cx, f, "{}", ^path.data.last().unwrap().as_sym(false))
714        }
715    }
716}
717
718impl Pretty for FluxDefId {
719    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
720        if cx.fully_qualified_paths {
721            w!(cx, f, "{:?}::{}", self.parent(), ^self.name())
722        } else {
723            w!(cx, f, "{}", ^self.name())
724        }
725    }
726}
727
728impl Pretty for FluxLocalDefId {
729    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
730        w!(cx, f, "{:?}", self.to_def_id())
731    }
732}
733
734impl Pretty for FieldIdx {
735    fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
736        write!(f, "{}", self.as_u32())
737    }
738}
739
740impl Pretty for Span {
741    fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
742        if cx.full_spans {
743            write!(f, "{self:?}")
744        } else {
745            let src_map = cx.tcx().sess.source_map();
746            let lo = src_map.lookup_char_pos(self.lo());
747            let hi = src_map.lookup_char_pos(self.hi());
748            // use rustc_span::FileName;
749            // match lo.file.name {
750            //     FileName::Real(ref name) => {
751            //         write!(
752            //             f,
753            //             "{}",
754            //             name.local_path_if_available()
755            //                 .file_name()
756            //                 .unwrap()
757            //                 .to_string_lossy()
758            //         )
759            //     }
760            //     FileName::QuoteExpansion(_) => write!(f, "<quote expansion>"),
761            //     FileName::MacroExpansion(_) => write!(f, "<macro expansion>"),
762            //     FileName::Anon(_) => write!(f, "<anon>"),
763            //     FileName::ProcMacroSourceCode(_) => write!(f, "<proc-macro source code>"),
764            //     FileName::CfgSpec(_) => write!(f, "<cfgspec>"),
765            //     FileName::CliCrateAttr(_) => write!(f, "<crate attribute>"),
766            //     FileName::Custom(ref s) => write!(f, "<{}>", s),
767            //     FileName::DocTest(ref path, _) => write!(f, "{}", path.display()),
768            //     FileName::InlineAsm(_) => write!(f, "<inline asm>"),
769            // }?;
770            write!(
771                f,
772                "{}:{}: {}:{}",
773                lo.line,
774                lo.col.to_usize() + 1,
775                hi.line,
776                hi.col.to_usize() + 1,
777            )
778        }
779    }
780}
781
782trait FromOpt: Sized {
783    fn from_opt(opt: &config::Value) -> Option<Self>;
784}
785
786impl FromOpt for bool {
787    fn from_opt(opt: &config::Value) -> Option<Self> {
788        opt.as_bool()
789    }
790}
791
792impl FromOpt for KVarArgs {
793    fn from_opt(opt: &config::Value) -> Option<Self> {
794        match opt.as_str() {
795            Some("self") => Some(KVarArgs::SelfOnly),
796            Some("hide") => Some(KVarArgs::Hide),
797            Some("all") => Some(KVarArgs::All),
798            _ => None,
799        }
800    }
801}
802
803// -------------------------------------------------------------------------------------------------------------
804
805#[derive(Serialize, Debug)]
806pub struct NestedString {
807    pub text: String,
808    pub key: Option<String>,
809    pub children: Option<Vec<NestedString>>,
810}
811
812pub fn debug_nested<T: Pretty>(cx: &PrettyCx, t: &T) -> Result<NestedString, fmt::Error> {
813    let t = WithCx::new(cx, t);
814    let text = format!("{t:?}");
815    Ok(NestedString { text, children: None, key: None })
816}
817
818pub fn float_children(children: Vec<Option<Vec<NestedString>>>) -> Option<Vec<NestedString>> {
819    let mut childrens: Vec<_> = children.into_iter().flatten().collect();
820    if childrens.is_empty() {
821        None
822    } else if childrens.len() == 1 {
823        let c = childrens.pop().unwrap();
824        Some(c)
825    } else {
826        let mut res = vec![];
827        for (i, children) in childrens.into_iter().enumerate() {
828            res.push(NestedString { text: format!("arg{i}"), children: Some(children), key: None });
829        }
830        Some(res)
831    }
832}
833
834pub trait PrettyNested {
835    fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error>;
836
837    fn nested_string(&self, cx: &PrettyCx) -> String {
838        let res = self.fmt_nested(cx).unwrap();
839        serde_json::to_string(&res).unwrap()
840    }
841}