Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

librustc: Implement coercion for traits. #11156

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/libextra/enum_set.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading