about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2013-04-02 03:40:57 -0400
committerJosh Matthews <josh@joshmatthews.net>2013-04-17 00:34:25 +0200
commit97303703eec8e80003b4ffe729ad4df3ded1445c (patch)
treeb17ab368fc8c2f76ed901d61a5dc045c14ce4367
parent07e087bf310e7e7911bf05efa36a2cdb57855a4e (diff)
downloadrust-97303703eec8e80003b4ffe729ad4df3ded1445c.tar.gz
rust-97303703eec8e80003b4ffe729ad4df3ded1445c.zip
Allow casting to mutable trait objects.
-rw-r--r--src/librustc/metadata/tydecode.rs16
-rw-r--r--src/librustc/metadata/tyencode.rs13
-rw-r--r--src/librustc/middle/kind.rs2
-rw-r--r--src/librustc/middle/trans/debuginfo.rs2
-rw-r--r--src/librustc/middle/trans/expr.rs2
-rw-r--r--src/librustc/middle/trans/glue.rs8
-rw-r--r--src/librustc/middle/trans/monomorphize.rs2
-rw-r--r--src/librustc/middle/trans/reflect.rs2
-rw-r--r--src/librustc/middle/trans/type_of.rs4
-rw-r--r--src/librustc/middle/trans/type_use.rs2
-rw-r--r--src/librustc/middle/ty.rs46
-rw-r--r--src/librustc/middle/typeck/astconv.rs7
-rw-r--r--src/librustc/middle/typeck/check/method.rs2
-rw-r--r--src/librustc/middle/typeck/check/regionck.rs2
-rw-r--r--src/librustc/middle/typeck/check/vtable.rs20
-rw-r--r--src/librustc/middle/typeck/coherence.rs4
-rw-r--r--src/librustc/middle/typeck/infer/combine.rs8
-rw-r--r--src/librustc/middle/typeck/infer/mod.rs5
-rw-r--r--src/librustc/util/ppaux.rs18
-rw-r--r--src/test/compile-fail/cast-immutable-mutable-trait.rs28
-rw-r--r--src/test/run-pass/cast-mutable-trait.rs34
21 files changed, 162 insertions, 65 deletions
diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index f52ff056472..41ebf14a9a8 100644
--- a/src/librustc/metadata/tydecode.rs
+++ b/src/librustc/metadata/tydecode.rs
@@ -313,8 +313,9 @@ fn parse_ty(st: @mut PState, conv: conv_did) -> ty::t {
         let def = parse_def(st, NominalType, conv);
         let substs = parse_substs(st, conv);
         let store = parse_trait_store(st);
+        let mt = parse_mutability(st);
         assert!(next(st) == ']');
-        return ty::mk_trait(st.tcx, def, substs, store);
+        return ty::mk_trait(st.tcx, def, substs, store, mt);
       }
       'p' => {
         let did = parse_def(st, TypeParameter, conv);
@@ -396,13 +397,16 @@ fn parse_ty(st: @mut PState, conv: conv_did) -> ty::t {
     }
 }
 
-fn parse_mt(st: @mut PState, conv: conv_did) -> ty::mt {
-    let mut m;
+fn parse_mutability(st: @mut PState) -> ast::mutability {
     match peek(st) {
-      'm' => { next(st); m = ast::m_mutbl; }
-      '?' => { next(st); m = ast::m_const; }
-      _ => { m = ast::m_imm; }
+      'm' => { next(st); ast::m_mutbl }
+      '?' => { next(st); ast::m_const }
+      _ => { ast::m_imm }
     }
+}
+
+fn parse_mt(st: @mut PState, conv: conv_did) -> ty::mt {
+    let m = parse_mutability(st);
     ty::mt { ty: parse_ty(st, conv), mutbl: m }
 }
 
diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs
index 2e1dd8b6dad..a9a07d1b41d 100644
--- a/src/librustc/metadata/tyencode.rs
+++ b/src/librustc/metadata/tyencode.rs
@@ -22,6 +22,7 @@ use core::io;
 use core::uint;
 use core::vec;
 use syntax::abi::AbiSet;
+use syntax::ast;
 use syntax::ast::*;
 use syntax::diagnostic::span_handler;
 use syntax::print::pprust::*;
@@ -113,12 +114,17 @@ pub fn enc_ty(w: @io::Writer, cx: @ctxt, t: ty::t) {
       }
     }
 }
-fn enc_mt(w: @io::Writer, cx: @ctxt, mt: ty::mt) {
-    match mt.mutbl {
+
+fn enc_mutability(w: @io::Writer, mt: ast::mutability) {
+    match mt {
       m_imm => (),
       m_mutbl => w.write_char('m'),
       m_const => w.write_char('?')
     }
+}
+
+fn enc_mt(w: @io::Writer, cx: @ctxt, mt: ty::mt) {
+    enc_mutability(w, mt.mutbl);
     enc_ty(w, cx, mt.ty);
 }
 
@@ -269,12 +275,13 @@ fn enc_sty(w: @io::Writer, cx: @ctxt, +st: ty::sty) {
         enc_substs(w, cx, (*substs));
         w.write_char(']');
       }
-      ty::ty_trait(def, ref substs, store) => {
+      ty::ty_trait(def, ref substs, store, mt) => {
         w.write_str(&"x[");
         w.write_str((cx.ds)(def));
         w.write_char('|');
         enc_substs(w, cx, (*substs));
         enc_trait_store(w, cx, store);
+        enc_mutability(w, mt);
         w.write_char(']');
       }
       ty::ty_tup(ts) => {
diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs
index e5fc9f2d603..59ae4812f27 100644
--- a/src/librustc/middle/kind.rs
+++ b/src/librustc/middle/kind.rs
@@ -589,7 +589,7 @@ pub fn check_cast_for_escaping_regions(
 pub fn check_kind_bounds_of_cast(cx: Context, source: @expr, target: @expr) {
     let target_ty = ty::expr_ty(cx.tcx, target);
     match ty::get(target_ty).sty {
-        ty::ty_trait(_, _, ty::UniqTraitStore) => {
+        ty::ty_trait(_, _, ty::UniqTraitStore, _) => {
             let source_ty = ty::expr_ty(cx.tcx, source);
             if !ty::type_is_owned(cx.tcx, source_ty) {
                 cx.tcx.sess.span_err(
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index c02417aca8b..c10086aa56c 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -671,7 +671,7 @@ fn create_ty(cx: @CrateContext, t: ty::t, span: span)
         ty::ty_closure(ref _closurety) => {
             cx.sess.span_bug(span, ~"debuginfo for closure NYI")
         },
-        ty::ty_trait(_did, ref _substs, ref _vstore) => {
+        ty::ty_trait(_did, ref _substs, ref _vstore, _) => {
             cx.sess.span_bug(span, ~"debuginfo for trait NYI")
         },
         ty::ty_struct(did, ref substs) => {
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index d4a1013e83c..e75e49f18f3 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -667,7 +667,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
         }
         ast::expr_cast(val, _) => {
             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,
                                                   store);
                 }
diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs
index 827f4afaf78..51d4622d6a1 100644
--- a/src/librustc/middle/trans/glue.rs
+++ b/src/librustc/middle/trans/glue.rs
@@ -551,11 +551,11 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
       ty::ty_closure(_) => {
         closure::make_closure_glue(bcx, v0, t, drop_ty)
       }
-      ty::ty_trait(_, _, ty::BoxTraitStore) => {
+      ty::ty_trait(_, _, ty::BoxTraitStore, _) => {
         let llbox = Load(bcx, GEPi(bcx, v0, [0u, 1u]));
         decr_refcnt_maybe_free(bcx, llbox, ty::mk_opaque_box(ccx.tcx))
       }
-      ty::ty_trait(_, _, ty::UniqTraitStore) => {
+      ty::ty_trait(_, _, ty::UniqTraitStore, _) => {
         let lluniquevalue = GEPi(bcx, v0, [0, 1]);
         let lltydesc = Load(bcx, GEPi(bcx, v0, [0, 2]));
         call_tydesc_glue_full(bcx, lluniquevalue, lltydesc,
@@ -617,12 +617,12 @@ pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) {
       ty::ty_closure(_) => {
         closure::make_closure_glue(bcx, v, t, take_ty)
       }
-      ty::ty_trait(_, _, ty::BoxTraitStore) => {
+      ty::ty_trait(_, _, ty::BoxTraitStore, _) => {
         let llbox = Load(bcx, GEPi(bcx, v, [0u, 1u]));
         incr_refcnt_of_boxed(bcx, llbox);
         bcx
       }
-      ty::ty_trait(_, _, ty::UniqTraitStore) => {
+      ty::ty_trait(_, _, ty::UniqTraitStore, _) => {
         let llval = GEPi(bcx, v, [0, 1]);
         let lltydesc = Load(bcx, GEPi(bcx, v, [0, 2]));
         call_tydesc_glue_full(bcx, llval, lltydesc,
diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs
index 97dc3fed780..7aab6367d40 100644
--- a/src/librustc/middle/trans/monomorphize.rs
+++ b/src/librustc/middle/trans/monomorphize.rs
@@ -303,7 +303,7 @@ pub fn normalize_for_monomorphization(tcx: ty::ctxt,
         ty::ty_closure(ref fty) => {
             Some(normalized_closure_ty(tcx, fty.sigil))
         }
-        ty::ty_trait(_, _, ref store) => {
+        ty::ty_trait(_, _, ref store, _) => {
             let sigil = match *store {
                 ty::UniqTraitStore => ast::OwnedSigil,
                 ty::BoxTraitStore => ast::ManagedSigil,
diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs
index 596c55a68f8..e62e19f636a 100644
--- a/src/librustc/middle/trans/reflect.rs
+++ b/src/librustc/middle/trans/reflect.rs
@@ -323,7 +323,7 @@ pub impl Reflector {
           }
 
           // Miscallaneous extra types
-          ty::ty_trait(_, _, _) => self.leaf(~"trait"),
+          ty::ty_trait(_, _, _, _) => self.leaf(~"trait"),
           ty::ty_infer(_) => self.leaf(~"infer"),
           ty::ty_err => self.leaf(~"err"),
           ty::ty_param(ref p) => {
diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs
index 1c94fe28422..b9e4bad42dd 100644
--- a/src/librustc/middle/trans/type_of.rs
+++ b/src/librustc/middle/trans/type_of.rs
@@ -133,7 +133,7 @@ pub fn sizing_type_of(cx: @CrateContext, t: ty::t) -> TypeRef {
 
         ty::ty_bare_fn(*) => T_ptr(T_i8()),
         ty::ty_closure(*) => T_struct(~[T_ptr(T_i8()), T_ptr(T_i8())], false),
-        ty::ty_trait(_, _, store) => T_opaque_trait(cx, store),
+        ty::ty_trait(_, _, store, _) => T_opaque_trait(cx, store),
 
         ty::ty_estr(ty::vstore_fixed(size)) => T_array(T_i8(), size),
         ty::ty_evec(mt, ty::vstore_fixed(size)) => {
@@ -249,7 +249,7 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef {
 
       ty::ty_bare_fn(_) => T_ptr(type_of_fn_from_ty(cx, t)),
       ty::ty_closure(_) => T_fn_pair(cx, type_of_fn_from_ty(cx, t)),
-      ty::ty_trait(_, _, store) => T_opaque_trait(cx, store),
+      ty::ty_trait(_, _, store, _) => T_opaque_trait(cx, store),
       ty::ty_type => T_ptr(cx.tydesc_type),
       ty::ty_tup(*) => {
           let repr = adt::represent_type(cx, t);
diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs
index 572e9348f63..25e3ed0f400 100644
--- a/src/librustc/middle/trans/type_use.rs
+++ b/src/librustc/middle/trans/type_use.rs
@@ -216,7 +216,7 @@ pub fn type_needs_inner(cx: Context,
                 ty::ty_bare_fn(*) |
                 ty::ty_ptr(_) |
                 ty::ty_rptr(_, _) |
-                ty::ty_trait(_, _, _) => false,
+                ty::ty_trait(_, _, _, _) => false,
 
               ty::ty_enum(did, ref substs) => {
                 if list::find(enums_seen, |id| *id == did).is_none() {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index f62e366ebdc..4212b03c416 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -532,7 +532,7 @@ pub enum sty {
     ty_rptr(Region, mt),
     ty_bare_fn(BareFnTy),
     ty_closure(ClosureTy),
-    ty_trait(def_id, substs, TraitStore),
+    ty_trait(def_id, substs, TraitStore, ast::mutability),
     ty_struct(def_id, substs),
     ty_tup(~[t]),
 
@@ -946,7 +946,7 @@ fn mk_t_with_id(cx: ctxt, +st: sty, o_def_id: Option<ast::def_id>) -> t {
       &ty_infer(_) => flags |= needs_infer as uint,
       &ty_self(_) => flags |= has_self as uint,
       &ty_enum(_, ref substs) | &ty_struct(_, ref substs) |
-      &ty_trait(_, ref substs, _) => {
+      &ty_trait(_, ref substs, _, _) => {
         flags |= sflags(substs);
       }
       &ty_box(ref m) | &ty_uniq(ref m) | &ty_evec(ref m, _) |
@@ -1115,10 +1115,11 @@ pub fn mk_ctor_fn(cx: ctxt, input_tys: &[ty::t], output: ty::t) -> t {
 pub fn mk_trait(cx: ctxt,
                 did: ast::def_id,
                 +substs: substs,
-                store: TraitStore)
+                store: TraitStore,
+                mutability: ast::mutability)
              -> t {
     // take a copy of substs so that we own the vectors inside
-    mk_t(cx, ty_trait(did, substs, store))
+    mk_t(cx, ty_trait(did, substs, store, mutability))
 }
 
 pub fn mk_struct(cx: ctxt, struct_id: ast::def_id, +substs: substs) -> t {
@@ -1214,7 +1215,7 @@ pub fn maybe_walk_ty(ty: t, f: &fn(t) -> bool) {
         maybe_walk_ty(tm.ty, f);
       }
       ty_enum(_, ref substs) | ty_struct(_, ref substs) |
-      ty_trait(_, ref substs, _) => {
+      ty_trait(_, ref substs, _, _) => {
         for (*substs).tps.each |subty| { maybe_walk_ty(*subty, f); }
       }
       ty_tup(ref ts) => { for ts.each |tt| { maybe_walk_ty(*tt, f); } }
@@ -1277,8 +1278,8 @@ fn fold_sty(sty: &sty, fldop: &fn(t) -> t) -> sty {
         ty_enum(tid, ref substs) => {
             ty_enum(tid, fold_substs(substs, fldop))
         }
-        ty_trait(did, ref substs, st) => {
-            ty_trait(did, fold_substs(substs, fldop), st)
+        ty_trait(did, ref substs, st, mutbl) => {
+            ty_trait(did, fold_substs(substs, fldop), st, mutbl)
         }
         ty_tup(ref ts) => {
             let new_ts = ts.map(|tt| fldop(*tt));
@@ -1367,8 +1368,8 @@ pub fn fold_regions_and_ty(
       ty_struct(def_id, ref substs) => {
         ty::mk_struct(cx, def_id, fold_substs(substs, fldr, fldt))
       }
-      ty_trait(def_id, ref substs, st) => {
-        ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), st)
+      ty_trait(def_id, ref substs, st, mutbl) => {
+        ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), st, mutbl)
       }
       ty_bare_fn(ref f) => {
           ty::mk_bare_fn(cx, BareFnTy {sig: fold_sig(&f.sig, fldfnt),
@@ -1911,16 +1912,19 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
                 TC_MANAGED + nonowned(tc_mt(cx, mt, cache))
             }
 
-            ty_trait(_, _, UniqTraitStore) => {
+            ty_trait(_, _, UniqTraitStore, _) => {
                 TC_OWNED_CLOSURE
             }
 
-            ty_trait(_, _, BoxTraitStore) => {
-                TC_MANAGED
+            ty_trait(_, _, BoxTraitStore, mutbl) => {
+                match mutbl {
+                    ast::m_mutbl => TC_MANAGED + TC_MUTABLE,
+                    _ => TC_MANAGED
+                }
             }
 
-            ty_trait(_, _, RegionTraitStore(r)) => {
-                borrowed_contents(r, m_imm)
+            ty_trait(_, _, RegionTraitStore(r), mutbl) => {
+                borrowed_contents(r, mutbl)
             }
 
             ty_rptr(r, mt) => {
@@ -2241,7 +2245,7 @@ pub fn is_instantiable(cx: ctxt, r_ty: t) -> bool {
             false           // unsafe ptrs can always be NULL
           }
 
-          ty_trait(_, _, _) => {
+          ty_trait(_, _, _, _) => {
             false
           }
 
@@ -2385,7 +2389,7 @@ pub fn type_is_pod(cx: ctxt, ty: t) -> bool {
       ty_box(_) | ty_uniq(_) | ty_closure(_) |
       ty_estr(vstore_uniq) | ty_estr(vstore_box) |
       ty_evec(_, vstore_uniq) | ty_evec(_, vstore_box) |
-      ty_trait(_, _, _) | ty_rptr(_,_) | ty_opaque_box => result = false,
+      ty_trait(_, _, _, _) | ty_rptr(_,_) | ty_opaque_box => result = false,
       // Structural types
       ty_enum(did, ref substs) => {
         let variants = enum_variants(cx, did);
@@ -2673,8 +2677,8 @@ impl to_bytes::IterBytes for sty {
           ty_uniq(ref mt) =>
           to_bytes::iter_bytes_2(&19u8, mt, lsb0, f),
 
-          ty_trait(ref did, ref substs, ref v) =>
-          to_bytes::iter_bytes_4(&20u8, did, substs, v, lsb0, f),
+          ty_trait(ref did, ref substs, ref v, ref mutbl) =>
+          to_bytes::iter_bytes_5(&20u8, did, substs, v, mutbl, lsb0, f),
 
           ty_opaque_closure_ptr(ref ck) =>
           to_bytes::iter_bytes_2(&21u8, ck, lsb0, f),
@@ -3366,7 +3370,7 @@ pub fn ty_sort_str(cx: ctxt, t: t) -> ~str {
       ty_rptr(_, _) => ~"&-ptr",
       ty_bare_fn(_) => ~"extern fn",
       ty_closure(_) => ~"fn",
-      ty_trait(id, _, _) => fmt!("trait %s", item_path_str(cx, id)),
+      ty_trait(id, _, _, _) => fmt!("trait %s", item_path_str(cx, id)),
       ty_struct(id, _) => fmt!("struct %s", item_path_str(cx, id)),
       ty_tup(_) => ~"tuple",
       ty_infer(TyVar(_)) => ~"inferred type",
@@ -3679,7 +3683,7 @@ pub fn impl_trait_refs(cx: ctxt, id: ast::def_id) -> ~[@TraitRef] {
 
 pub fn ty_to_def_id(ty: t) -> Option<ast::def_id> {
     match get(ty).sty {
-      ty_trait(id, _, _) | ty_struct(id, _) | ty_enum(id, _) => Some(id),
+      ty_trait(id, _, _, _) | ty_struct(id, _) | ty_enum(id, _) => Some(id),
       _ => None
     }
 }
@@ -4413,7 +4417,7 @@ pub fn visitor_object_ty(tcx: ctxt) -> (@TraitRef, t) {
     assert!(tcx.intrinsic_traits.contains_key(&ty_visitor_name));
     let trait_ref = *tcx.intrinsic_traits.get(&ty_visitor_name);
     (trait_ref,
-     mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs, BoxTraitStore))
+     mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs, BoxTraitStore, ast::m_imm))
 }
 
 // Local Variables:
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index a0c12ff1a20..9f6ab8704cb 100644
--- a/src/librustc/middle/typeck/astconv.rs
+++ b/src/librustc/middle/typeck/astconv.rs
@@ -277,9 +277,9 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + Durable>(
                 }
                 return ty::mk_evec(tcx, mt, vst);
             }
-            ast::ty_path(path, id) if a_seq_ty.mutbl == ast::m_imm => {
+            ast::ty_path(path, id) => {
                 match tcx.def_map.find(&id) {
-                    Some(&ast::def_prim_ty(ast::ty_str)) => {
+                    Some(&ast::def_prim_ty(ast::ty_str)) if a_seq_ty.mutbl == ast::m_imm => {
                         check_path_args(tcx, path, NO_TPS | NO_REGIONS);
                         return ty::mk_estr(tcx, vst);
                     }
@@ -305,7 +305,8 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + Durable>(
                         return ty::mk_trait(tcx,
                                             result.def_id,
                                             copy result.substs,
-                                            trait_store);
+                                            trait_store,
+                                            a_seq_ty.mutbl);
                     }
                     _ => {}
                 }
diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs
index 6b09133e73a..131cef1c7f2 100644
--- a/src/librustc/middle/typeck/check/method.rs
+++ b/src/librustc/middle/typeck/check/method.rs
@@ -291,7 +291,7 @@ pub impl<'self> LookupContext<'self> {
                 ty_param(p) => {
                     self.push_inherent_candidates_from_param(self_ty, p);
                 }
-                ty_trait(did, ref substs, store) => {
+                ty_trait(did, ref substs, store, _) => {
                     self.push_inherent_candidates_from_trait(
                         self_ty, did, substs, store);
                     self.push_inherent_impl_candidates_for_type(did);
diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs
index 5594f2a0f65..dff794c548b 100644
--- a/src/librustc/middle/typeck/check/regionck.rs
+++ b/src/librustc/middle/typeck/check/regionck.rs
@@ -288,7 +288,7 @@ fn visit_expr(expr: @ast::expr, &&rcx: @mut Rcx, v: rvt) {
             // explaining how it goes about doing that.
             let target_ty = rcx.resolve_node_type(expr.id);
             match ty::get(target_ty).sty {
-                ty::ty_trait(_, _, ty::RegionTraitStore(trait_region)) => {
+                ty::ty_trait(_, _, ty::RegionTraitStore(trait_region), _) => {
                     let source_ty = rcx.fcx.expr_ty(source);
                     constrain_regions_in_type(rcx, trait_region,
                                               expr.span, source_ty);
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
index 8245dc88114..cc7519c1db4 100644
--- a/src/librustc/middle/typeck/check/vtable.rs
+++ b/src/librustc/middle/typeck/check/vtable.rs
@@ -141,10 +141,11 @@ fn fixup_substs(vcx: &VtableContext, location_info: &LocationInfo,
     // use a dummy type just to package up the substs that need fixing up
     let t = ty::mk_trait(tcx,
                          id, substs,
-                         ty::RegionTraitStore(ty::re_static));
+                         ty::RegionTraitStore(ty::re_static),
+                         ast::m_imm);
     do fixup_ty(vcx, location_info, t, is_early).map |t_f| {
         match ty::get(*t_f).sty {
-          ty::ty_trait(_, ref substs_f, _) => (/*bad*/copy *substs_f),
+          ty::ty_trait(_, ref substs_f, _, _) => (/*bad*/copy *substs_f),
           _ => fail!(~"t_f should be a trait")
         }
     }
@@ -544,7 +545,12 @@ pub fn early_resolve_expr(ex: @ast::expr,
           debug!("vtable resolution on expr %s", ex.repr(fcx.tcx()));
           let target_ty = fcx.expr_ty(ex);
           match ty::get(target_ty).sty {
-              ty::ty_trait(target_def_id, ref target_substs, store) => {
+              ty::ty_trait(target_def_id, ref target_substs, store, target_mutbl) => {
+                  fn mutability_allowed(a_mutbl: ast::mutability,
+                                        b_mutbl: ast::mutability) -> bool {
+                      a_mutbl == b_mutbl ||
+                      (a_mutbl == ast::m_mutbl && b_mutbl == ast::m_imm)
+                  }
                   // 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,
@@ -554,6 +560,14 @@ pub fn early_resolve_expr(ex: @ast::expr,
                   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,
+                                                  fmt!("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);
diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs
index 247b8eae2a8..2afe674db9c 100644
--- a/src/librustc/middle/typeck/coherence.rs
+++ b/src/librustc/middle/typeck/coherence.rs
@@ -114,7 +114,7 @@ pub fn type_is_defined_in_local_crate(original_type: t) -> bool {
     do ty::walk_ty(original_type) |t| {
         match get(t).sty {
             ty_enum(def_id, _) |
-            ty_trait(def_id, _, _) |
+            ty_trait(def_id, _, _, _) |
             ty_struct(def_id, _) => {
                 if def_id.crate == ast::local_crate {
                     found_nominal = true;
@@ -140,7 +140,7 @@ pub fn get_base_type_def_id(inference_context: @mut InferCtxt,
             match get(base_type).sty {
                 ty_enum(def_id, _) |
                 ty_struct(def_id, _) |
-                ty_trait(def_id, _, _) => {
+                ty_trait(def_id, _, _, _) => {
                     return Some(def_id);
                 }
                 _ => {
diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs
index be1d291cfe5..0bdf2842cca 100644
--- a/src/librustc/middle/typeck/infer/combine.rs
+++ b/src/librustc/middle/typeck/infer/combine.rs
@@ -525,13 +525,13 @@ pub fn super_tys<C:Combine>(
           }
       }
 
-      (ty::ty_trait(a_id, ref a_substs, a_store),
-       ty::ty_trait(b_id, ref b_substs, b_store))
-      if a_id == b_id => {
+      (ty::ty_trait(a_id, ref a_substs, a_store, a_mutbl),
+       ty::ty_trait(b_id, ref b_substs, b_store, b_mutbl))
+      if a_id == b_id && a_mutbl == b_mutbl => {
           let trait_def = ty::lookup_trait_def(tcx, a_id);
           do self.substs(&trait_def.generics, a_substs, b_substs).chain |substs| {
               do self.trait_stores(ty::terr_trait, a_store, b_store).chain |s| {
-                  Ok(ty::mk_trait(tcx, a_id, /*bad*/copy substs, s))
+                  Ok(ty::mk_trait(tcx, a_id, /*bad*/copy substs, s, a_mutbl))
               }
           }
       }
diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs
index 58de0122c8c..3cefe7646de 100644
--- a/src/librustc/middle/typeck/infer/mod.rs
+++ b/src/librustc/middle/typeck/infer/mod.rs
@@ -737,10 +737,11 @@ pub impl InferCtxt {
         let dummy0 = ty::mk_trait(self.tcx,
                                   trait_ref.def_id,
                                   copy trait_ref.substs,
-                                  ty::UniqTraitStore);
+                                  ty::UniqTraitStore,
+                                  ast::m_imm);
         let dummy1 = self.resolve_type_vars_if_possible(dummy0);
         match ty::get(dummy1).sty {
-            ty::ty_trait(ref def_id, ref substs, _) => {
+            ty::ty_trait(ref def_id, ref substs, _, _) => {
                 ty::TraitRef {def_id: *def_id,
                               substs: copy *substs}
             }
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 9b9e0e81b43..c0c6fe2d9d3 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -224,16 +224,20 @@ pub fn region_to_str_space(cx: ctxt, prefix: &str, region: Region) -> ~str {
     }
 }
 
+fn mutability_to_str(m: ast::mutability) -> ~str {
+    match m {
+        ast::m_mutbl => ~"mut ",
+        ast::m_imm => ~"",
+        ast::m_const => ~"const "
+    }
+}
+
 pub fn mt_to_str(cx: ctxt, m: &mt) -> ~str {
     mt_to_str_wrapped(cx, "", m, "")
 }
 
 pub fn mt_to_str_wrapped(cx: ctxt, before: &str, m: &mt, after: &str) -> ~str {
-    let mstr = match m.mutbl {
-      ast::m_mutbl => "mut ",
-      ast::m_imm => "",
-      ast::m_const => "const "
-    };
+    let mstr = mutability_to_str(m.mutbl);
     return fmt!("%s%s%s%s", mstr, before, ty_to_str(cx, m.ty), after);
 }
 
@@ -456,11 +460,11 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
         let base = ast_map::path_to_str(path, cx.sess.intr());
         parameterized(cx, base, substs.self_r, substs.tps)
       }
-      ty_trait(did, ref substs, s) => {
+      ty_trait(did, ref substs, s, mutbl) => {
         let path = ty::item_path(cx, did);
         let base = ast_map::path_to_str(path, cx.sess.intr());
         let ty = parameterized(cx, base, substs.self_r, substs.tps);
-        fmt!("%s%s", trait_store_to_str(cx, s), ty)
+        fmt!("%s%s%s", trait_store_to_str(cx, s), mutability_to_str(mutbl), ty)
       }
       ty_evec(ref mt, vs) => {
         vstore_ty_to_str(cx, mt, vs)
diff --git a/src/test/compile-fail/cast-immutable-mutable-trait.rs b/src/test/compile-fail/cast-immutable-mutable-trait.rs
new file mode 100644
index 00000000000..1047a995771
--- /dev/null
+++ b/src/test/compile-fail/cast-immutable-mutable-trait.rs
@@ -0,0 +1,28 @@
+// 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.
+
+trait T {
+    fn foo(@mut self);
+}
+
+struct S {
+    unused: int
+}
+
+impl T for S {
+    fn foo(@mut self) {
+    }
+}
+
+fn main() {
+    let s = @S { unused: 0 };
+    let _s2 = s as @mut T; //~ error: types differ in mutability
+    let _s3 = &s as &mut T; //~ error: types differ in mutability
+}
\ No newline at end of file
diff --git a/src/test/run-pass/cast-mutable-trait.rs b/src/test/run-pass/cast-mutable-trait.rs
new file mode 100644
index 00000000000..633188b9a62
--- /dev/null
+++ b/src/test/run-pass/cast-mutable-trait.rs
@@ -0,0 +1,34 @@
+// 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.
+
+trait T {
+    fn foo(@mut self);
+}
+
+struct S {
+    unused: int
+}
+
+impl T for S {
+    fn foo(@mut self) {
+    }
+}
+
+fn bar(t: @mut T) {
+    t.foo();
+}
+
+fn main() {
+    let s = @mut S { unused: 0 };
+    let s2 = s as @mut T;
+    s2.foo();
+    bar(s2);
+    bar(s as @mut T);
+}
\ No newline at end of file