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