diff --git a/doc/rust.md b/doc/rust.md index fd2da43a037f7..40a3bc12798f7 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -3395,16 +3395,23 @@ a [temporary](#lvalues-rvalues-and-temporaries), or a local variable. A _local variable_ (or *stack-local* allocation) holds a value directly, allocated within the stack's memory. The value is a part of the stack frame. -Local variables are immutable unless declared with `let mut`. The -`mut` keyword applies to all local variables declared within that -declaration (so `let mut (x, y) = ...` declares two mutable variables, `x` and -`y`). +Local variables are immutable unless declared otherwise like: `let mut x = ...`. Function parameters are immutable unless declared with `mut`. The `mut` keyword applies only to the following parameter (so `|mut x, y|` and `fn f(mut x: ~int, y: ~int)` declare one mutable variable `x` and one immutable variable `y`). +Methods that take either `self` or `~self` can optionally place them in a +mutable slot by prefixing them with `mut` (similar to regular arguments): + +~~~ +trait Changer { + fn change(mut self) -> Self; + fn modify(mut ~self) -> ~Self; +} +~~~ + Local variables are not initialized when allocated; the entire frame worth of local variables are allocated at once, on frame-entry, in an uninitialized state. Subsequent statements within a function may or may not initialize the diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index aa1c4c1eb7ec6..1023273032942 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -975,9 +975,9 @@ fn get_explicit_self(item: ebml::Doc) -> ast::explicit_self_ { let explicit_self_kind = string[0]; match explicit_self_kind as char { 's' => { return ast::sty_static; } - 'v' => { return ast::sty_value; } + 'v' => { return ast::sty_value(get_mutability(string[1])); } '@' => { return ast::sty_box(get_mutability(string[1])); } - '~' => { return ast::sty_uniq; } + '~' => { return ast::sty_uniq(get_mutability(string[1])); } '&' => { // FIXME(#4846) expl. region return ast::sty_region(None, get_mutability(string[1])); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 9f40593a93ae7..bae0dcc2a5203 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -662,8 +662,9 @@ fn encode_explicit_self(ebml_w: &mut writer::Encoder, explicit_self: ast::explic sty_static => { ebml_w.writer.write(&[ 's' as u8 ]); } - sty_value => { + sty_value(m) => { ebml_w.writer.write(&[ 'v' as u8 ]); + encode_mutability(ebml_w, m); } sty_region(_, m) => { // FIXME(#4846) encode custom lifetime @@ -674,8 +675,9 @@ fn encode_explicit_self(ebml_w: &mut writer::Encoder, explicit_self: ast::explic ebml_w.writer.write(&[ '@' as u8 ]); encode_mutability(ebml_w, m); } - sty_uniq => { + sty_uniq(m) => { ebml_w.writer.write(&[ '~' as u8 ]); + encode_mutability(ebml_w, m); } } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 294bbcb46f7b8..3d7f28b8b30b1 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -410,7 +410,7 @@ impl tr for ast::Def { ast::DefMethod(did0.tr(xcx), did1.map(|did1| did1.tr(xcx))) } ast::DefSelfTy(nid) => { ast::DefSelfTy(xcx.tr_id(nid)) } - ast::DefSelf(nid) => { ast::DefSelf(xcx.tr_id(nid)) } + ast::DefSelf(nid, m) => { ast::DefSelf(xcx.tr_id(nid), m) } ast::DefMod(did) => { ast::DefMod(did.tr(xcx)) } ast::DefForeignMod(did) => { ast::DefForeignMod(did.tr(xcx)) } ast::DefStatic(did, m) => { ast::DefStatic(did.tr(xcx), m) } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 6c53fc1602f23..71934c9f2a7ed 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -392,7 +392,7 @@ fn visit_fn(v: &mut LivenessVisitor, match *fk { visit::fk_method(_, _, method) => { match method.explicit_self.node { - sty_value | sty_region(*) | sty_box(_) | sty_uniq => { + sty_value(_) | sty_region(*) | sty_box(_) | sty_uniq(_) => { fn_maps.add_variable(Arg(method.self_id, special_idents::self_)); } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 37e89e58fa569..eb03027ad71ff 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -488,12 +488,12 @@ impl mem_categorization_ctxt { } } - ast::DefSelf(self_id) => { + ast::DefSelf(self_id, mutbl) => { @cmt_ { id:id, span:span, cat:cat_self(self_id), - mutbl: McImmutable, + mutbl: if mutbl { McDeclared } else { McImmutable }, ty:expr_ty } } diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index 1ed517c951293..5001614647a88 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -227,7 +227,7 @@ pub fn moved_variable_node_id_from_def(def: Def) -> Option { DefBinding(nid, _) | DefArg(nid, _) | DefLocal(nid, _) | - DefSelf(nid) => Some(nid), + DefSelf(nid, _) => Some(nid), _ => None } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index b480aaac1acb1..ee36b807ac79c 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -150,7 +150,7 @@ enum Mutability { enum SelfBinding { NoSelfBinding, - HasSelfBinding(NodeId) + HasSelfBinding(NodeId, explicit_self) } impl Visitor<()> for Resolver { @@ -3799,8 +3799,12 @@ impl Resolver { NoSelfBinding => { // Nothing to do. } - HasSelfBinding(self_node_id) => { - let def_like = DlDef(DefSelf(self_node_id)); + HasSelfBinding(self_node_id, explicit_self) => { + let mutable = match explicit_self.node { + sty_uniq(m) | sty_value(m) if m == MutMutable => true, + _ => false + }; + let def_like = DlDef(DefSelf(self_node_id, mutable)); *function_value_rib.self_binding = Some(def_like); } } @@ -3937,7 +3941,7 @@ impl Resolver { // we only have self ty if it is a non static method let self_binding = match method.explicit_self.node { sty_static => { NoSelfBinding } - _ => { HasSelfBinding(method.self_id) } + _ => { HasSelfBinding(method.self_id, method.explicit_self) } }; self.resolve_function(rib_kind, diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 238b15fe5979f..56f1e04784102 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -1099,7 +1099,7 @@ pub fn trans_local_var(bcx: @mut Block, def: ast::Def) -> Datum { ast::DefLocal(nid, _) | ast::DefBinding(nid, _) => { take_local(bcx, bcx.fcx.lllocals, nid) } - ast::DefSelf(nid) => { + ast::DefSelf(nid, _) => { let self_info: ValSelfData = match bcx.fcx.llself { Some(ref self_info) => *self_info, None => { diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs index a5be9a3ca5e14..d9f7cdeeb2ef1 100644 --- a/src/librustc/middle/trans/inline.rs +++ b/src/librustc/middle/trans/inline.rs @@ -144,7 +144,7 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::DefId) debug!("calling inline trans_fn with self_ty {}", ty_to_str(ccx.tcx, self_ty)); match mth.explicit_self.node { - ast::sty_value => impl_self(self_ty, ty::ByRef), + ast::sty_value(_) => impl_self(self_ty, ty::ByRef), _ => impl_self(self_ty, ty::ByCopy), } } diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index a8c18c721671d..61384c72efa25 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -120,7 +120,7 @@ pub fn trans_method(ccx: @mut CrateContext, debug!("calling trans_fn with self_ty {}", self_ty.repr(ccx.tcx)); match method.explicit_self.node { - ast::sty_value => impl_self(self_ty, ty::ByRef), + ast::sty_value(_) => impl_self(self_ty, ty::ByRef), _ => impl_self(self_ty, ty::ByCopy), } } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index ccda6bbaf9d11..dd0c6c12a69aa 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -672,7 +672,7 @@ fn ty_of_method_or_bare_fn( { match self_info.explicit_self.node { ast::sty_static => None, - ast::sty_value => { + ast::sty_value(_) => { Some(self_info.untransformed_self_ty) } ast::sty_region(ref lifetime, mutability) => { @@ -689,7 +689,7 @@ fn ty_of_method_or_bare_fn( ty::mt {ty: self_info.untransformed_self_ty, mutbl: mutability})) } - ast::sty_uniq => { + ast::sty_uniq(_) => { Some(ty::mk_uniq(this.tcx(), ty::mt {ty: self_info.untransformed_self_ty, mutbl: ast::MutImmutable})) diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index f6efd3aa5ad1f..af1d5ce3cc608 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -1082,7 +1082,7 @@ impl<'self> LookupContext<'self> { ast::sty_static => { self.bug(~"static method for object type receiver"); } - ast::sty_value => { + ast::sty_value(_) => { ty::mk_err() // error reported in `enforce_object_limitations()` } ast::sty_region(*) | ast::sty_box(*) | ast::sty_uniq(*) => { @@ -1141,7 +1141,7 @@ impl<'self> LookupContext<'self> { through an object"); } - ast::sty_value => { // reason (a) above + ast::sty_value(_) => { // reason (a) above self.tcx().sess.span_err( self.expr.span, "cannot call a method with a by-value receiver \ @@ -1198,7 +1198,7 @@ impl<'self> LookupContext<'self> { false } - sty_value => { + sty_value(_) => { rcvr_matches_ty(self.fcx, rcvr_ty, candidate) } @@ -1236,7 +1236,7 @@ impl<'self> LookupContext<'self> { } } - sty_uniq => { + sty_uniq(_) => { debug!("(is relevant?) explicit self is a unique pointer"); match ty::get(rcvr_ty).sty { ty::ty_uniq(mt) => { @@ -1369,7 +1369,7 @@ impl<'self> LookupContext<'self> { pub fn get_mode_from_explicit_self(explicit_self: ast::explicit_self_) -> SelfMode { match explicit_self { - sty_value => ty::ByRef, + sty_value(_) => ty::ByRef, _ => ty::ByCopy, } } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index eddf8aa518508..4514564ff1f6c 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3254,7 +3254,7 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt, defn: ast::Def) -> ty_param_bounds_and_ty { match defn { - ast::DefArg(nid, _) | ast::DefLocal(nid, _) | ast::DefSelf(nid) | + ast::DefArg(nid, _) | ast::DefLocal(nid, _) | ast::DefSelf(nid, _) | ast::DefBinding(nid, _) => { let typ = fcx.local_ty(sp, nid); return no_params(typ); diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 06a1305946238..09fc7b5c15c34 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -58,7 +58,7 @@ fn encl_region_of_def(fcx: @mut FnCtxt, def: ast::Def) -> ty::Region { let tcx = fcx.tcx(); match def { DefLocal(node_id, _) | DefArg(node_id, _) | - DefSelf(node_id) | DefBinding(node_id, _) => { + DefSelf(node_id, _) | DefBinding(node_id, _) => { tcx.region_maps.encl_region(node_id) } DefUpvar(_, subdef, closure_id, body_id) => { diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index 6ee7f8c172743..dd1ad8263da86 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -388,8 +388,8 @@ impl Clean for ast::explicit_self { fn clean(&self) -> SelfTy { match self.node { ast::sty_static => SelfStatic, - ast::sty_value => SelfValue, - ast::sty_uniq => SelfOwned, + ast::sty_value(_) => SelfValue, + ast::sty_uniq(_) => SelfOwned, ast::sty_region(lt, mt) => SelfBorrowed(lt.clean(), mt.clean()), ast::sty_box(mt) => SelfManaged(mt.clean()), } @@ -1171,7 +1171,7 @@ fn resolve_type(path: Path, tpbs: Option<~[TyParamBound]>, let (def_id, kind) = match *d { ast::DefFn(i, _) => (i, TypeFunction), - ast::DefSelf(i) | ast::DefSelfTy(i) => return Self(i), + ast::DefSelf(i, _) | ast::DefSelfTy(i) => return Self(i), ast::DefTy(i) => (i, TypeEnum), ast::DefTrait(i) => { debug!("saw DefTrait in def_to_id"); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 01033e829f6a7..372f1950c1de0 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -227,7 +227,7 @@ pub enum MethodProvenance { pub enum Def { DefFn(DefId, purity), DefStaticMethod(/* method */ DefId, MethodProvenance, purity), - DefSelf(NodeId), + DefSelf(NodeId, bool /* is_mutbl */), DefSelfTy(/* trait id */ NodeId), DefMod(DefId), DefForeignMod(DefId), @@ -921,10 +921,10 @@ pub enum ret_style { #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)] pub enum explicit_self_ { sty_static, // no self - sty_value, // `self` - sty_region(Option, Mutability), // `&'lt self` + sty_value(Mutability), // `self` + sty_region(Option, Mutability), // `&'lt self` sty_box(Mutability), // `@self` - sty_uniq // `~self` + sty_uniq(Mutability) // `~self` } pub type explicit_self = Spanned; diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index bdebc9872e690..1d9d5512ff424 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -66,7 +66,7 @@ pub fn def_id_of_def(d: Def) -> DefId { DefUse(id) | DefStruct(id) | DefTrait(id) | DefMethod(id, _) => { id } - DefArg(id, _) | DefLocal(id, _) | DefSelf(id) | DefSelfTy(id) + DefArg(id, _) | DefLocal(id, _) | DefSelf(id, _) | DefSelfTy(id) | DefUpvar(id, _, _, _) | DefBinding(id, _) | DefRegion(id) | DefTyParamBinder(id) | DefLabel(id) => { local_def(id) diff --git a/src/libsyntax/ext/deriving/ty.rs b/src/libsyntax/ext/deriving/ty.rs index 83c73e3d85f22..c60259304aef2 100644 --- a/src/libsyntax/ext/deriving/ty.rs +++ b/src/libsyntax/ext/deriving/ty.rs @@ -240,13 +240,13 @@ pub fn get_explicit_self(cx: @ExtCtxt, span: Span, self_ptr: &Option) let self_path = cx.expr_self(span); match *self_ptr { None => { - (self_path, respan(span, ast::sty_value)) + (self_path, respan(span, ast::sty_value(ast::MutImmutable))) } Some(ref ptr) => { let self_ty = respan( span, match *ptr { - Send => ast::sty_uniq, + Send => ast::sty_uniq(ast::MutImmutable), Managed(mutbl) => ast::sty_box(mutbl), Borrowed(ref lt, mutbl) => { let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s))); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ed6019e1a55ac..605e259cf0c2b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3438,15 +3438,11 @@ impl Parser { // parse the argument list and result type of a function // that may have a self type. - fn parse_fn_decl_with_self( - &self, - parse_arg_fn: - &fn(&Parser) -> arg - ) -> (explicit_self, fn_decl) { - fn maybe_parse_explicit_self( - cnstr: &fn(v: Mutability) -> ast::explicit_self_, - p: &Parser - ) -> ast::explicit_self_ { + fn parse_fn_decl_with_self(&self, parse_arg_fn: &fn(&Parser) -> arg) + -> (explicit_self, fn_decl) { + + fn maybe_parse_explicit_self(cnstr: &fn(v: Mutability) -> ast::explicit_self_, + p: &Parser) -> ast::explicit_self_ { // We need to make sure it isn't a type if p.look_ahead(1, |t| token::is_keyword(keywords::Self, t)) || ((p.look_ahead(1, |t| token::is_keyword(keywords::Const, t)) || @@ -3524,25 +3520,39 @@ impl Parser { self.span_err(*self.last_span, "mutability declaration not allowed here"); } - sty_uniq + sty_uniq(MutImmutable) }, self) } token::IDENT(*) if self.is_self_ident() => { self.bump(); - sty_value + sty_value(MutImmutable) } token::BINOP(token::STAR) => { // Possibly "*self" or "*mut self" -- not supported. Try to avoid // emitting cryptic "unexpected token" errors. self.bump(); - if self.token_is_mutability(self.token) { - self.bump(); - } + let mutability = if self.token_is_mutability(self.token) { + self.parse_mutability() + } else { MutImmutable }; if self.is_self_ident() { self.span_err(*self.span, "cannot pass self by unsafe pointer"); self.bump(); } - sty_value + sty_value(mutability) + } + _ if self.token_is_mutability(self.token) && + self.look_ahead(1, |t| token::is_keyword(keywords::Self, t)) => { + let mutability = self.parse_mutability(); + self.expect_self_ident(); + sty_value(mutability) + } + _ if self.token_is_mutability(self.token) && + self.look_ahead(1, |t| *t == token::TILDE) && + self.look_ahead(2, |t| token::is_keyword(keywords::Self, t)) => { + let mutability = self.parse_mutability(); + self.bump(); + self.expect_self_ident(); + sty_uniq(mutability) } _ => { sty_static diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index b245bd75ace72..0e330da31e623 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1686,8 +1686,14 @@ pub fn explicit_self_to_str(explicit_self: &ast::explicit_self_, intr: @ident_in pub fn print_explicit_self(s: @ps, explicit_self: ast::explicit_self_) -> bool { match explicit_self { ast::sty_static => { return false; } - ast::sty_value => { word(s.s, "self"); } - ast::sty_uniq => { word(s.s, "~self"); } + ast::sty_value(m) => { + print_mutability(s, m); + word(s.s, "self"); + } + ast::sty_uniq(m) => { + print_mutability(s, m); + word(s.s, "~self"); + } ast::sty_region(ref lt, m) => { word(s.s, "&"); print_opt_lifetime(s, lt); diff --git a/src/test/run-pass/by-value-self-in-mut-slot.rs b/src/test/run-pass/by-value-self-in-mut-slot.rs new file mode 100644 index 0000000000000..aa88004cd1199 --- /dev/null +++ b/src/test/run-pass/by-value-self-in-mut-slot.rs @@ -0,0 +1,30 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct X { + a: int +} + +trait Changer { + fn change(mut self) -> Self; +} + +impl Changer for X { + fn change(mut self) -> X { + self.a = 55; + self + } +} + +pub fn main() { + let x = X { a: 32 }; + let new_x = x.change(); + assert_eq!(new_x.a, 55); +} diff --git a/src/test/run-pass/self-in-mut-slot-default-method.rs b/src/test/run-pass/self-in-mut-slot-default-method.rs new file mode 100644 index 0000000000000..08d10fd11703b --- /dev/null +++ b/src/test/run-pass/self-in-mut-slot-default-method.rs @@ -0,0 +1,43 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct X { + a: int +} + +trait Changer { + fn change(mut self) -> Self { + self.set_to(55); + self + } + + fn change_again(mut ~self) -> ~Self { + self.set_to(45); + self + } + + fn set_to(&mut self, a: int); +} + +impl Changer for X { + fn set_to(&mut self, a: int) { + self.a = a; + } +} + +pub fn main() { + let x = X { a: 32 }; + let new_x = x.change(); + assert_eq!(new_x.a, 55); + + let x = ~new_x; + let new_x = x.change_again(); + assert_eq!(new_x.a, 45); +} diff --git a/src/test/run-pass/uniq-self-in-mut-slot.rs b/src/test/run-pass/uniq-self-in-mut-slot.rs new file mode 100644 index 0000000000000..7c2f52211761f --- /dev/null +++ b/src/test/run-pass/uniq-self-in-mut-slot.rs @@ -0,0 +1,30 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct X { + a: int +} + +trait Changer { + fn change(mut ~self) -> ~Self; +} + +impl Changer for X { + fn change(mut ~self) -> ~X { + self.a = 55; + self + } +} + +pub fn main() { + let x = ~X { a: 32 }; + let new_x = x.change(); + assert_eq!(new_x.a, 55); +}