rustc: Implement ~Trait. r=nmatsakis

This commit is contained in:
Patrick Walton 2012-10-31 15:09:26 -07:00
parent 65d4dbeb12
commit 0c2e6fda73
9 changed files with 163 additions and 31 deletions

View file

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

View file

@ -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())])
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View 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;
}

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