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