librustc: Allow moves out of self. r=nmatsakis

This commit is contained in:
Patrick Walton 2012-12-10 11:58:37 -08:00
parent 45848b2040
commit cd120736cb
16 changed files with 155 additions and 53 deletions

View file

@ -346,7 +346,8 @@ impl ast::def: tr {
did2_opt.map(|did2| did2.tr(xcx)), did2_opt.map(|did2| did2.tr(xcx)),
p) 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_mod(did) => { ast::def_mod(did.tr(xcx)) }
ast::def_foreign_mod(did) => { ast::def_foreign_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)) } ast::def_const(did) => { ast::def_const(did.tr(xcx)) }

View file

@ -471,6 +471,9 @@ impl check_loan_ctxt {
// rvalues, I guess. // rvalues, I guess.
cat_special(sk_static_item) => {} cat_special(sk_static_item) => {}
// We allow moving out of explicit self only.
cat_special(sk_self) => {}
cat_deref(_, _, unsafe_ptr) => {} cat_deref(_, _, unsafe_ptr) => {}
// Nothing else. // Nothing else.

View file

@ -74,7 +74,9 @@ priv impl &preserve_ctxt {
let _i = indenter(); let _i = indenter();
match cmt.cat { 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)) self.compare_scope(cmt, ty::re_scope(self.item_ub))
} }
cat_special(sk_static_item) | cat_special(sk_method) => { cat_special(sk_static_item) | cat_special(sk_method) => {

View file

@ -110,8 +110,10 @@ use core::io::WriterUtil;
use std::map::HashMap; use std::map::HashMap;
use syntax::ast::*; use syntax::ast::*;
use syntax::codemap::span; use syntax::codemap::span;
use syntax::parse::token::special_idents;
use syntax::print::pprust::{expr_to_str, block_to_str}; 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}; use syntax::{visit, ast_util};
export check_crate; export check_crate;
@ -265,7 +267,6 @@ struct LocalInfo {
enum VarKind { enum VarKind {
Arg(node_id, ident, rmode), Arg(node_id, ident, rmode),
Local(LocalInfo), Local(LocalInfo),
Self,
ImplicitRet ImplicitRet
} }
@ -273,7 +274,8 @@ fn relevant_def(def: def) -> Option<node_id> {
match def { match def {
def_binding(nid, _) | def_binding(nid, _) |
def_arg(nid, _) | def_arg(nid, _) |
def_local(nid, _) => Some(nid), def_local(nid, _) |
def_self(nid, _) => Some(nid),
_ => None _ => None
} }
@ -338,8 +340,7 @@ impl IrMaps {
Arg(node_id, _, _) => { Arg(node_id, _, _) => {
self.variable_map.insert(node_id, v); self.variable_map.insert(node_id, v);
} }
Self | ImplicitRet => { ImplicitRet => {}
}
} }
debug!("%s is %?", v.to_str(), vk); debug!("%s is %?", v.to_str(), vk);
@ -361,7 +362,6 @@ impl IrMaps {
match copy self.var_kinds[*var] { match copy self.var_kinds[*var] {
Local(LocalInfo {ident: nm, _}) | Local(LocalInfo {ident: nm, _}) |
Arg(_, nm, _) => self.tcx.sess.str_of(nm), Arg(_, nm, _) => self.tcx.sess.str_of(nm),
Self => ~"self",
ImplicitRet => ~"<implicit-ret>" ImplicitRet => ~"<implicit-ret>"
} }
} }
@ -404,7 +404,7 @@ impl IrMaps {
(*v).push(id); (*v).push(id);
} }
Arg(_, _, by_ref) | Arg(_, _, by_ref) |
Arg(_, _, by_val) | Self | ImplicitRet => { Arg(_, _, by_val) | ImplicitRet => {
debug!("--but it is not owned"); 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, // gather up the various local variables, significant expressions,
// and so forth: // and so forth:
visit::visit_fn(fk, decl, body, sp, id, fn_maps, v); 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))); copy or move mode", self.tcx.sess.str_of(name)));
return; return;
} }
Self => {
self.tcx.sess.span_err(
move_span,
~"illegal move from self (cannot move out of a field of \
self)");
return;
}
Local(*) | ImplicitRet => { Local(*) | ImplicitRet => {
self.tcx.sess.span_bug( self.tcx.sess.span_bug(
move_span, move_span,

View file

@ -224,6 +224,7 @@ enum special_kind {
sk_method, sk_method,
sk_static_item, sk_static_item,
sk_self, sk_self,
sk_implicit_self, // old by-reference `self`
sk_heap_upvar sk_heap_upvar
} }
@ -566,7 +567,7 @@ impl &mem_categorization_ctxt {
ast::def_ty(_) | ast::def_prim_ty(_) | ast::def_ty(_) | ast::def_prim_ty(_) |
ast::def_ty_param(*) | ast::def_struct(*) | ast::def_ty_param(*) | ast::def_struct(*) |
ast::def_typaram_binder(*) | ast::def_region(_) | ast::def_typaram_binder(*) | ast::def_region(_) |
ast::def_label(_) => { ast::def_label(_) | ast::def_self_ty(*) => {
@{id:id, span:span, @{id:id, span:span,
cat:cat_special(sk_static_item), lp:None, cat:cat_special(sk_static_item), lp:None,
mutbl:m_imm, ty:expr_ty} mutbl:m_imm, ty:expr_ty}
@ -599,9 +600,15 @@ impl &mem_categorization_ctxt {
mutbl:m, ty:expr_ty} 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, @{id:id, span:span,
cat:cat_special(sk_self), lp:None, cat:cat_special(special_kind), lp:None,
mutbl:m_imm, ty:expr_ty} mutbl:m_imm, ty:expr_ty}
} }
@ -975,6 +982,7 @@ impl &mem_categorization_ctxt {
match cat { match cat {
cat_special(sk_method) => ~"method", cat_special(sk_method) => ~"method",
cat_special(sk_static_item) => ~"static_item", cat_special(sk_static_item) => ~"static_item",
cat_special(sk_implicit_self) => ~"implicit-self",
cat_special(sk_self) => ~"self", cat_special(sk_self) => ~"self",
cat_special(sk_heap_upvar) => ~"heap-upvar", cat_special(sk_heap_upvar) => ~"heap-upvar",
cat_stack_upvar(_) => ~"stack-upvar", cat_stack_upvar(_) => ~"stack-upvar",
@ -1053,7 +1061,8 @@ impl &mem_categorization_ctxt {
match cmt.cat { match cmt.cat {
cat_special(sk_method) => ~"method", cat_special(sk_method) => ~"method",
cat_special(sk_static_item) => ~"static item", 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) => { cat_special(sk_heap_upvar) => {
~"captured outer variable in a heap closure" ~"captured outer variable in a heap closure"
} }

View file

@ -16,14 +16,13 @@ use metadata::decoder::{def_like, dl_def, dl_field, dl_impl};
use middle::lang_items::LanguageItems; use middle::lang_items::LanguageItems;
use middle::lint::{deny, allow, forbid, level, unused_imports, warn}; use middle::lint::{deny, allow, forbid, level, unused_imports, warn};
use middle::pat_util::{pat_bindings}; use middle::pat_util::{pat_bindings};
use syntax::ast::{_mod, add, arm}; use syntax::ast::{_mod, add, arm, binding_mode, bitand, bitor, bitxor, blk};
use syntax::ast::{bitand, bitor, bitxor}; use syntax::ast::{capture_clause};
use syntax::ast::{binding_mode, blk, capture_clause, struct_dtor}; use syntax::ast::{crate, crate_num, decl_item, def, def_arg, def_binding};
use syntax::ast::{crate, crate_num, decl_item}; use syntax::ast::{def_const, def_foreign_mod, def_fn, def_id, def_label};
use syntax::ast::{def, def_arg, def_binding, def_struct, def_const, def_fn}; use syntax::ast::{def_local, def_mod, def_prim_ty, def_region, def_self};
use syntax::ast::{def_foreign_mod, def_id, def_label, def_local, def_mod}; use syntax::ast::{def_self_ty, def_static_method, def_struct, def_ty};
use syntax::ast::{def_prim_ty, def_region, def_self, def_ty, def_ty_param}; use syntax::ast::{def_ty_param, def_typaram_binder};
use syntax::ast::{def_typaram_binder, def_static_method};
use syntax::ast::{def_upvar, def_use, def_variant, expr, expr_assign_op}; 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_binary, expr_break, expr_cast, expr_field, expr_fn};
use syntax::ast::{expr_fn_block, expr_index, expr_method_call, expr_path}; 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::{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_box, pat_lit, pat_range, pat_rec, pat_struct};
use syntax::ast::{pat_tup, pat_uniq, pat_wild, private, provided, public}; 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::{required, rem, self_ty_, shl, shr, stmt_decl, struct_dtor};
use syntax::ast::{struct_field, struct_variant_kind, sty_static, subtract}; use syntax::ast::{struct_field, struct_variant_kind, sty_by_ref, sty_static};
use syntax::ast::{trait_ref, tuple_variant_kind, Ty, ty_bool, ty_char}; use syntax::ast::{subtract, trait_ref, tuple_variant_kind, Ty, ty_bool};
use syntax::ast::{ty_f, ty_f32, ty_f64, ty_float, ty_i, ty_i16, ty_i32}; use syntax::ast::{ty_char, ty_f, ty_f32, ty_f64, ty_float, ty_i, ty_i16};
use syntax::ast::{ty_i64, ty_i8, ty_int, ty_param, ty_path, ty_str, ty_u}; use syntax::ast::{ty_i32, ty_i64, ty_i8, ty_int, ty_param, ty_path, ty_str};
use syntax::ast::{ty_u16, ty_u32, ty_u64, ty_u8, ty_uint, type_value_ns}; use syntax::ast::{ty_u, ty_u16, ty_u32, ty_u64, ty_u8, ty_uint};
use syntax::ast::{ty_param_bound, unnamed_field}; 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::{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_item_use, view_path_glob, view_path_list};
use syntax::ast::{view_path_simple, visibility, anonymous, named}; use syntax::ast::{view_path_simple, visibility, anonymous, named};
@ -197,7 +196,7 @@ impl Mutability : cmp::Eq {
enum SelfBinding { enum SelfBinding {
NoSelfBinding, NoSelfBinding,
HasSelfBinding(node_id) HasSelfBinding(node_id, bool /* is implicit */)
} }
enum CaptureClause { enum CaptureClause {
@ -1753,7 +1752,7 @@ impl Resolver {
def_self(*) | def_arg(*) | def_local(*) | def_self(*) | def_arg(*) | def_local(*) |
def_prim_ty(*) | def_ty_param(*) | def_binding(*) | def_prim_ty(*) | def_ty_param(*) | def_binding(*) |
def_use(*) | def_upvar(*) | def_region(*) | 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); fail fmt!("didn't expect `%?`", def);
} }
} }
@ -3724,7 +3723,7 @@ impl Resolver {
let self_type_rib = @Rib(NormalRibKind); let self_type_rib = @Rib(NormalRibKind);
(*self.type_ribs).push(self_type_rib); (*self.type_ribs).push(self_type_rib);
self_type_rib.bindings.insert(self.self_ident, 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. // Create a new rib for the trait-wide type parameters.
do self.with_type_parameter_rib do self.with_type_parameter_rib
@ -3985,8 +3984,9 @@ impl Resolver {
NoSelfBinding => { NoSelfBinding => {
// Nothing to do. // Nothing to do.
} }
HasSelfBinding(self_node_id) => { HasSelfBinding(self_node_id, is_implicit) => {
let def_like = dl_def(def_self(self_node_id)); let def_like = dl_def(def_self(self_node_id,
is_implicit));
(*function_value_rib).bindings.insert(self.self_ident, (*function_value_rib).bindings.insert(self.self_ident,
def_like); def_like);
} }
@ -4065,7 +4065,8 @@ impl Resolver {
NoTypeParameters, NoTypeParameters,
(*destructor).node.body, (*destructor).node.body,
HasSelfBinding HasSelfBinding
((*destructor).node.self_id), ((*destructor).node.self_id,
true),
NoCaptureClause, NoCaptureClause,
visitor); visitor);
} }
@ -4088,7 +4089,8 @@ impl Resolver {
// we only have self ty if it is a non static method // we only have self ty if it is a non static method
let self_binding = match method.self_ty.node { let self_binding = match method.self_ty.node {
sty_static => { NoSelfBinding } 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, self.resolve_function(rib_kind,

View file

@ -114,7 +114,8 @@ fn trans(bcx: block, expr: @ast::expr) -> Callee {
ast::def_mod(*) | ast::def_foreign_mod(*) | ast::def_mod(*) | ast::def_foreign_mod(*) |
ast::def_const(*) | ast::def_ty(*) | ast::def_prim_ty(*) | ast::def_const(*) | ast::def_ty(*) | ast::def_prim_ty(*) |
ast::def_use(*) | ast::def_typaram_binder(*) | 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( bcx.tcx().sess.span_bug(
ref_expr.span, ref_expr.span,
fmt!("Cannot translate def %? \ fmt!("Cannot translate def %? \

View file

@ -828,7 +828,7 @@ fn trans_local_var(bcx: block,
ast::def_local(nid, _) | ast::def_binding(nid, _) => { ast::def_local(nid, _) | ast::def_binding(nid, _) => {
take_local(bcx, bcx.fcx.lllocals, nid, expr_id_opt) 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 { let self_info: ValSelfData = match bcx.fcx.llself {
Some(ref self_info) => *self_info, Some(ref self_info) => *self_info,
None => { None => {

View file

@ -354,7 +354,7 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope Copy Owned>(
check_path_args(tcx, path, NO_TPS | NO_REGIONS); check_path_args(tcx, path, NO_TPS | NO_REGIONS);
ty::mk_param(tcx, n, id) 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 // n.b.: resolve guarantees that the self type only appears in a
// trait, which we rely upon in various places when creating // trait, which we rely upon in various places when creating
// substs // substs

View file

@ -2721,7 +2721,7 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
match defn { match defn {
ast::def_arg(nid, _) | ast::def_local(nid, _) | 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)); assert (fcx.inh.locals.contains_key(nid));
let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid)); let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid));
return no_params(typ); 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(*) => { ast::def_label(*) => {
fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found 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");
}
} }
} }

View file

@ -46,7 +46,7 @@ type rvt = visit::vt<@rcx>;
fn encl_region_of_def(fcx: @fn_ctxt, def: ast::def) -> ty::Region { fn encl_region_of_def(fcx: @fn_ctxt, def: ast::def) -> ty::Region {
let tcx = fcx.tcx(); let tcx = fcx.tcx();
match def { 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, _) => def_binding(node_id, _) =>
return encl_region(tcx, node_id), return encl_region(tcx, node_id),
def_upvar(_, subdef, closure_id, body_id) => { def_upvar(_, subdef, closure_id, body_id) => {

View file

@ -118,7 +118,8 @@ enum def {
def_static_method(/* method */ def_id, def_static_method(/* method */ def_id,
/* trait */ Option<def_id>, /* trait */ Option<def_id>,
purity), purity),
def_self(node_id), def_self(node_id, bool /* is_implicit */),
def_self_ty(node_id),
def_mod(def_id), def_mod(def_id),
def_foreign_mod(def_id), def_foreign_mod(def_id),
def_const(def_id), def_const(def_id),
@ -156,9 +157,15 @@ impl def : cmp::Eq {
_ => false _ => false
} }
} }
def_self(e0a) => { def_self(e0a, e1a) => {
match (*other) { 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 _ => false
} }
} }

View file

@ -71,8 +71,8 @@ pure fn def_id_of_def(d: def) -> def_id {
def_use(id) | def_struct(id) => { def_use(id) | def_struct(id) => {
id id
} }
def_arg(id, _) | def_local(id, _) | def_self(id) | def_arg(id, _) | def_local(id, _) | def_self(id, _) | def_self_ty(id)
def_upvar(id, _, _, _) | def_binding(id, _) | def_region(id) | def_upvar(id, _, _, _) | def_binding(id, _) | def_region(id)
| def_typaram_binder(id) | def_label(id) => { | def_typaram_binder(id) | def_label(id) => {
local_def(id) local_def(id)
} }
@ -384,7 +384,7 @@ impl inlined_item: inlined_item_utils {
referring to a def_self */ referring to a def_self */
fn is_self(d: ast::def) -> bool { fn is_self(d: ast::def) -> bool {
match d { match d {
def_self(_) => true, def_self(*) => true,
def_upvar(_, d, _, _) => is_self(*d), def_upvar(_, d, _, _) => is_self(*d),
_ => false _ => false
} }

View file

@ -0,0 +1,19 @@
struct S {
x: int,
drop {}
}
impl S {
fn foo(self) -> int {
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());
}

View file

@ -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());
}

View file

@ -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();
}