rustc: Implement ~Trait. r=nmatsakis
This commit is contained in:
parent
65d4dbeb12
commit
0c2e6fda73
9 changed files with 163 additions and 31 deletions
|
|
@ -286,6 +286,7 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
|
|||
maybe_copy(cx, source, Some(("casted values must be copyable",
|
||||
try_adding)));
|
||||
check_cast_for_escaping_regions(cx, source, e);
|
||||
check_kind_bounds_of_cast(cx, source, e);
|
||||
}
|
||||
expr_copy(expr) => check_copy_ex(cx, expr, false,
|
||||
Some(("explicit copy requires a copyable argument", ""))),
|
||||
|
|
@ -607,6 +608,26 @@ fn check_cast_for_escaping_regions(
|
|||
}
|
||||
}
|
||||
|
||||
/// Ensures that values placed into a ~Trait are copyable and sendable.
|
||||
fn check_kind_bounds_of_cast(cx: ctx, source: @expr, target: @expr) {
|
||||
let target_ty = ty::expr_ty(cx.tcx, target);
|
||||
match ty::get(target_ty).sty {
|
||||
ty::ty_trait(_, _, ty::vstore_uniq) => {
|
||||
let source_ty = ty::expr_ty(cx.tcx, source);
|
||||
let source_kind = ty::type_kind(cx.tcx, source_ty);
|
||||
if !ty::kind_can_be_copied(source_kind) {
|
||||
cx.tcx.sess.span_err(target.span,
|
||||
~"uniquely-owned trait objects must be copyable");
|
||||
}
|
||||
if !ty::kind_can_be_sent(source_kind) {
|
||||
cx.tcx.sess.span_err(target.span,
|
||||
~"uniquely-owned trait objects must be sendable");
|
||||
}
|
||||
}
|
||||
_ => {} // Nothing to do.
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
|||
|
|
@ -971,10 +971,15 @@ fn T_captured_tydescs(cx: @crate_ctxt, n: uint) -> TypeRef {
|
|||
|
||||
fn T_opaque_trait(cx: @crate_ctxt, vstore: ty::vstore) -> TypeRef {
|
||||
match vstore {
|
||||
ty::vstore_box =>
|
||||
T_struct(~[T_ptr(cx.tydesc_type), T_opaque_box_ptr(cx)]),
|
||||
_ =>
|
||||
T_struct(~[T_ptr(cx.tydesc_type), T_ptr(T_i8())])
|
||||
ty::vstore_box => {
|
||||
T_struct(~[T_ptr(cx.tydesc_type), T_opaque_box_ptr(cx)])
|
||||
}
|
||||
ty::vstore_uniq => {
|
||||
T_struct(~[T_ptr(cx.tydesc_type),
|
||||
T_unique_ptr(T_unique(cx, T_i8())),
|
||||
T_ptr(cx.tydesc_type)])
|
||||
}
|
||||
_ => T_struct(~[T_ptr(cx.tydesc_type), T_ptr(T_i8())])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -614,7 +614,16 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
|
|||
DontAutorefArg);
|
||||
}
|
||||
ast::expr_cast(val, _) => {
|
||||
return meth::trans_trait_cast(bcx, val, expr.id, dest);
|
||||
match ty::get(node_id_type(bcx, expr.id)).sty {
|
||||
ty::ty_trait(_, _, vstore) => {
|
||||
return meth::trans_trait_cast(bcx, val, expr.id, dest,
|
||||
vstore);
|
||||
}
|
||||
_ => {
|
||||
bcx.tcx().sess.span_bug(expr.span,
|
||||
~"expr_cast of non-trait");
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::expr_assign_op(op, dst, src) => {
|
||||
return trans_assign_op(bcx, expr, op, dst, src);
|
||||
|
|
|
|||
|
|
@ -482,7 +482,11 @@ fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
|
|||
decr_refcnt_maybe_free(bcx, llbox, ty::mk_opaque_box(ccx.tcx))
|
||||
}
|
||||
ty::ty_trait(_, _, ty::vstore_uniq) => {
|
||||
ccx.tcx.sess.unimpl(~"drop of unique trait");
|
||||
let lluniquevalue = GEPi(bcx, v0, [0, 1]);
|
||||
let lltydesc = Load(bcx, GEPi(bcx, v0, [0, 2]));
|
||||
call_tydesc_glue_full(bcx, lluniquevalue, lltydesc,
|
||||
abi::tydesc_field_free_glue, None);
|
||||
bcx
|
||||
}
|
||||
ty::ty_opaque_closure_ptr(ck) => {
|
||||
closure::make_opaque_cbox_drop_glue(bcx, ck, v0)
|
||||
|
|
@ -536,11 +540,18 @@ fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) {
|
|||
ty::ty_fn(_) => {
|
||||
closure::make_fn_glue(bcx, v, t, take_ty)
|
||||
}
|
||||
ty::ty_trait(_, _, _) => {
|
||||
ty::ty_trait(_, _, ty::vstore_box) => {
|
||||
let llbox = Load(bcx, GEPi(bcx, v, [0u, 1u]));
|
||||
incr_refcnt_of_boxed(bcx, llbox);
|
||||
bcx
|
||||
}
|
||||
ty::ty_trait(_, _, ty::vstore_uniq) => {
|
||||
let llval = GEPi(bcx, v, [0, 1]);
|
||||
let lltydesc = Load(bcx, GEPi(bcx, v, [0, 2]));
|
||||
call_tydesc_glue_full(bcx, llval, lltydesc,
|
||||
abi::tydesc_field_take_glue, None);
|
||||
bcx
|
||||
}
|
||||
ty::ty_opaque_closure_ptr(ck) => {
|
||||
closure::make_opaque_cbox_take_glue(bcx, ck, v)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -650,7 +650,8 @@ fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: ~[ty::t],
|
|||
fn trans_trait_cast(bcx: block,
|
||||
val: @ast::expr,
|
||||
id: ast::node_id,
|
||||
dest: expr::Dest)
|
||||
dest: expr::Dest,
|
||||
vstore: ty::vstore)
|
||||
-> block
|
||||
{
|
||||
let mut bcx = bcx;
|
||||
|
|
@ -666,25 +667,54 @@ fn trans_trait_cast(bcx: block,
|
|||
let ccx = bcx.ccx();
|
||||
let v_ty = expr_ty(bcx, val);
|
||||
|
||||
let mut llboxdest = GEPi(bcx, lldest, [0u, 1u]);
|
||||
if bcx.tcx().legacy_boxed_traits.contains_key(id) {
|
||||
// Allocate an @ box and store the value into it
|
||||
let {bcx: new_bcx, box: llbox, body: body} = malloc_boxed(bcx, v_ty);
|
||||
bcx = new_bcx;
|
||||
add_clean_free(bcx, llbox, heap_shared);
|
||||
bcx = expr::trans_into(bcx, val, SaveIn(body));
|
||||
revoke_clean(bcx, llbox);
|
||||
match vstore {
|
||||
ty::vstore_slice(*) | ty::vstore_box => {
|
||||
let mut llboxdest = GEPi(bcx, lldest, [0u, 1u]);
|
||||
if bcx.tcx().legacy_boxed_traits.contains_key(id) {
|
||||
// Allocate an @ box and store the value into it
|
||||
let {bcx: new_bcx, box: llbox, body: body} =
|
||||
malloc_boxed(bcx, v_ty);
|
||||
bcx = new_bcx;
|
||||
add_clean_free(bcx, llbox, heap_shared);
|
||||
bcx = expr::trans_into(bcx, val, SaveIn(body));
|
||||
revoke_clean(bcx, llbox);
|
||||
|
||||
// Store the @ box into the pair
|
||||
Store(bcx, llbox, PointerCast(bcx, llboxdest, T_ptr(val_ty(llbox))));
|
||||
} else {
|
||||
// Just store the @ box into the pair.
|
||||
llboxdest = PointerCast(bcx, llboxdest,
|
||||
T_ptr(type_of::type_of(bcx.ccx(), v_ty)));
|
||||
bcx = expr::trans_into(bcx, val, SaveIn(llboxdest));
|
||||
// Store the @ box into the pair
|
||||
Store(bcx, llbox, PointerCast(bcx,
|
||||
llboxdest,
|
||||
T_ptr(val_ty(llbox))));
|
||||
} else {
|
||||
// Just store the pointer into the pair.
|
||||
llboxdest = PointerCast(bcx,
|
||||
llboxdest,
|
||||
T_ptr(type_of::type_of(bcx.ccx(),
|
||||
v_ty)));
|
||||
bcx = expr::trans_into(bcx, val, SaveIn(llboxdest));
|
||||
}
|
||||
}
|
||||
ty::vstore_uniq => {
|
||||
// Translate the uniquely-owned value into the second element of
|
||||
// the triple. (The first element is the vtable.)
|
||||
let mut llvaldest = GEPi(bcx, lldest, [0, 1]);
|
||||
llvaldest = PointerCast(bcx,
|
||||
llvaldest,
|
||||
T_ptr(type_of::type_of(bcx.ccx(), v_ty)));
|
||||
bcx = expr::trans_into(bcx, val, SaveIn(llvaldest));
|
||||
|
||||
// Get the type descriptor of the wrapped value and store it into
|
||||
// the third element of the triple as well.
|
||||
let tydesc = get_tydesc(bcx.ccx(), v_ty);
|
||||
glue::lazily_emit_all_tydesc_glue(bcx.ccx(), tydesc);
|
||||
let lltydescdest = GEPi(bcx, lldest, [0, 2]);
|
||||
Store(bcx, tydesc.tydesc, lltydescdest);
|
||||
}
|
||||
_ => {
|
||||
bcx.tcx().sess.span_bug(val.span, ~"unexpected vstore in \
|
||||
trans_trait_cast");
|
||||
}
|
||||
}
|
||||
|
||||
// Store the vtable into the pair
|
||||
// Store the vtable into the pair or triple.
|
||||
let orig = ccx.maps.vtable_map.get(id)[0];
|
||||
let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, orig);
|
||||
let vtable = get_vtable(bcx.ccx(), orig);
|
||||
|
|
|
|||
|
|
@ -190,13 +190,14 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope Copy Owned>(
|
|||
match ty::get(result.ty).sty {
|
||||
ty::ty_trait(trait_def_id, substs, _) => {
|
||||
match vst {
|
||||
ty::vstore_box | ty::vstore_slice(*) => {}
|
||||
ty::vstore_box | ty::vstore_slice(*) |
|
||||
ty::vstore_uniq => {}
|
||||
_ => {
|
||||
tcx.sess.span_unimpl(path.span,
|
||||
~"`~trait` is \
|
||||
unimplemented; use \
|
||||
`@trait` instead for \
|
||||
now");
|
||||
tcx.sess.span_err(path.span,
|
||||
~"@trait, ~trait or &trait \
|
||||
are the only supported \
|
||||
forms of casting-to-\
|
||||
trait");
|
||||
}
|
||||
}
|
||||
return ty::mk_trait(tcx, trait_def_id, substs, vst);
|
||||
|
|
|
|||
|
|
@ -540,14 +540,18 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
|
|||
None => {
|
||||
// Try the new-style boxed trait; "@int as @Trait".
|
||||
// Or the new-style region trait; "&int as &Trait".
|
||||
// Or the new-style uniquely-owned trait; "~int as
|
||||
// ~Trait".
|
||||
let mut err = false;
|
||||
let ty = structurally_resolved_type(fcx, ex.span, ty);
|
||||
match ty::get(ty).sty {
|
||||
ty::ty_box(mt) | ty::ty_rptr(_, mt) => {
|
||||
ty::ty_box(mt) | ty::ty_rptr(_, mt) |
|
||||
ty::ty_uniq(mt) => {
|
||||
// Ensure that the trait vstore and the pointer
|
||||
// type match.
|
||||
match (ty::get(ty).sty, vstore) {
|
||||
(ty::ty_box(_), ty::vstore_box) |
|
||||
(ty::ty_uniq(_), ty::vstore_uniq) |
|
||||
(ty::ty_rptr(*), ty::vstore_slice(*)) => {
|
||||
let vtable_opt =
|
||||
lookup_vtable_invariant(fcx,
|
||||
|
|
@ -600,6 +604,14 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
|
|||
a borrowed \
|
||||
trait");
|
||||
}
|
||||
(ty::ty_uniq(*), _) => {
|
||||
fcx.ccx.tcx.sess.span_err(ex.span,
|
||||
~"must cast \
|
||||
a unique \
|
||||
pointer to \
|
||||
a uniquely-\
|
||||
owned trait");
|
||||
}
|
||||
_ => {
|
||||
fcx.ccx.tcx.sess.impossible_case(
|
||||
ex.span,
|
||||
|
|
|
|||
21
src/test/compile-fail/unique-object-noncopyable.rs
Normal file
21
src/test/compile-fail/unique-object-noncopyable.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
trait Foo {
|
||||
fn f();
|
||||
}
|
||||
|
||||
struct Bar {
|
||||
x: int,
|
||||
drop {}
|
||||
}
|
||||
|
||||
impl Bar : Foo {
|
||||
fn f() {
|
||||
io::println("hi");
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = ~Bar { x: 10 };
|
||||
let y = (move x) as ~Foo; //~ ERROR uniquely-owned trait objects must be copyable
|
||||
let _z = copy y;
|
||||
}
|
||||
|
||||
22
src/test/run-pass/unique-object.rs
Normal file
22
src/test/run-pass/unique-object.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
trait Foo {
|
||||
fn f();
|
||||
}
|
||||
|
||||
struct Bar {
|
||||
x: int
|
||||
}
|
||||
|
||||
impl Bar : Foo {
|
||||
fn f() {
|
||||
io::println("hi");
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = ~Bar { x: 10 };
|
||||
let y = x as ~Foo;
|
||||
let z = copy y;
|
||||
y.f();
|
||||
z.f();
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue