rustc_mir_dataflow/framework/
fmt.rs
1use std::fmt;
5
6use rustc_index::Idx;
7use rustc_index::bit_set::{ChunkedBitSet, DenseBitSet, MixedBitSet};
8
9use super::lattice::MaybeReachable;
10
11pub trait DebugWithContext<C>: Eq + fmt::Debug {
13 fn fmt_with(&self, _ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14 fmt::Debug::fmt(self, f)
15 }
16
17 fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 if self == old {
26 return Ok(());
27 }
28
29 write!(f, "\u{001f}+")?;
30 self.fmt_with(ctxt, f)?;
31
32 if f.alternate() {
33 write!(f, "\n")?;
34 } else {
35 write!(f, "\t")?;
36 }
37
38 write!(f, "\u{001f}-")?;
39 old.fmt_with(ctxt, f)
40 }
41}
42
43pub struct DebugWithAdapter<'a, T, C> {
45 pub this: T,
46 pub ctxt: &'a C,
47}
48
49impl<T, C> fmt::Debug for DebugWithAdapter<'_, T, C>
50where
51 T: DebugWithContext<C>,
52{
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 self.this.fmt_with(self.ctxt, f)
55 }
56}
57
58pub struct DebugDiffWithAdapter<'a, T, C> {
60 pub new: T,
61 pub old: T,
62 pub ctxt: &'a C,
63}
64
65impl<T, C> fmt::Debug for DebugDiffWithAdapter<'_, T, C>
66where
67 T: DebugWithContext<C>,
68{
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 self.new.fmt_diff_with(&self.old, self.ctxt, f)
71 }
72}
73
74impl<T, C> DebugWithContext<C> for DenseBitSet<T>
77where
78 T: Idx + DebugWithContext<C>,
79{
80 fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 f.debug_set().entries(self.iter().map(|i| DebugWithAdapter { this: i, ctxt })).finish()
82 }
83
84 fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 let size = self.domain_size();
86 assert_eq!(size, old.domain_size());
87
88 let mut set_in_self = MixedBitSet::new_empty(size);
89 let mut cleared_in_self = MixedBitSet::new_empty(size);
90
91 for i in (0..size).map(T::new) {
92 match (self.contains(i), old.contains(i)) {
93 (true, false) => set_in_self.insert(i),
94 (false, true) => cleared_in_self.insert(i),
95 _ => continue,
96 };
97 }
98
99 fmt_diff(&set_in_self, &cleared_in_self, ctxt, f)
100 }
101}
102
103impl<T, C> DebugWithContext<C> for ChunkedBitSet<T>
104where
105 T: Idx + DebugWithContext<C>,
106{
107 fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 f.debug_set().entries(self.iter().map(|i| DebugWithAdapter { this: i, ctxt })).finish()
109 }
110
111 fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 let size = self.domain_size();
113 assert_eq!(size, old.domain_size());
114
115 let mut set_in_self = MixedBitSet::new_empty(size);
116 let mut cleared_in_self = MixedBitSet::new_empty(size);
117
118 for i in (0..size).map(T::new) {
119 match (self.contains(i), old.contains(i)) {
120 (true, false) => set_in_self.insert(i),
121 (false, true) => cleared_in_self.insert(i),
122 _ => continue,
123 };
124 }
125
126 fmt_diff(&set_in_self, &cleared_in_self, ctxt, f)
127 }
128}
129
130impl<T, C> DebugWithContext<C> for MixedBitSet<T>
131where
132 T: Idx + DebugWithContext<C>,
133{
134 fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 match self {
136 MixedBitSet::Small(set) => set.fmt_with(ctxt, f),
137 MixedBitSet::Large(set) => set.fmt_with(ctxt, f),
138 }
139 }
140
141 fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 match (self, old) {
143 (MixedBitSet::Small(set), MixedBitSet::Small(old)) => set.fmt_diff_with(old, ctxt, f),
144 (MixedBitSet::Large(set), MixedBitSet::Large(old)) => set.fmt_diff_with(old, ctxt, f),
145 _ => panic!("MixedBitSet size mismatch"),
146 }
147 }
148}
149
150impl<S, C> DebugWithContext<C> for MaybeReachable<S>
151where
152 S: DebugWithContext<C>,
153{
154 fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155 match self {
156 MaybeReachable::Unreachable => {
157 write!(f, "unreachable")
158 }
159 MaybeReachable::Reachable(set) => set.fmt_with(ctxt, f),
160 }
161 }
162
163 fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 match (self, old) {
165 (MaybeReachable::Unreachable, MaybeReachable::Unreachable) => Ok(()),
166 (MaybeReachable::Unreachable, MaybeReachable::Reachable(set)) => {
167 write!(f, "\u{001f}+")?;
168 set.fmt_with(ctxt, f)
169 }
170 (MaybeReachable::Reachable(set), MaybeReachable::Unreachable) => {
171 write!(f, "\u{001f}-")?;
172 set.fmt_with(ctxt, f)
173 }
174 (MaybeReachable::Reachable(this), MaybeReachable::Reachable(old)) => {
175 this.fmt_diff_with(old, ctxt, f)
176 }
177 }
178 }
179}
180
181fn fmt_diff<T, C>(
182 inserted: &MixedBitSet<T>,
183 removed: &MixedBitSet<T>,
184 ctxt: &C,
185 f: &mut fmt::Formatter<'_>,
186) -> fmt::Result
187where
188 T: Idx + DebugWithContext<C>,
189{
190 let mut first = true;
191 for idx in inserted.iter() {
192 let delim = if first {
193 "\u{001f}+"
194 } else if f.alternate() {
195 "\n\u{001f}+"
196 } else {
197 ", "
198 };
199
200 write!(f, "{delim}")?;
201 idx.fmt_with(ctxt, f)?;
202 first = false;
203 }
204
205 if !f.alternate() {
206 first = true;
207 if !inserted.is_empty() && !removed.is_empty() {
208 write!(f, "\t")?;
209 }
210 }
211
212 for idx in removed.iter() {
213 let delim = if first {
214 "\u{001f}-"
215 } else if f.alternate() {
216 "\n\u{001f}-"
217 } else {
218 ", "
219 };
220
221 write!(f, "{delim}")?;
222 idx.fmt_with(ctxt, f)?;
223 first = false;
224 }
225
226 Ok(())
227}
228
229impl<T, C> DebugWithContext<C> for &'_ T
230where
231 T: DebugWithContext<C>,
232{
233 fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234 (*self).fmt_with(ctxt, f)
235 }
236
237 fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
238 (*self).fmt_diff_with(*old, ctxt, f)
239 }
240}
241
242impl<C> DebugWithContext<C> for rustc_middle::mir::Local {}
243impl<C> DebugWithContext<C> for crate::move_paths::InitIndex {}
244
245impl<'tcx, C> DebugWithContext<C> for crate::move_paths::MovePathIndex
246where
247 C: crate::move_paths::HasMoveData<'tcx>,
248{
249 fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250 write!(f, "{}", ctxt.move_data().move_paths[*self])
251 }
252}