Skip to content

Commit 0c2e6fd

Browse files
committed
rustc: Implement ~Trait. r=nmatsakis
1 parent 65d4dbe commit 0c2e6fd

File tree

9 files changed

+164
-32
lines changed

9 files changed

+164
-32
lines changed

src/rustc/middle/kind.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
286286
maybe_copy(cx, source, Some(("casted values must be copyable",
287287
try_adding)));
288288
check_cast_for_escaping_regions(cx, source, e);
289+
check_kind_bounds_of_cast(cx, source, e);
289290
}
290291
expr_copy(expr) => check_copy_ex(cx, expr, false,
291292
Some(("explicit copy requires a copyable argument", ""))),
@@ -607,6 +608,26 @@ fn check_cast_for_escaping_regions(
607608
}
608609
}
609610

611+
/// Ensures that values placed into a ~Trait are copyable and sendable.
612+
fn check_kind_bounds_of_cast(cx: ctx, source: @expr, target: @expr) {
613+
let target_ty = ty::expr_ty(cx.tcx, target);
614+
match ty::get(target_ty).sty {
615+
ty::ty_trait(_, _, ty::vstore_uniq) => {
616+
let source_ty = ty::expr_ty(cx.tcx, source);
617+
let source_kind = ty::type_kind(cx.tcx, source_ty);
618+
if !ty::kind_can_be_copied(source_kind) {
619+
cx.tcx.sess.span_err(target.span,
620+
~"uniquely-owned trait objects must be copyable");
621+
}
622+
if !ty::kind_can_be_sent(source_kind) {
623+
cx.tcx.sess.span_err(target.span,
624+
~"uniquely-owned trait objects must be sendable");
625+
}
626+
}
627+
_ => {} // Nothing to do.
628+
}
629+
}
630+
610631
//
611632
// Local Variables:
612633
// mode: rust

src/rustc/middle/trans/common.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -971,10 +971,15 @@ fn T_captured_tydescs(cx: @crate_ctxt, n: uint) -> TypeRef {
971971

972972
fn T_opaque_trait(cx: @crate_ctxt, vstore: ty::vstore) -> TypeRef {
973973
match vstore {
974-
ty::vstore_box =>
975-
T_struct(~[T_ptr(cx.tydesc_type), T_opaque_box_ptr(cx)]),
976-
_ =>
977-
T_struct(~[T_ptr(cx.tydesc_type), T_ptr(T_i8())])
974+
ty::vstore_box => {
975+
T_struct(~[T_ptr(cx.tydesc_type), T_opaque_box_ptr(cx)])
976+
}
977+
ty::vstore_uniq => {
978+
T_struct(~[T_ptr(cx.tydesc_type),
979+
T_unique_ptr(T_unique(cx, T_i8())),
980+
T_ptr(cx.tydesc_type)])
981+
}
982+
_ => T_struct(~[T_ptr(cx.tydesc_type), T_ptr(T_i8())])
978983
}
979984
}
980985

src/rustc/middle/trans/expr.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,16 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
614614
DontAutorefArg);
615615
}
616616
ast::expr_cast(val, _) => {
617-
return meth::trans_trait_cast(bcx, val, expr.id, dest);
617+
match ty::get(node_id_type(bcx, expr.id)).sty {
618+
ty::ty_trait(_, _, vstore) => {
619+
return meth::trans_trait_cast(bcx, val, expr.id, dest,
620+
vstore);
621+
}
622+
_ => {
623+
bcx.tcx().sess.span_bug(expr.span,
624+
~"expr_cast of non-trait");
625+
}
626+
}
618627
}
619628
ast::expr_assign_op(op, dst, src) => {
620629
return trans_assign_op(bcx, expr, op, dst, src);

src/rustc/middle/trans/glue.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,11 @@ fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
482482
decr_refcnt_maybe_free(bcx, llbox, ty::mk_opaque_box(ccx.tcx))
483483
}
484484
ty::ty_trait(_, _, ty::vstore_uniq) => {
485-
ccx.tcx.sess.unimpl(~"drop of unique trait");
485+
let lluniquevalue = GEPi(bcx, v0, [0, 1]);
486+
let lltydesc = Load(bcx, GEPi(bcx, v0, [0, 2]));
487+
call_tydesc_glue_full(bcx, lluniquevalue, lltydesc,
488+
abi::tydesc_field_free_glue, None);
489+
bcx
486490
}
487491
ty::ty_opaque_closure_ptr(ck) => {
488492
closure::make_opaque_cbox_drop_glue(bcx, ck, v0)
@@ -536,11 +540,18 @@ fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) {
536540
ty::ty_fn(_) => {
537541
closure::make_fn_glue(bcx, v, t, take_ty)
538542
}
539-
ty::ty_trait(_, _, _) => {
543+
ty::ty_trait(_, _, ty::vstore_box) => {
540544
let llbox = Load(bcx, GEPi(bcx, v, [0u, 1u]));
541545
incr_refcnt_of_boxed(bcx, llbox);
542546
bcx
543547
}
548+
ty::ty_trait(_, _, ty::vstore_uniq) => {
549+
let llval = GEPi(bcx, v, [0, 1]);
550+
let lltydesc = Load(bcx, GEPi(bcx, v, [0, 2]));
551+
call_tydesc_glue_full(bcx, llval, lltydesc,
552+
abi::tydesc_field_take_glue, None);
553+
bcx
554+
}
544555
ty::ty_opaque_closure_ptr(ck) => {
545556
closure::make_opaque_cbox_take_glue(bcx, ck, v)
546557
}

src/rustc/middle/trans/meth.rs

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,8 @@ fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: ~[ty::t],
650650
fn trans_trait_cast(bcx: block,
651651
val: @ast::expr,
652652
id: ast::node_id,
653-
dest: expr::Dest)
653+
dest: expr::Dest,
654+
vstore: ty::vstore)
654655
-> block
655656
{
656657
let mut bcx = bcx;
@@ -666,25 +667,54 @@ fn trans_trait_cast(bcx: block,
666667
let ccx = bcx.ccx();
667668
let v_ty = expr_ty(bcx, val);
668669

669-
let mut llboxdest = GEPi(bcx, lldest, [0u, 1u]);
670-
if bcx.tcx().legacy_boxed_traits.contains_key(id) {
671-
// Allocate an @ box and store the value into it
672-
let {bcx: new_bcx, box: llbox, body: body} = malloc_boxed(bcx, v_ty);
673-
bcx = new_bcx;
674-
add_clean_free(bcx, llbox, heap_shared);
675-
bcx = expr::trans_into(bcx, val, SaveIn(body));
676-
revoke_clean(bcx, llbox);
677-
678-
// Store the @ box into the pair
679-
Store(bcx, llbox, PointerCast(bcx, llboxdest, T_ptr(val_ty(llbox))));
680-
} else {
681-
// Just store the @ box into the pair.
682-
llboxdest = PointerCast(bcx, llboxdest,
683-
T_ptr(type_of::type_of(bcx.ccx(), v_ty)));
684-
bcx = expr::trans_into(bcx, val, SaveIn(llboxdest));
670+
match vstore {
671+
ty::vstore_slice(*) | ty::vstore_box => {
672+
let mut llboxdest = GEPi(bcx, lldest, [0u, 1u]);
673+
if bcx.tcx().legacy_boxed_traits.contains_key(id) {
674+
// Allocate an @ box and store the value into it
675+
let {bcx: new_bcx, box: llbox, body: body} =
676+
malloc_boxed(bcx, v_ty);
677+
bcx = new_bcx;
678+
add_clean_free(bcx, llbox, heap_shared);
679+
bcx = expr::trans_into(bcx, val, SaveIn(body));
680+
revoke_clean(bcx, llbox);
681+
682+
// Store the @ box into the pair
683+
Store(bcx, llbox, PointerCast(bcx,
684+
llboxdest,
685+
T_ptr(val_ty(llbox))));
686+
} else {
687+
// Just store the pointer into the pair.
688+
llboxdest = PointerCast(bcx,
689+
llboxdest,
690+
T_ptr(type_of::type_of(bcx.ccx(),
691+
v_ty)));
692+
bcx = expr::trans_into(bcx, val, SaveIn(llboxdest));
693+
}
694+
}
695+
ty::vstore_uniq => {
696+
// Translate the uniquely-owned value into the second element of
697+
// the triple. (The first element is the vtable.)
698+
let mut llvaldest = GEPi(bcx, lldest, [0, 1]);
699+
llvaldest = PointerCast(bcx,
700+
llvaldest,
701+
T_ptr(type_of::type_of(bcx.ccx(), v_ty)));
702+
bcx = expr::trans_into(bcx, val, SaveIn(llvaldest));
703+
704+
// Get the type descriptor of the wrapped value and store it into
705+
// the third element of the triple as well.
706+
let tydesc = get_tydesc(bcx.ccx(), v_ty);
707+
glue::lazily_emit_all_tydesc_glue(bcx.ccx(), tydesc);
708+
let lltydescdest = GEPi(bcx, lldest, [0, 2]);
709+
Store(bcx, tydesc.tydesc, lltydescdest);
710+
}
711+
_ => {
712+
bcx.tcx().sess.span_bug(val.span, ~"unexpected vstore in \
713+
trans_trait_cast");
714+
}
685715
}
686716

687-
// Store the vtable into the pair
717+
// Store the vtable into the pair or triple.
688718
let orig = ccx.maps.vtable_map.get(id)[0];
689719
let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, orig);
690720
let vtable = get_vtable(bcx.ccx(), orig);

src/rustc/middle/typeck/astconv.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -190,13 +190,14 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope Copy Owned>(
190190
match ty::get(result.ty).sty {
191191
ty::ty_trait(trait_def_id, substs, _) => {
192192
match vst {
193-
ty::vstore_box | ty::vstore_slice(*) => {}
193+
ty::vstore_box | ty::vstore_slice(*) |
194+
ty::vstore_uniq => {}
194195
_ => {
195-
tcx.sess.span_unimpl(path.span,
196-
~"`~trait` is \
197-
unimplemented; use \
198-
`@trait` instead for \
199-
now");
196+
tcx.sess.span_err(path.span,
197+
~"@trait, ~trait or &trait \
198+
are the only supported \
199+
forms of casting-to-\
200+
trait");
200201
}
201202
}
202203
return ty::mk_trait(tcx, trait_def_id, substs, vst);

src/rustc/middle/typeck/check/vtable.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,14 +540,18 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
540540
None => {
541541
// Try the new-style boxed trait; "@int as @Trait".
542542
// Or the new-style region trait; "&int as &Trait".
543+
// Or the new-style uniquely-owned trait; "~int as
544+
// ~Trait".
543545
let mut err = false;
544546
let ty = structurally_resolved_type(fcx, ex.span, ty);
545547
match ty::get(ty).sty {
546-
ty::ty_box(mt) | ty::ty_rptr(_, mt) => {
548+
ty::ty_box(mt) | ty::ty_rptr(_, mt) |
549+
ty::ty_uniq(mt) => {
547550
// Ensure that the trait vstore and the pointer
548551
// type match.
549552
match (ty::get(ty).sty, vstore) {
550553
(ty::ty_box(_), ty::vstore_box) |
554+
(ty::ty_uniq(_), ty::vstore_uniq) |
551555
(ty::ty_rptr(*), ty::vstore_slice(*)) => {
552556
let vtable_opt =
553557
lookup_vtable_invariant(fcx,
@@ -600,6 +604,14 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
600604
a borrowed \
601605
trait");
602606
}
607+
(ty::ty_uniq(*), _) => {
608+
fcx.ccx.tcx.sess.span_err(ex.span,
609+
~"must cast \
610+
a unique \
611+
pointer to \
612+
a uniquely-\
613+
owned trait");
614+
}
603615
_ => {
604616
fcx.ccx.tcx.sess.impossible_case(
605617
ex.span,
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
trait Foo {
2+
fn f();
3+
}
4+
5+
struct Bar {
6+
x: int,
7+
drop {}
8+
}
9+
10+
impl Bar : Foo {
11+
fn f() {
12+
io::println("hi");
13+
}
14+
}
15+
16+
fn main() {
17+
let x = ~Bar { x: 10 };
18+
let y = (move x) as ~Foo; //~ ERROR uniquely-owned trait objects must be copyable
19+
let _z = copy y;
20+
}
21+

src/test/run-pass/unique-object.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
trait Foo {
2+
fn f();
3+
}
4+
5+
struct Bar {
6+
x: int
7+
}
8+
9+
impl Bar : Foo {
10+
fn f() {
11+
io::println("hi");
12+
}
13+
}
14+
15+
fn main() {
16+
let x = ~Bar { x: 10 };
17+
let y = x as ~Foo;
18+
let z = copy y;
19+
y.f();
20+
z.f();
21+
}
22+

0 commit comments

Comments
 (0)