mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
auto merge of #11156 : luqmana/rust/trait-object-coercion, r=pcwalton
This ports over @pcwalton's old pull that bitrotted (#5597). Fixes #10039. r? @pcwalton / @nikomatsakis
This commit is contained in:
commit
1a9c8cc128
@ -13,7 +13,7 @@
|
|||||||
//! This module defines a container which uses an efficient bit mask
|
//! This module defines a container which uses an efficient bit mask
|
||||||
//! representation to hold C-like enum variants.
|
//! 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.
|
/// A specialized Set implementation to use enum types.
|
||||||
pub struct EnumSet<E> {
|
pub struct EnumSet<E> {
|
||||||
// We must maintain the invariant that no bits are set
|
// We must maintain the invariant that no bits are set
|
||||||
|
@ -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)
|
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 {
|
fn parse_sigil(st: &mut PState) -> ast::Sigil {
|
||||||
match next(st) {
|
match next(st) {
|
||||||
'@' => ast::ManagedSigil,
|
'@' => ast::ManagedSigil,
|
||||||
|
@ -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_region_substs(w, cx, &substs.regions);
|
||||||
enc_opt(w, substs.self_ty, |w, t| enc_ty(w, cx, t));
|
enc_opt(w, substs.self_ty, |w, t| enc_ty(w, cx, t));
|
||||||
mywrite!(w, "[");
|
mywrite!(w, "[");
|
||||||
|
@ -450,15 +450,13 @@ impl tr for ast::Def {
|
|||||||
// ______________________________________________________________________
|
// ______________________________________________________________________
|
||||||
// Encoding and decoding of adjustment information
|
// Encoding and decoding of adjustment information
|
||||||
|
|
||||||
impl tr for ty::AutoAdjustment {
|
impl tr for ty::AutoDerefRef {
|
||||||
fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::AutoAdjustment {
|
fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::AutoDerefRef {
|
||||||
match *self {
|
ty::AutoDerefRef {
|
||||||
ty::AutoAddEnv(r, s) => ty::AutoAddEnv(r.tr(xcx), s),
|
autoderefs: self.autoderefs,
|
||||||
ty::AutoDerefRef(ref adr) => {
|
autoref: match self.autoref {
|
||||||
ty::AutoDerefRef(ty::AutoDerefRef {
|
Some(ref autoref) => Some(autoref.tr(xcx)),
|
||||||
autoderefs: adr.autoderefs,
|
None => None
|
||||||
autoref: adr.autoref.map(|ar| ar.tr(xcx)),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -786,6 +784,8 @@ trait ebml_writer_helpers {
|
|||||||
fn emit_tpbt(&mut self,
|
fn emit_tpbt(&mut self,
|
||||||
ecx: &e::EncodeContext,
|
ecx: &e::EncodeContext,
|
||||||
tpbt: ty::ty_param_bounds_and_ty);
|
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> {
|
impl<'a> ebml_writer_helpers for writer::Encoder<'a> {
|
||||||
@ -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 {
|
trait write_tag_and_id {
|
||||||
@ -1023,7 +1057,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
|
|||||||
ebml_w.tag(c::tag_table_adjustments, |ebml_w| {
|
ebml_w.tag(c::tag_table_adjustments, |ebml_w| {
|
||||||
ebml_w.id(id);
|
ebml_w.id(id);
|
||||||
ebml_w.tag(c::tag_table_val, |ebml_w| {
|
ebml_w.tag(c::tag_table_val, |ebml_w| {
|
||||||
(**adj).encode(ebml_w)
|
ebml_w.emit_auto_adjustment(ecx, **adj);
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1064,6 +1098,8 @@ trait ebml_decoder_decoder_helpers {
|
|||||||
-> ty::TypeParameterDef;
|
-> ty::TypeParameterDef;
|
||||||
fn read_ty_param_bounds_and_ty(&mut self, xcx: @ExtendedDecodeContext)
|
fn read_ty_param_bounds_and_ty(&mut self, xcx: @ExtendedDecodeContext)
|
||||||
-> ty::ty_param_bounds_and_ty;
|
-> 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,
|
fn convert_def_id(&mut self,
|
||||||
xcx: @ExtendedDecodeContext,
|
xcx: @ExtendedDecodeContext,
|
||||||
source: DefIdSource,
|
source: DefIdSource,
|
||||||
@ -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,
|
fn convert_def_id(&mut self,
|
||||||
xcx: @ExtendedDecodeContext,
|
xcx: @ExtendedDecodeContext,
|
||||||
source: tydecode::DefIdSource,
|
source: tydecode::DefIdSource,
|
||||||
@ -1289,8 +1380,7 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext,
|
|||||||
vtable_map.get().insert(id, vtable_res);
|
vtable_map.get().insert(id, vtable_res);
|
||||||
}
|
}
|
||||||
c::tag_table_adjustments => {
|
c::tag_table_adjustments => {
|
||||||
let adj: @ty::AutoAdjustment = @Decodable::decode(val_dsr);
|
let adj: @ty::AutoAdjustment = @val_dsr.read_auto_adjustment(xcx);
|
||||||
adj.tr(xcx);
|
|
||||||
let mut adjustments = dcx.tcx
|
let mut adjustments = dcx.tcx
|
||||||
.adjustments
|
.adjustments
|
||||||
.borrow_mut();
|
.borrow_mut();
|
||||||
|
@ -419,6 +419,10 @@ impl<'a> GatherLoanCtxt<'a> {
|
|||||||
ty::AutoUnsafe(_) => {}
|
ty::AutoUnsafe(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ty::AutoObject(..) => {
|
||||||
|
// XXX: Handle @Trait to &Trait casts here?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,7 +490,7 @@ impl BorrowckCtxt {
|
|||||||
adj: @ty::AutoAdjustment)
|
adj: @ty::AutoAdjustment)
|
||||||
-> mc::cmt {
|
-> mc::cmt {
|
||||||
match *adj {
|
match *adj {
|
||||||
ty::AutoAddEnv(..) => {
|
ty::AutoAddEnv(..) | ty::AutoObject(..) => {
|
||||||
// no autoderefs
|
// no autoderefs
|
||||||
mc::cat_expr_unadjusted(self.tcx, self.method_map, expr)
|
mc::cat_expr_unadjusted(self.tcx, self.method_map, expr)
|
||||||
}
|
}
|
||||||
|
@ -311,14 +311,9 @@ pub fn check_expr(cx: &mut Context, e: @Expr) {
|
|||||||
let _ = check_durable(cx.tcx, interior_type, interior.span);
|
let _ = check_durable(cx.tcx, interior_type, interior.span);
|
||||||
}
|
}
|
||||||
ExprCast(source, _) => {
|
ExprCast(source, _) => {
|
||||||
check_cast_for_escaping_regions(cx, source, e);
|
let source_ty = ty::expr_ty(cx.tcx, source);
|
||||||
match ty::get(ty::expr_ty(cx.tcx, e)).sty {
|
let target_ty = ty::expr_ty(cx.tcx, e);
|
||||||
ty::ty_trait(_, _, _, _, bounds) => {
|
check_trait_cast(cx, source_ty, target_ty, source.span);
|
||||||
let source_ty = ty::expr_ty(cx.tcx, source);
|
|
||||||
check_trait_cast_bounds(cx, e.span, source_ty, bounds)
|
|
||||||
}
|
|
||||||
_ => { }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ExprRepeat(element, count_expr, _) => {
|
ExprRepeat(element, count_expr, _) => {
|
||||||
let count = ty::eval_repeat_count(&cx.tcx, count_expr);
|
let count = ty::eval_repeat_count(&cx.tcx, count_expr);
|
||||||
@ -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, ());
|
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) {
|
fn check_ty(cx: &mut Context, aty: &Ty) {
|
||||||
match aty.node {
|
match aty.node {
|
||||||
ty_path(_, _, id) => {
|
ty_path(_, _, id) => {
|
||||||
@ -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.
|
/// FIXME(#5723)---This code should probably move into regionck.
|
||||||
pub fn check_cast_for_escaping_regions(
|
pub fn check_cast_for_escaping_regions(
|
||||||
cx: &Context,
|
cx: &Context,
|
||||||
source: &Expr,
|
source_ty: ty::t,
|
||||||
target: &Expr)
|
target_ty: ty::t,
|
||||||
|
source_span: Span)
|
||||||
{
|
{
|
||||||
// Determine what type we are casting to; if it is not an trait, then no
|
// Determine what type we are casting to; if it is not an trait, then no
|
||||||
// worries.
|
// worries.
|
||||||
let target_ty = ty::expr_ty(cx.tcx, target);
|
|
||||||
match ty::get(target_ty).sty {
|
match ty::get(target_ty).sty {
|
||||||
ty::ty_trait(..) => {}
|
ty::ty_trait(..) => {}
|
||||||
_ => { return; }
|
_ => { return; }
|
||||||
@ -545,7 +562,6 @@ pub fn check_cast_for_escaping_regions(
|
|||||||
// Assuming the trait instance can escape, then ensure that each parameter
|
// Assuming the trait instance can escape, then ensure that each parameter
|
||||||
// either appears in the trait type or is sendable.
|
// either appears in the trait type or is sendable.
|
||||||
let target_params = ty::param_tys_in_type(target_ty);
|
let target_params = ty::param_tys_in_type(target_ty);
|
||||||
let source_ty = ty::expr_ty(cx.tcx, source);
|
|
||||||
ty::walk_regions_and_ty(
|
ty::walk_regions_and_ty(
|
||||||
cx.tcx,
|
cx.tcx,
|
||||||
source_ty,
|
source_ty,
|
||||||
@ -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)) {
|
// if !target_regions.iter().any(|t_r| is_subregion_of(cx, *t_r, r)) {
|
||||||
// cx.tcx.sess.span_err(
|
// cx.tcx.sess.span_err(
|
||||||
// source.span,
|
// source_span,
|
||||||
// format!("source contains borrowed pointer with lifetime \
|
// format!("source contains borrowed pointer with lifetime \
|
||||||
// not found in the target type `{}`",
|
// not found in the target type `{}`",
|
||||||
// ty_to_str(cx.tcx, target_ty)));
|
// ty_to_str(cx.tcx, target_ty)));
|
||||||
@ -570,7 +586,7 @@ pub fn check_cast_for_escaping_regions(
|
|||||||
if target_params.iter().any(|x| x == &source_param) {
|
if target_params.iter().any(|x| x == &source_param) {
|
||||||
/* case (2) */
|
/* case (2) */
|
||||||
} else {
|
} else {
|
||||||
check_durable(cx.tcx, ty, source.span); /* case (3) */
|
check_durable(cx.tcx, ty, source_span); /* case (3) */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -347,6 +347,13 @@ impl mem_categorization_ctxt {
|
|||||||
self.cat_expr_unadjusted(expr)
|
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(..)) => {
|
Some(&@ty::AutoAddEnv(..)) => {
|
||||||
// Convert a bare fn to a closure by adding NULL env.
|
// Convert a bare fn to a closure by adding NULL env.
|
||||||
// Result is an rvalue.
|
// Result is an rvalue.
|
||||||
|
@ -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: \
|
cx.sess.span_bug(e.span, format!("unexpected static function: \
|
||||||
region {:?} sigil {:?}", *r, *s))
|
region {:?} sigil {:?}", *r, *s))
|
||||||
}
|
}
|
||||||
|
Some(@ty::AutoObject(..)) => {
|
||||||
|
cx.sess.span_unimpl(e.span, "unimplemented const coercion to trait object");
|
||||||
|
}
|
||||||
Some(@ty::AutoDerefRef(ref adj)) => {
|
Some(@ty::AutoDerefRef(ref adj)) => {
|
||||||
let mut ty = ety;
|
let mut ty = ety;
|
||||||
let mut maybe_ptr = None;
|
let mut maybe_ptr = None;
|
||||||
|
@ -139,7 +139,7 @@ use middle::trans::inline;
|
|||||||
use middle::trans::tvec;
|
use middle::trans::tvec;
|
||||||
use middle::trans::type_of;
|
use middle::trans::type_of;
|
||||||
use middle::ty::struct_fields;
|
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::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use util::common::indenter;
|
use util::common::indenter;
|
||||||
@ -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()));
|
debug!("after adjustments, datum={}", datum.to_str(bcx.ccx()));
|
||||||
return DatumBlock {bcx: bcx, datum: datum};
|
return DatumBlock {bcx: bcx, datum: datum};
|
||||||
@ -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);
|
let ty = expr_ty(bcx, expr);
|
||||||
|
|
||||||
debug!("trans_into_unadjusted(expr={}, dest={})",
|
debug!("trans_into_unadjusted(expr={}, dest={})",
|
||||||
@ -778,8 +799,8 @@ fn trans_rvalue_dps_unadjusted(bcx: @Block, expr: &ast::Expr,
|
|||||||
ast::ExprCast(val, _) => {
|
ast::ExprCast(val, _) => {
|
||||||
match ty::get(node_id_type(bcx, expr.id)).sty {
|
match ty::get(node_id_type(bcx, expr.id)).sty {
|
||||||
ty::ty_trait(_, _, store, _, _) => {
|
ty::ty_trait(_, _, store, _, _) => {
|
||||||
return meth::trans_trait_cast(bcx, val, expr.id, dest,
|
return meth::trans_trait_cast(bcx, val, expr.id,
|
||||||
store);
|
dest, store, true /* adjustments */);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
bcx.tcx().sess.span_bug(expr.span,
|
bcx.tcx().sess.span_bug(expr.span,
|
||||||
|
@ -646,14 +646,22 @@ pub fn trans_trait_cast(bcx: @Block,
|
|||||||
val: &ast::Expr,
|
val: &ast::Expr,
|
||||||
id: ast::NodeId,
|
id: ast::NodeId,
|
||||||
dest: expr::Dest,
|
dest: expr::Dest,
|
||||||
_store: ty::TraitStore)
|
_store: ty::TraitStore,
|
||||||
|
do_adjustments: bool)
|
||||||
-> @Block {
|
-> @Block {
|
||||||
let mut bcx = bcx;
|
let mut bcx = bcx;
|
||||||
let _icx = push_ctxt("impl::trans_cast");
|
let _icx = push_ctxt("impl::trans_cast");
|
||||||
|
|
||||||
|
// Pick the right trans function
|
||||||
|
let trans_into = if do_adjustments {
|
||||||
|
expr::trans_into
|
||||||
|
} else {
|
||||||
|
expr::trans_into_unadjusted
|
||||||
|
};
|
||||||
|
|
||||||
let lldest = match dest {
|
let lldest = match dest {
|
||||||
Ignore => {
|
Ignore => {
|
||||||
return expr::trans_into(bcx, val, Ignore);
|
return trans_into(bcx, val, Ignore);
|
||||||
}
|
}
|
||||||
SaveIn(dest) => dest
|
SaveIn(dest) => dest
|
||||||
};
|
};
|
||||||
@ -668,7 +676,7 @@ pub fn trans_trait_cast(bcx: @Block,
|
|||||||
llboxdest = PointerCast(bcx,
|
llboxdest = PointerCast(bcx,
|
||||||
llboxdest,
|
llboxdest,
|
||||||
type_of(bcx.ccx(), v_ty).ptr_to());
|
type_of(bcx.ccx(), v_ty).ptr_to());
|
||||||
bcx = expr::trans_into(bcx, val, SaveIn(llboxdest));
|
bcx = trans_into(bcx, val, SaveIn(llboxdest));
|
||||||
|
|
||||||
// Store the vtable into the pair or triple.
|
// Store the vtable into the pair or triple.
|
||||||
// This is structured a bit funny because of dynamic borrow failures.
|
// This is structured a bit funny because of dynamic borrow failures.
|
||||||
|
@ -224,10 +224,14 @@ pub enum Variance {
|
|||||||
Bivariant, // T<A> <: T<B> -- e.g., unused type parameter
|
Bivariant, // T<A> <: T<B> -- e.g., unused type parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(Decodable, Encodable)]
|
|
||||||
pub enum AutoAdjustment {
|
pub enum AutoAdjustment {
|
||||||
AutoAddEnv(ty::Region, ast::Sigil),
|
AutoAddEnv(ty::Region, ast::Sigil),
|
||||||
AutoDerefRef(AutoDerefRef)
|
AutoDerefRef(AutoDerefRef),
|
||||||
|
AutoObject(ast::Sigil, Option<ty::Region>,
|
||||||
|
ast::Mutability,
|
||||||
|
ty::BuiltinBounds,
|
||||||
|
ast::DefId, /* Trait ID */
|
||||||
|
ty::substs /* Trait substitutions */)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(Decodable, Encodable)]
|
#[deriving(Decodable, Encodable)]
|
||||||
@ -730,7 +734,7 @@ pub struct ParamBounds {
|
|||||||
|
|
||||||
pub type BuiltinBounds = EnumSet<BuiltinBound>;
|
pub type BuiltinBounds = EnumSet<BuiltinBound>;
|
||||||
|
|
||||||
#[deriving(Clone, Eq, IterBytes, ToStr)]
|
#[deriving(Clone, Encodable, Eq, Decodable, IterBytes, ToStr)]
|
||||||
#[repr(uint)]
|
#[repr(uint)]
|
||||||
pub enum BuiltinBound {
|
pub enum BuiltinBound {
|
||||||
BoundStatic,
|
BoundStatic,
|
||||||
@ -2955,6 +2959,10 @@ pub fn adjust_ty(cx: ctxt,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(@AutoObject(ref sigil, ref region, m, b, def_id, ref substs)) => {
|
||||||
|
trait_adjustment_to_ty(cx, sigil, region, def_id, substs, m, b)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fn borrow_vec(cx: ctxt, span: Span,
|
fn borrow_vec(cx: ctxt, span: Span,
|
||||||
@ -3014,6 +3022,19 @@ pub fn adjust_ty(cx: ctxt,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn trait_adjustment_to_ty(cx: ctxt, sigil: &ast::Sigil, region: &Option<Region>,
|
||||||
|
def_id: ast::DefId, substs: &substs, m: ast::Mutability,
|
||||||
|
bounds: BuiltinBounds) -> t {
|
||||||
|
|
||||||
|
let trait_store = match *sigil {
|
||||||
|
BorrowedSigil => RegionTraitStore(region.expect("expected valid region")),
|
||||||
|
OwnedSigil => UniqTraitStore,
|
||||||
|
ManagedSigil => BoxTraitStore
|
||||||
|
};
|
||||||
|
|
||||||
|
mk_trait(cx, def_id, substs.clone(), trait_store, m, bounds)
|
||||||
|
}
|
||||||
|
|
||||||
impl AutoRef {
|
impl AutoRef {
|
||||||
pub fn map_region(&self, f: |Region| -> Region) -> AutoRef {
|
pub fn map_region(&self, f: |Region| -> Region) -> AutoRef {
|
||||||
match *self {
|
match *self {
|
||||||
|
@ -327,6 +327,25 @@ fn visit_expr(rcx: &mut Rcx, expr: @ast::Expr) {
|
|||||||
infer::AutoBorrow(expr.span));
|
infer::AutoBorrow(expr.span));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ty::AutoObject(ast::BorrowedSigil, Some(trait_region), _, _, _, _) => {
|
||||||
|
// Determine if we are casting `expr` to an trait
|
||||||
|
// instance. If so, we have to be sure that the type of
|
||||||
|
// the source obeys the trait's region bound.
|
||||||
|
//
|
||||||
|
// Note: there is a subtle point here concerning type
|
||||||
|
// parameters. It is possible that the type of `source`
|
||||||
|
// contains type parameters, which in turn may contain
|
||||||
|
// regions that are not visible to us (only the caller
|
||||||
|
// knows about them). The kind checker is ultimately
|
||||||
|
// responsible for guaranteeing region safety in that
|
||||||
|
// particular case. There is an extensive comment on the
|
||||||
|
// function check_cast_for_escaping_regions() in kind.rs
|
||||||
|
// explaining how it goes about doing that.
|
||||||
|
|
||||||
|
let source_ty = rcx.fcx.expr_ty(expr);
|
||||||
|
constrain_regions_in_type(rcx, trait_region,
|
||||||
|
infer::RelateObjectBound(expr.span), source_ty);
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1075,6 +1094,27 @@ pub mod guarantor {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(&@ty::AutoObject(ast::BorrowedSigil, Some(region), _, _, _, _)) => {
|
||||||
|
expr_ct.cat = ExprCategorization {
|
||||||
|
guarantor: None,
|
||||||
|
pointer: BorrowedPointer(region)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(&@ty::AutoObject(ast::OwnedSigil, _, _, _, _, _)) => {
|
||||||
|
expr_ct.cat = ExprCategorization {
|
||||||
|
guarantor: None,
|
||||||
|
pointer: OwnedPointer
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(&@ty::AutoObject(ast::ManagedSigil, _, _, _, _, _)) => {
|
||||||
|
expr_ct.cat = ExprCategorization {
|
||||||
|
guarantor: None,
|
||||||
|
pointer: OtherPointer
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Some(&@ty::AutoDerefRef(ref adjustment)) => {
|
Some(&@ty::AutoDerefRef(ref adjustment)) => {
|
||||||
debug!("adjustment={:?}", adjustment);
|
debug!("adjustment={:?}", adjustment);
|
||||||
|
|
||||||
@ -1103,6 +1143,8 @@ pub mod guarantor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(..) => fail!("invalid or unhandled adjustment"),
|
||||||
|
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
|
||||||
use middle::ty::param_ty;
|
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
|
use middle::ty::{AutoAddEnv, AutoDerefRef, AutoObject, param_ty};
|
||||||
use middle::ty_fold::TypeFolder;
|
use middle::ty_fold::TypeFolder;
|
||||||
use middle::typeck::check::{FnCtxt, impl_self_ty};
|
use middle::typeck::check::{FnCtxt, impl_self_ty};
|
||||||
use middle::typeck::check::{structurally_resolved_type};
|
use middle::typeck::check::{structurally_resolved_type};
|
||||||
@ -565,6 +565,106 @@ pub fn early_resolve_expr(ex: @ast::Expr,
|
|||||||
let _indent = indenter();
|
let _indent = indenter();
|
||||||
|
|
||||||
let cx = fcx.ccx;
|
let cx = fcx.ccx;
|
||||||
|
let resolve_object_cast = |src: @ast::Expr, target_ty: ty::t| {
|
||||||
|
match ty::get(target_ty).sty {
|
||||||
|
// Bounds of type's contents are not checked here, but in kind.rs.
|
||||||
|
ty::ty_trait(target_def_id, ref target_substs, store,
|
||||||
|
target_mutbl, _bounds) => {
|
||||||
|
fn mutability_allowed(a_mutbl: ast::Mutability,
|
||||||
|
b_mutbl: ast::Mutability) -> bool {
|
||||||
|
a_mutbl == b_mutbl ||
|
||||||
|
(a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable)
|
||||||
|
}
|
||||||
|
// Look up vtables for the type we're casting to,
|
||||||
|
// passing in the source and target type. The source
|
||||||
|
// must be a pointer type suitable to the object sigil,
|
||||||
|
// e.g.: `@x as @Trait`, `&x as &Trait` or `~x as ~Trait`
|
||||||
|
let ty = structurally_resolved_type(fcx, ex.span,
|
||||||
|
fcx.expr_ty(src));
|
||||||
|
match (&ty::get(ty).sty, store) {
|
||||||
|
(&ty::ty_box(mt), ty::BoxTraitStore) |
|
||||||
|
(&ty::ty_uniq(mt), ty::UniqTraitStore) |
|
||||||
|
(&ty::ty_rptr(_, mt), ty::RegionTraitStore(..))
|
||||||
|
if !mutability_allowed(mt.mutbl, target_mutbl) => {
|
||||||
|
fcx.tcx().sess.span_err(ex.span,
|
||||||
|
format!("types differ in mutability"));
|
||||||
|
}
|
||||||
|
|
||||||
|
(&ty::ty_box(mt), ty::BoxTraitStore) |
|
||||||
|
(&ty::ty_uniq(mt), ty::UniqTraitStore) |
|
||||||
|
(&ty::ty_rptr(_, mt), ty::RegionTraitStore(..)) => {
|
||||||
|
let location_info =
|
||||||
|
&location_info_for_expr(ex);
|
||||||
|
let vcx = fcx.vtable_context();
|
||||||
|
let target_trait_ref = @ty::TraitRef {
|
||||||
|
def_id: target_def_id,
|
||||||
|
substs: ty::substs {
|
||||||
|
tps: target_substs.tps.clone(),
|
||||||
|
regions: target_substs.regions.clone(),
|
||||||
|
self_ty: Some(mt.ty)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let param_bounds = ty::ParamBounds {
|
||||||
|
builtin_bounds: ty::EmptyBuiltinBounds(),
|
||||||
|
trait_bounds: ~[target_trait_ref]
|
||||||
|
};
|
||||||
|
let vtables =
|
||||||
|
lookup_vtables_for_param(&vcx,
|
||||||
|
location_info,
|
||||||
|
None,
|
||||||
|
¶m_bounds,
|
||||||
|
mt.ty,
|
||||||
|
is_early);
|
||||||
|
|
||||||
|
if !is_early {
|
||||||
|
insert_vtables(fcx, ex.id, @~[vtables]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, if this is &trait, we need to link the
|
||||||
|
// regions.
|
||||||
|
match (&ty::get(ty).sty, store) {
|
||||||
|
(&ty::ty_rptr(ra, _),
|
||||||
|
ty::RegionTraitStore(rb)) => {
|
||||||
|
infer::mk_subr(fcx.infcx(),
|
||||||
|
false,
|
||||||
|
infer::RelateObjectBound(
|
||||||
|
ex.span),
|
||||||
|
rb,
|
||||||
|
ra);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(_, ty::UniqTraitStore) => {
|
||||||
|
fcx.ccx.tcx.sess.span_err(
|
||||||
|
ex.span,
|
||||||
|
format!("can only cast an ~-pointer \
|
||||||
|
to a ~-object, not a {}",
|
||||||
|
ty::ty_sort_str(fcx.tcx(), ty)));
|
||||||
|
}
|
||||||
|
|
||||||
|
(_, ty::BoxTraitStore) => {
|
||||||
|
fcx.ccx.tcx.sess.span_err(
|
||||||
|
ex.span,
|
||||||
|
format!("can only cast an @-pointer \
|
||||||
|
to an @-object, not a {}",
|
||||||
|
ty::ty_sort_str(fcx.tcx(), ty)));
|
||||||
|
}
|
||||||
|
|
||||||
|
(_, ty::RegionTraitStore(_)) => {
|
||||||
|
fcx.ccx.tcx.sess.span_err(
|
||||||
|
ex.span,
|
||||||
|
format!("can only cast an &-pointer \
|
||||||
|
to an &-object, not a {}",
|
||||||
|
ty::ty_sort_str(fcx.tcx(), ty)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => { /* not a cast to a trait; ignore */ }
|
||||||
|
}
|
||||||
|
};
|
||||||
match ex.node {
|
match ex.node {
|
||||||
ast::ExprPath(..) => {
|
ast::ExprPath(..) => {
|
||||||
fcx.opt_node_ty_substs(ex.id, |substs| {
|
fcx.opt_node_ty_substs(ex.id, |substs| {
|
||||||
@ -621,107 +721,24 @@ pub fn early_resolve_expr(ex: @ast::Expr,
|
|||||||
ast::ExprCast(src, _) => {
|
ast::ExprCast(src, _) => {
|
||||||
debug!("vtable resolution on expr {}", ex.repr(fcx.tcx()));
|
debug!("vtable resolution on expr {}", ex.repr(fcx.tcx()));
|
||||||
let target_ty = fcx.expr_ty(ex);
|
let target_ty = fcx.expr_ty(ex);
|
||||||
match ty::get(target_ty).sty {
|
resolve_object_cast(src, target_ty);
|
||||||
// Bounds of type's contents are not checked here, but in kind.rs.
|
|
||||||
ty::ty_trait(target_def_id, ref target_substs, store,
|
|
||||||
target_mutbl, _bounds) => {
|
|
||||||
fn mutability_allowed(a_mutbl: ast::Mutability,
|
|
||||||
b_mutbl: ast::Mutability) -> bool {
|
|
||||||
a_mutbl == b_mutbl ||
|
|
||||||
(a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable)
|
|
||||||
}
|
|
||||||
// Look up vtables for the type we're casting to,
|
|
||||||
// passing in the source and target type. The source
|
|
||||||
// must be a pointer type suitable to the object sigil,
|
|
||||||
// e.g.: `@x as @Trait`, `&x as &Trait` or `~x as ~Trait`
|
|
||||||
let ty = structurally_resolved_type(fcx, ex.span,
|
|
||||||
fcx.expr_ty(src));
|
|
||||||
match (&ty::get(ty).sty, store) {
|
|
||||||
(&ty::ty_box(mt), ty::BoxTraitStore) |
|
|
||||||
(&ty::ty_uniq(mt), ty::UniqTraitStore) |
|
|
||||||
(&ty::ty_rptr(_, mt), ty::RegionTraitStore(..))
|
|
||||||
if !mutability_allowed(mt.mutbl, target_mutbl) => {
|
|
||||||
fcx.tcx().sess.span_err(ex.span,
|
|
||||||
format!("types differ in mutability"));
|
|
||||||
}
|
|
||||||
|
|
||||||
(&ty::ty_box(mt), ty::BoxTraitStore) |
|
|
||||||
(&ty::ty_uniq(mt), ty::UniqTraitStore) |
|
|
||||||
(&ty::ty_rptr(_, mt), ty::RegionTraitStore(..)) => {
|
|
||||||
let location_info =
|
|
||||||
&location_info_for_expr(ex);
|
|
||||||
let vcx = fcx.vtable_context();
|
|
||||||
let target_trait_ref = @ty::TraitRef {
|
|
||||||
def_id: target_def_id,
|
|
||||||
substs: ty::substs {
|
|
||||||
tps: target_substs.tps.clone(),
|
|
||||||
regions: target_substs.regions.clone(),
|
|
||||||
self_ty: Some(mt.ty)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let param_bounds = ty::ParamBounds {
|
|
||||||
builtin_bounds: ty::EmptyBuiltinBounds(),
|
|
||||||
trait_bounds: ~[target_trait_ref]
|
|
||||||
};
|
|
||||||
let vtables =
|
|
||||||
lookup_vtables_for_param(&vcx,
|
|
||||||
location_info,
|
|
||||||
None,
|
|
||||||
¶m_bounds,
|
|
||||||
mt.ty,
|
|
||||||
is_early);
|
|
||||||
|
|
||||||
if !is_early {
|
|
||||||
insert_vtables(fcx, ex.id, @~[vtables]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, if this is &trait, we need to link the
|
|
||||||
// regions.
|
|
||||||
match (&ty::get(ty).sty, store) {
|
|
||||||
(&ty::ty_rptr(ra, _),
|
|
||||||
ty::RegionTraitStore(rb)) => {
|
|
||||||
infer::mk_subr(fcx.infcx(),
|
|
||||||
false,
|
|
||||||
infer::RelateObjectBound(
|
|
||||||
ex.span),
|
|
||||||
rb,
|
|
||||||
ra);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(_, ty::UniqTraitStore) => {
|
|
||||||
fcx.ccx.tcx.sess.span_err(
|
|
||||||
ex.span,
|
|
||||||
format!("can only cast an ~-pointer \
|
|
||||||
to a ~-object, not a {}",
|
|
||||||
ty::ty_sort_str(fcx.tcx(), ty)));
|
|
||||||
}
|
|
||||||
|
|
||||||
(_, ty::BoxTraitStore) => {
|
|
||||||
fcx.ccx.tcx.sess.span_err(
|
|
||||||
ex.span,
|
|
||||||
format!("can only cast an @-pointer \
|
|
||||||
to an @-object, not a {}",
|
|
||||||
ty::ty_sort_str(fcx.tcx(), ty)));
|
|
||||||
}
|
|
||||||
|
|
||||||
(_, ty::RegionTraitStore(_)) => {
|
|
||||||
fcx.ccx.tcx.sess.span_err(
|
|
||||||
ex.span,
|
|
||||||
format!("can only cast an &-pointer \
|
|
||||||
to an &-object, not a {}",
|
|
||||||
ty::ty_sort_str(fcx.tcx(), ty)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => { /* not a cast to a trait; ignore */ }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Search for auto-adjustments to find trait coercions
|
||||||
|
let adjustments = fcx.inh.adjustments.borrow();
|
||||||
|
match adjustments.get().find(&ex.id) {
|
||||||
|
Some(&@AutoObject(ref sigil, ref region, m, b, def_id, ref substs)) => {
|
||||||
|
debug!("doing trait adjustment for expr {} {} (early? {})",
|
||||||
|
ex.id, ex.repr(fcx.tcx()), is_early);
|
||||||
|
|
||||||
|
let object_ty = ty::trait_adjustment_to_ty(cx.tcx, sigil, region,
|
||||||
|
def_id, substs, m, b);
|
||||||
|
resolve_object_cast(ex, object_ty);
|
||||||
|
}
|
||||||
|
Some(&@AutoAddEnv(..)) | Some(&@AutoDerefRef(..)) | None => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_expr(fcx: @FnCtxt,
|
fn resolve_expr(fcx: @FnCtxt,
|
||||||
|
@ -182,6 +182,12 @@ fn resolve_type_vars_for_node(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId)
|
|||||||
let mut adjustments = fcx.tcx().adjustments.borrow_mut();
|
let mut adjustments = fcx.tcx().adjustments.borrow_mut();
|
||||||
adjustments.get().insert(id, resolved_adj);
|
adjustments.get().insert(id, resolved_adj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(adjustment @ @ty::AutoObject(..)) => {
|
||||||
|
debug!("Adjustments for node {}: {:?}", id, adjustment);
|
||||||
|
let mut adjustments = fcx.tcx().adjustments.borrow_mut();
|
||||||
|
adjustments.get().insert(id, adjustment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve the type of the node with id `id`
|
// Resolve the type of the node with id `id`
|
||||||
|
@ -121,18 +121,63 @@ impl Coerce {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ty_trait(_, _, ty::RegionTraitStore(..), m, _) => {
|
|
||||||
return self.unpack_actual_value(a, |sty_a| {
|
|
||||||
self.coerce_borrowed_object(a, sty_a, b, m)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::ty_ptr(mt_b) => {
|
ty::ty_ptr(mt_b) => {
|
||||||
return self.unpack_actual_value(a, |sty_a| {
|
return self.unpack_actual_value(a, |sty_a| {
|
||||||
self.coerce_unsafe_ptr(a, sty_a, b, mt_b)
|
self.coerce_unsafe_ptr(a, sty_a, b, mt_b)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ty::ty_trait(def_id, ref substs, ty::BoxTraitStore, m, bounds) => {
|
||||||
|
let result = self.unpack_actual_value(a, |sty_a| {
|
||||||
|
match *sty_a {
|
||||||
|
ty::ty_box(..) => {
|
||||||
|
self.coerce_object(a, sty_a, b, def_id, substs,
|
||||||
|
ty::BoxTraitStore, m, bounds)
|
||||||
|
}
|
||||||
|
_ => Err(ty::terr_mismatch)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(t) => return Ok(t),
|
||||||
|
Err(..) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::ty_trait(def_id, ref substs, ty::UniqTraitStore, m, bounds) => {
|
||||||
|
let result = self.unpack_actual_value(a, |sty_a| {
|
||||||
|
match *sty_a {
|
||||||
|
ty::ty_uniq(..) => {
|
||||||
|
self.coerce_object(a, sty_a, b, def_id, substs,
|
||||||
|
ty::UniqTraitStore, m, bounds)
|
||||||
|
}
|
||||||
|
_ => Err(ty::terr_mismatch)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(t) => return Ok(t),
|
||||||
|
Err(..) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::ty_trait(def_id, ref substs, ty::RegionTraitStore(region), m, bounds) => {
|
||||||
|
let result = self.unpack_actual_value(a, |sty_a| {
|
||||||
|
match *sty_a {
|
||||||
|
ty::ty_rptr(..) => {
|
||||||
|
self.coerce_object(a, sty_a, b, def_id, substs,
|
||||||
|
ty::RegionTraitStore(region), m, bounds)
|
||||||
|
}
|
||||||
|
_ => self.coerce_borrowed_object(a, sty_a, b, m)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(t) => return Ok(t),
|
||||||
|
Err(..) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,4 +455,30 @@ impl Coerce {
|
|||||||
autoref: Some(ty::AutoUnsafe(mt_b.mutbl))
|
autoref: Some(ty::AutoUnsafe(mt_b.mutbl))
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn coerce_object(&self,
|
||||||
|
a: ty::t,
|
||||||
|
sty_a: &ty::sty,
|
||||||
|
b: ty::t,
|
||||||
|
trait_def_id: ast::DefId,
|
||||||
|
trait_substs: &ty::substs,
|
||||||
|
trait_store: ty::TraitStore,
|
||||||
|
m: ast::Mutability,
|
||||||
|
bounds: ty::BuiltinBounds) -> CoerceResult {
|
||||||
|
|
||||||
|
debug!("coerce_object(a={}, sty_a={:?}, b={})",
|
||||||
|
a.inf_str(self.infcx), sty_a,
|
||||||
|
b.inf_str(self.infcx));
|
||||||
|
|
||||||
|
let (sigil, region) = match trait_store {
|
||||||
|
ty::BoxTraitStore => (ast::ManagedSigil, None),
|
||||||
|
ty::UniqTraitStore => (ast::OwnedSigil, None),
|
||||||
|
ty::RegionTraitStore(region) => (ast::BorrowedSigil, Some(region))
|
||||||
|
};
|
||||||
|
|
||||||
|
let adjustment = @ty::AutoObject(sigil, region, m, bounds,
|
||||||
|
trait_def_id, trait_substs.clone());
|
||||||
|
|
||||||
|
Ok(Some(adjustment))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ use std::hashmap::HashMap;
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x: @HashMap<~str, ~str> = @HashMap::new();
|
let x: @HashMap<~str, ~str> = @HashMap::new();
|
||||||
let x: @Map<~str, ~str> = x as @Map<~str, ~str>;
|
let x: @Map<~str, ~str> = x;
|
||||||
let y: @Map<uint, ~str> = @x;
|
let y: @Map<uint, ~str> = @x;
|
||||||
//~^ ERROR expected trait std::container::Map but found @-ptr
|
//~^ ERROR failed to find an implementation of trait std::container::Map<uint,~str> for @std::container::Map<~str,~str>:'static
|
||||||
}
|
}
|
||||||
|
32
src/test/compile-fail/trait-coercion-generic-bad.rs
Normal file
32
src/test/compile-fail/trait-coercion-generic-bad.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[feature(managed_boxes)];
|
||||||
|
|
||||||
|
struct Struct {
|
||||||
|
person: &'static str
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Trait<T> {
|
||||||
|
fn f(&self, x: T);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait<&'static str> for Struct {
|
||||||
|
fn f(&self, x: &'static str) {
|
||||||
|
println!("Hello, {}!", x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s: @Trait<int> = @Struct { person: "Fred" }; //~ ERROR expected Trait<int>, but found Trait<&'static str>
|
||||||
|
//~^ ERROR expected Trait<int>, but found Trait<&'static str>
|
||||||
|
s.f(1);
|
||||||
|
}
|
||||||
|
|
32
src/test/compile-fail/trait-coercion-generic-regions.rs
Normal file
32
src/test/compile-fail/trait-coercion-generic-regions.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[feature(managed_boxes)];
|
||||||
|
|
||||||
|
struct Struct {
|
||||||
|
person: &'static str
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Trait<T> {
|
||||||
|
fn f(&self, x: T);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait<&'static str> for Struct {
|
||||||
|
fn f(&self, x: &'static str) {
|
||||||
|
println!("Hello, {}!", x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let person = ~"Fred";
|
||||||
|
let person: &str = person; //~ ERROR borrowed value does not live long enough
|
||||||
|
let s: @Trait<&'static str> = @Struct { person: person };
|
||||||
|
}
|
||||||
|
|
42
src/test/run-pass/trait-coercion-generic.rs
Normal file
42
src/test/run-pass/trait-coercion-generic.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[feature(managed_boxes)];
|
||||||
|
|
||||||
|
trait Trait<T> {
|
||||||
|
fn f(&self, x: T);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Struct {
|
||||||
|
x: int,
|
||||||
|
y: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait<&'static str> for Struct {
|
||||||
|
fn f(&self, x: &'static str) {
|
||||||
|
println(~"Hi, " + x + ~"!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(x: @Trait<&'static str>) {
|
||||||
|
x.f("Sue");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let a = Struct { x: 1, y: 2 };
|
||||||
|
let b: @Trait<&'static str> = @a;
|
||||||
|
b.f("Fred");
|
||||||
|
let c: ~Trait<&'static str> = ~a;
|
||||||
|
c.f("Mary");
|
||||||
|
let d: &Trait<&'static str> = &a;
|
||||||
|
d.f("Joe");
|
||||||
|
f(@a);
|
||||||
|
}
|
||||||
|
|
42
src/test/run-pass/trait-coercion.rs
Normal file
42
src/test/run-pass/trait-coercion.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[feature(managed_boxes)];
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
fn f(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Struct {
|
||||||
|
x: int,
|
||||||
|
y: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for Struct {
|
||||||
|
fn f(&self) {
|
||||||
|
println("Hi!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(x: @Trait) {
|
||||||
|
x.f();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let a = Struct { x: 1, y: 2 };
|
||||||
|
let b: @Trait = @a;
|
||||||
|
b.f();
|
||||||
|
let c: ~Trait = ~a;
|
||||||
|
c.f();
|
||||||
|
let d: &Trait = &a;
|
||||||
|
d.f();
|
||||||
|
f(@a);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user