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