auto merge of #10026 : luqmana/rust/mut-pat, r=pcwalton

Fixes #9792.
This commit is contained in:
bors 2013-10-27 09:51:21 -07:00
commit 16b8a41531
24 changed files with 224 additions and 168 deletions

View File

@ -730,7 +730,7 @@ impl<'self> GatherLoanCtxt<'self> {
loan_mutability,
scope_r);
}
ast::BindInfer => {
ast::BindByValue(_) => {
// No borrows here, but there may be moves
if self.bccx.is_move(pat.id) {
gather_moves::gather_move_from_pat(

View File

@ -884,7 +884,7 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
BindByRef(_) => {
by_ref_span = Some(span);
}
BindInfer => {
BindByValue(_) => {
if cx.moves_map.contains(&id) {
any_by_move = true;
}

View File

@ -432,14 +432,12 @@ fn is_nullary_variant(cx: &Context, ex: @Expr) -> bool {
fn check_imm_free_var(cx: &Context, def: Def, sp: Span) {
match def {
DefLocal(_, is_mutbl) => {
if is_mutbl {
cx.tcx.sess.span_err(
sp,
"mutable variables cannot be implicitly captured");
}
DefLocal(_, BindByValue(MutMutable)) => {
cx.tcx.sess.span_err(
sp,
"mutable variables cannot be implicitly captured");
}
DefArg(*) => { /* ok */ }
DefLocal(*) | DefArg(*) => { /* ok */ }
DefUpvar(_, def1, _, _) => { check_imm_free_var(cx, *def1, sp); }
DefBinding(*) | DefSelf(*) => { /*ok*/ }
_ => {

View File

@ -813,27 +813,24 @@ fn check_unused_unsafe(cx: &Context, e: &ast::Expr) {
}
fn check_unused_mut_pat(cx: &Context, p: @ast::Pat) {
let mut used = false;
let mut bindings = 0;
do pat_util::pat_bindings(cx.tcx.def_map, p) |_, id, _, _| {
used = used || cx.tcx.used_mut_nodes.contains(&id);
bindings += 1;
}
if !used {
let msg = if bindings == 1 {
"variable does not need to be mutable"
} else {
"variables do not need to be mutable"
};
cx.span_lint(unused_mut, p.span, msg);
}
}
fn check_unused_mut_fn_decl(cx: &Context, fd: &ast::fn_decl) {
for arg in fd.inputs.iter() {
if arg.is_mutbl {
check_unused_mut_pat(cx, arg.pat);
match p.node {
ast::PatIdent(ast::BindByValue(ast::MutMutable), _, _) => {
let mut used = false;
let mut bindings = 0;
do pat_util::pat_bindings(cx.tcx.def_map, p) |_, id, _, _| {
used = used || cx.tcx.used_mut_nodes.contains(&id);
bindings += 1;
}
if !used {
let msg = if bindings == 1 {
"variable does not need to be mutable"
} else {
"variables do not need to be mutable"
};
cx.span_lint(unused_mut, p.span, msg);
}
}
_ => ()
}
}
@ -1075,6 +1072,8 @@ impl Visitor<()> for Context {
fn visit_pat(&mut self, p: @ast::Pat, _: ()) {
check_pat_non_uppercase_statics(self, p);
check_unused_mut_pat(self, p);
visit::walk_pat(self, p, ());
}
@ -1095,30 +1094,9 @@ impl Visitor<()> for Context {
visit::walk_stmt(self, s, ());
}
fn visit_ty_method(&mut self, tm: &ast::TypeMethod, _: ()) {
check_unused_mut_fn_decl(self, &tm.decl);
visit::walk_ty_method(self, tm, ());
}
fn visit_trait_method(&mut self, tm: &ast::trait_method, _: ()) {
match *tm {
ast::required(ref m) => check_unused_mut_fn_decl(self, &m.decl),
ast::provided(ref m) => check_unused_mut_fn_decl(self, &m.decl)
}
visit::walk_trait_method(self, tm, ());
}
fn visit_local(&mut self, l: @ast::Local, _: ()) {
if l.is_mutbl {
check_unused_mut_pat(self, l.pat);
}
visit::walk_local(self, l, ());
}
fn visit_fn(&mut self, fk: &visit::fn_kind, decl: &ast::fn_decl,
body: &ast::Block, span: Span, id: ast::NodeId, _: ()) {
let recurse = |this: &mut Context| {
check_unused_mut_fn_decl(this, decl);
visit::walk_fn(this, fk, decl, body, span, id, ());
};

View File

@ -429,7 +429,7 @@ fn visit_fn(v: &mut LivenessVisitor,
fn visit_local(v: &mut LivenessVisitor, local: @Local, this: @mut IrMaps) {
let def_map = this.tcx.def_map;
do pat_util::pat_bindings(def_map, local.pat) |_bm, p_id, sp, path| {
do pat_util::pat_bindings(def_map, local.pat) |bm, p_id, sp, path| {
debug!("adding local variable {}", p_id);
let name = ast_util::path_to_ident(path);
this.add_live_node_for_node(p_id, VarDefNode(sp));
@ -437,10 +437,14 @@ fn visit_local(v: &mut LivenessVisitor, local: @Local, this: @mut IrMaps) {
Some(_) => FromLetWithInitializer,
None => FromLetNoInitializer
};
let mutbl = match bm {
BindByValue(MutMutable) => true,
_ => false
};
this.add_variable(Local(LocalInfo {
id: p_id,
ident: name,
is_mutbl: local.is_mutbl,
is_mutbl: mutbl,
kind: kind
}));
}
@ -454,11 +458,15 @@ fn visit_arm(v: &mut LivenessVisitor, arm: &Arm, this: @mut IrMaps) {
debug!("adding local variable {} from match with bm {:?}",
p_id, bm);
let name = ast_util::path_to_ident(path);
let mutbl = match bm {
BindByValue(MutMutable) => true,
_ => false
};
this.add_live_node_for_node(p_id, VarDefNode(sp));
this.add_variable(Local(LocalInfo {
id: p_id,
ident: name,
is_mutbl: false,
is_mutbl: mutbl,
kind: FromMatch(bm)
}));
}

View File

@ -473,12 +473,15 @@ impl mem_categorization_ctxt {
}
}
ast::DefArg(vid, mutbl) => {
ast::DefArg(vid, binding_mode) => {
// Idea: make this could be rewritten to model by-ref
// stuff as `&const` and `&mut`?
// m: mutability of the argument
let m = if mutbl {McDeclared} else {McImmutable};
let m = match binding_mode {
ast::BindByValue(ast::MutMutable) => McDeclared,
_ => McImmutable
};
@cmt_ {
id: id,
span: span,
@ -548,25 +551,20 @@ impl mem_categorization_ctxt {
}
}
ast::DefLocal(vid, mutbl) => {
let m = if mutbl {McDeclared} else {McImmutable};
@cmt_ {
id:id,
span:span,
cat:cat_local(vid),
mutbl:m,
ty:expr_ty
}
}
ast::DefBinding(vid, _) => {
ast::DefLocal(vid, binding_mode) |
ast::DefBinding(vid, binding_mode) => {
// by-value/by-ref bindings are local variables
let m = match binding_mode {
ast::BindByValue(ast::MutMutable) => McDeclared,
_ => McImmutable
};
@cmt_ {
id:id,
span:span,
cat:cat_local(vid),
mutbl:McImmutable,
ty:expr_ty
id: id,
span: span,
cat: cat_local(vid),
mutbl: m,
ty: expr_ty
}
}
}

View File

@ -618,7 +618,7 @@ impl VisitContext {
do pat_bindings(self.tcx.def_map, pat) |bm, id, _span, path| {
let binding_moves = match bm {
BindByRef(_) => false,
BindInfer => {
BindByValue(_) => {
let pat_ty = ty::node_id_to_type(self.tcx, id);
debug!("pattern {:?} {} type is {}",
id,

View File

@ -3817,11 +3817,8 @@ impl Resolver {
Some(declaration) => {
for argument in declaration.inputs.iter() {
let binding_mode = ArgumentIrrefutableMode;
let mutability =
if argument.is_mutbl {Mutable} else {Immutable};
this.resolve_pattern(argument.pat,
binding_mode,
mutability,
None);
this.resolve_type(&argument.ty);
@ -4036,8 +4033,6 @@ impl Resolver {
}
fn resolve_local(&mut self, local: @Local) {
let mutability = if local.is_mutbl {Mutable} else {Immutable};
// Resolve the type.
self.resolve_type(&local.ty);
@ -4052,7 +4047,7 @@ impl Resolver {
}
// Resolve the pattern.
self.resolve_pattern(local.pat, LocalIrrefutableMode, mutability, None);
self.resolve_pattern(local.pat, LocalIrrefutableMode, None);
}
// build a map from pattern identifiers to binding-info's.
@ -4116,8 +4111,7 @@ impl Resolver {
let bindings_list = @mut HashMap::new();
for pattern in arm.pats.iter() {
self.resolve_pattern(*pattern, RefutableMode, Immutable,
Some(bindings_list));
self.resolve_pattern(*pattern, RefutableMode, Some(bindings_list));
}
// This has to happen *after* we determine which
@ -4261,7 +4255,6 @@ impl Resolver {
fn resolve_pattern(&mut self,
pattern: @Pat,
mode: PatternBindingMode,
mutability: Mutability,
// Maps idents to the node ID for the (outermost)
// pattern that binds them
bindings_list: Option<@mut HashMap<Name,NodeId>>) {
@ -4324,8 +4317,6 @@ impl Resolver {
debug!("(resolving pattern) binding `{}`",
interner_get(renamed));
let is_mutable = mutability == Mutable;
let def = match mode {
RefutableMode => {
// For pattern arms, we must use
@ -4335,11 +4326,11 @@ impl Resolver {
}
LocalIrrefutableMode => {
// But for locals, we use `def_local`.
DefLocal(pattern.id, is_mutable)
DefLocal(pattern.id, binding_mode)
}
ArgumentIrrefutableMode => {
// And for function arguments, `def_arg`.
DefArg(pattern.id, is_mutable)
DefArg(pattern.id, binding_mode)
}
};
@ -5361,7 +5352,7 @@ impl Resolver {
pat_binding_mode: BindingMode,
descr: &str) {
match pat_binding_mode {
BindInfer => {}
BindByValue(_) => {}
BindByRef(*) => {
self.resolve_error(
pat.span,

View File

@ -1842,7 +1842,7 @@ fn create_bindings_map(bcx: @mut Block, pat: @ast::Pat) -> BindingsMap {
let llmatch;
let trmode;
match bm {
ast::BindInfer => {
ast::BindByValue(_) => {
// in this case, the final type of the variable will be T,
// but during matching we need to store a *T as explained
// above
@ -2130,7 +2130,7 @@ fn bind_irrefutable_pat(bcx: @mut Block,
bcx, pat.id, path, binding_mode,
|bcx, variable_ty, llvariable_val| {
match pat_binding_mode {
ast::BindInfer => {
ast::BindByValue(_) => {
// By value binding: move the value that `val`
// points at into the binding's stack slot.
let datum = Datum {val: val,
@ -2241,7 +2241,7 @@ fn bind_irrefutable_pat(bcx: @mut Block,
fn simple_identifier<'a>(pat: &'a ast::Pat) -> Option<&'a ast::Path> {
match pat.node {
ast::PatIdent(ast::BindInfer, ref path, None) => {
ast::PatIdent(ast::BindByValue(_), ref path, None) => {
Some(path)
}
_ => {

View File

@ -2065,7 +2065,6 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
// Translate variant arguments to function arguments.
let fn_args = do args.map |varg| {
ast::arg {
is_mutbl: false,
ty: (*varg.ty()).clone(),
pat: ast_util::ident_to_pat(
ccx.tcx.sess.next_node_id(),

View File

@ -476,7 +476,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::Pat, expected: ty::t) {
demand::eqtype(fcx, pat.span, region_ty, typ);
}
// otherwise the type of x is the expected type T
ast::BindInfer => {
ast::BindByValue(_) => {
demand::eqtype(fcx, pat.span, expected, typ);
}
}

View File

@ -232,8 +232,8 @@ pub enum Def {
DefMod(DefId),
DefForeignMod(DefId),
DefStatic(DefId, bool /* is_mutbl */),
DefArg(NodeId, bool /* is_mutbl */),
DefLocal(NodeId, bool /* is_mutbl */),
DefArg(NodeId, BindingMode),
DefLocal(NodeId, BindingMode),
DefVariant(DefId /* enum */, DefId /* variant */, bool /* is_structure */),
DefTy(DefId),
DefTrait(DefId),
@ -324,7 +324,7 @@ pub struct FieldPat {
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum BindingMode {
BindByRef(Mutability),
BindInfer
BindByValue(Mutability),
}
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
@ -445,7 +445,6 @@ pub enum Stmt_ {
// a refinement on pat.
#[deriving(Eq, Encodable, Decodable,IterBytes)]
pub struct Local {
is_mutbl: bool,
ty: Ty,
pat: @Pat,
init: Option<@Expr>,
@ -880,7 +879,6 @@ pub struct inline_asm {
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub struct arg {
is_mutbl: bool,
ty: Ty,
pat: @Pat,
id: NodeId,

View File

@ -234,7 +234,7 @@ pub fn ident_to_path(s: Span, identifier: Ident) -> Path {
pub fn ident_to_pat(id: NodeId, s: Span, i: Ident) -> @Pat {
@ast::Pat { id: id,
node: PatIdent(BindInfer, ident_to_path(s, i), None),
node: PatIdent(BindByValue(MutImmutable), ident_to_path(s, i), None),
span: s }
}

View File

@ -399,9 +399,12 @@ impl AstBuilder for @ExtCtxt {
}
fn stmt_let(&self, sp: Span, mutbl: bool, ident: ast::Ident, ex: @ast::Expr) -> @ast::Stmt {
let pat = self.pat_ident(sp, ident);
let pat = if mutbl {
self.pat_ident_binding_mode(sp, ident, ast::BindByValue(ast::MutMutable))
} else {
self.pat_ident(sp, ident)
};
let local = @ast::Local {
is_mutbl: mutbl,
ty: self.ty_infer(sp),
pat: pat,
init: Some(ex),
@ -419,9 +422,12 @@ impl AstBuilder for @ExtCtxt {
typ: ast::Ty,
ex: @ast::Expr)
-> @ast::Stmt {
let pat = self.pat_ident(sp, ident);
let pat = if mutbl {
self.pat_ident_binding_mode(sp, ident, ast::BindByValue(ast::MutMutable))
} else {
self.pat_ident(sp, ident)
};
let local = @ast::Local {
is_mutbl: mutbl,
ty: typ,
pat: pat,
init: Some(ex),
@ -624,7 +630,7 @@ impl AstBuilder for @ExtCtxt {
self.pat(span, ast::PatLit(expr))
}
fn pat_ident(&self, span: Span, ident: ast::Ident) -> @ast::Pat {
self.pat_ident_binding_mode(span, ident, ast::BindInfer)
self.pat_ident_binding_mode(span, ident, ast::BindByValue(ast::MutImmutable))
}
fn pat_ident_binding_mode(&self,
@ -710,7 +716,6 @@ impl AstBuilder for @ExtCtxt {
fn arg(&self, span: Span, ident: ast::Ident, ty: ast::Ty) -> ast::arg {
let arg_pat = self.pat_ident(span, ident);
ast::arg {
is_mutbl: false,
ty: ty,
pat: arg_pat,
id: ast::DUMMY_NODE_ID

View File

@ -922,7 +922,7 @@ fn create_struct_pattern(cx: @ExtCtxt,
if struct_def.fields.is_empty() {
return (
cx.pat_ident_binding_mode(
span, struct_ident, ast::BindInfer),
span, struct_ident, ast::BindByValue(ast::MutImmutable)),
~[]);
}
@ -985,7 +985,7 @@ fn create_enum_variant_pattern(cx: @ExtCtxt,
ast::tuple_variant_kind(ref variant_args) => {
if variant_args.is_empty() {
return (cx.pat_ident_binding_mode(
span, variant_ident, ast::BindInfer), ~[]);
span, variant_ident, ast::BindByValue(ast::MutImmutable)), ~[]);
}
let matching_path = cx.path_ident(span, variant_ident);

View File

@ -551,13 +551,13 @@ fn expand_non_macro_stmt(exts: SyntaxEnv, s: &Stmt, fld: &MacroExpander)
let pending_renames = block_info.pending_renames;
// take it apart:
let @Local{is_mutbl:is_mutbl,
ty:_,
pat:pat,
init:init,
id:id,
span:span
} = *local;
let @Local {
ty: _,
pat: pat,
init: init,
id: id,
span: span
} = *local;
// types can't be copied automatically because of the owned ptr in ty_tup...
let ty = local.ty.clone();
// expand the pat (it might contain exprs... #:(o)>
@ -585,7 +585,6 @@ fn expand_non_macro_stmt(exts: SyntaxEnv, s: &Stmt, fld: &MacroExpander)
let new_init_opt = init.map(|e| fld.fold_expr(e));
let rewritten_local =
@Local {
is_mutbl: is_mutbl,
ty: ty,
pat: rewritten_pat,
init: new_init_opt,

View File

@ -356,7 +356,6 @@ pub trait ast_fold {
fn fold_local(&self, l: @Local) -> @Local {
@Local {
is_mutbl: l.is_mutbl,
ty: self.fold_ty(&l.ty),
pat: self.fold_pat(l.pat),
init: l.init.map(|e| self.fold_expr(e)),
@ -426,7 +425,6 @@ fn fold_attribute_<T:ast_fold>(at: Attribute, fld: &T) -> Attribute {
//used in noop_fold_foreign_item and noop_fold_fn_decl
fn fold_arg_<T:ast_fold>(a: &arg, fld: &T) -> arg {
ast::arg {
is_mutbl: a.is_mutbl,
ty: fld.fold_ty(&a.ty),
pat: fld.fold_pat(a.pat),
id: fld.new_id(a.id),

View File

@ -639,7 +639,7 @@ mod test {
assert_eq!(parser.parse_pat(),
@ast::Pat{id: ast::DUMMY_NODE_ID,
node: ast::PatIdent(
ast::BindInfer,
ast::BindByValue(ast::MutImmutable),
ast::Path {
span:sp(0,1),
global:false,
@ -666,7 +666,6 @@ mod test {
id: ast::DUMMY_NODE_ID,
node: ast::item_fn(ast::fn_decl{
inputs: ~[ast::arg{
is_mutbl: false,
ty: ast::Ty{id: ast::DUMMY_NODE_ID,
node: ast::ty_path(ast::Path{
span:sp(10,13),
@ -685,7 +684,7 @@ mod test {
pat: @ast::Pat {
id: ast::DUMMY_NODE_ID,
node: ast::PatIdent(
ast::BindInfer,
ast::BindByValue(ast::MutImmutable),
ast::Path {
span:sp(6,7),
global:false,

View File

@ -34,7 +34,6 @@ pub enum ObsoleteSyntax {
ObsoleteBareFnType,
ObsoleteNamedExternModule,
ObsoleteMultipleLocalDecl,
ObsoleteMutWithMultipleBindings,
ObsoleteUnsafeExternFn,
ObsoleteTraitFuncVisibility,
ObsoleteConstPointer,
@ -91,11 +90,6 @@ impl ParserObsoleteMethods for Parser {
"instead of e.g. `let a = 1, b = 2`, write \
`let (a, b) = (1, 2)`."
),
ObsoleteMutWithMultipleBindings => (
"`mut` with multiple bindings",
"use multiple local declarations instead of e.g. `let mut \
(x, y) = ...`."
),
ObsoleteUnsafeExternFn => (
"unsafe external function",
"external functions are always unsafe; remove the `unsafe` \

View File

@ -17,7 +17,7 @@ use ast::{CallSugar, NoSugar, DoSugar};
use ast::{TyBareFn, TyClosure};
use ast::{RegionTyParamBound, TraitTyParamBound};
use ast::{provided, public, purity};
use ast::{_mod, BiAdd, arg, Arm, Attribute, BindByRef, BindInfer};
use ast::{_mod, BiAdd, arg, Arm, Attribute, BindByRef, BindByValue};
use ast::{BiBitAnd, BiBitOr, BiBitXor, Block};
use ast::{BlockCheckMode, UnBox};
use ast::{Crate, CrateConfig, Decl, DeclItem};
@ -1184,15 +1184,8 @@ impl Parser {
pub fn is_named_argument(&self) -> bool {
let offset = match *self.token {
token::BINOP(token::AND) => 1,
token::BINOP(token::MINUS) => 1,
token::ANDAND => 1,
token::BINOP(token::PLUS) => {
if self.look_ahead(1, |t| *t == token::BINOP(token::PLUS)) {
2
} else {
1
}
},
_ if token::is_keyword(keywords::Mut, self.token) => 1,
_ => 0
};
@ -1210,16 +1203,11 @@ impl Parser {
// This version of parse arg doesn't necessarily require
// identifier names.
pub fn parse_arg_general(&self, require_name: bool) -> arg {
let is_mutbl = self.eat_keyword(keywords::Mut);
let pat = if require_name || self.is_named_argument() {
debug!("parse_arg_general parse_pat (require_name:{:?})",
require_name);
let pat = self.parse_pat();
if is_mutbl && !ast_util::pat_is_ident(pat) {
self.obsolete(*self.span, ObsoleteMutWithMultipleBindings)
}
self.expect(&token::COLON);
pat
} else {
@ -1232,7 +1220,6 @@ impl Parser {
let t = self.parse_ty(false);
ast::arg {
is_mutbl: is_mutbl,
ty: t,
pat: pat,
id: ast::DUMMY_NODE_ID,
@ -1246,7 +1233,6 @@ impl Parser {
// parse an argument in a lambda header e.g. |arg, arg|
pub fn parse_fn_block_arg(&self) -> arg {
let is_mutbl = self.eat_keyword(keywords::Mut);
let pat = self.parse_pat();
let t = if self.eat(&token::COLON) {
self.parse_ty(false)
@ -1258,7 +1244,6 @@ impl Parser {
}
};
ast::arg {
is_mutbl: is_mutbl,
ty: t,
pat: pat,
id: ast::DUMMY_NODE_ID
@ -1809,7 +1794,7 @@ impl Parser {
return self.mk_mac_expr(lo, hi, mac_invoc_tt(pth, tts, EMPTY_CTXT));
} else if *self.token == token::LBRACE {
// This might be a struct literal.
if self.looking_at_record_literal() {
if self.looking_at_struct_literal() {
// It's a struct literal.
self.bump();
let mut fields = ~[];
@ -2520,12 +2505,11 @@ impl Parser {
}
}
// For distingishing between record literals and blocks
fn looking_at_record_literal(&self) -> bool {
// For distingishing between struct literals and blocks
fn looking_at_struct_literal(&self) -> bool {
*self.token == token::LBRACE &&
(self.look_ahead(1, |t| token::is_keyword(keywords::Mut, t)) ||
(self.look_ahead(1, |t| token::is_plain_ident(t)) &&
self.look_ahead(2, |t| *t == token::COLON)))
(self.look_ahead(1, |t| token::is_plain_ident(t)) &&
self.look_ahead(2, |t| *t == token::COLON))
}
fn parse_match_expr(&self) -> @Expr {
@ -2681,7 +2665,7 @@ impl Parser {
} else {
subpat = @ast::Pat {
id: ast::DUMMY_NODE_ID,
node: PatIdent(BindInfer, fieldpath, None),
node: PatIdent(BindByValue(MutImmutable), fieldpath, None),
span: *self.last_span
};
}
@ -2863,6 +2847,8 @@ impl Parser {
} else {
pat = PatLit(val);
}
} else if self.eat_keyword(keywords::Mut) {
pat = self.parse_pat_ident(BindByValue(MutMutable));
} else if self.eat_keyword(keywords::Ref) {
// parse ref pat
let mutbl = self.parse_mutability();
@ -2891,7 +2877,7 @@ impl Parser {
// or just foo
sub = None;
}
pat = PatIdent(BindInfer, name, sub);
pat = PatIdent(BindByValue(MutImmutable), name, sub);
} else {
// parse an enum pat
let enum_path = self.parse_path(LifetimeAndTypesWithColons)
@ -2935,7 +2921,7 @@ impl Parser {
// it could still be either an enum
// or an identifier pattern, resolve
// will sort it out:
pat = PatIdent(BindInfer,
pat = PatIdent(BindByValue(MutImmutable),
enum_path,
None);
} else {
@ -2989,14 +2975,10 @@ impl Parser {
}
// parse a local variable declaration
fn parse_local(&self, is_mutbl: bool) -> @Local {
fn parse_local(&self) -> @Local {
let lo = self.span.lo;
let pat = self.parse_pat();
if is_mutbl && !ast_util::pat_is_ident(pat) {
self.obsolete(*self.span, ObsoleteMutWithMultipleBindings)
}
let mut ty = Ty {
id: ast::DUMMY_NODE_ID,
node: ty_infer,
@ -3005,7 +2987,6 @@ impl Parser {
if self.eat(&token::COLON) { ty = self.parse_ty(false); }
let init = self.parse_initializer();
@ast::Local {
is_mutbl: is_mutbl,
ty: ty,
pat: pat,
init: init,
@ -3016,11 +2997,10 @@ impl Parser {
// parse a "let" stmt
fn parse_let(&self) -> @Decl {
let is_mutbl = self.eat_keyword(keywords::Mut);
let lo = self.span.lo;
let local = self.parse_local(is_mutbl);
let local = self.parse_local();
while self.eat(&token::COMMA) {
let _ = self.parse_local(is_mutbl);
let _ = self.parse_local();
self.obsolete(*self.span, ObsoleteMultipleLocalDecl);
}
return @spanned(lo, self.last_span.hi, DeclLocal(local));

View File

@ -1476,10 +1476,6 @@ pub fn print_decl(s: @ps, decl: &ast::Decl) {
ibox(s, indent_unit);
word_nbsp(s, "let");
if loc.is_mutbl {
word_nbsp(s, "mut");
}
fn print_local(s: @ps, loc: &ast::Local) {
ibox(s, indent_unit);
print_local_decl(s, loc);
@ -1589,7 +1585,10 @@ pub fn print_pat(s: @ps, pat: &ast::Pat) {
word_nbsp(s, "ref");
print_mutability(s, mutbl);
}
ast::BindInfer => {}
ast::BindByValue(ast::MutImmutable) => {}
ast::BindByValue(ast::MutMutable) => {
word_nbsp(s, "mut");
}
}
print_path(s, path, true);
match sub {
@ -1932,9 +1931,6 @@ pub fn print_mt(s: @ps, mt: &ast::mt) {
pub fn print_arg(s: @ps, input: &ast::arg) {
ibox(s, indent_unit);
if input.is_mutbl {
word_space(s, "mut");
}
match input.ty.node {
ast::ty_infer => print_pat(s, input.pat),
_ => {

View File

@ -20,6 +20,14 @@ fn main() {
let mut a = 2; //~ ERROR: variable does not need to be mutable
let mut b = 3; //~ ERROR: variable does not need to be mutable
let mut a = ~[3]; //~ ERROR: variable does not need to be mutable
let (mut a, b) = (1, 2); //~ ERROR: variable does not need to be mutable
match 30 {
mut x => {} //~ ERROR: variable does not need to be mutable
}
let x = |mut y: int| 10; //~ ERROR: variable does not need to be mutable
fn what(mut foo: int) {} //~ ERROR: variable does not need to be mutable
// positive cases
let mut a = 2;
@ -30,6 +38,17 @@ fn main() {
do callback {
a.push(3);
}
let (mut a, b) = (1, 2);
a = 34;
match 30 {
mut x => {
x = 21;
}
}
let x = |mut y: int| y = 32;
fn nothing(mut foo: int) { foo = 37; }
}
fn callback(f: &fn()) {}

View File

@ -0,0 +1,16 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Can't put mut in non-ident pattern
pub fn main() {
struct Foo { x: int }
let mut Foo { x: x } = Foo { x: 3 }; //~ ERROR: expected `;` but found `{`
}

View File

@ -0,0 +1,80 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
trait Foo {
fn foo(&self, mut x: int) -> int {
let val = x;
x = 37 * x;
val + x
}
}
struct X;
impl Foo for X {}
pub fn main() {
let (a, mut b) = (23, 4);
assert_eq!(a, 23);
assert_eq!(b, 4);
b = a + b;
assert_eq!(b, 27);
assert_eq!(X.foo(2), 76);
enum Bar {
Foo(int),
Baz(f32, u8)
}
let (x, mut y) = (32, Foo(21));
match x {
mut z @ 32 => {
assert_eq!(z, 32);
z = 34;
assert_eq!(z, 34);
}
_ => {}
}
check_bar(&y);
y = Baz(10.0, 3);
check_bar(&y);
fn check_bar(y: &Bar) {
match y {
&Foo(a) => {
assert_eq!(a, 21);
}
&Baz(a, b) => {
assert_eq!(a, 10.0);
assert_eq!(b, 3);
}
}
}
fn foo1((x, mut y): (f64, int), mut z: int) -> int {
y = 2 * 6;
z = y + (x as int);
y - z
}
struct A {
x: int
}
let A { x: mut x } = A { x: 10 };
assert_eq!(x, 10);
x = 30;
assert_eq!(x, 30);
(|A { x: mut t }: A| { t = t+1; t })(A { x: 34 });
}