about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-03-27 21:51:53 -0700
committerbors <bors@rust-lang.org>2013-03-27 21:51:53 -0700
commit84ddff3909b5920228642649b7f5cc011c0b900a (patch)
tree25cfe9b7ddd20bc08ea56de4fe87dbabf9a885f0
parent4954d3e50177c46d260a5340ff91bfada8590ef0 (diff)
parentc317d3f6fa9475e65b6276743c09444441059ca7 (diff)
downloadrust-84ddff3909b5920228642649b7f5cc011c0b900a.tar.gz
rust-84ddff3909b5920228642649b7f5cc011c0b900a.zip
auto merge of #5578 : erickt/rust/incoming, r=jbclements,erickt
Hey folks,

This patch series does some work on the json decoder, specifically with auto decoding of enums. Previously, we would take this code:

```
enum A {
    B,
    C(~str, uint)
}
```

and would encode a value of this enum to either `["B", []]` or `["C", ["D", 123]]`. I've changed this to `"B"` or `["C", "D", 123]`. This matches the style of the O'Caml json library [json-wheel](http://mjambon.com/json-wheel.html). I've added tests to make sure all this work.

In order to make this change, I added passing a `&[&str]` vec to `Decode::emit_enum_variant` so the json decoder can convert the name of a variant into it's position. I also changed the impl of `Encodable` for `Option<T>` to have the right upper casing.

I also did some work on the parser, which allows for `fn foo<T: ::cmp::Eq>() { ... }` statements (#5572), fixed the pretty printer properly expanding `debug!("...")` expressions, and removed `ast::expr_vstore_fixed`, which doesn't appear to be used anymore.
-rw-r--r--src/librustc/middle/astencode.rs39
-rw-r--r--src/librustc/middle/check_const.rs1
-rw-r--r--src/librustc/middle/const_eval.rs1
-rw-r--r--src/librustc/middle/liveness.rs2
-rw-r--r--src/librustc/middle/moves.rs2
-rw-r--r--src/librustc/middle/trans/consts.rs3
-rw-r--r--src/librustc/middle/trans/expr.rs5
-rw-r--r--src/librustc/middle/trans/type_use.rs2
-rw-r--r--src/librustc/middle/ty.rs1
-rw-r--r--src/librustc/middle/typeck/check/mod.rs10
-rw-r--r--src/libstd/ebml.rs56
-rw-r--r--src/libstd/json.rs581
-rw-r--r--src/libstd/prettyprint.rs14
-rw-r--r--src/libstd/serialize.rs37
-rw-r--r--src/libsyntax/ast.rs9
-rw-r--r--src/libsyntax/ext/auto_encode.rs96
-rw-r--r--src/libsyntax/ext/build.rs5
-rw-r--r--src/libsyntax/ext/quote.rs167
-rw-r--r--src/libsyntax/fold.rs3
-rw-r--r--src/libsyntax/parse/mod.rs39
-rw-r--r--src/libsyntax/parse/parser.rs17
-rw-r--r--src/libsyntax/print/pprust.rs41
-rw-r--r--src/libsyntax/visit.rs2
-rw-r--r--src/test/run-pass/issue-5572.rs3
24 files changed, 820 insertions, 316 deletions
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 2ec5b59b9c5..c2692e9fa10 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -681,6 +681,7 @@ impl vtable_decoder_helpers for reader::Decoder {
         @self.read_to_vec(|| self.read_vtable_origin(xcx) )
     }
 
+    #[cfg(stage0)]
     fn read_vtable_origin(&self, xcx: @ExtendedDecodeContext)
         -> typeck::vtable_origin {
         do self.read_enum(~"vtable_origin") {
@@ -715,6 +716,44 @@ impl vtable_decoder_helpers for reader::Decoder {
             }
         }
     }
+
+    #[cfg(stage1)]
+    #[cfg(stage2)]
+    #[cfg(stage3)]
+    fn read_vtable_origin(&self, xcx: @ExtendedDecodeContext)
+        -> typeck::vtable_origin {
+        do self.read_enum("vtable_origin") {
+            do self.read_enum_variant(["vtable_static", "vtable_param"]) |i| {
+                match i {
+                  0 => {
+                    typeck::vtable_static(
+                        do self.read_enum_variant_arg(0u) {
+                            self.read_def_id(xcx)
+                        },
+                        do self.read_enum_variant_arg(1u) {
+                            self.read_tys(xcx)
+                        },
+                        do self.read_enum_variant_arg(2u) {
+                            self.read_vtable_res(xcx)
+                        }
+                    )
+                  }
+                  1 => {
+                    typeck::vtable_param(
+                        do self.read_enum_variant_arg(0u) {
+                            self.read_uint()
+                        },
+                        do self.read_enum_variant_arg(1u) {
+                            self.read_uint()
+                        }
+                    )
+                  }
+                  // hard to avoid - user input
+                  _ => fail!(~"bad enum variant")
+                }
+            }
+        }
+    }
 }
 
 // ______________________________________________________________________
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index f9212d1ff7b..4bbedf5fc00 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -156,7 +156,6 @@ pub fn check_expr(sess: Session,
           expr_paren(e) => { check_expr(sess, def_map, method_map,
                                          tcx, e, is_const, v); }
           expr_vstore(_, expr_vstore_slice) |
-          expr_vstore(_, expr_vstore_fixed(_)) |
           expr_vec(_, m_imm) |
           expr_addr_of(m_imm, _) |
           expr_field(*) |
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index a25d873af41..d610b007f35 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -110,7 +110,6 @@ pub fn classify(e: @expr,
 
               ast::expr_vstore(e, vstore) => {
                   match vstore {
-                      ast::expr_vstore_fixed(_) |
                       ast::expr_vstore_slice => classify(e, tcx),
                       ast::expr_vstore_uniq |
                       ast::expr_vstore_box |
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 4d6226a5db6..503077e5b06 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -1290,7 +1290,7 @@ pub impl Liveness {
             self.propagate_through_expr(l, ln)
           }
 
-          expr_log(_, l, r) |
+          expr_log(l, r) |
           expr_index(l, r) |
           expr_binary(_, l, r) => {
             self.propagate_through_exprs(~[l, r], succ)
diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs
index f5382d69174..a8749138549 100644
--- a/src/librustc/middle/moves.rs
+++ b/src/librustc/middle/moves.rs
@@ -567,7 +567,7 @@ pub impl VisitContext {
                 self.consume_block(blk, visitor);
             }
 
-            expr_log(_, a_expr, b_expr) => {
+            expr_log(a_expr, b_expr) => {
                 self.consume_expr(a_expr, visitor);
                 self.use_expr(b_expr, Read, visitor);
             }
diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs
index 1362f97c08e..050fc0dd334 100644
--- a/src/librustc/middle/trans/consts.rs
+++ b/src/librustc/middle/trans/consts.rs
@@ -466,9 +466,6 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef {
             let (v, _, _) = const_vec(cx, e, *es);
             v
           }
-          ast::expr_vstore(e, ast::expr_vstore_fixed(_)) => {
-            const_expr(cx, e)
-          }
           ast::expr_vstore(sub, ast::expr_vstore_slice) => {
             match sub.node {
               ast::expr_lit(ref lit) => {
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 3e1496692ae..4ee63f8bf33 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -496,7 +496,7 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block {
         ast::expr_ret(ex) => {
             return controlflow::trans_ret(bcx, ex);
         }
-        ast::expr_log(_, lvl, a) => {
+        ast::expr_log(lvl, a) => {
             return controlflow::trans_log(expr, lvl, bcx, a);
         }
         ast::expr_while(cond, ref body) => {
@@ -703,9 +703,6 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
         ast::expr_vstore(contents, ast::expr_vstore_mut_slice) => {
             return tvec::trans_slice_vstore(bcx, expr, contents, dest);
         }
-        ast::expr_vstore(contents, ast::expr_vstore_fixed(_)) => {
-            return tvec::trans_fixed_vstore(bcx, expr, contents, dest);
-        }
         ast::expr_vec(*) | ast::expr_repeat(*) => {
             return tvec::trans_fixed_vstore(bcx, expr, expr, dest);
         }
diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs
index cad2a03f7a1..1d9e57ce8ce 100644
--- a/src/librustc/middle/trans/type_use.rs
+++ b/src/librustc/middle/trans/type_use.rs
@@ -329,7 +329,7 @@ pub fn mark_for_expr(cx: Context, e: @expr) {
         type_needs(cx, use_repr, ty::type_autoderef(cx.ccx.tcx, base_ty));
         mark_for_method_call(cx, e.id, e.callee_id);
       }
-      expr_log(_, _, val) => {
+      expr_log(_, val) => {
         node_type_needs(cx, use_tydesc, val.id);
       }
       expr_call(f, _, _) => {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 088d8183d48..58db934160b 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -3114,7 +3114,6 @@ pub fn expr_kind(tcx: ctxt,
         ast::expr_lit(@codemap::spanned {node: lit_str(_), _}) |
         ast::expr_vstore(_, ast::expr_vstore_slice) |
         ast::expr_vstore(_, ast::expr_vstore_mut_slice) |
-        ast::expr_vstore(_, ast::expr_vstore_fixed(_)) |
         ast::expr_vec(*) => {
             RvalueDpsExpr
         }
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 85efc9fa738..8762cdf516b 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -2366,7 +2366,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
         }
         fcx.write_bot(id);
       }
-      ast::expr_log(_, lv, e) => {
+      ast::expr_log(lv, e) => {
         check_expr_has_type(fcx, lv,
                                   ty::mk_mach_uint(tcx, ast::ty_u32));
 
@@ -3301,14 +3301,6 @@ pub fn ast_expr_vstore_to_vstore(fcx: @mut FnCtxt,
                                  v: ast::expr_vstore)
                               -> ty::vstore {
     match v {
-        ast::expr_vstore_fixed(None) => ty::vstore_fixed(n),
-        ast::expr_vstore_fixed(Some(u)) => {
-            if n != u {
-                let s = fmt!("fixed-size sequence mismatch: %u vs. %u",u, n);
-                fcx.ccx.tcx.sess.span_err(e.span,s);
-            }
-            ty::vstore_fixed(u)
-        }
         ast::expr_vstore_uniq => ty::vstore_uniq,
         ast::expr_vstore_box | ast::expr_vstore_mut_box => ty::vstore_box,
         ast::expr_vstore_slice | ast::expr_vstore_mut_slice => {
diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs
index b82616d386a..8b559295819 100644
--- a/src/libstd/ebml.rs
+++ b/src/libstd/ebml.rs
@@ -335,6 +335,7 @@ pub mod reader {
             self.push_doc(self.next_doc(EsEnum), f)
         }
 
+        #[cfg(stage0)]
         fn read_enum_variant<T>(&self, f: &fn(uint) -> T) -> T {
             debug!("read_enum_variant()");
             let idx = self._next_uint(EsEnumVid);
@@ -344,6 +345,18 @@ pub mod reader {
             }
         }
 
+        #[cfg(stage1)]
+        #[cfg(stage2)]
+        #[cfg(stage3)]
+        fn read_enum_variant<T>(&self, _names: &[&str], f: &fn(uint) -> T) -> T {
+            debug!("read_enum_variant()");
+            let idx = self._next_uint(EsEnumVid);
+            debug!("  idx=%u", idx);
+            do self.push_doc(self.next_doc(EsEnumBody)) {
+                f(idx)
+            }
+        }
+
         fn read_enum_variant_arg<T>(&self, idx: uint, f: &fn() -> T) -> T {
             debug!("read_enum_variant_arg(idx=%u)", idx);
             f()
@@ -397,8 +410,37 @@ pub mod reader {
             debug!("read_tup_elt(idx=%u)", idx);
             f()
         }
-    }
 
+        #[cfg(stage0)]
+        fn read_option<T>(&self, f: &fn() -> T) -> Option<T> {
+            debug!("read_option()");
+            do self.read_enum("Option") || {
+                do self.read_enum_variant |idx| {
+                    match idx {
+                        0 => None,
+                        1 => Some(f()),
+                        _ => fail!(),
+                    }
+                }
+            }
+        }
+
+        #[cfg(stage1)]
+        #[cfg(stage2)]
+        #[cfg(stage3)]
+        fn read_option<T>(&self, f: &fn() -> T) -> Option<T> {
+            debug!("read_option()");
+            do self.read_enum("Option") || {
+                do self.read_enum_variant(["None", "Some"]) |idx| {
+                    match idx {
+                        0 => None,
+                        1 => Some(f()),
+                        _ => fail!(),
+                    }
+                }
+            }
+        }
+    }
 }
 
 pub mod writer {
@@ -664,9 +706,19 @@ pub mod writer {
 
         fn emit_tup(&self, _len: uint, f: &fn()) { f() }
         fn emit_tup_elt(&self, _idx: uint, f: &fn()) { f() }
-    }
 
+        fn emit_option(&self, f: &fn()) {
+            self.emit_enum("Option", f);
+        }
+        fn emit_option_none(&self) {
+            self.emit_enum_variant("None", 0, 0, || ())
+        }
+        fn emit_option_some(&self, f: &fn()) {
+            self.emit_enum_variant("Some", 1, 1, f)
+        }
+    }
 }
+
 // ___________________________________________________________________________
 // Testing
 
diff --git a/src/libstd/json.rs b/src/libstd/json.rs
index 7c9b15bfded..c48b210dca2 100644
--- a/src/libstd/json.rs
+++ b/src/libstd/json.rs
@@ -119,39 +119,19 @@ impl serialize::Encoder for Encoder {
         f()
     }
 
-    fn emit_enum_variant(&self, name: &str, _id: uint, _cnt: uint, f: &fn()) {
-        // encoding of enums is special-cased for Option. Specifically:
-        // Some(34) => 34
-        // None => null
-
-        // other enums are encoded as vectors:
+    fn emit_enum_variant(&self, name: &str, _id: uint, cnt: uint, f: &fn()) {
+        // enums are encoded as strings or vectors:
+        // Bunny => "Bunny"
         // Kangaroo(34,"William") => ["Kangaroo",[34,"William"]]
 
-        // the default expansion for enums is more verbose than I'd like;
-        // specifically, the inner pair of brackets seems superfluous,
-        // BUT the design of the enumeration framework and the requirements
-        // of the special-case for Option mean that a first argument must
-        // be encoded "naked"--with no commas--and that the option name
-        // can't be followed by just a comma, because there might not
-        // be any elements in the tuple.
-
-        // FIXME #4872: this would be more precise and less frightening
-        // with fully-qualified option names. To get that information,
-        // we'd have to change the expansion of auto-encode to pass
-        // those along.
-
-        if (name == ~"Some") {
-            f();
-        } else if (name == ~"None") {
-            self.wr.write_str(~"null");
+        if cnt == 0 {
+            self.wr.write_str(escape_str(name));
         } else {
             self.wr.write_char('[');
             self.wr.write_str(escape_str(name));
             self.wr.write_char(',');
-            self.wr.write_char('[');
             f();
             self.wr.write_char(']');
-            self.wr.write_char(']');
         }
     }
 
@@ -200,6 +180,10 @@ impl serialize::Encoder for Encoder {
     fn emit_tup_elt(&self, idx: uint, f: &fn()) {
         self.emit_vec_elt(idx, f)
     }
+
+    fn emit_option(&self, f: &fn()) { f(); }
+    fn emit_option_none(&self) { self.emit_nil(); }
+    fn emit_option_some(&self, f: &fn()) { f(); }
 }
 
 pub struct PrettyEncoder {
@@ -250,27 +234,44 @@ impl serialize::Encoder for PrettyEncoder {
     fn emit_owned(&self, f: &fn()) { f() }
     fn emit_managed(&self, f: &fn()) { f() }
 
-    fn emit_enum(&self, name: &str, f: &fn()) {
-        if name != "option" { fail!(~"only supports option enum") }
-        f()
-    }
-    fn emit_enum_variant(&self, _name: &str, id: uint, _cnt: uint, f: &fn()) {
-        if id == 0 {
-            self.emit_nil();
+    fn emit_enum(&self, _name: &str, f: &fn()) { f() }
+    fn emit_enum_variant(&self, name: &str, _id: uint, cnt: uint, f: &fn()) {
+        if cnt == 0 {
+            self.wr.write_str(escape_str(name));
         } else {
-            f()
+            self.wr.write_char('[');
+            self.indent += 2;
+            self.wr.write_char('\n');
+            self.wr.write_str(spaces(self.indent));
+            self.wr.write_str(escape_str(name));
+            self.wr.write_str(",\n");
+            f();
+            self.wr.write_char('\n');
+            self.indent -= 2;
+            self.wr.write_str(spaces(self.indent));
+            self.wr.write_char(']');
         }
     }
-    fn emit_enum_variant_arg(&self, _idx: uint, f: &fn()) {
+    fn emit_enum_variant_arg(&self, idx: uint, f: &fn()) {
+        if idx != 0 {
+            self.wr.write_str(",\n");
+        }
+        self.wr.write_str(spaces(self.indent));
         f()
     }
 
-    fn emit_borrowed_vec(&self, _len: uint, f: &fn()) {
-        self.wr.write_char('[');
-        self.indent += 2;
-        f();
-        self.indent -= 2;
-        self.wr.write_char(']');
+    fn emit_borrowed_vec(&self, len: uint, f: &fn()) {
+        if len == 0 {
+            self.wr.write_str("[]");
+        } else {
+            self.wr.write_char('[');
+            self.indent += 2;
+            f();
+            self.wr.write_char('\n');
+            self.indent -= 2;
+            self.wr.write_str(spaces(self.indent));
+            self.wr.write_char(']');
+        }
     }
     fn emit_owned_vec(&self, len: uint, f: &fn()) {
         self.emit_borrowed_vec(len, f)
@@ -292,11 +293,17 @@ impl serialize::Encoder for PrettyEncoder {
         self.wr.write_char('{');
         self.indent += 2;
         f();
+        self.wr.write_char('\n');
         self.indent -= 2;
+        self.wr.write_str(spaces(self.indent));
         self.wr.write_char('}');
     }
-    fn emit_struct(&self, _name: &str, _len: uint, f: &fn()) {
-        self.emit_rec(f)
+    fn emit_struct(&self, _name: &str, len: uint, f: &fn()) {
+        if len == 0 {
+            self.wr.write_str("{}");
+        } else {
+            self.emit_rec(f)
+        }
     }
     fn emit_field(&self, name: &str, idx: uint, f: &fn()) {
         if idx == 0 {
@@ -315,6 +322,10 @@ impl serialize::Encoder for PrettyEncoder {
     fn emit_tup_elt(&self, idx: uint, f: &fn()) {
         self.emit_vec_elt(idx, f)
     }
+
+    fn emit_option(&self, f: &fn()) { f(); }
+    fn emit_option_none(&self) { self.emit_nil(); }
+    fn emit_option_some(&self, f: &fn()) { f(); }
 }
 
 impl<S:serialize::Encoder> serialize::Encodable<S> for Json {
@@ -816,7 +827,7 @@ impl<'self> serialize::Decoder for Decoder<'self> {
         debug!("read_owned_str");
         match *self.pop() {
             String(ref s) => copy *s,
-            _ => fail!(~"not a string")
+            ref json => fail!(fmt!("not a string: %?", *json))
         }
     }
 
@@ -824,7 +835,7 @@ impl<'self> serialize::Decoder for Decoder<'self> {
         debug!("read_managed_str");
         match *self.pop() {
             String(ref s) => s.to_managed(),
-            _ => fail!(~"not a string")
+            ref json => fail!(fmt!("not a string: %?", *json))
         }
     }
 
@@ -840,10 +851,10 @@ impl<'self> serialize::Decoder for Decoder<'self> {
 
     fn read_enum<T>(&self, name: &str, f: &fn() -> T) -> T {
         debug!("read_enum(%s)", name);
-        if name != ~"option" { fail!(~"only supports the option enum") }
         f()
     }
 
+    #[cfg(stage0)]
     fn read_enum_variant<T>(&self, f: &fn(uint) -> T) -> T {
         debug!("read_enum_variant()");
         let idx = match *self.peek() {
@@ -853,10 +864,32 @@ impl<'self> serialize::Decoder for Decoder<'self> {
         f(idx)
     }
 
+    #[cfg(stage1)]
+    #[cfg(stage2)]
+    #[cfg(stage3)]
+    fn read_enum_variant<T>(&self, names: &[&str], f: &fn(uint) -> T) -> T {
+        debug!("read_enum_variant(names=%?)", names);
+        let name = match *self.peek() {
+            String(ref s) => s,
+            List([String(ref s), .. _]) => s,
+            ref json => fail!(fmt!("invalid variant: %?", *json)),
+        };
+        let idx = match vec::position(names, |n| str::eq_slice(*n, *name)) {
+            Some(idx) => idx,
+            None => fail!(fmt!("Unknown variant name: %?", name)),
+        };
+        f(idx)
+    }
+
     fn read_enum_variant_arg<T>(&self, idx: uint, f: &fn() -> T) -> T {
         debug!("read_enum_variant_arg(idx=%u)", idx);
-        if idx != 0 { fail!(~"unknown index") }
-        f()
+        match *self.peek() {
+            List(ref list) => {
+                self.stack.push(&list[idx + 1]);
+                f()
+            }
+            ref json => fail!(fmt!("not a list: %?", json)),
+        }
     }
 
     fn read_owned_vec<T>(&self, f: &fn(uint) -> T) -> T {
@@ -946,6 +979,13 @@ impl<'self> serialize::Decoder for Decoder<'self> {
             _ => fail!(~"not a list")
         }
     }
+
+    fn read_option<T>(&self, f: &fn() -> T) -> Option<T> {
+        match *self.peek() {
+            Null => { self.pop(); None }
+            _ => Some(f()),
+        }
+    }
 }
 
 impl Eq for Json {
@@ -1195,14 +1235,12 @@ impl to_str::ToStr for Error {
 
 #[cfg(test)]
 mod tests {
-    use core::prelude::*;
-
-    use json::*;
-    use serialize;
+    use super::*;
 
-    use core::result;
+    use core::prelude::*;
     use core::hashmap::linear::LinearMap;
 
+    use std::serialize::Decodable;
 
     fn mk_object(items: &[(~str, Json)]) -> Json {
         let mut d = ~LinearMap::new();
@@ -1218,45 +1256,89 @@ mod tests {
 
     #[test]
     fn test_write_null() {
-        fail_unless!(to_str(&Null) == ~"null");
+        assert_eq!(to_str(&Null), ~"null");
     }
 
     #[test]
     fn test_write_number() {
-        fail_unless!(to_str(&Number(3f)) == ~"3");
-        fail_unless!(to_str(&Number(3.1f)) == ~"3.1");
-        fail_unless!(to_str(&Number(-1.5f)) == ~"-1.5");
-        fail_unless!(to_str(&Number(0.5f)) == ~"0.5");
+        assert_eq!(to_str(&Number(3f)), ~"3");
+        assert_eq!(to_str(&Number(3.1f)), ~"3.1");
+        assert_eq!(to_str(&Number(-1.5f)), ~"-1.5");
+        assert_eq!(to_str(&Number(0.5f)), ~"0.5");
     }
 
     #[test]
     fn test_write_str() {
-        fail_unless!(to_str(&String(~"")) == ~"\"\"");
-        fail_unless!(to_str(&String(~"foo")) == ~"\"foo\"");
+        assert_eq!(to_str(&String(~"")), ~"\"\"");
+        assert_eq!(to_str(&String(~"foo")), ~"\"foo\"");
     }
 
     #[test]
     fn test_write_bool() {
-        fail_unless!(to_str(&Boolean(true)) == ~"true");
-        fail_unless!(to_str(&Boolean(false)) == ~"false");
+        assert_eq!(to_str(&Boolean(true)), ~"true");
+        assert_eq!(to_str(&Boolean(false)), ~"false");
     }
 
     #[test]
     fn test_write_list() {
-        fail_unless!(to_str(&List(~[])) == ~"[]");
-        fail_unless!(to_str(&List(~[Boolean(true)])) == ~"[true]");
-        fail_unless!(to_str(&List(~[
+        assert_eq!(to_str(&List(~[])), ~"[]");
+        assert_eq!(to_str(&List(~[Boolean(true)])), ~"[true]");
+        assert_eq!(to_str(&List(~[
             Boolean(false),
             Null,
             List(~[String(~"foo\nbar"), Number(3.5f)])
-        ])) == ~"[false,null,[\"foo\\nbar\",3.5]]");
+        ])), ~"[false,null,[\"foo\\nbar\",3.5]]");
+    }
+
+    #[test]
+    fn test_write_list_pretty() {
+        assert_eq!(to_pretty_str(&List(~[])), ~"[]");
+        assert_eq!(
+            to_pretty_str(&List(~[Boolean(true)])),
+            ~"\
+            [\n  \
+                true\n\
+            ]"
+        );
+        assert_eq!(
+            to_pretty_str(&List(~[
+                Boolean(false),
+                Null,
+                List(~[String(~"foo\nbar"), Number(3.5f)])
+            ])),
+            ~"\
+            [\n  \
+                false,\n  \
+                null,\n  \
+                [\n    \
+                    \"foo\\nbar\",\n    \
+                    3.5\n  \
+                ]\n\
+            ]"
+        );
     }
 
     #[test]
     fn test_write_object() {
-        fail_unless!(to_str(&mk_object(~[])) == ~"{}");
-        fail_unless!(to_str(&mk_object(~[(~"a", Boolean(true))]))
-            == ~"{\"a\":true}");
+        assert_eq!(to_str(&mk_object(~[])), ~"{}");
+        assert_eq!(
+            to_str(&mk_object(~[(~"a", Boolean(true))])),
+            ~"{\"a\":true}"
+        );
+        assert_eq!(
+            to_str(&mk_object(~[
+                (~"b", List(~[
+                    mk_object(~[(~"c", String(~"\x0c\r"))]),
+                    mk_object(~[(~"d", String(~""))])
+                ]))
+            ])),
+            ~"{\
+                \"b\":[\
+                    {\"c\":\"\\f\\r\"},\
+                    {\"d\":\"\"}\
+                ]\
+            }"
+        );
         let a = mk_object(~[
             (~"a", Boolean(true)),
             (~"b", List(~[
@@ -1266,248 +1348,343 @@ mod tests {
         ]);
         // We can't compare the strings directly because the object fields be
         // printed in a different order.
-        let b = result::unwrap(from_str(to_str(&a)));
-        fail_unless!(a == b);
+        let b = from_str(to_str(&a)).unwrap();
+        assert_eq!(a, b);
     }
 
     #[test]
-    fn test_write_enum () {
-        let bw = @io::BytesWriter();
-        let bww : @io::Writer = (bw as @io::Writer);
-        let encoder = (@Encoder(bww) as @serialize::Encoder);
-        do encoder.emit_enum(~"animal") {
-            do encoder.emit_enum_variant (~"frog",37,1242) {
-                // name of frog:
-                do encoder.emit_enum_variant_arg (0) {
-                    encoder.emit_owned_str(~"Henry")
-                }
-                // mass of frog in grams:
-                do encoder.emit_enum_variant_arg (1) {
-                    encoder.emit_int(349);
-                }
-            }
-        }
-        assert_eq!(str::from_bytes(bw.bytes), ~"[\"frog\",[\"Henry\",349]]");
+    fn test_write_object_pretty() {
+        assert_eq!(to_pretty_str(&mk_object(~[])), ~"{\n}");
+        assert_eq!(
+            to_pretty_str(&mk_object(~[(~"a", Boolean(true))])),
+            ~"\
+            {\n  \
+                \"a\": true\n\
+            }"
+        );
+        assert_eq!(
+            to_pretty_str(&mk_object(~[
+                (~"b", List(~[
+                    mk_object(~[(~"c", String(~"\x0c\r"))]),
+                    mk_object(~[(~"d", String(~""))])
+                ]))
+            ])),
+            ~"\
+            {\n  \
+                \"b\": [\n    \
+                    {\n      \
+                        \"c\": \"\\f\\r\"\n    \
+                    },\n    \
+                    {\n      \
+                        \"d\": \"\"\n    \
+                    }\n  \
+                ]\n\
+            }"
+        );
+        let a = mk_object(~[
+            (~"a", Boolean(true)),
+            (~"b", List(~[
+                mk_object(~[(~"c", String(~"\x0c\r"))]),
+                mk_object(~[(~"d", String(~""))])
+            ]))
+        ]);
+        // We can't compare the strings directly because the object fields be
+        // printed in a different order.
+        let b = from_str(to_str(&a)).unwrap();
+        assert_eq!(a, b);
+    }
+
+    #[auto_encode]
+    #[auto_decode]
+    #[deriving(Eq)]
+    enum Animal {
+        Dog,
+        Frog(~str, int)
     }
 
     #[test]
-    fn test_write_some () {
-        let bw = @io::BytesWriter();
-        let bww : @io::Writer = (bw as @io::Writer);
-        let encoder = (@Encoder(bww) as @serialize::Encoder);
-        do encoder.emit_enum(~"Option") {
-            do encoder.emit_enum_variant (~"Some",37,1242) {
-                do encoder.emit_enum_variant_arg (0) {
-                    encoder.emit_owned_str(~"jodhpurs")
-                }
-            }
-        }
-        assert_eq!(str::from_bytes(bw.bytes), ~"\"jodhpurs\"");
+    fn test_write_enum_no_args() {
+        let animal = Dog;
+
+        let s = do io::with_str_writer |wr| {
+            let encoder = Encoder(wr);
+            animal.encode(&encoder);
+        };
+        assert_eq!(s, ~"\"Dog\"");
     }
 
     #[test]
-    fn test_write_none () {
-        let bw = @io::BytesWriter();
-        let bww : @io::Writer = (bw as @io::Writer);
-        let encoder = (@Encoder(bww) as @serialize::Encoder);
-        do encoder.emit_enum(~"Option") {
-            do encoder.emit_enum_variant (~"None",37,1242) {
-            }
-        }
-        assert_eq!(str::from_bytes(bw.bytes), ~"null");
+    fn test_write_enum_no_args_pretty() {
+        let animal = Dog;
+
+        let s = do io::with_str_writer |wr| {
+            let encoder = PrettyEncoder(wr);
+            animal.encode(&encoder);
+        };
+        assert_eq!(s, ~"\"Dog\"");
+    }
+
+    #[test]
+    fn test_write_enum_multiple_args() {
+        let animal = Frog(~"Henry", 349);
+
+        let s = do io::with_str_writer |wr| {
+            let encoder = Encoder(wr);
+            animal.encode(&encoder);
+        };
+        assert_eq!(s, ~"[\"Frog\",\"Henry\",349]");
+    }
+
+    #[test]
+    fn test_write_enum_multiple_args_pretty() {
+        let animal = Frog(~"Henry", 349);
+
+        let s = do io::with_str_writer |wr| {
+            let encoder = PrettyEncoder(wr);
+            animal.encode(&encoder);
+        };
+        assert_eq!(
+            s,
+            ~"\
+            [\n  \
+                \"Frog\",\n  \
+                \"Henry\",\n  \
+                349\n\
+            ]"
+        );
+    }
+
+    #[test]
+    fn test_write_some() {
+        let value = Some(~"jodhpurs");
+        let s = do io::with_str_writer |wr| {
+            let encoder = Encoder(wr);
+            value.encode(&encoder);
+        };
+        assert_eq!(s, ~"\"jodhpurs\"");
+    }
+
+    #[test]
+    fn test_write_some_pretty() {
+        let value = Some(~"jodhpurs");
+        let s = do io::with_str_writer |wr| {
+            let encoder = PrettyEncoder(wr);
+            value.encode(&encoder);
+        };
+        assert_eq!(s, ~"\"jodhpurs\"");
+    }
+
+    #[test]
+    fn test_write_none() {
+        let value: Option<~str> = None;
+        let s = do io::with_str_writer |wr| {
+            let encoder = Encoder(wr);
+            value.encode(&encoder);
+        };
+        assert_eq!(s, ~"null");
+    }
+
+    #[test]
+    fn test_write_none_pretty() {
+        let value: Option<~str> = None;
+        let s = do io::with_str_writer |wr| {
+            let encoder = Encoder(wr);
+            value.encode(&encoder);
+        };
+        assert_eq!(s, ~"null");
     }
 
     #[test]
     fn test_trailing_characters() {
-        fail_unless!(from_str(~"nulla") ==
+        assert_eq!(from_str(~"nulla"),
             Err(Error {line: 1u, col: 5u, msg: @~"trailing characters"}));
-        fail_unless!(from_str(~"truea") ==
+        assert_eq!(from_str(~"truea"),
             Err(Error {line: 1u, col: 5u, msg: @~"trailing characters"}));
-        fail_unless!(from_str(~"falsea") ==
+        assert_eq!(from_str(~"falsea"),
             Err(Error {line: 1u, col: 6u, msg: @~"trailing characters"}));
-        fail_unless!(from_str(~"1a") ==
+        assert_eq!(from_str(~"1a"),
             Err(Error {line: 1u, col: 2u, msg: @~"trailing characters"}));
-        fail_unless!(from_str(~"[]a") ==
+        assert_eq!(from_str(~"[]a"),
             Err(Error {line: 1u, col: 3u, msg: @~"trailing characters"}));
-        fail_unless!(from_str(~"{}a") ==
+        assert_eq!(from_str(~"{}a"),
             Err(Error {line: 1u, col: 3u, msg: @~"trailing characters"}));
     }
 
     #[test]
     fn test_read_identifiers() {
-        fail_unless!(from_str(~"n") ==
+        assert_eq!(from_str(~"n"),
             Err(Error {line: 1u, col: 2u, msg: @~"invalid syntax"}));
-        fail_unless!(from_str(~"nul") ==
+        assert_eq!(from_str(~"nul"),
             Err(Error {line: 1u, col: 4u, msg: @~"invalid syntax"}));
 
-        fail_unless!(from_str(~"t") ==
+        assert_eq!(from_str(~"t"),
             Err(Error {line: 1u, col: 2u, msg: @~"invalid syntax"}));
-        fail_unless!(from_str(~"truz") ==
+        assert_eq!(from_str(~"truz"),
             Err(Error {line: 1u, col: 4u, msg: @~"invalid syntax"}));
 
-        fail_unless!(from_str(~"f") ==
+        assert_eq!(from_str(~"f"),
             Err(Error {line: 1u, col: 2u, msg: @~"invalid syntax"}));
-        fail_unless!(from_str(~"faz") ==
+        assert_eq!(from_str(~"faz"),
             Err(Error {line: 1u, col: 3u, msg: @~"invalid syntax"}));
 
-        fail_unless!(from_str(~"null") == Ok(Null));
-        fail_unless!(from_str(~"true") == Ok(Boolean(true)));
-        fail_unless!(from_str(~"false") == Ok(Boolean(false)));
-        fail_unless!(from_str(~" null ") == Ok(Null));
-        fail_unless!(from_str(~" true ") == Ok(Boolean(true)));
-        fail_unless!(from_str(~" false ") == Ok(Boolean(false)));
+        assert_eq!(from_str(~"null"), Ok(Null));
+        assert_eq!(from_str(~"true"), Ok(Boolean(true)));
+        assert_eq!(from_str(~"false"), Ok(Boolean(false)));
+        assert_eq!(from_str(~" null "), Ok(Null));
+        assert_eq!(from_str(~" true "), Ok(Boolean(true)));
+        assert_eq!(from_str(~" false "), Ok(Boolean(false)));
     }
 
     #[test]
     fn test_read_number() {
-        fail_unless!(from_str(~"+") ==
+        assert_eq!(from_str(~"+"),
             Err(Error {line: 1u, col: 1u, msg: @~"invalid syntax"}));
-        fail_unless!(from_str(~".") ==
+        assert_eq!(from_str(~"."),
             Err(Error {line: 1u, col: 1u, msg: @~"invalid syntax"}));
 
-        fail_unless!(from_str(~"-") ==
+        assert_eq!(from_str(~"-"),
             Err(Error {line: 1u, col: 2u, msg: @~"invalid number"}));
-        fail_unless!(from_str(~"00") ==
+        assert_eq!(from_str(~"00"),
             Err(Error {line: 1u, col: 2u, msg: @~"invalid number"}));
-        fail_unless!(from_str(~"1.") ==
+        assert_eq!(from_str(~"1."),
             Err(Error {line: 1u, col: 3u, msg: @~"invalid number"}));
-        fail_unless!(from_str(~"1e") ==
+        assert_eq!(from_str(~"1e"),
             Err(Error {line: 1u, col: 3u, msg: @~"invalid number"}));
-        fail_unless!(from_str(~"1e+") ==
+        assert_eq!(from_str(~"1e+"),
             Err(Error {line: 1u, col: 4u, msg: @~"invalid number"}));
 
-        fail_unless!(from_str(~"3") == Ok(Number(3f)));
-        fail_unless!(from_str(~"3.1") == Ok(Number(3.1f)));
-        fail_unless!(from_str(~"-1.2") == Ok(Number(-1.2f)));
-        fail_unless!(from_str(~"0.4") == Ok(Number(0.4f)));
-        fail_unless!(from_str(~"0.4e5") == Ok(Number(0.4e5f)));
-        fail_unless!(from_str(~"0.4e+15") == Ok(Number(0.4e15f)));
-        fail_unless!(from_str(~"0.4e-01") == Ok(Number(0.4e-01f)));
-        fail_unless!(from_str(~" 3 ") == Ok(Number(3f)));
+        assert_eq!(from_str(~"3"), Ok(Number(3f)));
+        assert_eq!(from_str(~"3.1"), Ok(Number(3.1f)));
+        assert_eq!(from_str(~"-1.2"), Ok(Number(-1.2f)));
+        assert_eq!(from_str(~"0.4"), Ok(Number(0.4f)));
+        assert_eq!(from_str(~"0.4e5"), Ok(Number(0.4e5f)));
+        assert_eq!(from_str(~"0.4e+15"), Ok(Number(0.4e15f)));
+        assert_eq!(from_str(~"0.4e-01"), Ok(Number(0.4e-01f)));
+        assert_eq!(from_str(~" 3 "), Ok(Number(3f)));
     }
 
     #[test]
     fn test_read_str() {
-        fail_unless!(from_str(~"\"") ==
+        assert_eq!(from_str(~"\""),
             Err(Error {line: 1u, col: 2u, msg: @~"EOF while parsing string"
         }));
-        fail_unless!(from_str(~"\"lol") ==
+        assert_eq!(from_str(~"\"lol"),
             Err(Error {line: 1u, col: 5u, msg: @~"EOF while parsing string"
         }));
 
-        fail_unless!(from_str(~"\"\"") == Ok(String(~"")));
-        fail_unless!(from_str(~"\"foo\"") == Ok(String(~"foo")));
-        fail_unless!(from_str(~"\"\\\"\"") == Ok(String(~"\"")));
-        fail_unless!(from_str(~"\"\\b\"") == Ok(String(~"\x08")));
-        fail_unless!(from_str(~"\"\\n\"") == Ok(String(~"\n")));
-        fail_unless!(from_str(~"\"\\r\"") == Ok(String(~"\r")));
-        fail_unless!(from_str(~"\"\\t\"") == Ok(String(~"\t")));
-        fail_unless!(from_str(~" \"foo\" ") == Ok(String(~"foo")));
+        assert_eq!(from_str(~"\"\""), Ok(String(~"")));
+        assert_eq!(from_str(~"\"foo\""), Ok(String(~"foo")));
+        assert_eq!(from_str(~"\"\\\"\""), Ok(String(~"\"")));
+        assert_eq!(from_str(~"\"\\b\""), Ok(String(~"\x08")));
+        assert_eq!(from_str(~"\"\\n\""), Ok(String(~"\n")));
+        assert_eq!(from_str(~"\"\\r\""), Ok(String(~"\r")));
+        assert_eq!(from_str(~"\"\\t\""), Ok(String(~"\t")));
+        assert_eq!(from_str(~" \"foo\" "), Ok(String(~"foo")));
     }
 
     #[test]
     fn test_unicode_hex_escapes_in_str() {
-        fail_unless!(from_str(~"\"\\u12ab\"") == Ok(String(~"\u12ab")));
-        fail_unless!(from_str(~"\"\\uAB12\"") == Ok(String(~"\uAB12")));
+        assert_eq!(from_str(~"\"\\u12ab\""), Ok(String(~"\u12ab")));
+        assert_eq!(from_str(~"\"\\uAB12\""), Ok(String(~"\uAB12")));
     }
 
     #[test]
     fn test_read_list() {
-        fail_unless!(from_str(~"[") ==
+        assert_eq!(from_str(~"["),
             Err(Error {line: 1u, col: 2u, msg: @~"EOF while parsing value"}));
-        fail_unless!(from_str(~"[1") ==
+        assert_eq!(from_str(~"[1"),
             Err(Error {line: 1u, col: 3u, msg: @~"EOF while parsing list"}));
-        fail_unless!(from_str(~"[1,") ==
+        assert_eq!(from_str(~"[1,"),
             Err(Error {line: 1u, col: 4u, msg: @~"EOF while parsing value"}));
-        fail_unless!(from_str(~"[1,]") ==
+        assert_eq!(from_str(~"[1,]"),
             Err(Error {line: 1u, col: 4u, msg: @~"invalid syntax"}));
-        fail_unless!(from_str(~"[6 7]") ==
+        assert_eq!(from_str(~"[6 7]"),
             Err(Error {line: 1u, col: 4u, msg: @~"expected `,` or `]`"}));
 
-        fail_unless!(from_str(~"[]") == Ok(List(~[])));
-        fail_unless!(from_str(~"[ ]") == Ok(List(~[])));
-        fail_unless!(from_str(~"[true]") == Ok(List(~[Boolean(true)])));
-        fail_unless!(from_str(~"[ false ]") == Ok(List(~[Boolean(false)])));
-        fail_unless!(from_str(~"[null]") == Ok(List(~[Null])));
-        fail_unless!(from_str(~"[3, 1]") ==
+        assert_eq!(from_str(~"[]"), Ok(List(~[])));
+        assert_eq!(from_str(~"[ ]"), Ok(List(~[])));
+        assert_eq!(from_str(~"[true]"), Ok(List(~[Boolean(true)])));
+        assert_eq!(from_str(~"[ false ]"), Ok(List(~[Boolean(false)])));
+        assert_eq!(from_str(~"[null]"), Ok(List(~[Null])));
+        assert_eq!(from_str(~"[3, 1]"),
                      Ok(List(~[Number(3f), Number(1f)])));
-        fail_unless!(from_str(~"\n[3, 2]\n") ==
+        assert_eq!(from_str(~"\n[3, 2]\n"),
                      Ok(List(~[Number(3f), Number(2f)])));
-        fail_unless!(from_str(~"[2, [4, 1]]") ==
+        assert_eq!(from_str(~"[2, [4, 1]]"),
                Ok(List(~[Number(2f), List(~[Number(4f), Number(1f)])])));
     }
 
     #[test]
     fn test_read_object() {
-        fail_unless!(from_str(~"{") ==
+        assert_eq!(from_str(~"{"),
             Err(Error {
                 line: 1u,
                 col: 2u,
                 msg: @~"EOF while parsing object"}));
-        fail_unless!(from_str(~"{ ") ==
+        assert_eq!(from_str(~"{ "),
             Err(Error {
                 line: 1u,
                 col: 3u,
                 msg: @~"EOF while parsing object"}));
-        fail_unless!(from_str(~"{1") ==
+        assert_eq!(from_str(~"{1"),
             Err(Error {
                 line: 1u,
                 col: 2u,
                 msg: @~"key must be a string"}));
-        fail_unless!(from_str(~"{ \"a\"") ==
+        assert_eq!(from_str(~"{ \"a\""),
             Err(Error {
                 line: 1u,
                 col: 6u,
                 msg: @~"EOF while parsing object"}));
-        fail_unless!(from_str(~"{\"a\"") ==
+        assert_eq!(from_str(~"{\"a\""),
             Err(Error {
                 line: 1u,
                 col: 5u,
                 msg: @~"EOF while parsing object"}));
-        fail_unless!(from_str(~"{\"a\" ") ==
+        assert_eq!(from_str(~"{\"a\" "),
             Err(Error {
                 line: 1u,
                 col: 6u,
                 msg: @~"EOF while parsing object"}));
 
-        fail_unless!(from_str(~"{\"a\" 1") ==
+        assert_eq!(from_str(~"{\"a\" 1"),
             Err(Error {line: 1u, col: 6u, msg: @~"expected `:`"}));
-        fail_unless!(from_str(~"{\"a\":") ==
+        assert_eq!(from_str(~"{\"a\":"),
             Err(Error {line: 1u, col: 6u, msg: @~"EOF while parsing value"}));
-        fail_unless!(from_str(~"{\"a\":1") ==
+        assert_eq!(from_str(~"{\"a\":1"),
             Err(Error {
                 line: 1u,
                 col: 7u,
                 msg: @~"EOF while parsing object"}));
-        fail_unless!(from_str(~"{\"a\":1 1") ==
+        assert_eq!(from_str(~"{\"a\":1 1"),
             Err(Error {line: 1u, col: 8u, msg: @~"expected `,` or `}`"}));
-        fail_unless!(from_str(~"{\"a\":1,") ==
+        assert_eq!(from_str(~"{\"a\":1,"),
             Err(Error {
                 line: 1u,
                 col: 8u,
                 msg: @~"EOF while parsing object"}));
 
-        fail_unless!(result::unwrap(from_str(~"{}")) == mk_object(~[]));
-        fail_unless!(result::unwrap(from_str(~"{\"a\": 3}")) ==
+        assert_eq!(result::unwrap(from_str(~"{}")), mk_object(~[]));
+        assert_eq!(result::unwrap(from_str(~"{\"a\": 3}")),
                   mk_object(~[(~"a", Number(3.0f))]));
 
-        fail_unless!(result::unwrap(from_str(
-                ~"{ \"a\": null, \"b\" : true }")) ==
+        assert_eq!(result::unwrap(from_str(
+                ~"{ \"a\": null, \"b\" : true }")),
                   mk_object(~[
                       (~"a", Null),
                       (~"b", Boolean(true))]));
-        fail_unless!(result::unwrap(
-                      from_str(~"\n{ \"a\": null, \"b\" : true }\n")) ==
+        assert_eq!(result::unwrap(
+                      from_str(~"\n{ \"a\": null, \"b\" : true }\n")),
                   mk_object(~[
                       (~"a", Null),
                       (~"b", Boolean(true))]));
-        fail_unless!(result::unwrap(from_str(
-                ~"{\"a\" : 1.0 ,\"b\": [ true ]}")) ==
+        assert_eq!(result::unwrap(from_str(
+                ~"{\"a\" : 1.0 ,\"b\": [ true ]}")),
                   mk_object(~[
                       (~"a", Number(1.0)),
                       (~"b", List(~[Boolean(true)]))
                   ]));
-        fail_unless!(result::unwrap(from_str(
+        assert_eq!(result::unwrap(from_str(
                       ~"{" +
                           ~"\"a\": 1.0, " +
                           ~"\"b\": [" +
@@ -1515,7 +1692,7 @@ mod tests {
                               ~"\"foo\\nbar\", " +
                               ~"{ \"c\": {\"d\": null} } " +
                           ~"]" +
-                      ~"}")) ==
+                      ~"}")),
                   mk_object(~[
                       (~"a", Number(1.0f)),
                       (~"b", List(~[
@@ -1529,8 +1706,36 @@ mod tests {
     }
 
     #[test]
+    fn test_read_none() {
+        let decoder = Decoder(from_str(~"null").unwrap());
+        let value: Option<~str> = Decodable::decode(&decoder);
+        assert_eq!(value, None);
+    }
+
+    #[test]
+    fn test_read_some() {
+        let decoder = Decoder(from_str(~"\"jodhpurs\"").unwrap());
+        let value: Option<~str> = Decodable::decode(&decoder);
+        assert_eq!(value, Some(~"jodhpurs"));
+    }
+
+    #[test]
+    fn test_read_enum_no_args() {
+        let decoder = Decoder(from_str(~"\"Dog\"").unwrap());
+        let value: Animal = Decodable::decode(&decoder);
+        assert_eq!(value, Dog);
+    }
+
+    #[test]
+    fn test_read_enum_multiple_args() {
+        let decoder = Decoder(from_str(~"[\"Frog\",\"Henry\",349]").unwrap());
+        let value: Animal = Decodable::decode(&decoder);
+        assert_eq!(value, Frog(~"Henry", 349));
+    }
+
+    #[test]
     fn test_multiline_errors() {
-        fail_unless!(from_str(~"{\n  \"foo\":\n \"bar\"") ==
+        assert_eq!(from_str(~"{\n  \"foo\":\n \"bar\""),
             Err(Error {
                 line: 3u,
                 col: 8u,
diff --git a/src/libstd/prettyprint.rs b/src/libstd/prettyprint.rs
index f823d73cf0b..ed4f3e957c0 100644
--- a/src/libstd/prettyprint.rs
+++ b/src/libstd/prettyprint.rs
@@ -182,4 +182,18 @@ impl serialize::Encoder for Serializer {
         if idx > 0u { self.wr.write_str(~", "); }
         f();
     }
+
+    fn emit_option(&self, f: &fn()) {
+        f();
+    }
+
+    fn emit_option_none(&self) {
+        self.wr.write_str("None");
+    }
+
+    fn emit_option_some(&self, f: &fn()) {
+        self.wr.write_str("Some(");
+        f();
+        self.wr.write_char(')');
+    }
 }
diff --git a/src/libstd/serialize.rs b/src/libstd/serialize.rs
index 326b9e4dc07..02f4a934874 100644
--- a/src/libstd/serialize.rs
+++ b/src/libstd/serialize.rs
@@ -62,6 +62,11 @@ pub trait Encoder {
 
     fn emit_tup(&self, len: uint, f: &fn());
     fn emit_tup_elt(&self, idx: uint, f: &fn());
+
+    // Specialized types:
+    fn emit_option(&self, f: &fn());
+    fn emit_option_none(&self);
+    fn emit_option_some(&self, f: &fn());
 }
 
 pub trait Decoder {
@@ -87,7 +92,15 @@ pub trait Decoder {
 
     // Compound types:
     fn read_enum<T>(&self, name: &str, f: &fn() -> T) -> T;
+
+    #[cfg(stage0)]
     fn read_enum_variant<T>(&self, f: &fn(uint) -> T) -> T;
+
+    #[cfg(stage1)]
+    #[cfg(stage2)]
+    #[cfg(stage3)]
+    fn read_enum_variant<T>(&self, names: &[&str], f: &fn(uint) -> T) -> T;
+
     fn read_enum_variant_arg<T>(&self, idx: uint, f: &fn() -> T) -> T;
 
     fn read_owned<T>(&self, f: &fn() -> T) -> T;
@@ -103,6 +116,9 @@ pub trait Decoder {
 
     fn read_tup<T>(&self, sz: uint, f: &fn() -> T) -> T;
     fn read_tup_elt<T>(&self, idx: uint, f: &fn() -> T) -> T;
+
+    // Specialized types:
+    fn read_option<T>(&self, f: &fn() -> T) -> Option<T>;
 }
 
 pub trait Encodable<S:Encoder> {
@@ -368,14 +384,10 @@ impl<D:Decoder,T:Decodable<D>> Decodable<D> for @[T] {
 
 impl<S:Encoder,T:Encodable<S>> Encodable<S> for Option<T> {
     fn encode(&self, s: &S) {
-        do s.emit_enum(~"option") {
+        do s.emit_option {
             match *self {
-              None => do s.emit_enum_variant(~"none", 0u, 0u) {
-              },
-
-              Some(ref v) => do s.emit_enum_variant(~"some", 1u, 1u) {
-                s.emit_enum_variant_arg(0u, || v.encode(s))
-              }
+                None => s.emit_option_none(),
+                Some(ref v) => s.emit_option_some(|| v.encode(s)),
             }
         }
     }
@@ -383,16 +395,7 @@ impl<S:Encoder,T:Encodable<S>> Encodable<S> for Option<T> {
 
 impl<D:Decoder,T:Decodable<D>> Decodable<D> for Option<T> {
     fn decode(d: &D) -> Option<T> {
-        do d.read_enum(~"option") {
-            do d.read_enum_variant |i| {
-                match i {
-                  0 => None,
-                  1 => Some(d.read_enum_variant_arg(
-                      0u, || Decodable::decode(d))),
-                  _ => fail!(fmt!("Bad variant for option: %u", i))
-                }
-            }
-        }
+        d.read_option(|| Decodable::decode(d))
     }
 }
 
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 12d4e9d5e24..6b788810a79 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -386,7 +386,6 @@ pub enum vstore {
 #[auto_decode]
 #[deriving(Eq)]
 pub enum expr_vstore {
-    expr_vstore_fixed(Option<uint>),   // [1,2,3,4]
     expr_vstore_uniq,                  // ~[1,2,3,4]
     expr_vstore_box,                   // @[1,2,3,4]
     expr_vstore_mut_box,               // @mut [1,2,3,4]
@@ -546,12 +545,6 @@ pub struct expr {
 #[auto_encode]
 #[auto_decode]
 #[deriving(Eq)]
-pub enum log_level { error, debug, log_other }
-// 0 = error, 1 = debug, 2 = log_other
-
-#[auto_encode]
-#[auto_decode]
-#[deriving(Eq)]
 pub enum CallSugar {
     NoSugar,
     DoSugar,
@@ -598,7 +591,7 @@ pub enum expr_ {
     expr_break(Option<ident>),
     expr_again(Option<ident>),
     expr_ret(Option<@expr>),
-    expr_log(log_level, @expr, @expr),
+    expr_log(@expr, @expr),
 
     expr_inline_asm(@~str,              // asm
                     ~[(@~str, @expr)],  // inputs
diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs
index e81e460e832..2a112f106a8 100644
--- a/src/libsyntax/ext/auto_encode.rs
+++ b/src/libsyntax/ext/auto_encode.rs
@@ -1059,6 +1059,18 @@ fn mk_enum_deser_body(
     name: ast::ident,
     variants: ~[ast::variant]
 ) -> @ast::expr {
+    let expr_arm_names = build::mk_base_vec_e(
+        ext_cx,
+        span,
+         do variants.map |variant| {
+            build::mk_base_str(
+                ext_cx,
+                span,
+                ext_cx.str_of(variant.node.name)
+            )
+        }
+    );
+
     let mut arms = do variants.mapi |v_idx, variant| {
         let body = match variant.node.kind {
             ast::tuple_variant_kind(ref args) => {
@@ -1152,13 +1164,13 @@ fn mk_enum_deser_body(
         )
     );
 
-    // ast for `__d.read_enum_variant($(expr_lambda))`
+    // ast for `__d.read_enum_variant($expr_arm_names, $(expr_lambda))`
     let expr_lambda = ext_cx.lambda_expr(
         ext_cx.expr_method_call(
             span,
             ext_cx.expr_var(span, ~"__d"),
             ext_cx.ident_of(~"read_enum_variant"),
-            ~[expr_lambda]
+            ~[expr_arm_names, expr_lambda]
         )
     );
 
@@ -1174,9 +1186,9 @@ fn mk_enum_deser_body(
     )
 }
 
-
 #[cfg(test)]
 mod test {
+    use core::option::{None, Some};
     use std::serialize::Encodable;
     use std::serialize::Encoder;
 
@@ -1190,6 +1202,9 @@ mod test {
         CallToEmitNil,
         CallToEmitStruct(~str,uint),
         CallToEmitField(~str,uint),
+        CallToEmitOption,
+        CallToEmitOptionNone,
+        CallToEmitOptionSome,
         // all of the ones I was too lazy to handle:
         CallToOther
     }
@@ -1281,6 +1296,18 @@ mod test {
         fn emit_tup_elt(&self, +_idx: uint, f: &fn()) {
             self.add_unknown_to_log(); f();
         }
+
+        fn emit_option(&self, f: &fn()) {
+            self.add_to_log(CallToEmitOption);
+            f();
+        }
+        fn emit_option_none(&self) {
+            self.add_to_log(CallToEmitOptionNone);
+        }
+        fn emit_option_some(&self, f: &fn()) {
+            self.add_to_log(CallToEmitOptionSome);
+            f();
+        }
     }
 
 
@@ -1296,13 +1323,58 @@ mod test {
         Magazine(~str)
     }
 
-    #[test] fn encode_enum_test () {
-        assert_eq!(to_call_log(Book(34,44)),
-                     ~[CallToEmitEnum (~"Written"),
-                       CallToEmitEnumVariant (~"Book",0,2),
-                       CallToEmitEnumVariantArg (0),
-                       CallToEmitUint (34),
-                       CallToEmitEnumVariantArg (1),
-                       CallToEmitUint (44)]);
-        }
+    #[test]
+    fn test_encode_enum() {
+        assert_eq!(
+            to_call_log(Book(34,44)),
+            ~[
+                CallToEmitEnum(~"Written"),
+                CallToEmitEnumVariant(~"Book",0,2),
+                CallToEmitEnumVariantArg(0),
+                CallToEmitUint(34),
+                CallToEmitEnumVariantArg(1),
+                CallToEmitUint(44),
+            ]
+        );
+    }
+
+    pub struct BPos(uint);
+
+    #[auto_encode]
+    pub struct HasPos { pos : BPos }
+
+    #[test]
+    fn test_encode_newtype() {
+        assert_eq!(
+            to_call_log(HasPos { pos:BPos(48) }),
+            ~[
+                CallToEmitStruct(~"HasPos",1),
+                CallToEmitField(~"pos",0),
+                CallToEmitUint(48),
+            ]
+        );
+    }
+
+    #[test]
+    fn test_encode_option() {
+        let mut v = None;
+
+        assert_eq!(
+            to_call_log(v),
+            ~[
+                CallToEmitOption,
+                CallToEmitOptionNone,
+            ]
+        );
+
+        v = Some(54u);
+        assert_eq!(
+            to_call_log(v),
+            ~[
+                CallToEmitOption,
+                CallToEmitOptionSome,
+                CallToEmitUint(54)
+            ]
+        );
+    }
 }
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index ad71441e046..9499f95f0e7 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -152,11 +152,6 @@ pub fn mk_slice_vec_e(cx: @ext_ctxt, sp: span, +exprs: ~[@ast::expr])
     mk_vstore_e(cx, sp, mk_base_vec_e(cx, sp, exprs),
                 ast::expr_vstore_slice)
 }
-pub fn mk_fixed_vec_e(cx: @ext_ctxt, sp: span, +exprs: ~[@ast::expr])
-                   -> @ast::expr {
-    mk_vstore_e(cx, sp, mk_base_vec_e(cx, sp, exprs),
-                ast::expr_vstore_fixed(None))
-}
 pub fn mk_base_str(cx: @ext_ctxt, sp: span, +s: ~str) -> @ast::expr {
     let lit = ast::lit_str(@s);
     return mk_lit(cx, sp, lit);
diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs
index 6044c3ad3d2..a6f078d07b4 100644
--- a/src/libsyntax/ext/quote.rs
+++ b/src/libsyntax/ext/quote.rs
@@ -42,8 +42,7 @@ pub mod rt {
     pub use ast::*;
     pub use parse::token::*;
     pub use parse::new_parser_from_tts;
-    pub use codemap::BytePos;
-    pub use codemap::span;
+    pub use codemap::{BytePos, span, dummy_spanned};
 
     use print::pprust;
     use print::pprust::{item_to_str, ty_to_str};
@@ -89,7 +88,7 @@ pub mod rt {
         }
     }
 
-    impl ToSource for ~[@ast::item] {
+    impl<'self> ToSource for &'self [@ast::item] {
         fn to_source(&self, cx: @ext_ctxt) -> ~str {
             str::connect(self.map(|i| i.to_source(cx)), ~"\n\n")
         }
@@ -101,7 +100,7 @@ pub mod rt {
         }
     }
 
-    impl ToSource for ~[@ast::Ty] {
+    impl<'self> ToSource for &'self [@ast::Ty] {
         fn to_source(&self, cx: @ext_ctxt) -> ~str {
             str::connect(self.map(|i| i.to_source(cx)), ~", ")
         }
@@ -119,6 +118,90 @@ pub mod rt {
         }
     }
 
+    impl ToSource for ast::blk {
+        fn to_source(&self, cx: @ext_ctxt) -> ~str {
+            pprust::block_to_str(self, cx.parse_sess().interner)
+        }
+    }
+
+    impl<'self> ToSource for &'self str {
+        fn to_source(&self, _cx: @ext_ctxt) -> ~str {
+            let lit = dummy_spanned(ast::lit_str(@str::from_slice(*self)));
+            pprust::lit_to_str(@lit)
+        }
+    }
+
+    impl ToSource for int {
+        fn to_source(&self, _cx: @ext_ctxt) -> ~str {
+            let lit = dummy_spanned(ast::lit_int(*self as i64, ast::ty_i));
+            pprust::lit_to_str(@lit)
+        }
+    }
+
+    impl ToSource for i8 {
+        fn to_source(&self, _cx: @ext_ctxt) -> ~str {
+            let lit = dummy_spanned(ast::lit_int(*self as i64, ast::ty_i8));
+            pprust::lit_to_str(@lit)
+        }
+    }
+
+    impl ToSource for i16 {
+        fn to_source(&self, _cx: @ext_ctxt) -> ~str {
+            let lit = dummy_spanned(ast::lit_int(*self as i64, ast::ty_i16));
+            pprust::lit_to_str(@lit)
+        }
+    }
+
+
+    impl ToSource for i32 {
+        fn to_source(&self, _cx: @ext_ctxt) -> ~str {
+            let lit = dummy_spanned(ast::lit_int(*self as i64, ast::ty_i32));
+            pprust::lit_to_str(@lit)
+        }
+    }
+
+    impl ToSource for i64 {
+        fn to_source(&self, _cx: @ext_ctxt) -> ~str {
+            let lit = dummy_spanned(ast::lit_int(*self as i64, ast::ty_i64));
+            pprust::lit_to_str(@lit)
+        }
+    }
+
+    impl ToSource for uint {
+        fn to_source(&self, _cx: @ext_ctxt) -> ~str {
+            let lit = dummy_spanned(ast::lit_uint(*self as u64, ast::ty_u));
+            pprust::lit_to_str(@lit)
+        }
+    }
+
+    impl ToSource for u8 {
+        fn to_source(&self, _cx: @ext_ctxt) -> ~str {
+            let lit = dummy_spanned(ast::lit_uint(*self as u64, ast::ty_u8));
+            pprust::lit_to_str(@lit)
+        }
+    }
+
+    impl ToSource for u16 {
+        fn to_source(&self, _cx: @ext_ctxt) -> ~str {
+            let lit = dummy_spanned(ast::lit_uint(*self as u64, ast::ty_u16));
+            pprust::lit_to_str(@lit)
+        }
+    }
+
+    impl ToSource for u32 {
+        fn to_source(&self, _cx: @ext_ctxt) -> ~str {
+            let lit = dummy_spanned(ast::lit_uint(*self as u64, ast::ty_u32));
+            pprust::lit_to_str(@lit)
+        }
+    }
+
+    impl ToSource for u64 {
+        fn to_source(&self, _cx: @ext_ctxt) -> ~str {
+            let lit = dummy_spanned(ast::lit_uint(*self as u64, ast::ty_u64));
+            pprust::lit_to_str(@lit)
+        }
+    }
+
     // Alas ... we write these out instead. All redundant.
 
     impl ToTokens for ast::ident {
@@ -133,7 +216,7 @@ pub mod rt {
         }
     }
 
-    impl ToTokens for ~[@ast::item] {
+    impl<'self> ToTokens for &'self [@ast::item] {
         fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
             cx.parse_tts(self.to_source(cx))
         }
@@ -145,7 +228,7 @@ pub mod rt {
         }
     }
 
-    impl ToTokens for ~[@ast::Ty] {
+    impl<'self> ToTokens for &'self [@ast::Ty] {
         fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
             cx.parse_tts(self.to_source(cx))
         }
@@ -163,6 +246,78 @@ pub mod rt {
         }
     }
 
+    impl ToTokens for ast::blk {
+        fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
+            cx.parse_tts(self.to_source(cx))
+        }
+    }
+
+    impl<'self> ToTokens for &'self str {
+        fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
+            cx.parse_tts(self.to_source(cx))
+        }
+    }
+
+    impl ToTokens for int {
+        fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
+            cx.parse_tts(self.to_source(cx))
+        }
+    }
+
+    impl ToTokens for i8 {
+        fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
+            cx.parse_tts(self.to_source(cx))
+        }
+    }
+
+    impl ToTokens for i16 {
+        fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
+            cx.parse_tts(self.to_source(cx))
+        }
+    }
+
+    impl ToTokens for i32 {
+        fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
+            cx.parse_tts(self.to_source(cx))
+        }
+    }
+
+    impl ToTokens for i64 {
+        fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
+            cx.parse_tts(self.to_source(cx))
+        }
+    }
+
+    impl ToTokens for uint {
+        fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
+            cx.parse_tts(self.to_source(cx))
+        }
+    }
+
+    impl ToTokens for u8 {
+        fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
+            cx.parse_tts(self.to_source(cx))
+        }
+    }
+
+    impl ToTokens for u16 {
+        fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
+            cx.parse_tts(self.to_source(cx))
+        }
+    }
+
+    impl ToTokens for u32 {
+        fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
+            cx.parse_tts(self.to_source(cx))
+        }
+    }
+
+    impl ToTokens for u64 {
+        fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
+            cx.parse_tts(self.to_source(cx))
+        }
+    }
+
     pub trait ExtParseUtils {
         fn parse_item(&self, s: ~str) -> @ast::item;
         fn parse_expr(&self, s: ~str) -> @ast::expr;
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 9d4cf4e8939..279d57a291e 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -552,9 +552,8 @@ pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ {
         expr_ret(ref e) => {
             expr_ret(e.map(|x| fld.fold_expr(*x)))
         }
-        expr_log(i, lv, e) => {
+        expr_log(lv, e) => {
             expr_log(
-                i,
                 fld.fold_expr(lv),
                 fld.fold_expr(e)
             )
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index a0c73668a05..0ddf9111e02 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -326,19 +326,32 @@ mod test {
             @~"fn foo (x : int) { x; }",
             ~[],
             new_parse_sess(None));
-        assert_eq!(to_json_str(@tts),
-                    ~"[[\"tt_tok\",[null,[\"IDENT\",[\"fn\",false]]]],\
-                      [\"tt_tok\",[null,[\"IDENT\",[\"foo\",false]]]],\
-                      [\"tt_delim\",[[[\"tt_tok\",[null,[\"LPAREN\",[]]]],\
-                      [\"tt_tok\",[null,[\"IDENT\",[\"x\",false]]]],\
-                      [\"tt_tok\",[null,[\"COLON\",[]]]],\
-                      [\"tt_tok\",[null,[\"IDENT\",[\"int\",false]]]],\
-                      [\"tt_tok\",[null,[\"RPAREN\",[]]]]]]],\
-                      [\"tt_delim\",[[[\"tt_tok\",[null,[\"LBRACE\",[]]]],\
-                      [\"tt_tok\",[null,[\"IDENT\",[\"x\",false]]]],\
-                      [\"tt_tok\",[null,[\"SEMI\",[]]]],\
-                      [\"tt_tok\",[null,[\"RBRACE\",[]]]]]]]]"
-                   );
+        assert_eq!(
+            to_json_str(@tts),
+            ~"[\
+                [\"tt_tok\",null,[\"IDENT\",\"fn\",false]],\
+                [\"tt_tok\",null,[\"IDENT\",\"foo\",false]],\
+                [\
+                    \"tt_delim\",\
+                    [\
+                        [\"tt_tok\",null,\"LPAREN\"],\
+                        [\"tt_tok\",null,[\"IDENT\",\"x\",false]],\
+                        [\"tt_tok\",null,\"COLON\"],\
+                        [\"tt_tok\",null,[\"IDENT\",\"int\",false]],\
+                        [\"tt_tok\",null,\"RPAREN\"]\
+                    ]\
+                ],\
+                [\
+                    \"tt_delim\",\
+                    [\
+                        [\"tt_tok\",null,\"LBRACE\"],\
+                        [\"tt_tok\",null,[\"IDENT\",\"x\",false]],\
+                        [\"tt_tok\",null,\"SEMI\"],\
+                        [\"tt_tok\",null,\"RBRACE\"]\
+                    ]\
+                ]\
+            ]"
+        );
         let ast1 = new_parser_from_tts(new_parse_sess(None),~[],tts)
             .parse_item(~[]);
         let ast2 = parse_item_from_source_str(
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index c2e7ecacd20..6ca91791ffd 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -28,7 +28,7 @@ use ast::{expr_lit, expr_log, expr_loop, expr_loop_body, expr_mac};
 use ast::{expr_method_call, expr_paren, expr_path, expr_repeat};
 use ast::{expr_ret, expr_swap, expr_struct, expr_tup, expr_unary};
 use ast::{expr_vec, expr_vstore, expr_vstore_mut_box, expr_inline_asm};
-use ast::{expr_vstore_fixed, expr_vstore_slice, expr_vstore_box};
+use ast::{expr_vstore_slice, expr_vstore_box};
 use ast::{expr_vstore_mut_slice, expr_while, extern_fn, field, fn_decl};
 use ast::{expr_vstore_uniq, TyClosure, TyBareFn, Onceness, Once, Many};
 use ast::{foreign_item, foreign_item_const, foreign_item_fn, foreign_mod};
@@ -1223,7 +1223,7 @@ pub impl Parser {
             let lvl = self.parse_expr();
             self.expect(&token::COMMA);
             let e = self.parse_expr();
-            ex = expr_log(ast::log_other, lvl, e);
+            ex = expr_log(lvl, e);
             hi = self.span.hi;
             self.expect(&token::RPAREN);
         } else if self.eat_keyword(&~"return") {
@@ -2721,8 +2721,9 @@ pub impl Parser {
                     }
                     self.bump();
                 }
-                token::IDENT(*) => {
+                token::MOD_SEP | token::IDENT(*) => {
                     let maybe_bound = match *self.token {
+                        token::MOD_SEP => None,
                         token::IDENT(copy sid, _) => {
                             match *self.id_to_str(sid) {
                                 ~"send" |
@@ -2750,7 +2751,7 @@ pub impl Parser {
                             result.push(bound);
                         }
                         None => {
-                            let ty = self.parse_ty(false);
+                            let ty = self.parse_ty(true);
                             result.push(TraitTyParamBound(ty));
                         }
                     }
@@ -3099,14 +3100,6 @@ pub impl Parser {
     //    impl<T> Foo { ... }
     //    impl<T> ToStr for ~[T] { ... }
     fn parse_item_impl(&self, visibility: ast::visibility) -> item_info {
-        fn wrap_path(p: &Parser, pt: @path) -> @Ty {
-            @Ty {
-                id: p.get_id(),
-                node: ty_path(pt, p.get_id()),
-                span: pt.span,
-            }
-        }
-
         // First, parse type parameters if necessary.
         let generics = self.parse_generics();
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 9fffed7074b..cb142ef3f54 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -325,7 +325,7 @@ pub fn commasep<IN>(s: @ps, b: breaks, elts: &[IN], op: &fn(@ps, IN)) {
 pub fn commasep_cmnt<IN>(s: @ps, b: breaks, elts: &[IN], op: &fn(@ps, IN),
                          get_span: &fn(IN) -> codemap::span) {
     box(s, 0u, b);
-    let len = vec::len::<IN>(elts);
+    let len = elts.len();
     let mut i = 0u;
     for elts.each |elt| {
         maybe_print_comment(s, get_span(*elt).hi);
@@ -1029,8 +1029,6 @@ pub fn print_vstore(s: @ps, t: ast::vstore) {
 
 pub fn print_expr_vstore(s: @ps, t: ast::expr_vstore) {
     match t {
-      ast::expr_vstore_fixed(Some(i)) => word(s.s, fmt!("%u", i)),
-      ast::expr_vstore_fixed(None) => word(s.s, ~"_"),
       ast::expr_vstore_uniq => word(s.s, ~"~"),
       ast::expr_vstore_box => word(s.s, ~"@"),
       ast::expr_vstore_mut_box => {
@@ -1105,16 +1103,9 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) {
     let ann_node = node_expr(s, expr);
     (s.ann.pre)(ann_node);
     match expr.node {
-        ast::expr_vstore(e, v) => match v {
-            ast::expr_vstore_fixed(_) => {
-                print_expr(s, e);
-                word(s.s, ~"/");
-                print_expr_vstore(s, v);
-            }
-            _ => {
-                print_expr_vstore(s, v);
-                print_expr(s, e);
-            }
+        ast::expr_vstore(e, v) => {
+            print_expr_vstore(s, v);
+            print_expr(s, e);
         },
       ast::expr_vec(ref exprs, mutbl) => {
         ibox(s, indent_unit);
@@ -1391,20 +1382,14 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) {
           _ => ()
         }
       }
-      ast::expr_log(lvl, lexp, expr) => {
-        match lvl {
-          ast::debug => { word_nbsp(s, ~"log"); print_expr(s, expr); }
-          ast::error => { word_nbsp(s, ~"log_err"); print_expr(s, expr); }
-          ast::log_other => {
-            word_nbsp(s, ~"log");
-            popen(s);
-            print_expr(s, lexp);
-            word(s.s, ~",");
-            space_if_not_bol(s);
-            print_expr(s, expr);
-            pclose(s);
-          }
-        }
+      ast::expr_log(lexp, expr) => {
+        word(s.s, ~"__log");
+        popen(s);
+        print_expr(s, lexp);
+        word(s.s, ~",");
+        space_if_not_bol(s);
+        print_expr(s, expr);
+        pclose(s);
       }
       ast::expr_inline_asm(a, in, out, c, v, _) => {
         if v {
@@ -2139,7 +2124,7 @@ pub fn print_comment(s: @ps, cmnt: comments::cmnt) {
     }
 }
 
-pub fn print_string(s: @ps, st: ~str) {
+pub fn print_string(s: @ps, st: &str) {
     word(s.s, ~"\"");
     word(s.s, str::escape_default(st));
     word(s.s, ~"\"");
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index a159c98d21b..2bdf26fba58 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -559,7 +559,7 @@ pub fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
         expr_break(_) => (),
         expr_again(_) => (),
         expr_ret(eo) => visit_expr_opt(eo, e, v),
-        expr_log(_, lv, x) => {
+        expr_log(lv, x) => {
             (v.visit_expr)(lv, e, v);
             (v.visit_expr)(x, e, v);
         }
diff --git a/src/test/run-pass/issue-5572.rs b/src/test/run-pass/issue-5572.rs
new file mode 100644
index 00000000000..d0db5e5cb3c
--- /dev/null
+++ b/src/test/run-pass/issue-5572.rs
@@ -0,0 +1,3 @@
+fn foo<T: ::cmp::Eq>(t: T) { }
+
+fn main() { }