about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/comp/driver/driver.rs7
-rw-r--r--src/comp/driver/session.rs3
-rw-r--r--src/comp/metadata/astencode.rs2
-rw-r--r--src/comp/metadata/astencode_gen.rs42
-rw-r--r--src/comp/middle/alias.rs8
-rw-r--r--src/comp/middle/last_use.rs2
-rw-r--r--src/comp/middle/mutbl.rs9
-rw-r--r--src/comp/middle/resolve.rs7
-rw-r--r--src/comp/middle/trans/base.rs2
-rw-r--r--src/comp/middle/tstate/auxiliary.rs8
-rw-r--r--src/comp/middle/tstate/bitvectors.rs2
-rw-r--r--src/comp/middle/tstate/pre_post_conditions.rs6
-rw-r--r--src/comp/middle/tstate/states.rs2
-rw-r--r--src/comp/middle/typeck.rs2
-rw-r--r--src/comp/syntax/ast.rs5
-rw-r--r--src/comp/syntax/ast_util.rs2
-rw-r--r--src/comp/syntax/fold.rs3
-rw-r--r--src/comp/syntax/parse/parser.rs16
-rwxr-xr-xsrc/etc/gen-astencode54
-rw-r--r--src/rustdoc/astsrv.rs3
20 files changed, 112 insertions, 73 deletions
diff --git a/src/comp/driver/driver.rs b/src/comp/driver/driver.rs
index fd3b718231a..4aaabc667ba 100644
--- a/src/comp/driver/driver.rs
+++ b/src/comp/driver/driver.rs
@@ -421,6 +421,7 @@ fn build_session_options(match: getopts::match,
     let cfg = parse_cfgspecs(getopts::opt_strs(match, "cfg"));
     let test = opt_present(match, "test");
     let warn_unused_imports = opt_present(match, "warn-unused-imports");
+    let enforce_mut_vars = opt_present(match, "enforce-mut-vars");
     let sopts: @session::options =
         @{crate_type: crate_type,
           static: static,
@@ -444,7 +445,8 @@ fn build_session_options(match: getopts::match,
           no_asm_comments: no_asm_comments,
           monomorphize: monomorphize,
           inline: inline,
-          warn_unused_imports: warn_unused_imports};
+          warn_unused_imports: warn_unused_imports,
+          enforce_mut_vars: enforce_mut_vars};
     ret sopts;
 }
 
@@ -518,7 +520,8 @@ fn opts() -> [getopts::opt] {
          optmulti("cfg"), optflag("test"),
          optflag("lib"), optflag("bin"), optflag("static"), optflag("gc"),
          optflag("no-asm-comments"),
-         optflag("warn-unused-imports")];
+         optflag("warn-unused-imports"),
+         optflag("enforce-mut-vars")];
 }
 
 type output_filenames = @{out_filename: str, obj_filename:str};
diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs
index b967ad23f58..ec2182d2929 100644
--- a/src/comp/driver/session.rs
+++ b/src/comp/driver/session.rs
@@ -47,7 +47,8 @@ type options =
      no_asm_comments: bool,
      monomorphize: bool,
      inline: bool,
-     warn_unused_imports: bool};
+     warn_unused_imports: bool,
+     enforce_mut_vars: bool};
 
 type crate_metadata = {name: str, data: [u8]};
 
diff --git a/src/comp/metadata/astencode.rs b/src/comp/metadata/astencode.rs
index 0f641d477f1..71ddbeb749b 100644
--- a/src/comp/metadata/astencode.rs
+++ b/src/comp/metadata/astencode.rs
@@ -360,7 +360,7 @@ impl of tr for ast::def {
           ast::def_native_mod(did) { ast::def_native_mod(did.tr(xcx)) }
           ast::def_const(did) { ast::def_const(did.tr(xcx)) }
           ast::def_arg(nid, m) { ast::def_arg(xcx.tr_id(nid), m) }
-          ast::def_local(nid) { ast::def_local(xcx.tr_id(nid)) }
+          ast::def_local(nid, b) { ast::def_local(xcx.tr_id(nid), b) }
           ast::def_variant(e_did, v_did) {
             ast::def_variant(e_did.tr(xcx), v_did.tr(xcx))
           }
diff --git a/src/comp/metadata/astencode_gen.rs b/src/comp/metadata/astencode_gen.rs
index 648af0c7a5c..f95b9a2105f 100644
--- a/src/comp/metadata/astencode_gen.rs
+++ b/src/comp/metadata/astencode_gen.rs
@@ -1956,18 +1956,20 @@ fn serialize_114<S: std::serialization::serializer>(s: S,
 fn serialize_106<S: std::serialization::serializer>(s: S,
                                                     v: syntax::ast::local_) {
 
-    s.emit_rec(/*@syntax::ast::ty*//*@syntax::ast::pat*/
+    s.emit_rec(/*bool*//*@syntax::ast::ty*//*@syntax::ast::pat*/
                /*core::option::t<syntax::ast::initializer>*/
                /*syntax::ast::node_id*/
                {||
                    {
-                       s.emit_rec_field("ty", 0u,
+                       s.emit_rec_field("is_mutbl", 0u,
+                                        {|| serialize_18(s, v.is_mutbl) });
+                       s.emit_rec_field("ty", 1u,
                                         {|| serialize_29(s, v.ty) });
-                       s.emit_rec_field("pat", 1u,
+                       s.emit_rec_field("pat", 2u,
                                         {|| serialize_107(s, v.pat) });
-                       s.emit_rec_field("init", 2u,
+                       s.emit_rec_field("init", 3u,
                                         {|| serialize_114(s, v.init) });
-                       s.emit_rec_field("id", 3u, {|| serialize_27(s, v.id) })
+                       s.emit_rec_field("id", 4u, {|| serialize_27(s, v.id) })
                    }
                });
 }
@@ -5974,6 +5976,8 @@ fn deserialize_106<S: std::serialization::deserializer>(s: S) ->
     s.read_rec(
 
 
+               /*bool*/
+
                /*@syntax::ast::ty*/
 
                /*@syntax::ast::pat*/
@@ -5983,13 +5987,16 @@ fn deserialize_106<S: std::serialization::deserializer>(s: S) ->
                /*syntax::ast::node_id*/
 
                {||
-                   {ty: s.read_rec_field("ty", 0u, {|| deserialize_29(s) }),
+                   {is_mutbl:
+                        s.read_rec_field("is_mutbl", 0u,
+                                         {|| deserialize_18(s) }),
+                    ty: s.read_rec_field("ty", 1u, {|| deserialize_29(s) }),
                     pat:
-                        s.read_rec_field("pat", 1u, {|| deserialize_107(s) }),
+                        s.read_rec_field("pat", 2u, {|| deserialize_107(s) }),
                     init:
-                        s.read_rec_field("init", 2u,
+                        s.read_rec_field("init", 3u,
                                          {|| deserialize_114(s) }),
-                    id: s.read_rec_field("id", 3u, {|| deserialize_27(s) }),}
+                    id: s.read_rec_field("id", 4u, {|| deserialize_27(s) }),}
                })
 }
 /*syntax::ast::local*/
@@ -8015,7 +8022,7 @@ fn serialize_161<S: std::serialization::serializer>(s: S,
                 /*syntax::ast::def_id*/
                 /*syntax::ast::node_id*/
                 /*syntax::ast::mode<syntax::ast::rmode>*/
-                /*syntax::ast::node_id*/
+                /*syntax::ast::node_id*//*bool*/
                 /*syntax::ast::def_id*//*syntax::ast::def_id*/
                 /*syntax::ast::def_id*/
                 /*syntax::ast::prim_ty*/
@@ -8112,14 +8119,19 @@ fn serialize_161<S: std::serialization::serializer>(s: S,
                                                 }
                                             })
                       }
-                      syntax::ast::def_local(v0) {
-                        s.emit_enum_variant("syntax::ast::def_local", 6u, 1u,
+                      syntax::ast::def_local(v0, v1) {
+                        s.emit_enum_variant("syntax::ast::def_local", 6u, 2u,
                                             {||
                                                 {
                                                     s.emit_enum_variant_arg(0u,
                                                                             {||
                                                                                 serialize_27(s,
                                                                                              v0)
+                                                                            });
+                                                    s.emit_enum_variant_arg(1u,
+                                                                            {||
+                                                                                serialize_18(s,
+                                                                                             v1)
                                                                             })
                                                 }
                                             })
@@ -8378,7 +8390,7 @@ fn deserialize_161<S: std::serialization::deserializer>(s: S) ->
                 /*syntax::ast::node_id*/
                 /*syntax::ast::mode<syntax::ast::rmode>*/
 
-                /*syntax::ast::node_id*/
+                /*syntax::ast::node_id*//*bool*/
 
                 /*syntax::ast::def_id*//*syntax::ast::def_id*/
 
@@ -8451,6 +8463,10 @@ fn deserialize_161<S: std::serialization::deserializer>(s: S) ->
                                                 syntax::ast::def_local(s.read_enum_variant_arg(0u,
                                                                                                {||
                                                                                                    deserialize_27(s)
+                                                                                               }),
+                                                                       s.read_enum_variant_arg(1u,
+                                                                                               {||
+                                                                                                   deserialize_18(s)
                                                                                                }))
                                               }
                                               7u {
diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs
index 4a04bbff6ff..cb0785b4df1 100644
--- a/src/comp/middle/alias.rs
+++ b/src/comp/middle/alias.rs
@@ -255,7 +255,7 @@ fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr])
     }
     let f_may_close =
         alt f.node {
-          ast::expr_path(_) { def_is_local(cx.tcx.def_map.get(f.id)) }
+          ast::expr_path(_) { def_is_local_or_self(cx.tcx.def_map.get(f.id)) }
           _ { true }
         };
     if f_may_close {
@@ -390,7 +390,7 @@ fn check_for(cx: ctx, local: @ast::local, seq: @ast::expr, blk: ast::blk,
 fn check_var(cx: ctx, ex: @ast::expr, p: @ast::path, id: ast::node_id,
              assign: bool, sc: scope) {
     let def = cx.tcx.def_map.get(id);
-    if !def_is_local(def) { ret; }
+    if !def_is_local_or_self(def) { ret; }
     let my_defnum = ast_util::def_id_of_def(def).node;
     let my_local_id = local_id_of_node(cx, my_defnum);
     let var_t = ty::expr_ty(cx.tcx, ex);
@@ -539,9 +539,9 @@ fn ty_can_unsafely_include(cx: ctx, needle: unsafe_ty, haystack: ty::t,
     ret helper(cx.tcx, needle, haystack, mutbl);
 }
 
-fn def_is_local(d: ast::def) -> bool {
+fn def_is_local_or_self(d: ast::def) -> bool {
     alt d {
-      ast::def_local(_) | ast::def_arg(_, _) | ast::def_binding(_) |
+      ast::def_local(_, _) | ast::def_arg(_, _) | ast::def_binding(_) |
       ast::def_upvar(_, _, _) | ast::def_self(_) { true }
       _ { false }
     }
diff --git a/src/comp/middle/last_use.rs b/src/comp/middle/last_use.rs
index c4dadc02f44..12ffdfccb41 100644
--- a/src/comp/middle/last_use.rs
+++ b/src/comp/middle/last_use.rs
@@ -342,7 +342,7 @@ fn clear_in_current(cx: ctx, my_def: node_id, to: bool) {
 
 fn def_is_owned_local(cx: ctx, d: def) -> option<node_id> {
     alt d {
-      def_local(id) { some(id) }
+      def_local(id, _) { some(id) }
       def_arg(id, m) {
         alt ty::resolved_mode(cx.tcx, m) {
           by_copy | by_move { some(id) }
diff --git a/src/comp/middle/mutbl.rs b/src/comp/middle/mutbl.rs
index b490387424d..836b2631427 100644
--- a/src/comp/middle/mutbl.rs
+++ b/src/comp/middle/mutbl.rs
@@ -298,6 +298,15 @@ fn is_immutable_def(cx: @ctx, def: def) -> option<str> {
           _ { some("upvar") }
         };
       }
+
+      // Note: we should *always* allow all local variables to be assigned
+      // here and then guarantee in the typestate pass that immutable local
+      // variables are assigned at most once.  But this requires a new kind of
+      // propagation (def. not assigned), so I didn't do that.
+      def_local(_, false) if cx.tcx.sess.opts.enforce_mut_vars {
+        some("immutable local variable")
+      }
+
       def_binding(_) { some("binding") }
       _ { none }
     }
diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs
index a1642202501..117641c9fe8 100644
--- a/src/comp/middle/resolve.rs
+++ b/src/comp/middle/resolve.rs
@@ -957,7 +957,7 @@ fn scope_closes(sc: scope) -> option<node_id> {
 
 fn def_is_local(d: def) -> bool {
     alt d {
-      ast::def_arg(_, _) | ast::def_local(_) | ast::def_binding(_) |
+      ast::def_arg(_, _) | ast::def_local(_, _) | ast::def_binding(_) |
       ast::def_upvar(_, _, _) { true }
       _ { false }
     }
@@ -1235,7 +1235,8 @@ fn lookup_in_block(e: env, name: ident, sp: span, b: ast::blk_, pos: uint,
                                      && (i < pos || j < loc_pos) {
                             alt lookup_in_pat(e, name, loc.node.pat) {
                               some(nid) {
-                                ret some(ast::def_local(nid));
+                                ret some(ast::def_local(nid,
+                                                        loc.node.is_mutbl));
                               }
                               _ { }
                             }
@@ -1702,7 +1703,7 @@ fn ns_for_def(d: def) -> namespace {
     alt d {
       ast::def_variant(_, _) { ns_val(definite_enum) }
       ast::def_fn(_, _) | ast::def_self(_) |
-      ast::def_const(_) | ast::def_arg(_, _) | ast::def_local(_) |
+      ast::def_const(_) | ast::def_arg(_, _) | ast::def_local(_, _) |
       ast::def_upvar(_, _, _) |  ast::def_self(_) |
       ast::def_class_field(_,_) | ast::def_class_method(_,_)
           { ns_val(value_or_enum) }
diff --git a/src/comp/middle/trans/base.rs b/src/comp/middle/trans/base.rs
index 04b51b85bcf..479def401fb 100644
--- a/src/comp/middle/trans/base.rs
+++ b/src/comp/middle/trans/base.rs
@@ -2253,7 +2253,7 @@ fn trans_local_var(cx: block, def: ast::def) -> local_var_result {
         assert (cx.fcx.llargs.contains_key(nid));
         ret take_local(cx.fcx.llargs, nid);
       }
-      ast::def_local(nid) | ast::def_binding(nid) {
+      ast::def_local(nid, _) | ast::def_binding(nid) {
         assert (cx.fcx.lllocals.contains_key(nid));
         ret take_local(cx.fcx.lllocals, nid);
       }
diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs
index 9ab7cc850f6..11b1ef3366e 100644
--- a/src/comp/middle/tstate/auxiliary.rs
+++ b/src/comp/middle/tstate/auxiliary.rs
@@ -576,7 +576,7 @@ fn expr_to_constr_arg(tcx: ty::ctxt, e: @expr) -> @constr_arg_use {
     alt e.node {
       expr_path(p) {
         alt tcx.def_map.find(e.id) {
-          some(def_local(nid)) | some(def_arg(nid, _)) |
+          some(def_local(nid, _)) | some(def_arg(nid, _)) |
           some(def_binding(nid)) | some(def_upvar(nid, _, _)) {
             ret @respan(p.span,
                         carg_ident({ident: p.node.idents[0], node: nid}));
@@ -786,7 +786,7 @@ enum if_ty { if_check, plain_if, }
 fn local_node_id_to_def_id_strict(fcx: fn_ctxt, sp: span, i: node_id) ->
    def_id {
     alt local_node_id_to_def(fcx, i) {
-      some(def_local(nid)) | some(def_arg(nid, _)) |
+      some(def_local(nid, _)) | some(def_arg(nid, _)) |
       some(def_upvar(nid, _, _)) {
         ret local_def(nid);
       }
@@ -810,8 +810,8 @@ fn local_node_id_to_def(fcx: fn_ctxt, i: node_id) -> option<def> {
 
 fn local_node_id_to_def_id(fcx: fn_ctxt, i: node_id) -> option<def_id> {
     alt local_node_id_to_def(fcx, i) {
-      some(def_local(nid)) | some(def_arg(nid, _)) | some(def_binding(nid)) |
-      some(def_upvar(nid, _, _)) {
+      some(def_local(nid, _)) | some(def_arg(nid, _)) |
+      some(def_binding(nid)) | some(def_upvar(nid, _, _)) {
         some(local_def(nid))
       }
       _ { none }
diff --git a/src/comp/middle/tstate/bitvectors.rs b/src/comp/middle/tstate/bitvectors.rs
index f3d2be56b13..6acb23d906a 100644
--- a/src/comp/middle/tstate/bitvectors.rs
+++ b/src/comp/middle/tstate/bitvectors.rs
@@ -185,7 +185,7 @@ fn clear_in_poststate_expr(fcx: fn_ctxt, e: @expr, t: poststate) {
         alt vec::last(p.node.idents) {
           some(i) {
             alt local_node_id_to_def(fcx, e.id) {
-              some(def_local(nid)) {
+              some(def_local(nid, _)) {
                 clear_in_poststate_(bit_num(fcx, ninit(nid, i)), t);
               }
               some(_) {/* ignore args (for now...) */ }
diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs
index fef7d525384..8a83f7dd7b4 100644
--- a/src/comp/middle/tstate/pre_post_conditions.rs
+++ b/src/comp/middle/tstate/pre_post_conditions.rs
@@ -176,7 +176,7 @@ fn gen_if_local(fcx: fn_ctxt, lhs: @expr, rhs: @expr, larger_id: node_id,
     alt node_id_to_def(fcx.ccx, new_var) {
       some(d) {
         alt d {
-          def_local(nid) {
+          def_local(nid, _) {
             find_pre_post_expr(fcx, rhs);
             let p = expr_pp(fcx.ccx, rhs);
             set_pre_and_post(fcx.ccx, larger_id, p.precondition,
@@ -214,7 +214,7 @@ fn handle_update(fcx: fn_ctxt, parent: @expr, lhs: @expr, rhs: @expr,
             // pure and assign_op require the lhs to be init'd
             let df = node_id_to_def_strict(fcx.ccx.tcx, lhs.id);
             alt df {
-              def_local(nid) {
+              def_local(nid, _) {
                 let i = bit_num(fcx, ninit(nid, path_to_ident(p)));
                 require_and_preserve(i, expr_pp(fcx.ccx, lhs));
               }
@@ -259,7 +259,7 @@ fn handle_var(fcx: fn_ctxt, rslt: pre_and_post, id: node_id, name: ident) {
 fn handle_var_def(fcx: fn_ctxt, rslt: pre_and_post, def: def, name: ident) {
     log(debug, ("handle_var_def: ", def, name));
     alt def {
-      def_local(nid) | def_arg(nid, _) {
+      def_local(nid, _) | def_arg(nid, _) {
         use_var(fcx, nid);
         let i = bit_num(fcx, ninit(nid, name));
         require_and_preserve(i, rslt);
diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs
index 162659d1718..bba7b4c4834 100644
--- a/src/comp/middle/tstate/states.rs
+++ b/src/comp/middle/tstate/states.rs
@@ -246,7 +246,7 @@ fn gen_if_local(fcx: fn_ctxt, p: poststate, e: @expr) -> bool {
     alt e.node {
       expr_path(pth) {
         alt fcx.ccx.tcx.def_map.find(e.id) {
-          some(def_local(nid)) {
+          some(def_local(nid, _)) {
             ret set_in_poststate_ident(fcx, nid, path_to_ident(pth), p);
           }
           _ { ret false; }
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index ee16bf3aadf..265f5717461 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -101,7 +101,7 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
         let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid));
         ret {bounds: @[], ty: typ};
       }
-      ast::def_local(nid) {
+      ast::def_local(nid, _) {
         assert (fcx.locals.contains_key(nid));
         let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid));
         ret {bounds: @[], ty: typ};
diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs
index 9e84cb9cd90..edc5ade4062 100644
--- a/src/comp/syntax/ast.rs
+++ b/src/comp/syntax/ast.rs
@@ -38,7 +38,7 @@ enum def {
     def_native_mod(def_id),
     def_const(def_id),
     def_arg(node_id, mode),
-    def_local(node_id),
+    def_local(node_id, bool /* is_mutbl */),
     def_variant(def_id /* enum */, def_id /* variant */),
     def_ty(def_id),
     def_prim_ty(prim_ty),
@@ -194,7 +194,8 @@ enum init_op { init_assign, init_move, }
 type initializer = {op: init_op, expr: @expr};
 
 type local_ =  // FIXME: should really be a refinement on pat
-    {ty: @ty, pat: @pat, init: option<initializer>, id: node_id};
+    {is_mutbl: bool, ty: @ty, pat: @pat,
+     init: option<initializer>, id: node_id};
 
 type local = spanned<local_>;
 
diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs
index fb36fc17216..5f303b8c4a8 100644
--- a/src/comp/syntax/ast_util.rs
+++ b/src/comp/syntax/ast_util.rs
@@ -41,7 +41,7 @@ fn def_id_of_def(d: def) -> def_id {
       def_use(id) |
       def_class(id) | def_class_field(_, id) | def_class_method(_, id) { id }
 
-      def_self(id) | def_arg(id, _) | def_local(id) |
+      def_self(id) | def_arg(id, _) | def_local(id, _) |
       def_upvar(id, _, _) | def_binding(id) {
         local_def(id)
       }
diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs
index 00624bdf270..94a0ff6b879 100644
--- a/src/comp/syntax/fold.rs
+++ b/src/comp/syntax/fold.rs
@@ -532,7 +532,8 @@ fn noop_fold_path(&&p: path_, fld: ast_fold) -> path_ {
 }
 
 fn noop_fold_local(l: local_, fld: ast_fold) -> local_ {
-    ret {ty: fld.fold_ty(l.ty),
+    ret {is_mutbl: l.is_mutbl,
+         ty: fld.fold_ty(l.ty),
          pat: fld.fold_pat(l.pat),
          init:
              alt l.init {
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs
index 0de75d88422..5837baf1ff9 100644
--- a/src/comp/syntax/parse/parser.rs
+++ b/src/comp/syntax/parse/parser.rs
@@ -1346,7 +1346,7 @@ fn parse_else_expr(p: parser) -> @ast::expr {
 
 fn parse_for_expr(p: parser) -> @ast::expr {
     let lo = p.last_span.lo;
-    let decl = parse_local(p, false);
+    let decl = parse_local(p, false, false);
     expect_word(p, "in");
     let seq = parse_expr(p);
     let body = parse_block_no_value(p);
@@ -1568,24 +1568,24 @@ fn parse_pat(p: parser) -> @ast::pat {
     ret @{id: p.get_id(), node: pat, span: ast_util::mk_sp(lo, hi)};
 }
 
-fn parse_local(p: parser, allow_init: bool) -> @ast::local {
+fn parse_local(p: parser, is_mutbl: bool,
+               allow_init: bool) -> @ast::local {
     let lo = p.span.lo;
     let pat = parse_pat(p);
     let ty = @spanned(lo, lo, ast::ty_infer);
     if eat(p, token::COLON) { ty = parse_ty(p, false); }
     let init = if allow_init { parse_initializer(p) } else { none };
     ret @spanned(lo, p.last_span.hi,
-                 {ty: ty, pat: pat, init: init, id: p.get_id()});
+                 {is_mutbl: is_mutbl, ty: ty, pat: pat,
+                  init: init, id: p.get_id()});
 }
 
 fn parse_let(p: parser) -> @ast::decl {
-    if eat_word(p, "mut") {
-        /* FIXME */
-    }
+    let is_mutbl = eat_word(p, "mut");
     let lo = p.span.lo;
-    let locals = [parse_local(p, true)];
+    let locals = [parse_local(p, is_mutbl, true)];
     while eat(p, token::COMMA) {
-        locals += [parse_local(p, true)];
+        locals += [parse_local(p, is_mutbl, true)];
     }
     ret @spanned(lo, p.last_span.hi, ast::decl_local(locals));
 }
diff --git a/src/etc/gen-astencode b/src/etc/gen-astencode
index d2fd1aff5e5..601c73ae0a2 100755
--- a/src/etc/gen-astencode
+++ b/src/etc/gen-astencode
@@ -1,5 +1,19 @@
 #!/bin/sh
 
+function msg {
+        echo ""
+        echo ""
+        echo "****************************************"
+        echo "* Processing errors encountered        *"
+        echo "*                                      *"
+        echo "* Dummy versions of the AST encoder    *"
+        echo "* have been left in astencode_gen.rs.  *"
+        echo "* Fix the compilation errors and rerun *"
+        echo "* this script to generate the real     *"
+        echo "* versions.                            *"
+        echo "****************************************"
+}
+
 M=src/comp/metadata
 GEN_TYPES="syntax::ast::item syntax::ast::def middle::typeck::method_origin \
            middle::freevars::freevar_entry syntax::ast::def_id"
@@ -7,19 +21,6 @@ GEN_TYPES="syntax::ast::item syntax::ast::def middle::typeck::method_origin \
 # Find serializer tool:
 for S in build/*/stage1/bin/serializer; do
 
-    if [ ! -x "$S" ]; then
-        echo "serializer excutable not found; try 'make serializer'"
-        exit 1
-    fi
-
-    # Find rustc:
-    D=$(dirname "$S")
-    R="${D}/../../stage0/bin/rustc"
-    if [ ! -x "$R" ]; then
-        echo "rustc not found or not executable at path '$R'"
-        exit 1
-    fi
-
     echo "Generating src/comp/metadata/astencode_gen.rs"
 
     # First, generate dummy fns so that the compiler can type
@@ -33,20 +34,25 @@ for S in build/*/stage1/bin/serializer; do
           >> $M/astencode_gen.rs
     done
 
+    # Find rustc and serializer:
+    D=$(dirname "$S")
+    R="${D}/../../stage0/bin/rustc"
+    if [ ! -x "$R" ]; then
+        echo "rustc not found or not executable at path '$R'"
+        msg
+        exit 1
+    fi
+
+    if [ ! -x "$S" ]; then
+        echo "serializer excutable not found; try 'make serializer'"
+        msg
+        exit 1
+    fi
+
     # Generate the real code into a temporary file.
     if ! "$S" src/comp/rustc.rc $GEN_TYPES > tmp.$$.rs
     then
-        echo ""
-        echo ""
-        echo "****************************************"
-        echo "* Compilation errors encountered       *"
-        echo "*                                      *"
-        echo "* Dummy versions of the AST encoder    *"
-        echo "* have been left in astencode_gen.rs.  *"
-        echo "* Fix the compilation errors and rerun *"
-        echo "* this script to generate the real     *"
-        echo "* versions.                            *"
-        echo "****************************************"
+        msg
         rm tmp.$$.rs
         exit 1
     fi
diff --git a/src/rustdoc/astsrv.rs b/src/rustdoc/astsrv.rs
index 4d0cdf3142f..227bb56841d 100644
--- a/src/rustdoc/astsrv.rs
+++ b/src/rustdoc/astsrv.rs
@@ -146,7 +146,8 @@ fn build_session() -> (session::session, @mutable bool) {
         no_asm_comments: false,
         monomorphize: false,
         inline: false,
-        warn_unused_imports: false
+        warn_unused_imports: false,
+        enforce_mut_vars: false
     };
 
     let codemap = codemap::new_codemap();