rustc: Implement "@Foo as @Bar" for boxed traits

This commit is contained in:
Patrick Walton
2012-10-03 15:18:50 -07:00
parent d936773e56
commit b34327be0d
3 changed files with 89 additions and 31 deletions

View File

@@ -929,6 +929,8 @@ fn decode_side_tables(xcx: extended_decode_ctxt,
if tag == (c::tag_table_mutbl as uint) { if tag == (c::tag_table_mutbl as uint) {
dcx.maps.mutbl_map.insert(id, ()); dcx.maps.mutbl_map.insert(id, ());
} else if tag == (c::tag_table_legacy_boxed_trait as uint) {
dcx.tcx.legacy_boxed_traits.insert(id, ());
} else { } else {
let val_doc = entry_doc[c::tag_table_val as uint]; let val_doc = entry_doc[c::tag_table_val as uint];
let val_dsr = ebml::ebml_deserializer(val_doc); let val_dsr = ebml::ebml_deserializer(val_doc);
@@ -969,8 +971,6 @@ fn decode_side_tables(xcx: extended_decode_ctxt,
} else if tag == (c::tag_table_adjustments as uint) { } else if tag == (c::tag_table_adjustments as uint) {
let adj = @ty::deserialize_AutoAdjustment(val_dsr).tr(xcx); let adj = @ty::deserialize_AutoAdjustment(val_dsr).tr(xcx);
dcx.tcx.adjustments.insert(id, adj); dcx.tcx.adjustments.insert(id, adj);
} else if tag == (c::tag_table_legacy_boxed_trait as uint) {
dcx.tcx.legacy_boxed_traits.insert(id, ());
} else { } else {
xcx.dcx.tcx.sess.bug( xcx.dcx.tcx.sess.bug(
fmt!("unknown tag found in side tables: %x", tag)); fmt!("unknown tag found in side tables: %x", tag));

View File

@@ -536,6 +536,7 @@ fn trans_trait_cast(bcx: block,
dest: expr::Dest) dest: expr::Dest)
-> block -> block
{ {
let mut bcx = bcx;
let _icx = bcx.insn_ctxt("impl::trans_cast"); let _icx = bcx.insn_ctxt("impl::trans_cast");
let lldest = match dest { let lldest = match dest {
@@ -548,16 +549,24 @@ fn trans_trait_cast(bcx: block,
let ccx = bcx.ccx(); let ccx = bcx.ccx();
let v_ty = expr_ty(bcx, val); let v_ty = expr_ty(bcx, val);
let mut llboxdest = GEPi(bcx, lldest, [0u, 1u]);
llboxdest = PointerCast(bcx, llboxdest,
T_ptr(type_of::type_of(bcx.ccx(), v_ty)));
if bcx.tcx().legacy_boxed_traits.contains_key(id) {
// Allocate an @ box and store the value into it // Allocate an @ box and store the value into it
let {bcx: bcx, box: llbox, body: body} = malloc_boxed(bcx, v_ty); let {bcx: new_bcx, box: llbox, body: body} = malloc_boxed(bcx, v_ty);
bcx = new_bcx;
add_clean_free(bcx, llbox, heap_shared); add_clean_free(bcx, llbox, heap_shared);
let bcx = expr::trans_into(bcx, val, SaveIn(body)); bcx = expr::trans_into(bcx, val, SaveIn(body));
revoke_clean(bcx, llbox); revoke_clean(bcx, llbox);
// Store the @ box into the pair // Store the @ box into the pair
Store(bcx, llbox, PointerCast(bcx, Store(bcx, llbox, llboxdest);
GEPi(bcx, lldest, [0u, 1u]), } else {
T_ptr(val_ty(llbox)))); // Just store the @ box into the pair.
bcx = expr::trans_into(bcx, val, SaveIn(llboxdest));
}
// Store the vtable into the pair // Store the vtable into the pair
let orig = ccx.maps.vtable_map.get(id)[0]; let orig = ccx.maps.vtable_map.get(id)[0];

View File

@@ -51,8 +51,18 @@ fn lookup_vtables(fcx: @fn_ctxt,
match *bound { match *bound {
ty::bound_trait(i_ty) => { ty::bound_trait(i_ty) => {
let i_ty = ty::subst(tcx, substs, i_ty); let i_ty = ty::subst(tcx, substs, i_ty);
result.push(lookup_vtable(fcx, expr, *ty, i_ty, match lookup_vtable(fcx, expr, *ty, i_ty, allow_unsafe,
allow_unsafe, is_early)); is_early) {
Some(vtable) => result.push(vtable),
None => {
fcx.tcx().sess.span_fatal(
expr.span,
fmt!("failed to find an implementation of trait \
%s for %s",
ty_to_str(fcx.tcx(), i_ty),
ty_to_str(fcx.tcx(), *ty)));
}
}
} }
_ => () _ => ()
} }
@@ -91,7 +101,7 @@ fn lookup_vtable(fcx: @fn_ctxt,
trait_ty: ty::t, trait_ty: ty::t,
allow_unsafe: bool, allow_unsafe: bool,
is_early: bool) is_early: bool)
-> vtable_origin -> Option<vtable_origin>
{ {
debug!("lookup_vtable(ty=%s, trait_ty=%s)", debug!("lookup_vtable(ty=%s, trait_ty=%s)",
@@ -113,7 +123,7 @@ fn lookup_vtable(fcx: @fn_ctxt,
// The type has unconstrained type variables in it, so we can't // The type has unconstrained type variables in it, so we can't
// do early resolution on it. Return some completely bogus vtable // do early resolution on it. Return some completely bogus vtable
// information: we aren't storing it anyways. // information: we aren't storing it anyways.
return vtable_param(0, 0); return Some(vtable_param(0, 0));
} }
}; };
@@ -135,7 +145,7 @@ fn lookup_vtable(fcx: @fn_ctxt,
idid); idid);
relate_trait_tys(fcx, expr, relate_trait_tys(fcx, expr,
trait_ty, ity); trait_ty, ity);
return vtable_param(n, n_bound); return Some(vtable_param(n, n_bound));
} }
} }
_ => tcx.sess.impossible_case( _ => tcx.sess.impossible_case(
@@ -170,7 +180,7 @@ fn lookup_vtable(fcx: @fn_ctxt,
} }
} }
} }
return vtable_trait(did, substs.tps); return Some(vtable_trait(did, substs.tps));
} }
_ => { _ => {
@@ -303,7 +313,7 @@ fn lookup_vtable(fcx: @fn_ctxt,
None => { None => {
assert is_early; assert is_early;
// Bail out with a bogus answer // Bail out with a bogus answer
return vtable_param(0, 0); return Some(vtable_param(0, 0));
} }
}; };
@@ -341,23 +351,20 @@ fn lookup_vtable(fcx: @fn_ctxt,
match found.len() { match found.len() {
0 => { /* fallthrough */ } 0 => { /* fallthrough */ }
1 => { return found[0]; } 1 => { return Some(found[0]); }
_ => { _ => {
if !is_early { if !is_early {
fcx.ccx.tcx.sess.span_err( fcx.ccx.tcx.sess.span_err(
expr.span, expr.span,
~"multiple applicable methods in scope"); ~"multiple applicable methods in scope");
} }
return found[0]; return Some(found[0]);
} }
} }
} }
} }
tcx.sess.span_fatal( return None;
expr.span,
fmt!("failed to find an implementation of trait %s for %s",
ty_to_str(tcx, trait_ty), ty_to_str(tcx, ty)));
} }
fn fixup_ty(fcx: @fn_ctxt, fn fixup_ty(fcx: @fn_ctxt,
@@ -459,13 +466,55 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
Look up vtables for the type we're casting to, Look up vtables for the type we're casting to,
passing in the source and target type passing in the source and target type
*/ */
let vtable = lookup_vtable(fcx, ex, fcx.expr_ty(src), let ty = fcx.expr_ty(src);
target_ty, true, is_early); let vtable_opt = lookup_vtable(fcx, ex, ty, target_ty, true,
is_early);
match vtable_opt {
None => {
// Try the new-style boxed 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(boxed_ty) => {
let vtable_opt = lookup_vtable(fcx, ex,
boxed_ty.ty,
target_ty, true,
is_early);
match vtable_opt {
Some(vtable) => {
/*
Map this expression to that vtable (that
is: "ex has vtable <vtable>")
*/
if !is_early {
cx.vtable_map.insert(ex.id,
@~[vtable]);
}
}
None => err = true
}
}
_ => err = true
}
if err {
fcx.tcx().sess.span_fatal(
ex.span,
fmt!("failed to find an implementation of trait \
%s for %s",
ty_to_str(fcx.tcx(), target_ty),
ty_to_str(fcx.tcx(), ty)));
}
}
Some(vtable) => {
/* /*
Map this expression to that vtable (that is: "ex has Map this expression to that vtable (that is: "ex has
vtable <vtable>") vtable <vtable>")
*/ */
if !is_early { cx.vtable_map.insert(ex.id, @~[vtable]); } if !is_early { cx.vtable_map.insert(ex.id, @~[vtable]); }
fcx.tcx().legacy_boxed_traits.insert(ex.id, ());
}
}
} }
_ => () _ => ()
} }