Skip to main content

rustc_public/mir/
pretty.rs

1//! Implement methods to pretty print rustc_public's IR body.
2use std::fmt::Debug;
3use std::io::Write;
4use std::{fmt, io, iter};
5
6use fmt::{Display, Formatter};
7
8use super::{AggregateKind, AssertMessage, BinOp, BorrowKind, FakeBorrowKind, TerminatorKind};
9use crate::mir::{
10    Operand, Place, RawPtrKind, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents,
11};
12use crate::ty::{AdtKind, AssocKind, MirConst, Ty, TyConst};
13use crate::{Body, CrateDef, IndexedVal, Mutability, with};
14
15impl Display for Ty {
16    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
17        with(|ctx| f.write_fmt(format_args!("{0}", ctx.ty_pretty(*self)))write!(f, "{}", ctx.ty_pretty(*self)))
18    }
19}
20
21impl Display for AssocKind {
22    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
23        match self {
24            AssocKind::Fn { has_self: true, .. } => f.write_fmt(format_args!("method"))write!(f, "method"),
25            AssocKind::Fn { has_self: false, .. } => f.write_fmt(format_args!("associated function"))write!(f, "associated function"),
26            AssocKind::Const { .. } => f.write_fmt(format_args!("associated const"))write!(f, "associated const"),
27            AssocKind::Type { .. } => f.write_fmt(format_args!("associated type"))write!(f, "associated type"),
28        }
29    }
30}
31
32impl Debug for Place {
33    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
34        with(|ctx| f.write_fmt(format_args!("{0}", ctx.place_pretty(self)))write!(f, "{}", ctx.place_pretty(self)))
35    }
36}
37
38pub(crate) fn function_body<W: Write>(writer: &mut W, body: &Body, name: &str) -> io::Result<()> {
39    writer.write_fmt(format_args!("fn {0}(", name))write!(writer, "fn {name}(")?;
40    let mut sep = "";
41    for (index, local) in body.arg_locals().iter().enumerate() {
42        writer.write_fmt(format_args!("{0}_{1}: {2}", sep, index + 1, local.ty))write!(writer, "{}_{}: {}", sep, index + 1, local.ty)?;
43        sep = ", ";
44    }
45    writer.write_fmt(format_args!(")"))write!(writer, ")")?;
46
47    let return_local = body.ret_local();
48    writer.write_fmt(format_args!(" -> {0} {{\n", return_local.ty))writeln!(writer, " -> {} {{", return_local.ty)?;
49
50    body.locals().iter().enumerate().try_for_each(|(index, local)| -> io::Result<()> {
51        if index == 0 || index > body.arg_count {
52            writer.write_fmt(format_args!("    let {0}_{1}: {2};\n",
        pretty_mut(local.mutability), index, local.ty))writeln!(writer, "    let {}_{}: {};", pretty_mut(local.mutability), index, local.ty)
53        } else {
54            Ok(())
55        }
56    })?;
57
58    body.var_debug_info.iter().try_for_each(|info| {
59        let content = match &info.value {
60            VarDebugInfoContents::Place(place) => {
61                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", place))
    })format!("{place:?}")
62            }
63            VarDebugInfoContents::Const(constant) => pretty_mir_const(&constant.const_),
64        };
65        writer.write_fmt(format_args!("    debug {0} => {1};\n", info.name, content))writeln!(writer, "    debug {} => {};", info.name, content)
66    })?;
67
68    body.blocks
69        .iter()
70        .enumerate()
71        .map(|(index, block)| -> io::Result<()> {
72            writer.write_fmt(format_args!("    bb{0}: {{\n", index))writeln!(writer, "    bb{index}: {{")?;
73            let _ = block
74                .statements
75                .iter()
76                .map(|statement| -> io::Result<()> {
77                    pretty_statement(writer, &statement.kind)?;
78                    Ok(())
79                })
80                .collect::<Vec<_>>();
81            pretty_terminator(writer, &block.terminator.kind)?;
82            writer.write_fmt(format_args!("    }}\n"))writeln!(writer, "    }}").unwrap();
83            Ok(())
84        })
85        .collect::<Result<Vec<_>, _>>()?;
86    writer.write_fmt(format_args!("}}\n"))writeln!(writer, "}}")?;
87    Ok(())
88}
89
90fn pretty_statement<W: Write>(writer: &mut W, statement: &StatementKind) -> io::Result<()> {
91    const INDENT: &str = "        ";
92    match statement {
93        StatementKind::Assign(place, rval) => {
94            writer.write_fmt(format_args!("{0}{1:?} = ", INDENT, place))write!(writer, "{INDENT}{place:?} = ")?;
95            pretty_rvalue(writer, rval)?;
96            writer.write_fmt(format_args!(";\n"))writeln!(writer, ";")
97        }
98        // FIXME: Add rest of the statements
99        StatementKind::FakeRead(cause, place) => {
100            writer.write_fmt(format_args!("{0}FakeRead({1:?}, {2:?});\n", INDENT, cause,
        place))writeln!(writer, "{INDENT}FakeRead({cause:?}, {place:?});")
101        }
102        StatementKind::SetDiscriminant { place, variant_index } => {
103            writer.write_fmt(format_args!("{1}discriminant({2:?}) = {0};\n",
        variant_index.to_index(), INDENT, place))writeln!(writer, "{INDENT}discriminant({place:?}) = {};", variant_index.to_index())
104        }
105        StatementKind::StorageLive(local) => {
106            writer.write_fmt(format_args!("{0}StorageLive(_{1});\n", INDENT, local))writeln!(writer, "{INDENT}StorageLive(_{local});")
107        }
108        StatementKind::StorageDead(local) => {
109            writer.write_fmt(format_args!("{0}StorageDead(_{1});\n", INDENT, local))writeln!(writer, "{INDENT}StorageDead(_{local});")
110        }
111        StatementKind::PlaceMention(place) => {
112            writer.write_fmt(format_args!("{0}PlaceMention({1:?};\n", INDENT, place))writeln!(writer, "{INDENT}PlaceMention({place:?};")
113        }
114        StatementKind::ConstEvalCounter => {
115            writer.write_fmt(format_args!("{0}ConstEvalCounter;\n", INDENT))writeln!(writer, "{INDENT}ConstEvalCounter;")
116        }
117        StatementKind::Nop => writer.write_fmt(format_args!("{0}nop;\n", INDENT))writeln!(writer, "{INDENT}nop;"),
118        StatementKind::AscribeUserType { .. }
119        | StatementKind::Coverage(_)
120        | StatementKind::Intrinsic(_) => {
121            // FIX-ME: Make them pretty.
122            writer.write_fmt(format_args!("{0}{1:?};\n", INDENT, statement))writeln!(writer, "{INDENT}{statement:?};")
123        }
124    }
125}
126
127fn pretty_terminator<W: Write>(writer: &mut W, terminator: &TerminatorKind) -> io::Result<()> {
128    pretty_terminator_head(writer, terminator)?;
129    let successors = terminator.successors();
130    let successor_count = successors.len();
131    let labels = pretty_successor_labels(terminator);
132
133    let show_unwind = !#[allow(non_exhaustive_omitted_patterns)] match terminator.unwind() {
    None | Some(UnwindAction::Cleanup(_)) => true,
    _ => false,
}matches!(terminator.unwind(), None | Some(UnwindAction::Cleanup(_)));
134    let fmt_unwind = |w: &mut W| -> io::Result<()> {
135        w.write_fmt(format_args!("unwind "))write!(w, "unwind ")?;
136        match terminator.unwind() {
137            None | Some(UnwindAction::Cleanup(_)) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
138            Some(UnwindAction::Continue) => w.write_fmt(format_args!("continue"))write!(w, "continue"),
139            Some(UnwindAction::Unreachable) => w.write_fmt(format_args!("unreachable"))write!(w, "unreachable"),
140            Some(UnwindAction::Terminate) => w.write_fmt(format_args!("terminate"))write!(w, "terminate"),
141        }
142    };
143
144    match (successor_count, show_unwind) {
145        (0, false) => {}
146        (0, true) => {
147            writer.write_fmt(format_args!(" -> "))write!(writer, " -> ")?;
148            fmt_unwind(writer)?;
149        }
150        (1, false) => writer.write_fmt(format_args!(" -> bb{0:?}", successors[0]))write!(writer, " -> bb{:?}", successors[0])?,
151        _ => {
152            writer.write_fmt(format_args!(" -> ["))write!(writer, " -> [")?;
153            for (i, target) in successors.iter().enumerate() {
154                if i > 0 {
155                    writer.write_fmt(format_args!(", "))write!(writer, ", ")?;
156                }
157                writer.write_fmt(format_args!("{0}: bb{1:?}", labels[i], target))write!(writer, "{}: bb{:?}", labels[i], target)?;
158            }
159            if show_unwind {
160                writer.write_fmt(format_args!(", "))write!(writer, ", ")?;
161                fmt_unwind(writer)?;
162            }
163            writer.write_fmt(format_args!("]"))write!(writer, "]")?;
164        }
165    };
166
167    writer.write_fmt(format_args!(";\n"))writeln!(writer, ";")
168}
169
170fn pretty_terminator_head<W: Write>(writer: &mut W, terminator: &TerminatorKind) -> io::Result<()> {
171    use self::TerminatorKind::*;
172    const INDENT: &str = "        ";
173    match terminator {
174        Goto { .. } => writer.write_fmt(format_args!("{0}goto", INDENT))write!(writer, "{INDENT}goto"),
175        SwitchInt { discr, .. } => {
176            writer.write_fmt(format_args!("{1}switchInt({0})", pretty_operand(discr),
        INDENT))write!(writer, "{INDENT}switchInt({})", pretty_operand(discr))
177        }
178        Resume => writer.write_fmt(format_args!("{0}resume", INDENT))write!(writer, "{INDENT}resume"),
179        Abort => writer.write_fmt(format_args!("{0}abort", INDENT))write!(writer, "{INDENT}abort"),
180        Return => writer.write_fmt(format_args!("{0}return", INDENT))write!(writer, "{INDENT}return"),
181        Unreachable => writer.write_fmt(format_args!("{0}unreachable", INDENT))write!(writer, "{INDENT}unreachable"),
182        Drop { place, .. } => writer.write_fmt(format_args!("{0}drop({1:?})", INDENT, place))write!(writer, "{INDENT}drop({place:?})"),
183        Call { func, args, destination, .. } => {
184            writer.write_fmt(format_args!("{2}{0:?} = {1}(", destination,
        pretty_operand(func), INDENT))write!(writer, "{INDENT}{:?} = {}(", destination, pretty_operand(func))?;
185            let mut args_iter = args.iter();
186            args_iter.next().map_or(Ok(()), |arg| writer.write_fmt(format_args!("{0}", pretty_operand(arg)))write!(writer, "{}", pretty_operand(arg)))?;
187            args_iter.try_for_each(|arg| writer.write_fmt(format_args!(", {0}", pretty_operand(arg)))write!(writer, ", {}", pretty_operand(arg)))?;
188            writer.write_fmt(format_args!(")"))write!(writer, ")")
189        }
190        Assert { cond, expected, msg, target: _, unwind: _ } => {
191            writer.write_fmt(format_args!("{0}assert(", INDENT))write!(writer, "{INDENT}assert(")?;
192            if !expected {
193                writer.write_fmt(format_args!("!"))write!(writer, "!")?;
194            }
195            writer.write_fmt(format_args!("{0}, ", pretty_operand(cond)))write!(writer, "{}, ", pretty_operand(cond))?;
196            pretty_assert_message(writer, msg)?;
197            writer.write_fmt(format_args!(")"))write!(writer, ")")
198        }
199        InlineAsm { .. } => writer.write_fmt(format_args!("{0}InlineAsm", INDENT))write!(writer, "{INDENT}InlineAsm"),
200    }
201}
202
203fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec<String> {
204    use self::TerminatorKind::*;
205    match terminator {
206        Call { target: None, unwind: UnwindAction::Cleanup(_), .. }
207        | InlineAsm { destination: None, .. } => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        ["unwind".into()]))vec!["unwind".into()],
208        Resume | Abort | Return | Unreachable | Call { target: None, unwind: _, .. } => ::alloc::vec::Vec::new()vec![],
209        Goto { .. } => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        ["".to_string()]))vec!["".to_string()],
210        SwitchInt { targets, .. } => targets
211            .branches()
212            .map(|(val, _target)| ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}", val))
    })format!("{val}"))
213            .chain(iter::once("otherwise".into()))
214            .collect(),
215        Drop { unwind: UnwindAction::Cleanup(_), .. } => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        ["return".into(), "unwind".into()]))vec!["return".into(), "unwind".into()],
216        Call { target: Some(_), unwind: UnwindAction::Cleanup(_), .. } => {
217            ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        ["return".into(), "unwind".into()]))vec!["return".into(), "unwind".into()]
218        }
219        Drop { unwind: _, .. } | Call { target: Some(_), unwind: _, .. } => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        ["return".into()]))vec!["return".into()],
220        Assert { unwind: UnwindAction::Cleanup(_), .. } => {
221            ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        ["success".into(), "unwind".into()]))vec!["success".into(), "unwind".into()]
222        }
223        Assert { unwind: _, .. } => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        ["success".into()]))vec!["success".into()],
224        InlineAsm { destination: Some(_), .. } => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        ["goto".into(), "unwind".into()]))vec!["goto".into(), "unwind".into()],
225    }
226}
227
228fn pretty_assert_message<W: Write>(writer: &mut W, msg: &AssertMessage) -> io::Result<()> {
229    match msg {
230        AssertMessage::BoundsCheck { len, index } => {
231            let pretty_len = pretty_operand(len);
232            let pretty_index = pretty_operand(index);
233            writer.write_fmt(format_args!("\"index out of bounds: the length is {{}} but the index is {{}}\", {0}, {1}",
        pretty_len, pretty_index))write!(
234                writer,
235                "\"index out of bounds: the length is {{}} but the index is {{}}\", {pretty_len}, {pretty_index}"
236            )
237        }
238        AssertMessage::Overflow(BinOp::Add, l, r) => {
239            let pretty_l = pretty_operand(l);
240            let pretty_r = pretty_operand(r);
241            writer.write_fmt(format_args!("\"attempt to compute `{{}} + {{}}`, which would overflow\", {0}, {1}",
        pretty_l, pretty_r))write!(
242                writer,
243                "\"attempt to compute `{{}} + {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
244            )
245        }
246        AssertMessage::Overflow(BinOp::Sub, l, r) => {
247            let pretty_l = pretty_operand(l);
248            let pretty_r = pretty_operand(r);
249            writer.write_fmt(format_args!("\"attempt to compute `{{}} - {{}}`, which would overflow\", {0}, {1}",
        pretty_l, pretty_r))write!(
250                writer,
251                "\"attempt to compute `{{}} - {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
252            )
253        }
254        AssertMessage::Overflow(BinOp::Mul, l, r) => {
255            let pretty_l = pretty_operand(l);
256            let pretty_r = pretty_operand(r);
257            writer.write_fmt(format_args!("\"attempt to compute `{{}} * {{}}`, which would overflow\", {0}, {1}",
        pretty_l, pretty_r))write!(
258                writer,
259                "\"attempt to compute `{{}} * {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
260            )
261        }
262        AssertMessage::Overflow(BinOp::Div, l, r) => {
263            let pretty_l = pretty_operand(l);
264            let pretty_r = pretty_operand(r);
265            writer.write_fmt(format_args!("\"attempt to compute `{{}} / {{}}`, which would overflow\", {0}, {1}",
        pretty_l, pretty_r))write!(
266                writer,
267                "\"attempt to compute `{{}} / {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
268            )
269        }
270        AssertMessage::Overflow(BinOp::Rem, l, r) => {
271            let pretty_l = pretty_operand(l);
272            let pretty_r = pretty_operand(r);
273            writer.write_fmt(format_args!("\"attempt to compute `{{}} % {{}}`, which would overflow\", {0}, {1}",
        pretty_l, pretty_r))write!(
274                writer,
275                "\"attempt to compute `{{}} % {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
276            )
277        }
278        AssertMessage::Overflow(BinOp::Shr, _, r) => {
279            let pretty_r = pretty_operand(r);
280            writer.write_fmt(format_args!("\"attempt to shift right by `{{}}`, which would overflow\", {0}",
        pretty_r))write!(writer, "\"attempt to shift right by `{{}}`, which would overflow\", {pretty_r}")
281        }
282        AssertMessage::Overflow(BinOp::Shl, _, r) => {
283            let pretty_r = pretty_operand(r);
284            writer.write_fmt(format_args!("\"attempt to shift left by `{{}}`, which would overflow\", {0}",
        pretty_r))write!(writer, "\"attempt to shift left by `{{}}`, which would overflow\", {pretty_r}")
285        }
286        AssertMessage::Overflow(op, _, _) => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("`{0:?}` cannot overflow", op)));
}unreachable!("`{:?}` cannot overflow", op),
287        AssertMessage::OverflowNeg(op) => {
288            let pretty_op = pretty_operand(op);
289            writer.write_fmt(format_args!("\"attempt to negate `{{}}`, which would overflow\", {0}",
        pretty_op))write!(writer, "\"attempt to negate `{{}}`, which would overflow\", {pretty_op}")
290        }
291        AssertMessage::DivisionByZero(op) => {
292            let pretty_op = pretty_operand(op);
293            writer.write_fmt(format_args!("\"attempt to divide `{{}}` by zero\", {0}",
        pretty_op))write!(writer, "\"attempt to divide `{{}}` by zero\", {pretty_op}")
294        }
295        AssertMessage::RemainderByZero(op) => {
296            let pretty_op = pretty_operand(op);
297            writer.write_fmt(format_args!("\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {0}",
        pretty_op))write!(
298                writer,
299                "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {pretty_op}"
300            )
301        }
302        AssertMessage::MisalignedPointerDereference { required, found } => {
303            let pretty_required = pretty_operand(required);
304            let pretty_found = pretty_operand(found);
305            writer.write_fmt(format_args!("\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{0}, {1}",
        pretty_required, pretty_found))write!(
306                writer,
307                "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{pretty_required}, {pretty_found}"
308            )
309        }
310        AssertMessage::NullPointerDereference => {
311            writer.write_fmt(format_args!("\"null pointer dereference occurred\""))write!(writer, "\"null pointer dereference occurred\"")
312        }
313        AssertMessage::InvalidEnumConstruction(op) => {
314            let pretty_op = pretty_operand(op);
315            writer.write_fmt(format_args!("\"trying to construct an enum from an invalid value {{}}\",{0}",
        pretty_op))write!(writer, "\"trying to construct an enum from an invalid value {{}}\",{pretty_op}")
316        }
317        AssertMessage::ResumedAfterReturn(_)
318        | AssertMessage::ResumedAfterPanic(_)
319        | AssertMessage::ResumedAfterDrop(_) => {
320            writer.write_fmt(format_args!("{0}", msg.description().unwrap()))write!(writer, "{}", msg.description().unwrap())
321        }
322    }
323}
324
325fn pretty_operand(operand: &Operand) -> String {
326    match operand {
327        Operand::Copy(copy) => {
328            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", copy))
    })format!("{copy:?}")
329        }
330        Operand::Move(mv) => {
331            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("move {0:?}", mv))
    })format!("move {mv:?}")
332        }
333        Operand::Constant(cnst) => pretty_mir_const(&cnst.const_),
334        Operand::RuntimeChecks(checks) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", checks))
    })format!("{checks:?}"),
335    }
336}
337
338fn pretty_mir_const(literal: &MirConst) -> String {
339    with(|cx| cx.mir_const_pretty(literal))
340}
341
342fn pretty_ty_const(ct: &TyConst) -> String {
343    with(|cx| cx.ty_const_pretty(ct.id))
344}
345
346fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> {
347    match rval {
348        Rvalue::AddressOf(mutability, place) => {
349            writer.write_fmt(format_args!("&raw {0} {1:?}",
        pretty_raw_ptr_kind(*mutability), place))write!(writer, "&raw {} {:?}", pretty_raw_ptr_kind(*mutability), place)
350        }
351        Rvalue::Aggregate(aggregate_kind, operands) => {
352            // FIXME: Add pretty_aggregate function that returns a pretty string
353            pretty_aggregate(writer, aggregate_kind, operands)
354        }
355        Rvalue::BinaryOp(bin, op1, op2) => {
356            writer.write_fmt(format_args!("{0:?}({1}, {2})", bin, pretty_operand(op1),
        pretty_operand(op2)))write!(writer, "{:?}({}, {})", bin, pretty_operand(op1), pretty_operand(op2))
357        }
358        Rvalue::Cast(_, op, ty) => {
359            writer.write_fmt(format_args!("{0} as {1}", pretty_operand(op), ty))write!(writer, "{} as {}", pretty_operand(op), ty)
360        }
361        Rvalue::CheckedBinaryOp(bin, op1, op2) => {
362            writer.write_fmt(format_args!("Checked{0:?}({1}, {2})", bin,
        pretty_operand(op1), pretty_operand(op2)))write!(writer, "Checked{:?}({}, {})", bin, pretty_operand(op1), pretty_operand(op2))
363        }
364        Rvalue::CopyForDeref(deref) => {
365            writer.write_fmt(format_args!("CopyForDeref({0:?})", deref))write!(writer, "CopyForDeref({deref:?})")
366        }
367        Rvalue::Discriminant(place) => {
368            writer.write_fmt(format_args!("discriminant({0:?})", place))write!(writer, "discriminant({place:?})")
369        }
370        Rvalue::Len(len) => {
371            writer.write_fmt(format_args!("len({0:?})", len))write!(writer, "len({len:?})")
372        }
373        Rvalue::Ref(_, borrowkind, place) => {
374            let kind = match borrowkind {
375                BorrowKind::Shared => "&",
376                BorrowKind::Fake(FakeBorrowKind::Deep) => "&fake ",
377                BorrowKind::Fake(FakeBorrowKind::Shallow) => "&fake shallow ",
378                BorrowKind::Mut { .. } => "&mut ",
379            };
380            writer.write_fmt(format_args!("{0}{1:?}", kind, place))write!(writer, "{kind}{place:?}")
381        }
382        Rvalue::Repeat(op, cnst) => {
383            writer.write_fmt(format_args!("[{0}; {1}]", pretty_operand(op),
        pretty_ty_const(cnst)))write!(writer, "[{}; {}]", pretty_operand(op), pretty_ty_const(cnst))
384        }
385        Rvalue::ThreadLocalRef(item) => {
386            writer.write_fmt(format_args!("thread_local_ref{0:?}", item))write!(writer, "thread_local_ref{item:?}")
387        }
388        Rvalue::UnaryOp(un, op) => {
389            writer.write_fmt(format_args!("{0:?}({1})", un, pretty_operand(op)))write!(writer, "{:?}({})", un, pretty_operand(op))
390        }
391        Rvalue::Use(op, retag) => writer.write_fmt(format_args!("{0}{1}",
        if #[allow(non_exhaustive_omitted_patterns)] match retag {
                crate::mir::WithRetag::No => true,
                _ => false,
            } {
            "no_retag "
        } else { "" }, pretty_operand(op)))write!(
392            writer,
393            "{}{}",
394            if matches!(retag, crate::mir::WithRetag::No) { "no_retag " } else { "" },
395            pretty_operand(op)
396        ),
397    }
398}
399
400fn pretty_aggregate<W: Write>(
401    writer: &mut W,
402    aggregate_kind: &AggregateKind,
403    operands: &Vec<Operand>,
404) -> io::Result<()> {
405    let suffix = match aggregate_kind {
406        AggregateKind::Array(_) => {
407            writer.write_fmt(format_args!("["))write!(writer, "[")?;
408            "]"
409        }
410        AggregateKind::Tuple => {
411            writer.write_fmt(format_args!("("))write!(writer, "(")?;
412            ")"
413        }
414        AggregateKind::Adt(def, var, _, _, _) => {
415            if def.kind() == AdtKind::Enum {
416                writer.write_fmt(format_args!("{0}::{1}", def.trimmed_name(),
        def.variant(*var).unwrap().name()))write!(writer, "{}::{}", def.trimmed_name(), def.variant(*var).unwrap().name())?;
417            } else {
418                writer.write_fmt(format_args!("{0}", def.variant(*var).unwrap().name()))write!(writer, "{}", def.variant(*var).unwrap().name())?;
419            }
420            if operands.is_empty() {
421                return Ok(());
422            }
423            // FIXME: Change this once we have CtorKind in StableMIR.
424            writer.write_fmt(format_args!("("))write!(writer, "(")?;
425            ")"
426        }
427        AggregateKind::Closure(def, _) => {
428            writer.write_fmt(format_args!("{{closure@{0}}}(", def.span().diagnostic()))write!(writer, "{{closure@{}}}(", def.span().diagnostic())?;
429            ")"
430        }
431        AggregateKind::Coroutine(def, _) => {
432            writer.write_fmt(format_args!("{{coroutine@{0}}}(", def.span().diagnostic()))write!(writer, "{{coroutine@{}}}(", def.span().diagnostic())?;
433            ")"
434        }
435        AggregateKind::CoroutineClosure(def, _) => {
436            writer.write_fmt(format_args!("{{coroutine-closure@{0}}}(",
        def.span().diagnostic()))write!(writer, "{{coroutine-closure@{}}}(", def.span().diagnostic())?;
437            ")"
438        }
439        AggregateKind::RawPtr(ty, mutability) => {
440            writer.write_fmt(format_args!("*{0} {1} from (",
        if *mutability == Mutability::Mut { "mut" } else { "const" }, ty))write!(
441                writer,
442                "*{} {ty} from (",
443                if *mutability == Mutability::Mut { "mut" } else { "const" }
444            )?;
445            ")"
446        }
447    };
448    let mut separator = "";
449    for op in operands {
450        writer.write_fmt(format_args!("{0}{1}", separator, pretty_operand(op)))write!(writer, "{}{}", separator, pretty_operand(op))?;
451        separator = ", ";
452    }
453    writer.write_fmt(format_args!("{0}", suffix))write!(writer, "{suffix}")
454}
455
456fn pretty_mut(mutability: Mutability) -> &'static str {
457    match mutability {
458        Mutability::Not => " ",
459        Mutability::Mut => "mut ",
460    }
461}
462
463fn pretty_raw_ptr_kind(kind: RawPtrKind) -> &'static str {
464    match kind {
465        RawPtrKind::Const => "const",
466        RawPtrKind::Mut => "mut",
467        RawPtrKind::FakeForPtrMetadata => "const (fake)",
468    }
469}