]>
Commit | Line | Data |
---|---|---|
9cc50fc6 SL |
1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
a7813a04 | 11 | use rustc::hir; |
7cac9316 | 12 | use rustc::hir::def_id::{DefId, LOCAL_CRATE}; |
c30ab7b3 | 13 | use rustc::mir::*; |
ff7c6d11 XL |
14 | use rustc::mir::visit::Visitor; |
15 | use rustc::ty::{self, TyCtxt}; | |
7cac9316 | 16 | use rustc::ty::item_path; |
476ff2be | 17 | use rustc_data_structures::fx::FxHashMap; |
ff7c6d11 | 18 | use rustc_data_structures::indexed_vec::Idx; |
54a0048b SL |
19 | use std::fmt::Display; |
20 | use std::fs; | |
9cc50fc6 | 21 | use std::io::{self, Write}; |
ff7c6d11 | 22 | use std::path::{Path, PathBuf}; |
abe05a73 XL |
23 | use super::graphviz::write_mir_fn_graphviz; |
24 | use transform::MirSource; | |
9cc50fc6 SL |
25 | |
26 | const INDENT: &'static str = " "; | |
a7813a04 | 27 | /// Alignment for lining up comments following MIR statements |
ff7c6d11 | 28 | pub(crate) const ALIGN: usize = 40; |
9cc50fc6 | 29 | |
abe05a73 XL |
30 | /// An indication of where we are in the control flow graph. Used for printing |
31 | /// extra information in `dump_mir` | |
32 | pub enum PassWhere { | |
33 | /// We have not started dumping the control flow graph, but we are about to. | |
34 | BeforeCFG, | |
35 | ||
36 | /// We just finished dumping the control flow graph. This is right before EOF | |
37 | AfterCFG, | |
38 | ||
39 | /// We are about to start dumping the given basic block. | |
40 | BeforeBlock(BasicBlock), | |
41 | ||
ff7c6d11 XL |
42 | /// We are just about to dump the given statement or terminator. |
43 | BeforeLocation(Location), | |
44 | ||
45 | /// We just dumped the given statement or terminator. | |
46 | AfterLocation(Location), | |
abe05a73 XL |
47 | } |
48 | ||
54a0048b SL |
49 | /// If the session is properly configured, dumps a human-readable |
50 | /// representation of the mir into: | |
51 | /// | |
a7813a04 | 52 | /// ```text |
7cac9316 | 53 | /// rustc.node<node_id>.<pass_num>.<pass_name>.<disambiguator> |
54a0048b SL |
54 | /// ``` |
55 | /// | |
56 | /// Output from this function is controlled by passing `-Z dump-mir=<filter>`, | |
57 | /// where `<filter>` takes the following forms: | |
58 | /// | |
59 | /// - `all` -- dump MIR for all fns, all passes, all everything | |
ff7c6d11 XL |
60 | /// - a filter defined by a set of substrings combined with `&` and `|` |
61 | /// (`&` has higher precedence). At least one of the `|`-separated groups | |
62 | /// must match; an `|`-separated group matches if all of its `&`-separated | |
63 | /// substrings are matched. | |
64 | /// | |
65 | /// Example: | |
66 | /// | |
67 | /// - `nll` == match if `nll` appears in the name | |
68 | /// - `foo & nll` == match if `foo` and `nll` both appear in the name | |
69 | /// - `foo & nll | typeck` == match if `foo` and `nll` both appear in the name | |
70 | /// or `typeck` appears in the name. | |
71 | /// - `foo & nll | bar & typeck` == match if `foo` and `nll` both appear in the name | |
72 | /// or `typeck` and `bar` both appear in the name. | |
73 | pub fn dump_mir<'a, 'gcx, 'tcx, F>( | |
74 | tcx: TyCtxt<'a, 'gcx, 'tcx>, | |
0531ce1d | 75 | pass_num: Option<&dyn Display>, |
ff7c6d11 | 76 | pass_name: &str, |
0531ce1d | 77 | disambiguator: &dyn Display, |
ff7c6d11 XL |
78 | source: MirSource, |
79 | mir: &Mir<'tcx>, | |
80 | extra_data: F, | |
81 | ) where | |
0531ce1d | 82 | F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, |
abe05a73 | 83 | { |
7cac9316 XL |
84 | if !dump_enabled(tcx, pass_name, source) { |
85 | return; | |
86 | } | |
87 | ||
ff7c6d11 XL |
88 | let node_path = item_path::with_forced_impl_filename_line(|| { |
89 | // see notes on #41697 below | |
abe05a73 | 90 | tcx.item_path_str(source.def_id) |
7cac9316 | 91 | }); |
ff7c6d11 XL |
92 | dump_matched_mir_node( |
93 | tcx, | |
94 | pass_num, | |
95 | pass_name, | |
96 | &node_path, | |
97 | disambiguator, | |
98 | source, | |
99 | mir, | |
100 | extra_data, | |
101 | ); | |
7cac9316 XL |
102 | } |
103 | ||
ff7c6d11 XL |
104 | pub fn dump_enabled<'a, 'gcx, 'tcx>( |
105 | tcx: TyCtxt<'a, 'gcx, 'tcx>, | |
106 | pass_name: &str, | |
107 | source: MirSource, | |
108 | ) -> bool { | |
54a0048b | 109 | let filters = match tcx.sess.opts.debugging_opts.dump_mir { |
7cac9316 | 110 | None => return false, |
54a0048b SL |
111 | Some(ref filters) => filters, |
112 | }; | |
ff7c6d11 XL |
113 | let node_path = item_path::with_forced_impl_filename_line(|| { |
114 | // see notes on #41697 below | |
abe05a73 | 115 | tcx.item_path_str(source.def_id) |
7cac9316 | 116 | }); |
ff7c6d11 XL |
117 | filters.split("|").any(|or_filter| { |
118 | or_filter.split("&").all(|and_filter| { | |
119 | and_filter == "all" || pass_name.contains(and_filter) || node_path.contains(and_filter) | |
120 | }) | |
121 | }) | |
7cac9316 | 122 | } |
54a0048b | 123 | |
7cac9316 XL |
124 | // #41697 -- we use `with_forced_impl_filename_line()` because |
125 | // `item_path_str()` would otherwise trigger `type_of`, and this can | |
126 | // run while we are already attempting to evaluate `type_of`. | |
127 | ||
ff7c6d11 XL |
128 | fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>( |
129 | tcx: TyCtxt<'a, 'gcx, 'tcx>, | |
0531ce1d | 130 | pass_num: Option<&dyn Display>, |
ff7c6d11 XL |
131 | pass_name: &str, |
132 | node_path: &str, | |
0531ce1d | 133 | disambiguator: &dyn Display, |
ff7c6d11 XL |
134 | source: MirSource, |
135 | mir: &Mir<'tcx>, | |
136 | mut extra_data: F, | |
137 | ) where | |
0531ce1d | 138 | F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, |
abe05a73 | 139 | { |
83c7162d | 140 | let _: io::Result<()> = do_catch! {{ |
ff7c6d11 XL |
141 | let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, source)?; |
142 | writeln!(file, "// MIR for `{}`", node_path)?; | |
143 | writeln!(file, "// source = {:?}", source)?; | |
144 | writeln!(file, "// pass_name = {}", pass_name)?; | |
145 | writeln!(file, "// disambiguator = {}", disambiguator)?; | |
146 | if let Some(ref layout) = mir.generator_layout { | |
147 | writeln!(file, "// generator_layout = {:?}", layout)?; | |
148 | } | |
149 | writeln!(file, "")?; | |
150 | extra_data(PassWhere::BeforeCFG, &mut file)?; | |
151 | write_mir_fn(tcx, source, mir, &mut extra_data, &mut file)?; | |
152 | extra_data(PassWhere::AfterCFG, &mut file)?; | |
83c7162d | 153 | }}; |
ff7c6d11 XL |
154 | |
155 | if tcx.sess.opts.debugging_opts.dump_mir_graphviz { | |
83c7162d | 156 | let _: io::Result<()> = do_catch! {{ |
ff7c6d11 XL |
157 | let mut file = |
158 | create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, source)?; | |
159 | write_mir_fn_graphviz(tcx, source.def_id, mir, &mut file)?; | |
83c7162d | 160 | }}; |
ff7c6d11 XL |
161 | } |
162 | } | |
163 | ||
164 | /// Returns the path to the filename where we should dump a given MIR. | |
165 | /// Also used by other bits of code (e.g., NLL inference) that dump | |
166 | /// graphviz data or other things. | |
167 | fn dump_path( | |
168 | tcx: TyCtxt<'_, '_, '_>, | |
169 | extension: &str, | |
0531ce1d | 170 | pass_num: Option<&dyn Display>, |
ff7c6d11 | 171 | pass_name: &str, |
0531ce1d | 172 | disambiguator: &dyn Display, |
ff7c6d11 XL |
173 | source: MirSource, |
174 | ) -> PathBuf { | |
abe05a73 XL |
175 | let promotion_id = match source.promoted { |
176 | Some(id) => format!("-{:?}", id), | |
ff7c6d11 | 177 | None => String::new(), |
3157f602 XL |
178 | }; |
179 | ||
7cac9316 XL |
180 | let pass_num = if tcx.sess.opts.debugging_opts.dump_mir_exclude_pass_number { |
181 | format!("") | |
182 | } else { | |
183 | match pass_num { | |
184 | None => format!(".-------"), | |
abe05a73 | 185 | Some(pass_num) => format!(".{}", pass_num), |
7cac9316 XL |
186 | } |
187 | }; | |
188 | ||
5bcae85e | 189 | let mut file_path = PathBuf::new(); |
2c00a5a8 | 190 | file_path.push(Path::new(&tcx.sess.opts.debugging_opts.dump_mir_dir)); |
abe05a73 | 191 | |
ff7c6d11 XL |
192 | let item_name = tcx.hir |
193 | .def_path(source.def_id) | |
194 | .to_filename_friendly_no_crate(); | |
195 | ||
196 | let file_name = format!( | |
197 | "rustc.{}{}{}.{}.{}.{}", | |
198 | item_name, | |
199 | promotion_id, | |
200 | pass_num, | |
201 | pass_name, | |
202 | disambiguator, | |
203 | extension, | |
204 | ); | |
205 | ||
5bcae85e | 206 | file_path.push(&file_name); |
abe05a73 | 207 | |
ff7c6d11 XL |
208 | file_path |
209 | } | |
210 | ||
211 | /// Attempts to open a file where we should dump a given MIR or other | |
212 | /// bit of MIR-related data. Used by `mir-dump`, but also by other | |
213 | /// bits of code (e.g., NLL inference) that dump graphviz data or | |
214 | /// other things, and hence takes the extension as an argument. | |
215 | pub(crate) fn create_dump_file( | |
216 | tcx: TyCtxt<'_, '_, '_>, | |
217 | extension: &str, | |
0531ce1d | 218 | pass_num: Option<&dyn Display>, |
ff7c6d11 | 219 | pass_name: &str, |
0531ce1d | 220 | disambiguator: &dyn Display, |
ff7c6d11 XL |
221 | source: MirSource, |
222 | ) -> io::Result<fs::File> { | |
223 | let file_path = dump_path(tcx, extension, pass_num, pass_name, disambiguator, source); | |
224 | if let Some(parent) = file_path.parent() { | |
225 | fs::create_dir_all(parent)?; | |
abe05a73 | 226 | } |
ff7c6d11 | 227 | fs::File::create(&file_path) |
54a0048b SL |
228 | } |
229 | ||
9cc50fc6 | 230 | /// Write out a human-readable textual representation for the given MIR. |
ff7c6d11 XL |
231 | pub fn write_mir_pretty<'a, 'gcx, 'tcx>( |
232 | tcx: TyCtxt<'a, 'gcx, 'tcx>, | |
233 | single: Option<DefId>, | |
0531ce1d | 234 | w: &mut dyn Write, |
ff7c6d11 XL |
235 | ) -> io::Result<()> { |
236 | writeln!( | |
237 | w, | |
238 | "// WARNING: This output format is intended for human consumers only" | |
239 | )?; | |
240 | writeln!( | |
241 | w, | |
242 | "// and is subject to change without notice. Knock yourself out." | |
243 | )?; | |
cc61c64b | 244 | |
a7813a04 | 245 | let mut first = true; |
7cac9316 XL |
246 | for def_id in dump_mir_def_ids(tcx, single) { |
247 | let mir = &tcx.optimized_mir(def_id); | |
5bcae85e | 248 | |
a7813a04 XL |
249 | if first { |
250 | first = false; | |
251 | } else { | |
252 | // Put empty lines between all items | |
253 | writeln!(w, "")?; | |
254 | } | |
255 | ||
abe05a73 | 256 | write_mir_fn(tcx, MirSource::item(def_id), mir, &mut |_, _| Ok(()), w)?; |
a7813a04 | 257 | |
3157f602 | 258 | for (i, mir) in mir.promoted.iter_enumerated() { |
a7813a04 | 259 | writeln!(w, "")?; |
abe05a73 XL |
260 | let src = MirSource { |
261 | def_id, | |
ff7c6d11 | 262 | promoted: Some(i), |
abe05a73 XL |
263 | }; |
264 | write_mir_fn(tcx, src, mir, &mut |_, _| Ok(()), w)?; | |
a7813a04 | 265 | } |
54a0048b SL |
266 | } |
267 | Ok(()) | |
268 | } | |
9cc50fc6 | 269 | |
ff7c6d11 XL |
270 | pub fn write_mir_fn<'a, 'gcx, 'tcx, F>( |
271 | tcx: TyCtxt<'a, 'gcx, 'tcx>, | |
272 | src: MirSource, | |
273 | mir: &Mir<'tcx>, | |
274 | extra_data: &mut F, | |
0531ce1d | 275 | w: &mut dyn Write, |
ff7c6d11 | 276 | ) -> io::Result<()> |
abe05a73 | 277 | where |
0531ce1d | 278 | F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, |
abe05a73 | 279 | { |
a7813a04 | 280 | write_mir_intro(tcx, src, mir, w)?; |
3157f602 | 281 | for block in mir.basic_blocks().indices() { |
abe05a73 XL |
282 | extra_data(PassWhere::BeforeBlock(block), w)?; |
283 | write_basic_block(tcx, block, mir, extra_data, w)?; | |
3157f602 XL |
284 | if block.index() + 1 != mir.basic_blocks().len() { |
285 | writeln!(w, "")?; | |
286 | } | |
54a0048b SL |
287 | } |
288 | ||
54a0048b SL |
289 | writeln!(w, "}}")?; |
290 | Ok(()) | |
9cc50fc6 SL |
291 | } |
292 | ||
293 | /// Write out a human-readable textual representation for the given basic block. | |
ff7c6d11 XL |
294 | pub fn write_basic_block<'cx, 'gcx, 'tcx, F>( |
295 | tcx: TyCtxt<'cx, 'gcx, 'tcx>, | |
296 | block: BasicBlock, | |
297 | mir: &Mir<'tcx>, | |
298 | extra_data: &mut F, | |
0531ce1d | 299 | w: &mut dyn Write, |
ff7c6d11 | 300 | ) -> io::Result<()> |
abe05a73 | 301 | where |
0531ce1d | 302 | F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, |
abe05a73 | 303 | { |
3157f602 | 304 | let data = &mir[block]; |
9cc50fc6 SL |
305 | |
306 | // Basic block label at the top. | |
ea8adc8c XL |
307 | let cleanup_text = if data.is_cleanup { " // cleanup" } else { "" }; |
308 | let lbl = format!("{}{:?}: {{", INDENT, block); | |
309 | writeln!(w, "{0:1$}{2}", lbl, ALIGN, cleanup_text)?; | |
9cc50fc6 SL |
310 | |
311 | // List of statements in the middle. | |
ff7c6d11 XL |
312 | let mut current_location = Location { |
313 | block: block, | |
314 | statement_index: 0, | |
315 | }; | |
9cc50fc6 | 316 | for statement in &data.statements { |
ff7c6d11 | 317 | extra_data(PassWhere::BeforeLocation(current_location), w)?; |
a7813a04 | 318 | let indented_mir = format!("{0}{0}{1:?};", INDENT, statement); |
ff7c6d11 XL |
319 | writeln!( |
320 | w, | |
321 | "{:A$} // {:?}: {}", | |
322 | indented_mir, | |
323 | current_location, | |
324 | comment(tcx, statement.source_info), | |
325 | A = ALIGN, | |
326 | )?; | |
327 | ||
328 | write_extra(tcx, w, |visitor| { | |
329 | visitor.visit_statement(current_location.block, statement, current_location); | |
330 | })?; | |
331 | ||
332 | extra_data(PassWhere::AfterLocation(current_location), w)?; | |
54a0048b SL |
333 | |
334 | current_location.statement_index += 1; | |
9cc50fc6 SL |
335 | } |
336 | ||
337 | // Terminator at the bottom. | |
ff7c6d11 | 338 | extra_data(PassWhere::BeforeLocation(current_location), w)?; |
a7813a04 | 339 | let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind); |
ff7c6d11 XL |
340 | writeln!( |
341 | w, | |
342 | "{:A$} // {:?}: {}", | |
343 | indented_terminator, | |
344 | current_location, | |
345 | comment(tcx, data.terminator().source_info), | |
346 | A = ALIGN, | |
347 | )?; | |
348 | ||
349 | write_extra(tcx, w, |visitor| { | |
350 | visitor.visit_terminator(current_location.block, data.terminator(), current_location); | |
351 | })?; | |
352 | ||
353 | extra_data(PassWhere::AfterLocation(current_location), w)?; | |
9cc50fc6 | 354 | |
5bcae85e | 355 | writeln!(w, "{}}}", INDENT) |
9cc50fc6 SL |
356 | } |
357 | ||
ff7c6d11 XL |
358 | /// After we print the main statement, we sometimes dump extra |
359 | /// information. There's often a lot of little things "nuzzled up" in | |
360 | /// a statement. | |
361 | fn write_extra<'cx, 'gcx, 'tcx, F>( | |
362 | tcx: TyCtxt<'cx, 'gcx, 'tcx>, | |
0531ce1d | 363 | write: &mut dyn Write, |
ff7c6d11 XL |
364 | mut visit_op: F, |
365 | ) -> io::Result<()> | |
366 | where | |
367 | F: FnMut(&mut ExtraComments<'cx, 'gcx, 'tcx>), | |
368 | { | |
369 | let mut extra_comments = ExtraComments { | |
370 | _tcx: tcx, | |
371 | comments: vec![], | |
372 | }; | |
373 | visit_op(&mut extra_comments); | |
374 | for comment in extra_comments.comments { | |
375 | writeln!(write, "{:A$} // {}", "", comment, A = ALIGN)?; | |
376 | } | |
377 | Ok(()) | |
378 | } | |
379 | ||
380 | struct ExtraComments<'cx, 'gcx: 'tcx, 'tcx: 'cx> { | |
381 | _tcx: TyCtxt<'cx, 'gcx, 'tcx>, // don't need it now, but bet we will soon | |
382 | comments: Vec<String>, | |
383 | } | |
384 | ||
385 | impl<'cx, 'gcx, 'tcx> ExtraComments<'cx, 'gcx, 'tcx> { | |
386 | fn push(&mut self, lines: &str) { | |
387 | for line in lines.split("\n") { | |
388 | self.comments.push(line.to_string()); | |
389 | } | |
390 | } | |
391 | } | |
392 | ||
393 | impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ExtraComments<'cx, 'gcx, 'tcx> { | |
394 | fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { | |
395 | self.super_constant(constant, location); | |
396 | let Constant { span, ty, literal } = constant; | |
397 | self.push(&format!("mir::Constant")); | |
2c00a5a8 XL |
398 | self.push(&format!("+ span: {:?}", span)); |
399 | self.push(&format!("+ ty: {:?}", ty)); | |
400 | self.push(&format!("+ literal: {:?}", literal)); | |
ff7c6d11 XL |
401 | } |
402 | ||
403 | fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) { | |
404 | self.super_const(constant); | |
405 | let ty::Const { ty, val } = constant; | |
406 | self.push(&format!("ty::Const")); | |
2c00a5a8 XL |
407 | self.push(&format!("+ ty: {:?}", ty)); |
408 | self.push(&format!("+ val: {:?}", val)); | |
ff7c6d11 XL |
409 | } |
410 | ||
411 | fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { | |
412 | self.super_rvalue(rvalue, location); | |
413 | match rvalue { | |
414 | Rvalue::Aggregate(kind, _) => match **kind { | |
415 | AggregateKind::Closure(def_id, substs) => { | |
416 | self.push(&format!("closure")); | |
2c00a5a8 XL |
417 | self.push(&format!("+ def_id: {:?}", def_id)); |
418 | self.push(&format!("+ substs: {:#?}", substs)); | |
ff7c6d11 XL |
419 | } |
420 | ||
421 | AggregateKind::Generator(def_id, substs, interior) => { | |
422 | self.push(&format!("generator")); | |
2c00a5a8 XL |
423 | self.push(&format!("+ def_id: {:?}", def_id)); |
424 | self.push(&format!("+ substs: {:#?}", substs)); | |
425 | self.push(&format!("+ interior: {:?}", interior)); | |
ff7c6d11 XL |
426 | } |
427 | ||
428 | _ => {} | |
429 | }, | |
430 | ||
431 | _ => {} | |
432 | } | |
433 | } | |
434 | } | |
435 | ||
3157f602 | 436 | fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String { |
ff7c6d11 XL |
437 | format!( |
438 | "scope {} at {}", | |
439 | scope.index(), | |
440 | tcx.sess.codemap().span_to_string(span) | |
441 | ) | |
54a0048b SL |
442 | } |
443 | ||
c30ab7b3 SL |
444 | /// Prints user-defined variables in a scope tree. |
445 | /// | |
446 | /// Returns the total number of variables printed. | |
ff7c6d11 XL |
447 | fn write_scope_tree( |
448 | tcx: TyCtxt, | |
449 | mir: &Mir, | |
450 | scope_tree: &FxHashMap<VisibilityScope, Vec<VisibilityScope>>, | |
0531ce1d | 451 | w: &mut dyn Write, |
ff7c6d11 XL |
452 | parent: VisibilityScope, |
453 | depth: usize, | |
454 | ) -> io::Result<()> { | |
3157f602 | 455 | let indent = depth * INDENT.len(); |
a7813a04 XL |
456 | |
457 | let children = match scope_tree.get(&parent) { | |
458 | Some(childs) => childs, | |
459 | None => return Ok(()), | |
460 | }; | |
461 | ||
3157f602 XL |
462 | for &child in children { |
463 | let data = &mir.visibility_scopes[child]; | |
464 | assert_eq!(data.parent_scope, Some(parent)); | |
465 | writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?; | |
a7813a04 | 466 | |
3157f602 | 467 | // User variable types (including the user's name in a comment). |
c30ab7b3 SL |
468 | for local in mir.vars_iter() { |
469 | let var = &mir.local_decls[local]; | |
cc61c64b XL |
470 | let (name, source_info) = if var.source_info.scope == child { |
471 | (var.name.unwrap(), var.source_info) | |
c30ab7b3 SL |
472 | } else { |
473 | // Not a variable or not declared in this scope. | |
3157f602 | 474 | continue; |
c30ab7b3 | 475 | }; |
54a0048b | 476 | |
3157f602 XL |
477 | let mut_str = if var.mutability == Mutability::Mut { |
478 | "mut " | |
479 | } else { | |
480 | "" | |
481 | }; | |
482 | ||
483 | let indent = indent + INDENT.len(); | |
ff7c6d11 XL |
484 | let indented_var = format!( |
485 | "{0:1$}let {2}{3:?}: {4:?};", | |
486 | INDENT, | |
487 | indent, | |
488 | mut_str, | |
489 | local, | |
490 | var.ty | |
491 | ); | |
492 | writeln!( | |
493 | w, | |
494 | "{0:1$} // \"{2}\" in {3}", | |
495 | indented_var, | |
496 | ALIGN, | |
497 | name, | |
498 | comment(tcx, source_info) | |
499 | )?; | |
54a0048b SL |
500 | } |
501 | ||
3157f602 | 502 | write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?; |
a7813a04 | 503 | |
3157f602 | 504 | writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?; |
54a0048b | 505 | } |
a7813a04 | 506 | |
54a0048b SL |
507 | Ok(()) |
508 | } | |
509 | ||
9cc50fc6 SL |
510 | /// Write out a human-readable textual representation of the MIR's `fn` type and the types of its |
511 | /// local variables (both user-defined bindings and compiler temporaries). | |
ff7c6d11 XL |
512 | pub fn write_mir_intro<'a, 'gcx, 'tcx>( |
513 | tcx: TyCtxt<'a, 'gcx, 'tcx>, | |
514 | src: MirSource, | |
515 | mir: &Mir, | |
0531ce1d | 516 | w: &mut dyn Write, |
ff7c6d11 | 517 | ) -> io::Result<()> { |
3157f602 | 518 | write_mir_sig(tcx, src, mir, w)?; |
2c00a5a8 | 519 | writeln!(w, "{{")?; |
3157f602 XL |
520 | |
521 | // construct a scope tree and write it out | |
476ff2be | 522 | let mut scope_tree: FxHashMap<VisibilityScope, Vec<VisibilityScope>> = FxHashMap(); |
3157f602 XL |
523 | for (index, scope_data) in mir.visibility_scopes.iter().enumerate() { |
524 | if let Some(parent) = scope_data.parent_scope { | |
ff7c6d11 XL |
525 | scope_tree |
526 | .entry(parent) | |
527 | .or_insert(vec![]) | |
528 | .push(VisibilityScope::new(index)); | |
3157f602 XL |
529 | } else { |
530 | // Only the argument scope has no parent, because it's the root. | |
531 | assert_eq!(index, ARGUMENT_VISIBILITY_SCOPE.index()); | |
532 | } | |
533 | } | |
534 | ||
ff7c6d11 | 535 | // Print return place |
c30ab7b3 SL |
536 | let indented_retptr = format!("{}let mut {:?}: {};", |
537 | INDENT, | |
ff7c6d11 XL |
538 | RETURN_PLACE, |
539 | mir.local_decls[RETURN_PLACE].ty); | |
540 | writeln!(w, "{0:1$} // return place", | |
c30ab7b3 SL |
541 | indented_retptr, |
542 | ALIGN)?; | |
543 | ||
3157f602 XL |
544 | write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?; |
545 | ||
c30ab7b3 SL |
546 | write_temp_decls(mir, w)?; |
547 | ||
548 | // Add an empty line before the first block is printed. | |
549 | writeln!(w, "")?; | |
550 | ||
551 | Ok(()) | |
3157f602 XL |
552 | } |
553 | ||
0531ce1d | 554 | fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut dyn Write) -> io::Result<()> { |
abe05a73 XL |
555 | let id = tcx.hir.as_local_node_id(src.def_id).unwrap(); |
556 | let body_owner_kind = tcx.hir.body_owner_kind(id); | |
557 | match (body_owner_kind, src.promoted) { | |
558 | (_, Some(i)) => write!(w, "{:?} in", i)?, | |
559 | (hir::BodyOwnerKind::Fn, _) => write!(w, "fn")?, | |
560 | (hir::BodyOwnerKind::Const, _) => write!(w, "const")?, | |
561 | (hir::BodyOwnerKind::Static(hir::MutImmutable), _) => write!(w, "static")?, | |
562 | (hir::BodyOwnerKind::Static(hir::MutMutable), _) => write!(w, "static mut")?, | |
9cc50fc6 SL |
563 | } |
564 | ||
ff7c6d11 XL |
565 | item_path::with_forced_impl_filename_line(|| { |
566 | // see notes on #41697 elsewhere | |
abe05a73 | 567 | write!(w, " {}", tcx.item_path_str(src.def_id)) |
7cac9316 | 568 | })?; |
a7813a04 | 569 | |
abe05a73 XL |
570 | match (body_owner_kind, src.promoted) { |
571 | (hir::BodyOwnerKind::Fn, None) => { | |
ea8adc8c XL |
572 | write!(w, "(")?; |
573 | ||
574 | // fn argument types. | |
575 | for (i, arg) in mir.args_iter().enumerate() { | |
576 | if i != 0 { | |
577 | write!(w, ", ")?; | |
578 | } | |
ff7c6d11 | 579 | write!(w, "{:?}: {}", Place::Local(arg), mir.local_decls[arg].ty)?; |
a7813a04 | 580 | } |
9cc50fc6 | 581 | |
2c00a5a8 | 582 | write!(w, ") -> {}", mir.return_ty())?; |
ea8adc8c | 583 | } |
ff7c6d11 | 584 | (hir::BodyOwnerKind::Const, _) | (hir::BodyOwnerKind::Static(_), _) | (_, Some(_)) => { |
ea8adc8c | 585 | assert_eq!(mir.arg_count, 0); |
2c00a5a8 | 586 | write!(w, ": {} =", mir.return_ty())?; |
ea8adc8c | 587 | } |
9cc50fc6 | 588 | } |
2c00a5a8 XL |
589 | |
590 | if let Some(yield_ty) = mir.yield_ty { | |
591 | writeln!(w)?; | |
592 | writeln!(w, "yields {}", yield_ty)?; | |
593 | } | |
594 | ||
595 | Ok(()) | |
3157f602 | 596 | } |
9cc50fc6 | 597 | |
0531ce1d | 598 | fn write_temp_decls(mir: &Mir, w: &mut dyn Write) -> io::Result<()> { |
9cc50fc6 | 599 | // Compiler-introduced temporary types. |
c30ab7b3 | 600 | for temp in mir.temps_iter() { |
ff7c6d11 XL |
601 | writeln!( |
602 | w, | |
603 | "{}let mut {:?}: {};", | |
604 | INDENT, | |
605 | temp, | |
606 | mir.local_decls[temp].ty | |
607 | )?; | |
a7813a04 XL |
608 | } |
609 | ||
9cc50fc6 SL |
610 | Ok(()) |
611 | } | |
7cac9316 XL |
612 | |
613 | pub fn dump_mir_def_ids(tcx: TyCtxt, single: Option<DefId>) -> Vec<DefId> { | |
614 | if let Some(i) = single { | |
615 | vec![i] | |
616 | } else { | |
617 | tcx.mir_keys(LOCAL_CRATE).iter().cloned().collect() | |
618 | } | |
619 | } |