diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index cf6b0bf332e41..8acba42f9a8e8 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -346,7 +346,8 @@ impl ast::def: tr { did2_opt.map(|did2| did2.tr(xcx)), p) } - ast::def_self(nid) => { ast::def_self(xcx.tr_id(nid)) } + ast::def_self_ty(nid) => { ast::def_self_ty(xcx.tr_id(nid)) } + ast::def_self(nid, i) => { ast::def_self(xcx.tr_id(nid), i) } ast::def_mod(did) => { ast::def_mod(did.tr(xcx)) } ast::def_foreign_mod(did) => { ast::def_foreign_mod(did.tr(xcx)) } ast::def_const(did) => { ast::def_const(did.tr(xcx)) } diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 5f5fb6a22d98b..858cfb06d5120 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -471,6 +471,9 @@ impl check_loan_ctxt { // rvalues, I guess. cat_special(sk_static_item) => {} + // We allow moving out of explicit self only. + cat_special(sk_self) => {} + cat_deref(_, _, unsafe_ptr) => {} // Nothing else. diff --git a/src/librustc/middle/borrowck/preserve.rs b/src/librustc/middle/borrowck/preserve.rs index 1243b9baf5f13..b1a34bbe2569b 100644 --- a/src/librustc/middle/borrowck/preserve.rs +++ b/src/librustc/middle/borrowck/preserve.rs @@ -74,7 +74,9 @@ priv impl &preserve_ctxt { let _i = indenter(); match cmt.cat { - cat_special(sk_self) | cat_special(sk_heap_upvar) => { + cat_special(sk_self) | + cat_special(sk_implicit_self) | + cat_special(sk_heap_upvar) => { self.compare_scope(cmt, ty::re_scope(self.item_ub)) } cat_special(sk_static_item) | cat_special(sk_method) => { diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 48fff1a269bde..5ae0d4b1292d2 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -110,8 +110,10 @@ use core::io::WriterUtil; use std::map::HashMap; use syntax::ast::*; use syntax::codemap::span; +use syntax::parse::token::special_idents; use syntax::print::pprust::{expr_to_str, block_to_str}; -use syntax::visit::vt; +use syntax::visit::{fk_anon, fk_dtor, fk_fn_block, fk_item_fn, fk_method}; +use syntax::visit::{vt}; use syntax::{visit, ast_util}; export check_crate; @@ -265,7 +267,6 @@ struct LocalInfo { enum VarKind { Arg(node_id, ident, rmode), Local(LocalInfo), - Self, ImplicitRet } @@ -273,7 +274,8 @@ fn relevant_def(def: def) -> Option { match def { def_binding(nid, _) | def_arg(nid, _) | - def_local(nid, _) => Some(nid), + def_local(nid, _) | + def_self(nid, _) => Some(nid), _ => None } @@ -338,8 +340,7 @@ impl IrMaps { Arg(node_id, _, _) => { self.variable_map.insert(node_id, v); } - Self | ImplicitRet => { - } + ImplicitRet => {} } debug!("%s is %?", v.to_str(), vk); @@ -361,7 +362,6 @@ impl IrMaps { match copy self.var_kinds[*var] { Local(LocalInfo {ident: nm, _}) | Arg(_, nm, _) => self.tcx.sess.str_of(nm), - Self => ~"self", ImplicitRet => ~"" } } @@ -404,7 +404,7 @@ impl IrMaps { (*v).push(id); } Arg(_, _, by_ref) | - Arg(_, _, by_val) | Self | ImplicitRet => { + Arg(_, _, by_val) | ImplicitRet => { debug!("--but it is not owned"); } } @@ -432,6 +432,31 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, } }; + // Add `self`, whether explicit or implicit. + match fk { + fk_method(_, _, method) => { + match method.self_ty.node { + sty_by_ref => { + fn_maps.add_variable(Arg(method.self_id, + special_idents::self_, + by_ref)); + } + sty_value | sty_region(_) | sty_box(_) | sty_uniq(_) => { + fn_maps.add_variable(Arg(method.self_id, + special_idents::self_, + by_copy)); + } + sty_static => {} + } + } + fk_dtor(_, _, self_id, _) => { + fn_maps.add_variable(Arg(self_id, + special_idents::self_, + by_copy)); + } + fk_item_fn(*) | fk_anon(*) | fk_fn_block(*) => {} + } + // gather up the various local variables, significant expressions, // and so forth: visit::visit_fn(fk, decl, body, sp, id, fn_maps, v); @@ -1790,13 +1815,6 @@ impl @Liveness { copy or move mode", self.tcx.sess.str_of(name))); return; } - Self => { - self.tcx.sess.span_err( - move_span, - ~"illegal move from self (cannot move out of a field of \ - self)"); - return; - } Local(*) | ImplicitRet => { self.tcx.sess.span_bug( move_span, diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 3751c7f47691b..8fc8104c98f33 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -224,6 +224,7 @@ enum special_kind { sk_method, sk_static_item, sk_self, + sk_implicit_self, // old by-reference `self` sk_heap_upvar } @@ -566,7 +567,7 @@ impl &mem_categorization_ctxt { ast::def_ty(_) | ast::def_prim_ty(_) | ast::def_ty_param(*) | ast::def_struct(*) | ast::def_typaram_binder(*) | ast::def_region(_) | - ast::def_label(_) => { + ast::def_label(_) | ast::def_self_ty(*) => { @{id:id, span:span, cat:cat_special(sk_static_item), lp:None, mutbl:m_imm, ty:expr_ty} @@ -599,9 +600,15 @@ impl &mem_categorization_ctxt { mutbl:m, ty:expr_ty} } - ast::def_self(_) => { + ast::def_self(_, is_implicit) => { + let special_kind = if is_implicit { + sk_implicit_self + } else { + sk_self + }; + @{id:id, span:span, - cat:cat_special(sk_self), lp:None, + cat:cat_special(special_kind), lp:None, mutbl:m_imm, ty:expr_ty} } @@ -975,6 +982,7 @@ impl &mem_categorization_ctxt { match cat { cat_special(sk_method) => ~"method", cat_special(sk_static_item) => ~"static_item", + cat_special(sk_implicit_self) => ~"implicit-self", cat_special(sk_self) => ~"self", cat_special(sk_heap_upvar) => ~"heap-upvar", cat_stack_upvar(_) => ~"stack-upvar", @@ -1053,7 +1061,8 @@ impl &mem_categorization_ctxt { match cmt.cat { cat_special(sk_method) => ~"method", cat_special(sk_static_item) => ~"static item", - cat_special(sk_self) => ~"self reference", + cat_special(sk_implicit_self) => ~"self reference", + cat_special(sk_self) => ~"self value", cat_special(sk_heap_upvar) => { ~"captured outer variable in a heap closure" } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index bc728e5319a33..93fe8817120cd 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -16,14 +16,13 @@ use metadata::decoder::{def_like, dl_def, dl_field, dl_impl}; use middle::lang_items::LanguageItems; use middle::lint::{deny, allow, forbid, level, unused_imports, warn}; use middle::pat_util::{pat_bindings}; -use syntax::ast::{_mod, add, arm}; -use syntax::ast::{bitand, bitor, bitxor}; -use syntax::ast::{binding_mode, blk, capture_clause, struct_dtor}; -use syntax::ast::{crate, crate_num, decl_item}; -use syntax::ast::{def, def_arg, def_binding, def_struct, def_const, def_fn}; -use syntax::ast::{def_foreign_mod, def_id, def_label, def_local, def_mod}; -use syntax::ast::{def_prim_ty, def_region, def_self, def_ty, def_ty_param}; -use syntax::ast::{def_typaram_binder, def_static_method}; +use syntax::ast::{_mod, add, arm, binding_mode, bitand, bitor, bitxor, blk}; +use syntax::ast::{capture_clause}; +use syntax::ast::{crate, crate_num, decl_item, def, def_arg, def_binding}; +use syntax::ast::{def_const, def_foreign_mod, def_fn, def_id, def_label}; +use syntax::ast::{def_local, def_mod, def_prim_ty, def_region, def_self}; +use syntax::ast::{def_self_ty, def_static_method, def_struct, def_ty}; +use syntax::ast::{def_ty_param, def_typaram_binder}; use syntax::ast::{def_upvar, def_use, def_variant, expr, expr_assign_op}; use syntax::ast::{expr_binary, expr_break, expr_cast, expr_field, expr_fn}; use syntax::ast::{expr_fn_block, expr_index, expr_method_call, expr_path}; @@ -40,13 +39,13 @@ use syntax::ast::{local, local_crate, lt, method, mode, module_ns, mul, ne}; use syntax::ast::{neg, node_id, pat, pat_enum, pat_ident, path, prim_ty}; use syntax::ast::{pat_box, pat_lit, pat_range, pat_rec, pat_struct}; use syntax::ast::{pat_tup, pat_uniq, pat_wild, private, provided, public}; -use syntax::ast::{required, rem, self_ty_, shl, shr, stmt_decl}; -use syntax::ast::{struct_field, struct_variant_kind, sty_static, subtract}; -use syntax::ast::{trait_ref, tuple_variant_kind, Ty, ty_bool, ty_char}; -use syntax::ast::{ty_f, ty_f32, ty_f64, ty_float, ty_i, ty_i16, ty_i32}; -use syntax::ast::{ty_i64, ty_i8, ty_int, ty_param, ty_path, ty_str, ty_u}; -use syntax::ast::{ty_u16, ty_u32, ty_u64, ty_u8, ty_uint, type_value_ns}; -use syntax::ast::{ty_param_bound, unnamed_field}; +use syntax::ast::{required, rem, self_ty_, shl, shr, stmt_decl, struct_dtor}; +use syntax::ast::{struct_field, struct_variant_kind, sty_by_ref, sty_static}; +use syntax::ast::{subtract, trait_ref, tuple_variant_kind, Ty, ty_bool}; +use syntax::ast::{ty_char, ty_f, ty_f32, ty_f64, ty_float, ty_i, ty_i16}; +use syntax::ast::{ty_i32, ty_i64, ty_i8, ty_int, ty_param, ty_path, ty_str}; +use syntax::ast::{ty_u, ty_u16, ty_u32, ty_u64, ty_u8, ty_uint}; +use syntax::ast::{type_value_ns, ty_param_bound, unnamed_field}; use syntax::ast::{variant, view_item, view_item_export, view_item_import}; use syntax::ast::{view_item_use, view_path_glob, view_path_list}; use syntax::ast::{view_path_simple, visibility, anonymous, named}; @@ -197,7 +196,7 @@ impl Mutability : cmp::Eq { enum SelfBinding { NoSelfBinding, - HasSelfBinding(node_id) + HasSelfBinding(node_id, bool /* is implicit */) } enum CaptureClause { @@ -1753,7 +1752,7 @@ impl Resolver { def_self(*) | def_arg(*) | def_local(*) | def_prim_ty(*) | def_ty_param(*) | def_binding(*) | def_use(*) | def_upvar(*) | def_region(*) | - def_typaram_binder(*) | def_label(*) => { + def_typaram_binder(*) | def_label(*) | def_self_ty(*) => { fail fmt!("didn't expect `%?`", def); } } @@ -3724,7 +3723,7 @@ impl Resolver { let self_type_rib = @Rib(NormalRibKind); (*self.type_ribs).push(self_type_rib); self_type_rib.bindings.insert(self.self_ident, - dl_def(def_self(item.id))); + dl_def(def_self_ty(item.id))); // Create a new rib for the trait-wide type parameters. do self.with_type_parameter_rib @@ -3985,8 +3984,9 @@ impl Resolver { NoSelfBinding => { // Nothing to do. } - HasSelfBinding(self_node_id) => { - let def_like = dl_def(def_self(self_node_id)); + HasSelfBinding(self_node_id, is_implicit) => { + let def_like = dl_def(def_self(self_node_id, + is_implicit)); (*function_value_rib).bindings.insert(self.self_ident, def_like); } @@ -4065,7 +4065,8 @@ impl Resolver { NoTypeParameters, (*destructor).node.body, HasSelfBinding - ((*destructor).node.self_id), + ((*destructor).node.self_id, + true), NoCaptureClause, visitor); } @@ -4088,7 +4089,8 @@ impl Resolver { // we only have self ty if it is a non static method let self_binding = match method.self_ty.node { sty_static => { NoSelfBinding } - _ => { HasSelfBinding(method.self_id) } + sty_by_ref => { HasSelfBinding(method.self_id, true) } + _ => { HasSelfBinding(method.self_id, false) } }; self.resolve_function(rib_kind, diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 7117ae6910cc2..1d109c7966841 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -114,7 +114,8 @@ fn trans(bcx: block, expr: @ast::expr) -> Callee { ast::def_mod(*) | ast::def_foreign_mod(*) | ast::def_const(*) | ast::def_ty(*) | ast::def_prim_ty(*) | ast::def_use(*) | ast::def_typaram_binder(*) | - ast::def_region(*) | ast::def_label(*) | ast::def_ty_param(*) => { + ast::def_region(*) | ast::def_label(*) | ast::def_ty_param(*) | + ast::def_self_ty(*) => { bcx.tcx().sess.span_bug( ref_expr.span, fmt!("Cannot translate def %? \ diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 764ddabd1434f..c0abc63c4a111 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -830,7 +830,7 @@ fn trans_local_var(bcx: block, ast::def_local(nid, _) | ast::def_binding(nid, _) => { take_local(bcx, bcx.fcx.lllocals, nid, expr_id_opt) } - ast::def_self(nid) => { + ast::def_self(nid, _) => { let self_info: ValSelfData = match bcx.fcx.llself { Some(ref self_info) => *self_info, None => { diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 37958f84d5962..ab0fedb5e6bfb 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -354,7 +354,7 @@ fn ast_ty_to_ty( check_path_args(tcx, path, NO_TPS | NO_REGIONS); ty::mk_param(tcx, n, id) } - ast::def_self(_) => { + ast::def_self_ty(_) => { // n.b.: resolve guarantees that the self type only appears in a // trait, which we rely upon in various places when creating // substs diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 68fad6f81d64f..8af091fdb9ad0 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -2721,7 +2721,7 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) -> match defn { ast::def_arg(nid, _) | ast::def_local(nid, _) | - ast::def_self(nid) | ast::def_binding(nid, _) => { + ast::def_self(nid, _) | ast::def_binding(nid, _) => { assert (fcx.inh.locals.contains_key(nid)); let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid)); return no_params(typ); @@ -2774,6 +2774,9 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) -> ast::def_label(*) => { fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found label"); } + ast::def_self_ty(*) => { + fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found self ty"); + } } } diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index e58add83c0944..41918d42da423 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -46,7 +46,7 @@ type rvt = visit::vt<@rcx>; fn encl_region_of_def(fcx: @fn_ctxt, def: ast::def) -> ty::Region { let tcx = fcx.tcx(); match def { - def_local(node_id, _) | def_arg(node_id, _) | def_self(node_id) | + def_local(node_id, _) | def_arg(node_id, _) | def_self(node_id, _) | def_binding(node_id, _) => return encl_region(tcx, node_id), def_upvar(_, subdef, closure_id, body_id) => { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c21aa7d248ea0..444f90c7f0458 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -118,7 +118,8 @@ enum def { def_static_method(/* method */ def_id, /* trait */ Option, purity), - def_self(node_id), + def_self(node_id, bool /* is_implicit */), + def_self_ty(node_id), def_mod(def_id), def_foreign_mod(def_id), def_const(def_id), @@ -156,9 +157,15 @@ impl def : cmp::Eq { _ => false } } - def_self(e0a) => { + def_self(e0a, e1a) => { match (*other) { - def_self(e0b) => e0a == e0b, + def_self(e0b, e1b) => e0a == e0b && e1a == e1b, + _ => false + } + } + def_self_ty(e0a) => { + match (*other) { + def_self_ty(e0b) => e0a == e0b, _ => false } } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 3a8d399a45cdb..ef7bd1d892859 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -71,8 +71,8 @@ pure fn def_id_of_def(d: def) -> def_id { def_use(id) | def_struct(id) => { id } - def_arg(id, _) | def_local(id, _) | def_self(id) | - def_upvar(id, _, _, _) | def_binding(id, _) | def_region(id) + def_arg(id, _) | def_local(id, _) | def_self(id, _) | def_self_ty(id) + | def_upvar(id, _, _, _) | def_binding(id, _) | def_region(id) | def_typaram_binder(id) | def_label(id) => { local_def(id) } @@ -384,7 +384,7 @@ impl inlined_item: inlined_item_utils { referring to a def_self */ fn is_self(d: ast::def) -> bool { match d { - def_self(_) => true, + def_self(*) => true, def_upvar(_, d, _, _) => is_self(*d), _ => false } diff --git a/src/test/compile-fail/use-after-move-self.rs b/src/test/compile-fail/use-after-move-self.rs new file mode 100644 index 0000000000000..7bc1979fb8f4f --- /dev/null +++ b/src/test/compile-fail/use-after-move-self.rs @@ -0,0 +1,18 @@ +struct S { + x: int +} + +impl S { + fn foo(self) -> int { + (move self).bar(); + return self.x; //~ ERROR use of moved variable + } + + fn bar(self) {} +} + +fn main() { + let x = S { x: 1 }; + io::println(x.foo().to_str()); +} + diff --git a/src/test/run-pass/move-self.rs b/src/test/run-pass/move-self.rs new file mode 100644 index 0000000000000..5598839e31dc6 --- /dev/null +++ b/src/test/run-pass/move-self.rs @@ -0,0 +1,19 @@ +struct S { + x: ~str +} + +impl S { + fn foo(self) { + (move self).bar(); + } + + fn bar(self) { + io::println(self.x); + } +} + +fn main() { + let x = S { x: ~"Hello!" }; + x.foo(); +} +