about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-12-27 13:16:45 -0800
committerbors <bors@rust-lang.org>2013-12-27 13:16:45 -0800
commit1a9c8cc1283675dfc1b85dbf80a9ea07a2b8b335 (patch)
tree24b4d7140a3f92fbdaf1c785f917d61246ce0061
parentcc1b93e4254b241aae337a02c4bdb2d8fa4c7777 (diff)
parent981c6b12fad24ef28998668e515e62976f72b3bf (diff)
downloadrust-1a9c8cc1283675dfc1b85dbf80a9ea07a2b8b335.tar.gz
rust-1a9c8cc1283675dfc1b85dbf80a9ea07a2b8b335.zip
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
-rw-r--r--src/libextra/enum_set.rs2
-rw-r--r--src/librustc/metadata/tydecode.rs6
-rw-r--r--src/librustc/metadata/tyencode.rs2
-rw-r--r--src/librustc/middle/astencode.rs114
-rw-r--r--src/librustc/middle/borrowck/gather_loans/mod.rs4
-rw-r--r--src/librustc/middle/borrowck/mod.rs2
-rw-r--r--src/librustc/middle/kind.rs44
-rw-r--r--src/librustc/middle/mem_categorization.rs7
-rw-r--r--src/librustc/middle/trans/consts.rs3
-rw-r--r--src/librustc/middle/trans/expr.rs27
-rw-r--r--src/librustc/middle/trans/meth.rs14
-rw-r--r--src/librustc/middle/ty.rs27
-rw-r--r--src/librustc/middle/typeck/check/regionck.rs42
-rw-r--r--src/librustc/middle/typeck/check/vtable.rs215
-rw-r--r--src/librustc/middle/typeck/check/writeback.rs6
-rw-r--r--src/librustc/middle/typeck/infer/coercion.rs81
-rw-r--r--src/test/compile-fail/map-types.rs4
-rw-r--r--src/test/compile-fail/trait-coercion-generic-bad.rs32
-rw-r--r--src/test/compile-fail/trait-coercion-generic-regions.rs32
-rw-r--r--src/test/run-pass/trait-coercion-generic.rs42
-rw-r--r--src/test/run-pass/trait-coercion.rs42
21 files changed, 604 insertions, 144 deletions
diff --git a/src/libextra/enum_set.rs b/src/libextra/enum_set.rs
index 75611f88b63..6fd42f74a76 100644
--- a/src/libextra/enum_set.rs
+++ b/src/libextra/enum_set.rs
@@ -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
diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index 2e989f48b80..22fc7f4b3ea 100644
--- a/src/librustc/metadata/tydecode.rs
+++ b/src/librustc/metadata/tydecode.rs
@@ -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,
diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs
index 06d74055af4..1f9f1e18565 100644
--- a/src/librustc/metadata/tyencode.rs
+++ b/src/librustc/metadata/tyencode.rs
@@ -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, "[");
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 38f23a900d8..3560a930237 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -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
             }
         }
     }
@@ -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> {
@@ -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 {
@@ -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);
                 })
             })
         }
@@ -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,
@@ -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,
@@ -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();
diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs
index 36e35760400..86ccfda90c9 100644
--- a/src/librustc/middle/borrowck/gather_loans/mod.rs
+++ b/src/librustc/middle/borrowck/gather_loans/mod.rs
@@ -419,6 +419,10 @@ impl<'a> GatherLoanCtxt<'a> {
                     ty::AutoUnsafe(_) => {}
                 }
             }
+
+            ty::AutoObject(..) => {
+                // XXX: Handle @Trait to &Trait casts here?
+            }
         }
     }
 
diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs
index 61e5d1f25fe..ddc31598d67 100644
--- a/src/librustc/middle/borrowck/mod.rs
+++ b/src/librustc/middle/borrowck/mod.rs
@@ -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)
             }
diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs
index e426f92759f..70abd94ea31 100644
--- a/src/librustc/middle/kind.rs
+++ b/src/librustc/middle/kind.rs
@@ -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);
@@ -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) => {
@@ -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; }
@@ -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,
@@ -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)));
@@ -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) */
                     }
                 }
                 _ => {}
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index b39ddecf8c4..2349b5f4dd3 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -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.
diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs
index 19dc19262c0..c9d30ec1994 100644
--- a/src/librustc/middle/trans/consts.rs
+++ b/src/librustc/middle/trans/consts.rs
@@ -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;
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 2990a27391f..bf7a0d6039b 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -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;
@@ -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};
@@ -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={})",
@@ -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,
diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs
index f4df98870bb..d16cf6f1c3b 100644
--- a/src/librustc/middle/trans/meth.rs
+++ b/src/librustc/middle/trans/meth.rs
@@ -646,14 +646,22 @@ pub fn trans_trait_cast(bcx: @Block,
                         val: &ast::Expr,
                         id: ast::NodeId,
                         dest: expr::Dest,
-                        _store: ty::TraitStore)
+                        _store: ty::TraitStore,
+                        do_adjustments: bool)
                      -> @Block {
     let mut bcx = bcx;
     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 {
         Ignore => {
-            return expr::trans_into(bcx, val, Ignore);
+            return trans_into(bcx, val, Ignore);
         }
         SaveIn(dest) => dest
     };
@@ -668,7 +676,7 @@ pub fn trans_trait_cast(bcx: @Block,
     llboxdest = PointerCast(bcx,
                             llboxdest,
                             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.
     // This is structured a bit funny because of dynamic borrow failures.
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 60bbca6cf35..a3c2e2a4404 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -224,10 +224,14 @@ pub enum Variance {
     Bivariant,      // T<A> <: T<B>            -- e.g., unused type parameter
 }
 
-#[deriving(Decodable, Encodable)]
 pub enum AutoAdjustment {
     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)]
@@ -730,7 +734,7 @@ pub struct ParamBounds {
 
 pub type BuiltinBounds = EnumSet<BuiltinBound>;
 
-#[deriving(Clone, Eq, IterBytes, ToStr)]
+#[deriving(Clone, Encodable, Eq, Decodable, IterBytes, ToStr)]
 #[repr(uint)]
 pub enum BuiltinBound {
     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,
@@ -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 {
     pub fn map_region(&self, f: |Region| -> Region) -> AutoRef {
         match *self {
diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs
index 87947a91ccd..03fe9dc41b8 100644
--- a/src/librustc/middle/typeck/check/regionck.rs
+++ b/src/librustc/middle/typeck/check/regionck.rs
@@ -327,6 +327,25 @@ fn visit_expr(rcx: &mut Rcx, expr: @ast::Expr) {
                             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)) => {
                 debug!("adjustment={:?}", adjustment);
 
@@ -1103,6 +1143,8 @@ pub mod guarantor {
                 }
             }
 
+            Some(..) => fail!("invalid or unhandled adjustment"),
+
             None => {}
         }
 
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
index f2899cb6340..35501e5d5eb 100644
--- a/src/librustc/middle/typeck/check/vtable.rs
+++ b/src/librustc/middle/typeck/check/vtable.rs
@@ -9,8 +9,8 @@
 // except according to those terms.
 
 
-use middle::ty::param_ty;
 use middle::ty;
+use middle::ty::{AutoAddEnv, AutoDerefRef, AutoObject, param_ty};
 use middle::ty_fold::TypeFolder;
 use middle::typeck::check::{FnCtxt, impl_self_ty};
 use middle::typeck::check::{structurally_resolved_type};
@@ -565,6 +565,106 @@ pub fn early_resolve_expr(ex: @ast::Expr,
     let _indent = indenter();
 
     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,
+                                                     &param_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 {
       ast::ExprPath(..) => {
         fcx.opt_node_ty_substs(ex.id, |substs| {
@@ -621,107 +721,24 @@ pub fn early_resolve_expr(ex: @ast::Expr,
       ast::ExprCast(src, _) => {
           debug!("vtable resolution on expr {}", ex.repr(fcx.tcx()));
           let target_ty = fcx.expr_ty(ex);
-          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,
-                                                         &param_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 */ }
-          }
+          resolve_object_cast(src, target_ty);
       }
       _ => ()
     }
+
+    // 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,
diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs
index 3f371253e05..f84220da8e7 100644
--- a/src/librustc/middle/typeck/check/writeback.rs
+++ b/src/librustc/middle/typeck/check/writeback.rs
@@ -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();
             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`
diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs
index f4c3c33dbb3..0d4c3ef52d3 100644
--- a/src/librustc/middle/typeck/infer/coercion.rs
+++ b/src/librustc/middle/typeck/infer/coercion.rs
@@ -121,16 +121,61 @@ impl Coerce {
                 });
             }
 
-            ty::ty_trait(_, _, ty::RegionTraitStore(..), m, _) => {
+            ty::ty_ptr(mt_b) => {
                 return self.unpack_actual_value(a, |sty_a| {
-                    self.coerce_borrowed_object(a, sty_a, b, m)
+                    self.coerce_unsafe_ptr(a, sty_a, b, mt_b)
                 });
             }
 
-            ty::ty_ptr(mt_b) => {
-                return self.unpack_actual_value(a, |sty_a| {
-                    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))
         })))
     }
+
+    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))
+    }
 }
diff --git a/src/test/compile-fail/map-types.rs b/src/test/compile-fail/map-types.rs
index c2c4a0b6908..0a1eab913be 100644
--- a/src/test/compile-fail/map-types.rs
+++ b/src/test/compile-fail/map-types.rs
@@ -17,7 +17,7 @@ use std::hashmap::HashMap;
 
 fn main() {
     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;
-    //~^ 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
 }
diff --git a/src/test/compile-fail/trait-coercion-generic-bad.rs b/src/test/compile-fail/trait-coercion-generic-bad.rs
new file mode 100644
index 00000000000..2d73158add2
--- /dev/null
+++ b/src/test/compile-fail/trait-coercion-generic-bad.rs
@@ -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);
+}
+
diff --git a/src/test/compile-fail/trait-coercion-generic-regions.rs b/src/test/compile-fail/trait-coercion-generic-regions.rs
new file mode 100644
index 00000000000..1ea18a7c75b
--- /dev/null
+++ b/src/test/compile-fail/trait-coercion-generic-regions.rs
@@ -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 };
+}
+
diff --git a/src/test/run-pass/trait-coercion-generic.rs b/src/test/run-pass/trait-coercion-generic.rs
new file mode 100644
index 00000000000..415f7baf3d9
--- /dev/null
+++ b/src/test/run-pass/trait-coercion-generic.rs
@@ -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);
+}
+
diff --git a/src/test/run-pass/trait-coercion.rs b/src/test/run-pass/trait-coercion.rs
new file mode 100644
index 00000000000..1c6968266e1
--- /dev/null
+++ b/src/test/run-pass/trait-coercion.rs
@@ -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);
+}
+