]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir/src/dataflow/framework/fmt.rs
Auto merge of #77948 - cuviper:rust-llvm11, r=nikic
[rust.git] / compiler / rustc_mir / src / dataflow / framework / fmt.rs
1 //! Custom formatting traits used when outputting Graphviz diagrams with the results of a dataflow
2 //! analysis.
3
4 use rustc_index::bit_set::{BitSet, HybridBitSet};
5 use rustc_index::vec::Idx;
6 use std::fmt;
7
8 /// An extension to `fmt::Debug` for data that can be better printed with some auxiliary data `C`.
9 pub trait DebugWithContext<C>: Eq + fmt::Debug {
10     fn fmt_with(&self, _ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11         fmt::Debug::fmt(self, f)
12     }
13
14     /// Print the difference between `self` and `old`.
15     ///
16     /// This should print nothing if `self == old`.
17     ///
18     /// `+` and `-` are typically used to indicate differences. However, these characters are
19     /// fairly common and may be needed to print a types representation. If using them to indicate
20     /// a diff, prefix them with the "Unit Separator"  control character (␟  U+001F).
21     fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22         if self == old {
23             return Ok(());
24         }
25
26         write!(f, "\u{001f}+")?;
27         self.fmt_with(ctxt, f)?;
28
29         if f.alternate() {
30             write!(f, "\n")?;
31         } else {
32             write!(f, "\t")?;
33         }
34
35         write!(f, "\u{001f}-")?;
36         self.fmt_with(ctxt, f)
37     }
38 }
39
40 /// Implements `fmt::Debug` by deferring to `<T as DebugWithContext<C>>::fmt_with`.
41 pub struct DebugWithAdapter<'a, T, C> {
42     pub this: T,
43     pub ctxt: &'a C,
44 }
45
46 impl<T, C> fmt::Debug for DebugWithAdapter<'_, T, C>
47 where
48     T: DebugWithContext<C>,
49 {
50     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51         self.this.fmt_with(self.ctxt, f)
52     }
53 }
54
55 /// Implements `fmt::Debug` by deferring to `<T as DebugWithContext<C>>::fmt_diff_with`.
56 pub struct DebugDiffWithAdapter<'a, T, C> {
57     pub new: T,
58     pub old: T,
59     pub ctxt: &'a C,
60 }
61
62 impl<T, C> fmt::Debug for DebugDiffWithAdapter<'_, T, C>
63 where
64     T: DebugWithContext<C>,
65 {
66     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67         self.new.fmt_diff_with(&self.old, self.ctxt, f)
68     }
69 }
70
71 // Impls
72
73 impl<T, C> DebugWithContext<C> for BitSet<T>
74 where
75     T: Idx + DebugWithContext<C>,
76 {
77     fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78         f.debug_set().entries(self.iter().map(|i| DebugWithAdapter { this: i, ctxt })).finish()
79     }
80
81     fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82         let size = self.domain_size();
83         assert_eq!(size, old.domain_size());
84
85         let mut set_in_self = HybridBitSet::new_empty(size);
86         let mut cleared_in_self = HybridBitSet::new_empty(size);
87
88         for i in (0..size).map(T::new) {
89             match (self.contains(i), old.contains(i)) {
90                 (true, false) => set_in_self.insert(i),
91                 (false, true) => cleared_in_self.insert(i),
92                 _ => continue,
93             };
94         }
95
96         let mut first = true;
97         for idx in set_in_self.iter() {
98             let delim = if first {
99                 "\u{001f}+"
100             } else if f.alternate() {
101                 "\n\u{001f}+"
102             } else {
103                 ", "
104             };
105
106             write!(f, "{}", delim)?;
107             idx.fmt_with(ctxt, f)?;
108             first = false;
109         }
110
111         if !f.alternate() {
112             first = true;
113             if !set_in_self.is_empty() && !cleared_in_self.is_empty() {
114                 write!(f, "\t")?;
115             }
116         }
117
118         for idx in cleared_in_self.iter() {
119             let delim = if first {
120                 "\u{001f}-"
121             } else if f.alternate() {
122                 "\n\u{001f}-"
123             } else {
124                 ", "
125             };
126
127             write!(f, "{}", delim)?;
128             idx.fmt_with(ctxt, f)?;
129             first = false;
130         }
131
132         Ok(())
133     }
134 }
135
136 impl<T, C> DebugWithContext<C> for &'_ T
137 where
138     T: DebugWithContext<C>,
139 {
140     fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141         (*self).fmt_with(ctxt, f)
142     }
143
144     fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145         (*self).fmt_diff_with(*old, ctxt, f)
146     }
147 }
148
149 impl<C> DebugWithContext<C> for rustc_middle::mir::Local {}
150 impl<C> DebugWithContext<C> for crate::dataflow::move_paths::InitIndex {}
151
152 impl<'tcx, C> DebugWithContext<C> for crate::dataflow::move_paths::MovePathIndex
153 where
154     C: crate::dataflow::move_paths::HasMoveData<'tcx>,
155 {
156     fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157         write!(f, "{}", ctxt.move_data().move_paths[*self])
158     }
159 }
160
161 impl<T, C> DebugWithContext<C> for crate::dataflow::lattice::Dual<T>
162 where
163     T: DebugWithContext<C>,
164 {
165     fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166         (self.0).fmt_with(ctxt, f)
167     }
168
169     fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170         (self.0).fmt_diff_with(&old.0, ctxt, f)
171     }
172 }