1
Fork 0

introduce an owned kind for data that contains no borrowed ptrs

This commit is contained in:
Niko Matsakis 2012-07-16 20:17:57 -07:00
parent d809336d0f
commit 0e42004bab
25 changed files with 245 additions and 142 deletions

View file

@ -62,6 +62,7 @@ enum ty_param_bound {
bound_copy, bound_copy,
bound_send, bound_send,
bound_const, bound_const,
bound_owned,
bound_trait(@ty), bound_trait(@ty),
} }

View file

@ -135,7 +135,7 @@ fn fold_fn_decl(decl: ast::fn_decl, fld: ast_fold) -> ast::fn_decl {
fn fold_ty_param_bound(tpb: ty_param_bound, fld: ast_fold) -> ty_param_bound { fn fold_ty_param_bound(tpb: ty_param_bound, fld: ast_fold) -> ty_param_bound {
alt tpb { alt tpb {
bound_copy | bound_send | bound_const { tpb } bound_copy | bound_send | bound_const | bound_owned { tpb }
bound_trait(ty) { bound_trait(fld.fold_ty(ty)) } bound_trait(ty) { bound_trait(fld.fold_ty(ty)) }
} }
} }

View file

@ -16,7 +16,8 @@ import dvec::{dvec, extensions};
import vec::{push}; import vec::{push};
import ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute, import ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute,
bitand, bitor, bitxor, blk, blk_check_mode, bound_const, bitand, bitor, bitxor, blk, blk_check_mode, bound_const,
bound_copy, bound_send, bound_trait, box, by_copy, by_move, bound_copy, bound_send, bound_trait, bound_owned,
box, by_copy, by_move,
by_mutbl_ref, by_ref, by_val, capture_clause, capture_item, by_mutbl_ref, by_ref, by_val, capture_clause, capture_item,
carg_base, carg_ident, cdir_dir_mod, cdir_src_mod, carg_base, carg_ident, cdir_dir_mod, cdir_src_mod,
cdir_view_item, checked_expr, claimed_expr, class_immutable, cdir_view_item, checked_expr, claimed_expr, class_immutable,
@ -1935,12 +1936,16 @@ class parser {
let ident = self.parse_ident(); let ident = self.parse_ident();
if self.eat(token::COLON) { if self.eat(token::COLON) {
while self.token != token::COMMA && self.token != token::GT { while self.token != token::COMMA && self.token != token::GT {
if self.eat_keyword(~"send") { push(bounds, bound_send); } if self.eat_keyword(~"send") {
else if self.eat_keyword(~"copy") { push(bounds, bound_copy) } push(bounds, bound_send); }
else if self.eat_keyword(~"copy") {
push(bounds, bound_copy) }
else if self.eat_keyword(~"const") { else if self.eat_keyword(~"const") {
push(bounds, bound_const) push(bounds, bound_const);
} } else if self.eat_keyword(~"owned") {
else { push(bounds, bound_trait(self.parse_ty(false))); } push(bounds, bound_owned);
} else {
push(bounds, bound_trait(self.parse_ty(false))); }
} }
} }
ret {ident: ident, id: self.get_id(), bounds: @bounds}; ret {ident: ident, id: self.get_id(), bounds: @bounds};

View file

@ -313,7 +313,7 @@ fn restricted_keyword_table() -> hashmap<~str, ()> {
~"if", ~"iface", ~"impl", ~"import", ~"if", ~"iface", ~"impl", ~"import",
~"let", ~"log", ~"loop", ~"let", ~"log", ~"loop",
~"mod", ~"mut", ~"mod", ~"mut",
~"new", ~"new", ~"owned",
~"pure", ~"ret", ~"pure", ~"ret",
~"true", ~"trait", ~"type", ~"true", ~"trait", ~"type",
~"unchecked", ~"unsafe", ~"unchecked", ~"unsafe",

View file

@ -1377,6 +1377,7 @@ fn print_bounds(s: ps, bounds: @~[ast::ty_param_bound]) {
ast::bound_copy { word(s.s, ~"copy"); } ast::bound_copy { word(s.s, ~"copy"); }
ast::bound_send { word(s.s, ~"send"); } ast::bound_send { word(s.s, ~"send"); }
ast::bound_const { word(s.s, ~"const"); } ast::bound_const { word(s.s, ~"const"); }
ast::bound_owned { word(s.s, ~"owned"); }
ast::bound_trait(t) { print_type(s, t); } ast::bound_trait(t) { print_type(s, t); }
} }
} }

View file

@ -246,7 +246,7 @@ fn visit_ty_params<E>(tps: ~[ty_param], e: E, v: vt<E>) {
for vec::each(*tp.bounds) |bound| { for vec::each(*tp.bounds) |bound| {
alt bound { alt bound {
bound_trait(t) { v.visit_ty(t, e, v); } bound_trait(t) { v.visit_ty(t, e, v); }
bound_copy | bound_send | bound_const { } bound_copy | bound_send | bound_const | bound_owned { }
} }
} }
} }

View file

@ -417,6 +417,7 @@ fn parse_bounds(st: @pstate, conv: conv_did) -> @~[ty::param_bound] {
'S' { ty::bound_send } 'S' { ty::bound_send }
'C' { ty::bound_copy } 'C' { ty::bound_copy }
'K' { ty::bound_const } 'K' { ty::bound_const }
'O' { ty::bound_owned }
'I' { ty::bound_trait(parse_ty(st, conv)) } 'I' { ty::bound_trait(parse_ty(st, conv)) }
'.' { break; } '.' { break; }
}); });

View file

@ -350,6 +350,7 @@ fn enc_bounds(w: io::writer, cx: @ctxt, bs: @~[ty::param_bound]) {
ty::bound_send { w.write_char('S'); } ty::bound_send { w.write_char('S'); }
ty::bound_copy { w.write_char('C'); } ty::bound_copy { w.write_char('C'); }
ty::bound_const { w.write_char('K'); } ty::bound_const { w.write_char('K'); }
ty::bound_owned { w.write_char('O'); }
ty::bound_trait(tp) { ty::bound_trait(tp) {
w.write_char('I'); w.write_char('I');
enc_ty(w, cx, tp); enc_ty(w, cx, tp);

View file

@ -1,8 +1,7 @@
import syntax::{visit, ast_util}; import syntax::{visit, ast_util};
import syntax::ast::*; import syntax::ast::*;
import syntax::codemap::span; import syntax::codemap::span;
import ty::{kind, kind_sendable, kind_copyable, kind_noncopyable, kind_const, import ty::{kind, kind_copyable, kind_noncopyable, kind_const, operators};
operators};
import driver::session::session; import driver::session::session;
import std::map::hashmap; import std::map::hashmap;
import util::ppaux::{ty_to_str, tys_to_str}; import util::ppaux::{ty_to_str, tys_to_str};
@ -21,6 +20,7 @@ import lint::{non_implicitly_copyable_typarams,implicit_copies};
// copy: Things that can be copied. // copy: Things that can be copied.
// const: Things thare are deeply immutable. They are guaranteed never to // const: Things thare are deeply immutable. They are guaranteed never to
// change, and can be safely shared without copying between tasks. // change, and can be safely shared without copying between tasks.
// owned: Things that do not contain borrowed pointers.
// //
// Send includes scalar types as well as classes and unique types containing // Send includes scalar types as well as classes and unique types containing
// only sendable types. // only sendable types.
@ -41,15 +41,21 @@ import lint::{non_implicitly_copyable_typarams,implicit_copies};
fn kind_to_str(k: kind) -> ~str { fn kind_to_str(k: kind) -> ~str {
let mut kinds = ~[]; let mut kinds = ~[];
if ty::kind_lteq(kind_const(), k) { if ty::kind_lteq(kind_const(), k) {
vec::push(kinds, ~"const"); vec::push(kinds, ~"const");
} }
if ty::kind_can_be_copied(k) { if ty::kind_can_be_copied(k) {
vec::push(kinds, ~"copy"); vec::push(kinds, ~"copy");
} }
if ty::kind_can_be_sent(k) { if ty::kind_can_be_sent(k) {
vec::push(kinds, ~"send"); vec::push(kinds, ~"send");
} else if ty::kind_is_owned(k) {
vec::push(kinds, ~"owned");
} }
str::connect(kinds, ~" ") str::connect(kinds, ~" ")
} }
@ -93,8 +99,8 @@ fn with_appropriate_checker(cx: ctx, id: node_id, b: fn(check_fn)) {
fn check_for_uniq(cx: ctx, id: node_id, fv: option<@freevar_entry>, fn check_for_uniq(cx: ctx, id: node_id, fv: option<@freevar_entry>,
is_move: bool, var_t: ty::t, sp: span) { is_move: bool, var_t: ty::t, sp: span) {
// all captured data must be sendable, regardless of whether it is // all captured data must be sendable, regardless of whether it is
// moved in or copied in // moved in or copied in. Note that send implies owned.
check_send(cx, var_t, sp); if !check_send(cx, var_t, sp) { ret; }
// copied in data must be copyable, but moved in data can be anything // copied in data must be copyable, but moved in data can be anything
let is_implicit = fv.is_some(); let is_implicit = fv.is_some();
@ -108,6 +114,9 @@ fn with_appropriate_checker(cx: ctx, id: node_id, b: fn(check_fn)) {
fn check_for_box(cx: ctx, id: node_id, fv: option<@freevar_entry>, fn check_for_box(cx: ctx, id: node_id, fv: option<@freevar_entry>,
is_move: bool, var_t: ty::t, sp: span) { is_move: bool, var_t: ty::t, sp: span) {
// all captured data must be owned
if !check_owned(cx, var_t, sp) { ret; }
// copied in data must be copyable, but moved in data can be anything // copied in data must be copyable, but moved in data can be anything
let is_implicit = fv.is_some(); let is_implicit = fv.is_some();
if !is_move { check_copy(cx, id, var_t, sp, is_implicit); } if !is_move { check_copy(cx, id, var_t, sp, is_implicit); }
@ -422,9 +431,21 @@ fn check_copy(cx: ctx, id: node_id, ty: ty::t, sp: span,
} }
} }
fn check_send(cx: ctx, ty: ty::t, sp: span) { fn check_send(cx: ctx, ty: ty::t, sp: span) -> bool {
if !ty::kind_can_be_sent(ty::type_kind(cx.tcx, ty)) { if !ty::kind_can_be_sent(ty::type_kind(cx.tcx, ty)) {
cx.tcx.sess.span_err(sp, ~"not a sendable value"); cx.tcx.sess.span_err(sp, ~"not a sendable value");
false
} else {
true
}
}
fn check_owned(cx: ctx, ty: ty::t, sp: span) -> bool {
if !ty::kind_is_owned(ty::type_kind(cx.tcx, ty)) {
cx.tcx.sess.span_err(sp, ~"not an owned value");
false
} else {
true
} }
} }

View file

@ -4,6 +4,7 @@ import metadata::cstore::find_use_stmt_cnum;
import metadata::decoder::{def_like, dl_def, dl_field, dl_impl}; import metadata::decoder::{def_like, dl_def, dl_field, dl_impl};
import middle::lint::{error, ignore, level, unused_imports, warn}; import middle::lint::{error, ignore, level, unused_imports, warn};
import syntax::ast::{_mod, arm, blk, bound_const, bound_copy, bound_trait}; import syntax::ast::{_mod, arm, blk, bound_const, bound_copy, bound_trait};
import syntax::ast::{bound_owned};
import syntax::ast::{bound_send, capture_clause, class_ctor, class_dtor}; import syntax::ast::{bound_send, capture_clause, class_ctor, class_dtor};
import syntax::ast::{class_member, class_method, crate, crate_num, decl_item}; import syntax::ast::{class_member, class_method, crate, crate_num, decl_item};
import syntax::ast::{def, def_arg, def_binding, def_class, def_const, def_fn}; import syntax::ast::{def, def_arg, def_binding, def_class, def_const, def_fn};
@ -3181,7 +3182,7 @@ class Resolver {
for type_parameters.each |type_parameter| { for type_parameters.each |type_parameter| {
for (*type_parameter.bounds).each |bound| { for (*type_parameter.bounds).each |bound| {
alt bound { alt bound {
bound_copy | bound_send | bound_const { bound_copy | bound_send | bound_const | bound_owned {
// Nothing to do. // Nothing to do.
} }
bound_trait(interface_type) { bound_trait(interface_type) {

View file

@ -1373,23 +1373,23 @@ fn move_val(cx: block, action: copy_action, dst: ValueRef,
let tcx = cx.tcx(); let tcx = cx.tcx();
let mut cx = cx; let mut cx = cx;
if ty::type_is_scalar(t) { if ty::type_is_scalar(t) {
if src.kind == owned { src_val = Load(cx, src_val); } if src.kind == lv_owned { src_val = Load(cx, src_val); }
Store(cx, src_val, dst); Store(cx, src_val, dst);
ret cx; ret cx;
} else if ty::type_is_nil(t) || ty::type_is_bot(t) { } else if ty::type_is_nil(t) || ty::type_is_bot(t) {
ret cx; ret cx;
} else if ty::type_is_boxed(t) || ty::type_is_unique(t) { } else if ty::type_is_boxed(t) || ty::type_is_unique(t) {
if src.kind == owned { src_val = Load(cx, src_val); } if src.kind == lv_owned { src_val = Load(cx, src_val); }
if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); } if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); }
Store(cx, src_val, dst); Store(cx, src_val, dst);
if src.kind == owned { ret zero_mem(cx, src.val, t); } if src.kind == lv_owned { ret zero_mem(cx, src.val, t); }
// If we're here, it must be a temporary. // If we're here, it must be a temporary.
revoke_clean(cx, src_val); revoke_clean(cx, src_val);
ret cx; ret cx;
} else if type_is_structural_or_param(t) { } else if type_is_structural_or_param(t) {
if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); } if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); }
memmove_ty(cx, dst, src_val, t); memmove_ty(cx, dst, src_val, t);
if src.kind == owned { ret zero_mem(cx, src_val, t); } if src.kind == lv_owned { ret zero_mem(cx, src_val, t); }
// If we're here, it must be a temporary. // If we're here, it must be a temporary.
revoke_clean(cx, src_val); revoke_clean(cx, src_val);
ret cx; ret cx;
@ -1403,8 +1403,8 @@ fn store_temp_expr(cx: block, action: copy_action, dst: ValueRef,
-> block { -> block {
let _icx = cx.insn_ctxt(~"trans_temp_expr"); let _icx = cx.insn_ctxt(~"trans_temp_expr");
// Lvals in memory are not temporaries. Copy them. // Lvals in memory are not temporaries. Copy them.
if src.kind != temporary && !last_use { if src.kind != lv_temporary && !last_use {
let v = if src.kind == owned { let v = if src.kind == lv_owned {
load_if_immediate(cx, src.val, t) load_if_immediate(cx, src.val, t)
} else { } else {
src.val src.val
@ -1518,7 +1518,7 @@ fn trans_addr_of(cx: block, e: @ast::expr, dest: dest) -> block {
let mut {bcx, val, kind} = trans_temp_lval(cx, e); let mut {bcx, val, kind} = trans_temp_lval(cx, e);
let ety = expr_ty(cx, e); let ety = expr_ty(cx, e);
let is_immediate = ty::type_is_immediate(ety); let is_immediate = ty::type_is_immediate(ety);
if (kind == temporary && is_immediate) || kind == owned_imm { if (kind == lv_temporary && is_immediate) || kind == lv_owned_imm {
val = do_spill(bcx, val, ety); val = do_spill(bcx, val, ety);
} }
ret store_in_dest(bcx, val, dest); ret store_in_dest(bcx, val, dest);
@ -1696,7 +1696,7 @@ fn trans_assign_op(bcx: block, ex: @ast::expr, op: ast::binop,
let _icx = bcx.insn_ctxt(~"trans_assign_op"); let _icx = bcx.insn_ctxt(~"trans_assign_op");
let t = expr_ty(bcx, src); let t = expr_ty(bcx, src);
let lhs_res = trans_lval(bcx, dst); let lhs_res = trans_lval(bcx, dst);
assert (lhs_res.kind == owned); assert (lhs_res.kind == lv_owned);
// A user-defined operator method // A user-defined operator method
alt bcx.ccx().maps.method_map.find(ex.id) { alt bcx.ccx().maps.method_map.find(ex.id) {
@ -1720,7 +1720,7 @@ fn trans_assign_op(bcx: block, ex: @ast::expr, op: ast::binop,
arg_exprs(~[src]), save_in(target)); arg_exprs(~[src]), save_in(target));
ret move_val(bcx, DROP_EXISTING, lhs_res.val, ret move_val(bcx, DROP_EXISTING, lhs_res.val,
{bcx: bcx, val: target, kind: owned}, {bcx: bcx, val: target, kind: lv_owned},
dty); dty);
} }
_ {} _ {}
@ -1947,9 +1947,9 @@ fn trans_loop(cx:block, body: ast::blk) -> block {
} }
enum lval_kind { enum lval_kind {
temporary, //< Temporary value passed by value if of immediate type lv_temporary, //< Temporary value passed by value if of immediate type
owned, //< Non-temporary value passed by pointer lv_owned, //< Non-temporary value passed by pointer
owned_imm, //< Non-temporary value passed by value lv_owned_imm, //< Non-temporary value passed by value
} }
type local_var_result = {val: ValueRef, kind: lval_kind}; type local_var_result = {val: ValueRef, kind: lval_kind};
type lval_result = {bcx: block, val: ValueRef, kind: lval_kind}; type lval_result = {bcx: block, val: ValueRef, kind: lval_kind};
@ -1972,10 +1972,10 @@ fn lval_from_local_var(bcx: block, r: local_var_result) -> lval_result {
} }
fn lval_owned(bcx: block, val: ValueRef) -> lval_result { fn lval_owned(bcx: block, val: ValueRef) -> lval_result {
ret {bcx: bcx, val: val, kind: owned}; ret {bcx: bcx, val: val, kind: lv_owned};
} }
fn lval_temp(bcx: block, val: ValueRef) -> lval_result { fn lval_temp(bcx: block, val: ValueRef) -> lval_result {
ret {bcx: bcx, val: val, kind: temporary}; ret {bcx: bcx, val: val, kind: lv_temporary};
} }
fn lval_no_env(bcx: block, val: ValueRef, kind: lval_kind) fn lval_no_env(bcx: block, val: ValueRef, kind: lval_kind)
@ -2355,7 +2355,7 @@ fn lval_static_fn_inner(bcx: block, fn_id: ast::def_id, id: ast::node_id,
val = PointerCast(bcx, val, T_ptr(type_of_fn_from_ty( val = PointerCast(bcx, val, T_ptr(type_of_fn_from_ty(
ccx, node_id_type(bcx, id)))); ccx, node_id_type(bcx, id))));
} }
ret {bcx: bcx, val: val, kind: owned, env: null_env}; ret {bcx: bcx, val: val, kind: lv_owned, env: null_env};
} }
let mut val = if fn_id.crate == ast::local_crate { let mut val = if fn_id.crate == ast::local_crate {
@ -2376,7 +2376,7 @@ fn lval_static_fn_inner(bcx: block, fn_id: ast::def_id, id: ast::node_id,
ast::extern_fn { ast::extern_fn {
// Extern functions are just opaque pointers // Extern functions are just opaque pointers
let val = PointerCast(bcx, val, T_ptr(T_i8())); let val = PointerCast(bcx, val, T_ptr(T_i8()));
ret lval_no_env(bcx, val, owned_imm); ret lval_no_env(bcx, val, lv_owned_imm);
} }
_ { /* fall through */ } _ { /* fall through */ }
} }
@ -2384,7 +2384,7 @@ fn lval_static_fn_inner(bcx: block, fn_id: ast::def_id, id: ast::node_id,
_ { /* fall through */ } _ { /* fall through */ }
} }
ret {bcx: bcx, val: val, kind: owned, env: null_env}; ret {bcx: bcx, val: val, kind: lv_owned, env: null_env};
} }
fn lookup_discriminant(ccx: @crate_ctxt, vid: ast::def_id) -> ValueRef { fn lookup_discriminant(ccx: @crate_ctxt, vid: ast::def_id) -> ValueRef {
@ -2415,15 +2415,15 @@ fn trans_local_var(cx: block, def: ast::def) -> local_var_result {
fn take_local(table: hashmap<ast::node_id, local_val>, fn take_local(table: hashmap<ast::node_id, local_val>,
id: ast::node_id) -> local_var_result { id: ast::node_id) -> local_var_result {
alt table.find(id) { alt table.find(id) {
some(local_mem(v)) { {val: v, kind: owned} } some(local_mem(v)) { {val: v, kind: lv_owned} }
some(local_imm(v)) { {val: v, kind: owned_imm} } some(local_imm(v)) { {val: v, kind: lv_owned_imm} }
r { fail(~"take_local: internal error"); } r { fail(~"take_local: internal error"); }
} }
} }
alt def { alt def {
ast::def_upvar(nid, _, _) { ast::def_upvar(nid, _, _) {
assert (cx.fcx.llupvars.contains_key(nid)); assert (cx.fcx.llupvars.contains_key(nid));
ret { val: cx.fcx.llupvars.get(nid), kind: owned }; ret { val: cx.fcx.llupvars.get(nid), kind: lv_owned };
} }
ast::def_arg(nid, _) { ast::def_arg(nid, _) {
assert (cx.fcx.llargs.contains_key(nid)); assert (cx.fcx.llargs.contains_key(nid));
@ -2439,7 +2439,7 @@ fn trans_local_var(cx: block, def: ast::def) -> local_var_result {
none { cx.sess().bug(~"trans_local_var: reference to self \ none { cx.sess().bug(~"trans_local_var: reference to self \
out of context"); } out of context"); }
}; };
ret {val: slf, kind: owned}; ret {val: slf, kind: lv_owned};
} }
_ { _ {
cx.sess().unimpl(#fmt("unsupported def type in trans_local_def: %?", cx.sess().unimpl(#fmt("unsupported def type in trans_local_def: %?",
@ -2478,16 +2478,17 @@ fn trans_var(cx: block, def: ast::def, id: ast::node_id)-> lval_maybe_callee {
let lldiscrim_gv = lookup_discriminant(ccx, vid); let lldiscrim_gv = lookup_discriminant(ccx, vid);
let lldiscrim = Load(cx, lldiscrim_gv); let lldiscrim = Load(cx, lldiscrim_gv);
Store(cx, lldiscrim, lldiscrimptr); Store(cx, lldiscrim, lldiscrimptr);
ret lval_no_env(cx, llenumptr, temporary); ret lval_no_env(cx, llenumptr, lv_temporary);
} }
} }
ast::def_const(did) { ast::def_const(did) {
if did.crate == ast::local_crate { if did.crate == ast::local_crate {
ret lval_no_env(cx, get_item_val(ccx, did.node), owned); ret lval_no_env(cx, get_item_val(ccx, did.node), lv_owned);
} else { } else {
let tp = node_id_type(cx, id); let tp = node_id_type(cx, id);
let val = trans_external_path(ccx, did, tp); let val = trans_external_path(ccx, did, tp);
ret lval_no_env(cx, load_if_immediate(cx, val, tp), owned_imm); ret lval_no_env(cx, load_if_immediate(cx, val, tp),
lv_owned_imm);
} }
} }
_ { _ {
@ -2538,7 +2539,7 @@ fn trans_rec_field_inner(bcx: block, val: ValueRef, ty: ty::t,
} }
else { GEPi(bcx, val, ~[0u, ix]) }; else { GEPi(bcx, val, ~[0u, ix]) };
ret {bcx: bcx, val: val, kind: owned}; ret {bcx: bcx, val: val, kind: lv_owned};
} }
@ -2717,7 +2718,7 @@ fn lval_maybe_callee_to_lval(c: lval_maybe_callee, sp: span) -> lval_result {
let llfnty = llvm::LLVMGetElementType(val_ty(c.val)); let llfnty = llvm::LLVMGetElementType(val_ty(c.val));
let llfn = create_real_fn_pair(c.bcx, llfnty, c.val, let llfn = create_real_fn_pair(c.bcx, llfnty, c.val,
null_env_ptr(c.bcx)); null_env_ptr(c.bcx));
{bcx: c.bcx, val: llfn, kind: temporary} {bcx: c.bcx, val: llfn, kind: lv_temporary}
} }
} }
} }
@ -2863,7 +2864,7 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
ast::expr_loop_body(blk) { ast::expr_loop_body(blk) {
let scratch = alloc_ty(cx, expr_ty(cx, blk)); let scratch = alloc_ty(cx, expr_ty(cx, blk));
let bcx = trans_loop_body(cx, e, ret_flag, save_in(scratch)); let bcx = trans_loop_body(cx, e, ret_flag, save_in(scratch));
{bcx: bcx, val: scratch, kind: temporary} {bcx: bcx, val: scratch, kind: lv_temporary}
} }
} }
} }
@ -2881,7 +2882,7 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
let {bcx, val} = lval_result_to_result(lv, e_ty); let {bcx, val} = lval_result_to_result(lv, e_ty);
let {bcx, val, ty: e_ty} = let {bcx, val, ty: e_ty} =
autoderef(bcx, e.id, val, e_ty, derefs); autoderef(bcx, e.id, val, e_ty, derefs);
{lv: {bcx: bcx, val: val, kind: temporary}, {lv: {bcx: bcx, val: val, kind: lv_temporary},
e_ty: e_ty} e_ty: e_ty}
}; };
@ -2904,14 +2905,14 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
alt arg_mode { alt arg_mode {
ast::by_ref | ast::by_mutbl_ref { ast::by_ref | ast::by_mutbl_ref {
// Ensure that the value is spilled into memory: // Ensure that the value is spilled into memory:
if lv.kind != owned && ty::type_is_immediate(e_ty) { if lv.kind != lv_owned && ty::type_is_immediate(e_ty) {
val = do_spill_noroot(bcx, val); val = do_spill_noroot(bcx, val);
} }
} }
ast::by_val { ast::by_val {
// Ensure that the value is not spilled into memory: // Ensure that the value is not spilled into memory:
if lv.kind == owned || !ty::type_is_immediate(e_ty) { if lv.kind == lv_owned || !ty::type_is_immediate(e_ty) {
val = Load(bcx, val); val = Load(bcx, val);
} }
} }
@ -2921,15 +2922,15 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
let alloc = alloc_ty(bcx, arg.ty); let alloc = alloc_ty(bcx, arg.ty);
let move_out = arg_mode == ast::by_move || let move_out = arg_mode == ast::by_move ||
ccx.maps.last_use_map.contains_key(e.id); ccx.maps.last_use_map.contains_key(e.id);
if lv.kind == temporary { revoke_clean(bcx, val); } if lv.kind == lv_temporary { revoke_clean(bcx, val); }
if lv.kind == owned || !ty::type_is_immediate(arg.ty) { if lv.kind == lv_owned || !ty::type_is_immediate(arg.ty) {
memmove_ty(bcx, alloc, val, arg.ty); memmove_ty(bcx, alloc, val, arg.ty);
if move_out && ty::type_needs_drop(ccx.tcx, arg.ty) { if move_out && ty::type_needs_drop(ccx.tcx, arg.ty) {
bcx = zero_mem(bcx, val, arg.ty); bcx = zero_mem(bcx, val, arg.ty);
} }
} else { Store(bcx, val, alloc); } } else { Store(bcx, val, alloc); }
val = alloc; val = alloc;
if lv.kind != temporary && !move_out { if lv.kind != lv_temporary && !move_out {
bcx = take_ty(bcx, val, arg.ty); bcx = take_ty(bcx, val, arg.ty);
} }
@ -2977,9 +2978,9 @@ fn adapt_borrowed_value(lv: lval_result,
ty::ty_estr(_) | ty::ty_evec(_, _) { ty::ty_estr(_) | ty::ty_evec(_, _) {
let ccx = bcx.ccx(); let ccx = bcx.ccx();
let val = alt lv.kind { let val = alt lv.kind {
temporary { lv.val } lv_temporary { lv.val }
owned { load_if_immediate(bcx, lv.val, e_ty) } lv_owned { load_if_immediate(bcx, lv.val, e_ty) }
owned_imm { lv.val } lv_owned_imm { lv.val }
}; };
let unit_ty = ty::sequence_element_type(ccx.tcx, e_ty); let unit_ty = ty::sequence_element_type(ccx.tcx, e_ty);
@ -3150,7 +3151,7 @@ fn trans_call_inner(
} }
is_closure { is_closure {
// It's a closure. Have to fetch the elements // It's a closure. Have to fetch the elements
if f_res.kind == owned { if f_res.kind == lv_owned {
faddr = load_if_immediate(bcx, faddr, fn_expr_ty); faddr = load_if_immediate(bcx, faddr, fn_expr_ty);
} }
let pair = faddr; let pair = faddr;
@ -3418,17 +3419,17 @@ fn trans_temp_lval(bcx: block, e: @ast::expr) -> lval_result {
let ty = expr_ty(bcx, e); let ty = expr_ty(bcx, e);
if ty::type_is_nil(ty) || ty::type_is_bot(ty) { if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
bcx = trans_expr(bcx, e, ignore); bcx = trans_expr(bcx, e, ignore);
ret {bcx: bcx, val: C_nil(), kind: temporary}; ret {bcx: bcx, val: C_nil(), kind: lv_temporary};
} else if ty::type_is_immediate(ty) { } else if ty::type_is_immediate(ty) {
let cell = empty_dest_cell(); let cell = empty_dest_cell();
bcx = trans_expr(bcx, e, by_val(cell)); bcx = trans_expr(bcx, e, by_val(cell));
add_clean_temp(bcx, *cell, ty); add_clean_temp(bcx, *cell, ty);
ret {bcx: bcx, val: *cell, kind: temporary}; ret {bcx: bcx, val: *cell, kind: lv_temporary};
} else { } else {
let scratch = alloc_ty(bcx, ty); let scratch = alloc_ty(bcx, ty);
let bcx = trans_expr_save_in(bcx, e, scratch); let bcx = trans_expr_save_in(bcx, e, scratch);
add_clean_temp(bcx, scratch, ty); add_clean_temp(bcx, scratch, ty);
ret {bcx: bcx, val: scratch, kind: temporary}; ret {bcx: bcx, val: scratch, kind: lv_temporary};
} }
} }
} }
@ -3442,9 +3443,9 @@ fn trans_temp_expr(bcx: block, e: @ast::expr) -> result {
fn load_value_from_lval_result(lv: lval_result, ty: ty::t) -> ValueRef { fn load_value_from_lval_result(lv: lval_result, ty: ty::t) -> ValueRef {
alt lv.kind { alt lv.kind {
temporary { lv.val } lv_temporary { lv.val }
owned { load_if_immediate(lv.bcx, lv.val, ty) } lv_owned { load_if_immediate(lv.bcx, lv.val, ty) }
owned_imm { lv.val } lv_owned_imm { lv.val }
} }
} }
@ -3521,7 +3522,7 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
let _icx = bcx.insn_ctxt(~"root_value_expr"); let _icx = bcx.insn_ctxt(~"root_value_expr");
add_root_cleanup(bcx, scope_id, root_loc, ty); add_root_cleanup(bcx, scope_id, root_loc, ty);
let lv = {bcx: bcx, val: root_loc, kind: owned}; let lv = {bcx: bcx, val: root_loc, kind: lv_owned};
lval_result_to_dps(lv, ty, false, dest) lval_result_to_dps(lv, ty, false, dest)
} }
}; };
@ -3647,7 +3648,7 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
assert dest == ignore; assert dest == ignore;
let src_r = trans_temp_lval(bcx, src); let src_r = trans_temp_lval(bcx, src);
let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst); let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst);
assert kind == owned; assert kind == lv_owned;
let is_last_use = let is_last_use =
bcx.ccx().maps.last_use_map.contains_key(src.id); bcx.ccx().maps.last_use_map.contains_key(src.id);
ret store_temp_expr(bcx, DROP_EXISTING, addr, src_r, ret store_temp_expr(bcx, DROP_EXISTING, addr, src_r,
@ -3658,14 +3659,14 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
assert dest == ignore; assert dest == ignore;
let src_r = trans_temp_lval(bcx, src); let src_r = trans_temp_lval(bcx, src);
let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst); let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst);
assert kind == owned; assert kind == lv_owned;
ret move_val(bcx, DROP_EXISTING, addr, src_r, ret move_val(bcx, DROP_EXISTING, addr, src_r,
expr_ty(bcx, src)); expr_ty(bcx, src));
} }
ast::expr_swap(dst, src) { ast::expr_swap(dst, src) {
assert dest == ignore; assert dest == ignore;
let lhs_res = trans_lval(bcx, dst); let lhs_res = trans_lval(bcx, dst);
assert lhs_res.kind == owned; assert lhs_res.kind == lv_owned;
let rhs_res = trans_lval(lhs_res.bcx, src); let rhs_res = trans_lval(lhs_res.bcx, src);
let t = expr_ty(bcx, src); let t = expr_ty(bcx, src);
let tmp_alloc = alloc_ty(rhs_res.bcx, t); let tmp_alloc = alloc_ty(rhs_res.bcx, t);
@ -3728,7 +3729,7 @@ fn lval_to_dps(bcx: block, e: @ast::expr, dest: dest) -> block {
let last_use_map = bcx.ccx().maps.last_use_map; let last_use_map = bcx.ccx().maps.last_use_map;
let ty = expr_ty(bcx, e); let ty = expr_ty(bcx, e);
let lv = trans_lval(bcx, e); let lv = trans_lval(bcx, e);
let last_use = (lv.kind == owned && last_use_map.contains_key(e.id)); let last_use = (lv.kind == lv_owned && last_use_map.contains_key(e.id));
#debug["is last use (%s) = %b, %d", expr_to_str(e), last_use, #debug["is last use (%s) = %b, %d", expr_to_str(e), last_use,
lv.kind as int]; lv.kind as int];
lval_result_to_dps(lv, ty, last_use, dest) lval_result_to_dps(lv, ty, last_use, dest)
@ -3740,7 +3741,7 @@ fn lval_result_to_dps(lv: lval_result, ty: ty::t,
let ccx = bcx.ccx(); let ccx = bcx.ccx();
alt dest { alt dest {
by_val(cell) { by_val(cell) {
if kind == temporary { if kind == lv_temporary {
revoke_clean(bcx, val); revoke_clean(bcx, val);
*cell = val; *cell = val;
} else if last_use { } else if last_use {
@ -3749,7 +3750,7 @@ fn lval_result_to_dps(lv: lval_result, ty: ty::t,
bcx = zero_mem(bcx, val, ty); bcx = zero_mem(bcx, val, ty);
} }
} else { } else {
if kind == owned { val = Load(bcx, val); } if kind == lv_owned { val = Load(bcx, val); }
let {bcx: cx, val} = take_ty_immediate(bcx, val, ty); let {bcx: cx, val} = take_ty_immediate(bcx, val, ty);
*cell = val; *cell = val;
bcx = cx; bcx = cx;
@ -4788,7 +4789,7 @@ fn trans_class_ctor(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
// Translate the body of the ctor // Translate the body of the ctor
bcx = trans_block(bcx_top, body, ignore); bcx = trans_block(bcx_top, body, ignore);
let lval_res = {bcx: bcx, val: selfptr, kind: owned}; let lval_res = {bcx: bcx, val: selfptr, kind: lv_owned};
// Generate the return expression // Generate the return expression
bcx = store_temp_expr(bcx, INIT, fcx.llretptr, lval_res, bcx = store_temp_expr(bcx, INIT, fcx.llretptr, lval_res,
rslt_ty, true); rslt_ty, true);

View file

@ -216,31 +216,31 @@ fn store_environment(bcx: block,
let bound_data = GEPi(bcx, llbox, let bound_data = GEPi(bcx, llbox,
~[0u, abi::box_field_body, i]); ~[0u, abi::box_field_body, i]);
alt bv { alt bv {
env_copy(val, ty, owned) { env_copy(val, ty, lv_owned) {
let val1 = load_if_immediate(bcx, val, ty); let val1 = load_if_immediate(bcx, val, ty);
bcx = base::copy_val(bcx, INIT, bound_data, val1, ty); bcx = base::copy_val(bcx, INIT, bound_data, val1, ty);
} }
env_copy(val, ty, owned_imm) { env_copy(val, ty, lv_owned_imm) {
bcx = base::copy_val(bcx, INIT, bound_data, val, ty); bcx = base::copy_val(bcx, INIT, bound_data, val, ty);
} }
env_copy(_, _, temporary) { env_copy(_, _, lv_temporary) {
fail ~"cannot capture temporary upvar"; fail ~"cannot capture temporary upvar";
} }
env_move(val, ty, kind) { env_move(val, ty, kind) {
let src = {bcx:bcx, val:val, kind:kind}; let src = {bcx:bcx, val:val, kind:kind};
bcx = move_val(bcx, INIT, bound_data, src, ty); bcx = move_val(bcx, INIT, bound_data, src, ty);
} }
env_ref(val, ty, owned) { env_ref(val, ty, lv_owned) {
#debug["> storing %s into %s", #debug["> storing %s into %s",
val_str(bcx.ccx().tn, val), val_str(bcx.ccx().tn, val),
val_str(bcx.ccx().tn, bound_data)]; val_str(bcx.ccx().tn, bound_data)];
Store(bcx, val, bound_data); Store(bcx, val, bound_data);
} }
env_ref(val, ty, owned_imm) { env_ref(val, ty, lv_owned_imm) {
let addr = do_spill_noroot(bcx, val); let addr = do_spill_noroot(bcx, val);
Store(bcx, addr, bound_data); Store(bcx, addr, bound_data);
} }
env_ref(_, _, temporary) { env_ref(_, _, lv_temporary) {
fail ~"cannot capture temporary upvar"; fail ~"cannot capture temporary upvar";
} }
} }
@ -289,7 +289,7 @@ fn build_closure(bcx0: block,
vec::push(env_vals, env_move(lv.val, ty, lv.kind)); vec::push(env_vals, env_move(lv.val, ty, lv.kind));
} }
capture::cap_drop { capture::cap_drop {
assert lv.kind == owned; assert lv.kind == lv_owned;
bcx = drop_ty(bcx, lv.val, ty); bcx = drop_ty(bcx, lv.val, ty);
bcx = zero_mem(bcx, lv.val, ty); bcx = zero_mem(bcx, lv.val, ty);
} }
@ -303,9 +303,9 @@ fn build_closure(bcx0: block,
let nil_ret = PointerCast(bcx, our_ret, T_ptr(T_nil())); let nil_ret = PointerCast(bcx, our_ret, T_ptr(T_nil()));
vec::push(env_vals, vec::push(env_vals,
env_ref(flagptr, env_ref(flagptr,
ty::mk_mut_ptr(tcx, ty::mk_bool(tcx)), owned)); ty::mk_mut_ptr(tcx, ty::mk_bool(tcx)), lv_owned));
vec::push(env_vals, vec::push(env_vals,
env_ref(nil_ret, ty::mk_nil_ptr(tcx), owned)); env_ref(nil_ret, ty::mk_nil_ptr(tcx), lv_owned));
} }
ret store_environment(bcx, env_vals, ck); ret store_environment(bcx, env_vals, ck);
} }

View file

@ -881,7 +881,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
let tp_ty = substs.tys[0]; let tp_ty = substs.tys[0];
let src = {bcx: bcx, let src = {bcx: bcx,
val: get_param(decl, first_real_arg + 1u), val: get_param(decl, first_real_arg + 1u),
kind: owned }; kind: lv_owned};
bcx = move_val(bcx, DROP_EXISTING, bcx = move_val(bcx, DROP_EXISTING,
get_param(decl, first_real_arg), get_param(decl, first_real_arg),
src, src,
@ -891,7 +891,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
let tp_ty = substs.tys[0]; let tp_ty = substs.tys[0];
let src = {bcx: bcx, let src = {bcx: bcx,
val: get_param(decl, first_real_arg + 1u), val: get_param(decl, first_real_arg + 1u),
kind: owned }; kind: lv_owned};
bcx = move_val(bcx, INIT, bcx = move_val(bcx, INIT,
get_param(decl, first_real_arg), get_param(decl, first_real_arg),
src, src,
@ -982,7 +982,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
|bcx| lval_no_env( |bcx| lval_no_env(
bcx, bcx,
get_param(decl, first_real_arg), get_param(decl, first_real_arg),
temporary), lv_temporary),
arg_vals(~[frameaddress_val]), ignore); arg_vals(~[frameaddress_val]), ignore);
} }
} }

View file

@ -162,7 +162,7 @@ fn trans_trait_callee(bcx: block, val: ValueRef,
let vtable = PointerCast(bcx, vtable, let vtable = PointerCast(bcx, vtable,
T_ptr(T_array(T_ptr(llfty), n_method + 1u))); T_ptr(T_array(T_ptr(llfty), n_method + 1u)));
let mptr = Load(bcx, GEPi(bcx, vtable, ~[0u, n_method])); let mptr = Load(bcx, GEPi(bcx, vtable, ~[0u, n_method]));
{bcx: bcx, val: mptr, kind: owned, env: env} {bcx: bcx, val: mptr, kind: lv_owned, env: env}
} }
fn find_vtable_in_fn_ctxt(ps: param_substs, n_param: uint, n_bound: uint) fn find_vtable_in_fn_ctxt(ps: param_substs, n_param: uint, n_bound: uint)

View file

@ -107,9 +107,10 @@ export tbox_has_flag;
export ty_var_id; export ty_var_id;
export ty_to_def_id; export ty_to_def_id;
export ty_fn_args; export ty_fn_args;
export kind, kind_implicitly_copyable, kind_sendable, kind_copyable; export kind, kind_implicitly_copyable, kind_send_copy, kind_copyable;
export kind_noncopyable, kind_const; export kind_noncopyable, kind_const;
export kind_can_be_copied, kind_can_be_sent, kind_can_be_implicitly_copied; export kind_can_be_copied, kind_can_be_sent, kind_can_be_implicitly_copied;
export kind_is_owned;
export proto_kind, kind_lteq, type_kind; export proto_kind, kind_lteq, type_kind;
export operators; export operators;
export type_err, terr_vstore_kind; export type_err, terr_vstore_kind;
@ -144,7 +145,8 @@ export closure_kind;
export ck_block; export ck_block;
export ck_box; export ck_box;
export ck_uniq; export ck_uniq;
export param_bound, param_bounds, bound_copy, bound_send, bound_trait; export param_bound, param_bounds, bound_copy, bound_owned;
export bound_send, bound_trait;
export param_bounds_to_kind; export param_bounds_to_kind;
export default_arg_mode_for_ty; export default_arg_mode_for_ty;
export item_path; export item_path;
@ -409,6 +411,7 @@ enum type_err {
enum param_bound { enum param_bound {
bound_copy, bound_copy,
bound_owned,
bound_send, bound_send,
bound_const, bound_const,
bound_trait(t), bound_trait(t),
@ -451,8 +454,15 @@ fn param_bounds_to_kind(bounds: param_bounds) -> kind {
bound_copy { bound_copy {
kind = raise_kind(kind, kind_implicitly_copyable()); kind = raise_kind(kind, kind_implicitly_copyable());
} }
bound_send { kind = raise_kind(kind, kind_send_only()); } bound_owned {
bound_const { kind = raise_kind(kind, kind_const()); } kind = raise_kind(kind, kind_owned());
}
bound_send {
kind = raise_kind(kind, kind_send_only() | kind_owned());
}
bound_const {
kind = raise_kind(kind, kind_const());
}
bound_trait(_) {} bound_trait(_) {}
} }
} }
@ -1303,11 +1313,20 @@ fn type_needs_unwind_cleanup_(cx: ctxt, ty: t,
enum kind { kind_(u32) } enum kind { kind_(u32) }
// *ALL* implicitly copiable things must be copiable /// can be copied (implicitly or explicitly)
const KIND_MASK_COPY : u32 = 0b00000000000000000000000000000001u32; const KIND_MASK_COPY : u32 = 0b00000000000000000000000000000001_u32;
const KIND_MASK_SEND : u32 = 0b00000000000000000000000000000010u32;
const KIND_MASK_CONST : u32 = 0b00000000000000000000000000000100u32; /// can be sent: no shared box, borrowed ptr (must imply OWNED)
const KIND_MASK_IMPLICIT : u32 = 0b00000000000000000000000000001000u32; const KIND_MASK_SEND : u32 = 0b00000000000000000000000000000010_u32;
/// is owned (no borrowed ptrs)
const KIND_MASK_OWNED : u32 = 0b00000000000000000000000000000100_u32;
/// is deeply immutable
const KIND_MASK_CONST : u32 = 0b00000000000000000000000000001000_u32;
/// can be implicitly copied (must imply COPY)
const KIND_MASK_IMPLICIT : u32 = 0b00000000000000000000000000010000_u32;
fn kind_noncopyable() -> kind { fn kind_noncopyable() -> kind {
kind_(0u32) kind_(0u32)
@ -1325,7 +1344,7 @@ fn kind_implicitly_sendable() -> kind {
kind_(KIND_MASK_IMPLICIT | KIND_MASK_COPY | KIND_MASK_SEND) kind_(KIND_MASK_IMPLICIT | KIND_MASK_COPY | KIND_MASK_SEND)
} }
fn kind_sendable() -> kind { fn kind_send_copy() -> kind {
kind_(KIND_MASK_COPY | KIND_MASK_SEND) kind_(KIND_MASK_COPY | KIND_MASK_SEND)
} }
@ -1337,6 +1356,10 @@ fn kind_const() -> kind {
kind_(KIND_MASK_CONST) kind_(KIND_MASK_CONST)
} }
fn kind_owned() -> kind {
kind_(KIND_MASK_OWNED)
}
fn kind_top() -> kind { fn kind_top() -> kind {
kind_(0xffffffffu32) kind_(0xffffffffu32)
} }
@ -1349,6 +1372,14 @@ fn remove_implicit(k: kind) -> kind {
k - kind_(KIND_MASK_IMPLICIT) k - kind_(KIND_MASK_IMPLICIT)
} }
fn remove_send(k: kind) -> kind {
k - kind_(KIND_MASK_SEND)
}
fn remove_owned_send(k: kind) -> kind {
k - kind_(KIND_MASK_OWNED) - kind_(KIND_MASK_SEND)
}
fn remove_copyable(k: kind) -> kind { fn remove_copyable(k: kind) -> kind {
k - kind_(KIND_MASK_COPY) k - kind_(KIND_MASK_COPY)
} }
@ -1371,24 +1402,29 @@ impl operators for kind {
// against the kind constants, as we may modify the kind hierarchy in the // against the kind constants, as we may modify the kind hierarchy in the
// future. // future.
pure fn kind_can_be_implicitly_copied(k: kind) -> bool { pure fn kind_can_be_implicitly_copied(k: kind) -> bool {
*k & KIND_MASK_IMPLICIT != 0u32 *k & KIND_MASK_IMPLICIT == KIND_MASK_IMPLICIT
} }
pure fn kind_can_be_copied(k: kind) -> bool { pure fn kind_can_be_copied(k: kind) -> bool {
*k & KIND_MASK_COPY != 0u32 *k & KIND_MASK_COPY == KIND_MASK_COPY
} }
pure fn kind_can_be_sent(k: kind) -> bool { pure fn kind_can_be_sent(k: kind) -> bool {
*k & KIND_MASK_SEND != 0u32 *k & KIND_MASK_SEND == KIND_MASK_SEND
}
pure fn kind_is_owned(k: kind) -> bool {
*k & KIND_MASK_OWNED == KIND_MASK_OWNED
} }
fn proto_kind(p: proto) -> kind { fn proto_kind(p: proto) -> kind {
alt p { alt p {
ast::proto_any { kind_noncopyable() } ast::proto_any { kind_noncopyable() }
ast::proto_block { kind_noncopyable() } ast::proto_block { kind_noncopyable() }
ast::proto_box { kind_implicitly_copyable() } ast::proto_box { kind_implicitly_copyable() | kind_owned() }
ast::proto_uniq { kind_sendable() } ast::proto_uniq { kind_send_copy() | kind_owned() }
ast::proto_bare { kind_implicitly_sendable() | kind_const() } ast::proto_bare { kind_implicitly_sendable() | kind_const() |
kind_owned() }
} }
} }
@ -1408,16 +1444,16 @@ fn raise_kind(a: kind, b: kind) -> kind {
fn test_kinds() { fn test_kinds() {
// The kind "lattice" is defined by the subset operation on the // The kind "lattice" is defined by the subset operation on the
// set of permitted operations. // set of permitted operations.
assert kind_lteq(kind_sendable(), kind_sendable()); assert kind_lteq(kind_send_copy(), kind_send_copy());
assert kind_lteq(kind_copyable(), kind_sendable()); assert kind_lteq(kind_copyable(), kind_send_copy());
assert kind_lteq(kind_copyable(), kind_copyable()); assert kind_lteq(kind_copyable(), kind_copyable());
assert kind_lteq(kind_noncopyable(), kind_sendable()); assert kind_lteq(kind_noncopyable(), kind_send_copy());
assert kind_lteq(kind_noncopyable(), kind_copyable()); assert kind_lteq(kind_noncopyable(), kind_copyable());
assert kind_lteq(kind_noncopyable(), kind_noncopyable()); assert kind_lteq(kind_noncopyable(), kind_noncopyable());
assert kind_lteq(kind_copyable(), kind_implicitly_copyable()); assert kind_lteq(kind_copyable(), kind_implicitly_copyable());
assert kind_lteq(kind_copyable(), kind_implicitly_sendable()); assert kind_lteq(kind_copyable(), kind_implicitly_sendable());
assert kind_lteq(kind_sendable(), kind_implicitly_sendable()); assert kind_lteq(kind_send_copy(), kind_implicitly_sendable());
assert !kind_lteq(kind_sendable(), kind_implicitly_copyable()); assert !kind_lteq(kind_send_copy(), kind_implicitly_copyable());
assert !kind_lteq(kind_copyable(), kind_send_only()); assert !kind_lteq(kind_copyable(), kind_send_only());
} }
@ -1447,66 +1483,73 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
cx.kind_cache.insert(ty, kind_top()); cx.kind_cache.insert(ty, kind_top());
let result = alt get(ty).struct { let result = alt get(ty).struct {
// Scalar and unique types are sendable // Scalar and unique types are sendable, constant, and owned
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
ty_ptr(_) { kind_implicitly_sendable() | kind_const() } ty_ptr(_) {
kind_implicitly_sendable() | kind_const() | kind_owned()
}
// Implicit copyability of strs is configurable // Implicit copyability of strs is configurable
ty_estr(vstore_uniq) { ty_estr(vstore_uniq) {
if cx.vecs_implicitly_copyable { if cx.vecs_implicitly_copyable {
kind_implicitly_sendable() | kind_const() kind_implicitly_sendable() | kind_const() | kind_owned()
} else { kind_sendable() | kind_const() } } else {
kind_send_copy() | kind_const() | kind_owned()
}
} }
// functions depend on the protocol
ty_fn(f) { proto_kind(f.proto) } ty_fn(f) { proto_kind(f.proto) }
// Those with refcounts raise noncopyable to copyable, // Those with refcounts raise noncopyable to copyable,
// lower sendable to copyable. Therefore just set result to copyable. // lower sendable to copyable. Therefore just set result to copyable.
ty_box(tm) { ty_box(tm) {
if tm.mutbl == ast::m_mutbl { remove_send(mutable_type_kind(cx, tm) | kind_implicitly_copyable())
kind_implicitly_copyable()
}
else {
let k = type_kind(cx, tm.ty);
if kind_lteq(kind_const(), k) {
kind_implicitly_copyable() | kind_const()
}
else { kind_implicitly_copyable() }
}
} }
ty_trait(_, _) { kind_implicitly_copyable() }
// Iface instances are (for now) like shared boxes, basically
ty_trait(_, _) { kind_implicitly_copyable() | kind_owned() }
// Region pointers are copyable but NOT owned nor sendable
ty_rptr(_, _) { kind_implicitly_copyable() } ty_rptr(_, _) { kind_implicitly_copyable() }
// Unique boxes and vecs have the kind of their contained type, // Unique boxes and vecs have the kind of their contained type,
// but unique boxes can't be implicitly copyable. // but unique boxes can't be implicitly copyable.
ty_uniq(tm) { ty_uniq(tm) { remove_implicit(mutable_type_kind(cx, tm)) }
remove_implicit(mutable_type_kind(cx, tm))
}
// Implicit copyability of vecs is configurable // Implicit copyability of vecs is configurable
ty_evec(tm, vstore_uniq) { ty_evec(tm, vstore_uniq) {
if cx.vecs_implicitly_copyable { if cx.vecs_implicitly_copyable {
mutable_type_kind(cx, tm) mutable_type_kind(cx, tm)
} else { remove_implicit(mutable_type_kind(cx, tm)) } } else {
remove_implicit(mutable_type_kind(cx, tm))
}
} }
// Slices, refcounted evecs are copyable; uniques depend on the their // Slices, refcounted evecs are copyable; uniques depend on the their
// contained type, but aren't implicitly copyable. Fixed vectors have // contained type, but aren't implicitly copyable. Fixed vectors have
// the kind of the element they contain, taking mutability into account. // the kind of the element they contain, taking mutability into account.
ty_evec(tm, vstore_box) | ty_evec(tm, vstore_box) {
remove_send(kind_implicitly_copyable() | mutable_type_kind(cx, tm))
}
ty_evec(tm, vstore_slice(_)) { ty_evec(tm, vstore_slice(_)) {
if kind_lteq(kind_const(), type_kind(cx, tm.ty)) { remove_owned_send(kind_implicitly_copyable() |
kind_implicitly_copyable() | kind_const() mutable_type_kind(cx, tm))
}
else {
kind_implicitly_copyable()
}
} }
ty_evec(tm, vstore_fixed(_)) { ty_evec(tm, vstore_fixed(_)) {
mutable_type_kind(cx, tm) mutable_type_kind(cx, tm)
} }
// All estrs are copyable; uniques and interiors are sendable. // All estrs are copyable; uniques and interiors are sendable.
ty_estr(vstore_box) | ty_estr(vstore_box) {
ty_estr(vstore_slice(_)) { kind_implicitly_copyable() | kind_const() } kind_implicitly_copyable() | kind_const() | kind_owned()
ty_estr(vstore_fixed(_)) { kind_implicitly_sendable() | kind_const() } }
ty_estr(vstore_slice(_)) {
kind_implicitly_copyable() | kind_const()
}
ty_estr(vstore_fixed(_)) {
kind_implicitly_sendable() | kind_const() | kind_owned()
}
// Records lower to the lowest of their members. // Records lower to the lowest of their members.
ty_rec(flds) { ty_rec(flds) {
@ -1516,6 +1559,7 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
} }
lowest lowest
} }
ty_class(did, substs) { ty_class(did, substs) {
// Classes are sendable if all their fields are sendable, // Classes are sendable if all their fields are sendable,
// likewise for copyable... // likewise for copyable...
@ -1532,18 +1576,20 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
} }
lowest lowest
} }
// Tuples lower to the lowest of their members. // Tuples lower to the lowest of their members.
ty_tup(tys) { ty_tup(tys) {
let mut lowest = kind_top(); let mut lowest = kind_top();
for tys.each |ty| { lowest = lower_kind(lowest, type_kind(cx, ty)); } for tys.each |ty| { lowest = lower_kind(lowest, type_kind(cx, ty)); }
lowest lowest
} }
// Enums lower to the lowest of their variants. // Enums lower to the lowest of their variants.
ty_enum(did, substs) { ty_enum(did, substs) {
let mut lowest = kind_top(); let mut lowest = kind_top();
let variants = enum_variants(cx, did); let variants = enum_variants(cx, did);
if vec::len(*variants) == 0u { if vec::len(*variants) == 0u {
lowest = kind_send_only(); lowest = kind_send_only() | kind_owned();
} else { } else {
for vec::each(*variants) |variant| { for vec::each(*variants) |variant| {
for variant.args.each |aty| { for variant.args.each |aty| {
@ -1556,11 +1602,15 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
} }
lowest lowest
} }
ty_param(_, did) { ty_param(_, did) {
param_bounds_to_kind(cx.ty_param_bounds.get(did.node)) param_bounds_to_kind(cx.ty_param_bounds.get(did.node))
} }
// FIXME (#2663): is self ever const?
// self is a special type parameter that can only appear in ifaces; it
// is never bounded in any way, hence it has the bottom kind.
ty_self { kind_noncopyable() } ty_self { kind_noncopyable() }
ty_var(_) | ty_var_integral(_) { ty_var(_) | ty_var_integral(_) {
cx.sess.bug(~"Asked to compute kind of a type variable"); cx.sess.bug(~"Asked to compute kind of a type variable");
} }

View file

@ -169,7 +169,8 @@ class lookup {
let bounds = tcx.ty_param_bounds.get(did.node); let bounds = tcx.ty_param_bounds.get(did.node);
for vec::each(*bounds) |bound| { for vec::each(*bounds) |bound| {
let (iid, bound_substs) = alt bound { let (iid, bound_substs) = alt bound {
ty::bound_copy | ty::bound_send | ty::bound_const { ty::bound_copy | ty::bound_send | ty::bound_const |
ty::bound_owned {
again; /* ok */ again; /* ok */
} }
ty::bound_trait(bound_t) { ty::bound_trait(bound_t) {

View file

@ -68,7 +68,8 @@ fn lookup_vtable(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
let mut n_bound = 0u; let mut n_bound = 0u;
for vec::each(*tcx.ty_param_bounds.get(did.node)) |bound| { for vec::each(*tcx.ty_param_bounds.get(did.node)) |bound| {
alt bound { alt bound {
ty::bound_send | ty::bound_copy | ty::bound_const { ty::bound_send | ty::bound_copy | ty::bound_const |
ty::bound_owned {
/* ignore */ /* ignore */
} }
ty::bound_trait(ity) { ty::bound_trait(ity) {

View file

@ -572,6 +572,7 @@ fn ty_param_bounds(ccx: @crate_ctxt,
ast::bound_send { ~[ty::bound_send] } ast::bound_send { ~[ty::bound_send] }
ast::bound_copy { ~[ty::bound_copy] } ast::bound_copy { ~[ty::bound_copy] }
ast::bound_const { ~[ty::bound_const] } ast::bound_const { ~[ty::bound_const] }
ast::bound_owned { ~[ty::bound_owned] }
ast::bound_trait(t) { ast::bound_trait(t) {
let ity = ast_ty_to_ty(ccx, empty_rscope, t); let ity = ast_ty_to_ty(ccx, empty_rscope, t);
alt ty::get(ity).struct { alt ty::get(ity).struct {

View file

@ -57,7 +57,6 @@ fn re_scope_id_to_str(cx: ctxt, node_id: ast::node_id) -> ~str {
} }
} }
none { none {
// FIXME(#2586)
#fmt["<unknown-%d>", node_id] #fmt["<unknown-%d>", node_id]
} }
_ { cx.sess.bug( _ { cx.sess.bug(

View file

@ -1,11 +1,9 @@
// error-pattern: copying a noncopyable value
fn to_lambda1(f: fn@(uint) -> uint) -> fn@(uint) -> uint { fn to_lambda1(f: fn@(uint) -> uint) -> fn@(uint) -> uint {
ret f; ret f;
} }
fn to_lambda2(b: fn(uint) -> uint) -> fn@(uint) -> uint { fn to_lambda2(b: fn(uint) -> uint) -> fn@(uint) -> uint {
ret to_lambda1({|x| b(x)}); ret to_lambda1({|x| b(x)}); //~ ERROR not an owned value
} }
fn main() { fn main() {

View file

@ -1,6 +1,8 @@
// error-pattern: copying a noncopyable value // error-pattern: copying a noncopyable value
fn to_lambda2(b: fn(uint) -> uint) -> fn@(uint) -> uint { class foo { let x: int; new(x: int) { self.x = x; } drop { } }
fn to_lambda2(b: foo) -> fn@(uint) -> uint {
// test case where copy clause specifies a value that is not used // test case where copy clause specifies a value that is not used
// in fn@ body, but value is illegal to copy: // in fn@ body, but value is illegal to copy:
ret fn@(u: uint, copy b) -> uint { 22u }; ret fn@(u: uint, copy b) -> uint { 22u };

View file

@ -0,0 +1,19 @@
fn copy1<T: copy>(t: T) -> fn@() -> T {
fn@() -> T { t } //~ ERROR not an owned value
}
fn copy2<T: copy owned>(t: T) -> fn@() -> T {
fn@() -> T { t }
}
fn main() {
let x = &3;
copy2(&x); //~ ERROR instantiating a type parameter with an incompatible type
copy2(@3);
copy2(@&x); //~ ERROR instantiating a type parameter with an incompatible type
copy2(fn@() {});
copy2(fn~() {}); //~ WARNING instantiating copy type parameter with a not implicitly copyable type
copy2(fn&() {}); //~ ERROR instantiating a type parameter with an incompatible type
}

View file

@ -2,7 +2,7 @@ type pair<A,B> = {
a: A, b: B a: A, b: B
}; };
fn f<A:copy>(a: A, b: u16) -> fn@() -> (A, u16) { fn f<A:copy owned>(a: A, b: u16) -> fn@() -> (A, u16) {
fn@() -> (A, u16) { (a, b) } fn@() -> (A, u16) { (a, b) }
} }

View file

@ -6,7 +6,7 @@ type pair<A,B> = {
a: A, b: B a: A, b: B
}; };
fn f<A:copy>(a: A, b: u16) -> fn@() -> (A, u16) { fn f<A:copy owned>(a: A, b: u16) -> fn@() -> (A, u16) {
fn@() -> (A, u16) { (a, b) } fn@() -> (A, u16) { (a, b) }
} }

View file

@ -1,8 +1,8 @@
fn fix_help<A, B: send>(f: extern fn(fn@(A) -> B, A) -> B, x: A) -> B { fn fix_help<A: owned, B: send>(f: extern fn(fn@(A) -> B, A) -> B, x: A) -> B {
ret f({|a|fix_help(f, a)}, x); ret f({|a|fix_help(f, a)}, x);
} }
fn fix<A, B: send>(f: extern fn(fn@(A) -> B, A) -> B) -> fn@(A) -> B { fn fix<A: owned, B: send>(f: extern fn(fn@(A) -> B, A) -> B) -> fn@(A) -> B {
ret {|a|fix_help(f, a)}; ret {|a|fix_help(f, a)};
} }