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 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 #[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 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 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 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#[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}