Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
librustc: Implement coercion for traits.
  • Loading branch information
luqmana committed Dec 27, 2013
1 parent 00d87e0 commit 1265a03
Show file tree
Hide file tree
Showing 16 changed files with 454 additions and 142 deletions.
2 changes: 1 addition & 1 deletion src/libextra/enum_set.rs
Expand Up @@ -13,7 +13,7 @@
//! This module defines a container which uses an efficient bit mask
//! representation to hold C-like enum variants.

#[deriving(Clone, Eq, IterBytes, ToStr)]
#[deriving(Clone, Eq, IterBytes, ToStr, Encodable, Decodable)]
/// A specialized Set implementation to use enum types.
pub struct EnumSet<E> {
// We must maintain the invariant that no bits are set
Expand Down
6 changes: 6 additions & 0 deletions src/librustc/metadata/tydecode.rs
Expand Up @@ -129,6 +129,12 @@ pub fn parse_trait_ref_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tc
parse_trait_ref(&mut st, conv)
}

pub fn parse_substs_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: ty::ctxt,
conv: conv_did) -> ty::substs {
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_substs(&mut st, conv)
}

fn parse_sigil(st: &mut PState) -> ast::Sigil {
match next(st) {
'@' => ast::ManagedSigil,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/metadata/tyencode.rs
Expand Up @@ -140,7 +140,7 @@ fn enc_opt<T>(w: &mut MemWriter, t: Option<T>, enc_f: |&mut MemWriter, T|) {
}
}

fn enc_substs(w: &mut MemWriter, cx: @ctxt, substs: &ty::substs) {
pub fn enc_substs(w: &mut MemWriter, cx: @ctxt, substs: &ty::substs) {
enc_region_substs(w, cx, &substs.regions);
enc_opt(w, substs.self_ty, |w, t| enc_ty(w, cx, t));
mywrite!(w, "[");
Expand Down
114 changes: 102 additions & 12 deletions src/librustc/middle/astencode.rs
Expand Up @@ -450,15 +450,13 @@ impl tr for ast::Def {
// ______________________________________________________________________
// Encoding and decoding of adjustment information

impl tr for ty::AutoAdjustment {
fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::AutoAdjustment {
match *self {
ty::AutoAddEnv(r, s) => ty::AutoAddEnv(r.tr(xcx), s),
ty::AutoDerefRef(ref adr) => {
ty::AutoDerefRef(ty::AutoDerefRef {
autoderefs: adr.autoderefs,
autoref: adr.autoref.map(|ar| ar.tr(xcx)),
})
impl tr for ty::AutoDerefRef {
fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::AutoDerefRef {
ty::AutoDerefRef {
autoderefs: self.autoderefs,
autoref: match self.autoref {
Some(ref autoref) => Some(autoref.tr(xcx)),
None => None
}
}
}
Expand Down Expand Up @@ -786,6 +784,8 @@ trait ebml_writer_helpers {
fn emit_tpbt(&mut self,
ecx: &e::EncodeContext,
tpbt: ty::ty_param_bounds_and_ty);
fn emit_substs(&mut self, ecx: &e::EncodeContext, substs: &ty::substs);
fn emit_auto_adjustment(&mut self, ecx: &e::EncodeContext, adj: &ty::AutoAdjustment);
}

impl<'a> ebml_writer_helpers for writer::Encoder<'a> {
Expand Down Expand Up @@ -833,6 +833,40 @@ impl<'a> ebml_writer_helpers for writer::Encoder<'a> {
})
})
}

fn emit_substs(&mut self, ecx: &e::EncodeContext, substs: &ty::substs) {
self.emit_opaque(|this| tyencode::enc_substs(this.writer, ecx.ty_str_ctxt(), substs))
}

fn emit_auto_adjustment(&mut self, ecx: &e::EncodeContext, adj: &ty::AutoAdjustment) {
self.emit_enum("AutoAdjustment", |this| {
match *adj {
ty::AutoAddEnv(region, sigil) => {
this.emit_enum_variant("AutoAddEnv", 0, 2, |this| {
this.emit_enum_variant_arg(0, |this| region.encode(this));
this.emit_enum_variant_arg(1, |this| sigil.encode(this));
});
}

ty::AutoDerefRef(ref auto_deref_ref) => {
this.emit_enum_variant("AutoDerefRef", 1, 1, |this| {
this.emit_enum_variant_arg(0, |this| auto_deref_ref.encode(this));
});
}

ty::AutoObject(sigil, region, m, b, def_id, ref substs) => {
this.emit_enum_variant("AutoObject", 2, 6, |this| {
this.emit_enum_variant_arg(0, |this| sigil.encode(this));
this.emit_enum_variant_arg(1, |this| region.encode(this));
this.emit_enum_variant_arg(2, |this| m.encode(this));
this.emit_enum_variant_arg(3, |this| b.encode(this));
this.emit_enum_variant_arg(4, |this| def_id.encode(this));
this.emit_enum_variant_arg(5, |this| this.emit_substs(ecx, substs));
});
}
}
});
}
}

trait write_tag_and_id {
Expand Down Expand Up @@ -1023,7 +1057,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
ebml_w.tag(c::tag_table_adjustments, |ebml_w| {
ebml_w.id(id);
ebml_w.tag(c::tag_table_val, |ebml_w| {
(**adj).encode(ebml_w)
ebml_w.emit_auto_adjustment(ecx, **adj);
})
})
}
Expand Down Expand Up @@ -1064,6 +1098,8 @@ trait ebml_decoder_decoder_helpers {
-> ty::TypeParameterDef;
fn read_ty_param_bounds_and_ty(&mut self, xcx: @ExtendedDecodeContext)
-> ty::ty_param_bounds_and_ty;
fn read_substs(&mut self, xcx: @ExtendedDecodeContext) -> ty::substs;
fn read_auto_adjustment(&mut self, xcx: @ExtendedDecodeContext) -> ty::AutoAdjustment;
fn convert_def_id(&mut self,
xcx: @ExtendedDecodeContext,
source: DefIdSource,
Expand Down Expand Up @@ -1172,6 +1208,61 @@ impl<'a> ebml_decoder_decoder_helpers for reader::Decoder<'a> {
})
}

fn read_substs(&mut self, xcx: @ExtendedDecodeContext) -> ty::substs {
self.read_opaque(|this, doc| {
tydecode::parse_substs_data(doc.data,
xcx.dcx.cdata.cnum,
doc.start,
xcx.dcx.tcx,
|s, a| this.convert_def_id(xcx, s, a))
})
}

fn read_auto_adjustment(&mut self, xcx: @ExtendedDecodeContext) -> ty::AutoAdjustment {
self.read_enum("AutoAdjustment", |this| {
let variants = ["AutoAddEnv", "AutoDerefRef", "AutoObject"];
this.read_enum_variant(variants, |this, i| {
match i {
0 => {
let region: ty::Region =
this.read_enum_variant_arg(0, |this| Decodable::decode(this));
let sigil: ast::Sigil =
this.read_enum_variant_arg(1, |this| Decodable::decode(this));

ty:: AutoAddEnv(region.tr(xcx), sigil)
}
1 => {
let auto_deref_ref: ty::AutoDerefRef =
this.read_enum_variant_arg(0, |this| Decodable::decode(this));

ty::AutoDerefRef(auto_deref_ref.tr(xcx))
}
2 => {
let sigil: ast::Sigil =
this.read_enum_variant_arg(0, |this| Decodable::decode(this));
let region: Option<ty::Region> =
this.read_enum_variant_arg(1, |this| Decodable::decode(this));
let m: ast::Mutability =
this.read_enum_variant_arg(2, |this| Decodable::decode(this));
let b: ty::BuiltinBounds =
this.read_enum_variant_arg(3, |this| Decodable::decode(this));
let def_id: ast::DefId =
this.read_enum_variant_arg(4, |this| Decodable::decode(this));
let substs = this.read_enum_variant_arg(5, |this| this.read_substs(xcx));

let region = match region {
Some(r) => Some(r.tr(xcx)),
None => None
};

ty::AutoObject(sigil, region, m, b, def_id.tr(xcx), substs)
}
_ => fail!("bad enum variant for ty::AutoAdjustment")
}
})
})
}

fn convert_def_id(&mut self,
xcx: @ExtendedDecodeContext,
source: tydecode::DefIdSource,
Expand Down Expand Up @@ -1289,8 +1380,7 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext,
vtable_map.get().insert(id, vtable_res);
}
c::tag_table_adjustments => {
let adj: @ty::AutoAdjustment = @Decodable::decode(val_dsr);
adj.tr(xcx);
let adj: @ty::AutoAdjustment = @val_dsr.read_auto_adjustment(xcx);
let mut adjustments = dcx.tcx
.adjustments
.borrow_mut();
Expand Down
4 changes: 4 additions & 0 deletions src/librustc/middle/borrowck/gather_loans/mod.rs
Expand Up @@ -419,6 +419,10 @@ impl<'a> GatherLoanCtxt<'a> {
ty::AutoUnsafe(_) => {}
}
}

ty::AutoObject(..) => {
// XXX: Handle @Trait to &Trait casts here?
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/borrowck/mod.rs
Expand Up @@ -490,7 +490,7 @@ impl BorrowckCtxt {
adj: @ty::AutoAdjustment)
-> mc::cmt {
match *adj {
ty::AutoAddEnv(..) => {
ty::AutoAddEnv(..) | ty::AutoObject(..) => {
// no autoderefs
mc::cat_expr_unadjusted(self.tcx, self.method_map, expr)
}
Expand Down
44 changes: 30 additions & 14 deletions src/librustc/middle/kind.rs
Expand Up @@ -311,14 +311,9 @@ pub fn check_expr(cx: &mut Context, e: @Expr) {
let _ = check_durable(cx.tcx, interior_type, interior.span);
}
ExprCast(source, _) => {
check_cast_for_escaping_regions(cx, source, e);
match ty::get(ty::expr_ty(cx.tcx, e)).sty {
ty::ty_trait(_, _, _, _, bounds) => {
let source_ty = ty::expr_ty(cx.tcx, source);
check_trait_cast_bounds(cx, e.span, source_ty, bounds)
}
_ => { }
}
let source_ty = ty::expr_ty(cx.tcx, source);
let target_ty = ty::expr_ty(cx.tcx, e);
check_trait_cast(cx, source_ty, target_ty, source.span);
}
ExprRepeat(element, count_expr, _) => {
let count = ty::eval_repeat_count(&cx.tcx, count_expr);
Expand All @@ -330,9 +325,31 @@ pub fn check_expr(cx: &mut Context, e: @Expr) {
}
_ => {}
}

// Search for auto-adjustments to find trait coercions.
let adjustments = cx.tcx.adjustments.borrow();
match adjustments.get().find(&e.id) {
Some(&@ty::AutoObject(..)) => {
let source_ty = ty::expr_ty(cx.tcx, e);
let target_ty = ty::expr_ty_adjusted(cx.tcx, e);
check_trait_cast(cx, source_ty, target_ty, e.span);
}
Some(&@ty::AutoAddEnv(..)) | Some(&@ty::AutoDerefRef(..)) | None => {}
}

visit::walk_expr(cx, e, ());
}

fn check_trait_cast(cx: &mut Context, source_ty: ty::t, target_ty: ty::t, span: Span) {
check_cast_for_escaping_regions(cx, source_ty, target_ty, span);
match ty::get(target_ty).sty {
ty::ty_trait(_, _, _, _, bounds) => {
check_trait_cast_bounds(cx, span, source_ty, bounds);
}
_ => {}
}
}

fn check_ty(cx: &mut Context, aty: &Ty) {
match aty.node {
ty_path(_, _, id) => {
Expand Down Expand Up @@ -510,12 +527,12 @@ pub fn check_durable(tcx: ty::ctxt, ty: ty::t, sp: Span) -> bool {
/// FIXME(#5723)---This code should probably move into regionck.
pub fn check_cast_for_escaping_regions(
cx: &Context,
source: &Expr,
target: &Expr)
source_ty: ty::t,
target_ty: ty::t,
source_span: Span)
{
// Determine what type we are casting to; if it is not an trait, then no
// worries.
let target_ty = ty::expr_ty(cx.tcx, target);
match ty::get(target_ty).sty {
ty::ty_trait(..) => {}
_ => { return; }
Expand Down Expand Up @@ -545,7 +562,6 @@ pub fn check_cast_for_escaping_regions(
// Assuming the trait instance can escape, then ensure that each parameter
// either appears in the trait type or is sendable.
let target_params = ty::param_tys_in_type(target_ty);
let source_ty = ty::expr_ty(cx.tcx, source);
ty::walk_regions_and_ty(
cx.tcx,
source_ty,
Expand All @@ -555,7 +571,7 @@ pub fn check_cast_for_escaping_regions(
//
// if !target_regions.iter().any(|t_r| is_subregion_of(cx, *t_r, r)) {
// cx.tcx.sess.span_err(
// source.span,
// source_span,
// format!("source contains borrowed pointer with lifetime \
// not found in the target type `{}`",
// ty_to_str(cx.tcx, target_ty)));
Expand All @@ -570,7 +586,7 @@ pub fn check_cast_for_escaping_regions(
if target_params.iter().any(|x| x == &source_param) {
/* case (2) */
} else {
check_durable(cx.tcx, ty, source.span); /* case (3) */
check_durable(cx.tcx, ty, source_span); /* case (3) */
}
}
_ => {}
Expand Down
7 changes: 7 additions & 0 deletions src/librustc/middle/mem_categorization.rs
Expand Up @@ -347,6 +347,13 @@ impl mem_categorization_ctxt {
self.cat_expr_unadjusted(expr)
}

Some(&@ty::AutoObject(..)) => {
// Implicity casts a concrete object to trait object
// Result is an rvalue
let expr_ty = ty::expr_ty_adjusted(self.tcx, expr);
self.cat_rvalue_node(expr, expr_ty)
}

Some(&@ty::AutoAddEnv(..)) => {
// Convert a bare fn to a closure by adding NULL env.
// Result is an rvalue.
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/middle/trans/consts.rs
Expand Up @@ -199,6 +199,9 @@ pub fn const_expr(cx: @CrateContext, e: &ast::Expr) -> (ValueRef, bool) {
cx.sess.span_bug(e.span, format!("unexpected static function: \
region {:?} sigil {:?}", *r, *s))
}
Some(@ty::AutoObject(..)) => {
cx.sess.span_unimpl(e.span, "unimplemented const coercion to trait object");
}
Some(@ty::AutoDerefRef(ref adj)) => {
let mut ty = ety;
let mut maybe_ptr = None;
Expand Down
27 changes: 24 additions & 3 deletions src/librustc/middle/trans/expr.rs
Expand Up @@ -139,7 +139,7 @@ use middle::trans::inline;
use middle::trans::tvec;
use middle::trans::type_of;
use middle::ty::struct_fields;
use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoUnsafe};
use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoObject, AutoUnsafe};
use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn};
use middle::ty;
use util::common::indenter;
Expand Down Expand Up @@ -228,6 +228,23 @@ pub fn trans_to_datum(bcx: @Block, expr: &ast::Expr) -> DatumBlock {
}
};
}
AutoObject(ref sigil, ref region, _, _, _, _) => {

let adjusted_ty = ty::expr_ty_adjusted(bcx.tcx(), expr);
let scratch = scratch_datum(bcx, adjusted_ty, "__adjust", false);

let trait_store = match *sigil {
ast::BorrowedSigil => ty::RegionTraitStore(region.expect("expected valid region")),
ast::OwnedSigil => ty::UniqTraitStore,
ast::ManagedSigil => ty::BoxTraitStore
};

bcx = meth::trans_trait_cast(bcx, expr, expr.id, SaveIn(scratch.val),
trait_store, false /* no adjustments */);

datum = scratch.to_appropriate_datum(bcx);
datum.add_clean(bcx);
}
}
debug!("after adjustments, datum={}", datum.to_str(bcx.ccx()));
return DatumBlock {bcx: bcx, datum: datum};
Expand Down Expand Up @@ -432,6 +449,10 @@ pub fn trans_into(bcx: @Block, expr: &ast::Expr, dest: Dest) -> @Block {
};
}

trans_into_unadjusted(bcx, expr, dest)
}

pub fn trans_into_unadjusted(bcx: @Block, expr: &ast::Expr, dest: Dest) -> @Block {
let ty = expr_ty(bcx, expr);

debug!("trans_into_unadjusted(expr={}, dest={})",
Expand Down Expand Up @@ -778,8 +799,8 @@ fn trans_rvalue_dps_unadjusted(bcx: @Block, expr: &ast::Expr,
ast::ExprCast(val, _) => {
match ty::get(node_id_type(bcx, expr.id)).sty {
ty::ty_trait(_, _, store, _, _) => {
return meth::trans_trait_cast(bcx, val, expr.id, dest,
store);
return meth::trans_trait_cast(bcx, val, expr.id,
dest, store, true /* adjustments */);
}
_ => {
bcx.tcx().sess.span_bug(expr.span,
Expand Down

0 comments on commit 1265a03

Please sign in to comment.