Remove by-mutable-ref mode from the compiler

and test cases. Closes #3513
This commit is contained in:
Tim Chevalier 2012-10-05 22:07:53 -07:00
parent 05999290e2
commit f96a2a2ca1
26 changed files with 59 additions and 95 deletions

View file

@ -2784,14 +2784,12 @@ aside a copy of that value to refer to. If this is not semantically safe (for
example, if the referred-to value contains mutable fields), it will reject the example, if the referred-to value contains mutable fields), it will reject the
program. If the compiler deems copying the value expensive, it will warn. program. If the compiler deems copying the value expensive, it will warn.
A function can be declared to take an argument by mutable reference. This A function with an argument of type `&mut T`, for some type `T`, can write to
allows the function to write to the slot that the reference refers to. the slot that its argument refers to. An example of such a function is:
An example function that accepts an value by mutable reference:
~~~~~~~~ ~~~~~~~~
fn incr(&i: int) { fn incr(i: &mut int) {
i = i + 1; *i = *i + 1;
} }
~~~~~~~~ ~~~~~~~~

View file

@ -574,7 +574,7 @@ impl<T:cmp::Eq> inferable<T> : cmp::Eq {
// "resolved" mode: the real modes. // "resolved" mode: the real modes.
#[auto_serialize] #[auto_serialize]
enum rmode { by_ref, by_val, by_mutbl_ref, by_move, by_copy } enum rmode { by_ref, by_val, by_move, by_copy }
impl rmode : to_bytes::IterBytes { impl rmode : to_bytes::IterBytes {
pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) {

View file

@ -22,7 +22,8 @@ pub enum ObsoleteSyntax {
ObsoleteClassMethod, ObsoleteClassMethod,
ObsoleteClassTraits, ObsoleteClassTraits,
ObsoletePrivSection, ObsoletePrivSection,
ObsoleteModeInFnType ObsoleteModeInFnType,
ObsoleteByMutRefMode
} }
impl ObsoleteSyntax : cmp::Eq { impl ObsoleteSyntax : cmp::Eq {
@ -94,6 +95,10 @@ impl parser : ObsoleteReporter {
"to use a (deprecated) mode in a fn type, you should \ "to use a (deprecated) mode in a fn type, you should \
give the argument an explicit name (like `&&v: int`)" give the argument an explicit name (like `&&v: int`)"
), ),
ObsoleteByMutRefMode => (
"by-mutable-reference mode",
"Declare an argument of type &mut T instead"
),
}; };
self.report(sp, kind, kind_str, desc); self.report(sp, kind, kind_str, desc);

View file

@ -20,13 +20,13 @@ use obsolete::{
ObsoleteLowerCaseKindBounds, ObsoleteLet, ObsoleteLowerCaseKindBounds, ObsoleteLet,
ObsoleteFieldTerminator, ObsoleteStructCtor, ObsoleteFieldTerminator, ObsoleteStructCtor,
ObsoleteWith, ObsoleteClassMethod, ObsoleteClassTraits, ObsoleteWith, ObsoleteClassMethod, ObsoleteClassTraits,
ObsoleteModeInFnType ObsoleteModeInFnType, ObsoleteByMutRefMode
}; };
use ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute, use ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute,
bind_by_ref, bind_by_implicit_ref, bind_by_value, bind_by_move, bind_by_ref, bind_by_implicit_ref, bind_by_value, bind_by_move,
bitand, bitor, bitxor, blk, blk_check_mode, bound_const, bitand, bitor, bitxor, blk, blk_check_mode, bound_const,
bound_copy, bound_send, bound_trait, bound_owned, box, by_copy, bound_copy, bound_send, bound_trait, bound_owned, box, by_copy,
by_move, by_mutbl_ref, by_ref, by_val, capture_clause, by_move, by_ref, by_val, capture_clause,
capture_item, cdir_dir_mod, cdir_src_mod, cdir_view_item, capture_item, cdir_dir_mod, cdir_src_mod, cdir_view_item,
class_immutable, class_mutable, class_immutable, class_mutable,
crate, crate_cfg, crate_directive, decl, decl_item, decl_local, crate, crate_cfg, crate_directive, decl, decl_item, decl_local,
@ -570,9 +570,10 @@ impl parser {
fn parse_arg_mode() -> mode { fn parse_arg_mode() -> mode {
if self.eat(token::BINOP(token::AND)) { if self.eat(token::BINOP(token::AND)) {
self.span_fatal(copy self.last_span, self.obsolete(copy self.span,
~"Obsolete syntax has no effect"); ObsoleteByMutRefMode);
expl(by_mutbl_ref) // Bogus mode, but doesn't matter since it's an error
expl(by_ref)
} else if self.eat(token::BINOP(token::MINUS)) { } else if self.eat(token::BINOP(token::MINUS)) {
expl(by_move) expl(by_move)
} else if self.eat(token::ANDAND) { } else if self.eat(token::ANDAND) {

View file

@ -1688,7 +1688,6 @@ fn print_fn_block_args(s: ps, decl: ast::fn_decl,
fn mode_to_str(m: ast::mode) -> ~str { fn mode_to_str(m: ast::mode) -> ~str {
match m { match m {
ast::expl(ast::by_mutbl_ref) => ~"&",
ast::expl(ast::by_move) => ~"-", ast::expl(ast::by_move) => ~"-",
ast::expl(ast::by_ref) => ~"&&", ast::expl(ast::by_ref) => ~"&&",
ast::expl(ast::by_val) => ~"++", ast::expl(ast::by_val) => ~"++",

View file

@ -394,7 +394,6 @@ fn parse_arg(st: @pstate, conv: conv_did) -> ty::arg {
fn parse_mode(st: @pstate) -> ast::mode { fn parse_mode(st: @pstate) -> ast::mode {
let m = ast::expl(match next(st) { let m = ast::expl(match next(st) {
'&' => ast::by_mutbl_ref,
'-' => ast::by_move, '-' => ast::by_move,
'+' => ast::by_copy, '+' => ast::by_copy,
'=' => ast::by_ref, '=' => ast::by_ref,

View file

@ -333,7 +333,6 @@ fn enc_arg(w: io::Writer, cx: @ctxt, arg: ty::arg) {
fn enc_mode(w: io::Writer, cx: @ctxt, m: mode) { fn enc_mode(w: io::Writer, cx: @ctxt, m: mode) {
match ty::resolved_mode(cx.tcx, m) { match ty::resolved_mode(cx.tcx, m) {
by_mutbl_ref => w.write_char('&'),
by_move => w.write_char('-'), by_move => w.write_char('-'),
by_copy => w.write_char('+'), by_copy => w.write_char('+'),
by_ref => w.write_char('='), by_ref => w.write_char('='),

View file

@ -529,7 +529,7 @@ impl check_loan_ctxt {
ast::by_move => { ast::by_move => {
self.check_move_out(*arg); self.check_move_out(*arg);
} }
ast::by_mutbl_ref | ast::by_ref | ast::by_ref |
ast::by_copy | ast::by_val => { ast::by_copy | ast::by_val => {
} }
} }

View file

@ -115,10 +115,6 @@ fn req_loans_in_expr(ex: @ast::expr,
let scope_r = ty::re_scope(ex.id); let scope_r = ty::re_scope(ex.id);
for vec::each2(args, arg_tys) |arg, arg_ty| { for vec::each2(args, arg_tys) |arg, arg_ty| {
match ty::resolved_mode(self.tcx(), arg_ty.mode) { match ty::resolved_mode(self.tcx(), arg_ty.mode) {
ast::by_mutbl_ref => {
let arg_cmt = self.bccx.cat_expr(*arg);
self.guarantee_valid(arg_cmt, m_mutbl, scope_r);
}
ast::by_ref => { ast::by_ref => {
let arg_cmt = self.bccx.cat_expr(*arg); let arg_cmt = self.bccx.cat_expr(*arg);
self.guarantee_valid(arg_cmt, m_imm, scope_r); self.guarantee_valid(arg_cmt, m_imm, scope_r);

View file

@ -323,7 +323,7 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
for ty::ty_fn_args(ty::expr_ty(cx.tcx, f)).each |arg_t| { for ty::ty_fn_args(ty::expr_ty(cx.tcx, f)).each |arg_t| {
match ty::arg_mode(cx.tcx, *arg_t) { match ty::arg_mode(cx.tcx, *arg_t) {
by_copy => maybe_copy(cx, args[i], None), by_copy => maybe_copy(cx, args[i], None),
by_ref | by_val | by_mutbl_ref | by_move => () by_ref | by_val | by_move => ()
} }
i += 1u; i += 1u;
} }
@ -335,7 +335,7 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
Some(ref mme) => { Some(ref mme) => {
match ty::arg_mode(cx.tcx, mme.self_arg) { match ty::arg_mode(cx.tcx, mme.self_arg) {
by_copy => maybe_copy(cx, lhs, None), by_copy => maybe_copy(cx, lhs, None),
by_ref | by_val | by_mutbl_ref | by_move => () by_ref | by_val | by_move => ()
} }
} }
_ => () _ => ()
@ -465,14 +465,7 @@ fn check_imm_free_var(cx: ctx, def: def, sp: span) {
cx.tcx.sess.span_err(sp, msg); cx.tcx.sess.span_err(sp, msg);
} }
} }
def_arg(_, mode) => { def_arg(*) => { /* ok */ }
match ty::resolved_mode(cx.tcx, mode) {
by_ref | by_val | by_move | by_copy => { /* ok */ }
by_mutbl_ref => {
cx.tcx.sess.span_err(sp, msg);
}
}
}
def_upvar(_, def1, _, _) => { def_upvar(_, def1, _, _) => {
check_imm_free_var(cx, *def1, sp); check_imm_free_var(cx, *def1, sp);
} }

View file

@ -398,7 +398,7 @@ impl IrMaps {
(*v).push(id); (*v).push(id);
} }
Arg(_, _, by_ref) | Arg(_, _, by_mutbl_ref) | Arg(_, _, by_ref) |
Arg(_, _, by_val) | Self | Field(_) | ImplicitRet | Arg(_, _, by_val) | Self | Field(_) | ImplicitRet |
Local(LocalInfo {kind: FromMatch(bind_by_implicit_ref), _}) => { Local(LocalInfo {kind: FromMatch(bind_by_implicit_ref), _}) => {
debug!("--but it is not owned"); debug!("--but it is not owned");
@ -919,7 +919,7 @@ impl Liveness {
// inputs passed by & mode should be considered live on exit: // inputs passed by & mode should be considered live on exit:
for decl.inputs.each |arg| { for decl.inputs.each |arg| {
match ty::resolved_mode(self.tcx, arg.mode) { match ty::resolved_mode(self.tcx, arg.mode) {
by_mutbl_ref | by_ref | by_val => { by_ref | by_val => {
// These are "non-owned" modes, so register a read at // These are "non-owned" modes, so register a read at
// the end. This will prevent us from moving out of // the end. This will prevent us from moving out of
// such variables but also prevent us from registering // such variables but also prevent us from registering
@ -1573,7 +1573,7 @@ fn check_expr(expr: @expr, &&self: @Liveness, vt: vt<@Liveness>) {
let targs = ty::ty_fn_args(ty::expr_ty(self.tcx, f)); let targs = ty::ty_fn_args(ty::expr_ty(self.tcx, f));
for vec::each2(args, targs) |arg_expr, arg_ty| { for vec::each2(args, targs) |arg_expr, arg_ty| {
match ty::resolved_mode(self.tcx, arg_ty.mode) { match ty::resolved_mode(self.tcx, arg_ty.mode) {
by_val | by_copy | by_ref | by_mutbl_ref => {} by_val | by_copy | by_ref => {}
by_move => { by_move => {
self.check_move_from_expr(*arg_expr, vt); self.check_move_from_expr(*arg_expr, vt);
} }
@ -1865,26 +1865,9 @@ impl @Liveness {
fn warn_about_unused_args(sp: span, decl: fn_decl, entry_ln: LiveNode) { fn warn_about_unused_args(sp: span, decl: fn_decl, entry_ln: LiveNode) {
for decl.inputs.each |arg| { for decl.inputs.each |arg| {
let var = self.variable(arg.id, arg.ty.span); let var = self.variable(arg.id, arg.ty.span);
match ty::resolved_mode(self.tcx, arg.mode) {
by_mutbl_ref => {
// for mutable reference arguments, something like
// x = 1;
// is not worth warning about, as it has visible
// side effects outside the fn.
match self.assigned_on_entry(entry_ln, var) {
Some(_) => { /*ok*/ }
None => {
// but if it is not written, it ought to be used
self.warn_about_unused(sp, entry_ln, var); self.warn_about_unused(sp, entry_ln, var);
} }
} }
}
by_val | by_ref | by_move | by_copy => {
self.warn_about_unused(sp, entry_ln, var);
}
}
}
}
fn warn_about_unused_or_dead_vars_in_pat(pat: @pat) { fn warn_about_unused_or_dead_vars_in_pat(pat: @pat) {
do self.pat_bindings(pat) |ln, var, sp| { do self.pat_bindings(pat) |ln, var, sp| {

View file

@ -523,9 +523,6 @@ impl &mem_categorization_ctxt {
// m: mutability of the argument // m: mutability of the argument
// lp: loan path, must be none for aliasable things // lp: loan path, must be none for aliasable things
let {m,lp} = match ty::resolved_mode(self.tcx, mode) { let {m,lp} = match ty::resolved_mode(self.tcx, mode) {
ast::by_mutbl_ref => {
{m: m_mutbl, lp: None}
}
ast::by_move | ast::by_copy => { ast::by_move | ast::by_copy => {
{m: m_imm, lp: Some(@lp_arg(vid))} {m: m_imm, lp: Some(@lp_arg(vid))}
} }

View file

@ -1503,7 +1503,7 @@ fn copy_args_to_allocas(fcx: fn_ctxt,
// the event it's not truly needed. // the event it's not truly needed.
let llarg; let llarg;
match ty::resolved_mode(tcx, arg_ty.mode) { match ty::resolved_mode(tcx, arg_ty.mode) {
ast::by_ref | ast::by_mutbl_ref => { ast::by_ref => {
llarg = raw_llarg; llarg = raw_llarg;
} }
ast::by_move | ast::by_copy => { ast::by_move | ast::by_copy => {

View file

@ -592,7 +592,7 @@ fn trans_arg_expr(bcx: block,
DoAutorefArg => { val = arg_datum.to_ref_llval(bcx); } DoAutorefArg => { val = arg_datum.to_ref_llval(bcx); }
DontAutorefArg => { DontAutorefArg => {
match arg_mode { match arg_mode {
ast::by_ref | ast::by_mutbl_ref => { ast::by_ref => {
val = arg_datum.to_ref_llval(bcx); val = arg_datum.to_ref_llval(bcx);
} }

View file

@ -154,7 +154,7 @@ fn trans_method_callee(bcx: block, callee_id: ast::node_id,
typeck::method_trait(_, off, vstore) => { typeck::method_trait(_, off, vstore) => {
trans_trait_callee(bcx, callee_id, off, self, vstore) trans_trait_callee(bcx, callee_id, off, self, vstore)
} }
typeck::method_self(_, off) => { typeck::method_self(*) => {
bcx.tcx().sess.span_bug(self.span, ~"self method call"); bcx.tcx().sess.span_bug(self.span, ~"self method call");
} }
} }

View file

@ -210,7 +210,6 @@ impl reflector {
ast::expl(e) => match e { ast::expl(e) => match e {
ast::by_ref => 1u, ast::by_ref => 1u,
ast::by_val => 2u, ast::by_val => 2u,
ast::by_mutbl_ref => 3u,
ast::by_move => 4u, ast::by_move => 4u,
ast::by_copy => 5u ast::by_copy => 5u
} }

View file

@ -53,7 +53,7 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint)
by_val | by_move | by_copy => { by_val | by_move | by_copy => {
type_needs(cx, use_repr, arg.ty); type_needs(cx, use_repr, arg.ty);
} }
by_ref | by_mutbl_ref => {} by_ref => {}
} }
} }
} }

View file

@ -144,7 +144,7 @@ mod map_reduce {
fn start_mappers<K1: Copy Send, K2: Hash IterBytes Eq Const Copy Send, fn start_mappers<K1: Copy Send, K2: Hash IterBytes Eq Const Copy Send,
V: Copy Send>( V: Copy Send>(
map: &mapper<K1, K2, V>, map: &mapper<K1, K2, V>,
&ctrls: ~[ctrl_proto::server::open<K2, V>], ctrls: &mut ~[ctrl_proto::server::open<K2, V>],
inputs: &~[K1]) inputs: &~[K1])
-> ~[joinable_task] -> ~[joinable_task]
{ {
@ -213,9 +213,9 @@ mod map_reduce {
let mut is_done = false; let mut is_done = false;
fn get<V: Copy Send>(p: Port<reduce_proto<V>>, fn get<V: Copy Send>(p: Port<reduce_proto<V>>,
&ref_count: int, &is_done: bool) ref_count: &mut int, is_done: &mut bool)
-> Option<V> { -> Option<V> {
while !is_done || ref_count > 0 { while !*is_done || *ref_count > 0 {
match recv(p) { match recv(p) {
emit_val(v) => { emit_val(v) => {
// error!("received %d", v); // error!("received %d", v);
@ -223,16 +223,16 @@ mod map_reduce {
} }
done => { done => {
// error!("all done"); // error!("all done");
is_done = true; *is_done = true;
} }
addref => { ref_count += 1; } addref => { *ref_count += 1; }
release => { ref_count -= 1; } release => { *ref_count -= 1; }
} }
} }
return None; return None;
} }
(*reduce)(&key, || get(p, ref_count, is_done) ); (*reduce)(&key, || get(p, &mut ref_count, &mut is_done) );
} }
fn map_reduce<K1: Copy Send, K2: Hash IterBytes Eq Const Copy Send, V: Copy Send>( fn map_reduce<K1: Copy Send, K2: Hash IterBytes Eq Const Copy Send, V: Copy Send>(
@ -246,7 +246,7 @@ mod map_reduce {
// to do the rest. // to do the rest.
let reducers = map::HashMap(); let reducers = map::HashMap();
let mut tasks = start_mappers(&map, ctrl, &inputs); let mut tasks = start_mappers(&map, &mut ctrl, &inputs);
let mut num_mappers = vec::len(inputs) as int; let mut num_mappers = vec::len(inputs) as int;
while num_mappers > 0 { while num_mappers > 0 {

View file

@ -1,11 +1,9 @@
#[forbid(deprecated_mode)]; #[forbid(deprecated_mode)];
fn foo(_f: fn(&i: int)) { //~ ERROR explicit mode fn foo(_f: fn(&i: int)) { //~ ERROR by-mutable-reference mode
//~^ WARNING Obsolete syntax has no effect
} }
type Bar = fn(&i: int); //~ ERROR explicit mode type Bar = fn(&i: int); //~ ERROR by-mutable-reference mode
//~^ WARNING Obsolete syntax has no effect
fn main() { fn main() {
} }

View file

@ -1,11 +1,8 @@
//error-pattern: mismatched types //error-pattern: by-mutable-reference mode
fn bad(&a: int) { fn bad(&a: int) {
} }
// unnamed argument &int is now parsed x: &int
// it's not parsed &x: int anymore
fn called(f: fn(&int)) { fn called(f: fn(&int)) {
} }

View file

@ -1,10 +1,10 @@
// xfail-fast // xfail-fast
#[legacy_modes]; #[legacy_modes];
fn f1(a: {mut x: int}, &b: int, -c: int) -> int { fn f1(a: {mut x: int}, b: &mut int, -c: int) -> int {
let r = a.x + b + c; let r = a.x + *b + c;
a.x = 0; a.x = 0;
b = 10; *b = 10;
return r; return r;
} }
@ -12,7 +12,7 @@ fn f2(a: int, f: fn(int)) -> int { f(1); return a; }
fn main() { fn main() {
let mut a = {mut x: 1}, b = 2, c = 3; let mut a = {mut x: 1}, b = 2, c = 3;
assert (f1(a, b, c) == 6); assert (f1(a, &mut b, c) == 6);
assert (a.x == 0); assert (a.x == 0);
assert (b == 10); assert (b == 10);
assert (f2(a.x, |x| a.x = 50 ) == 0); assert (f2(a.x, |x| a.x = 50 ) == 0);

View file

@ -1,15 +1,15 @@
fn f(i: int, &called: bool) { fn f(i: int, called: &mut bool) {
assert i == 10; assert i == 10;
called = true; *called = true;
} }
fn g(f: extern fn(int, &v: bool), &called: bool) { fn g(f: extern fn(int, v: &mut bool), called: &mut bool) {
f(10, called); f(10, called);
} }
fn main() { fn main() {
let mut called = false; let mut called = false;
let h = f; let h = f;
g(h, called); g(h, &mut called);
assert called == true; assert called == true;
} }

View file

@ -1,12 +1,12 @@
fn incr(&x: int) -> bool { x += 1; assert (false); return false; } fn incr(x: &mut int) -> bool { *x += 1; assert (false); return false; }
fn main() { fn main() {
let x = 1 == 2 || 3 == 3; let x = 1 == 2 || 3 == 3;
assert (x); assert (x);
let mut y: int = 10; let mut y: int = 10;
log(debug, x || incr(y)); log(debug, x || incr(&mut y));
assert (y == 10); assert (y == 10);
if true && x { assert (true); } else { assert (false); } if true && x { assert (true); } else { assert (false); }
} }

View file

@ -3,13 +3,13 @@
// -*- rust -*- // -*- rust -*-
extern mod std; extern mod std;
fn grow(&v: ~[int]) { v += ~[1]; } fn grow(v: &mut ~[int]) { *v += ~[1]; }
fn main() { fn main() {
let mut v: ~[int] = ~[]; let mut v: ~[int] = ~[];
grow(v); grow(&mut v);
grow(v); grow(&mut v);
grow(v); grow(&mut v);
let len = vec::len::<int>(v); let len = vec::len::<int>(v);
log(debug, len); log(debug, len);
assert (len == 3 as uint); assert (len == 3 as uint);

View file

@ -1,9 +1,9 @@
fn f(&i: ~int) { fn f(i: &mut ~int) {
i = ~200; *i = ~200;
} }
fn main() { fn main() {
let mut i = ~100; let mut i = ~100;
f(i); f(&mut i);
assert *i == 200; assert *i == 200;
} }

View file

@ -4,10 +4,10 @@
// -*- rust -*- // -*- rust -*-
type point = {x: int, y: int, mut z: int}; type point = {x: int, y: int, mut z: int};
fn f(&p: point) { p.z = 13; } fn f(p: &mut point) { p.z = 13; }
fn main() { fn main() {
let mut x: point = {x: 10, y: 11, mut z: 12}; let mut x: point = {x: 10, y: 11, mut z: 12};
f(x); f(&mut x);
assert (x.z == 13); assert (x.z == 13);
} }