about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/mir/repr.rs111
-rw-r--r--src/librustc_mir/lib.rs6
-rw-r--r--src/librustc_mir/mir_map.rs29
-rw-r--r--src/librustc_mir/pretty.rs85
4 files changed, 191 insertions, 40 deletions
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index b6e86077ccf..75a588d424e 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -18,7 +18,7 @@ use rustc_front::hir::InlineAsm;
 use syntax::ast::Name;
 use syntax::codemap::Span;
 use std::borrow::{Cow, IntoCow};
-use std::fmt::{Debug, Formatter, Error, Write};
+use std::fmt::{self, Debug, Formatter, Write};
 use std::{iter, u32};
 
 /// Lowered representation of a single function.
@@ -183,8 +183,8 @@ impl BasicBlock {
 }
 
 impl Debug for BasicBlock {
-    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
-        write!(fmt, "BB({})", self.0)
+    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
+        write!(fmt, "bb{}", self.0)
     }
 }
 
@@ -317,7 +317,7 @@ impl<'tcx> BasicBlockData<'tcx> {
 }
 
 impl<'tcx> Debug for Terminator<'tcx> {
-    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
+    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
         try!(self.fmt_head(fmt));
         let successors = self.successors();
         let labels = self.fmt_successor_labels();
@@ -347,7 +347,7 @@ impl<'tcx> Terminator<'tcx> {
     /// Write the "head" part of the terminator; that is, its name and the data it uses to pick the
     /// successor basic block, if any. The only information not inlcuded is the list of possible
     /// successors, which may be rendered differently between the text and the graphviz format.
-    pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> Result<(), Error> {
+    pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> fmt::Result {
         use self::Terminator::*;
         match *self {
             Goto { .. } => write!(fmt, "goto"),
@@ -421,7 +421,7 @@ pub enum DropKind {
 }
 
 impl<'tcx> Debug for Statement<'tcx> {
-    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
+    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
         use self::StatementKind::*;
         match self.kind {
             Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv),
@@ -541,7 +541,7 @@ impl<'tcx> Lvalue<'tcx> {
 }
 
 impl<'tcx> Debug for Lvalue<'tcx> {
-    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
+    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
         use self::Lvalue::*;
 
         match *self {
@@ -551,24 +551,24 @@ impl<'tcx> Debug for Lvalue<'tcx> {
                 write!(fmt,"arg{:?}", id),
             Temp(id) =>
                 write!(fmt,"tmp{:?}", id),
-            Static(id) =>
-                write!(fmt,"Static({:?})", id),
+            Static(def_id) =>
+                write!(fmt, "{}", ty::tls::with(|tcx| tcx.item_path_str(def_id))),
             ReturnPointer =>
-                write!(fmt,"ReturnPointer"),
+                write!(fmt, "return"),
             Projection(ref data) =>
                 match data.elem {
                     ProjectionElem::Downcast(ref adt_def, index) =>
-                        write!(fmt,"({:?} as {})", data.base, adt_def.variants[index].name),
+                        write!(fmt, "({:?} as {})", data.base, adt_def.variants[index].name),
                     ProjectionElem::Deref =>
-                        write!(fmt,"(*{:?})", data.base),
+                        write!(fmt, "(*{:?})", data.base),
                     ProjectionElem::Field(field) =>
-                        write!(fmt,"{:?}.{:?}", data.base, field.index()),
+                        write!(fmt, "{:?}.{:?}", data.base, field.index()),
                     ProjectionElem::Index(ref index) =>
-                        write!(fmt,"{:?}[{:?}]", data.base, index),
+                        write!(fmt, "{:?}[{:?}]", data.base, index),
                     ProjectionElem::ConstantIndex { offset, min_length, from_end: false } =>
-                        write!(fmt,"{:?}[{:?} of {:?}]", data.base, offset, min_length),
+                        write!(fmt, "{:?}[{:?} of {:?}]", data.base, offset, min_length),
                     ProjectionElem::ConstantIndex { offset, min_length, from_end: true } =>
-                        write!(fmt,"{:?}[-{:?} of {:?}]", data.base, offset, min_length),
+                        write!(fmt, "{:?}[-{:?} of {:?}]", data.base, offset, min_length),
                 },
         }
     }
@@ -588,7 +588,7 @@ pub enum Operand<'tcx> {
 }
 
 impl<'tcx> Debug for Operand<'tcx> {
-    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
+    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
         use self::Operand::*;
         match *self {
             Constant(ref a) => write!(fmt, "{:?}", a),
@@ -715,22 +715,87 @@ pub enum UnOp {
 }
 
 impl<'tcx> Debug for Rvalue<'tcx> {
-    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
+    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
         use self::Rvalue::*;
 
         match *self {
             Use(ref lvalue) => write!(fmt, "{:?}", lvalue),
             Repeat(ref a, ref b) => write!(fmt, "[{:?}; {:?}]", a, b),
-            Ref(ref a, bk, ref b) => write!(fmt, "&{:?} {:?} {:?}", a, bk, b),
             Len(ref a) => write!(fmt, "Len({:?})", a),
             Cast(ref kind, ref lv, ref ty) => write!(fmt, "{:?} as {:?} ({:?})", lv, ty, kind),
             BinaryOp(ref op, ref a, ref b) => write!(fmt, "{:?}({:?}, {:?})", op, a, b),
             UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a),
             Box(ref t) => write!(fmt, "Box({:?})", t),
-            Aggregate(ref kind, ref lvs) => write!(fmt, "Aggregate<{:?}>{:?}", kind, lvs),
             InlineAsm(ref asm) => write!(fmt, "InlineAsm({:?})", asm),
             Slice { ref input, from_start, from_end } =>
                 write!(fmt, "{:?}[{:?}..-{:?}]", input, from_start, from_end),
+
+            Ref(_, borrow_kind, ref lv) => {
+                let kind_str = match borrow_kind {
+                    BorrowKind::Shared => "",
+                    BorrowKind::Mut | BorrowKind::Unique => "mut ",
+                };
+                write!(fmt, "&{}{:?}", kind_str, lv)
+            }
+
+            Aggregate(ref kind, ref lvs) => {
+                use self::AggregateKind::*;
+
+                fn fmt_tuple(fmt: &mut Formatter, name: &str, lvs: &[Operand]) -> fmt::Result {
+                    let mut tuple_fmt = fmt.debug_tuple(name);
+                    for lv in lvs {
+                        tuple_fmt.field(lv);
+                    }
+                    tuple_fmt.finish()
+                }
+
+                match *kind {
+                    Vec => write!(fmt, "{:?}", lvs),
+
+                    Tuple => {
+                        if lvs.len() == 1 {
+                            write!(fmt, "({:?},)", lvs[0])
+                        } else {
+                            fmt_tuple(fmt, "", lvs)
+                        }
+                    }
+
+                    Adt(adt_def, variant, _) => {
+                        let variant_def = &adt_def.variants[variant];
+                        let name = ty::tls::with(|tcx| tcx.item_path_str(variant_def.did));
+
+                        match variant_def.kind() {
+                            ty::VariantKind::Unit => write!(fmt, "{}", name),
+                            ty::VariantKind::Tuple => fmt_tuple(fmt, &name, lvs),
+                            ty::VariantKind::Struct => {
+                                let mut struct_fmt = fmt.debug_struct(&name);
+                                for (field, lv) in variant_def.fields.iter().zip(lvs) {
+                                    struct_fmt.field(&field.name.as_str(), lv);
+                                }
+                                struct_fmt.finish()
+                            }
+                        }
+                    }
+
+                    Closure(def_id, _) => ty::tls::with(|tcx| {
+                        if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
+                            let name = format!("[closure@{:?}]", tcx.map.span(node_id));
+                            let mut struct_fmt = fmt.debug_struct(&name);
+
+                            tcx.with_freevars(node_id, |freevars| {
+                                for (freevar, lv) in freevars.iter().zip(lvs) {
+                                    let var_name = tcx.local_var_name_str(freevar.def.var_id());
+                                    struct_fmt.field(&var_name, lv);
+                                }
+                            });
+
+                            struct_fmt.finish()
+                        } else {
+                            write!(fmt, "[closure]")
+                        }
+                    }),
+                }
+            }
         }
     }
 }
@@ -771,13 +836,13 @@ pub enum Literal<'tcx> {
 }
 
 impl<'tcx> Debug for Constant<'tcx> {
-    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
+    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
         write!(fmt, "{:?}", self.literal)
     }
 }
 
 impl<'tcx> Debug for Literal<'tcx> {
-    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
+    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
         use self::Literal::*;
         match *self {
             Item { def_id, .. } =>
@@ -788,7 +853,7 @@ impl<'tcx> Debug for Literal<'tcx> {
 }
 
 /// Write a `ConstVal` in a way closer to the original source code than the `Debug` output.
-pub fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> Result<(), Error> {
+pub fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
     use middle::const_eval::ConstVal::*;
     match *const_val {
         Float(f) => write!(fmt, "{:?}", f),
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 6a1134385d9..9cc40bbc383 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -29,8 +29,8 @@ extern crate rustc_back;
 extern crate syntax;
 
 pub mod build;
-pub mod mir_map;
+pub mod graphviz;
 mod hair;
-mod graphviz;
+pub mod mir_map;
+pub mod pretty;
 pub mod transform;
-
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index 5c9399ebdad..a3ca4c05456 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -22,6 +22,7 @@ extern crate rustc_front;
 
 use build;
 use graphviz;
+use pretty;
 use transform::*;
 use rustc::mir::repr::Mir;
 use hair::cx::Cx;
@@ -152,29 +153,29 @@ impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
                                          .flat_map(|a| a.meta_item_list())
                                          .flat_map(|l| l.iter());
                 for item in meta_item_list {
-                    if item.check_name("graphviz") {
+                    if item.check_name("graphviz") || item.check_name("pretty") {
                         match item.value_str() {
                             Some(s) => {
-                                match
-                                    File::create(format!("{}{}", prefix, s))
-                                    .and_then(|ref mut output| {
+                                let filename = format!("{}{}", prefix, s);
+                                let result = File::create(&filename).and_then(|ref mut output| {
+                                    if item.check_name("graphviz") {
                                         graphviz::write_mir_graphviz(&mir, output)
-                                    })
-                                {
-                                    Ok(()) => { }
-                                    Err(e) => {
-                                        self.tcx.sess.span_fatal(
-                                            item.span,
-                                            &format!("Error writing graphviz \
-                                                      results to `{}`: {}",
-                                                     s, e));
+                                    } else {
+                                        pretty::write_mir_pretty(&mir, output)
                                     }
+                                });
+
+                                if let Err(e) = result {
+                                    self.tcx.sess.span_fatal(
+                                        item.span,
+                                        &format!("Error writing MIR {} results to `{}`: {}",
+                                                 item.name(), filename, e));
                                 }
                             }
                             None => {
                                 self.tcx.sess.span_err(
                                     item.span,
-                                    "graphviz attribute requires a path");
+                                    &format!("{} attribute requires a path", item.name()));
                             }
                         }
                     }
diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs
new file mode 100644
index 00000000000..163559f2792
--- /dev/null
+++ b/src/librustc_mir/pretty.rs
@@ -0,0 +1,85 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::mir::repr::*;
+use rustc::middle::ty;
+use std::io::{self, Write};
+
+const INDENT: &'static str = "    ";
+
+/// Write out a human-readable textual representation for the given MIR.
+pub fn write_mir_pretty<W: Write>(mir: &Mir, w: &mut W) -> io::Result<()> {
+    try!(write_mir_intro(mir, w));
+
+    // Nodes
+    for block in mir.all_basic_blocks() {
+        try!(write_basic_block(block, mir, w));
+    }
+
+    writeln!(w, "}}")
+}
+
+/// Write out a human-readable textual representation for the given basic block.
+fn write_basic_block<W: Write>(block: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<()> {
+    let data = mir.basic_block_data(block);
+
+    // Basic block label at the top.
+    try!(writeln!(w, "\n{}{:?}: {{", INDENT, block));
+
+    // List of statements in the middle.
+    for statement in &data.statements {
+        try!(writeln!(w, "{0}{0}{1:?};", INDENT, statement));
+    }
+
+    // Terminator at the bottom.
+    try!(writeln!(w, "{0}{0}{1:?};", INDENT, data.terminator));
+
+    writeln!(w, "{}}}", INDENT)
+}
+
+/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
+/// local variables (both user-defined bindings and compiler temporaries).
+fn write_mir_intro<W: Write>(mir: &Mir, w: &mut W) -> io::Result<()> {
+    try!(write!(w, "fn("));
+
+    // fn argument types.
+    for (i, arg) in mir.arg_decls.iter().enumerate() {
+        if i > 0 {
+            try!(write!(w, ", "));
+        }
+        try!(write!(w, "{:?}: {}", Lvalue::Arg(i as u32), arg.ty));
+    }
+
+    try!(write!(w, ") -> "));
+
+    // fn return type.
+    match mir.return_ty {
+        ty::FnOutput::FnConverging(ty) => try!(write!(w, "{}", ty)),
+        ty::FnOutput::FnDiverging => try!(write!(w, "!")),
+    }
+
+    try!(writeln!(w, " {{"));
+
+    // User variable types (including the user's name in a comment).
+    for (i, var) in mir.var_decls.iter().enumerate() {
+        try!(write!(w, "{}let ", INDENT));
+        if var.mutability == Mutability::Mut {
+            try!(write!(w, "mut "));
+        }
+        try!(writeln!(w, "{:?}: {}; // {}", Lvalue::Var(i as u32), var.ty, var.name));
+    }
+
+    // Compiler-introduced temporary types.
+    for (i, temp) in mir.temp_decls.iter().enumerate() {
+        try!(writeln!(w, "{}let mut {:?}: {};", INDENT, Lvalue::Temp(i as u32), temp.ty));
+    }
+
+    Ok(())
+}