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)),
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)) }

View File

@ -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.

View File

@ -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) => {

View File

@ -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<node_id> {
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 => ~"<implicit-ret>"
}
}
@ -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,

View File

@ -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"
}

View File

@ -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,

View File

@ -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 %? \

View File

@ -828,7 +828,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 => {

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);
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

View File

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

View File

@ -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) => {

View File

@ -118,7 +118,8 @@ enum def {
def_static_method(/* method */ def_id,
/* trait */ Option<def_id>,
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
}
}

View File

@ -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
}

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