about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-01-03 22:36:53 -0800
committerbors <bors@rust-lang.org>2014-01-03 22:36:53 -0800
commit3dd7c49faf5ae3a9158ab242a264c0f0eb99f657 (patch)
tree0393c0b2e10c7579d86c222071bb9c64b0451b60 /src/libsyntax
parent0ff6c12ce94993dae702d597a213eee6b969231a (diff)
parent80921536343e87d2f7d7f19ad90d63f50b557e06 (diff)
downloadrust-3dd7c49faf5ae3a9158ab242a264c0f0eb99f657.tar.gz
rust-3dd7c49faf5ae3a9158ab242a264c0f0eb99f657.zip
auto merge of #11251 : pcwalton/rust/remove-at-mut, r=pcwalton
r? @nikomatsakis 

for the borrow checker changes. Write guards are now eliminated.
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs12
-rw-r--r--src/libsyntax/ast_map.rs147
-rw-r--r--src/libsyntax/ast_util.rs132
-rw-r--r--src/libsyntax/attr.rs5
-rw-r--r--src/libsyntax/codemap.rs78
-rw-r--r--src/libsyntax/diagnostic.rs68
-rw-r--r--src/libsyntax/ext/base.rs6
-rw-r--r--src/libsyntax/ext/build.rs11
-rw-r--r--src/libsyntax/ext/deriving/ty.rs8
-rw-r--r--src/libsyntax/ext/expand.rs50
-rw-r--r--src/libsyntax/ext/source_util.rs8
-rw-r--r--src/libsyntax/ext/trace_macros.rs2
-rw-r--r--src/libsyntax/ext/tt/macro_parser.rs26
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs13
-rw-r--r--src/libsyntax/ext/tt/transcribe.rs179
-rw-r--r--src/libsyntax/fold.rs4
-rw-r--r--src/libsyntax/parse/comments.rs85
-rw-r--r--src/libsyntax/parse/lexer.rs373
-rw-r--r--src/libsyntax/parse/mod.rs65
-rw-r--r--src/libsyntax/parse/parser.rs73
-rw-r--r--src/libsyntax/print/pp.rs40
-rw-r--r--src/libsyntax/print/pprust.rs864
-rw-r--r--src/libsyntax/util/interner.rs75
-rw-r--r--src/libsyntax/util/parser_testing.rs6
-rw-r--r--src/libsyntax/visit.rs4
25 files changed, 1261 insertions, 1073 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 51aa7cd4377..3523d63ef60 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -15,6 +15,7 @@ use abi::AbiSet;
 use opt_vec::OptVec;
 use parse::token::{interner_get, str_to_ident};
 
+use std::cell::RefCell;
 use std::hashmap::HashMap;
 use std::option::Option;
 use std::to_str::ToStr;
@@ -88,9 +89,9 @@ pub type SyntaxContext = u32;
 // it should cut down on memory use *a lot*; applying a mark
 // to a tree containing 50 identifiers would otherwise generate
 pub struct SCTable {
-    table : ~[SyntaxContext_],
-    mark_memo : HashMap<(SyntaxContext,Mrk),SyntaxContext>,
-    rename_memo : HashMap<(SyntaxContext,Ident,Name),SyntaxContext>
+    table: RefCell<~[SyntaxContext_]>,
+    mark_memo: RefCell<HashMap<(SyntaxContext,Mrk),SyntaxContext>>,
+    rename_memo: RefCell<HashMap<(SyntaxContext,Ident,Name),SyntaxContext>>,
 }
 
 // NB: these must be placed in any SCTable...
@@ -414,7 +415,6 @@ pub enum Vstore {
 pub enum ExprVstore {
     ExprVstoreUniq,                 // ~[1,2,3,4]
     ExprVstoreBox,                  // @[1,2,3,4]
-    ExprVstoreMutBox,               // @mut [1,2,3,4]
     ExprVstoreSlice,                // &[1,2,3,4]
     ExprVstoreMutSlice,             // &mut [1,2,3,4]
 }
@@ -443,7 +443,7 @@ pub enum BinOp {
 
 #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
 pub enum UnOp {
-    UnBox(Mutability),
+    UnBox,
     UnUniq,
     UnDeref,
     UnNot,
@@ -874,7 +874,7 @@ pub struct TyBareFn {
 pub enum ty_ {
     ty_nil,
     ty_bot, /* bottom type */
-    ty_box(mt),
+    ty_box(P<Ty>),
     ty_uniq(P<Ty>),
     ty_vec(P<Ty>),
     ty_fixed_length_vec(P<Ty>, @Expr),
diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs
index 504a51f80a8..8a5a1d2426c 100644
--- a/src/libsyntax/ast_map.rs
+++ b/src/libsyntax/ast_map.rs
@@ -23,6 +23,7 @@ use print::pprust;
 use visit::{Visitor, fn_kind};
 use visit;
 
+use std::cell::RefCell;
 use std::hashmap::HashMap;
 use std::vec;
 
@@ -94,7 +95,7 @@ pub fn path_elt_to_str(pe: path_elt, itr: @ident_interner) -> ~str {
 fn pretty_ty(ty: &Ty, itr: @ident_interner, out: &mut ~str) {
     let (prefix, subty) = match ty.node {
         ty_uniq(ty) => ("$UP$", &*ty),
-        ty_box(mt { ty, .. }) => ("$SP$", &*ty),
+        ty_box(ty) => ("$SP$", &*ty),
         ty_ptr(mt { ty, mutbl }) => (if mutbl == MutMutable {"$RPmut$"} else {"$RP$"},
                                      &*ty),
         ty_rptr(_, mt { ty, mutbl }) => (if mutbl == MutMutable {"$BPmut$"} else {"$BP$"},
@@ -192,17 +193,17 @@ impl ast_node {
     }
 }
 
-pub type map = @mut HashMap<NodeId, ast_node>;
+pub type map = @RefCell<HashMap<NodeId, ast_node>>;
 
 pub struct Ctx {
     map: map,
-    path: path,
-    diag: @mut SpanHandler,
+    path: RefCell<path>,
+    diag: @SpanHandler,
 }
 
 impl Ctx {
     fn extend(&self, elt: path_elt) -> @path {
-        @vec::append(self.path.clone(), [elt])
+        @vec::append(self.path.get(), [elt])
     }
 
     fn map_method(&mut self,
@@ -215,8 +216,10 @@ impl Ctx {
         } else {
             node_method(m, impl_did, impl_path)
         };
-        self.map.insert(m.id, entry);
-        self.map.insert(m.self_id, node_local(special_idents::self_));
+
+        let mut map = self.map.borrow_mut();
+        map.get().insert(m.id, entry);
+        map.get().insert(m.self_id, node_local(special_idents::self_));
     }
 
     fn map_struct_def(&mut self,
@@ -231,10 +234,11 @@ impl Ctx {
             Some(ctor_id) => {
                 match parent_node {
                     node_item(item, _) => {
-                        self.map.insert(ctor_id,
-                                        node_struct_ctor(struct_def,
-                                                         item,
-                                                         p));
+                        let mut map = self.map.borrow_mut();
+                        map.get().insert(ctor_id,
+                                         node_struct_ctor(struct_def,
+                                                          item,
+                                                          p));
                     }
                     _ => fail!("struct def parent wasn't an item")
                 }
@@ -243,13 +247,17 @@ impl Ctx {
     }
 
     fn map_expr(&mut self, ex: @Expr) {
-        self.map.insert(ex.id, node_expr(ex));
+        {
+            let mut map = self.map.borrow_mut();
+            map.get().insert(ex.id, node_expr(ex));
+        }
 
         // Expressions which are or might be calls:
         {
             let r = ex.get_callee_id();
             for callee_id in r.iter() {
-                self.map.insert(*callee_id, node_callee_scope(ex));
+                let mut map = self.map.borrow_mut();
+                map.get().insert(*callee_id, node_callee_scope(ex));
             }
         }
 
@@ -263,26 +271,40 @@ impl Ctx {
               sp: codemap::Span,
               id: NodeId) {
         for a in decl.inputs.iter() {
-            self.map.insert(a.id, node_arg(a.pat));
+            let mut map = self.map.borrow_mut();
+            map.get().insert(a.id, node_arg(a.pat));
         }
         match *fk {
-            visit::fk_method(name, _, _) => { self.path.push(path_name(name)) }
+            visit::fk_method(name, _, _) => {
+                let mut path = self.path.borrow_mut();
+                path.get().push(path_name(name))
+            }
             _ => {}
         }
         visit::walk_fn(self, fk, decl, body, sp, id, ());
         match *fk {
-            visit::fk_method(..) => { self.path.pop(); }
+            visit::fk_method(..) => {
+                let mut path = self.path.borrow_mut();
+                path.get().pop();
+            }
             _ => {}
         }
     }
 
     fn map_stmt(&mut self, stmt: @Stmt) {
-        self.map.insert(stmt_id(stmt), node_stmt(stmt));
+        {
+            let mut map = self.map.borrow_mut();
+            map.get().insert(stmt_id(stmt), node_stmt(stmt));
+        }
         visit::walk_stmt(self, stmt, ());
     }
 
     fn map_block(&mut self, b: P<Block>) {
-        self.map.insert(b.id, node_block(b));
+        {
+            let mut map = self.map.borrow_mut();
+            map.get().insert(b.id, node_block(b));
+        }
+
         visit::walk_block(self, b, ());
     }
 
@@ -290,8 +312,9 @@ impl Ctx {
         match pat.node {
             PatIdent(_, ref path, _) => {
                 // Note: this is at least *potentially* a pattern...
-                self.map.insert(pat.id,
-                                node_local(ast_util::path_to_ident(path)));
+                let mut map = self.map.borrow_mut();
+                map.get().insert(pat.id,
+                                 node_local(ast_util::path_to_ident(path)));
             }
             _ => ()
         }
@@ -303,8 +326,11 @@ impl Ctx {
 impl Visitor<()> for Ctx {
     fn visit_item(&mut self, i: @item, _: ()) {
         // clone is FIXME #2543
-        let item_path = @self.path.clone();
-        self.map.insert(i.id, node_item(i, item_path));
+        let item_path = @self.path.get();
+        {
+            let mut map = self.map.borrow_mut();
+            map.get().insert(i.id, node_item(i, item_path));
+        }
         match i.node {
             item_impl(_, ref maybe_trait, ty, ref ms) => {
                 // Right now the ident on impls is __extensions__ which isn't
@@ -318,13 +344,15 @@ impl Visitor<()> for Ctx {
                     self.map_method(impl_did, extended, *m, false)
                 }
 
-                self.path.push(elt);
+                let mut path = self.path.borrow_mut();
+                path.get().push(elt);
             }
             item_enum(ref enum_definition, _) => {
                 for &v in enum_definition.variants.iter() {
                     let elt = path_name(i.ident);
-                    self.map.insert(v.node.id,
-                                    node_variant(v, i, self.extend(elt)));
+                    let mut map = self.map.borrow_mut();
+                    map.get().insert(v.node.id,
+                                     node_variant(v, i, self.extend(elt)));
                 }
             }
             item_foreign_mod(ref nm) => {
@@ -336,16 +364,17 @@ impl Visitor<()> for Ctx {
                         inherited => i.vis
                     };
 
-                    self.map.insert(nitem.id,
-                                    node_foreign_item(*nitem,
-                                                      nm.abis,
-                                                      visibility,
-                                                      // FIXME (#2543)
+                    let mut map = self.map.borrow_mut();
+                    map.get().insert(nitem.id,
+                                     node_foreign_item(*nitem,
+                                                       nm.abis,
+                                                       visibility,
+                                                       // FIXME (#2543)
                                                         // Anonymous extern
                                                         // mods go in the
                                                         // parent scope.
-                                                        @self.path.clone()
-                                                      ));
+                                                        @self.path.get()
+                                                       ));
                 }
             }
             item_struct(struct_def, _) => {
@@ -355,7 +384,8 @@ impl Visitor<()> for Ctx {
             }
             item_trait(_, ref traits, ref methods) => {
                 for p in traits.iter() {
-                    self.map.insert(p.ref_id, node_item(i, item_path));
+                    let mut map = self.map.borrow_mut();
+                    map.get().insert(p.ref_id, node_item(i, item_path));
                 }
                 for tm in methods.iter() {
                     let ext = { self.extend(path_name(i.ident)) };
@@ -364,7 +394,8 @@ impl Visitor<()> for Ctx {
                         required(ref m) => {
                             let entry =
                                 node_trait_method(@(*tm).clone(), d_id, ext);
-                            self.map.insert(m.id, entry);
+                            let mut map = self.map.borrow_mut();
+                            map.get().insert(m.id, entry);
                         }
                         provided(m) => {
                             self.map_method(d_id, ext, m, true);
@@ -377,13 +408,19 @@ impl Visitor<()> for Ctx {
 
         match i.node {
             item_mod(_) | item_foreign_mod(_) => {
-                self.path.push(path_mod(i.ident));
+                let mut path = self.path.borrow_mut();
+                path.get().push(path_mod(i.ident));
             }
             item_impl(..) => {} // this was guessed above.
-            _ => self.path.push(path_name(i.ident))
+            _ => {
+                let mut path = self.path.borrow_mut();
+                path.get().push(path_name(i.ident))
+            }
         }
         visit::walk_item(self, i, ());
-        self.path.pop();
+
+        let mut path = self.path.borrow_mut();
+        path.get().pop();
     }
 
     fn visit_pat(&mut self, pat: &Pat, _: ()) {
@@ -418,29 +455,29 @@ impl Visitor<()> for Ctx {
     }
 }
 
-pub fn map_crate(diag: @mut SpanHandler, c: &Crate) -> map {
-    let cx = @mut Ctx {
-        map: @mut HashMap::new(),
-        path: ~[],
+pub fn map_crate(diag: @SpanHandler, c: &Crate) -> map {
+    let mut cx = Ctx {
+        map: @RefCell::new(HashMap::new()),
+        path: RefCell::new(~[]),
         diag: diag,
     };
-    visit::walk_crate(cx, c, ());
+    visit::walk_crate(&mut cx, c, ());
     cx.map
 }
 
 // Used for items loaded from external crate that are being inlined into this
 // crate.  The `path` should be the path to the item but should not include
 // the item itself.
-pub fn map_decoded_item(diag: @mut SpanHandler,
+pub fn map_decoded_item(diag: @SpanHandler,
                         map: map,
                         path: path,
                         ii: &inlined_item) {
     // I believe it is ok for the local IDs of inlined items from other crates
     // to overlap with the local ids from this crate, so just generate the ids
     // starting from 0.
-    let cx = @mut Ctx {
+    let mut cx = Ctx {
         map: map,
-        path: path.clone(),
+        path: RefCell::new(path.clone()),
         diag: diag,
     };
 
@@ -450,10 +487,11 @@ pub fn map_decoded_item(diag: @mut SpanHandler,
     match *ii {
         ii_item(..) => {} // fallthrough
         ii_foreign(i) => {
-            cx.map.insert(i.id, node_foreign_item(i,
-                                                  AbiSet::Intrinsic(),
-                                                  i.vis,    // Wrong but OK
-                                                  @path));
+            let mut map = cx.map.borrow_mut();
+            map.get().insert(i.id, node_foreign_item(i,
+                                                     AbiSet::Intrinsic(),
+                                                     i.vis,    // Wrong but OK
+                                                     @path));
         }
         ii_method(impl_did, is_provided, m) => {
             cx.map_method(impl_did, @path, m, is_provided);
@@ -461,11 +499,12 @@ pub fn map_decoded_item(diag: @mut SpanHandler,
     }
 
     // visit the item / method contents and add those to the map:
-    ii.accept((), cx);
+    ii.accept((), &mut cx);
 }
 
 pub fn node_id_to_str(map: map, id: NodeId, itr: @ident_interner) -> ~str {
-    match map.find(&id) {
+    let map = map.borrow();
+    match map.get().find(&id) {
       None => {
         format!("unknown node (id={})", id)
       }
@@ -529,7 +568,8 @@ pub fn node_id_to_str(map: map, id: NodeId, itr: @ident_interner) -> ~str {
 
 pub fn node_item_query<Result>(items: map, id: NodeId, query: |@item| -> Result, error_msg: ~str)
                        -> Result {
-    match items.find(&id) {
+    let items = items.borrow();
+    match items.get().find(&id) {
         Some(&node_item(it, _)) => query(it),
         _ => fail!("{}", error_msg)
     }
@@ -538,7 +578,8 @@ pub fn node_item_query<Result>(items: map, id: NodeId, query: |@item| -> Result,
 pub fn node_span(items: map,
                  id: ast::NodeId)
                  -> Span {
-    match items.find(&id) {
+    let items = items.borrow();
+    match items.get().find(&id) {
         Some(&node_item(item, _)) => item.span,
         Some(&node_foreign_item(foreign_item, _, _, _)) => foreign_item.span,
         Some(&node_trait_method(@required(ref type_method), _, _)) => type_method.span,
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index f93eb6754ad..f99fed517b1 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -17,6 +17,7 @@ use parse::token;
 use visit::Visitor;
 use visit;
 
+use std::cell::{Cell, RefCell};
 use std::hashmap::HashMap;
 use std::u32;
 use std::local_data;
@@ -136,13 +137,13 @@ pub fn is_shift_binop(b: BinOp) -> bool {
     }
 }
 
-pub fn unop_to_str(op: UnOp) -> ~str {
+pub fn unop_to_str(op: UnOp) -> &'static str {
     match op {
-      UnBox(mt) => if mt == MutMutable { ~"@mut " } else { ~"@" },
-      UnUniq => ~"~",
-      UnDeref => ~"*",
-      UnNot => ~"!",
-      UnNeg => ~"-"
+      UnBox => "@",
+      UnUniq => "~",
+      UnDeref => "*",
+      UnNot => "!",
+      UnNeg => "-",
     }
 }
 
@@ -601,21 +602,23 @@ pub fn visit_ids_for_inlined_item<O: IdVisitingOperation>(item: &inlined_item,
 }
 
 struct IdRangeComputingVisitor {
-    result: @mut id_range,
+    result: Cell<id_range>,
 }
 
 impl IdVisitingOperation for IdRangeComputingVisitor {
     fn visit_id(&self, id: NodeId) {
-        self.result.add(id)
+        let mut id_range = self.result.get();
+        id_range.add(id);
+        self.result.set(id_range)
     }
 }
 
 pub fn compute_id_range_for_inlined_item(item: &inlined_item) -> id_range {
-    let result = @mut id_range::max();
-    visit_ids_for_inlined_item(item, &IdRangeComputingVisitor {
-        result: result,
-    });
-    *result
+    let visitor = IdRangeComputingVisitor {
+        result: Cell::new(id_range::max())
+    };
+    visit_ids_for_inlined_item(item, &visitor);
+    visitor.result.get()
 }
 
 pub fn is_item_impl(item: @ast::item) -> bool {
@@ -709,21 +712,25 @@ pub fn new_mark(m:Mrk, tail:SyntaxContext) -> SyntaxContext {
 
 // Extend a syntax context with a given mark and table
 // FIXME #8215 : currently pub to allow testing
-pub fn new_mark_internal(m:Mrk, tail:SyntaxContext,table:&mut SCTable)
-    -> SyntaxContext {
+pub fn new_mark_internal(m: Mrk, tail: SyntaxContext, table: &SCTable)
+                         -> SyntaxContext {
     let key = (tail,m);
     // FIXME #5074 : can't use more natural style because we're missing
     // flow-sensitivity. Results in two lookups on a hash table hit.
     // also applies to new_rename_internal, below.
     // let try_lookup = table.mark_memo.find(&key);
-    match table.mark_memo.contains_key(&key) {
+    let mut mark_memo = table.mark_memo.borrow_mut();
+    match mark_memo.get().contains_key(&key) {
         false => {
-            let new_idx = idx_push(&mut table.table,Mark(m,tail));
-            table.mark_memo.insert(key,new_idx);
+            let new_idx = {
+                let mut table = table.table.borrow_mut();
+                idx_push(table.get(), Mark(m,tail))
+            };
+            mark_memo.get().insert(key,new_idx);
             new_idx
         }
         true => {
-            match table.mark_memo.find(&key) {
+            match mark_memo.get().find(&key) {
                 None => fail!("internal error: key disappeared 2013042901"),
                 Some(idxptr) => {*idxptr}
             }
@@ -738,19 +745,26 @@ pub fn new_rename(id:Ident, to:Name, tail:SyntaxContext) -> SyntaxContext {
 
 // Extend a syntax context with a given rename and sctable
 // FIXME #8215 : currently pub to allow testing
-pub fn new_rename_internal(id:Ident, to:Name, tail:SyntaxContext, table: &mut SCTable)
-    -> SyntaxContext {
+pub fn new_rename_internal(id: Ident,
+                           to: Name,
+                           tail: SyntaxContext,
+                           table: &SCTable)
+                           -> SyntaxContext {
     let key = (tail,id,to);
     // FIXME #5074
     //let try_lookup = table.rename_memo.find(&key);
-    match table.rename_memo.contains_key(&key) {
+    let mut rename_memo = table.rename_memo.borrow_mut();
+    match rename_memo.get().contains_key(&key) {
         false => {
-            let new_idx = idx_push(&mut table.table,Rename(id,to,tail));
-            table.rename_memo.insert(key,new_idx);
+            let new_idx = {
+                let mut table = table.table.borrow_mut();
+                idx_push(table.get(), Rename(id,to,tail))
+            };
+            rename_memo.get().insert(key,new_idx);
             new_idx
         }
         true => {
-            match table.rename_memo.find(&key) {
+            match rename_memo.get().find(&key) {
                 None => fail!("internal error: key disappeared 2013042902"),
                 Some(idxptr) => {*idxptr}
             }
@@ -763,18 +777,18 @@ pub fn new_rename_internal(id:Ident, to:Name, tail:SyntaxContext, table: &mut SC
 // FIXME #8215 : currently pub to allow testing
 pub fn new_sctable_internal() -> SCTable {
     SCTable {
-        table: ~[EmptyCtxt,IllegalCtxt],
-        mark_memo: HashMap::new(),
-        rename_memo: HashMap::new()
+        table: RefCell::new(~[EmptyCtxt,IllegalCtxt]),
+        mark_memo: RefCell::new(HashMap::new()),
+        rename_memo: RefCell::new(HashMap::new()),
     }
 }
 
 // fetch the SCTable from TLS, create one if it doesn't yet exist.
-pub fn get_sctable() -> @mut SCTable {
-    local_data_key!(sctable_key: @@mut SCTable)
+pub fn get_sctable() -> @SCTable {
+    local_data_key!(sctable_key: @@SCTable)
     match local_data::get(sctable_key, |k| k.map(|k| *k)) {
         None => {
-            let new_table = @@mut new_sctable_internal();
+            let new_table = @@new_sctable_internal();
             local_data::set(sctable_key,new_table);
             *new_table
         },
@@ -785,7 +799,8 @@ pub fn get_sctable() -> @mut SCTable {
 /// print out an SCTable for debugging
 pub fn display_sctable(table : &SCTable) {
     error!("SC table:");
-    for (idx,val) in table.table.iter().enumerate() {
+    let table = table.table.borrow();
+    for (idx,val) in table.get().iter().enumerate() {
         error!("{:4u} : {:?}",idx,val);
     }
 }
@@ -799,7 +814,9 @@ fn idx_push<T>(vec: &mut ~[T], val: T) -> u32 {
 
 /// Resolve a syntax object to a name, per MTWT.
 pub fn mtwt_resolve(id : Ident) -> Name {
-    resolve_internal(id, get_sctable(), get_resolve_table())
+    let resolve_table = get_resolve_table();
+    let mut resolve_table = resolve_table.borrow_mut();
+    resolve_internal(id, get_sctable(), resolve_table.get())
 }
 
 // FIXME #8215: must be pub for testing
@@ -807,12 +824,12 @@ pub type ResolveTable = HashMap<(Name,SyntaxContext),Name>;
 
 // okay, I admit, putting this in TLS is not so nice:
 // fetch the SCTable from TLS, create one if it doesn't yet exist.
-pub fn get_resolve_table() -> @mut ResolveTable {
-    local_data_key!(resolve_table_key: @@mut ResolveTable)
+pub fn get_resolve_table() -> @RefCell<ResolveTable> {
+    local_data_key!(resolve_table_key: @@RefCell<ResolveTable>)
     match local_data::get(resolve_table_key, |k| k.map(|k| *k)) {
         None => {
-            let new_table = @@mut HashMap::new();
-            local_data::set(resolve_table_key,new_table);
+            let new_table = @@RefCell::new(HashMap::new());
+            local_data::set(resolve_table_key, new_table);
             *new_table
         },
         Some(intr) => *intr
@@ -823,13 +840,17 @@ pub fn get_resolve_table() -> @mut ResolveTable {
 // adding memoization to possibly resolve 500+ seconds in resolve for librustc (!)
 // FIXME #8215 : currently pub to allow testing
 pub fn resolve_internal(id : Ident,
-                        table : &mut SCTable,
+                        table : &SCTable,
                         resolve_table : &mut ResolveTable) -> Name {
     let key = (id.name,id.ctxt);
     match resolve_table.contains_key(&key) {
         false => {
             let resolved = {
-                match table.table[id.ctxt] {
+                let result = {
+                    let table = table.table.borrow();
+                    table.get()[id.ctxt]
+                };
+                match result {
                     EmptyCtxt => id.name,
                     // ignore marks here:
                     Mark(_,subctxt) =>
@@ -874,7 +895,11 @@ pub fn marksof(ctxt: SyntaxContext, stopname: Name, table: &SCTable) -> ~[Mrk] {
     let mut result = ~[];
     let mut loopvar = ctxt;
     loop {
-        match table.table[loopvar] {
+        let table_entry = {
+            let table = table.table.borrow();
+            table.get()[loopvar]
+        };
+        match table_entry {
             EmptyCtxt => {return result;},
             Mark(mark,tl) => {
                 xorPush(&mut result,mark);
@@ -898,7 +923,8 @@ pub fn marksof(ctxt: SyntaxContext, stopname: Name, table: &SCTable) -> ~[Mrk] {
 /// FAILS when outside is not a mark.
 pub fn mtwt_outer_mark(ctxt: SyntaxContext) -> Mrk {
     let sctable = get_sctable();
-    match sctable.table[ctxt] {
+    let table = sctable.table.borrow();
+    match table.get()[ctxt] {
         ast::Mark(mrk,_) => mrk,
         _ => fail!("can't retrieve outer mark when outside is not a mark")
     }
@@ -1003,7 +1029,7 @@ mod test {
 
     // unfold a vector of TestSC values into a SCTable,
     // returning the resulting index
-    fn unfold_test_sc(tscs : ~[TestSC], tail: SyntaxContext, table : &mut SCTable)
+    fn unfold_test_sc(tscs : ~[TestSC], tail: SyntaxContext, table: &SCTable)
         -> SyntaxContext {
         tscs.rev_iter().fold(tail, |tail : SyntaxContext, tsc : &TestSC|
                   {match *tsc {
@@ -1015,7 +1041,8 @@ mod test {
     fn refold_test_sc(mut sc: SyntaxContext, table : &SCTable) -> ~[TestSC] {
         let mut result = ~[];
         loop {
-            match table.table[sc] {
+            let table = table.table.borrow();
+            match table.get()[sc] {
                 EmptyCtxt => {return result;},
                 Mark(mrk,tail) => {
                     result.push(M(mrk));
@@ -1037,15 +1064,19 @@ mod test {
 
         let test_sc = ~[M(3),R(id(101,0),14),M(9)];
         assert_eq!(unfold_test_sc(test_sc.clone(),EMPTY_CTXT,&mut t),4);
-        assert_eq!(t.table[2],Mark(9,0));
-        assert_eq!(t.table[3],Rename(id(101,0),14,2));
-        assert_eq!(t.table[4],Mark(3,3));
+        {
+            let table = t.table.borrow();
+            assert_eq!(table.get()[2],Mark(9,0));
+            assert_eq!(table.get()[3],Rename(id(101,0),14,2));
+            assert_eq!(table.get()[4],Mark(3,3));
+        }
         assert_eq!(refold_test_sc(4,&t),test_sc);
     }
 
     // extend a syntax context with a sequence of marks given
     // in a vector. v[0] will be the outermost mark.
-    fn unfold_marks(mrks:~[Mrk],tail:SyntaxContext,table: &mut SCTable) -> SyntaxContext {
+    fn unfold_marks(mrks: ~[Mrk], tail: SyntaxContext, table: &SCTable)
+                    -> SyntaxContext {
         mrks.rev_iter().fold(tail, |tail:SyntaxContext, mrk:&Mrk|
                    {new_mark_internal(*mrk,tail,table)})
     }
@@ -1054,8 +1085,11 @@ mod test {
         let mut t = new_sctable_internal();
 
         assert_eq!(unfold_marks(~[3,7],EMPTY_CTXT,&mut t),3);
-        assert_eq!(t.table[2],Mark(7,0));
-        assert_eq!(t.table[3],Mark(3,2));
+        {
+            let table = t.table.borrow();
+            assert_eq!(table.get()[2],Mark(7,0));
+            assert_eq!(table.get()[3],Mark(3,2));
+        }
     }
 
     #[test] fn test_marksof () {
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 7a3ac0f2f4d..df8b45dbcf5 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -355,8 +355,7 @@ pub fn find_stability<AM: AttrMetaMethods, It: Iterator<AM>>(mut metas: It) -> O
     None
 }
 
-pub fn require_unique_names(diagnostic: @mut SpanHandler,
-                            metas: &[@MetaItem]) {
+pub fn require_unique_names(diagnostic: @SpanHandler, metas: &[@MetaItem]) {
     let mut set = HashSet::new();
     for meta in metas.iter() {
         let name = meta.name();
@@ -381,7 +380,7 @@ pub fn require_unique_names(diagnostic: @mut SpanHandler,
  * present (before fields, if any) with that type; reprensentation
  * optimizations which would remove it will not be done.
  */
-pub fn find_repr_attr(diagnostic: @mut SpanHandler, attr: @ast::MetaItem, acc: ReprAttr)
+pub fn find_repr_attr(diagnostic: @SpanHandler, attr: @ast::MetaItem, acc: ReprAttr)
     -> ReprAttr {
     let mut acc = acc;
     match attr.node {
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index fffcae0bde3..c0aee7fc634 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -21,6 +21,7 @@ source code snippets, etc.
 
 */
 
+use std::cell::RefCell;
 use std::cmp;
 use extra::serialize::{Encodable, Decodable, Encoder, Decoder};
 
@@ -220,9 +221,9 @@ pub struct FileMap {
     /// The start position of this source in the CodeMap
     start_pos: BytePos,
     /// Locations of lines beginnings in the source code
-    lines: @mut ~[BytePos],
+    lines: RefCell<~[BytePos]>,
     /// Locations of multi-byte characters in the source code
-    multibyte_chars: @mut ~[MultiByteChar],
+    multibyte_chars: RefCell<~[MultiByteChar]>,
 }
 
 impl FileMap {
@@ -233,14 +234,16 @@ impl FileMap {
     // about what ends a line between this file and parse.rs
     pub fn next_line(&self, pos: BytePos) {
         // the new charpos must be > the last one (or it's the first one).
-        let lines = &mut *self.lines;
-        assert!((lines.len() == 0) || (lines[lines.len() - 1] < pos))
-        lines.push(pos);
+        let mut lines = self.lines.borrow_mut();;
+        let line_len = lines.get().len();
+        assert!(line_len == 0 || (lines.get()[line_len - 1] < pos))
+        lines.get().push(pos);
     }
 
     // get a line from the list of pre-computed line-beginnings
     pub fn get_line(&self, line: int) -> ~str {
-        let begin: BytePos = self.lines[line] - self.start_pos;
+        let mut lines = self.lines.borrow_mut();
+        let begin: BytePos = lines.get()[line] - self.start_pos;
         let begin = begin.to_uint();
         let slice = self.src.slice_from(begin);
         match slice.find('\n') {
@@ -255,7 +258,8 @@ impl FileMap {
             pos: pos,
             bytes: bytes,
         };
-        self.multibyte_chars.push(mbc);
+        let mut multibyte_chars = self.multibyte_chars.borrow_mut();
+        multibyte_chars.get().push(mbc);
     }
 
     pub fn is_real_file(&self) -> bool {
@@ -264,13 +268,13 @@ impl FileMap {
 }
 
 pub struct CodeMap {
-    files: @mut ~[@FileMap]
+    files: RefCell<~[@FileMap]>
 }
 
 impl CodeMap {
     pub fn new() -> CodeMap {
         CodeMap {
-            files: @mut ~[],
+            files: RefCell::new(~[]),
         }
     }
 
@@ -284,23 +288,23 @@ impl CodeMap {
                                 substr: FileSubstr,
                                 src: @str)
                                 -> @FileMap {
-        let files = &mut *self.files;
-        let start_pos = if files.len() == 0 {
+        let mut files = self.files.borrow_mut();
+        let start_pos = if files.get().len() == 0 {
             0
         } else {
-            let last_start = files.last().start_pos.to_uint();
-            let last_len = files.last().src.len();
+            let last_start = files.get().last().start_pos.to_uint();
+            let last_len = files.get().last().src.len();
             last_start + last_len
         };
 
         let filemap = @FileMap {
             name: filename, substr: substr, src: src,
             start_pos: Pos::from_uint(start_pos),
-            lines: @mut ~[],
-            multibyte_chars: @mut ~[],
+            lines: RefCell::new(~[]),
+            multibyte_chars: RefCell::new(~[]),
         };
 
-        files.push(filemap);
+        files.get().push(filemap);
 
         return filemap;
     }
@@ -346,9 +350,11 @@ impl CodeMap {
     }
 
     pub fn span_to_str(&self, sp: Span) -> ~str {
-        let files = &*self.files;
-        if files.len() == 0 && sp == DUMMY_SP {
-            return ~"no-location";
+        {
+            let files = self.files.borrow();
+            if files.get().len() == 0 && sp == DUMMY_SP {
+                return ~"no-location";
+            }
         }
 
         let lo = self.lookup_char_pos_adj(sp.lo);
@@ -388,7 +394,12 @@ impl CodeMap {
     }
 
     pub fn get_filemap(&self, filename: &str) -> @FileMap {
-        for fm in self.files.iter() { if filename == fm.name { return *fm; } }
+        let files = self.files.borrow();
+        for fm in files.get().iter() {
+            if filename == fm.name {
+                return *fm
+            }
+        }
         //XXjdm the following triggers a mismatched type bug
         //      (or expected function, found _|_)
         fail!(); // ("asking for " + filename + " which we don't know about");
@@ -397,13 +408,14 @@ impl CodeMap {
 
 impl CodeMap {
     fn lookup_filemap_idx(&self, pos: BytePos) -> uint {
-        let files = &*self.files;
+        let files = self.files.borrow();
+        let files = files.get();
         let len = files.len();
         let mut a = 0u;
         let mut b = len;
         while b - a > 1u {
             let m = (a + b) / 2u;
-            if self.files[m].start_pos > pos {
+            if files[m].start_pos > pos {
                 b = m;
             } else {
                 a = m;
@@ -419,13 +431,15 @@ impl CodeMap {
     fn lookup_line(&self, pos: BytePos) -> FileMapAndLine
     {
         let idx = self.lookup_filemap_idx(pos);
-        let f = self.files[idx];
+
+        let files = self.files.borrow();
+        let f = files.get()[idx];
         let mut a = 0u;
-        let lines = &*f.lines;
-        let mut b = lines.len();
+        let mut lines = f.lines.borrow_mut();
+        let mut b = lines.get().len();
         while b - a > 1u {
             let m = (a + b) / 2u;
-            if lines[m] > pos { b = m; } else { a = m; }
+            if lines.get()[m] > pos { b = m; } else { a = m; }
         }
         return FileMapAndLine {fm: f, line: a};
     }
@@ -434,7 +448,8 @@ impl CodeMap {
         let FileMapAndLine {fm: f, line: a} = self.lookup_line(pos);
         let line = a + 1u; // Line numbers start at 1
         let chpos = self.bytepos_to_local_charpos(pos);
-        let linebpos = f.lines[a];
+        let mut lines = f.lines.borrow_mut();
+        let linebpos = lines.get()[a];
         let linechpos = self.bytepos_to_local_charpos(linebpos);
         debug!("codemap: byte pos {:?} is on the line at byte pos {:?}",
                pos, linebpos);
@@ -452,7 +467,8 @@ impl CodeMap {
     fn lookup_byte_offset(&self, bpos: BytePos)
         -> FileMapAndBytePos {
         let idx = self.lookup_filemap_idx(bpos);
-        let fm = self.files[idx];
+        let files = self.files.borrow();
+        let fm = files.get()[idx];
         let offset = bpos - fm.start_pos;
         return FileMapAndBytePos {fm: fm, pos: offset};
     }
@@ -462,12 +478,14 @@ impl CodeMap {
     fn bytepos_to_local_charpos(&self, bpos: BytePos) -> CharPos {
         debug!("codemap: converting {:?} to char pos", bpos);
         let idx = self.lookup_filemap_idx(bpos);
-        let map = self.files[idx];
+        let files = self.files.borrow();
+        let map = files.get()[idx];
 
         // The number of extra bytes due to multibyte chars in the FileMap
         let mut total_extra_bytes = 0;
 
-        for mbc in map.multibyte_chars.iter() {
+        let multibyte_chars = map.multibyte_chars.borrow();
+        for mbc in multibyte_chars.get().iter() {
             debug!("codemap: {:?}-byte char at {:?}", mbc.bytes, mbc.pos);
             if mbc.pos < bpos {
                 total_extra_bytes += mbc.bytes;
diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs
index c905281cdb2..76327c27898 100644
--- a/src/libsyntax/diagnostic.rs
+++ b/src/libsyntax/diagnostic.rs
@@ -11,6 +11,7 @@
 use codemap::{Pos, Span};
 use codemap;
 
+use std::cell::Cell;
 use std::io;
 use std::io::stdio::StdWriter;
 use std::local_data;
@@ -30,32 +31,32 @@ pub trait Emitter {
 // accepts span information for source-location
 // reporting.
 pub struct SpanHandler {
-    handler: @mut Handler,
+    handler: @Handler,
     cm: @codemap::CodeMap,
 }
 
 impl SpanHandler {
-    pub fn span_fatal(@mut self, sp: Span, msg: &str) -> ! {
+    pub fn span_fatal(@self, sp: Span, msg: &str) -> ! {
         self.handler.emit(Some((&*self.cm, sp)), msg, fatal);
         fail!();
     }
-    pub fn span_err(@mut self, sp: Span, msg: &str) {
+    pub fn span_err(@self, sp: Span, msg: &str) {
         self.handler.emit(Some((&*self.cm, sp)), msg, error);
         self.handler.bump_err_count();
     }
-    pub fn span_warn(@mut self, sp: Span, msg: &str) {
+    pub fn span_warn(@self, sp: Span, msg: &str) {
         self.handler.emit(Some((&*self.cm, sp)), msg, warning);
     }
-    pub fn span_note(@mut self, sp: Span, msg: &str) {
+    pub fn span_note(@self, sp: Span, msg: &str) {
         self.handler.emit(Some((&*self.cm, sp)), msg, note);
     }
-    pub fn span_bug(@mut self, sp: Span, msg: &str) -> ! {
+    pub fn span_bug(@self, sp: Span, msg: &str) -> ! {
         self.span_fatal(sp, ice_msg(msg));
     }
-    pub fn span_unimpl(@mut self, sp: Span, msg: &str) -> ! {
+    pub fn span_unimpl(@self, sp: Span, msg: &str) -> ! {
         self.span_bug(sp, ~"unimplemented " + msg);
     }
-    pub fn handler(@mut self) -> @mut Handler {
+    pub fn handler(@self) -> @Handler {
         self.handler
     }
 }
@@ -64,53 +65,53 @@ impl SpanHandler {
 // (fatal, bug, unimpl) may cause immediate exit,
 // others log errors for later reporting.
 pub struct Handler {
-    err_count: uint,
+    err_count: Cell<uint>,
     emit: @Emitter,
 }
 
 impl Handler {
-    pub fn fatal(@mut self, msg: &str) -> ! {
+    pub fn fatal(@self, msg: &str) -> ! {
         self.emit.emit(None, msg, fatal);
         fail!();
     }
-    pub fn err(@mut self, msg: &str) {
+    pub fn err(@self, msg: &str) {
         self.emit.emit(None, msg, error);
         self.bump_err_count();
     }
-    pub fn bump_err_count(@mut self) {
-        self.err_count += 1u;
+    pub fn bump_err_count(@self) {
+        self.err_count.set(self.err_count.get() + 1u);
     }
-    pub fn err_count(@mut self) -> uint {
-        self.err_count
+    pub fn err_count(@self) -> uint {
+        self.err_count.get()
     }
-    pub fn has_errors(@mut self) -> bool {
-        self.err_count > 0u
+    pub fn has_errors(@self) -> bool {
+        self.err_count.get()> 0u
     }
-    pub fn abort_if_errors(@mut self) {
+    pub fn abort_if_errors(@self) {
         let s;
-        match self.err_count {
+        match self.err_count.get() {
           0u => return,
           1u => s = ~"aborting due to previous error",
           _  => {
             s = format!("aborting due to {} previous errors",
-                     self.err_count);
+                     self.err_count.get());
           }
         }
         self.fatal(s);
     }
-    pub fn warn(@mut self, msg: &str) {
+    pub fn warn(@self, msg: &str) {
         self.emit.emit(None, msg, warning);
     }
-    pub fn note(@mut self, msg: &str) {
+    pub fn note(@self, msg: &str) {
         self.emit.emit(None, msg, note);
     }
-    pub fn bug(@mut self, msg: &str) -> ! {
+    pub fn bug(@self, msg: &str) -> ! {
         self.fatal(ice_msg(msg));
     }
-    pub fn unimpl(@mut self, msg: &str) -> ! {
+    pub fn unimpl(@self, msg: &str) -> ! {
         self.bug(~"unimplemented " + msg);
     }
-    pub fn emit(@mut self,
+    pub fn emit(@self,
             cmsp: Option<(&codemap::CodeMap, Span)>,
             msg: &str,
             lvl: level) {
@@ -123,22 +124,22 @@ pub fn ice_msg(msg: &str) -> ~str {
             \nWe would appreciate a bug report: {}", msg, BUG_REPORT_URL)
 }
 
-pub fn mk_span_handler(handler: @mut Handler, cm: @codemap::CodeMap)
-                    -> @mut SpanHandler {
-    @mut SpanHandler {
+pub fn mk_span_handler(handler: @Handler, cm: @codemap::CodeMap)
+                       -> @SpanHandler {
+    @SpanHandler {
         handler: handler,
         cm: cm,
     }
 }
 
-pub fn mk_handler(emitter: Option<@Emitter>) -> @mut Handler {
+pub fn mk_handler(emitter: Option<@Emitter>) -> @Handler {
     let emit: @Emitter = match emitter {
         Some(e) => e,
         None => @DefaultEmitter as @Emitter
     };
 
-    @mut Handler {
-        err_count: 0,
+    @Handler {
+        err_count: Cell::new(0),
         emit: emit,
     }
 }
@@ -327,10 +328,7 @@ fn print_macro_backtrace(cm: &codemap::CodeMap, sp: Span) {
     }
 }
 
-pub fn expect<T:Clone>(
-              diag: @mut SpanHandler,
-              opt: Option<T>,
-              msg: || -> ~str)
+pub fn expect<T:Clone>(diag: @SpanHandler, opt: Option<T>, msg: || -> ~str)
               -> T {
     match opt {
        Some(ref t) => (*t).clone(),
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 03e028ea1f1..b4888f1092f 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -284,7 +284,7 @@ pub fn syntax_expander_table() -> SyntaxEnv {
 // when a macro expansion occurs, the resulting nodes have the backtrace()
 // -> expn_info of their expansion context stored into their span.
 pub struct ExtCtxt {
-    parse_sess: @mut parse::ParseSess,
+    parse_sess: @parse::ParseSess,
     cfg: ast::CrateConfig,
     backtrace: Option<@ExpnInfo>,
 
@@ -293,7 +293,7 @@ pub struct ExtCtxt {
 }
 
 impl ExtCtxt {
-    pub fn new(parse_sess: @mut parse::ParseSess, cfg: ast::CrateConfig)
+    pub fn new(parse_sess: @parse::ParseSess, cfg: ast::CrateConfig)
                -> ExtCtxt {
         ExtCtxt {
             parse_sess: parse_sess,
@@ -320,7 +320,7 @@ impl ExtCtxt {
     }
 
     pub fn codemap(&self) -> @CodeMap { self.parse_sess.cm }
-    pub fn parse_sess(&self) -> @mut parse::ParseSess { self.parse_sess }
+    pub fn parse_sess(&self) -> @parse::ParseSess { self.parse_sess }
     pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() }
     pub fn call_site(&self) -> Span {
         match self.backtrace {
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 1a3513ab81c..481472e8f0b 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -54,7 +54,7 @@ pub trait AstBuilder {
                lifetime: Option<ast::Lifetime>,
                mutbl: ast::Mutability) -> P<ast::Ty>;
     fn ty_uniq(&self, span: Span, ty: P<ast::Ty>) -> P<ast::Ty>;
-    fn ty_box(&self, span: Span, ty: P<ast::Ty>, mutbl: ast::Mutability) -> P<ast::Ty>;
+    fn ty_box(&self, span: Span, ty: P<ast::Ty>) -> P<ast::Ty>;
 
     fn ty_option(&self, ty: P<ast::Ty>) -> P<ast::Ty>;
     fn ty_infer(&self, sp: Span) -> P<ast::Ty>;
@@ -311,12 +311,13 @@ impl AstBuilder for ExtCtxt {
         self.ty(span,
                 ast::ty_rptr(lifetime, self.ty_mt(ty, mutbl)))
     }
+
     fn ty_uniq(&self, span: Span, ty: P<ast::Ty>) -> P<ast::Ty> {
         self.ty(span, ast::ty_uniq(ty))
     }
-    fn ty_box(&self, span: Span,
-                 ty: P<ast::Ty>, mutbl: ast::Mutability) -> P<ast::Ty> {
-        self.ty(span, ast::ty_box(self.ty_mt(ty, mutbl)))
+
+    fn ty_box(&self, span: Span, ty: P<ast::Ty>) -> P<ast::Ty> {
+        self.ty(span, ast::ty_box(ty))
     }
 
     fn ty_option(&self, ty: P<ast::Ty>) -> P<ast::Ty> {
@@ -494,7 +495,7 @@ impl AstBuilder for ExtCtxt {
     }
 
     fn expr_managed(&self, sp: Span, e: @ast::Expr) -> @ast::Expr {
-        self.expr_unary(sp, ast::UnBox(ast::MutImmutable), e)
+        self.expr_unary(sp, ast::UnBox, e)
     }
 
     fn expr_field_access(&self, sp: Span, expr: @ast::Expr, ident: ast::Ident) -> @ast::Expr {
diff --git a/src/libsyntax/ext/deriving/ty.rs b/src/libsyntax/ext/deriving/ty.rs
index 10e07520a84..89bed626c1e 100644
--- a/src/libsyntax/ext/deriving/ty.rs
+++ b/src/libsyntax/ext/deriving/ty.rs
@@ -24,7 +24,7 @@ use opt_vec::OptVec;
 /// The types of pointers
 pub enum PtrTy<'a> {
     Send, // ~
-    Managed(ast::Mutability), // @[mut]
+    Managed, // @
     Borrowed(Option<&'a str>, ast::Mutability), // &['lifetime] [mut]
 }
 
@@ -138,8 +138,8 @@ impl<'a> Ty<'a> {
                     Send => {
                         cx.ty_uniq(span, raw_ty)
                     }
-                    Managed(mutbl) => {
-                        cx.ty_box(span, raw_ty, mutbl)
+                    Managed => {
+                        cx.ty_box(span, raw_ty)
                     }
                     Borrowed(ref lt, mutbl) => {
                         let lt = mk_lifetime(cx, span, lt);
@@ -251,7 +251,7 @@ pub fn get_explicit_self(cx: &ExtCtxt, span: Span, self_ptr: &Option<PtrTy>)
                 span,
                 match *ptr {
                     Send => ast::sty_uniq(ast::MutImmutable),
-                    Managed(mutbl) => ast::sty_box(mutbl),
+                    Managed => ast::sty_box(ast::MutImmutable),
                     Borrowed(ref lt, mutbl) => {
                         let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s)));
                         ast::sty_region(lt, mutbl)
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 1d9620d405f..aa7c26805c3 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -493,13 +493,14 @@ fn expand_non_macro_stmt(s: &Stmt, fld: &mut MacroExpander)
             let mut name_finder = new_name_finder(~[]);
             name_finder.visit_pat(expanded_pat,());
             // generate fresh names, push them to a new pending list
-            let new_pending_renames = @mut ~[];
+            let mut new_pending_renames = ~[];
             for ident in name_finder.ident_accumulator.iter() {
                 let new_name = fresh_name(ident);
                 new_pending_renames.push((*ident,new_name));
             }
             let rewritten_pat = {
-                let mut rename_fld = renames_to_fold(new_pending_renames);
+                let mut rename_fld =
+                    renames_to_fold(&mut new_pending_renames);
                 // rewrite the pattern using the new names (the old ones
                 // have already been applied):
                 rename_fld.fold_pat(expanded_pat)
@@ -889,7 +890,7 @@ impl ast_fold for Injector {
 
 // add a bunch of macros as though they were placed at the head of the
 // program (ick). This should run before cfg stripping.
-pub fn inject_std_macros(parse_sess: @mut parse::ParseSess,
+pub fn inject_std_macros(parse_sess: @parse::ParseSess,
                          cfg: ast::CrateConfig,
                          c: Crate)
                          -> Crate {
@@ -939,7 +940,7 @@ impl<'a> ast_fold for MacroExpander<'a> {
     }
 }
 
-pub fn expand_crate(parse_sess: @mut parse::ParseSess,
+pub fn expand_crate(parse_sess: @parse::ParseSess,
                     cfg: ast::CrateConfig,
                     c: Crate) -> Crate {
     let mut cx = ExtCtxt::new(parse_sess, cfg.clone());
@@ -981,21 +982,6 @@ impl CtxtFn for Renamer {
     }
 }
 
-// a renamer that performs a whole bunch of renames
-pub struct MultiRenamer {
-    renames : @mut ~[(ast::Ident,ast::Name)]
-}
-
-impl CtxtFn for MultiRenamer {
-    fn f(&self, starting_ctxt : ast::SyntaxContext) -> ast::SyntaxContext {
-        // the individual elements are memoized... it would
-        // also be possible to memoize on the whole list at once.
-        self.renames.iter().fold(starting_ctxt,|ctxt,&(from,to)| {
-            new_rename(from,to,ctxt)
-        })
-    }
-}
-
 // a marker adds the given mark to the syntax context
 pub struct Marker { mark : Mrk }
 
@@ -1306,9 +1292,11 @@ mod test {
         let a3_name = gensym("a3");
         // a context that renames from ("a",empty) to "a2" :
         let ctxt2 = new_rename(ast::Ident::new(a_name),a2_name,EMPTY_CTXT);
-        let pending_renames = @mut ~[(ast::Ident::new(a_name),a2_name),
-                                     (ast::Ident{name:a_name,ctxt:ctxt2},a3_name)];
-        let double_renamed = renames_to_fold(pending_renames).fold_crate(item_ast);
+        let mut pending_renames = ~[
+            (ast::Ident::new(a_name),a2_name),
+            (ast::Ident{name:a_name,ctxt:ctxt2},a3_name)
+        ];
+        let double_renamed = renames_to_fold(&mut pending_renames).fold_crate(item_ast);
         let mut path_finder = new_path_finder(~[]);
         visit::walk_crate(&mut path_finder, &double_renamed, ());
         match path_finder.path_accumulator {
@@ -1318,11 +1306,11 @@ mod test {
         }
     }
 
-    fn fake_print_crate(crate: &ast::Crate) {
-        let out = @mut std::io::stderr() as @mut std::io::Writer;
-        let s = pprust::rust_printer(out, get_ident_interner());
-        pprust::print_crate_(s, crate);
-    }
+    //fn fake_print_crate(crate: &ast::Crate) {
+    //    let mut out = ~std::io::stderr() as ~std::io::Writer;
+    //    let mut s = pprust::rust_printer(out, get_ident_interner());
+    //    pprust::print_crate_(&mut s, crate);
+    //}
 
     fn expand_crate_str(crate_str: @str) -> ast::Crate {
         let (crate_ast,ps) = string_to_crate_and_sess(crate_str);
@@ -1516,8 +1504,12 @@ foo_module!()
                          mtwt_resolve(v.segments[0].identifier));
                 let table = get_sctable();
                 println("SC table:");
-                for (idx,val) in table.table.iter().enumerate() {
-                    println!("{:4u} : {:?}",idx,val);
+
+                {
+                    let table = table.table.borrow();
+                    for (idx,val) in table.get().iter().enumerate() {
+                        println!("{:4u} : {:?}",idx,val);
+                    }
                 }
             }
             assert_eq!(mtwt_resolve(v.segments[0].identifier),resolved_binding);
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index 11e7c1c8499..5f634f7f054 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -19,6 +19,7 @@ use parse;
 use parse::token::{get_ident_interner};
 use print::pprust;
 
+use std::cell::RefCell;
 use std::io;
 use std::io::File;
 use std::str;
@@ -108,13 +109,14 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::token_tree])
             let s = s.to_managed();
             // Add this input file to the code map to make it available as
             // dependency information
-            cx.parse_sess.cm.files.push(@codemap::FileMap {
+            let mut files = cx.parse_sess.cm.files.borrow_mut();
+            files.get().push(@codemap::FileMap {
                 name: file.display().to_str().to_managed(),
                 substr: codemap::FssNone,
                 src: s,
                 start_pos: codemap::BytePos(0),
-                lines: @mut ~[],
-                multibyte_chars: @mut ~[],
+                lines: RefCell::new(~[]),
+                multibyte_chars: RefCell::new(~[]),
             });
             base::MRExpr(cx.expr_str(sp, s))
         }
diff --git a/src/libsyntax/ext/trace_macros.rs b/src/libsyntax/ext/trace_macros.rs
index 34151377d7b..a7d1d8fb366 100644
--- a/src/libsyntax/ext/trace_macros.rs
+++ b/src/libsyntax/ext/trace_macros.rs
@@ -25,7 +25,7 @@ pub fn expand_trace_macros(cx: &mut ExtCtxt,
     let tt_rdr = new_tt_reader(cx.parse_sess().span_diagnostic,
                                None,
                                tt.to_owned());
-    let rdr = tt_rdr as @mut reader;
+    let rdr = tt_rdr as @reader;
     let mut rust_parser = Parser(sess, cfg.clone(), rdr.dup());
 
     if rust_parser.is_keyword(keywords::True) {
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index 4d2923f391e..8b22e32262b 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -188,9 +188,9 @@ pub enum named_match {
 
 pub type earley_item = ~MatcherPos;
 
-pub fn nameize(p_s: @mut ParseSess, ms: &[matcher], res: &[@named_match])
+pub fn nameize(p_s: @ParseSess, ms: &[matcher], res: &[@named_match])
             -> HashMap<Ident,@named_match> {
-    fn n_rec(p_s: @mut ParseSess, m: &matcher, res: &[@named_match],
+    fn n_rec(p_s: @ParseSess, m: &matcher, res: &[@named_match],
              ret_val: &mut HashMap<Ident, @named_match>) {
         match *m {
           codemap::Spanned {node: match_tok(_), .. } => (),
@@ -221,12 +221,11 @@ pub enum parse_result {
     error(codemap::Span, ~str)
 }
 
-pub fn parse_or_else(
-    sess: @mut ParseSess,
-    cfg: ast::CrateConfig,
-    rdr: @mut reader,
-    ms: ~[matcher]
-) -> HashMap<Ident, @named_match> {
+pub fn parse_or_else(sess: @ParseSess,
+                     cfg: ast::CrateConfig,
+                     rdr: @reader,
+                     ms: ~[matcher])
+                     -> HashMap<Ident, @named_match> {
     match parse(sess, cfg, rdr, ms) {
       success(m) => m,
       failure(sp, str) => sess.span_diagnostic.span_fatal(sp, str),
@@ -243,12 +242,11 @@ pub fn token_name_eq(t1 : &Token, t2 : &Token) -> bool {
     }
 }
 
-pub fn parse(
-    sess: @mut ParseSess,
-    cfg: ast::CrateConfig,
-    rdr: @mut reader,
-    ms: &[matcher]
-) -> parse_result {
+pub fn parse(sess: @ParseSess,
+             cfg: ast::CrateConfig,
+             rdr: @reader,
+             ms: &[matcher])
+             -> parse_result {
     let mut cur_eis = ~[];
     cur_eis.push(initial_matcher_pos(ms.to_owned(), None, rdr.peek().sp.lo));
 
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index c9827fb54bd..32d9ed1238b 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -130,11 +130,7 @@ fn generic_extension(cx: &ExtCtxt,
         match *lhs {
           @matched_nonterminal(nt_matchers(ref mtcs)) => {
             // `none` is because we're not interpolating
-            let arg_rdr = new_tt_reader(
-                s_d,
-                None,
-                arg.to_owned()
-            ) as @mut reader;
+            let arg_rdr = new_tt_reader(s_d, None, arg.to_owned()) as @reader;
             match parse(cx.parse_sess(), cx.cfg(), arg_rdr, *mtcs) {
               success(named_matches) => {
                 let rhs = match rhses[i] {
@@ -154,10 +150,7 @@ fn generic_extension(cx: &ExtCtxt,
                 // rhs has holes ( `$id` and `$(...)` that need filled)
                 let trncbr = new_tt_reader(s_d, Some(named_matches),
                                            rhs);
-                let p = Parser(cx.parse_sess(),
-                               cx.cfg(),
-                               trncbr as @mut reader);
-
+                let p = Parser(cx.parse_sess(), cx.cfg(), trncbr as @reader);
                 // Let the context choose how to interpret the result.
                 // Weird, but useful for X-macros.
                 return MRAny(@ParserAnyMacro {
@@ -218,7 +211,7 @@ pub fn add_new_extension(cx: &mut ExtCtxt,
                                    arg.clone());
     let argument_map = parse_or_else(cx.parse_sess(),
                                      cx.cfg(),
-                                     arg_reader as @mut reader,
+                                     arg_reader as @reader,
                                      argument_gram);
 
     // Extract the arguments:
diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs
index cbce5fb16cb..060f6b8a8b9 100644
--- a/src/libsyntax/ext/tt/transcribe.rs
+++ b/src/libsyntax/ext/tt/transcribe.rs
@@ -17,65 +17,66 @@ use parse::token::{EOF, INTERPOLATED, IDENT, Token, nt_ident};
 use parse::token::{ident_to_str};
 use parse::lexer::TokenAndSpan;
 
+use std::cell::{Cell, RefCell};
 use std::hashmap::HashMap;
 use std::option;
 
 ///an unzipping of `token_tree`s
 struct TtFrame {
     forest: @~[ast::token_tree],
-    idx: uint,
+    idx: Cell<uint>,
     dotdotdoted: bool,
     sep: Option<Token>,
-    up: Option<@mut TtFrame>,
+    up: Option<@TtFrame>,
 }
 
 pub struct TtReader {
-    sp_diag: @mut SpanHandler,
+    sp_diag: @SpanHandler,
     // the unzipped tree:
-    stack: @mut TtFrame,
+    priv stack: RefCell<@TtFrame>,
     /* for MBE-style macro transcription */
-    interpolations: HashMap<Ident, @named_match>,
-    repeat_idx: ~[uint],
-    repeat_len: ~[uint],
+    priv interpolations: RefCell<HashMap<Ident, @named_match>>,
+    priv repeat_idx: RefCell<~[uint]>,
+    priv repeat_len: RefCell<~[uint]>,
     /* cached: */
-    cur_tok: Token,
-    cur_span: Span
+    cur_tok: RefCell<Token>,
+    cur_span: RefCell<Span>,
 }
 
 /** This can do Macro-By-Example transcription. On the other hand, if
  *  `src` contains no `tt_seq`s and `tt_nonterminal`s, `interp` can (and
  *  should) be none. */
-pub fn new_tt_reader(sp_diag: @mut SpanHandler,
+pub fn new_tt_reader(sp_diag: @SpanHandler,
                      interp: Option<HashMap<Ident,@named_match>>,
                      src: ~[ast::token_tree])
-                  -> @mut TtReader {
-    let r = @mut TtReader {
+                     -> @TtReader {
+    let r = @TtReader {
         sp_diag: sp_diag,
-        stack: @mut TtFrame {
+        stack: RefCell::new(@TtFrame {
             forest: @src,
-            idx: 0u,
+            idx: Cell::new(0u),
             dotdotdoted: false,
             sep: None,
             up: option::None
-        },
+        }),
         interpolations: match interp { /* just a convienience */
-            None => HashMap::new(),
-            Some(x) => x
+            None => RefCell::new(HashMap::new()),
+            Some(x) => RefCell::new(x),
         },
-        repeat_idx: ~[],
-        repeat_len: ~[],
+        repeat_idx: RefCell::new(~[]),
+        repeat_len: RefCell::new(~[]),
         /* dummy values, never read: */
-        cur_tok: EOF,
-        cur_span: DUMMY_SP
+        cur_tok: RefCell::new(EOF),
+        cur_span: RefCell::new(DUMMY_SP),
     };
     tt_next_token(r); /* get cur_tok and cur_span set up */
     return r;
 }
 
-fn dup_tt_frame(f: @mut TtFrame) -> @mut TtFrame {
-    @mut TtFrame {
+fn dup_tt_frame(f: @TtFrame) -> @TtFrame {
+    @TtFrame {
         forest: @(*f.forest).clone(),
-        idx: f.idx,
+        idx: f.idx.clone(),
         dotdotdoted: f.dotdotdoted,
         sep: f.sep.clone(),
         up: match f.up {
@@ -85,22 +86,21 @@ fn dup_tt_frame(f: @mut TtFrame) -> @mut TtFrame {
     }
 }
 
-pub fn dup_tt_reader(r: @mut TtReader) -> @mut TtReader {
-    @mut TtReader {
+pub fn dup_tt_reader(r: @TtReader) -> @TtReader {
+    @TtReader {
         sp_diag: r.sp_diag,
-        stack: dup_tt_frame(r.stack),
+        stack: RefCell::new(dup_tt_frame(r.stack.get())),
         repeat_idx: r.repeat_idx.clone(),
         repeat_len: r.repeat_len.clone(),
         cur_tok: r.cur_tok.clone(),
-        cur_span: r.cur_span,
+        cur_span: r.cur_span.clone(),
         interpolations: r.interpolations.clone(),
     }
 }
 
 
-fn lookup_cur_matched_by_matched(r: &mut TtReader,
-                                      start: @named_match)
-                                   -> @named_match {
+fn lookup_cur_matched_by_matched(r: &TtReader, start: @named_match)
+                                 -> @named_match {
     fn red(ad: @named_match, idx: &uint) -> @named_match {
         match *ad {
           matched_nonterminal(_) => {
@@ -110,15 +110,21 @@ fn lookup_cur_matched_by_matched(r: &mut TtReader,
           matched_seq(ref ads, _) => ads[*idx]
         }
     }
-    r.repeat_idx.iter().fold(start, red)
+    let repeat_idx = r.repeat_idx.borrow();
+    repeat_idx.get().iter().fold(start, red)
 }
 
-fn lookup_cur_matched(r: &mut TtReader, name: Ident) -> @named_match {
-    match r.interpolations.find_copy(&name) {
+fn lookup_cur_matched(r: &TtReader, name: Ident) -> @named_match {
+    let matched_opt = {
+        let interpolations = r.interpolations.borrow();
+        interpolations.get().find_copy(&name)
+    };
+    match matched_opt {
         Some(s) => lookup_cur_matched_by_matched(r, s),
         None => {
-            r.sp_diag.span_fatal(r.cur_span, format!("unknown macro variable `{}`",
-                                                  ident_to_str(&name)));
+            r.sp_diag.span_fatal(r.cur_span.get(),
+                                 format!("unknown macro variable `{}`",
+                                         ident_to_str(&name)));
         }
     }
 }
@@ -130,7 +136,7 @@ enum lis {
     lis_contradiction(~str),
 }
 
-fn lockstep_iter_size(t: &token_tree, r: &mut TtReader) -> lis {
+fn lockstep_iter_size(t: &token_tree, r: &TtReader) -> lis {
     fn lis_merge(lhs: lis, rhs: lis) -> lis {
         match lhs {
           lis_unconstrained => rhs.clone(),
@@ -166,46 +172,56 @@ fn lockstep_iter_size(t: &token_tree, r: &mut TtReader) -> lis {
 
 // return the next token from the TtReader.
 // EFFECT: advances the reader's token field
-pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
+pub fn tt_next_token(r: &TtReader) -> TokenAndSpan {
     // XXX(pcwalton): Bad copy?
     let ret_val = TokenAndSpan {
-        tok: r.cur_tok.clone(),
-        sp: r.cur_span,
+        tok: r.cur_tok.get(),
+        sp: r.cur_span.get(),
     };
     loop {
         {
-            let stack = &mut *r.stack;
-            if stack.idx < stack.forest.len() {
+            let mut stack = r.stack.borrow_mut();
+            if stack.get().idx.get() < stack.get().forest.len() {
                 break;
             }
         }
 
         /* done with this set; pop or repeat? */
-        if ! r.stack.dotdotdoted
-            || { *r.repeat_idx.last() == *r.repeat_len.last() - 1 } {
+        if !r.stack.get().dotdotdoted || {
+                let repeat_idx = r.repeat_idx.borrow();
+                let repeat_len = r.repeat_len.borrow();
+                *repeat_idx.get().last() == *repeat_len.get().last() - 1
+            } {
 
-            match r.stack.up {
+            match r.stack.get().up {
               None => {
-                r.cur_tok = EOF;
+                r.cur_tok.set(EOF);
                 return ret_val;
               }
               Some(tt_f) => {
-                if r.stack.dotdotdoted {
-                    r.repeat_idx.pop();
-                    r.repeat_len.pop();
+                if r.stack.get().dotdotdoted {
+                    {
+                        let mut repeat_idx = r.repeat_idx.borrow_mut();
+                        let mut repeat_len = r.repeat_len.borrow_mut();
+                        repeat_idx.get().pop();
+                        repeat_len.get().pop();
+                    }
                 }
 
-                r.stack = tt_f;
-                r.stack.idx += 1u;
+                r.stack.set(tt_f);
+                r.stack.get().idx.set(r.stack.get().idx.get() + 1u);
               }
             }
 
         } else { /* repeat */
-            r.stack.idx = 0u;
-            r.repeat_idx[r.repeat_idx.len() - 1u] += 1u;
-            match r.stack.sep.clone() {
+            r.stack.get().idx.set(0u);
+            {
+                let mut repeat_idx = r.repeat_idx.borrow_mut();
+                repeat_idx.get()[repeat_idx.get().len() - 1u] += 1u;
+            }
+            match r.stack.get().sep.clone() {
               Some(tk) => {
-                r.cur_tok = tk; /* repeat same span, I guess */
+                r.cur_tok.set(tk); /* repeat same span, I guess */
                 return ret_val;
               }
               None => ()
@@ -215,21 +231,21 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
     loop { /* because it's easiest, this handles `tt_delim` not starting
     with a `tt_tok`, even though it won't happen */
         // XXX(pcwalton): Bad copy.
-        match r.stack.forest[r.stack.idx].clone() {
+        match r.stack.get().forest[r.stack.get().idx.get()].clone() {
           tt_delim(tts) => {
-            r.stack = @mut TtFrame {
+            r.stack.set(@TtFrame {
                 forest: tts,
-                idx: 0u,
+                idx: Cell::new(0u),
                 dotdotdoted: false,
                 sep: None,
-                up: option::Some(r.stack)
-            };
+                up: option::Some(r.stack.get())
+            });
             // if this could be 0-length, we'd need to potentially recur here
           }
           tt_tok(sp, tok) => {
-            r.cur_span = sp;
-            r.cur_tok = tok;
-            r.stack.idx += 1u;
+            r.cur_span.set(sp);
+            r.cur_tok.set(tok);
+            r.stack.get().idx.set(r.stack.get().idx.get() + 1u);
             return ret_val;
           }
           tt_seq(sp, tts, sep, zerok) => {
@@ -256,18 +272,22 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
                                               once");
                           }
 
-                    r.stack.idx += 1u;
+                    r.stack.get().idx.set(r.stack.get().idx.get() + 1u);
                     return tt_next_token(r);
                 } else {
-                    r.repeat_len.push(len);
-                    r.repeat_idx.push(0u);
-                    r.stack = @mut TtFrame {
-                        forest: tts,
-                        idx: 0u,
-                        dotdotdoted: true,
-                        sep: sep,
-                        up: Some(r.stack)
-                    };
+                    {
+                        let mut repeat_idx = r.repeat_idx.borrow_mut();
+                        let mut repeat_len = r.repeat_len.borrow_mut();
+                        repeat_len.get().push(len);
+                        repeat_idx.get().push(0u);
+                        r.stack.set(@TtFrame {
+                            forest: tts,
+                            idx: Cell::new(0u),
+                            dotdotdoted: true,
+                            sep: sep,
+                            up: Some(r.stack.get())
+                        });
+                    }
                 }
               }
             }
@@ -279,20 +299,21 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
               (a) idents can be in lots of places, so it'd be a pain
               (b) we actually can, since it's a token. */
               matched_nonterminal(nt_ident(~sn,b)) => {
-                r.cur_span = sp; r.cur_tok = IDENT(sn,b);
-                r.stack.idx += 1u;
+                r.cur_span.set(sp);
+                r.cur_tok.set(IDENT(sn,b));
+                r.stack.get().idx.set(r.stack.get().idx.get() + 1u);
                 return ret_val;
               }
               matched_nonterminal(ref other_whole_nt) => {
                 // XXX(pcwalton): Bad copy.
-                r.cur_span = sp;
-                r.cur_tok = INTERPOLATED((*other_whole_nt).clone());
-                r.stack.idx += 1u;
+                r.cur_span.set(sp);
+                r.cur_tok.set(INTERPOLATED((*other_whole_nt).clone()));
+                r.stack.get().idx.set(r.stack.get().idx.get() + 1u);
                 return ret_val;
               }
               matched_seq(..) => {
                 r.sp_diag.span_fatal(
-                    r.cur_span, /* blame the macro writer */
+                    r.cur_span.get(), /* blame the macro writer */
                     format!("variable '{}' is still repeating at this depth",
                          ident_to_str(&ident)));
               }
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 4a2adc04fbd..47130a8e355 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -238,7 +238,7 @@ pub trait ast_fold {
     fn fold_ty(&mut self, t: P<Ty>) -> P<Ty> {
         let node = match t.node {
             ty_nil | ty_bot | ty_infer => t.node.clone(),
-            ty_box(ref mt) => ty_box(fold_mt(mt, self)),
+            ty_box(ty) => ty_box(self.fold_ty(ty)),
             ty_uniq(ty) => ty_uniq(self.fold_ty(ty)),
             ty_vec(ty) => ty_vec(self.fold_ty(ty)),
             ty_ptr(ref mt) => ty_ptr(fold_mt(mt, self)),
@@ -866,7 +866,7 @@ mod test {
     use super::*;
 
     // this version doesn't care about getting comments or docstrings in.
-    fn fake_print_crate(s: @pprust::ps, crate: &ast::Crate) {
+    fn fake_print_crate(s: &mut pprust::ps, crate: &ast::Crate) {
         pprust::print_mod(s, &crate.module, crate.attrs);
     }
 
diff --git a/src/libsyntax/parse/comments.rs b/src/libsyntax/parse/comments.rs
index b1390253d19..e0ab7f1535d 100644
--- a/src/libsyntax/parse/comments.rs
+++ b/src/libsyntax/parse/comments.rs
@@ -135,39 +135,44 @@ pub fn strip_doc_comment_decoration(comment: &str) -> ~str {
     fail!("not a doc-comment: {}", comment);
 }
 
-fn read_to_eol(rdr: @mut StringReader) -> ~str {
+fn read_to_eol(rdr: @StringReader) -> ~str {
     let mut val = ~"";
-    while rdr.curr != '\n' && !is_eof(rdr) {
-        val.push_char(rdr.curr);
+    while rdr.curr.get() != '\n' && !is_eof(rdr) {
+        val.push_char(rdr.curr.get());
         bump(rdr);
     }
-    if rdr.curr == '\n' { bump(rdr); }
+    if rdr.curr.get() == '\n' { bump(rdr); }
     return val;
 }
 
-fn read_one_line_comment(rdr: @mut StringReader) -> ~str {
+fn read_one_line_comment(rdr: @StringReader) -> ~str {
     let val = read_to_eol(rdr);
     assert!((val[0] == '/' as u8 && val[1] == '/' as u8) ||
                  (val[0] == '#' as u8 && val[1] == '!' as u8));
     return val;
 }
 
-fn consume_non_eol_whitespace(rdr: @mut StringReader) {
-    while is_whitespace(rdr.curr) && rdr.curr != '\n' && !is_eof(rdr) {
+fn consume_non_eol_whitespace(rdr: @StringReader) {
+    while is_whitespace(rdr.curr.get()) && rdr.curr.get() != '\n' &&
+            !is_eof(rdr) {
         bump(rdr);
     }
 }
 
-fn push_blank_line_comment(rdr: @mut StringReader, comments: &mut ~[cmnt]) {
+fn push_blank_line_comment(rdr: @StringReader, comments: &mut ~[cmnt]) {
     debug!(">>> blank-line comment");
     let v: ~[~str] = ~[];
-    comments.push(cmnt {style: blank_line, lines: v, pos: rdr.last_pos});
+    comments.push(cmnt {
+        style: blank_line,
+        lines: v,
+        pos: rdr.last_pos.get(),
+    });
 }
 
-fn consume_whitespace_counting_blank_lines(rdr: @mut StringReader,
+fn consume_whitespace_counting_blank_lines(rdr: @StringReader,
                                            comments: &mut ~[cmnt]) {
-    while is_whitespace(rdr.curr) && !is_eof(rdr) {
-        if rdr.col == CharPos(0u) && rdr.curr == '\n' {
+    while is_whitespace(rdr.curr.get()) && !is_eof(rdr) {
+        if rdr.col.get() == CharPos(0u) && rdr.curr.get() == '\n' {
             push_blank_line_comment(rdr, &mut *comments);
         }
         bump(rdr);
@@ -175,10 +180,10 @@ fn consume_whitespace_counting_blank_lines(rdr: @mut StringReader,
 }
 
 
-fn read_shebang_comment(rdr: @mut StringReader, code_to_the_left: bool,
+fn read_shebang_comment(rdr: @StringReader, code_to_the_left: bool,
                                             comments: &mut ~[cmnt]) {
     debug!(">>> shebang comment");
-    let p = rdr.last_pos;
+    let p = rdr.last_pos.get();
     debug!("<<< shebang comment");
     comments.push(cmnt {
         style: if code_to_the_left { trailing } else { isolated },
@@ -187,12 +192,12 @@ fn read_shebang_comment(rdr: @mut StringReader, code_to_the_left: bool,
     });
 }
 
-fn read_line_comments(rdr: @mut StringReader, code_to_the_left: bool,
+fn read_line_comments(rdr: @StringReader, code_to_the_left: bool,
                                           comments: &mut ~[cmnt]) {
     debug!(">>> line comments");
-    let p = rdr.last_pos;
+    let p = rdr.last_pos.get();
     let mut lines: ~[~str] = ~[];
-    while rdr.curr == '/' && nextch(rdr) == '/' {
+    while rdr.curr.get() == '/' && nextch(rdr) == '/' {
         let line = read_one_line_comment(rdr);
         debug!("{}", line);
         if is_doc_comment(line) { // doc-comments are not put in comments
@@ -244,22 +249,22 @@ fn trim_whitespace_prefix_and_push_line(lines: &mut ~[~str],
     lines.push(s1);
 }
 
-fn read_block_comment(rdr: @mut StringReader,
+fn read_block_comment(rdr: @StringReader,
                       code_to_the_left: bool,
                       comments: &mut ~[cmnt]) {
     debug!(">>> block comment");
-    let p = rdr.last_pos;
+    let p = rdr.last_pos.get();
     let mut lines: ~[~str] = ~[];
-    let col: CharPos = rdr.col;
+    let col: CharPos = rdr.col.get();
     bump(rdr);
     bump(rdr);
 
     let mut curr_line = ~"/*";
 
     // doc-comments are not really comments, they are attributes
-    if rdr.curr == '*' || rdr.curr == '!' {
-        while !(rdr.curr == '*' && nextch(rdr) == '/') && !is_eof(rdr) {
-            curr_line.push_char(rdr.curr);
+    if rdr.curr.get() == '*' || rdr.curr.get() == '!' {
+        while !(rdr.curr.get() == '*' && nextch(rdr) == '/') && !is_eof(rdr) {
+            curr_line.push_char(rdr.curr.get());
             bump(rdr);
         }
         if !is_eof(rdr) {
@@ -275,22 +280,22 @@ fn read_block_comment(rdr: @mut StringReader,
         while level > 0 {
             debug!("=== block comment level {}", level);
             if is_eof(rdr) {
-                (rdr as @mut reader).fatal(~"unterminated block comment");
+                (rdr as @reader).fatal(~"unterminated block comment");
             }
-            if rdr.curr == '\n' {
+            if rdr.curr.get() == '\n' {
                 trim_whitespace_prefix_and_push_line(&mut lines, curr_line,
                                                      col);
                 curr_line = ~"";
                 bump(rdr);
             } else {
-                curr_line.push_char(rdr.curr);
-                if rdr.curr == '/' && nextch(rdr) == '*' {
+                curr_line.push_char(rdr.curr.get());
+                if rdr.curr.get() == '/' && nextch(rdr) == '*' {
                     bump(rdr);
                     bump(rdr);
                     curr_line.push_char('*');
                     level += 1;
                 } else {
-                    if rdr.curr == '*' && nextch(rdr) == '/' {
+                    if rdr.curr.get() == '*' && nextch(rdr) == '/' {
                         bump(rdr);
                         bump(rdr);
                         curr_line.push_char('/');
@@ -306,28 +311,28 @@ fn read_block_comment(rdr: @mut StringReader,
 
     let mut style = if code_to_the_left { trailing } else { isolated };
     consume_non_eol_whitespace(rdr);
-    if !is_eof(rdr) && rdr.curr != '\n' && lines.len() == 1u {
+    if !is_eof(rdr) && rdr.curr.get() != '\n' && lines.len() == 1u {
         style = mixed;
     }
     debug!("<<< block comment");
     comments.push(cmnt {style: style, lines: lines, pos: p});
 }
 
-fn peeking_at_comment(rdr: @mut StringReader) -> bool {
-    return ((rdr.curr == '/' && nextch(rdr) == '/') ||
-         (rdr.curr == '/' && nextch(rdr) == '*')) ||
-         (rdr.curr == '#' && nextch(rdr) == '!');
+fn peeking_at_comment(rdr: @StringReader) -> bool {
+    return ((rdr.curr.get() == '/' && nextch(rdr) == '/') ||
+         (rdr.curr.get() == '/' && nextch(rdr) == '*')) ||
+         (rdr.curr.get() == '#' && nextch(rdr) == '!');
 }
 
-fn consume_comment(rdr: @mut StringReader,
+fn consume_comment(rdr: @StringReader,
                    code_to_the_left: bool,
                    comments: &mut ~[cmnt]) {
     debug!(">>> consume comment");
-    if rdr.curr == '/' && nextch(rdr) == '/' {
+    if rdr.curr.get() == '/' && nextch(rdr) == '/' {
         read_line_comments(rdr, code_to_the_left, comments);
-    } else if rdr.curr == '/' && nextch(rdr) == '*' {
+    } else if rdr.curr.get() == '/' && nextch(rdr) == '*' {
         read_block_comment(rdr, code_to_the_left, comments);
-    } else if rdr.curr == '#' && nextch(rdr) == '!' {
+    } else if rdr.curr.get() == '#' && nextch(rdr) == '!' {
         read_shebang_comment(rdr, code_to_the_left, comments);
     } else { fail!(); }
     debug!("<<< consume comment");
@@ -342,7 +347,7 @@ pub struct lit {
 // it appears this function is called only from pprust... that's
 // probably not a good thing.
 pub fn gather_comments_and_literals(span_diagnostic:
-                                    @mut diagnostic::SpanHandler,
+                                        @diagnostic::SpanHandler,
                                     path: @str,
                                     srdr: &mut io::Reader)
                                  -> (~[cmnt], ~[lit]) {
@@ -358,7 +363,7 @@ pub fn gather_comments_and_literals(span_diagnostic:
         loop {
             let mut code_to_the_left = !first_read;
             consume_non_eol_whitespace(rdr);
-            if rdr.curr == '\n' {
+            if rdr.curr.get() == '\n' {
                 code_to_the_left = false;
                 consume_whitespace_counting_blank_lines(rdr, &mut comments);
             }
@@ -370,7 +375,7 @@ pub fn gather_comments_and_literals(span_diagnostic:
         }
 
 
-        let bstart = rdr.last_pos;
+        let bstart = rdr.last_pos.get();
         rdr.next_token();
         //discard, and look ahead; we're working with internal state
         let TokenAndSpan {tok: tok, sp: sp} = rdr.peek();
diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs
index be93c962137..3b81b09112b 100644
--- a/src/libsyntax/parse/lexer.rs
+++ b/src/libsyntax/parse/lexer.rs
@@ -18,6 +18,7 @@ use parse::token;
 use parse::token::{str_to_ident};
 
 use std::cast::transmute;
+use std::cell::{Cell, RefCell};
 use std::char;
 use std::num::from_str_radix;
 use std::util;
@@ -25,12 +26,12 @@ use std::util;
 pub use ext::tt::transcribe::{TtReader, new_tt_reader};
 
 pub trait reader {
-    fn is_eof(@mut self) -> bool;
-    fn next_token(@mut self) -> TokenAndSpan;
-    fn fatal(@mut self, ~str) -> !;
-    fn span_diag(@mut self) -> @mut SpanHandler;
-    fn peek(@mut self) -> TokenAndSpan;
-    fn dup(@mut self) -> @mut reader;
+    fn is_eof(@self) -> bool;
+    fn next_token(@self) -> TokenAndSpan;
+    fn fatal(@self, ~str) -> !;
+    fn span_diag(@self) -> @SpanHandler;
+    fn peek(@self) -> TokenAndSpan;
+    fn dup(@self) -> @reader;
 }
 
 #[deriving(Clone, Eq)]
@@ -40,47 +41,47 @@ pub struct TokenAndSpan {
 }
 
 pub struct StringReader {
-    span_diagnostic: @mut SpanHandler,
+    span_diagnostic: @SpanHandler,
     src: @str,
     // The absolute offset within the codemap of the next character to read
-    pos: BytePos,
+    pos: Cell<BytePos>,
     // The absolute offset within the codemap of the last character read(curr)
-    last_pos: BytePos,
+    last_pos: Cell<BytePos>,
     // The column of the next character to read
-    col: CharPos,
+    col: Cell<CharPos>,
     // The last character to be read
-    curr: char,
+    curr: Cell<char>,
     filemap: @codemap::FileMap,
     /* cached: */
-    peek_tok: token::Token,
-    peek_span: Span
+    peek_tok: RefCell<token::Token>,
+    peek_span: RefCell<Span>,
 }
 
-pub fn new_string_reader(span_diagnostic: @mut SpanHandler,
+pub fn new_string_reader(span_diagnostic: @SpanHandler,
                          filemap: @codemap::FileMap)
-                      -> @mut StringReader {
+                      -> @StringReader {
     let r = new_low_level_string_reader(span_diagnostic, filemap);
     string_advance_token(r); /* fill in peek_* */
     return r;
 }
 
 /* For comments.rs, which hackily pokes into 'pos' and 'curr' */
-pub fn new_low_level_string_reader(span_diagnostic: @mut SpanHandler,
+pub fn new_low_level_string_reader(span_diagnostic: @SpanHandler,
                                    filemap: @codemap::FileMap)
-                                -> @mut StringReader {
+                                -> @StringReader {
     // Force the initial reader bump to start on a fresh line
     let initial_char = '\n';
-    let r = @mut StringReader {
+    let r = @StringReader {
         span_diagnostic: span_diagnostic,
         src: filemap.src,
-        pos: filemap.start_pos,
-        last_pos: filemap.start_pos,
-        col: CharPos(0),
-        curr: initial_char,
+        pos: Cell::new(filemap.start_pos),
+        last_pos: Cell::new(filemap.start_pos),
+        col: Cell::new(CharPos(0)),
+        curr: Cell::new(initial_char),
         filemap: filemap,
         /* dummy values; not read */
-        peek_tok: token::EOF,
-        peek_span: codemap::DUMMY_SP
+        peek_tok: RefCell::new(token::EOF),
+        peek_span: RefCell::new(codemap::DUMMY_SP),
     };
     bump(r);
     return r;
@@ -89,78 +90,84 @@ pub fn new_low_level_string_reader(span_diagnostic: @mut SpanHandler,
 // duplicating the string reader is probably a bad idea, in
 // that using them will cause interleaved pushes of line
 // offsets to the underlying filemap...
-fn dup_string_reader(r: @mut StringReader) -> @mut StringReader {
-    @mut StringReader {
+fn dup_string_reader(r: @StringReader) -> @StringReader {
+    @StringReader {
         span_diagnostic: r.span_diagnostic,
         src: r.src,
-        pos: r.pos,
-        last_pos: r.last_pos,
-        col: r.col,
-        curr: r.curr,
+        pos: Cell::new(r.pos.get()),
+        last_pos: Cell::new(r.last_pos.get()),
+        col: Cell::new(r.col.get()),
+        curr: Cell::new(r.curr.get()),
         filemap: r.filemap,
         peek_tok: r.peek_tok.clone(),
-        peek_span: r.peek_span
+        peek_span: r.peek_span.clone(),
     }
 }
 
 impl reader for StringReader {
-    fn is_eof(@mut self) -> bool { is_eof(self) }
+    fn is_eof(@self) -> bool { is_eof(self) }
     // return the next token. EFFECT: advances the string_reader.
-    fn next_token(@mut self) -> TokenAndSpan {
-        let ret_val = TokenAndSpan {
-            tok: util::replace(&mut self.peek_tok, token::UNDERSCORE),
-            sp: self.peek_span,
+    fn next_token(@self) -> TokenAndSpan {
+        let ret_val = {
+            let mut peek_tok = self.peek_tok.borrow_mut();
+            TokenAndSpan {
+                tok: util::replace(peek_tok.get(), token::UNDERSCORE),
+                sp: self.peek_span.get(),
+            }
         };
         string_advance_token(self);
         ret_val
     }
-    fn fatal(@mut self, m: ~str) -> ! {
-        self.span_diagnostic.span_fatal(self.peek_span, m)
+    fn fatal(@self, m: ~str) -> ! {
+        self.span_diagnostic.span_fatal(self.peek_span.get(), m)
     }
-    fn span_diag(@mut self) -> @mut SpanHandler { self.span_diagnostic }
-    fn peek(@mut self) -> TokenAndSpan {
+    fn span_diag(@self) -> @SpanHandler { self.span_diagnostic }
+    fn peek(@self) -> TokenAndSpan {
         // XXX(pcwalton): Bad copy!
         TokenAndSpan {
-            tok: self.peek_tok.clone(),
-            sp: self.peek_span,
+            tok: self.peek_tok.get(),
+            sp: self.peek_span.get(),
         }
     }
-    fn dup(@mut self) -> @mut reader { dup_string_reader(self) as @mut reader }
+    fn dup(@self) -> @reader { dup_string_reader(self) as @reader }
 }
 
 impl reader for TtReader {
-    fn is_eof(@mut self) -> bool { self.cur_tok == token::EOF }
-    fn next_token(@mut self) -> TokenAndSpan {
+    fn is_eof(@self) -> bool {
+        let cur_tok = self.cur_tok.borrow();
+        *cur_tok.get() == token::EOF
+    }
+    fn next_token(@self) -> TokenAndSpan {
         let r = tt_next_token(self);
         debug!("TtReader: r={:?}", r);
         return r;
     }
-    fn fatal(@mut self, m: ~str) -> ! {
-        self.sp_diag.span_fatal(self.cur_span, m);
+    fn fatal(@self, m: ~str) -> ! {
+        self.sp_diag.span_fatal(self.cur_span.get(), m);
     }
-    fn span_diag(@mut self) -> @mut SpanHandler { self.sp_diag }
-    fn peek(@mut self) -> TokenAndSpan {
+    fn span_diag(@self) -> @SpanHandler { self.sp_diag }
+    fn peek(@self) -> TokenAndSpan {
         TokenAndSpan {
-            tok: self.cur_tok.clone(),
-            sp: self.cur_span,
+            tok: self.cur_tok.get(),
+            sp: self.cur_span.get(),
         }
     }
-    fn dup(@mut self) -> @mut reader { dup_tt_reader(self) as @mut reader }
+    fn dup(@self) -> @reader { dup_tt_reader(self) as @reader }
 }
 
 // report a lexical error spanning [`from_pos`, `to_pos`)
-fn fatal_span(rdr: @mut StringReader,
+fn fatal_span(rdr: @StringReader,
               from_pos: BytePos,
               to_pos: BytePos,
               m: ~str)
            -> ! {
-    rdr.peek_span = codemap::mk_sp(from_pos, to_pos);
+    rdr.peek_span.set(codemap::mk_sp(from_pos, to_pos));
     rdr.fatal(m);
 }
 
 // report a lexical error spanning [`from_pos`, `to_pos`), appending an
 // escaped character to the error message
-fn fatal_span_char(rdr: @mut StringReader,
+fn fatal_span_char(rdr: @StringReader,
                    from_pos: BytePos,
                    to_pos: BytePos,
                    m: ~str,
@@ -174,7 +181,7 @@ fn fatal_span_char(rdr: @mut StringReader,
 
 // report a lexical error spanning [`from_pos`, `to_pos`), appending the
 // offending string to the error message
-fn fatal_span_verbose(rdr: @mut StringReader,
+fn fatal_span_verbose(rdr: @StringReader,
                       from_pos: BytePos,
                       to_pos: BytePos,
                       m: ~str)
@@ -190,19 +197,20 @@ fn fatal_span_verbose(rdr: @mut StringReader,
 
 // EFFECT: advance peek_tok and peek_span to refer to the next token.
 // EFFECT: update the interner, maybe.
-fn string_advance_token(r: @mut StringReader) {
+fn string_advance_token(r: @StringReader) {
     match (consume_whitespace_and_comments(r)) {
         Some(comment) => {
-            r.peek_span = comment.sp;
-            r.peek_tok = comment.tok;
+            r.peek_span.set(comment.sp);
+            r.peek_tok.set(comment.tok);
         },
         None => {
             if is_eof(r) {
-                r.peek_tok = token::EOF;
+                r.peek_tok.set(token::EOF);
             } else {
-                let start_bytepos = r.last_pos;
-                r.peek_tok = next_token_inner(r);
-                r.peek_span = codemap::mk_sp(start_bytepos, r.last_pos);
+                let start_bytepos = r.last_pos.get();
+                r.peek_tok.set(next_token_inner(r));
+                r.peek_span.set(codemap::mk_sp(start_bytepos,
+                                               r.last_pos.get()));
             };
         }
     }
@@ -216,17 +224,17 @@ fn byte_offset(rdr: &StringReader, pos: BytePos) -> BytePos {
 /// up to but excluding `rdr.last_pos`, meaning the slice does not include
 /// the character `rdr.curr`.
 pub fn with_str_from<T>(
-                     rdr: @mut StringReader,
+                     rdr: @StringReader,
                      start: BytePos,
                      f: |s: &str| -> T)
                      -> T {
-    with_str_from_to(rdr, start, rdr.last_pos, f)
+    with_str_from_to(rdr, start, rdr.last_pos.get(), f)
 }
 
 /// Calls `f` with astring slice of the source text spanning from `start`
 /// up to but excluding `end`.
 fn with_str_from_to<T>(
-                    rdr: @mut StringReader,
+                    rdr: @StringReader,
                     start: BytePos,
                     end: BytePos,
                     f: |s: &str| -> T)
@@ -238,20 +246,22 @@ fn with_str_from_to<T>(
 
 // EFFECT: advance the StringReader by one character. If a newline is
 // discovered, add it to the FileMap's list of line start offsets.
-pub fn bump(rdr: &mut StringReader) {
-    rdr.last_pos = rdr.pos;
-    let current_byte_offset = byte_offset(rdr, rdr.pos).to_uint();
+pub fn bump(rdr: &StringReader) {
+    rdr.last_pos.set(rdr.pos.get());
+    let current_byte_offset = byte_offset(rdr, rdr.pos.get()).to_uint();
     if current_byte_offset < (rdr.src).len() {
-        assert!(rdr.curr != unsafe { transmute(-1u32) }); // FIXME: #8971: unsound
-        let last_char = rdr.curr;
+        assert!(rdr.curr.get() != unsafe {
+            transmute(-1u32)
+        }); // FIXME: #8971: unsound
+        let last_char = rdr.curr.get();
         let next = rdr.src.char_range_at(current_byte_offset);
         let byte_offset_diff = next.next - current_byte_offset;
-        rdr.pos = rdr.pos + Pos::from_uint(byte_offset_diff);
-        rdr.curr = next.ch;
-        rdr.col = rdr.col + CharPos(1u);
+        rdr.pos.set(rdr.pos.get() + Pos::from_uint(byte_offset_diff));
+        rdr.curr.set(next.ch);
+        rdr.col.set(rdr.col.get() + CharPos(1u));
         if last_char == '\n' {
-            rdr.filemap.next_line(rdr.last_pos);
-            rdr.col = CharPos(0u);
+            rdr.filemap.next_line(rdr.last_pos.get());
+            rdr.col.set(CharPos(0u));
         }
 
         if byte_offset_diff > 1 {
@@ -259,14 +269,14 @@ pub fn bump(rdr: &mut StringReader) {
                 Pos::from_uint(current_byte_offset), byte_offset_diff);
         }
     } else {
-        rdr.curr = unsafe { transmute(-1u32) }; // FIXME: #8971: unsound
+        rdr.curr.set(unsafe { transmute(-1u32) }); // FIXME: #8971: unsound
     }
 }
-pub fn is_eof(rdr: @mut StringReader) -> bool {
-    rdr.curr == unsafe { transmute(-1u32) } // FIXME: #8971: unsound
+pub fn is_eof(rdr: @StringReader) -> bool {
+    rdr.curr.get() == unsafe { transmute(-1u32) } // FIXME: #8971: unsound
 }
-pub fn nextch(rdr: @mut StringReader) -> char {
-    let offset = byte_offset(rdr, rdr.pos).to_uint();
+pub fn nextch(rdr: @StringReader) -> char {
+    let offset = byte_offset(rdr, rdr.pos.get()).to_uint();
     if offset < (rdr.src).len() {
         return rdr.src.char_at(offset);
     } else { return unsafe { transmute(-1u32) }; } // FIXME: #8971: unsound
@@ -296,9 +306,9 @@ fn is_hex_digit(c: char) -> bool {
 
 // EFFECT: eats whitespace and comments.
 // returns a Some(sugared-doc-attr) if one exists, None otherwise.
-fn consume_whitespace_and_comments(rdr: @mut StringReader)
+fn consume_whitespace_and_comments(rdr: @StringReader)
                                 -> Option<TokenAndSpan> {
-    while is_whitespace(rdr.curr) { bump(rdr); }
+    while is_whitespace(rdr.curr.get()) { bump(rdr); }
     return consume_any_line_comment(rdr);
 }
 
@@ -309,17 +319,17 @@ pub fn is_line_non_doc_comment(s: &str) -> bool {
 // PRECONDITION: rdr.curr is not whitespace
 // EFFECT: eats any kind of comment.
 // returns a Some(sugared-doc-attr) if one exists, None otherwise
-fn consume_any_line_comment(rdr: @mut StringReader)
+fn consume_any_line_comment(rdr: @StringReader)
                          -> Option<TokenAndSpan> {
-    if rdr.curr == '/' {
+    if rdr.curr.get() == '/' {
         match nextch(rdr) {
           '/' => {
             bump(rdr);
             bump(rdr);
             // line comments starting with "///" or "//!" are doc-comments
-            if rdr.curr == '/' || rdr.curr == '!' {
-                let start_bpos = rdr.pos - BytePos(3);
-                while rdr.curr != '\n' && !is_eof(rdr) {
+            if rdr.curr.get() == '/' || rdr.curr.get() == '!' {
+                let start_bpos = rdr.pos.get() - BytePos(3);
+                while rdr.curr.get() != '\n' && !is_eof(rdr) {
                     bump(rdr);
                 }
                 let ret = with_str_from(rdr, start_bpos, |string| {
@@ -327,7 +337,7 @@ fn consume_any_line_comment(rdr: @mut StringReader)
                     if !is_line_non_doc_comment(string) {
                         Some(TokenAndSpan{
                             tok: token::DOC_COMMENT(str_to_ident(string)),
-                            sp: codemap::mk_sp(start_bpos, rdr.pos)
+                            sp: codemap::mk_sp(start_bpos, rdr.pos.get())
                         })
                     } else {
                         None
@@ -338,7 +348,7 @@ fn consume_any_line_comment(rdr: @mut StringReader)
                     return ret;
                 }
             } else {
-                while rdr.curr != '\n' && !is_eof(rdr) { bump(rdr); }
+                while rdr.curr.get() != '\n' && !is_eof(rdr) { bump(rdr); }
             }
             // Restart whitespace munch.
             return consume_whitespace_and_comments(rdr);
@@ -346,15 +356,18 @@ fn consume_any_line_comment(rdr: @mut StringReader)
           '*' => { bump(rdr); bump(rdr); return consume_block_comment(rdr); }
           _ => ()
         }
-    } else if rdr.curr == '#' {
+    } else if rdr.curr.get() == '#' {
         if nextch(rdr) == '!' {
             // I guess this is the only way to figure out if
             // we're at the beginning of the file...
             let cmap = @CodeMap::new();
-            (*cmap).files.push(rdr.filemap);
-            let loc = cmap.lookup_char_pos_adj(rdr.last_pos);
+            {
+                let mut files = cmap.files.borrow_mut();
+                files.get().push(rdr.filemap);
+            }
+            let loc = cmap.lookup_char_pos_adj(rdr.last_pos.get());
             if loc.line == 1u && loc.col == CharPos(0u) {
-                while rdr.curr != '\n' && !is_eof(rdr) { bump(rdr); }
+                while rdr.curr.get() != '\n' && !is_eof(rdr) { bump(rdr); }
                 return consume_whitespace_and_comments(rdr);
             }
         }
@@ -367,11 +380,10 @@ pub fn is_block_non_doc_comment(s: &str) -> bool {
 }
 
 // might return a sugared-doc-attr
-fn consume_block_comment(rdr: @mut StringReader)
-                      -> Option<TokenAndSpan> {
+fn consume_block_comment(rdr: @StringReader) -> Option<TokenAndSpan> {
     // block comments starting with "/**" or "/*!" are doc-comments
-    let is_doc_comment = rdr.curr == '*' || rdr.curr == '!';
-    let start_bpos = rdr.pos - BytePos(if is_doc_comment {3} else {2});
+    let is_doc_comment = rdr.curr.get() == '*' || rdr.curr.get() == '!';
+    let start_bpos = rdr.pos.get() - BytePos(if is_doc_comment {3} else {2});
 
     let mut level: int = 1;
     while level > 0 {
@@ -381,12 +393,12 @@ fn consume_block_comment(rdr: @mut StringReader)
             } else {
                 ~"unterminated block comment"
             };
-            fatal_span(rdr, start_bpos, rdr.last_pos, msg);
-        } else if rdr.curr == '/' && nextch(rdr) == '*' {
+            fatal_span(rdr, start_bpos, rdr.last_pos.get(), msg);
+        } else if rdr.curr.get() == '/' && nextch(rdr) == '*' {
             level += 1;
             bump(rdr);
             bump(rdr);
-        } else if rdr.curr == '*' && nextch(rdr) == '/' {
+        } else if rdr.curr.get() == '*' && nextch(rdr) == '/' {
             level -= 1;
             bump(rdr);
             bump(rdr);
@@ -401,7 +413,7 @@ fn consume_block_comment(rdr: @mut StringReader)
             if !is_block_non_doc_comment(string) {
                 Some(TokenAndSpan{
                         tok: token::DOC_COMMENT(str_to_ident(string)),
-                        sp: codemap::mk_sp(start_bpos, rdr.pos)
+                        sp: codemap::mk_sp(start_bpos, rdr.pos.get())
                     })
             } else {
                 None
@@ -415,13 +427,13 @@ fn consume_block_comment(rdr: @mut StringReader)
     if res.is_some() { res } else { consume_whitespace_and_comments(rdr) }
 }
 
-fn scan_exponent(rdr: @mut StringReader, start_bpos: BytePos) -> Option<~str> {
-    let mut c = rdr.curr;
+fn scan_exponent(rdr: @StringReader, start_bpos: BytePos) -> Option<~str> {
+    let mut c = rdr.curr.get();
     let mut rslt = ~"";
     if c == 'e' || c == 'E' {
         rslt.push_char(c);
         bump(rdr);
-        c = rdr.curr;
+        c = rdr.curr.get();
         if c == '-' || c == '+' {
             rslt.push_char(c);
             bump(rdr);
@@ -430,16 +442,16 @@ fn scan_exponent(rdr: @mut StringReader, start_bpos: BytePos) -> Option<~str> {
         if exponent.len() > 0u {
             return Some(rslt + exponent);
         } else {
-            fatal_span(rdr, start_bpos, rdr.last_pos,
+            fatal_span(rdr, start_bpos, rdr.last_pos.get(),
                        ~"scan_exponent: bad fp literal");
         }
     } else { return None::<~str>; }
 }
 
-fn scan_digits(rdr: @mut StringReader, radix: uint) -> ~str {
+fn scan_digits(rdr: @StringReader, radix: uint) -> ~str {
     let mut rslt = ~"";
     loop {
-        let c = rdr.curr;
+        let c = rdr.curr.get();
         if c == '_' { bump(rdr); continue; }
         match char::to_digit(c, radix) {
           Some(_) => {
@@ -451,12 +463,12 @@ fn scan_digits(rdr: @mut StringReader, radix: uint) -> ~str {
     };
 }
 
-fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
+fn scan_number(c: char, rdr: @StringReader) -> token::Token {
     let mut num_str;
     let mut base = 10u;
     let mut c = c;
     let mut n = nextch(rdr);
-    let start_bpos = rdr.last_pos;
+    let start_bpos = rdr.last_pos.get();
     if c == '0' && n == 'x' {
         bump(rdr);
         bump(rdr);
@@ -471,7 +483,7 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
         base = 2u;
     }
     num_str = scan_digits(rdr, base);
-    c = rdr.curr;
+    c = rdr.curr.get();
     nextch(rdr);
     if c == 'u' || c == 'i' {
         enum Result { Signed(ast::int_ty), Unsigned(ast::uint_ty) }
@@ -481,7 +493,7 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
             else { Unsigned(ast::ty_u) }
         };
         bump(rdr);
-        c = rdr.curr;
+        c = rdr.curr.get();
         if c == '8' {
             bump(rdr);
             tp = if signed { Signed(ast::ty_i8) }
@@ -505,12 +517,12 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
                       else { Unsigned(ast::ty_u64) };
         }
         if num_str.len() == 0u {
-            fatal_span(rdr, start_bpos, rdr.last_pos,
+            fatal_span(rdr, start_bpos, rdr.last_pos.get(),
                        ~"no valid digits found for number");
         }
         let parsed = match from_str_radix::<u64>(num_str, base as uint) {
             Some(p) => p,
-            None => fatal_span(rdr, start_bpos, rdr.last_pos,
+            None => fatal_span(rdr, start_bpos, rdr.last_pos.get(),
                                ~"int literal is too large")
         };
 
@@ -520,7 +532,8 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
         }
     }
     let mut is_float = false;
-    if rdr.curr == '.' && !(ident_start(nextch(rdr)) || nextch(rdr) == '.') {
+    if rdr.curr.get() == '.' && !(ident_start(nextch(rdr)) || nextch(rdr) ==
+                                  '.') {
         is_float = true;
         bump(rdr);
         let dec_part = scan_digits(rdr, 10u);
@@ -529,11 +542,11 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
     }
     if is_float {
         match base {
-          16u => fatal_span(rdr, start_bpos, rdr.last_pos,
+          16u => fatal_span(rdr, start_bpos, rdr.last_pos.get(),
                             ~"hexadecimal float literal is not supported"),
-          8u => fatal_span(rdr, start_bpos, rdr.last_pos,
+          8u => fatal_span(rdr, start_bpos, rdr.last_pos.get(),
                            ~"octal float literal is not supported"),
-          2u => fatal_span(rdr, start_bpos, rdr.last_pos,
+          2u => fatal_span(rdr, start_bpos, rdr.last_pos.get(),
                            ~"binary float literal is not supported"),
           _ => ()
         }
@@ -546,9 +559,9 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
       None => ()
     }
 
-    if rdr.curr == 'f' {
+    if rdr.curr.get() == 'f' {
         bump(rdr);
-        c = rdr.curr;
+        c = rdr.curr.get();
         n = nextch(rdr);
         if c == '3' && n == '2' {
             bump(rdr);
@@ -564,19 +577,20 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
             32-bit or 64-bit float, it won't be noticed till the
             back-end.  */
         } else {
-            fatal_span(rdr, start_bpos, rdr.last_pos, ~"expected `f32` or `f64` suffix");
+            fatal_span(rdr, start_bpos, rdr.last_pos.get(),
+                       ~"expected `f32` or `f64` suffix");
         }
     }
     if is_float {
         return token::LIT_FLOAT_UNSUFFIXED(str_to_ident(num_str));
     } else {
         if num_str.len() == 0u {
-            fatal_span(rdr, start_bpos, rdr.last_pos,
+            fatal_span(rdr, start_bpos, rdr.last_pos.get(),
                        ~"no valid digits found for number");
         }
         let parsed = match from_str_radix::<u64>(num_str, base as uint) {
             Some(p) => p,
-            None => fatal_span(rdr, start_bpos, rdr.last_pos,
+            None => fatal_span(rdr, start_bpos, rdr.last_pos.get(),
                                ~"int literal is too large")
         };
 
@@ -585,14 +599,14 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
     }
 }
 
-fn scan_numeric_escape(rdr: @mut StringReader, n_hex_digits: uint) -> char {
+fn scan_numeric_escape(rdr: @StringReader, n_hex_digits: uint) -> char {
     let mut accum_int = 0;
     let mut i = n_hex_digits;
-    let start_bpos = rdr.last_pos;
+    let start_bpos = rdr.last_pos.get();
     while i != 0u {
-        let n = rdr.curr;
+        let n = rdr.curr.get();
         if !is_hex_digit(n) {
-            fatal_span_char(rdr, rdr.last_pos, rdr.pos,
+            fatal_span_char(rdr, rdr.last_pos.get(), rdr.pos.get(),
                             ~"illegal character in numeric character escape",
                             n);
         }
@@ -603,7 +617,7 @@ fn scan_numeric_escape(rdr: @mut StringReader, n_hex_digits: uint) -> char {
     }
     match char::from_u32(accum_int as u32) {
         Some(x) => x,
-        None => fatal_span(rdr, start_bpos, rdr.last_pos,
+        None => fatal_span(rdr, start_bpos, rdr.last_pos.get(),
                            ~"illegal numeric character escape")
     }
 }
@@ -626,14 +640,14 @@ fn ident_continue(c: char) -> bool {
 // return the next token from the string
 // EFFECT: advances the input past that token
 // EFFECT: updates the interner
-fn next_token_inner(rdr: @mut StringReader) -> token::Token {
-    let c = rdr.curr;
+fn next_token_inner(rdr: @StringReader) -> token::Token {
+    let c = rdr.curr.get();
     if ident_start(c) && nextch(rdr) != '"' && nextch(rdr) != '#' {
         // Note: r as in r" or r#" is part of a raw string literal,
         // not an identifier, and is handled further down.
 
-        let start = rdr.last_pos;
-        while ident_continue(rdr.curr) {
+        let start = rdr.last_pos.get();
+        while ident_continue(rdr.curr.get()) {
             bump(rdr);
         }
 
@@ -641,7 +655,7 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
             if string == "_" {
                 token::UNDERSCORE
             } else {
-                let is_mod_name = rdr.curr == ':' && nextch(rdr) == ':';
+                let is_mod_name = rdr.curr.get() == ':' && nextch(rdr) == ':';
 
                 // FIXME: perform NFKC normalization here. (Issue #2253)
                 token::IDENT(str_to_ident(string), is_mod_name)
@@ -651,9 +665,9 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
     if is_dec_digit(c) {
         return scan_number(c, rdr);
     }
-    fn binop(rdr: @mut StringReader, op: token::binop) -> token::Token {
+    fn binop(rdr: @StringReader, op: token::binop) -> token::Token {
         bump(rdr);
-        if rdr.curr == '=' {
+        if rdr.curr.get() == '=' {
             bump(rdr);
             return token::BINOPEQ(op);
         } else { return token::BINOP(op); }
@@ -669,9 +683,9 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
       ',' => { bump(rdr); return token::COMMA; }
       '.' => {
           bump(rdr);
-          return if rdr.curr == '.' {
+          return if rdr.curr.get() == '.' {
               bump(rdr);
-              if rdr.curr == '.' {
+              if rdr.curr.get() == '.' {
                   bump(rdr);
                   token::DOTDOTDOT
               } else {
@@ -692,7 +706,7 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
       '~' => { bump(rdr); return token::TILDE; }
       ':' => {
         bump(rdr);
-        if rdr.curr == ':' {
+        if rdr.curr.get() == ':' {
             bump(rdr);
             return token::MOD_SEP;
         } else { return token::COLON; }
@@ -707,10 +721,10 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
       // Multi-byte tokens.
       '=' => {
         bump(rdr);
-        if rdr.curr == '=' {
+        if rdr.curr.get() == '=' {
             bump(rdr);
             return token::EQEQ;
-        } else if rdr.curr == '>' {
+        } else if rdr.curr.get() == '>' {
             bump(rdr);
             return token::FAT_ARROW;
         } else {
@@ -719,19 +733,19 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
       }
       '!' => {
         bump(rdr);
-        if rdr.curr == '=' {
+        if rdr.curr.get() == '=' {
             bump(rdr);
             return token::NE;
         } else { return token::NOT; }
       }
       '<' => {
         bump(rdr);
-        match rdr.curr {
+        match rdr.curr.get() {
           '=' => { bump(rdr); return token::LE; }
           '<' => { return binop(rdr, token::SHL); }
           '-' => {
             bump(rdr);
-            match rdr.curr {
+            match rdr.curr.get() {
               '>' => { bump(rdr); return token::DARROW; }
               _ => { return token::LARROW; }
             }
@@ -741,7 +755,7 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
       }
       '>' => {
         bump(rdr);
-        match rdr.curr {
+        match rdr.curr.get() {
           '=' => { bump(rdr); return token::GE; }
           '>' => { return binop(rdr, token::SHR); }
           _ => { return token::GT; }
@@ -750,14 +764,14 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
       '\'' => {
         // Either a character constant 'a' OR a lifetime name 'abc
         bump(rdr);
-        let start = rdr.last_pos;
-        let mut c2 = rdr.curr;
+        let start = rdr.last_pos.get();
+        let mut c2 = rdr.curr.get();
         bump(rdr);
 
         // If the character is an ident start not followed by another single
         // quote, then this is a lifetime name:
-        if ident_start(c2) && rdr.curr != '\'' {
-            while ident_continue(rdr.curr) {
+        if ident_start(c2) && rdr.curr.get() != '\'' {
+            while ident_continue(rdr.curr.get()) {
                 bump(rdr);
             }
             return with_str_from(rdr, start, |lifetime_name| {
@@ -765,11 +779,12 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
                 let tok = &token::IDENT(ident, false);
 
                 if token::is_keyword(token::keywords::Self, tok) {
-                    fatal_span(rdr, start, rdr.last_pos,
+                    fatal_span(rdr, start, rdr.last_pos.get(),
                                ~"invalid lifetime name: 'self is no longer a special lifetime");
                 } else if token::is_any_keyword(tok) &&
                     !token::is_keyword(token::keywords::Static, tok) {
-                    fatal_span(rdr, start, rdr.last_pos, ~"invalid lifetime name");
+                    fatal_span(rdr, start, rdr.last_pos.get(),
+                               ~"invalid lifetime name");
                 } else {
                     token::LIFETIME(ident)
                 }
@@ -780,8 +795,8 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
         match c2 {
             '\\' => {
                 // '\X' for some X must be a character constant:
-                let escaped = rdr.curr;
-                let escaped_pos = rdr.last_pos;
+                let escaped = rdr.curr.get();
+                let escaped_pos = rdr.last_pos.get();
                 bump(rdr);
                 match escaped {
                     'n' => { c2 = '\n'; }
@@ -795,24 +810,24 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
                     'u' => { c2 = scan_numeric_escape(rdr, 4u); }
                     'U' => { c2 = scan_numeric_escape(rdr, 8u); }
                     c2 => {
-                        fatal_span_char(rdr, escaped_pos, rdr.last_pos,
+                        fatal_span_char(rdr, escaped_pos, rdr.last_pos.get(),
                                         ~"unknown character escape", c2);
                     }
                 }
             }
             '\t' | '\n' | '\r' | '\'' => {
-                fatal_span_char(rdr, start, rdr.last_pos,
+                fatal_span_char(rdr, start, rdr.last_pos.get(),
                                 ~"character constant must be escaped", c2);
             }
             _ => {}
         }
-        if rdr.curr != '\'' {
+        if rdr.curr.get() != '\'' {
             fatal_span_verbose(rdr,
                                // Byte offsetting here is okay because the
                                // character before position `start` is an
                                // ascii single quote.
                                start - BytePos(1),
-                               rdr.last_pos,
+                               rdr.last_pos.get(),
                                ~"unterminated character constant");
         }
         bump(rdr); // advance curr past token
@@ -820,20 +835,20 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
       }
       '"' => {
         let mut accum_str = ~"";
-        let start_bpos = rdr.last_pos;
+        let start_bpos = rdr.last_pos.get();
         bump(rdr);
-        while rdr.curr != '"' {
+        while rdr.curr.get() != '"' {
             if is_eof(rdr) {
-                fatal_span(rdr, start_bpos, rdr.last_pos,
+                fatal_span(rdr, start_bpos, rdr.last_pos.get(),
                            ~"unterminated double quote string");
             }
 
-            let ch = rdr.curr;
+            let ch = rdr.curr.get();
             bump(rdr);
             match ch {
               '\\' => {
-                let escaped = rdr.curr;
-                let escaped_pos = rdr.last_pos;
+                let escaped = rdr.curr.get();
+                let escaped_pos = rdr.last_pos.get();
                 bump(rdr);
                 match escaped {
                   'n' => accum_str.push_char('\n'),
@@ -854,7 +869,7 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
                     accum_str.push_char(scan_numeric_escape(rdr, 8u));
                   }
                   c2 => {
-                    fatal_span_char(rdr, escaped_pos, rdr.last_pos,
+                    fatal_span_char(rdr, escaped_pos, rdr.last_pos.get(),
                                     ~"unknown string escape", c2);
                   }
                 }
@@ -866,32 +881,32 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
         return token::LIT_STR(str_to_ident(accum_str));
       }
       'r' => {
-        let start_bpos = rdr.last_pos;
+        let start_bpos = rdr.last_pos.get();
         bump(rdr);
         let mut hash_count = 0u;
-        while rdr.curr == '#' {
+        while rdr.curr.get() == '#' {
             bump(rdr);
             hash_count += 1;
         }
-        if rdr.curr != '"' {
-            fatal_span_char(rdr, start_bpos, rdr.last_pos,
+        if rdr.curr.get() != '"' {
+            fatal_span_char(rdr, start_bpos, rdr.last_pos.get(),
                             ~"only `#` is allowed in raw string delimitation; \
                               found illegal character",
-                            rdr.curr);
+                            rdr.curr.get());
         }
         bump(rdr);
-        let content_start_bpos = rdr.last_pos;
+        let content_start_bpos = rdr.last_pos.get();
         let mut content_end_bpos;
         'outer: loop {
             if is_eof(rdr) {
-                fatal_span(rdr, start_bpos, rdr.last_pos,
+                fatal_span(rdr, start_bpos, rdr.last_pos.get(),
                            ~"unterminated raw string");
             }
-            if rdr.curr == '"' {
-                content_end_bpos = rdr.last_pos;
+            if rdr.curr.get() == '"' {
+                content_end_bpos = rdr.last_pos.get();
                 for _ in range(0, hash_count) {
                     bump(rdr);
-                    if rdr.curr != '#' {
+                    if rdr.curr.get() != '#' {
                         continue 'outer;
                     }
                 }
@@ -932,14 +947,14 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
       '^' => { return binop(rdr, token::CARET); }
       '%' => { return binop(rdr, token::PERCENT); }
       c => {
-          fatal_span_char(rdr, rdr.last_pos, rdr.pos,
+          fatal_span_char(rdr, rdr.last_pos.get(), rdr.pos.get(),
                           ~"unknown start of token", c);
       }
     }
 }
 
-fn consume_whitespace(rdr: @mut StringReader) {
-    while is_whitespace(rdr.curr) && !is_eof(rdr) { bump(rdr); }
+fn consume_whitespace(rdr: @StringReader) {
+    while is_whitespace(rdr.curr.get()) && !is_eof(rdr) { bump(rdr); }
 }
 
 #[cfg(test)]
@@ -953,7 +968,7 @@ mod test {
 
     // represents a testing reader (incl. both reader and interner)
     struct Env {
-        string_reader: @mut StringReader
+        string_reader: @StringReader
     }
 
     // open a string reader for the given string
@@ -978,7 +993,7 @@ mod test {
             sp:Span {lo:BytePos(21),hi:BytePos(23),expn_info: None}};
         assert_eq!(tok1,tok2);
         // the 'main' id is already read:
-        assert_eq!(string_reader.last_pos.clone(), BytePos(28));
+        assert_eq!(string_reader.last_pos.get().clone(), BytePos(28));
         // read another token:
         let tok3 = string_reader.next_token();
         let tok4 = TokenAndSpan{
@@ -986,7 +1001,7 @@ mod test {
             sp:Span {lo:BytePos(24),hi:BytePos(28),expn_info: None}};
         assert_eq!(tok3,tok4);
         // the lparen is already read:
-        assert_eq!(string_reader.last_pos.clone(), BytePos(29))
+        assert_eq!(string_reader.last_pos.get().clone(), BytePos(29))
     }
 
     // check that the given reader produces the desired stream
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 5a8444518aa..c20e7f4aaec 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -19,6 +19,7 @@ use parse::attr::parser_attr;
 use parse::lexer::reader;
 use parse::parser::Parser;
 
+use std::cell::RefCell;
 use std::io;
 use std::io::File;
 use std::str;
@@ -41,27 +42,27 @@ pub mod obsolete;
 // info about a parsing session.
 pub struct ParseSess {
     cm: @codemap::CodeMap, // better be the same as the one in the reader!
-    span_diagnostic: @mut SpanHandler, // better be the same as the one in the reader!
+    span_diagnostic: @SpanHandler, // better be the same as the one in the reader!
     /// Used to determine and report recursive mod inclusions
-    included_mod_stack: ~[Path],
+    included_mod_stack: RefCell<~[Path]>,
 }
 
-pub fn new_parse_sess(demitter: Option<@Emitter>) -> @mut ParseSess {
+pub fn new_parse_sess(demitter: Option<@Emitter>) -> @ParseSess {
     let cm = @CodeMap::new();
-    @mut ParseSess {
+    @ParseSess {
         cm: cm,
         span_diagnostic: mk_span_handler(mk_handler(demitter), cm),
-        included_mod_stack: ~[],
+        included_mod_stack: RefCell::new(~[]),
     }
 }
 
-pub fn new_parse_sess_special_handler(sh: @mut SpanHandler,
+pub fn new_parse_sess_special_handler(sh: @SpanHandler,
                                       cm: @codemap::CodeMap)
-                                   -> @mut ParseSess {
-    @mut ParseSess {
+                                      -> @ParseSess {
+    @ParseSess {
         cm: cm,
         span_diagnostic: sh,
-        included_mod_stack: ~[],
+        included_mod_stack: RefCell::new(~[]),
     }
 }
 
@@ -73,7 +74,7 @@ pub fn new_parse_sess_special_handler(sh: @mut SpanHandler,
 pub fn parse_crate_from_file(
     input: &Path,
     cfg: ast::CrateConfig,
-    sess: @mut ParseSess
+    sess: @ParseSess
 ) -> ast::Crate {
     new_parser_from_file(sess, /*bad*/ cfg.clone(), input).parse_crate_mod()
     // why is there no p.abort_if_errors here?
@@ -82,7 +83,7 @@ pub fn parse_crate_from_file(
 pub fn parse_crate_attrs_from_file(
     input: &Path,
     cfg: ast::CrateConfig,
-    sess: @mut ParseSess
+    sess: @ParseSess
 ) -> ~[ast::Attribute] {
     let mut parser = new_parser_from_file(sess, cfg, input);
     let (inner, _) = parser.parse_inner_attrs_and_next();
@@ -93,7 +94,7 @@ pub fn parse_crate_from_source_str(
     name: @str,
     source: @str,
     cfg: ast::CrateConfig,
-    sess: @mut ParseSess
+    sess: @ParseSess
 ) -> ast::Crate {
     let mut p = new_parser_from_source_str(sess,
                                            /*bad*/ cfg.clone(),
@@ -106,7 +107,7 @@ pub fn parse_crate_attrs_from_source_str(
     name: @str,
     source: @str,
     cfg: ast::CrateConfig,
-    sess: @mut ParseSess
+    sess: @ParseSess
 ) -> ~[ast::Attribute] {
     let mut p = new_parser_from_source_str(sess,
                                            /*bad*/ cfg.clone(),
@@ -120,7 +121,7 @@ pub fn parse_expr_from_source_str(
     name: @str,
     source: @str,
     cfg: ast::CrateConfig,
-    sess: @mut ParseSess
+    sess: @ParseSess
 ) -> @ast::Expr {
     let mut p = new_parser_from_source_str(sess, cfg, name, source);
     maybe_aborted(p.parse_expr(), p)
@@ -131,7 +132,7 @@ pub fn parse_item_from_source_str(
     source: @str,
     cfg: ast::CrateConfig,
     attrs: ~[ast::Attribute],
-    sess: @mut ParseSess
+    sess: @ParseSess
 ) -> Option<@ast::item> {
     let mut p = new_parser_from_source_str(sess, cfg, name, source);
     maybe_aborted(p.parse_item(attrs),p)
@@ -141,7 +142,7 @@ pub fn parse_meta_from_source_str(
     name: @str,
     source: @str,
     cfg: ast::CrateConfig,
-    sess: @mut ParseSess
+    sess: @ParseSess
 ) -> @ast::MetaItem {
     let mut p = new_parser_from_source_str(sess, cfg, name, source);
     maybe_aborted(p.parse_meta_item(),p)
@@ -152,7 +153,7 @@ pub fn parse_stmt_from_source_str(
     source: @str,
     cfg: ast::CrateConfig,
     attrs: ~[ast::Attribute],
-    sess: @mut ParseSess
+    sess: @ParseSess
 ) -> @ast::Stmt {
     let mut p = new_parser_from_source_str(
         sess,
@@ -167,7 +168,7 @@ pub fn parse_tts_from_source_str(
     name: @str,
     source: @str,
     cfg: ast::CrateConfig,
-    sess: @mut ParseSess
+    sess: @ParseSess
 ) -> ~[ast::token_tree] {
     let mut p = new_parser_from_source_str(
         sess,
@@ -191,7 +192,7 @@ pub fn parse_from_source_str<T>(
                              ss: codemap::FileSubstr,
                              source: @str,
                              cfg: ast::CrateConfig,
-                             sess: @mut ParseSess)
+                             sess: @ParseSess)
                              -> T {
     let mut p = new_parser_from_source_substr(sess, cfg, name, ss, source);
     let r = f(&mut p);
@@ -202,7 +203,7 @@ pub fn parse_from_source_str<T>(
 }
 
 // Create a new parser from a source string
-pub fn new_parser_from_source_str(sess: @mut ParseSess,
+pub fn new_parser_from_source_str(sess: @ParseSess,
                                   cfg: ast::CrateConfig,
                                   name: @str,
                                   source: @str)
@@ -212,7 +213,7 @@ pub fn new_parser_from_source_str(sess: @mut ParseSess,
 
 // Create a new parser from a source string where the origin
 // is specified as a substring of another file.
-pub fn new_parser_from_source_substr(sess: @mut ParseSess,
+pub fn new_parser_from_source_substr(sess: @ParseSess,
                                   cfg: ast::CrateConfig,
                                   name: @str,
                                   ss: codemap::FileSubstr,
@@ -224,7 +225,7 @@ pub fn new_parser_from_source_substr(sess: @mut ParseSess,
 /// Create a new parser, handling errors as appropriate
 /// if the file doesn't exist
 pub fn new_parser_from_file(
-    sess: @mut ParseSess,
+    sess: @ParseSess,
     cfg: ast::CrateConfig,
     path: &Path
 ) -> Parser {
@@ -235,7 +236,7 @@ pub fn new_parser_from_file(
 /// the file at the given path to the codemap, and return a parser.
 /// On an error, use the given span as the source of the problem.
 pub fn new_sub_parser_from_file(
-    sess: @mut ParseSess,
+    sess: @ParseSess,
     cfg: ast::CrateConfig,
     path: &Path,
     sp: Span
@@ -244,7 +245,7 @@ pub fn new_sub_parser_from_file(
 }
 
 /// Given a filemap and config, return a parser
-pub fn filemap_to_parser(sess: @mut ParseSess,
+pub fn filemap_to_parser(sess: @ParseSess,
                          filemap: @FileMap,
                          cfg: ast::CrateConfig) -> Parser {
     tts_to_parser(sess,filemap_to_tts(sess,filemap),cfg)
@@ -252,7 +253,7 @@ pub fn filemap_to_parser(sess: @mut ParseSess,
 
 // must preserve old name for now, because quote! from the *existing*
 // compiler expands into it
-pub fn new_parser_from_tts(sess: @mut ParseSess,
+pub fn new_parser_from_tts(sess: @ParseSess,
                      cfg: ast::CrateConfig,
                      tts: ~[ast::token_tree]) -> Parser {
     tts_to_parser(sess,tts,cfg)
@@ -263,7 +264,7 @@ pub fn new_parser_from_tts(sess: @mut ParseSess,
 
 /// Given a session and a path and an optional span (for error reporting),
 /// add the path to the session's codemap and return the new filemap.
-pub fn file_to_filemap(sess: @mut ParseSess, path: &Path, spanopt: Option<Span>)
+pub fn file_to_filemap(sess: @ParseSess, path: &Path, spanopt: Option<Span>)
     -> @FileMap {
     let err = |msg: &str| {
         match spanopt {
@@ -292,35 +293,35 @@ pub fn file_to_filemap(sess: @mut ParseSess, path: &Path, spanopt: Option<Span>)
 
 // given a session and a string, add the string to
 // the session's codemap and return the new filemap
-pub fn string_to_filemap(sess: @mut ParseSess, source: @str, path: @str)
+pub fn string_to_filemap(sess: @ParseSess, source: @str, path: @str)
     -> @FileMap {
     sess.cm.new_filemap(path, source)
 }
 
 // given a session and a string and a path and a FileSubStr, add
 // the string to the CodeMap and return the new FileMap
-pub fn substring_to_filemap(sess: @mut ParseSess, source: @str, path: @str,
+pub fn substring_to_filemap(sess: @ParseSess, source: @str, path: @str,
                            filesubstr: FileSubstr) -> @FileMap {
     sess.cm.new_filemap_w_substr(path,filesubstr,source)
 }
 
 // given a filemap, produce a sequence of token-trees
-pub fn filemap_to_tts(sess: @mut ParseSess, filemap: @FileMap)
+pub fn filemap_to_tts(sess: @ParseSess, filemap: @FileMap)
     -> ~[ast::token_tree] {
     // it appears to me that the cfg doesn't matter here... indeed,
     // parsing tt's probably shouldn't require a parser at all.
     let cfg = ~[];
     let srdr = lexer::new_string_reader(sess.span_diagnostic, filemap);
-    let mut p1 = Parser(sess, cfg, srdr as @mut reader);
+    let mut p1 = Parser(sess, cfg, srdr as @reader);
     p1.parse_all_token_trees()
 }
 
 // given tts and cfg, produce a parser
-pub fn tts_to_parser(sess: @mut ParseSess,
+pub fn tts_to_parser(sess: @ParseSess,
                      tts: ~[ast::token_tree],
                      cfg: ast::CrateConfig) -> Parser {
     let trdr = lexer::new_tt_reader(sess.span_diagnostic, None, tts);
-    Parser(sess, cfg, trdr as @mut reader)
+    Parser(sess, cfg, trdr as @reader)
 }
 
 // abort if necessary
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 2428710087f..40a2ef86e4f 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -29,8 +29,7 @@ use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex};
 use ast::{ExprLit, ExprLogLevel, ExprLoop, ExprMac};
 use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc, ExprRepeat};
 use ast::{ExprRet, ExprSelf, ExprStruct, ExprTup, ExprUnary};
-use ast::{ExprVec, ExprVstore, ExprVstoreMutBox};
-use ast::{ExprVstoreSlice, ExprVstoreBox};
+use ast::{ExprVec, ExprVstore, ExprVstoreSlice, ExprVstoreBox};
 use ast::{ExprVstoreMutSlice, ExprWhile, ExprForLoop, extern_fn, Field, fn_decl};
 use ast::{ExprVstoreUniq, Onceness, Once, Many};
 use ast::{foreign_item, foreign_item_static, foreign_item_fn, foreign_mod};
@@ -81,6 +80,7 @@ use parse::{new_sub_parser_from_file, ParseSess};
 use opt_vec;
 use opt_vec::OptVec;
 
+use std::cell::Cell;
 use std::hashmap::HashSet;
 use std::util;
 use std::vec;
@@ -286,8 +286,8 @@ struct ParsedItemsAndViewItems {
 
 /* ident is handled by common.rs */
 
-pub fn Parser(sess: @mut ParseSess, cfg: ast::CrateConfig, rdr: @mut reader)
-           -> Parser {
+pub fn Parser(sess: @ParseSess, cfg: ast::CrateConfig, rdr: @reader)
+              -> Parser {
     let tok0 = rdr.next_token();
     let interner = get_ident_interner();
     let span = tok0.sp;
@@ -324,7 +324,7 @@ pub fn Parser(sess: @mut ParseSess, cfg: ast::CrateConfig, rdr: @mut reader)
 }
 
 pub struct Parser {
-    sess: @mut ParseSess,
+    sess: @ParseSess,
     cfg: CrateConfig,
     // the current token:
     token: token::Token,
@@ -340,7 +340,7 @@ pub struct Parser {
     tokens_consumed: uint,
     restriction: restriction,
     quote_depth: uint, // not (yet) related to the quasiquoter
-    reader: @mut reader,
+    reader: @reader,
     interner: @token::ident_interner,
     /// The set of seen errors about obsolete syntax. Used to suppress
     /// extra detail when the same error is seen twice
@@ -1299,7 +1299,7 @@ impl Parser {
         if sigil == OwnedSigil {
             ty_uniq(self.parse_ty(false))
         } else {
-            ty_box(self.parse_mt())
+            ty_box(self.parse_ty(false))
         }
     }
 
@@ -2185,7 +2185,7 @@ impl Parser {
         // unification of matchers and token_trees would vastly improve
         // the interpolation of matchers
         maybe_whole!(self, nt_matchers);
-        let name_idx = @mut 0u;
+        let name_idx = @Cell::new(0u);
         match self.token {
             token::LBRACE | token::LPAREN | token::LBRACKET => {
                 let other_delimiter = token::flip_delimiter(&self.token);
@@ -2200,7 +2200,7 @@ impl Parser {
     // Otherwise, `$( ( )` would be a valid matcher, and `$( () )` would be
     // invalid. It's similar to common::parse_seq.
     pub fn parse_matcher_subseq_upto(&mut self,
-                                     name_idx: @mut uint,
+                                     name_idx: @Cell<uint>,
                                      ket: &token::Token)
                                      -> ~[matcher] {
         let mut ret_val = ~[];
@@ -2217,13 +2217,13 @@ impl Parser {
         return ret_val;
     }
 
-    pub fn parse_matcher(&mut self, name_idx: @mut uint) -> matcher {
+    pub fn parse_matcher(&mut self, name_idx: @Cell<uint>) -> matcher {
         let lo = self.span.lo;
 
         let m = if self.token == token::DOLLAR {
             self.bump();
             if self.token == token::LPAREN {
-                let name_idx_lo = *name_idx;
+                let name_idx_lo = name_idx.get();
                 self.bump();
                 let ms = self.parse_matcher_subseq_upto(name_idx,
                                                         &token::RPAREN);
@@ -2231,13 +2231,13 @@ impl Parser {
                     self.fatal("repetition body must be nonempty");
                 }
                 let (sep, zerok) = self.parse_sep_and_zerok();
-                match_seq(ms, sep, zerok, name_idx_lo, *name_idx)
+                match_seq(ms, sep, zerok, name_idx_lo, name_idx.get())
             } else {
                 let bound_to = self.parse_ident();
                 self.expect(&token::COLON);
                 let nt_name = self.parse_ident();
-                let m = match_nonterminal(bound_to, nt_name, *name_idx);
-                *name_idx += 1u;
+                let m = match_nonterminal(bound_to, nt_name, name_idx.get());
+                name_idx.set(name_idx.get() + 1u);
                 m
             }
         } else {
@@ -2299,17 +2299,14 @@ impl Parser {
           }
           token::AT => {
             self.bump();
-            let m = self.parse_mutability();
             let e = self.parse_prefix_expr();
             hi = e.span.hi;
             // HACK: turn @[...] into a @-evec
             ex = match e.node {
-              ExprVec(..) | ExprRepeat(..) if m == MutMutable =>
-                ExprVstore(e, ExprVstoreMutBox),
               ExprVec(..) |
               ExprLit(@codemap::Spanned { node: lit_str(..), span: _}) |
-              ExprRepeat(..) if m == MutImmutable => ExprVstore(e, ExprVstoreBox),
-              _ => self.mk_unary(UnBox(m), e)
+              ExprRepeat(..) => ExprVstore(e, ExprVstoreBox),
+              _ => self.mk_unary(UnBox, e)
             };
           }
           token::TILDE => {
@@ -4264,21 +4261,28 @@ impl Parser {
                               path: Path,
                               outer_attrs: ~[ast::Attribute],
                               id_sp: Span) -> (ast::item_, ~[ast::Attribute]) {
-        let maybe_i = self.sess.included_mod_stack.iter().position(|p| *p == path);
-        match maybe_i {
-            Some(i) => {
-                let stack = &self.sess.included_mod_stack;
-                let mut err = ~"circular modules: ";
-                for p in stack.slice(i, stack.len()).iter() {
-                    p.display().with_str(|s| err.push_str(s));
-                    err.push_str(" -> ");
+        {
+            let mut included_mod_stack = self.sess
+                                             .included_mod_stack
+                                             .borrow_mut();
+            let maybe_i = included_mod_stack.get()
+                                            .iter()
+                                            .position(|p| *p == path);
+            match maybe_i {
+                Some(i) => {
+                    let mut err = ~"circular modules: ";
+                    let len = included_mod_stack.get().len();
+                    for p in included_mod_stack.get().slice(i, len).iter() {
+                        p.display().with_str(|s| err.push_str(s));
+                        err.push_str(" -> ");
+                    }
+                    path.display().with_str(|s| err.push_str(s));
+                    self.span_fatal(id_sp, err);
                 }
-                path.display().with_str(|s| err.push_str(s));
-                self.span_fatal(id_sp, err);
+                None => ()
             }
-            None => ()
+            included_mod_stack.get().push(path.clone());
         }
-        self.sess.included_mod_stack.push(path.clone());
 
         let mut p0 =
             new_sub_parser_from_file(self.sess,
@@ -4289,7 +4293,12 @@ impl Parser {
         let mod_attrs = vec::append(outer_attrs, inner);
         let first_item_outer_attrs = next;
         let m0 = p0.parse_mod_items(token::EOF, first_item_outer_attrs);
-        self.sess.included_mod_stack.pop();
+        {
+            let mut included_mod_stack = self.sess
+                                             .included_mod_stack
+                                             .borrow_mut();
+            included_mod_stack.get().pop();
+        }
         return (ast::item_mod(m0), mod_attrs);
     }
 
diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs
index 5138115746e..a6239ab3806 100644
--- a/src/libsyntax/print/pp.rs
+++ b/src/libsyntax/print/pp.rs
@@ -148,7 +148,7 @@ pub struct print_stack_elt {
 
 pub static size_infinity: int = 0xffff;
 
-pub fn mk_printer(out: @mut io::Writer, linewidth: uint) -> @mut Printer {
+pub fn mk_printer(out: ~io::Writer, linewidth: uint) -> Printer {
     // Yes 3, it makes the ring buffers big enough to never
     // fall behind.
     let n: uint = 3 * linewidth;
@@ -156,7 +156,7 @@ pub fn mk_printer(out: @mut io::Writer, linewidth: uint) -> @mut Printer {
     let token: ~[token] = vec::from_elem(n, EOF);
     let size: ~[int] = vec::from_elem(n, 0);
     let scan_stack: ~[uint] = vec::from_elem(n, 0u);
-    @mut Printer {
+    Printer {
         out: out,
         buf_len: n,
         margin: linewidth as int,
@@ -171,7 +171,7 @@ pub fn mk_printer(out: @mut io::Writer, linewidth: uint) -> @mut Printer {
         scan_stack_empty: true,
         top: 0,
         bottom: 0,
-        print_stack: @mut ~[],
+        print_stack: ~[],
         pending_indentation: 0
     }
 }
@@ -255,7 +255,7 @@ pub fn mk_printer(out: @mut io::Writer, linewidth: uint) -> @mut Printer {
  * called 'print'.
  */
 pub struct Printer {
-    out: @mut io::Writer,
+    out: ~io::Writer,
     buf_len: uint,
     margin: int, // width of lines we're constrained to
     space: int, // number of spaces left on line
@@ -276,7 +276,7 @@ pub struct Printer {
     top: uint, // index of top of scan_stack
     bottom: uint, // index of bottom of scan_stack
     // stack of blocks-in-progress being flushed by print
-    print_stack: @mut ~[print_stack_elt],
+    print_stack: ~[print_stack_elt],
     // buffered indentation to avoid writing trailing whitespace
     pending_indentation: int,
 }
@@ -461,7 +461,7 @@ impl Printer {
         self.pending_indentation += amount;
     }
     pub fn get_top(&mut self) -> print_stack_elt {
-        let print_stack = &mut *self.print_stack;
+        let print_stack = &mut self.print_stack;
         let n = print_stack.len();
         if n != 0u {
             print_stack[n - 1u]
@@ -506,7 +506,7 @@ impl Printer {
           }
           END => {
             debug!("print END -> pop END");
-            let print_stack = &mut *self.print_stack;
+            let print_stack = &mut self.print_stack;
             assert!((print_stack.len() != 0u));
             print_stack.pop();
           }
@@ -557,47 +557,47 @@ impl Printer {
 // Convenience functions to talk to the printer.
 //
 // "raw box"
-pub fn rbox(p: @mut Printer, indent: uint, b: breaks) {
+pub fn rbox(p: &mut Printer, indent: uint, b: breaks) {
     p.pretty_print(BEGIN(begin_t {
         offset: indent as int,
         breaks: b
     }));
 }
 
-pub fn ibox(p: @mut Printer, indent: uint) { rbox(p, indent, inconsistent); }
+pub fn ibox(p: &mut Printer, indent: uint) { rbox(p, indent, inconsistent); }
 
-pub fn cbox(p: @mut Printer, indent: uint) { rbox(p, indent, consistent); }
+pub fn cbox(p: &mut Printer, indent: uint) { rbox(p, indent, consistent); }
 
-pub fn break_offset(p: @mut Printer, n: uint, off: int) {
+pub fn break_offset(p: &mut Printer, n: uint, off: int) {
     p.pretty_print(BREAK(break_t {
         offset: off,
         blank_space: n as int
     }));
 }
 
-pub fn end(p: @mut Printer) { p.pretty_print(END); }
+pub fn end(p: &mut Printer) { p.pretty_print(END); }
 
-pub fn eof(p: @mut Printer) { p.pretty_print(EOF); }
+pub fn eof(p: &mut Printer) { p.pretty_print(EOF); }
 
-pub fn word(p: @mut Printer, wrd: &str) {
+pub fn word(p: &mut Printer, wrd: &str) {
     p.pretty_print(STRING(/* bad */ wrd.to_managed(), wrd.len() as int));
 }
 
-pub fn huge_word(p: @mut Printer, wrd: &str) {
+pub fn huge_word(p: &mut Printer, wrd: &str) {
     p.pretty_print(STRING(/* bad */ wrd.to_managed(), size_infinity));
 }
 
-pub fn zero_word(p: @mut Printer, wrd: &str) {
+pub fn zero_word(p: &mut Printer, wrd: &str) {
     p.pretty_print(STRING(/* bad */ wrd.to_managed(), 0));
 }
 
-pub fn spaces(p: @mut Printer, n: uint) { break_offset(p, n, 0); }
+pub fn spaces(p: &mut Printer, n: uint) { break_offset(p, n, 0); }
 
-pub fn zerobreak(p: @mut Printer) { spaces(p, 0u); }
+pub fn zerobreak(p: &mut Printer) { spaces(p, 0u); }
 
-pub fn space(p: @mut Printer) { spaces(p, 1u); }
+pub fn space(p: &mut Printer) { spaces(p, 1u); }
 
-pub fn hardbreak(p: @mut Printer) { spaces(p, size_infinity as uint); }
+pub fn hardbreak(p: &mut Printer) { spaces(p, size_infinity as uint); }
 
 pub fn hardbreak_tok_offset(off: int) -> token {
     BREAK(break_t {offset: off, blank_space: size_infinity})
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 79ef9c2cbbe..9725d6e38de 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -27,18 +27,20 @@ use print::pp::{breaks, consistent, inconsistent, eof};
 use print::pp;
 use print::pprust;
 
+use std::cast;
+use std::cell::RefCell;
 use std::char;
 use std::str;
 use std::io;
 use std::io::Decorator;
 use std::io::mem::MemWriter;
 
-// The @ps is stored here to prevent recursive type.
-pub enum ann_node<'a> {
-    node_block(@ps, &'a ast::Block),
-    node_item(@ps, &'a ast::item),
-    node_expr(@ps, &'a ast::Expr),
-    node_pat(@ps, &'a ast::Pat),
+// The &mut ps is stored here to prevent recursive type.
+pub enum ann_node<'a,'b> {
+    node_block(&'b mut ps, &'a ast::Block),
+    node_item(&'b mut ps, &'a ast::item),
+    node_expr(&'b mut ps, &'a ast::Expr),
+    node_pat(&'b mut ps, &'a ast::Pat),
 }
 
 pub trait pp_ann {
@@ -66,45 +68,51 @@ pub struct CurrentCommentAndLiteral {
 }
 
 pub struct ps {
-    s: @mut pp::Printer,
+    s: pp::Printer,
     cm: Option<@CodeMap>,
     intr: @token::ident_interner,
     comments: Option<~[comments::cmnt]>,
     literals: Option<~[comments::lit]>,
-    cur_cmnt_and_lit: @mut CurrentCommentAndLiteral,
-    boxes: @mut ~[pp::breaks],
+    cur_cmnt_and_lit: CurrentCommentAndLiteral,
+    boxes: RefCell<~[pp::breaks]>,
     ann: @pp_ann
 }
 
-pub fn ibox(s: @ps, u: uint) {
-    s.boxes.push(pp::inconsistent);
-    pp::ibox(s.s, u);
+pub fn ibox(s: &mut ps, u: uint) {
+    {
+        let mut boxes = s.boxes.borrow_mut();
+        boxes.get().push(pp::inconsistent);
+    }
+    pp::ibox(&mut s.s, u);
 }
 
-pub fn end(s: @ps) {
-    s.boxes.pop();
-    pp::end(s.s);
+pub fn end(s: &mut ps) {
+    {
+        let mut boxes = s.boxes.borrow_mut();
+        boxes.get().pop();
+    }
+    pp::end(&mut s.s);
 }
 
-pub fn rust_printer(writer: @mut io::Writer, intr: @ident_interner) -> @ps {
+pub fn rust_printer(writer: ~io::Writer, intr: @ident_interner) -> ps {
     return rust_printer_annotated(writer, intr, @no_ann::new() as @pp_ann);
 }
 
-pub fn rust_printer_annotated(writer: @mut io::Writer,
+pub fn rust_printer_annotated(writer: ~io::Writer,
                               intr: @ident_interner,
                               ann: @pp_ann)
-                              -> @ps {
-    return @ps {
+                              -> ps {
+    return ps {
         s: pp::mk_printer(writer, default_columns),
         cm: None::<@CodeMap>,
         intr: intr,
         comments: None::<~[comments::cmnt]>,
         literals: None::<~[comments::lit]>,
-        cur_cmnt_and_lit: @mut CurrentCommentAndLiteral {
+        cur_cmnt_and_lit: CurrentCommentAndLiteral {
             cur_cmnt: 0,
             cur_lit: 0
         },
-        boxes: @mut ~[],
+        boxes: RefCell::new(~[]),
         ann: ann
     };
 }
@@ -118,11 +126,11 @@ pub static default_columns: uint = 78u;
 // copy forward.
 pub fn print_crate(cm: @CodeMap,
                    intr: @ident_interner,
-                   span_diagnostic: @mut diagnostic::SpanHandler,
+                   span_diagnostic: @diagnostic::SpanHandler,
                    crate: &ast::Crate,
                    filename: @str,
-                   input: @mut io::Reader,
-                   out: @mut io::Writer,
+                   input: &mut io::Reader,
+                   out: ~io::Writer,
                    ann: @pp_ann,
                    is_expanded: bool) {
     let (cmnts, lits) = comments::gather_comments_and_literals(
@@ -130,7 +138,7 @@ pub fn print_crate(cm: @CodeMap,
         filename,
         input
     );
-    let s = @ps {
+    let mut s = ps {
         s: pp::mk_printer(out, default_columns),
         cm: Some(cm),
         intr: intr,
@@ -143,20 +151,20 @@ pub fn print_crate(cm: @CodeMap,
         } else {
             Some(lits)
         },
-        cur_cmnt_and_lit: @mut CurrentCommentAndLiteral {
+        cur_cmnt_and_lit: CurrentCommentAndLiteral {
             cur_cmnt: 0,
             cur_lit: 0
         },
-        boxes: @mut ~[],
+        boxes: RefCell::new(~[]),
         ann: ann
     };
-    print_crate_(s, crate);
+    print_crate_(&mut s, crate);
 }
 
-pub fn print_crate_(s: @ps, crate: &ast::Crate) {
+pub fn print_crate_(s: &mut ps, crate: &ast::Crate) {
     print_mod(s, &crate.module, crate.attrs);
     print_remaining_comments(s);
-    eof(s.s);
+    eof(&mut s.s);
 }
 
 pub fn ty_to_str(ty: &ast::Ty, intr: @ident_interner) -> ~str {
@@ -203,26 +211,30 @@ pub fn path_to_str(p: &ast::Path, intr: @ident_interner) -> ~str {
 pub fn fun_to_str(decl: &ast::fn_decl, purity: ast::purity, name: ast::Ident,
                   opt_explicit_self: Option<ast::explicit_self_>,
                   generics: &ast::Generics, intr: @ident_interner) -> ~str {
-    let wr = @mut MemWriter::new();
-    let s = rust_printer(wr as @mut io::Writer, intr);
-    print_fn(s, decl, Some(purity), AbiSet::Rust(),
+    let wr = ~MemWriter::new();
+    let mut s = rust_printer(wr as ~io::Writer, intr);
+    print_fn(&mut s, decl, Some(purity), AbiSet::Rust(),
              name, generics, opt_explicit_self, ast::inherited);
-    end(s); // Close the head box
-    end(s); // Close the outer box
-    eof(s.s);
-    str::from_utf8_owned(wr.inner_ref().to_owned())
+    end(&mut s); // Close the head box
+    end(&mut s); // Close the outer box
+    eof(&mut s.s);
+    unsafe {
+        get_mem_writer(&mut s.s.out)
+    }
 }
 
 pub fn block_to_str(blk: &ast::Block, intr: @ident_interner) -> ~str {
-    let wr = @mut MemWriter::new();
-    let s = rust_printer(wr as @mut io::Writer, intr);
+    let wr = ~MemWriter::new();
+    let mut s = rust_printer(wr as ~io::Writer, intr);
     // containing cbox, will be closed by print-block at }
-    cbox(s, indent_unit);
+    cbox(&mut s, indent_unit);
     // head-ibox, will be closed by print-block after {
-    ibox(s, 0u);
-    print_block(s, blk);
-    eof(s.s);
-    str::from_utf8_owned(wr.inner_ref().to_owned())
+    ibox(&mut s, 0u);
+    print_block(&mut s, blk);
+    eof(&mut s.s);
+    unsafe {
+        get_mem_writer(&mut s.s.out)
+    }
 }
 
 pub fn meta_item_to_str(mi: &ast::MetaItem, intr: @ident_interner) -> ~str {
@@ -237,28 +249,34 @@ pub fn variant_to_str(var: &ast::variant, intr: @ident_interner) -> ~str {
     to_str(var, print_variant, intr)
 }
 
-pub fn cbox(s: @ps, u: uint) {
-    s.boxes.push(pp::consistent);
-    pp::cbox(s.s, u);
+pub fn cbox(s: &mut ps, u: uint) {
+    {
+        let mut boxes = s.boxes.borrow_mut();
+        boxes.get().push(pp::consistent);
+    }
+    pp::cbox(&mut s.s, u);
 }
 
 // "raw box"
-pub fn rbox(s: @ps, u: uint, b: pp::breaks) {
-    s.boxes.push(b);
-    pp::rbox(s.s, u, b);
+pub fn rbox(s: &mut ps, u: uint, b: pp::breaks) {
+    {
+        let mut boxes = s.boxes.borrow_mut();
+        boxes.get().push(b);
+    }
+    pp::rbox(&mut s.s, u, b);
 }
 
-pub fn nbsp(s: @ps) { word(s.s, " "); }
+pub fn nbsp(s: &mut ps) { word(&mut s.s, " "); }
 
-pub fn word_nbsp(s: @ps, w: &str) { word(s.s, w); nbsp(s); }
+pub fn word_nbsp(s: &mut ps, w: &str) { word(&mut s.s, w); nbsp(s); }
 
-pub fn word_space(s: @ps, w: &str) { word(s.s, w); space(s.s); }
+pub fn word_space(s: &mut ps, w: &str) { word(&mut s.s, w); space(&mut s.s); }
 
-pub fn popen(s: @ps) { word(s.s, "("); }
+pub fn popen(s: &mut ps) { word(&mut s.s, "("); }
 
-pub fn pclose(s: @ps) { word(s.s, ")"); }
+pub fn pclose(s: &mut ps) { word(&mut s.s, ")"); }
 
-pub fn head(s: @ps, w: &str) {
+pub fn head(s: &mut ps, w: &str) {
     // outer-box is consistent
     cbox(s, indent_unit);
     // head-box is inconsistent
@@ -269,49 +287,53 @@ pub fn head(s: @ps, w: &str) {
     }
 }
 
-pub fn bopen(s: @ps) {
-    word(s.s, "{");
+pub fn bopen(s: &mut ps) {
+    word(&mut s.s, "{");
     end(s); // close the head-box
 }
 
-pub fn bclose_(s: @ps, span: codemap::Span, indented: uint) {
+pub fn bclose_(s: &mut ps, span: codemap::Span, indented: uint) {
     bclose_maybe_open(s, span, indented, true);
 }
-pub fn bclose_maybe_open (s: @ps, span: codemap::Span, indented: uint,
+pub fn bclose_maybe_open (s: &mut ps, span: codemap::Span, indented: uint,
                           close_box: bool) {
     maybe_print_comment(s, span.hi);
     break_offset_if_not_bol(s, 1u, -(indented as int));
-    word(s.s, "}");
+    word(&mut s.s, "}");
     if close_box {
         end(s); // close the outer-box
     }
 }
-pub fn bclose(s: @ps, span: codemap::Span) { bclose_(s, span, indent_unit); }
+pub fn bclose(s: &mut ps, span: codemap::Span) { bclose_(s, span, indent_unit); }
 
-pub fn is_begin(s: @ps) -> bool {
+pub fn is_begin(s: &mut ps) -> bool {
     match s.s.last_token() { pp::BEGIN(_) => true, _ => false }
 }
 
-pub fn is_end(s: @ps) -> bool {
+pub fn is_end(s: &mut ps) -> bool {
     match s.s.last_token() { pp::END => true, _ => false }
 }
 
-pub fn is_bol(s: @ps) -> bool {
+pub fn is_bol(s: &mut ps) -> bool {
     return s.s.last_token().is_eof() || s.s.last_token().is_hardbreak_tok();
 }
 
-pub fn in_cbox(s: @ps) -> bool {
-    let boxes = &*s.boxes;
-    let len = boxes.len();
+pub fn in_cbox(s: &mut ps) -> bool {
+    let boxes = s.boxes.borrow();
+    let len = boxes.get().len();
     if len == 0u { return false; }
-    return boxes[len - 1u] == pp::consistent;
+    return boxes.get()[len - 1u] == pp::consistent;
 }
 
-pub fn hardbreak_if_not_bol(s: @ps) { if !is_bol(s) { hardbreak(s.s); } }
-pub fn space_if_not_bol(s: @ps) { if !is_bol(s) { space(s.s); } }
-pub fn break_offset_if_not_bol(s: @ps, n: uint, off: int) {
+pub fn hardbreak_if_not_bol(s: &mut ps) {
     if !is_bol(s) {
-        break_offset(s.s, n, off);
+        hardbreak(&mut s.s)
+    }
+}
+pub fn space_if_not_bol(s: &mut ps) { if !is_bol(s) { space(&mut s.s); } }
+pub fn break_offset_if_not_bol(s: &mut ps, n: uint, off: int) {
+    if !is_bol(s) {
+        break_offset(&mut s.s, n, off);
     } else {
         if off != 0 && s.s.last_token().is_hardbreak_tok() {
             // We do something pretty sketchy here: tuck the nonzero
@@ -324,15 +346,15 @@ pub fn break_offset_if_not_bol(s: @ps, n: uint, off: int) {
 
 // Synthesizes a comment that was not textually present in the original source
 // file.
-pub fn synth_comment(s: @ps, text: ~str) {
-    word(s.s, "/*");
-    space(s.s);
-    word(s.s, text);
-    space(s.s);
-    word(s.s, "*/");
+pub fn synth_comment(s: &mut ps, text: ~str) {
+    word(&mut s.s, "/*");
+    space(&mut s.s);
+    word(&mut s.s, text);
+    space(&mut s.s);
+    word(&mut s.s, "*/");
 }
 
-pub fn commasep<T>(s: @ps, b: breaks, elts: &[T], op: |@ps, &T|) {
+pub fn commasep<T>(s: &mut ps, b: breaks, elts: &[T], op: |&mut ps, &T|) {
     rbox(s, 0u, b);
     let mut first = true;
     for elt in elts.iter() {
@@ -344,10 +366,10 @@ pub fn commasep<T>(s: @ps, b: breaks, elts: &[T], op: |@ps, &T|) {
 
 
 pub fn commasep_cmnt<T>(
-                     s: @ps,
+                     s: &mut ps,
                      b: breaks,
                      elts: &[T],
-                     op: |@ps, &T|,
+                     op: |&mut ps, &T|,
                      get_span: |&T| -> codemap::Span) {
     rbox(s, 0u, b);
     let len = elts.len();
@@ -357,7 +379,7 @@ pub fn commasep_cmnt<T>(
         op(s, elt);
         i += 1u;
         if i < len {
-            word(s.s, ",");
+            word(&mut s.s, ",");
             maybe_print_trailing_comment(s, get_span(elt),
                                          Some(get_span(&elts[i]).hi));
             space_if_not_bol(s);
@@ -366,11 +388,11 @@ pub fn commasep_cmnt<T>(
     end(s);
 }
 
-pub fn commasep_exprs(s: @ps, b: breaks, exprs: &[@ast::Expr]) {
+pub fn commasep_exprs(s: &mut ps, b: breaks, exprs: &[@ast::Expr]) {
     commasep_cmnt(s, b, exprs, |p, &e| print_expr(p, e), |e| e.span);
 }
 
-pub fn print_mod(s: @ps, _mod: &ast::_mod, attrs: &[ast::Attribute]) {
+pub fn print_mod(s: &mut ps, _mod: &ast::_mod, attrs: &[ast::Attribute]) {
     print_inner_attributes(s, attrs);
     for vitem in _mod.view_items.iter() {
         print_view_item(s, vitem);
@@ -378,7 +400,7 @@ pub fn print_mod(s: @ps, _mod: &ast::_mod, attrs: &[ast::Attribute]) {
     for item in _mod.items.iter() { print_item(s, *item); }
 }
 
-pub fn print_foreign_mod(s: @ps, nmod: &ast::foreign_mod,
+pub fn print_foreign_mod(s: &mut ps, nmod: &ast::foreign_mod,
                          attrs: &[ast::Attribute]) {
     print_inner_attributes(s, attrs);
     for vitem in nmod.view_items.iter() {
@@ -387,29 +409,29 @@ pub fn print_foreign_mod(s: @ps, nmod: &ast::foreign_mod,
     for item in nmod.items.iter() { print_foreign_item(s, *item); }
 }
 
-pub fn print_opt_lifetime(s: @ps, lifetime: &Option<ast::Lifetime>) {
+pub fn print_opt_lifetime(s: &mut ps, lifetime: &Option<ast::Lifetime>) {
     for l in lifetime.iter() {
         print_lifetime(s, l);
         nbsp(s);
     }
 }
 
-pub fn print_type(s: @ps, ty: &ast::Ty) {
+pub fn print_type(s: &mut ps, ty: &ast::Ty) {
     maybe_print_comment(s, ty.span.lo);
     ibox(s, 0u);
     match ty.node {
-      ast::ty_nil => word(s.s, "()"),
-      ast::ty_bot => word(s.s, "!"),
-      ast::ty_box(ref mt) => { word(s.s, "@"); print_mt(s, mt); }
-      ast::ty_uniq(ty) => { word(s.s, "~"); print_type(s, ty); }
+      ast::ty_nil => word(&mut s.s, "()"),
+      ast::ty_bot => word(&mut s.s, "!"),
+      ast::ty_box(ty) => { word(&mut s.s, "@"); print_type(s, ty); }
+      ast::ty_uniq(ty) => { word(&mut s.s, "~"); print_type(s, ty); }
       ast::ty_vec(ty) => {
-        word(s.s, "[");
+        word(&mut s.s, "[");
         print_type(s, ty);
-        word(s.s, "]");
+        word(&mut s.s, "]");
       }
-      ast::ty_ptr(ref mt) => { word(s.s, "*"); print_mt(s, mt); }
+      ast::ty_ptr(ref mt) => { word(&mut s.s, "*"); print_mt(s, mt); }
       ast::ty_rptr(ref lifetime, ref mt) => {
-          word(s.s, "&");
+          word(&mut s.s, "&");
           print_opt_lifetime(s, lifetime);
           print_mt(s, mt);
       }
@@ -417,7 +439,7 @@ pub fn print_type(s: @ps, ty: &ast::Ty) {
         popen(s);
         commasep(s, inconsistent, *elts, print_type_ref);
         if elts.len() == 1 {
-            word(s.s, ",");
+            word(&mut s.s, ",");
         }
         pclose(s);
       }
@@ -441,16 +463,16 @@ pub fn print_type(s: @ps, ty: &ast::Ty) {
       }
       ast::ty_path(ref path, ref bounds, _) => print_bounded_path(s, path, bounds),
       ast::ty_fixed_length_vec(ty, v) => {
-        word(s.s, "[");
+        word(&mut s.s, "[");
         print_type(s, ty);
-        word(s.s, ", ..");
+        word(&mut s.s, ", ..");
         print_expr(s, v);
-        word(s.s, "]");
+        word(&mut s.s, "]");
       }
       ast::ty_typeof(e) => {
-          word(s.s, "typeof(");
+          word(&mut s.s, "typeof(");
           print_expr(s, e);
-          word(s.s, ")");
+          word(&mut s.s, ")");
       }
       ast::ty_infer => {
           fail!("print_type shouldn't see a ty_infer");
@@ -460,11 +482,11 @@ pub fn print_type(s: @ps, ty: &ast::Ty) {
     end(s);
 }
 
-pub fn print_type_ref(s: @ps, ty: &P<ast::Ty>) {
+pub fn print_type_ref(s: &mut ps, ty: &P<ast::Ty>) {
     print_type(s, *ty);
 }
 
-pub fn print_foreign_item(s: @ps, item: &ast::foreign_item) {
+pub fn print_foreign_item(s: &mut ps, item: &ast::foreign_item) {
     hardbreak_if_not_bol(s);
     maybe_print_comment(s, item.span.lo);
     print_outer_attributes(s, item.attrs);
@@ -473,7 +495,7 @@ pub fn print_foreign_item(s: @ps, item: &ast::foreign_item) {
         print_fn(s, decl, None, AbiSet::Rust(), item.ident, generics, None,
                  item.vis);
         end(s); // end head-ibox
-        word(s.s, ";");
+        word(&mut s.s, ";");
         end(s); // end the outer fn box
       }
       ast::foreign_item_static(t, m) => {
@@ -484,19 +506,21 @@ pub fn print_foreign_item(s: @ps, item: &ast::foreign_item) {
         print_ident(s, item.ident);
         word_space(s, ":");
         print_type(s, t);
-        word(s.s, ";");
+        word(&mut s.s, ";");
         end(s); // end the head-ibox
         end(s); // end the outer cbox
       }
     }
 }
 
-pub fn print_item(s: @ps, item: &ast::item) {
+pub fn print_item(s: &mut ps, item: &ast::item) {
     hardbreak_if_not_bol(s);
     maybe_print_comment(s, item.span.lo);
     print_outer_attributes(s, item.attrs);
-    let ann_node = node_item(s, item);
-    s.ann.pre(ann_node);
+    {
+        let ann_node = node_item(s, item);
+        s.ann.pre(ann_node);
+    }
     match item.node {
       ast::item_static(ty, m, expr) => {
         head(s, visibility_qualified(item.vis, "static"));
@@ -506,12 +530,12 @@ pub fn print_item(s: @ps, item: &ast::item) {
         print_ident(s, item.ident);
         word_space(s, ":");
         print_type(s, ty);
-        space(s.s);
+        space(&mut s.s);
         end(s); // end the head-ibox
 
         word_space(s, "=");
         print_expr(s, expr);
-        word(s.s, ";");
+        word(&mut s.s, ";");
         end(s); // end the outer cbox
 
       }
@@ -526,7 +550,7 @@ pub fn print_item(s: @ps, item: &ast::item) {
             None,
             item.vis
         );
-        word(s.s, " ");
+        word(&mut s.s, " ");
         print_block_with_attrs(s, body, item.attrs);
       }
       ast::item_mod(ref _mod) => {
@@ -552,10 +576,10 @@ pub fn print_item(s: @ps, item: &ast::item) {
         print_generics(s, params);
         end(s); // end the inner ibox
 
-        space(s.s);
+        space(&mut s.s);
         word_space(s, "=");
         print_type(s, ty);
-        word(s.s, ";");
+        word(&mut s.s, ";");
         end(s); // end the outer ibox
       }
       ast::item_enum(ref enum_definition, ref params) => {
@@ -577,13 +601,13 @@ pub fn print_item(s: @ps, item: &ast::item) {
         head(s, visibility_qualified(item.vis, "impl"));
         if generics.is_parameterized() {
             print_generics(s, generics);
-            space(s.s);
+            space(&mut s.s);
         }
 
         match opt_trait {
             &Some(ref t) => {
                 print_trait_ref(s, t);
-                space(s.s);
+                space(&mut s.s);
                 word_space(s, "for");
             }
             &None => ()
@@ -591,7 +615,7 @@ pub fn print_item(s: @ps, item: &ast::item) {
 
         print_type(s, ty);
 
-        space(s.s);
+        space(&mut s.s);
         bopen(s);
         print_inner_attributes(s, item.attrs);
         for meth in methods.iter() {
@@ -604,7 +628,7 @@ pub fn print_item(s: @ps, item: &ast::item) {
         print_ident(s, item.ident);
         print_generics(s, generics);
         if traits.len() != 0u {
-            word(s.s, ":");
+            word(&mut s.s, ":");
             for (i, trait_) in traits.iter().enumerate() {
                 nbsp(s);
                 if i != 0 {
@@ -613,7 +637,7 @@ pub fn print_item(s: @ps, item: &ast::item) {
                 print_path(s, &trait_.path, false);
             }
         }
-        word(s.s, " ");
+        word(&mut s.s, " ");
         bopen(s);
         for meth in methods.iter() {
             print_trait_method(s, meth);
@@ -625,7 +649,7 @@ pub fn print_item(s: @ps, item: &ast::item) {
                                    ..}) => {
         print_visibility(s, item.vis);
         print_path(s, pth, false);
-        word(s.s, "! ");
+        word(&mut s.s, "! ");
         print_ident(s, item.ident);
         cbox(s, indent_unit);
         popen(s);
@@ -634,24 +658,27 @@ pub fn print_item(s: @ps, item: &ast::item) {
         end(s);
       }
     }
-    s.ann.post(ann_node);
+    {
+        let ann_node = node_item(s, item);
+        s.ann.post(ann_node);
+    }
 }
 
-fn print_trait_ref(s: @ps, t: &ast::trait_ref) {
+fn print_trait_ref(s: &mut ps, t: &ast::trait_ref) {
     print_path(s, &t.path, false);
 }
 
-pub fn print_enum_def(s: @ps, enum_definition: &ast::enum_def,
+pub fn print_enum_def(s: &mut ps, enum_definition: &ast::enum_def,
                       generics: &ast::Generics, ident: ast::Ident,
                       span: codemap::Span, visibility: ast::visibility) {
     head(s, visibility_qualified(visibility, "enum"));
     print_ident(s, ident);
     print_generics(s, generics);
-    space(s.s);
+    space(&mut s.s);
     print_variants(s, enum_definition.variants, span);
 }
 
-pub fn print_variants(s: @ps,
+pub fn print_variants(s: &mut ps,
                       variants: &[P<ast::variant>],
                       span: codemap::Span) {
     bopen(s);
@@ -661,7 +688,7 @@ pub fn print_variants(s: @ps,
         print_outer_attributes(s, v.node.attrs);
         ibox(s, indent_unit);
         print_variant(s, v);
-        word(s.s, ",");
+        word(&mut s.s, ",");
         end(s);
         maybe_print_trailing_comment(s, v.span, None);
     }
@@ -683,7 +710,7 @@ pub fn visibility_qualified(vis: ast::visibility, s: &str) -> ~str {
     }
 }
 
-pub fn print_visibility(s: @ps, vis: ast::visibility) {
+pub fn print_visibility(s: &mut ps, vis: ast::visibility) {
     match vis {
         ast::private | ast::public =>
         word_nbsp(s, visibility_to_str(vis)),
@@ -691,7 +718,7 @@ pub fn print_visibility(s: @ps, vis: ast::visibility) {
     }
 }
 
-pub fn print_struct(s: @ps,
+pub fn print_struct(s: &mut ps,
                     struct_def: &ast::struct_def,
                     generics: &ast::Generics,
                     ident: ast::Ident,
@@ -712,7 +739,7 @@ pub fn print_struct(s: @ps,
             });
             pclose(s);
         }
-        word(s.s, ";");
+        word(&mut s.s, ";");
         end(s);
         end(s); // close the outer-box
     } else {
@@ -731,7 +758,7 @@ pub fn print_struct(s: @ps,
                     print_ident(s, ident);
                     word_nbsp(s, ":");
                     print_type(s, field.node.ty);
-                    word(s.s, ",");
+                    word(&mut s.s, ",");
                 }
             }
         }
@@ -747,48 +774,48 @@ pub fn print_struct(s: @ps,
 /// appropriate macro, transcribe back into the grammar we just parsed from,
 /// and then pretty-print the resulting AST nodes (so, e.g., we print
 /// expression arguments as expressions). It can be done! I think.
-pub fn print_tt(s: @ps, tt: &ast::token_tree) {
+pub fn print_tt(s: &mut ps, tt: &ast::token_tree) {
     match *tt {
       ast::tt_delim(ref tts) => print_tts(s, &(tts.as_slice())),
       ast::tt_tok(_, ref tk) => {
-          word(s.s, parse::token::to_str(s.intr, tk));
+          word(&mut s.s, parse::token::to_str(s.intr, tk));
       }
       ast::tt_seq(_, ref tts, ref sep, zerok) => {
-        word(s.s, "$(");
+        word(&mut s.s, "$(");
         for tt_elt in (*tts).iter() { print_tt(s, tt_elt); }
-        word(s.s, ")");
+        word(&mut s.s, ")");
         match (*sep) {
-          Some(ref tk) => word(s.s, parse::token::to_str(s.intr, tk)),
+          Some(ref tk) => word(&mut s.s, parse::token::to_str(s.intr, tk)),
           None => ()
         }
-        word(s.s, if zerok { "*" } else { "+" });
+        word(&mut s.s, if zerok { "*" } else { "+" });
       }
       ast::tt_nonterminal(_, name) => {
-        word(s.s, "$");
+        word(&mut s.s, "$");
         print_ident(s, name);
       }
     }
 }
 
-pub fn print_tts(s: @ps, tts: & &[ast::token_tree]) {
+pub fn print_tts(s: &mut ps, tts: & &[ast::token_tree]) {
     ibox(s, 0);
     for (i, tt) in tts.iter().enumerate() {
         if i != 0 {
-            space(s.s);
+            space(&mut s.s);
         }
         print_tt(s, tt);
     }
     end(s);
 }
 
-pub fn print_variant(s: @ps, v: &ast::variant) {
+pub fn print_variant(s: &mut ps, v: &ast::variant) {
     print_visibility(s, v.node.vis);
     match v.node.kind {
         ast::tuple_variant_kind(ref args) => {
             print_ident(s, v.node.name);
             if !args.is_empty() {
                 popen(s);
-                fn print_variant_arg(s: @ps, arg: &ast::variant_arg) {
+                fn print_variant_arg(s: &mut ps, arg: &ast::variant_arg) {
                     print_type(s, arg.ty);
                 }
                 commasep(s, consistent, *args, print_variant_arg);
@@ -803,7 +830,7 @@ pub fn print_variant(s: @ps, v: &ast::variant) {
     }
     match v.node.disr_expr {
       Some(d) => {
-        space(s.s);
+        space(&mut s.s);
         word_space(s, "=");
         print_expr(s, d);
       }
@@ -811,7 +838,7 @@ pub fn print_variant(s: @ps, v: &ast::variant) {
     }
 }
 
-pub fn print_ty_method(s: @ps, m: &ast::TypeMethod) {
+pub fn print_ty_method(s: &mut ps, m: &ast::TypeMethod) {
     hardbreak_if_not_bol(s);
     maybe_print_comment(s, m.span.lo);
     print_outer_attributes(s, m.attrs);
@@ -826,28 +853,28 @@ pub fn print_ty_method(s: @ps, m: &ast::TypeMethod) {
                 &None,
                 Some(&m.generics),
                 Some(m.explicit_self.node));
-    word(s.s, ";");
+    word(&mut s.s, ";");
 }
 
-pub fn print_trait_method(s: @ps, m: &ast::trait_method) {
+pub fn print_trait_method(s: &mut ps, m: &ast::trait_method) {
     match *m {
         required(ref ty_m) => print_ty_method(s, ty_m),
         provided(m) => print_method(s, m)
     }
 }
 
-pub fn print_method(s: @ps, meth: &ast::method) {
+pub fn print_method(s: &mut ps, meth: &ast::method) {
     hardbreak_if_not_bol(s);
     maybe_print_comment(s, meth.span.lo);
     print_outer_attributes(s, meth.attrs);
     print_fn(s, meth.decl, Some(meth.purity), AbiSet::Rust(),
              meth.ident, &meth.generics, Some(meth.explicit_self.node),
              meth.vis);
-    word(s.s, " ");
+    word(&mut s.s, " ");
     print_block_with_attrs(s, meth.body, meth.attrs);
 }
 
-pub fn print_outer_attributes(s: @ps, attrs: &[ast::Attribute]) {
+pub fn print_outer_attributes(s: &mut ps, attrs: &[ast::Attribute]) {
     let mut count = 0;
     for attr in attrs.iter() {
         match attr.node.style {
@@ -858,14 +885,14 @@ pub fn print_outer_attributes(s: @ps, attrs: &[ast::Attribute]) {
     if count > 0 { hardbreak_if_not_bol(s); }
 }
 
-pub fn print_inner_attributes(s: @ps, attrs: &[ast::Attribute]) {
+pub fn print_inner_attributes(s: &mut ps, attrs: &[ast::Attribute]) {
     let mut count = 0;
     for attr in attrs.iter() {
         match attr.node.style {
           ast::AttrInner => {
             print_attribute(s, attr);
             if !attr.node.is_sugared_doc {
-                word(s.s, ";");
+                word(&mut s.s, ";");
             }
             count += 1;
           }
@@ -875,21 +902,21 @@ pub fn print_inner_attributes(s: @ps, attrs: &[ast::Attribute]) {
     if count > 0 { hardbreak_if_not_bol(s); }
 }
 
-pub fn print_attribute(s: @ps, attr: &ast::Attribute) {
+pub fn print_attribute(s: &mut ps, attr: &ast::Attribute) {
     hardbreak_if_not_bol(s);
     maybe_print_comment(s, attr.span.lo);
     if attr.node.is_sugared_doc {
         let comment = attr.value_str().unwrap();
-        word(s.s, comment);
+        word(&mut s.s, comment);
     } else {
-        word(s.s, "#[");
+        word(&mut s.s, "#[");
         print_meta_item(s, attr.meta());
-        word(s.s, "]");
+        word(&mut s.s, "]");
     }
 }
 
 
-pub fn print_stmt(s: @ps, st: &ast::Stmt) {
+pub fn print_stmt(s: &mut ps, st: &ast::Stmt) {
     maybe_print_comment(s, st.span.lo);
     match st.node {
       ast::StmtDecl(decl, _) => {
@@ -902,33 +929,33 @@ pub fn print_stmt(s: @ps, st: &ast::Stmt) {
       ast::StmtSemi(expr, _) => {
         space_if_not_bol(s);
         print_expr(s, expr);
-        word(s.s, ";");
+        word(&mut s.s, ";");
       }
       ast::StmtMac(ref mac, semi) => {
         space_if_not_bol(s);
         print_mac(s, mac);
-        if semi { word(s.s, ";"); }
+        if semi { word(&mut s.s, ";"); }
       }
     }
-    if parse::classify::stmt_ends_with_semi(st) { word(s.s, ";"); }
+    if parse::classify::stmt_ends_with_semi(st) { word(&mut s.s, ";"); }
     maybe_print_trailing_comment(s, st.span, None);
 }
 
-pub fn print_block(s: @ps, blk: &ast::Block) {
+pub fn print_block(s: &mut ps, blk: &ast::Block) {
     print_possibly_embedded_block(s, blk, block_normal, indent_unit);
 }
 
-pub fn print_block_unclosed(s: @ps, blk: &ast::Block) {
+pub fn print_block_unclosed(s: &mut ps, blk: &ast::Block) {
     print_possibly_embedded_block_(s, blk, block_normal, indent_unit, &[],
                                  false);
 }
 
-pub fn print_block_unclosed_indent(s: @ps, blk: &ast::Block, indented: uint) {
+pub fn print_block_unclosed_indent(s: &mut ps, blk: &ast::Block, indented: uint) {
     print_possibly_embedded_block_(s, blk, block_normal, indented, &[],
                                    false);
 }
 
-pub fn print_block_with_attrs(s: @ps,
+pub fn print_block_with_attrs(s: &mut ps,
                               blk: &ast::Block,
                               attrs: &[ast::Attribute]) {
     print_possibly_embedded_block_(s, blk, block_normal, indent_unit, attrs,
@@ -937,7 +964,7 @@ pub fn print_block_with_attrs(s: @ps,
 
 pub enum embed_type { block_block_fn, block_normal, }
 
-pub fn print_possibly_embedded_block(s: @ps,
+pub fn print_possibly_embedded_block(s: &mut ps,
                                      blk: &ast::Block,
                                      embedded: embed_type,
                                      indented: uint) {
@@ -945,7 +972,7 @@ pub fn print_possibly_embedded_block(s: @ps,
         s, blk, embedded, indented, &[], true);
 }
 
-pub fn print_possibly_embedded_block_(s: @ps,
+pub fn print_possibly_embedded_block_(s: &mut ps,
                                       blk: &ast::Block,
                                       embedded: embed_type,
                                       indented: uint,
@@ -956,8 +983,10 @@ pub fn print_possibly_embedded_block_(s: @ps,
       ast::DefaultBlock => ()
     }
     maybe_print_comment(s, blk.span.lo);
-    let ann_node = node_block(s, blk);
-    s.ann.pre(ann_node);
+    {
+        let ann_node = node_block(s, blk);
+        s.ann.pre(ann_node);
+    }
     match embedded {
       block_block_fn => end(s),
       block_normal => bopen(s)
@@ -978,17 +1007,20 @@ pub fn print_possibly_embedded_block_(s: @ps,
       _ => ()
     }
     bclose_maybe_open(s, blk.span, indented, close_box);
-    s.ann.post(ann_node);
+    {
+        let ann_node = node_block(s, blk);
+        s.ann.post(ann_node);
+    }
 }
 
-pub fn print_if(s: @ps, test: &ast::Expr, blk: &ast::Block,
+pub fn print_if(s: &mut ps, test: &ast::Expr, blk: &ast::Block,
                 elseopt: Option<@ast::Expr>, chk: bool) {
     head(s, "if");
     if chk { word_nbsp(s, "check"); }
     print_expr(s, test);
-    space(s.s);
+    space(&mut s.s);
     print_block(s, blk);
-    fn do_else(s: @ps, els: Option<@ast::Expr>) {
+    fn do_else(s: &mut ps, els: Option<@ast::Expr>) {
         match els {
           Some(_else) => {
             match _else.node {
@@ -996,9 +1028,9 @@ pub fn print_if(s: @ps, test: &ast::Expr, blk: &ast::Block,
               ast::ExprIf(i, t, e) => {
                 cbox(s, indent_unit - 1u);
                 ibox(s, 0u);
-                word(s.s, " else if ");
+                word(&mut s.s, " else if ");
                 print_expr(s, i);
-                space(s.s);
+                space(&mut s.s);
                 print_block(s, t);
                 do_else(s, e);
               }
@@ -1006,7 +1038,7 @@ pub fn print_if(s: @ps, test: &ast::Expr, blk: &ast::Block,
               ast::ExprBlock(b) => {
                 cbox(s, indent_unit - 1u);
                 ibox(s, 0u);
-                word(s.s, " else ");
+                word(&mut s.s, " else ");
                 print_block(s, b);
               }
               // BLEAH, constraints would be great here
@@ -1021,12 +1053,12 @@ pub fn print_if(s: @ps, test: &ast::Expr, blk: &ast::Block,
     do_else(s, elseopt);
 }
 
-pub fn print_mac(s: @ps, m: &ast::mac) {
+pub fn print_mac(s: &mut ps, m: &ast::mac) {
     match m.node {
       // I think it's reasonable to hide the ctxt here:
       ast::mac_invoc_tt(ref pth, ref tts, _) => {
         print_path(s, pth, false);
-        word(s.s, "!");
+        word(&mut s.s, "!");
         popen(s);
         print_tts(s, &tts.as_slice());
         pclose(s);
@@ -1034,36 +1066,32 @@ pub fn print_mac(s: @ps, m: &ast::mac) {
     }
 }
 
-pub fn print_vstore(s: @ps, t: ast::Vstore) {
+pub fn print_vstore(s: &mut ps, t: ast::Vstore) {
     match t {
-        ast::VstoreFixed(Some(i)) => word(s.s, format!("{}", i)),
-        ast::VstoreFixed(None) => word(s.s, "_"),
-        ast::VstoreUniq => word(s.s, "~"),
-        ast::VstoreBox => word(s.s, "@"),
+        ast::VstoreFixed(Some(i)) => word(&mut s.s, format!("{}", i)),
+        ast::VstoreFixed(None) => word(&mut s.s, "_"),
+        ast::VstoreUniq => word(&mut s.s, "~"),
+        ast::VstoreBox => word(&mut s.s, "@"),
         ast::VstoreSlice(ref r) => {
-            word(s.s, "&");
+            word(&mut s.s, "&");
             print_opt_lifetime(s, r);
         }
     }
 }
 
-pub fn print_expr_vstore(s: @ps, t: ast::ExprVstore) {
+pub fn print_expr_vstore(s: &mut ps, t: ast::ExprVstore) {
     match t {
-      ast::ExprVstoreUniq => word(s.s, "~"),
-      ast::ExprVstoreBox => word(s.s, "@"),
-      ast::ExprVstoreMutBox => {
-        word(s.s, "@");
-        word(s.s, "mut");
-      }
-      ast::ExprVstoreSlice => word(s.s, "&"),
+      ast::ExprVstoreUniq => word(&mut s.s, "~"),
+      ast::ExprVstoreBox => word(&mut s.s, "@"),
+      ast::ExprVstoreSlice => word(&mut s.s, "&"),
       ast::ExprVstoreMutSlice => {
-        word(s.s, "&");
-        word(s.s, "mut");
+        word(&mut s.s, "&");
+        word(&mut s.s, "mut");
       }
     }
 }
 
-pub fn print_call_pre(s: @ps,
+pub fn print_call_pre(s: &mut ps,
                       sugar: ast::CallSugar,
                       base_args: &mut ~[@ast::Expr])
                    -> Option<@ast::Expr> {
@@ -1080,7 +1108,7 @@ pub fn print_call_pre(s: @ps,
     }
 }
 
-pub fn print_call_post(s: @ps,
+pub fn print_call_post(s: &mut ps,
                        sugar: ast::CallSugar,
                        blk: &Option<@ast::Expr>,
                        base_args: &mut ~[@ast::Expr]) {
@@ -1107,8 +1135,8 @@ pub fn print_call_post(s: @ps,
     }
 }
 
-pub fn print_expr(s: @ps, expr: &ast::Expr) {
-    fn print_field(s: @ps, field: &ast::Field) {
+pub fn print_expr(s: &mut ps, expr: &ast::Expr) {
+    fn print_field(s: &mut ps, field: &ast::Field) {
         ibox(s, indent_unit);
         print_ident(s, field.ident.node);
         word_space(s, ":");
@@ -1119,8 +1147,10 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
 
     maybe_print_comment(s, expr.span.lo);
     ibox(s, indent_unit);
-    let ann_node = node_expr(s, expr);
-    s.ann.pre(ann_node);
+    {
+        let ann_node = node_expr(s, expr);
+        s.ann.pre(ann_node);
+    }
     match expr.node {
         ast::ExprVstore(e, v) => {
             print_expr_vstore(s, v);
@@ -1128,53 +1158,53 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
         },
       ast::ExprVec(ref exprs, mutbl) => {
         ibox(s, indent_unit);
-        word(s.s, "[");
+        word(&mut s.s, "[");
         if mutbl == ast::MutMutable {
-            word(s.s, "mut");
+            word(&mut s.s, "mut");
             if exprs.len() > 0u { nbsp(s); }
         }
         commasep_exprs(s, inconsistent, *exprs);
-        word(s.s, "]");
+        word(&mut s.s, "]");
         end(s);
       }
 
       ast::ExprRepeat(element, count, mutbl) => {
         ibox(s, indent_unit);
-        word(s.s, "[");
+        word(&mut s.s, "[");
         if mutbl == ast::MutMutable {
-            word(s.s, "mut");
+            word(&mut s.s, "mut");
             nbsp(s);
         }
         print_expr(s, element);
-        word(s.s, ",");
-        word(s.s, "..");
+        word(&mut s.s, ",");
+        word(&mut s.s, "..");
         print_expr(s, count);
-        word(s.s, "]");
+        word(&mut s.s, "]");
         end(s);
       }
 
       ast::ExprStruct(ref path, ref fields, wth) => {
         print_path(s, path, true);
-        word(s.s, "{");
+        word(&mut s.s, "{");
         commasep_cmnt(s, consistent, (*fields), print_field, get_span);
         match wth {
             Some(expr) => {
                 ibox(s, indent_unit);
-                word(s.s, ",");
-                space(s.s);
-                word(s.s, "..");
+                word(&mut s.s, ",");
+                space(&mut s.s);
+                word(&mut s.s, "..");
                 print_expr(s, expr);
                 end(s);
             }
-            _ => (word(s.s, ","))
+            _ => (word(&mut s.s, ","))
         }
-        word(s.s, "}");
+        word(&mut s.s, "}");
       }
       ast::ExprTup(ref exprs) => {
         popen(s);
         commasep_exprs(s, inconsistent, *exprs);
         if exprs.len() == 1 {
-            word(s.s, ",");
+            word(&mut s.s, ",");
         }
         pclose(s);
       }
@@ -1188,31 +1218,31 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
         let mut base_args = (*args).clone();
         let blk = print_call_pre(s, sugar, &mut base_args);
         print_expr(s, func);
-        word(s.s, ".");
+        word(&mut s.s, ".");
         print_ident(s, ident);
         if tys.len() > 0u {
-            word(s.s, "::<");
+            word(&mut s.s, "::<");
             commasep(s, inconsistent, *tys, print_type_ref);
-            word(s.s, ">");
+            word(&mut s.s, ">");
         }
         print_call_post(s, sugar, &blk, &mut base_args);
       }
       ast::ExprBinary(_, op, lhs, rhs) => {
         print_expr(s, lhs);
-        space(s.s);
+        space(&mut s.s);
         word_space(s, ast_util::binop_to_str(op));
         print_expr(s, rhs);
       }
       ast::ExprUnary(_, op, expr) => {
-        word(s.s, ast_util::unop_to_str(op));
+        word(&mut s.s, ast_util::unop_to_str(op));
         print_expr(s, expr);
       }
       ast::ExprAddrOf(m, expr) => {
-        word(s.s, "&");
+        word(&mut s.s, "&");
         print_mutability(s, m);
         // Avoid `& &e` => `&&e`.
         match (m, &expr.node) {
-            (ast::MutImmutable, &ast::ExprAddrOf(..)) => space(s.s),
+            (ast::MutImmutable, &ast::ExprAddrOf(..)) => space(&mut s.s),
             _ => { }
         }
         print_expr(s, expr);
@@ -1220,7 +1250,7 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
       ast::ExprLit(lit) => print_literal(s, lit),
       ast::ExprCast(expr, ty) => {
         print_expr(s, expr);
-        space(s.s);
+        space(&mut s.s);
         word_space(s, "as");
         print_type(s, ty);
       }
@@ -1230,31 +1260,31 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
       ast::ExprWhile(test, blk) => {
         head(s, "while");
         print_expr(s, test);
-        space(s.s);
+        space(&mut s.s);
         print_block(s, blk);
       }
       ast::ExprForLoop(pat, iter, blk, opt_ident) => {
         for ident in opt_ident.iter() {
-            word(s.s, "'");
+            word(&mut s.s, "'");
             print_ident(s, *ident);
             word_space(s, ":");
         }
         head(s, "for");
         print_pat(s, pat);
-        space(s.s);
+        space(&mut s.s);
         word_space(s, "in");
         print_expr(s, iter);
-        space(s.s);
+        space(&mut s.s);
         print_block(s, blk);
       }
       ast::ExprLoop(blk, opt_ident) => {
         for ident in opt_ident.iter() {
-            word(s.s, "'");
+            word(&mut s.s, "'");
             print_ident(s, *ident);
             word_space(s, ":");
         }
         head(s, "loop");
-        space(s.s);
+        space(&mut s.s);
         print_block(s, blk);
       }
       ast::ExprMatch(expr, ref arms) => {
@@ -1262,26 +1292,26 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
         ibox(s, 4);
         word_nbsp(s, "match");
         print_expr(s, expr);
-        space(s.s);
+        space(&mut s.s);
         bopen(s);
         let len = arms.len();
         for (i, arm) in arms.iter().enumerate() {
-            space(s.s);
+            space(&mut s.s);
             cbox(s, indent_unit);
             ibox(s, 0u);
             let mut first = true;
             for p in arm.pats.iter() {
                 if first {
                     first = false;
-                } else { space(s.s); word_space(s, "|"); }
+                } else { space(&mut s.s); word_space(s, "|"); }
                 print_pat(s, *p);
             }
-            space(s.s);
+            space(&mut s.s);
             match arm.guard {
               Some(e) => {
                 word_space(s, "if");
                 print_expr(s, e);
-                space(s.s);
+                space(&mut s.s);
               }
               None => ()
             }
@@ -1309,7 +1339,7 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
                         }
                         if !expr_is_simple_block(expr)
                             && i < len - 1 {
-                            word(s.s, ",");
+                            word(&mut s.s, ",");
                         }
                         end(s); // close enclosing cbox
                     }
@@ -1329,7 +1359,7 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
         //
         // if !decl.inputs.is_empty() {
         print_fn_block_args(s, decl);
-        space(s.s);
+        space(&mut s.s);
         // }
         assert!(body.stmts.is_empty());
         assert!(body.expr.is_some());
@@ -1356,7 +1386,7 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
         //
         // if !decl.inputs.is_empty() {
         print_proc_args(s, decl);
-        space(s.s);
+        space(&mut s.s);
         // }
         assert!(body.stmts.is_empty());
         assert!(body.expr.is_some());
@@ -1388,70 +1418,70 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
       }
       ast::ExprAssign(lhs, rhs) => {
         print_expr(s, lhs);
-        space(s.s);
+        space(&mut s.s);
         word_space(s, "=");
         print_expr(s, rhs);
       }
       ast::ExprAssignOp(_, op, lhs, rhs) => {
         print_expr(s, lhs);
-        space(s.s);
-        word(s.s, ast_util::binop_to_str(op));
+        space(&mut s.s);
+        word(&mut s.s, ast_util::binop_to_str(op));
         word_space(s, "=");
         print_expr(s, rhs);
       }
       ast::ExprField(expr, id, ref tys) => {
         print_expr(s, expr);
-        word(s.s, ".");
+        word(&mut s.s, ".");
         print_ident(s, id);
         if tys.len() > 0u {
-            word(s.s, "::<");
+            word(&mut s.s, "::<");
             commasep(s, inconsistent, *tys, print_type_ref);
-            word(s.s, ">");
+            word(&mut s.s, ">");
         }
       }
       ast::ExprIndex(_, expr, index) => {
         print_expr(s, expr);
-        word(s.s, "[");
+        word(&mut s.s, "[");
         print_expr(s, index);
-        word(s.s, "]");
+        word(&mut s.s, "]");
       }
       ast::ExprPath(ref path) => print_path(s, path, true),
-      ast::ExprSelf => word(s.s, "self"),
+      ast::ExprSelf => word(&mut s.s, "self"),
       ast::ExprBreak(opt_ident) => {
-        word(s.s, "break");
-        space(s.s);
+        word(&mut s.s, "break");
+        space(&mut s.s);
         for ident in opt_ident.iter() {
-            word(s.s, "'");
+            word(&mut s.s, "'");
             print_name(s, *ident);
-            space(s.s);
+            space(&mut s.s);
         }
       }
       ast::ExprAgain(opt_ident) => {
-        word(s.s, "continue");
-        space(s.s);
+        word(&mut s.s, "continue");
+        space(&mut s.s);
         for ident in opt_ident.iter() {
-            word(s.s, "'");
+            word(&mut s.s, "'");
             print_name(s, *ident);
-            space(s.s)
+            space(&mut s.s)
         }
       }
       ast::ExprRet(result) => {
-        word(s.s, "return");
+        word(&mut s.s, "return");
         match result {
-          Some(expr) => { word(s.s, " "); print_expr(s, expr); }
+          Some(expr) => { word(&mut s.s, " "); print_expr(s, expr); }
           _ => ()
         }
       }
       ast::ExprLogLevel => {
-        word(s.s, "__log_level");
+        word(&mut s.s, "__log_level");
         popen(s);
         pclose(s);
       }
       ast::ExprInlineAsm(ref a) => {
         if a.volatile {
-            word(s.s, "__volatile__ asm!");
+            word(&mut s.s, "__volatile__ asm!");
         } else {
-            word(s.s, "asm!");
+            word(&mut s.s, "asm!");
         }
         popen(s);
         print_string(s, a.asm, a.asm_str_style);
@@ -1482,11 +1512,14 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
           pclose(s);
       }
     }
-    s.ann.post(ann_node);
+    {
+        let ann_node = node_expr(s, expr);
+        s.ann.post(ann_node);
+    }
     end(s);
 }
 
-pub fn print_local_decl(s: @ps, loc: &ast::Local) {
+pub fn print_local_decl(s: &mut ps, loc: &ast::Local) {
     print_pat(s, loc.pat);
     match loc.ty.node {
       ast::ty_infer => (),
@@ -1494,7 +1527,7 @@ pub fn print_local_decl(s: @ps, loc: &ast::Local) {
     }
 }
 
-pub fn print_decl(s: @ps, decl: &ast::Decl) {
+pub fn print_decl(s: &mut ps, decl: &ast::Decl) {
     maybe_print_comment(s, decl.span.lo);
     match decl.node {
       ast::DeclLocal(ref loc) => {
@@ -1502,7 +1535,7 @@ pub fn print_decl(s: @ps, decl: &ast::Decl) {
         ibox(s, indent_unit);
         word_nbsp(s, "let");
 
-        fn print_local(s: @ps, loc: &ast::Local) {
+        fn print_local(s: &mut ps, loc: &ast::Local) {
             ibox(s, indent_unit);
             print_local_decl(s, loc);
             end(s);
@@ -1523,28 +1556,28 @@ pub fn print_decl(s: @ps, decl: &ast::Decl) {
     }
 }
 
-pub fn print_ident(s: @ps, ident: ast::Ident) {
-    word(s.s, ident_to_str(&ident));
+pub fn print_ident(s: &mut ps, ident: ast::Ident) {
+    word(&mut s.s, ident_to_str(&ident));
 }
 
-pub fn print_name(s: @ps, name: ast::Name) {
-    word(s.s, interner_get(name));
+pub fn print_name(s: &mut ps, name: ast::Name) {
+    word(&mut s.s, interner_get(name));
 }
 
-pub fn print_for_decl(s: @ps, loc: &ast::Local, coll: &ast::Expr) {
+pub fn print_for_decl(s: &mut ps, loc: &ast::Local, coll: &ast::Expr) {
     print_local_decl(s, loc);
-    space(s.s);
+    space(&mut s.s);
     word_space(s, "in");
     print_expr(s, coll);
 }
 
-fn print_path_(s: @ps,
+fn print_path_(s: &mut ps,
                path: &ast::Path,
                colons_before_params: bool,
                opt_bounds: &Option<OptVec<ast::TyParamBound>>) {
     maybe_print_comment(s, path.span.lo);
     if path.global {
-        word(s.s, "::");
+        word(&mut s.s, "::");
     }
 
     let mut first = true;
@@ -1552,7 +1585,7 @@ fn print_path_(s: @ps,
         if first {
             first = false
         } else {
-            word(s.s, "::")
+            word(&mut s.s, "::")
         }
 
         print_ident(s, segment.identifier);
@@ -1567,9 +1600,9 @@ fn print_path_(s: @ps,
 
         if !segment.lifetimes.is_empty() || !segment.types.is_empty() {
             if colons_before_params {
-                word(s.s, "::")
+                word(&mut s.s, "::")
             }
-            word(s.s, "<");
+            word(&mut s.s, "<");
 
             let mut comma = false;
             for lifetime in segment.lifetimes.iter() {
@@ -1590,29 +1623,31 @@ fn print_path_(s: @ps,
                          print_type_ref);
             }
 
-            word(s.s, ">")
+            word(&mut s.s, ">")
         }
     }
 }
 
-pub fn print_path(s: @ps, path: &ast::Path, colons_before_params: bool) {
+pub fn print_path(s: &mut ps, path: &ast::Path, colons_before_params: bool) {
     print_path_(s, path, colons_before_params, &None)
 }
 
-pub fn print_bounded_path(s: @ps, path: &ast::Path,
+pub fn print_bounded_path(s: &mut ps, path: &ast::Path,
                           bounds: &Option<OptVec<ast::TyParamBound>>) {
     print_path_(s, path, false, bounds)
 }
 
-pub fn print_pat(s: @ps, pat: &ast::Pat) {
+pub fn print_pat(s: &mut ps, pat: &ast::Pat) {
     maybe_print_comment(s, pat.span.lo);
-    let ann_node = node_pat(s, pat);
-    s.ann.pre(ann_node);
+    {
+        let ann_node = node_pat(s, pat);
+        s.ann.pre(ann_node);
+    }
     /* Pat isn't normalized, but the beauty of it
      is that it doesn't matter */
     match pat.node {
-      ast::PatWild => word(s.s, "_"),
-      ast::PatWildMulti => word(s.s, ".."),
+      ast::PatWild => word(&mut s.s, "_"),
+      ast::PatWildMulti => word(&mut s.s, ".."),
       ast::PatIdent(binding_mode, ref path, sub) => {
           match binding_mode {
               ast::BindByRef(mutbl) => {
@@ -1627,7 +1662,7 @@ pub fn print_pat(s: @ps, pat: &ast::Pat) {
           print_path(s, path, true);
           match sub {
               Some(p) => {
-                  word(s.s, "@");
+                  word(&mut s.s, "@");
                   print_pat(s, p);
               }
               None => ()
@@ -1636,7 +1671,7 @@ pub fn print_pat(s: @ps, pat: &ast::Pat) {
       ast::PatEnum(ref path, ref args_) => {
         print_path(s, path, true);
         match *args_ {
-          None => word(s.s, "(..)"),
+          None => word(&mut s.s, "(..)"),
           Some(ref args) => {
             if !args.is_empty() {
               popen(s);
@@ -1649,8 +1684,8 @@ pub fn print_pat(s: @ps, pat: &ast::Pat) {
       }
       ast::PatStruct(ref path, ref fields, etc) => {
         print_path(s, path, true);
-        word(s.s, "{");
-        fn print_field(s: @ps, f: &ast::FieldPat) {
+        word(&mut s.s, "{");
+        fn print_field(s: &mut ps, f: &ast::FieldPat) {
             cbox(s, indent_unit);
             print_ident(s, f.ident);
             word_space(s, ":");
@@ -1663,39 +1698,39 @@ pub fn print_pat(s: @ps, pat: &ast::Pat) {
                       get_span);
         if etc {
             if fields.len() != 0u { word_space(s, ","); }
-            word(s.s, "..");
+            word(&mut s.s, "..");
         }
-        word(s.s, "}");
+        word(&mut s.s, "}");
       }
       ast::PatTup(ref elts) => {
         popen(s);
         commasep(s, inconsistent, *elts, |s, &p| print_pat(s, p));
         if elts.len() == 1 {
-            word(s.s, ",");
+            word(&mut s.s, ",");
         }
         pclose(s);
       }
       ast::PatBox(inner) => {
-          word(s.s, "@");
+          word(&mut s.s, "@");
           print_pat(s, inner);
       }
       ast::PatUniq(inner) => {
-          word(s.s, "~");
+          word(&mut s.s, "~");
           print_pat(s, inner);
       }
       ast::PatRegion(inner) => {
-          word(s.s, "&");
+          word(&mut s.s, "&");
           print_pat(s, inner);
       }
       ast::PatLit(e) => print_expr(s, e),
       ast::PatRange(begin, end) => {
         print_expr(s, begin);
-        space(s.s);
-        word(s.s, "..");
+        space(&mut s.s);
+        word(&mut s.s, "..");
         print_expr(s, end);
       }
       ast::PatVec(ref before, slice, ref after) => {
-        word(s.s, "[");
+        word(&mut s.s, "[");
         commasep(s, inconsistent, *before, |s, &p| print_pat(s, p));
         for &p in slice.iter() {
             if !before.is_empty() { word_space(s, ","); }
@@ -1703,16 +1738,19 @@ pub fn print_pat(s: @ps, pat: &ast::Pat) {
                 @ast::Pat { node: ast::PatWildMulti, .. } => {
                     // this case is handled by print_pat
                 }
-                _ => word(s.s, ".."),
+                _ => word(&mut s.s, ".."),
             }
             print_pat(s, p);
             if !after.is_empty() { word_space(s, ","); }
         }
         commasep(s, inconsistent, *after, |s, &p| print_pat(s, p));
-        word(s.s, "]");
+        word(&mut s.s, "]");
       }
     }
-    s.ann.post(ann_node);
+    {
+        let ann_node = node_pat(s, pat);
+        s.ann.post(ann_node);
+    }
 }
 
 pub fn explicit_self_to_str(explicit_self: &ast::explicit_self_, intr: @ident_interner) -> ~str {
@@ -1720,31 +1758,31 @@ pub fn explicit_self_to_str(explicit_self: &ast::explicit_self_, intr: @ident_in
 }
 
 // Returns whether it printed anything
-pub fn print_explicit_self(s: @ps, explicit_self: ast::explicit_self_) -> bool {
+pub fn print_explicit_self(s: &mut ps, explicit_self: ast::explicit_self_) -> bool {
     match explicit_self {
         ast::sty_static => { return false; }
         ast::sty_value(m) => {
             print_mutability(s, m);
-            word(s.s, "self");
+            word(&mut s.s, "self");
         }
         ast::sty_uniq(m) => {
             print_mutability(s, m);
-            word(s.s, "~self");
+            word(&mut s.s, "~self");
         }
         ast::sty_region(ref lt, m) => {
-            word(s.s, "&");
+            word(&mut s.s, "&");
             print_opt_lifetime(s, lt);
             print_mutability(s, m);
-            word(s.s, "self");
+            word(&mut s.s, "self");
         }
         ast::sty_box(m) => {
-            word(s.s, "@"); print_mutability(s, m); word(s.s, "self");
+            word(&mut s.s, "@"); print_mutability(s, m); word(&mut s.s, "self");
         }
     }
     return true;
 }
 
-pub fn print_fn(s: @ps,
+pub fn print_fn(s: &mut ps,
                 decl: &ast::fn_decl,
                 purity: Option<ast::purity>,
                 abis: AbiSet,
@@ -1760,7 +1798,7 @@ pub fn print_fn(s: @ps,
     print_fn_args_and_ret(s, decl, opt_explicit_self);
 }
 
-pub fn print_fn_args(s: @ps, decl: &ast::fn_decl,
+pub fn print_fn_args(s: &mut ps, decl: &ast::fn_decl,
                  opt_explicit_self: Option<ast::explicit_self_>) {
     // It is unfortunate to duplicate the commasep logic, but we want the
     // self type and the args all in the same box.
@@ -1778,12 +1816,12 @@ pub fn print_fn_args(s: @ps, decl: &ast::fn_decl,
     end(s);
 }
 
-pub fn print_fn_args_and_ret(s: @ps, decl: &ast::fn_decl,
+pub fn print_fn_args_and_ret(s: &mut ps, decl: &ast::fn_decl,
                              opt_explicit_self: Option<ast::explicit_self_>) {
     popen(s);
     print_fn_args(s, decl, opt_explicit_self);
     if decl.variadic {
-        word(s.s, ", ...");
+        word(&mut s.s, ", ...");
     }
     pclose(s);
 
@@ -1798,10 +1836,10 @@ pub fn print_fn_args_and_ret(s: @ps, decl: &ast::fn_decl,
     }
 }
 
-pub fn print_fn_block_args(s: @ps, decl: &ast::fn_decl) {
-    word(s.s, "|");
+pub fn print_fn_block_args(s: &mut ps, decl: &ast::fn_decl) {
+    word(&mut s.s, "|");
     print_fn_args(s, decl, None);
-    word(s.s, "|");
+    word(&mut s.s, "|");
 
     match decl.output.node {
         ast::ty_infer => {}
@@ -1815,11 +1853,11 @@ pub fn print_fn_block_args(s: @ps, decl: &ast::fn_decl) {
     maybe_print_comment(s, decl.output.span.lo);
 }
 
-pub fn print_proc_args(s: @ps, decl: &ast::fn_decl) {
-    word(s.s, "proc");
-    word(s.s, "(");
+pub fn print_proc_args(s: &mut ps, decl: &ast::fn_decl) {
+    word(&mut s.s, "proc");
+    word(&mut s.s, "(");
     print_fn_args(s, decl, None);
-    word(s.s, ")");
+    word(&mut s.s, ")");
 
     match decl.output.node {
         ast::ty_infer => {}
@@ -1833,10 +1871,10 @@ pub fn print_proc_args(s: @ps, decl: &ast::fn_decl) {
     maybe_print_comment(s, decl.output.span.lo);
 }
 
-pub fn print_bounds(s: @ps, bounds: &OptVec<ast::TyParamBound>,
+pub fn print_bounds(s: &mut ps, bounds: &OptVec<ast::TyParamBound>,
                     print_colon_anyway: bool) {
     if !bounds.is_empty() {
-        word(s.s, ":");
+        word(&mut s.s, ":");
         let mut first = true;
         for bound in bounds.iter() {
             nbsp(s);
@@ -1848,24 +1886,24 @@ pub fn print_bounds(s: @ps, bounds: &OptVec<ast::TyParamBound>,
 
             match *bound {
                 TraitTyParamBound(ref tref) => print_trait_ref(s, tref),
-                RegionTyParamBound => word(s.s, "'static"),
+                RegionTyParamBound => word(&mut s.s, "'static"),
             }
         }
     } else if print_colon_anyway {
-        word(s.s, ":");
+        word(&mut s.s, ":");
     }
 }
 
-pub fn print_lifetime(s: @ps, lifetime: &ast::Lifetime) {
-    word(s.s, "'");
+pub fn print_lifetime(s: &mut ps, lifetime: &ast::Lifetime) {
+    word(&mut s.s, "'");
     print_ident(s, lifetime.ident);
 }
 
-pub fn print_generics(s: @ps, generics: &ast::Generics) {
+pub fn print_generics(s: &mut ps, generics: &ast::Generics) {
     let total = generics.lifetimes.len() + generics.ty_params.len();
     if total > 0 {
-        word(s.s, "<");
-        fn print_item(s: @ps, generics: &ast::Generics, idx: uint) {
+        word(&mut s.s, "<");
+        fn print_item(s: &mut ps, generics: &ast::Generics, idx: uint) {
             if idx < generics.lifetimes.len() {
                 let lifetime = generics.lifetimes.get(idx);
                 print_lifetime(s, lifetime);
@@ -1884,21 +1922,21 @@ pub fn print_generics(s: @ps, generics: &ast::Generics) {
 
         commasep(s, inconsistent, ints,
                  |s, &i| print_item(s, generics, i));
-        word(s.s, ">");
+        word(&mut s.s, ">");
     }
 }
 
-pub fn print_meta_item(s: @ps, item: &ast::MetaItem) {
+pub fn print_meta_item(s: &mut ps, item: &ast::MetaItem) {
     ibox(s, indent_unit);
     match item.node {
-      ast::MetaWord(name) => word(s.s, name),
+      ast::MetaWord(name) => word(&mut s.s, name),
       ast::MetaNameValue(name, value) => {
         word_space(s, name);
         word_space(s, "=");
         print_literal(s, &value);
       }
       ast::MetaList(name, ref items) => {
-        word(s.s, name);
+        word(&mut s.s, name);
         popen(s);
         commasep(s,
                  consistent,
@@ -1910,13 +1948,13 @@ pub fn print_meta_item(s: @ps, item: &ast::MetaItem) {
     end(s);
 }
 
-pub fn print_view_path(s: @ps, vp: &ast::view_path) {
+pub fn print_view_path(s: &mut ps, vp: &ast::view_path) {
     match vp.node {
       ast::view_path_simple(ident, ref path, _) => {
         // FIXME(#6993) can't compare identifiers directly here
         if path.segments.last().identifier.name != ident.name {
             print_ident(s, ident);
-            space(s.s);
+            space(&mut s.s);
             word_space(s, "=");
         }
         print_path(s, path, false);
@@ -1924,29 +1962,29 @@ pub fn print_view_path(s: @ps, vp: &ast::view_path) {
 
       ast::view_path_glob(ref path, _) => {
         print_path(s, path, false);
-        word(s.s, "::*");
+        word(&mut s.s, "::*");
       }
 
       ast::view_path_list(ref path, ref idents, _) => {
         if path.segments.is_empty() {
-            word(s.s, "{");
+            word(&mut s.s, "{");
         } else {
             print_path(s, path, false);
-            word(s.s, "::{");
+            word(&mut s.s, "::{");
         }
         commasep(s, inconsistent, (*idents), |s, w| {
             print_ident(s, w.node.name);
         });
-        word(s.s, "}");
+        word(&mut s.s, "}");
       }
     }
 }
 
-pub fn print_view_paths(s: @ps, vps: &[@ast::view_path]) {
+pub fn print_view_paths(s: &mut ps, vps: &[@ast::view_path]) {
     commasep(s, inconsistent, vps, |p, &vp| print_view_path(p, vp));
 }
 
-pub fn print_view_item(s: @ps, item: &ast::view_item) {
+pub fn print_view_item(s: &mut ps, item: &ast::view_item) {
     hardbreak_if_not_bol(s);
     maybe_print_comment(s, item.span.lo);
     print_outer_attributes(s, item.attrs);
@@ -1956,9 +1994,9 @@ pub fn print_view_item(s: @ps, item: &ast::view_item) {
             head(s, "extern mod");
             print_ident(s, id);
             for &(ref p, style) in optional_path.iter() {
-                space(s.s);
-                word(s.s, "=");
-                space(s.s);
+                space(&mut s.s);
+                word(&mut s.s, "=");
+                space(&mut s.s);
                 print_string(s, *p, style);
             }
         }
@@ -1968,24 +2006,24 @@ pub fn print_view_item(s: @ps, item: &ast::view_item) {
             print_view_paths(s, *vps);
         }
     }
-    word(s.s, ";");
+    word(&mut s.s, ";");
     end(s); // end inner head-block
     end(s); // end outer head-block
 }
 
-pub fn print_mutability(s: @ps, mutbl: ast::Mutability) {
+pub fn print_mutability(s: &mut ps, mutbl: ast::Mutability) {
     match mutbl {
       ast::MutMutable => word_nbsp(s, "mut"),
       ast::MutImmutable => {/* nothing */ }
     }
 }
 
-pub fn print_mt(s: @ps, mt: &ast::mt) {
+pub fn print_mt(s: &mut ps, mt: &ast::mt) {
     print_mutability(s, mt.mutbl);
     print_type(s, mt.ty);
 }
 
-pub fn print_arg(s: @ps, input: &ast::arg) {
+pub fn print_arg(s: &mut ps, input: &ast::arg) {
     ibox(s, indent_unit);
     match input.ty.node {
       ast::ty_infer => print_pat(s, input.pat),
@@ -1999,8 +2037,8 @@ pub fn print_arg(s: @ps, input: &ast::arg) {
             }
             _ => {
                 print_pat(s, input.pat);
-                word(s.s, ":");
-                space(s.s);
+                word(&mut s.s, ":");
+                space(&mut s.s);
             }
         }
         print_type(s, input.ty);
@@ -2009,7 +2047,7 @@ pub fn print_arg(s: @ps, input: &ast::arg) {
     end(s);
 }
 
-pub fn print_ty_fn(s: @ps,
+pub fn print_ty_fn(s: &mut ps,
                    opt_abis: Option<AbiSet>,
                    opt_sigil: Option<ast::Sigil>,
                    opt_region: &Option<ast::Lifetime>,
@@ -2025,7 +2063,7 @@ pub fn print_ty_fn(s: @ps,
     // Duplicates the logic in `print_fn_header_info()`.  This is because that
     // function prints the sigil in the wrong place.  That should be fixed.
     if opt_sigil == Some(ast::OwnedSigil) && onceness == ast::Once {
-        word(s.s, "proc");
+        word(&mut s.s, "proc");
     } else if opt_sigil == Some(ast::BorrowedSigil) {
         print_extern_opt_abis(s, opt_abis);
         for lifetime in opt_region.iter() {
@@ -2039,20 +2077,20 @@ pub fn print_ty_fn(s: @ps,
         print_opt_lifetime(s, opt_region);
         print_purity(s, purity);
         print_onceness(s, onceness);
-        word(s.s, "fn");
+        word(&mut s.s, "fn");
     }
 
-    match id { Some(id) => { word(s.s, " "); print_ident(s, id); } _ => () }
+    match id { Some(id) => { word(&mut s.s, " "); print_ident(s, id); } _ => () }
 
     if opt_sigil != Some(ast::BorrowedSigil) {
         opt_bounds.as_ref().map(|bounds| print_bounds(s, bounds, true));
     }
 
     match generics { Some(g) => print_generics(s, g), _ => () }
-    zerobreak(s.s);
+    zerobreak(&mut s.s);
 
     if opt_sigil == Some(ast::BorrowedSigil) {
-        word(s.s, "|");
+        word(&mut s.s, "|");
     } else {
         popen(s);
     }
@@ -2071,12 +2109,12 @@ pub fn print_ty_fn(s: @ps,
     end(s);
 
     if opt_sigil == Some(ast::BorrowedSigil) {
-        word(s.s, "|");
+        word(&mut s.s, "|");
 
         opt_bounds.as_ref().map(|bounds| print_bounds(s, bounds, true));
     } else {
         if decl.variadic {
-            word(s.s, ", ...");
+            word(&mut s.s, ", ...");
         }
         pclose(s);
     }
@@ -2098,7 +2136,7 @@ pub fn print_ty_fn(s: @ps,
     end(s);
 }
 
-pub fn maybe_print_trailing_comment(s: @ps, span: codemap::Span,
+pub fn maybe_print_trailing_comment(s: &mut ps, span: codemap::Span,
                                     next_pos: Option<BytePos>) {
     let cm;
     match s.cm { Some(ccm) => cm = ccm, _ => return }
@@ -2119,10 +2157,10 @@ pub fn maybe_print_trailing_comment(s: @ps, span: codemap::Span,
     }
 }
 
-pub fn print_remaining_comments(s: @ps) {
+pub fn print_remaining_comments(s: &mut ps) {
     // If there aren't any remaining comments, then we need to manually
     // make sure there is a line break at the end.
-    if next_comment(s).is_none() { hardbreak(s.s); }
+    if next_comment(s).is_none() { hardbreak(&mut s.s); }
     loop {
         match next_comment(s) {
           Some(ref cmnt) => {
@@ -2134,11 +2172,11 @@ pub fn print_remaining_comments(s: @ps) {
     }
 }
 
-pub fn print_literal(s: @ps, lit: &ast::lit) {
+pub fn print_literal(s: &mut ps, lit: &ast::lit) {
     maybe_print_comment(s, lit.span.lo);
     match next_lit(s, lit.span.lo) {
       Some(ref ltrl) => {
-        word(s.s, (*ltrl).lit);
+        word(&mut s.s, (*ltrl).lit);
         return;
       }
       _ => ()
@@ -2149,45 +2187,45 @@ pub fn print_literal(s: @ps, lit: &ast::lit) {
           let mut res = ~"'";
           char::from_u32(ch).unwrap().escape_default(|c| res.push_char(c));
           res.push_char('\'');
-          word(s.s, res);
+          word(&mut s.s, res);
       }
       ast::lit_int(i, t) => {
         if i < 0_i64 {
-            word(s.s,
+            word(&mut s.s,
                  ~"-" + (-i as u64).to_str_radix(10u)
                  + ast_util::int_ty_to_str(t));
         } else {
-            word(s.s,
+            word(&mut s.s,
                  (i as u64).to_str_radix(10u)
                  + ast_util::int_ty_to_str(t));
         }
       }
       ast::lit_uint(u, t) => {
-        word(s.s,
+        word(&mut s.s,
              u.to_str_radix(10u)
              + ast_util::uint_ty_to_str(t));
       }
       ast::lit_int_unsuffixed(i) => {
         if i < 0_i64 {
-            word(s.s, ~"-" + (-i as u64).to_str_radix(10u));
+            word(&mut s.s, ~"-" + (-i as u64).to_str_radix(10u));
         } else {
-            word(s.s, (i as u64).to_str_radix(10u));
+            word(&mut s.s, (i as u64).to_str_radix(10u));
         }
       }
       ast::lit_float(f, t) => {
-        word(s.s, f.to_owned() + ast_util::float_ty_to_str(t));
+        word(&mut s.s, f.to_owned() + ast_util::float_ty_to_str(t));
       }
-      ast::lit_float_unsuffixed(f) => word(s.s, f),
-      ast::lit_nil => word(s.s, "()"),
+      ast::lit_float_unsuffixed(f) => word(&mut s.s, f),
+      ast::lit_nil => word(&mut s.s, "()"),
       ast::lit_bool(val) => {
-        if val { word(s.s, "true"); } else { word(s.s, "false"); }
+        if val { word(&mut s.s, "true"); } else { word(&mut s.s, "false"); }
       }
       ast::lit_binary(arr) => {
         ibox(s, indent_unit);
-        word(s.s, "[");
-        commasep_cmnt(s, inconsistent, arr, |s, u| word(s.s, format!("{}", *u)),
+        word(&mut s.s, "[");
+        commasep_cmnt(s, inconsistent, arr, |s, u| word(&mut s.s, format!("{}", *u)),
                       |_| lit.span);
-        word(s.s, "]");
+        word(&mut s.s, "]");
         end(s);
       }
     }
@@ -2197,7 +2235,7 @@ pub fn lit_to_str(l: &ast::lit) -> ~str {
     return to_str(l, print_literal, parse::token::mk_fake_ident_interner());
 }
 
-pub fn next_lit(s: @ps, pos: BytePos) -> Option<comments::lit> {
+pub fn next_lit(s: &mut ps, pos: BytePos) -> Option<comments::lit> {
     match s.literals {
       Some(ref lits) => {
         while s.cur_cmnt_and_lit.cur_lit < lits.len() {
@@ -2212,7 +2250,7 @@ pub fn next_lit(s: @ps, pos: BytePos) -> Option<comments::lit> {
     }
 }
 
-pub fn maybe_print_comment(s: @ps, pos: BytePos) {
+pub fn maybe_print_comment(s: &mut ps, pos: BytePos) {
     loop {
         match next_comment(s) {
           Some(ref cmnt) => {
@@ -2226,33 +2264,33 @@ pub fn maybe_print_comment(s: @ps, pos: BytePos) {
     }
 }
 
-pub fn print_comment(s: @ps, cmnt: &comments::cmnt) {
+pub fn print_comment(s: &mut ps, cmnt: &comments::cmnt) {
     match cmnt.style {
       comments::mixed => {
         assert_eq!(cmnt.lines.len(), 1u);
-        zerobreak(s.s);
-        word(s.s, cmnt.lines[0]);
-        zerobreak(s.s);
+        zerobreak(&mut s.s);
+        word(&mut s.s, cmnt.lines[0]);
+        zerobreak(&mut s.s);
       }
       comments::isolated => {
         pprust::hardbreak_if_not_bol(s);
         for line in cmnt.lines.iter() {
             // Don't print empty lines because they will end up as trailing
             // whitespace
-            if !line.is_empty() { word(s.s, *line); }
-            hardbreak(s.s);
+            if !line.is_empty() { word(&mut s.s, *line); }
+            hardbreak(&mut s.s);
         }
       }
       comments::trailing => {
-        word(s.s, " ");
+        word(&mut s.s, " ");
         if cmnt.lines.len() == 1u {
-            word(s.s, cmnt.lines[0]);
-            hardbreak(s.s);
+            word(&mut s.s, cmnt.lines[0]);
+            hardbreak(&mut s.s);
         } else {
             ibox(s, 0u);
             for line in cmnt.lines.iter() {
-                if !line.is_empty() { word(s.s, *line); }
-                hardbreak(s.s);
+                if !line.is_empty() { word(&mut s.s, *line); }
+                hardbreak(&mut s.s);
             }
             end(s);
         }
@@ -2264,30 +2302,42 @@ pub fn print_comment(s: @ps, cmnt: &comments::cmnt) {
               pp::STRING(s, _) => ";" == s,
               _ => false
             };
-        if is_semi || is_begin(s) || is_end(s) { hardbreak(s.s); }
-        hardbreak(s.s);
+        if is_semi || is_begin(s) || is_end(s) { hardbreak(&mut s.s); }
+        hardbreak(&mut s.s);
       }
     }
 }
 
-pub fn print_string(s: @ps, st: &str, style: ast::StrStyle) {
+pub fn print_string(s: &mut ps, st: &str, style: ast::StrStyle) {
     let st = match style {
         ast::CookedStr => format!("\"{}\"", st.escape_default()),
         ast::RawStr(n) => format!("r{delim}\"{string}\"{delim}",
                                   delim="#".repeat(n), string=st)
     };
-    word(s.s, st);
+    word(&mut s.s, st);
 }
 
-pub fn to_str<T>(t: &T, f: |@ps, &T|, intr: @ident_interner) -> ~str {
-    let wr = @mut MemWriter::new();
-    let s = rust_printer(wr as @mut io::Writer, intr);
-    f(s, t);
-    eof(s.s);
-    str::from_utf8_owned(wr.inner_ref().to_owned())
+// XXX(pcwalton): A nasty function to extract the string from an `io::Writer`
+// that we "know" to be a `MemWriter` that works around the lack of checked
+// downcasts.
+unsafe fn get_mem_writer(writer: &mut ~io::Writer) -> ~str {
+    let (_, wr): (uint, ~MemWriter) = cast::transmute_copy(writer);
+    let result = str::from_utf8_owned(wr.inner_ref().to_owned());
+    cast::forget(wr);
+    result
 }
 
-pub fn next_comment(s: @ps) -> Option<comments::cmnt> {
+pub fn to_str<T>(t: &T, f: |&mut ps, &T|, intr: @ident_interner) -> ~str {
+    let wr = ~MemWriter::new();
+    let mut s = rust_printer(wr as ~io::Writer, intr);
+    f(&mut s, t);
+    eof(&mut s.s);
+    unsafe {
+        get_mem_writer(&mut s.s.out)
+    }
+}
+
+pub fn next_comment(s: &mut ps) -> Option<comments::cmnt> {
     match s.comments {
       Some(ref cmnts) => {
         if s.cur_cmnt_and_lit.cur_cmnt < cmnts.len() {
@@ -2300,7 +2350,7 @@ pub fn next_comment(s: @ps) -> Option<comments::cmnt> {
     }
 }
 
-pub fn print_opt_purity(s: @ps, opt_purity: Option<ast::purity>) {
+pub fn print_opt_purity(s: &mut ps, opt_purity: Option<ast::purity>) {
     match opt_purity {
         Some(ast::impure_fn) => { }
         Some(purity) => {
@@ -2310,7 +2360,7 @@ pub fn print_opt_purity(s: @ps, opt_purity: Option<ast::purity>) {
     }
 }
 
-pub fn print_opt_abis_and_extern_if_nondefault(s: @ps,
+pub fn print_opt_abis_and_extern_if_nondefault(s: &mut ps,
                                                opt_abis: Option<AbiSet>) {
     match opt_abis {
         Some(abis) if !abis.is_rust() => {
@@ -2321,7 +2371,7 @@ pub fn print_opt_abis_and_extern_if_nondefault(s: @ps,
     };
 }
 
-pub fn print_extern_opt_abis(s: @ps, opt_abis: Option<AbiSet>) {
+pub fn print_extern_opt_abis(s: &mut ps, opt_abis: Option<AbiSet>) {
     match opt_abis {
         Some(abis) => {
             word_nbsp(s, "extern");
@@ -2331,23 +2381,23 @@ pub fn print_extern_opt_abis(s: @ps, opt_abis: Option<AbiSet>) {
     };
 }
 
-pub fn print_opt_sigil(s: @ps, opt_sigil: Option<ast::Sigil>) {
+pub fn print_opt_sigil(s: &mut ps, opt_sigil: Option<ast::Sigil>) {
     match opt_sigil {
-        Some(ast::BorrowedSigil) => { word(s.s, "&"); }
-        Some(ast::OwnedSigil) => { word(s.s, "~"); }
-        Some(ast::ManagedSigil) => { word(s.s, "@"); }
+        Some(ast::BorrowedSigil) => { word(&mut s.s, "&"); }
+        Some(ast::OwnedSigil) => { word(&mut s.s, "~"); }
+        Some(ast::ManagedSigil) => { word(&mut s.s, "@"); }
         None => {}
     };
 }
 
-pub fn print_fn_header_info(s: @ps,
+pub fn print_fn_header_info(s: &mut ps,
                             _opt_explicit_self: Option<ast::explicit_self_>,
                             opt_purity: Option<ast::purity>,
                             abis: AbiSet,
                             onceness: ast::Onceness,
                             opt_sigil: Option<ast::Sigil>,
                             vis: ast::visibility) {
-    word(s.s, visibility_qualified(vis, ""));
+    word(&mut s.s, visibility_qualified(vis, ""));
 
     if abis != AbiSet::Rust() {
         word_nbsp(s, "extern");
@@ -2361,7 +2411,7 @@ pub fn print_fn_header_info(s: @ps,
     }
 
     print_onceness(s, onceness);
-    word(s.s, "fn");
+    word(&mut s.s, "fn");
     print_opt_sigil(s, opt_sigil);
 }
 
@@ -2380,14 +2430,14 @@ pub fn onceness_to_str(o: ast::Onceness) -> &'static str {
     }
 }
 
-pub fn print_purity(s: @ps, p: ast::purity) {
+pub fn print_purity(s: &mut ps, p: ast::purity) {
     match p {
       ast::impure_fn => (),
       _ => word_nbsp(s, purity_to_str(p))
     }
 }
 
-pub fn print_onceness(s: @ps, o: ast::Onceness) {
+pub fn print_onceness(s: &mut ps, o: ast::Onceness) {
     match o {
         ast::Once => { word_nbsp(s, "once"); }
         ast::Many => {}
@@ -2403,12 +2453,6 @@ mod test {
     use codemap;
     use parse::token;
 
-    fn string_check<T:Eq> (given : &T, expected: &T) {
-        if !(given == expected) {
-            fail!("given {:?}, expected {:?}", given, expected);
-        }
-    }
-
     #[test]
     fn test_fun_to_str() {
         let abba_ident = token::str_to_ident("abba");
diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs
index c144b36a86f..b694e1f702b 100644
--- a/src/libsyntax/util/interner.rs
+++ b/src/libsyntax/util/interner.rs
@@ -14,20 +14,21 @@
 
 use ast::Name;
 
+use std::cell::RefCell;
 use std::cmp::Equiv;
 use std::hashmap::HashMap;
 
 pub struct Interner<T> {
-    priv map: @mut HashMap<T, Name>,
-    priv vect: @mut ~[T],
+    priv map: @RefCell<HashMap<T, Name>>,
+    priv vect: @RefCell<~[T]>,
 }
 
 // when traits can extend traits, we should extend index<Name,T> to get []
 impl<T:Eq + IterBytes + Hash + Freeze + Clone + 'static> Interner<T> {
     pub fn new() -> Interner<T> {
         Interner {
-            map: @mut HashMap::new(),
-            vect: @mut ~[],
+            map: @RefCell::new(HashMap::new()),
+            vect: @RefCell::new(~[]),
         }
     }
 
@@ -40,37 +41,41 @@ impl<T:Eq + IterBytes + Hash + Freeze + Clone + 'static> Interner<T> {
     }
 
     pub fn intern(&self, val: T) -> Name {
-        match self.map.find(&val) {
+        let mut map = self.map.borrow_mut();
+        match map.get().find(&val) {
             Some(&idx) => return idx,
             None => (),
         }
 
-        let vect = &mut *self.vect;
-        let new_idx = vect.len() as Name;
-        self.map.insert(val.clone(), new_idx);
-        vect.push(val);
+        let mut vect = self.vect.borrow_mut();
+        let new_idx = vect.get().len() as Name;
+        map.get().insert(val.clone(), new_idx);
+        vect.get().push(val);
         new_idx
     }
 
     pub fn gensym(&self, val: T) -> Name {
-        let new_idx = {
-            let vect = &*self.vect;
-            vect.len() as Name
-        };
+        let mut vect = self.vect.borrow_mut();
+        let new_idx = vect.get().len() as Name;
         // leave out of .map to avoid colliding
-        self.vect.push(val);
+        vect.get().push(val);
         new_idx
     }
 
     pub fn get(&self, idx: Name) -> T {
-        self.vect[idx].clone()
+        let vect = self.vect.borrow();
+        vect.get()[idx].clone()
     }
 
-    pub fn len(&self) -> uint { let vect = &*self.vect; vect.len() }
+    pub fn len(&self) -> uint {
+        let vect = self.vect.borrow();
+        vect.get().len()
+    }
 
     pub fn find_equiv<Q:Hash + IterBytes + Equiv<T>>(&self, val: &Q)
                                               -> Option<Name> {
-        match self.map.find_equiv(val) {
+        let map = self.map.borrow();
+        match map.get().find_equiv(val) {
             Some(v) => Some(*v),
             None => None,
         }
@@ -80,16 +85,16 @@ impl<T:Eq + IterBytes + Hash + Freeze + Clone + 'static> Interner<T> {
 // A StrInterner differs from Interner<String> in that it accepts
 // borrowed pointers rather than @ ones, resulting in less allocation.
 pub struct StrInterner {
-    priv map: @mut HashMap<@str, Name>,
-    priv vect: @mut ~[@str],
+    priv map: @RefCell<HashMap<@str, Name>>,
+    priv vect: @RefCell<~[@str]>,
 }
 
 // when traits can extend traits, we should extend index<Name,T> to get []
 impl StrInterner {
     pub fn new() -> StrInterner {
         StrInterner {
-            map: @mut HashMap::new(),
-            vect: @mut ~[],
+            map: @RefCell::new(HashMap::new()),
+            vect: @RefCell::new(~[]),
         }
     }
 
@@ -100,22 +105,25 @@ impl StrInterner {
     }
 
     pub fn intern(&self, val: &str) -> Name {
-        match self.map.find_equiv(&val) {
+        let mut map = self.map.borrow_mut();
+        match map.get().find_equiv(&val) {
             Some(&idx) => return idx,
             None => (),
         }
 
         let new_idx = self.len() as Name;
         let val = val.to_managed();
-        self.map.insert(val, new_idx);
-        self.vect.push(val);
+        map.get().insert(val, new_idx);
+        let mut vect = self.vect.borrow_mut();
+        vect.get().push(val);
         new_idx
     }
 
     pub fn gensym(&self, val: &str) -> Name {
         let new_idx = self.len() as Name;
         // leave out of .map to avoid colliding
-        self.vect.push(val.to_managed());
+        let mut vect = self.vect.borrow_mut();
+        vect.get().push(val.to_managed());
         new_idx
     }
 
@@ -132,17 +140,26 @@ impl StrInterner {
     pub fn gensym_copy(&self, idx : Name) -> Name {
         let new_idx = self.len() as Name;
         // leave out of map to avoid colliding
-        self.vect.push(self.vect[idx]);
+        let mut vect = self.vect.borrow_mut();
+        let existing = vect.get()[idx];
+        vect.get().push(existing);
         new_idx
     }
 
-    pub fn get(&self, idx: Name) -> @str { self.vect[idx] }
+    pub fn get(&self, idx: Name) -> @str {
+        let vect = self.vect.borrow();
+        vect.get()[idx]
+    }
 
-    pub fn len(&self) -> uint { let vect = &*self.vect; vect.len() }
+    pub fn len(&self) -> uint {
+        let vect = self.vect.borrow();
+        vect.get().len()
+    }
 
     pub fn find_equiv<Q:Hash + IterBytes + Equiv<@str>>(&self, val: &Q)
                                                          -> Option<Name> {
-        match self.map.find_equiv(val) {
+        let map = self.map.borrow();
+        match map.get().find_equiv(val) {
             Some(v) => Some(*v),
             None => None,
         }
diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs
index 01e050c1ffe..dc546c7610f 100644
--- a/src/libsyntax/util/parser_testing.rs
+++ b/src/libsyntax/util/parser_testing.rs
@@ -17,7 +17,7 @@ use parse::token;
 
 // map a string to tts, using a made-up filename: return both the token_trees
 // and the ParseSess
-pub fn string_to_tts_and_sess (source_str : @str) -> (~[ast::token_tree],@mut ParseSess) {
+pub fn string_to_tts_and_sess (source_str : @str) -> (~[ast::token_tree],@ParseSess) {
     let ps = new_parse_sess(None);
     (filemap_to_tts(ps,string_to_filemap(ps,source_str,@"bogofile")),ps)
 }
@@ -28,7 +28,7 @@ pub fn string_to_tts(source_str : @str) -> ~[ast::token_tree] {
     tts
 }
 
-pub fn string_to_parser_and_sess(source_str: @str) -> (Parser,@mut ParseSess) {
+pub fn string_to_parser_and_sess(source_str: @str) -> (Parser,@ParseSess) {
     let ps = new_parse_sess(None);
     (new_parser_from_source_str(ps,~[],@"bogofile",source_str),ps)
 }
@@ -54,7 +54,7 @@ pub fn string_to_crate (source_str : @str) -> ast::Crate {
 }
 
 // parse a string, return a crate and the ParseSess
-pub fn string_to_crate_and_sess (source_str : @str) -> (ast::Crate,@mut ParseSess) {
+pub fn string_to_crate_and_sess (source_str : @str) -> (ast::Crate,@ParseSess) {
     let (mut p,ps) = string_to_parser_and_sess(source_str);
     (p.parse_crate_mod(),ps)
 }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 2e83a038c58..29567ab9442 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -302,10 +302,10 @@ pub fn skip_ty<E, V:Visitor<E>>(_: &mut V, _: &Ty, _: E) {
 
 pub fn walk_ty<E:Clone, V:Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) {
     match typ.node {
-        ty_uniq(ty) | ty_vec(ty) => {
+        ty_uniq(ty) | ty_vec(ty) | ty_box(ty) => {
             visitor.visit_ty(ty, env)
         }
-        ty_box(ref mutable_type) | ty_ptr(ref mutable_type) => {
+        ty_ptr(ref mutable_type) => {
             visitor.visit_ty(mutable_type.ty, env)
         }
         ty_rptr(ref lifetime, ref mutable_type) => {