Skip to content

Commit 2dd5b3a

Browse files
committed
optionally enforce local variable mutability
1 parent 99f231f commit 2dd5b3a

File tree

20 files changed

+112
-73
lines changed

20 files changed

+112
-73
lines changed

src/comp/driver/driver.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ fn build_session_options(match: getopts::match,
421421
let cfg = parse_cfgspecs(getopts::opt_strs(match, "cfg"));
422422
let test = opt_present(match, "test");
423423
let warn_unused_imports = opt_present(match, "warn-unused-imports");
424+
let enforce_mut_vars = opt_present(match, "enforce-mut-vars");
424425
let sopts: @session::options =
425426
@{crate_type: crate_type,
426427
static: static,
@@ -444,7 +445,8 @@ fn build_session_options(match: getopts::match,
444445
no_asm_comments: no_asm_comments,
445446
monomorphize: monomorphize,
446447
inline: inline,
447-
warn_unused_imports: warn_unused_imports};
448+
warn_unused_imports: warn_unused_imports,
449+
enforce_mut_vars: enforce_mut_vars};
448450
ret sopts;
449451
}
450452

@@ -518,7 +520,8 @@ fn opts() -> [getopts::opt] {
518520
optmulti("cfg"), optflag("test"),
519521
optflag("lib"), optflag("bin"), optflag("static"), optflag("gc"),
520522
optflag("no-asm-comments"),
521-
optflag("warn-unused-imports")];
523+
optflag("warn-unused-imports"),
524+
optflag("enforce-mut-vars")];
522525
}
523526

524527
type output_filenames = @{out_filename: str, obj_filename:str};

src/comp/driver/session.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ type options =
4747
no_asm_comments: bool,
4848
monomorphize: bool,
4949
inline: bool,
50-
warn_unused_imports: bool};
50+
warn_unused_imports: bool,
51+
enforce_mut_vars: bool};
5152

5253
type crate_metadata = {name: str, data: [u8]};
5354

src/comp/metadata/astencode.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ impl of tr for ast::def {
360360
ast::def_native_mod(did) { ast::def_native_mod(did.tr(xcx)) }
361361
ast::def_const(did) { ast::def_const(did.tr(xcx)) }
362362
ast::def_arg(nid, m) { ast::def_arg(xcx.tr_id(nid), m) }
363-
ast::def_local(nid) { ast::def_local(xcx.tr_id(nid)) }
363+
ast::def_local(nid, b) { ast::def_local(xcx.tr_id(nid), b) }
364364
ast::def_variant(e_did, v_did) {
365365
ast::def_variant(e_did.tr(xcx), v_did.tr(xcx))
366366
}

src/comp/metadata/astencode_gen.rs

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1956,18 +1956,20 @@ fn serialize_114<S: std::serialization::serializer>(s: S,
19561956
fn serialize_106<S: std::serialization::serializer>(s: S,
19571957
v: syntax::ast::local_) {
19581958

1959-
s.emit_rec(/*@syntax::ast::ty*//*@syntax::ast::pat*/
1959+
s.emit_rec(/*bool*//*@syntax::ast::ty*//*@syntax::ast::pat*/
19601960
/*core::option::t<syntax::ast::initializer>*/
19611961
/*syntax::ast::node_id*/
19621962
{||
19631963
{
1964-
s.emit_rec_field("ty", 0u,
1964+
s.emit_rec_field("is_mutbl", 0u,
1965+
{|| serialize_18(s, v.is_mutbl) });
1966+
s.emit_rec_field("ty", 1u,
19651967
{|| serialize_29(s, v.ty) });
1966-
s.emit_rec_field("pat", 1u,
1968+
s.emit_rec_field("pat", 2u,
19671969
{|| serialize_107(s, v.pat) });
1968-
s.emit_rec_field("init", 2u,
1970+
s.emit_rec_field("init", 3u,
19691971
{|| serialize_114(s, v.init) });
1970-
s.emit_rec_field("id", 3u, {|| serialize_27(s, v.id) })
1972+
s.emit_rec_field("id", 4u, {|| serialize_27(s, v.id) })
19711973
}
19721974
});
19731975
}
@@ -5974,6 +5976,8 @@ fn deserialize_106<S: std::serialization::deserializer>(s: S) ->
59745976
s.read_rec(
59755977

59765978

5979+
/*bool*/
5980+
59775981
/*@syntax::ast::ty*/
59785982

59795983
/*@syntax::ast::pat*/
@@ -5983,13 +5987,16 @@ fn deserialize_106<S: std::serialization::deserializer>(s: S) ->
59835987
/*syntax::ast::node_id*/
59845988

59855989
{||
5986-
{ty: s.read_rec_field("ty", 0u, {|| deserialize_29(s) }),
5990+
{is_mutbl:
5991+
s.read_rec_field("is_mutbl", 0u,
5992+
{|| deserialize_18(s) }),
5993+
ty: s.read_rec_field("ty", 1u, {|| deserialize_29(s) }),
59875994
pat:
5988-
s.read_rec_field("pat", 1u, {|| deserialize_107(s) }),
5995+
s.read_rec_field("pat", 2u, {|| deserialize_107(s) }),
59895996
init:
5990-
s.read_rec_field("init", 2u,
5997+
s.read_rec_field("init", 3u,
59915998
{|| deserialize_114(s) }),
5992-
id: s.read_rec_field("id", 3u, {|| deserialize_27(s) }),}
5999+
id: s.read_rec_field("id", 4u, {|| deserialize_27(s) }),}
59936000
})
59946001
}
59956002
/*syntax::ast::local*/
@@ -8015,7 +8022,7 @@ fn serialize_161<S: std::serialization::serializer>(s: S,
80158022
/*syntax::ast::def_id*/
80168023
/*syntax::ast::node_id*/
80178024
/*syntax::ast::mode<syntax::ast::rmode>*/
8018-
/*syntax::ast::node_id*/
8025+
/*syntax::ast::node_id*//*bool*/
80198026
/*syntax::ast::def_id*//*syntax::ast::def_id*/
80208027
/*syntax::ast::def_id*/
80218028
/*syntax::ast::prim_ty*/
@@ -8112,14 +8119,19 @@ fn serialize_161<S: std::serialization::serializer>(s: S,
81128119
}
81138120
})
81148121
}
8115-
syntax::ast::def_local(v0) {
8116-
s.emit_enum_variant("syntax::ast::def_local", 6u, 1u,
8122+
syntax::ast::def_local(v0, v1) {
8123+
s.emit_enum_variant("syntax::ast::def_local", 6u, 2u,
81178124
{||
81188125
{
81198126
s.emit_enum_variant_arg(0u,
81208127
{||
81218128
serialize_27(s,
81228129
v0)
8130+
});
8131+
s.emit_enum_variant_arg(1u,
8132+
{||
8133+
serialize_18(s,
8134+
v1)
81238135
})
81248136
}
81258137
})
@@ -8378,7 +8390,7 @@ fn deserialize_161<S: std::serialization::deserializer>(s: S) ->
83788390
/*syntax::ast::node_id*/
83798391
/*syntax::ast::mode<syntax::ast::rmode>*/
83808392

8381-
/*syntax::ast::node_id*/
8393+
/*syntax::ast::node_id*//*bool*/
83828394

83838395
/*syntax::ast::def_id*//*syntax::ast::def_id*/
83848396

@@ -8451,6 +8463,10 @@ fn deserialize_161<S: std::serialization::deserializer>(s: S) ->
84518463
syntax::ast::def_local(s.read_enum_variant_arg(0u,
84528464
{||
84538465
deserialize_27(s)
8466+
}),
8467+
s.read_enum_variant_arg(1u,
8468+
{||
8469+
deserialize_18(s)
84548470
}))
84558471
}
84568472
7u {

src/comp/middle/alias.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr])
255255
}
256256
let f_may_close =
257257
alt f.node {
258-
ast::expr_path(_) { def_is_local(cx.tcx.def_map.get(f.id)) }
258+
ast::expr_path(_) { def_is_local_or_self(cx.tcx.def_map.get(f.id)) }
259259
_ { true }
260260
};
261261
if f_may_close {
@@ -390,7 +390,7 @@ fn check_for(cx: ctx, local: @ast::local, seq: @ast::expr, blk: ast::blk,
390390
fn check_var(cx: ctx, ex: @ast::expr, p: @ast::path, id: ast::node_id,
391391
assign: bool, sc: scope) {
392392
let def = cx.tcx.def_map.get(id);
393-
if !def_is_local(def) { ret; }
393+
if !def_is_local_or_self(def) { ret; }
394394
let my_defnum = ast_util::def_id_of_def(def).node;
395395
let my_local_id = local_id_of_node(cx, my_defnum);
396396
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,
539539
ret helper(cx.tcx, needle, haystack, mutbl);
540540
}
541541

542-
fn def_is_local(d: ast::def) -> bool {
542+
fn def_is_local_or_self(d: ast::def) -> bool {
543543
alt d {
544-
ast::def_local(_) | ast::def_arg(_, _) | ast::def_binding(_) |
544+
ast::def_local(_, _) | ast::def_arg(_, _) | ast::def_binding(_) |
545545
ast::def_upvar(_, _, _) | ast::def_self(_) { true }
546546
_ { false }
547547
}

src/comp/middle/last_use.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ fn clear_in_current(cx: ctx, my_def: node_id, to: bool) {
342342

343343
fn def_is_owned_local(cx: ctx, d: def) -> option<node_id> {
344344
alt d {
345-
def_local(id) { some(id) }
345+
def_local(id, _) { some(id) }
346346
def_arg(id, m) {
347347
alt ty::resolved_mode(cx.tcx, m) {
348348
by_copy | by_move { some(id) }

src/comp/middle/mutbl.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,15 @@ fn is_immutable_def(cx: @ctx, def: def) -> option<str> {
298298
_ { some("upvar") }
299299
};
300300
}
301+
302+
// Note: we should *always* allow all local variables to be assigned
303+
// here and then guarantee in the typestate pass that immutable local
304+
// variables are assigned at most once. But this requires a new kind of
305+
// propagation (def. not assigned), so I didn't do that.
306+
def_local(_, false) if cx.tcx.sess.opts.enforce_mut_vars {
307+
some("immutable local variable")
308+
}
309+
301310
def_binding(_) { some("binding") }
302311
_ { none }
303312
}

src/comp/middle/resolve.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,7 @@ fn scope_closes(sc: scope) -> option<node_id> {
957957

958958
fn def_is_local(d: def) -> bool {
959959
alt d {
960-
ast::def_arg(_, _) | ast::def_local(_) | ast::def_binding(_) |
960+
ast::def_arg(_, _) | ast::def_local(_, _) | ast::def_binding(_) |
961961
ast::def_upvar(_, _, _) { true }
962962
_ { false }
963963
}
@@ -1235,7 +1235,8 @@ fn lookup_in_block(e: env, name: ident, sp: span, b: ast::blk_, pos: uint,
12351235
&& (i < pos || j < loc_pos) {
12361236
alt lookup_in_pat(e, name, loc.node.pat) {
12371237
some(nid) {
1238-
ret some(ast::def_local(nid));
1238+
ret some(ast::def_local(nid,
1239+
loc.node.is_mutbl));
12391240
}
12401241
_ { }
12411242
}
@@ -1702,7 +1703,7 @@ fn ns_for_def(d: def) -> namespace {
17021703
alt d {
17031704
ast::def_variant(_, _) { ns_val(definite_enum) }
17041705
ast::def_fn(_, _) | ast::def_self(_) |
1705-
ast::def_const(_) | ast::def_arg(_, _) | ast::def_local(_) |
1706+
ast::def_const(_) | ast::def_arg(_, _) | ast::def_local(_, _) |
17061707
ast::def_upvar(_, _, _) | ast::def_self(_) |
17071708
ast::def_class_field(_,_) | ast::def_class_method(_,_)
17081709
{ ns_val(value_or_enum) }

src/comp/middle/trans/base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2253,7 +2253,7 @@ fn trans_local_var(cx: block, def: ast::def) -> local_var_result {
22532253
assert (cx.fcx.llargs.contains_key(nid));
22542254
ret take_local(cx.fcx.llargs, nid);
22552255
}
2256-
ast::def_local(nid) | ast::def_binding(nid) {
2256+
ast::def_local(nid, _) | ast::def_binding(nid) {
22572257
assert (cx.fcx.lllocals.contains_key(nid));
22582258
ret take_local(cx.fcx.lllocals, nid);
22592259
}

src/comp/middle/tstate/auxiliary.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ fn expr_to_constr_arg(tcx: ty::ctxt, e: @expr) -> @constr_arg_use {
576576
alt e.node {
577577
expr_path(p) {
578578
alt tcx.def_map.find(e.id) {
579-
some(def_local(nid)) | some(def_arg(nid, _)) |
579+
some(def_local(nid, _)) | some(def_arg(nid, _)) |
580580
some(def_binding(nid)) | some(def_upvar(nid, _, _)) {
581581
ret @respan(p.span,
582582
carg_ident({ident: p.node.idents[0], node: nid}));
@@ -786,7 +786,7 @@ enum if_ty { if_check, plain_if, }
786786
fn local_node_id_to_def_id_strict(fcx: fn_ctxt, sp: span, i: node_id) ->
787787
def_id {
788788
alt local_node_id_to_def(fcx, i) {
789-
some(def_local(nid)) | some(def_arg(nid, _)) |
789+
some(def_local(nid, _)) | some(def_arg(nid, _)) |
790790
some(def_upvar(nid, _, _)) {
791791
ret local_def(nid);
792792
}
@@ -810,8 +810,8 @@ fn local_node_id_to_def(fcx: fn_ctxt, i: node_id) -> option<def> {
810810

811811
fn local_node_id_to_def_id(fcx: fn_ctxt, i: node_id) -> option<def_id> {
812812
alt local_node_id_to_def(fcx, i) {
813-
some(def_local(nid)) | some(def_arg(nid, _)) | some(def_binding(nid)) |
814-
some(def_upvar(nid, _, _)) {
813+
some(def_local(nid, _)) | some(def_arg(nid, _)) |
814+
some(def_binding(nid)) | some(def_upvar(nid, _, _)) {
815815
some(local_def(nid))
816816
}
817817
_ { none }

src/comp/middle/tstate/bitvectors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ fn clear_in_poststate_expr(fcx: fn_ctxt, e: @expr, t: poststate) {
185185
alt vec::last(p.node.idents) {
186186
some(i) {
187187
alt local_node_id_to_def(fcx, e.id) {
188-
some(def_local(nid)) {
188+
some(def_local(nid, _)) {
189189
clear_in_poststate_(bit_num(fcx, ninit(nid, i)), t);
190190
}
191191
some(_) {/* ignore args (for now...) */ }

src/comp/middle/tstate/pre_post_conditions.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ fn gen_if_local(fcx: fn_ctxt, lhs: @expr, rhs: @expr, larger_id: node_id,
176176
alt node_id_to_def(fcx.ccx, new_var) {
177177
some(d) {
178178
alt d {
179-
def_local(nid) {
179+
def_local(nid, _) {
180180
find_pre_post_expr(fcx, rhs);
181181
let p = expr_pp(fcx.ccx, rhs);
182182
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,
214214
// pure and assign_op require the lhs to be init'd
215215
let df = node_id_to_def_strict(fcx.ccx.tcx, lhs.id);
216216
alt df {
217-
def_local(nid) {
217+
def_local(nid, _) {
218218
let i = bit_num(fcx, ninit(nid, path_to_ident(p)));
219219
require_and_preserve(i, expr_pp(fcx.ccx, lhs));
220220
}
@@ -259,7 +259,7 @@ fn handle_var(fcx: fn_ctxt, rslt: pre_and_post, id: node_id, name: ident) {
259259
fn handle_var_def(fcx: fn_ctxt, rslt: pre_and_post, def: def, name: ident) {
260260
log(debug, ("handle_var_def: ", def, name));
261261
alt def {
262-
def_local(nid) | def_arg(nid, _) {
262+
def_local(nid, _) | def_arg(nid, _) {
263263
use_var(fcx, nid);
264264
let i = bit_num(fcx, ninit(nid, name));
265265
require_and_preserve(i, rslt);

src/comp/middle/tstate/states.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ fn gen_if_local(fcx: fn_ctxt, p: poststate, e: @expr) -> bool {
246246
alt e.node {
247247
expr_path(pth) {
248248
alt fcx.ccx.tcx.def_map.find(e.id) {
249-
some(def_local(nid)) {
249+
some(def_local(nid, _)) {
250250
ret set_in_poststate_ident(fcx, nid, path_to_ident(pth), p);
251251
}
252252
_ { ret false; }

src/comp/middle/typeck.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
101101
let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid));
102102
ret {bounds: @[], ty: typ};
103103
}
104-
ast::def_local(nid) {
104+
ast::def_local(nid, _) {
105105
assert (fcx.locals.contains_key(nid));
106106
let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid));
107107
ret {bounds: @[], ty: typ};

src/comp/syntax/ast.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ enum def {
3838
def_native_mod(def_id),
3939
def_const(def_id),
4040
def_arg(node_id, mode),
41-
def_local(node_id),
41+
def_local(node_id, bool /* is_mutbl */),
4242
def_variant(def_id /* enum */, def_id /* variant */),
4343
def_ty(def_id),
4444
def_prim_ty(prim_ty),
@@ -194,7 +194,8 @@ enum init_op { init_assign, init_move, }
194194
type initializer = {op: init_op, expr: @expr};
195195

196196
type local_ = // FIXME: should really be a refinement on pat
197-
{ty: @ty, pat: @pat, init: option<initializer>, id: node_id};
197+
{is_mutbl: bool, ty: @ty, pat: @pat,
198+
init: option<initializer>, id: node_id};
198199

199200
type local = spanned<local_>;
200201

src/comp/syntax/ast_util.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ fn def_id_of_def(d: def) -> def_id {
4141
def_use(id) |
4242
def_class(id) | def_class_field(_, id) | def_class_method(_, id) { id }
4343

44-
def_self(id) | def_arg(id, _) | def_local(id) |
44+
def_self(id) | def_arg(id, _) | def_local(id, _) |
4545
def_upvar(id, _, _) | def_binding(id) {
4646
local_def(id)
4747
}

src/comp/syntax/fold.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,8 @@ fn noop_fold_path(&&p: path_, fld: ast_fold) -> path_ {
532532
}
533533

534534
fn noop_fold_local(l: local_, fld: ast_fold) -> local_ {
535-
ret {ty: fld.fold_ty(l.ty),
535+
ret {is_mutbl: l.is_mutbl,
536+
ty: fld.fold_ty(l.ty),
536537
pat: fld.fold_pat(l.pat),
537538
init:
538539
alt l.init {

0 commit comments

Comments
 (0)