diff --git a/src/comp/driver/driver.rs b/src/comp/driver/driver.rs index fd3b718231af..4aaabc667ba2 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 b967ad23f58c..ec2182d2929b 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 0f641d477f1e..71ddbeb749bf 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 648af0c7a5c4..f95b9a2105f3 100644 --- a/src/comp/metadata/astencode_gen.rs +++ b/src/comp/metadata/astencode_gen.rs @@ -1956,18 +1956,20 @@ fn serialize_114(s: S, fn serialize_106(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::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: S) -> s.read_rec( + /*bool*/ + /*@syntax::ast::ty*/ /*@syntax::ast::pat*/ @@ -5983,13 +5987,16 @@ fn deserialize_106(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: S, /*syntax::ast::def_id*/ /*syntax::ast::node_id*/ /*syntax::ast::mode*/ - /*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: 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: S) -> /*syntax::ast::node_id*/ /*syntax::ast::mode*/ - /*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: 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 4a04bbff6ffb..cb0785b4df18 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 c4dadc02f44f..12ffdfccb416 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 { 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 b490387424d2..836b26314278 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 { _ { 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 a16422025013..117641c9fe87 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -957,7 +957,7 @@ fn scope_closes(sc: scope) -> option { 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 04b51b85bcf6..479def401fb9 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 9ab7cc850f63..11b1ef3366ec 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 { fn local_node_id_to_def_id(fcx: fn_ctxt, i: node_id) -> option { 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 f3d2be56b132..6acb23d906aa 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 fef7d5253847..8a83f7dd7b4e 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 162659d1718b..bba7b4c48345 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 ee16bf3aadf3..265f57174612 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 9e84cb9cd900..edc5ade40627 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, id: node_id}; + {is_mutbl: bool, ty: @ty, pat: @pat, + init: option, id: node_id}; type local = spanned; diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs index fb36fc172169..5f303b8c4a86 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 00624bdf270a..94a0ff6b8794 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 0de75d88422e..5837baf1ff90 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 d2fd1aff5e54..601c73ae0a24 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 4d0cdf3142fd..227bb56841d0 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();