introduce an owned kind for data that contains no borrowed ptrs
This commit is contained in:
parent
d809336d0f
commit
0e42004bab
25 changed files with 245 additions and 142 deletions
|
@ -62,6 +62,7 @@ enum ty_param_bound {
|
|||
bound_copy,
|
||||
bound_send,
|
||||
bound_const,
|
||||
bound_owned,
|
||||
bound_trait(@ty),
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
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)) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ import dvec::{dvec, extensions};
|
|||
import vec::{push};
|
||||
import ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute,
|
||||
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,
|
||||
carg_base, carg_ident, cdir_dir_mod, cdir_src_mod,
|
||||
cdir_view_item, checked_expr, claimed_expr, class_immutable,
|
||||
|
@ -1935,12 +1936,16 @@ class parser {
|
|||
let ident = self.parse_ident();
|
||||
if self.eat(token::COLON) {
|
||||
while self.token != token::COMMA && self.token != token::GT {
|
||||
if self.eat_keyword(~"send") { push(bounds, bound_send); }
|
||||
else if self.eat_keyword(~"copy") { push(bounds, bound_copy) }
|
||||
if self.eat_keyword(~"send") {
|
||||
push(bounds, bound_send); }
|
||||
else if self.eat_keyword(~"copy") {
|
||||
push(bounds, bound_copy) }
|
||||
else if self.eat_keyword(~"const") {
|
||||
push(bounds, bound_const)
|
||||
}
|
||||
else { push(bounds, bound_trait(self.parse_ty(false))); }
|
||||
push(bounds, bound_const);
|
||||
} else if self.eat_keyword(~"owned") {
|
||||
push(bounds, bound_owned);
|
||||
} else {
|
||||
push(bounds, bound_trait(self.parse_ty(false))); }
|
||||
}
|
||||
}
|
||||
ret {ident: ident, id: self.get_id(), bounds: @bounds};
|
||||
|
|
|
@ -313,7 +313,7 @@ fn restricted_keyword_table() -> hashmap<~str, ()> {
|
|||
~"if", ~"iface", ~"impl", ~"import",
|
||||
~"let", ~"log", ~"loop",
|
||||
~"mod", ~"mut",
|
||||
~"new",
|
||||
~"new", ~"owned",
|
||||
~"pure", ~"ret",
|
||||
~"true", ~"trait", ~"type",
|
||||
~"unchecked", ~"unsafe",
|
||||
|
|
|
@ -1377,6 +1377,7 @@ fn print_bounds(s: ps, bounds: @~[ast::ty_param_bound]) {
|
|||
ast::bound_copy { word(s.s, ~"copy"); }
|
||||
ast::bound_send { word(s.s, ~"send"); }
|
||||
ast::bound_const { word(s.s, ~"const"); }
|
||||
ast::bound_owned { word(s.s, ~"owned"); }
|
||||
ast::bound_trait(t) { print_type(s, t); }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -246,7 +246,7 @@ fn visit_ty_params<E>(tps: ~[ty_param], e: E, v: vt<E>) {
|
|||
for vec::each(*tp.bounds) |bound| {
|
||||
alt bound {
|
||||
bound_trait(t) { v.visit_ty(t, e, v); }
|
||||
bound_copy | bound_send | bound_const { }
|
||||
bound_copy | bound_send | bound_const | bound_owned { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -417,6 +417,7 @@ fn parse_bounds(st: @pstate, conv: conv_did) -> @~[ty::param_bound] {
|
|||
'S' { ty::bound_send }
|
||||
'C' { ty::bound_copy }
|
||||
'K' { ty::bound_const }
|
||||
'O' { ty::bound_owned }
|
||||
'I' { ty::bound_trait(parse_ty(st, conv)) }
|
||||
'.' { break; }
|
||||
});
|
||||
|
|
|
@ -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_copy { w.write_char('C'); }
|
||||
ty::bound_const { w.write_char('K'); }
|
||||
ty::bound_owned { w.write_char('O'); }
|
||||
ty::bound_trait(tp) {
|
||||
w.write_char('I');
|
||||
enc_ty(w, cx, tp);
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import syntax::{visit, ast_util};
|
||||
import syntax::ast::*;
|
||||
import syntax::codemap::span;
|
||||
import ty::{kind, kind_sendable, kind_copyable, kind_noncopyable, kind_const,
|
||||
operators};
|
||||
import ty::{kind, kind_copyable, kind_noncopyable, kind_const, operators};
|
||||
import driver::session::session;
|
||||
import std::map::hashmap;
|
||||
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.
|
||||
// const: Things thare are deeply immutable. They are guaranteed never to
|
||||
// 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
|
||||
// only sendable types.
|
||||
|
@ -41,15 +41,21 @@ import lint::{non_implicitly_copyable_typarams,implicit_copies};
|
|||
|
||||
fn kind_to_str(k: kind) -> ~str {
|
||||
let mut kinds = ~[];
|
||||
|
||||
if ty::kind_lteq(kind_const(), k) {
|
||||
vec::push(kinds, ~"const");
|
||||
}
|
||||
|
||||
if ty::kind_can_be_copied(k) {
|
||||
vec::push(kinds, ~"copy");
|
||||
}
|
||||
|
||||
if ty::kind_can_be_sent(k) {
|
||||
vec::push(kinds, ~"send");
|
||||
} else if ty::kind_is_owned(k) {
|
||||
vec::push(kinds, ~"owned");
|
||||
}
|
||||
|
||||
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>,
|
||||
is_move: bool, var_t: ty::t, sp: span) {
|
||||
// all captured data must be sendable, regardless of whether it is
|
||||
// moved in or copied in
|
||||
check_send(cx, var_t, sp);
|
||||
// moved in or copied in. Note that send implies owned.
|
||||
if !check_send(cx, var_t, sp) { ret; }
|
||||
|
||||
// copied in data must be copyable, but moved in data can be anything
|
||||
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>,
|
||||
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
|
||||
let is_implicit = fv.is_some();
|
||||
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)) {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import metadata::cstore::find_use_stmt_cnum;
|
|||
import metadata::decoder::{def_like, dl_def, dl_field, dl_impl};
|
||||
import middle::lint::{error, ignore, level, unused_imports, warn};
|
||||
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::{class_member, class_method, crate, crate_num, decl_item};
|
||||
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_parameter.bounds).each |bound| {
|
||||
alt bound {
|
||||
bound_copy | bound_send | bound_const {
|
||||
bound_copy | bound_send | bound_const | bound_owned {
|
||||
// Nothing to do.
|
||||
}
|
||||
bound_trait(interface_type) {
|
||||
|
|
|
@ -1373,23 +1373,23 @@ fn move_val(cx: block, action: copy_action, dst: ValueRef,
|
|||
let tcx = cx.tcx();
|
||||
let mut cx = cx;
|
||||
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);
|
||||
ret cx;
|
||||
} else if ty::type_is_nil(t) || ty::type_is_bot(t) {
|
||||
ret cx;
|
||||
} 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); }
|
||||
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.
|
||||
revoke_clean(cx, src_val);
|
||||
ret cx;
|
||||
} else if type_is_structural_or_param(t) {
|
||||
if action == DROP_EXISTING { cx = drop_ty(cx, dst, 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.
|
||||
revoke_clean(cx, src_val);
|
||||
ret cx;
|
||||
|
@ -1403,8 +1403,8 @@ fn store_temp_expr(cx: block, action: copy_action, dst: ValueRef,
|
|||
-> block {
|
||||
let _icx = cx.insn_ctxt(~"trans_temp_expr");
|
||||
// Lvals in memory are not temporaries. Copy them.
|
||||
if src.kind != temporary && !last_use {
|
||||
let v = if src.kind == owned {
|
||||
if src.kind != lv_temporary && !last_use {
|
||||
let v = if src.kind == lv_owned {
|
||||
load_if_immediate(cx, src.val, t)
|
||||
} else {
|
||||
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 ety = expr_ty(cx, e);
|
||||
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);
|
||||
}
|
||||
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 t = expr_ty(bcx, src);
|
||||
let lhs_res = trans_lval(bcx, dst);
|
||||
assert (lhs_res.kind == owned);
|
||||
assert (lhs_res.kind == lv_owned);
|
||||
|
||||
// A user-defined operator method
|
||||
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));
|
||||
|
||||
ret move_val(bcx, DROP_EXISTING, lhs_res.val,
|
||||
{bcx: bcx, val: target, kind: owned},
|
||||
{bcx: bcx, val: target, kind: lv_owned},
|
||||
dty);
|
||||
}
|
||||
_ {}
|
||||
|
@ -1947,9 +1947,9 @@ fn trans_loop(cx:block, body: ast::blk) -> block {
|
|||
}
|
||||
|
||||
enum lval_kind {
|
||||
temporary, //< Temporary value passed by value if of immediate type
|
||||
owned, //< Non-temporary value passed by pointer
|
||||
owned_imm, //< Non-temporary value passed by value
|
||||
lv_temporary, //< Temporary value passed by value if of immediate type
|
||||
lv_owned, //< Non-temporary value passed by pointer
|
||||
lv_owned_imm, //< Non-temporary value passed by value
|
||||
}
|
||||
type local_var_result = {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 {
|
||||
ret {bcx: bcx, val: val, kind: owned};
|
||||
ret {bcx: bcx, val: val, kind: lv_owned};
|
||||
}
|
||||
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)
|
||||
|
@ -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(
|
||||
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 {
|
||||
|
@ -2376,7 +2376,7 @@ fn lval_static_fn_inner(bcx: block, fn_id: ast::def_id, id: ast::node_id,
|
|||
ast::extern_fn {
|
||||
// Extern functions are just opaque pointers
|
||||
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 */ }
|
||||
}
|
||||
|
@ -2384,7 +2384,7 @@ fn lval_static_fn_inner(bcx: block, fn_id: ast::def_id, id: ast::node_id,
|
|||
_ { /* 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 {
|
||||
|
@ -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>,
|
||||
id: ast::node_id) -> local_var_result {
|
||||
alt table.find(id) {
|
||||
some(local_mem(v)) { {val: v, kind: owned} }
|
||||
some(local_imm(v)) { {val: v, kind: owned_imm} }
|
||||
some(local_mem(v)) { {val: v, kind: lv_owned} }
|
||||
some(local_imm(v)) { {val: v, kind: lv_owned_imm} }
|
||||
r { fail(~"take_local: internal error"); }
|
||||
}
|
||||
}
|
||||
alt def {
|
||||
ast::def_upvar(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, _) {
|
||||
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 \
|
||||
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: %?",
|
||||
|
@ -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 = Load(cx, lldiscrim_gv);
|
||||
Store(cx, lldiscrim, lldiscrimptr);
|
||||
ret lval_no_env(cx, llenumptr, temporary);
|
||||
ret lval_no_env(cx, llenumptr, lv_temporary);
|
||||
}
|
||||
}
|
||||
ast::def_const(did) {
|
||||
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 {
|
||||
let tp = node_id_type(cx, id);
|
||||
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]) };
|
||||
|
||||
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 llfn = create_real_fn_pair(c.bcx, llfnty, c.val,
|
||||
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) {
|
||||
let scratch = alloc_ty(cx, expr_ty(cx, blk));
|
||||
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, ty: e_ty} =
|
||||
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}
|
||||
};
|
||||
|
||||
|
@ -2904,14 +2905,14 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
|
|||
alt arg_mode {
|
||||
ast::by_ref | ast::by_mutbl_ref {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
ast::by_val {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
@ -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 move_out = arg_mode == ast::by_move ||
|
||||
ccx.maps.last_use_map.contains_key(e.id);
|
||||
if lv.kind == temporary { revoke_clean(bcx, val); }
|
||||
if lv.kind == owned || !ty::type_is_immediate(arg.ty) {
|
||||
if lv.kind == lv_temporary { revoke_clean(bcx, val); }
|
||||
if lv.kind == lv_owned || !ty::type_is_immediate(arg.ty) {
|
||||
memmove_ty(bcx, alloc, val, arg.ty);
|
||||
if move_out && ty::type_needs_drop(ccx.tcx, arg.ty) {
|
||||
bcx = zero_mem(bcx, val, arg.ty);
|
||||
}
|
||||
} else { Store(bcx, val, alloc); }
|
||||
val = alloc;
|
||||
if lv.kind != temporary && !move_out {
|
||||
if lv.kind != lv_temporary && !move_out {
|
||||
bcx = take_ty(bcx, val, arg.ty);
|
||||
}
|
||||
|
||||
|
@ -2977,9 +2978,9 @@ fn adapt_borrowed_value(lv: lval_result,
|
|||
ty::ty_estr(_) | ty::ty_evec(_, _) {
|
||||
let ccx = bcx.ccx();
|
||||
let val = alt lv.kind {
|
||||
temporary { lv.val }
|
||||
owned { load_if_immediate(bcx, lv.val, e_ty) }
|
||||
owned_imm { lv.val }
|
||||
lv_temporary { lv.val }
|
||||
lv_owned { load_if_immediate(bcx, lv.val, e_ty) }
|
||||
lv_owned_imm { lv.val }
|
||||
};
|
||||
|
||||
let unit_ty = ty::sequence_element_type(ccx.tcx, e_ty);
|
||||
|
@ -3150,7 +3151,7 @@ fn trans_call_inner(
|
|||
}
|
||||
is_closure {
|
||||
// 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);
|
||||
}
|
||||
let pair = faddr;
|
||||
|
@ -3418,17 +3419,17 @@ fn trans_temp_lval(bcx: block, e: @ast::expr) -> lval_result {
|
|||
let ty = expr_ty(bcx, e);
|
||||
if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
|
||||
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) {
|
||||
let cell = empty_dest_cell();
|
||||
bcx = trans_expr(bcx, e, by_val(cell));
|
||||
add_clean_temp(bcx, *cell, ty);
|
||||
ret {bcx: bcx, val: *cell, kind: temporary};
|
||||
ret {bcx: bcx, val: *cell, kind: lv_temporary};
|
||||
} else {
|
||||
let scratch = alloc_ty(bcx, ty);
|
||||
let bcx = trans_expr_save_in(bcx, e, scratch);
|
||||
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 {
|
||||
alt lv.kind {
|
||||
temporary { lv.val }
|
||||
owned { load_if_immediate(lv.bcx, lv.val, ty) }
|
||||
owned_imm { lv.val }
|
||||
lv_temporary { lv.val }
|
||||
lv_owned { load_if_immediate(lv.bcx, lv.val, ty) }
|
||||
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");
|
||||
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)
|
||||
}
|
||||
};
|
||||
|
@ -3647,7 +3648,7 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
|
|||
assert dest == ignore;
|
||||
let src_r = trans_temp_lval(bcx, src);
|
||||
let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst);
|
||||
assert kind == owned;
|
||||
assert kind == lv_owned;
|
||||
let is_last_use =
|
||||
bcx.ccx().maps.last_use_map.contains_key(src.id);
|
||||
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;
|
||||
let src_r = trans_temp_lval(bcx, src);
|
||||
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,
|
||||
expr_ty(bcx, src));
|
||||
}
|
||||
ast::expr_swap(dst, src) {
|
||||
assert dest == ignore;
|
||||
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 t = expr_ty(bcx, src);
|
||||
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 ty = expr_ty(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,
|
||||
lv.kind as int];
|
||||
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();
|
||||
alt dest {
|
||||
by_val(cell) {
|
||||
if kind == temporary {
|
||||
if kind == lv_temporary {
|
||||
revoke_clean(bcx, val);
|
||||
*cell = val;
|
||||
} 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);
|
||||
}
|
||||
} 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);
|
||||
*cell = val;
|
||||
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
|
||||
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
|
||||
bcx = store_temp_expr(bcx, INIT, fcx.llretptr, lval_res,
|
||||
rslt_ty, true);
|
||||
|
|
|
@ -216,31 +216,31 @@ fn store_environment(bcx: block,
|
|||
let bound_data = GEPi(bcx, llbox,
|
||||
~[0u, abi::box_field_body, i]);
|
||||
alt bv {
|
||||
env_copy(val, ty, owned) {
|
||||
env_copy(val, ty, lv_owned) {
|
||||
let val1 = load_if_immediate(bcx, val, 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);
|
||||
}
|
||||
env_copy(_, _, temporary) {
|
||||
env_copy(_, _, lv_temporary) {
|
||||
fail ~"cannot capture temporary upvar";
|
||||
}
|
||||
env_move(val, ty, kind) {
|
||||
let src = {bcx:bcx, val:val, kind:kind};
|
||||
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",
|
||||
val_str(bcx.ccx().tn, val),
|
||||
val_str(bcx.ccx().tn, 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);
|
||||
Store(bcx, addr, bound_data);
|
||||
}
|
||||
env_ref(_, _, temporary) {
|
||||
env_ref(_, _, lv_temporary) {
|
||||
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));
|
||||
}
|
||||
capture::cap_drop {
|
||||
assert lv.kind == owned;
|
||||
assert lv.kind == lv_owned;
|
||||
bcx = drop_ty(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()));
|
||||
vec::push(env_vals,
|
||||
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,
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -881,7 +881,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
|
|||
let tp_ty = substs.tys[0];
|
||||
let src = {bcx: bcx,
|
||||
val: get_param(decl, first_real_arg + 1u),
|
||||
kind: owned };
|
||||
kind: lv_owned};
|
||||
bcx = move_val(bcx, DROP_EXISTING,
|
||||
get_param(decl, first_real_arg),
|
||||
src,
|
||||
|
@ -891,7 +891,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
|
|||
let tp_ty = substs.tys[0];
|
||||
let src = {bcx: bcx,
|
||||
val: get_param(decl, first_real_arg + 1u),
|
||||
kind: owned };
|
||||
kind: lv_owned};
|
||||
bcx = move_val(bcx, INIT,
|
||||
get_param(decl, first_real_arg),
|
||||
src,
|
||||
|
@ -982,7 +982,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
|
|||
|bcx| lval_no_env(
|
||||
bcx,
|
||||
get_param(decl, first_real_arg),
|
||||
temporary),
|
||||
lv_temporary),
|
||||
arg_vals(~[frameaddress_val]), ignore);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -162,7 +162,7 @@ fn trans_trait_callee(bcx: block, val: ValueRef,
|
|||
let vtable = PointerCast(bcx, vtable,
|
||||
T_ptr(T_array(T_ptr(llfty), n_method + 1u)));
|
||||
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)
|
||||
|
|
|
@ -107,9 +107,10 @@ export tbox_has_flag;
|
|||
export ty_var_id;
|
||||
export ty_to_def_id;
|
||||
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_can_be_copied, kind_can_be_sent, kind_can_be_implicitly_copied;
|
||||
export kind_is_owned;
|
||||
export proto_kind, kind_lteq, type_kind;
|
||||
export operators;
|
||||
export type_err, terr_vstore_kind;
|
||||
|
@ -144,7 +145,8 @@ export closure_kind;
|
|||
export ck_block;
|
||||
export ck_box;
|
||||
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 default_arg_mode_for_ty;
|
||||
export item_path;
|
||||
|
@ -409,6 +411,7 @@ enum type_err {
|
|||
|
||||
enum param_bound {
|
||||
bound_copy,
|
||||
bound_owned,
|
||||
bound_send,
|
||||
bound_const,
|
||||
bound_trait(t),
|
||||
|
@ -451,8 +454,15 @@ fn param_bounds_to_kind(bounds: param_bounds) -> kind {
|
|||
bound_copy {
|
||||
kind = raise_kind(kind, kind_implicitly_copyable());
|
||||
}
|
||||
bound_send { kind = raise_kind(kind, kind_send_only()); }
|
||||
bound_const { kind = raise_kind(kind, kind_const()); }
|
||||
bound_owned {
|
||||
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(_) {}
|
||||
}
|
||||
}
|
||||
|
@ -1303,11 +1313,20 @@ fn type_needs_unwind_cleanup_(cx: ctxt, ty: t,
|
|||
|
||||
enum kind { kind_(u32) }
|
||||
|
||||
// *ALL* implicitly copiable things must be copiable
|
||||
const KIND_MASK_COPY : u32 = 0b00000000000000000000000000000001u32;
|
||||
const KIND_MASK_SEND : u32 = 0b00000000000000000000000000000010u32;
|
||||
const KIND_MASK_CONST : u32 = 0b00000000000000000000000000000100u32;
|
||||
const KIND_MASK_IMPLICIT : u32 = 0b00000000000000000000000000001000u32;
|
||||
/// can be copied (implicitly or explicitly)
|
||||
const KIND_MASK_COPY : u32 = 0b00000000000000000000000000000001_u32;
|
||||
|
||||
/// can be sent: no shared box, borrowed ptr (must imply OWNED)
|
||||
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 {
|
||||
kind_(0u32)
|
||||
|
@ -1325,7 +1344,7 @@ fn kind_implicitly_sendable() -> kind {
|
|||
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)
|
||||
}
|
||||
|
||||
|
@ -1337,6 +1356,10 @@ fn kind_const() -> kind {
|
|||
kind_(KIND_MASK_CONST)
|
||||
}
|
||||
|
||||
fn kind_owned() -> kind {
|
||||
kind_(KIND_MASK_OWNED)
|
||||
}
|
||||
|
||||
fn kind_top() -> kind {
|
||||
kind_(0xffffffffu32)
|
||||
}
|
||||
|
@ -1349,6 +1372,14 @@ fn remove_implicit(k: kind) -> kind {
|
|||
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 {
|
||||
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
|
||||
// future.
|
||||
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 {
|
||||
*k & KIND_MASK_COPY != 0u32
|
||||
*k & KIND_MASK_COPY == KIND_MASK_COPY
|
||||
}
|
||||
|
||||
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 {
|
||||
alt p {
|
||||
ast::proto_any { kind_noncopyable() }
|
||||
ast::proto_block { kind_noncopyable() }
|
||||
ast::proto_box { kind_implicitly_copyable() }
|
||||
ast::proto_uniq { kind_sendable() }
|
||||
ast::proto_bare { kind_implicitly_sendable() | kind_const() }
|
||||
ast::proto_box { kind_implicitly_copyable() | kind_owned() }
|
||||
ast::proto_uniq { kind_send_copy() | kind_owned() }
|
||||
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() {
|
||||
// The kind "lattice" is defined by the subset operation on the
|
||||
// set of permitted operations.
|
||||
assert kind_lteq(kind_sendable(), kind_sendable());
|
||||
assert kind_lteq(kind_copyable(), kind_sendable());
|
||||
assert kind_lteq(kind_send_copy(), kind_send_copy());
|
||||
assert kind_lteq(kind_copyable(), kind_send_copy());
|
||||
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_noncopyable());
|
||||
assert kind_lteq(kind_copyable(), kind_implicitly_copyable());
|
||||
assert kind_lteq(kind_copyable(), kind_implicitly_sendable());
|
||||
assert kind_lteq(kind_sendable(), kind_implicitly_sendable());
|
||||
assert !kind_lteq(kind_sendable(), kind_implicitly_copyable());
|
||||
assert kind_lteq(kind_send_copy(), kind_implicitly_sendable());
|
||||
assert !kind_lteq(kind_send_copy(), kind_implicitly_copyable());
|
||||
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());
|
||||
|
||||
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_ptr(_) { kind_implicitly_sendable() | kind_const() }
|
||||
ty_ptr(_) {
|
||||
kind_implicitly_sendable() | kind_const() | kind_owned()
|
||||
}
|
||||
|
||||
// Implicit copyability of strs is configurable
|
||||
ty_estr(vstore_uniq) {
|
||||
if cx.vecs_implicitly_copyable {
|
||||
kind_implicitly_sendable() | kind_const()
|
||||
} else { kind_sendable() | kind_const() }
|
||||
kind_implicitly_sendable() | kind_const() | kind_owned()
|
||||
} else {
|
||||
kind_send_copy() | kind_const() | kind_owned()
|
||||
}
|
||||
}
|
||||
|
||||
// functions depend on the protocol
|
||||
ty_fn(f) { proto_kind(f.proto) }
|
||||
|
||||
// Those with refcounts raise noncopyable to copyable,
|
||||
// lower sendable to copyable. Therefore just set result to copyable.
|
||||
ty_box(tm) {
|
||||
if tm.mutbl == ast::m_mutbl {
|
||||
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() }
|
||||
}
|
||||
remove_send(mutable_type_kind(cx, tm) | 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() }
|
||||
|
||||
// Unique boxes and vecs have the kind of their contained type,
|
||||
// but unique boxes can't be implicitly copyable.
|
||||
ty_uniq(tm) {
|
||||
remove_implicit(mutable_type_kind(cx, tm))
|
||||
}
|
||||
ty_uniq(tm) { remove_implicit(mutable_type_kind(cx, tm)) }
|
||||
|
||||
// Implicit copyability of vecs is configurable
|
||||
ty_evec(tm, vstore_uniq) {
|
||||
if cx.vecs_implicitly_copyable {
|
||||
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
|
||||
// contained type, but aren't implicitly copyable. Fixed vectors have
|
||||
// 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(_)) {
|
||||
if kind_lteq(kind_const(), type_kind(cx, tm.ty)) {
|
||||
kind_implicitly_copyable() | kind_const()
|
||||
}
|
||||
else {
|
||||
kind_implicitly_copyable()
|
||||
}
|
||||
remove_owned_send(kind_implicitly_copyable() |
|
||||
mutable_type_kind(cx, tm))
|
||||
}
|
||||
ty_evec(tm, vstore_fixed(_)) {
|
||||
mutable_type_kind(cx, tm)
|
||||
}
|
||||
|
||||
// All estrs are copyable; uniques and interiors are sendable.
|
||||
ty_estr(vstore_box) |
|
||||
ty_estr(vstore_slice(_)) { kind_implicitly_copyable() | kind_const() }
|
||||
ty_estr(vstore_fixed(_)) { kind_implicitly_sendable() | kind_const() }
|
||||
ty_estr(vstore_box) {
|
||||
kind_implicitly_copyable() | kind_const() | kind_owned()
|
||||
}
|
||||
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.
|
||||
ty_rec(flds) {
|
||||
|
@ -1516,6 +1559,7 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
|
|||
}
|
||||
lowest
|
||||
}
|
||||
|
||||
ty_class(did, substs) {
|
||||
// Classes are sendable if all their fields are sendable,
|
||||
// likewise for copyable...
|
||||
|
@ -1532,18 +1576,20 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
|
|||
}
|
||||
lowest
|
||||
}
|
||||
|
||||
// Tuples lower to the lowest of their members.
|
||||
ty_tup(tys) {
|
||||
let mut lowest = kind_top();
|
||||
for tys.each |ty| { lowest = lower_kind(lowest, type_kind(cx, ty)); }
|
||||
lowest
|
||||
}
|
||||
|
||||
// Enums lower to the lowest of their variants.
|
||||
ty_enum(did, substs) {
|
||||
let mut lowest = kind_top();
|
||||
let variants = enum_variants(cx, did);
|
||||
if vec::len(*variants) == 0u {
|
||||
lowest = kind_send_only();
|
||||
lowest = kind_send_only() | kind_owned();
|
||||
} else {
|
||||
for vec::each(*variants) |variant| {
|
||||
for variant.args.each |aty| {
|
||||
|
@ -1556,11 +1602,15 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
|
|||
}
|
||||
lowest
|
||||
}
|
||||
|
||||
ty_param(_, did) {
|
||||
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_var(_) | ty_var_integral(_) {
|
||||
cx.sess.bug(~"Asked to compute kind of a type variable");
|
||||
}
|
||||
|
|
|
@ -169,7 +169,8 @@ class lookup {
|
|||
let bounds = tcx.ty_param_bounds.get(did.node);
|
||||
for vec::each(*bounds) |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 */
|
||||
}
|
||||
ty::bound_trait(bound_t) {
|
||||
|
|
|
@ -68,7 +68,8 @@ fn lookup_vtable(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
|
|||
let mut n_bound = 0u;
|
||||
for vec::each(*tcx.ty_param_bounds.get(did.node)) |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 */
|
||||
}
|
||||
ty::bound_trait(ity) {
|
||||
|
|
|
@ -572,6 +572,7 @@ fn ty_param_bounds(ccx: @crate_ctxt,
|
|||
ast::bound_send { ~[ty::bound_send] }
|
||||
ast::bound_copy { ~[ty::bound_copy] }
|
||||
ast::bound_const { ~[ty::bound_const] }
|
||||
ast::bound_owned { ~[ty::bound_owned] }
|
||||
ast::bound_trait(t) {
|
||||
let ity = ast_ty_to_ty(ccx, empty_rscope, t);
|
||||
alt ty::get(ity).struct {
|
||||
|
|
|
@ -57,7 +57,6 @@ fn re_scope_id_to_str(cx: ctxt, node_id: ast::node_id) -> ~str {
|
|||
}
|
||||
}
|
||||
none {
|
||||
// FIXME(#2586)
|
||||
#fmt["<unknown-%d>", node_id]
|
||||
}
|
||||
_ { cx.sess.bug(
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
// error-pattern: copying a noncopyable value
|
||||
|
||||
fn to_lambda1(f: fn@(uint) -> uint) -> fn@(uint) -> uint {
|
||||
ret f;
|
||||
}
|
||||
|
||||
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() {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// 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
|
||||
// in fn@ body, but value is illegal to copy:
|
||||
ret fn@(u: uint, copy b) -> uint { 22u };
|
||||
|
|
19
src/test/compile-fail/kindck-owned.rs
Normal file
19
src/test/compile-fail/kindck-owned.rs
Normal 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
|
||||
}
|
|
@ -2,7 +2,7 @@ type pair<A,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) }
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ type pair<A,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) }
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
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)};
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue