From 97303703eec8e80003b4ffe729ad4df3ded1445c Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Tue, 2 Apr 2013 03:40:57 -0400 Subject: [PATCH] Allow casting to mutable trait objects. --- src/librustc/metadata/tydecode.rs | 16 ++++--- src/librustc/metadata/tyencode.rs | 13 ++++-- src/librustc/middle/kind.rs | 2 +- src/librustc/middle/trans/debuginfo.rs | 2 +- src/librustc/middle/trans/expr.rs | 2 +- src/librustc/middle/trans/glue.rs | 8 ++-- src/librustc/middle/trans/monomorphize.rs | 2 +- src/librustc/middle/trans/reflect.rs | 2 +- src/librustc/middle/trans/type_of.rs | 4 +- src/librustc/middle/trans/type_use.rs | 2 +- src/librustc/middle/ty.rs | 46 ++++++++++--------- src/librustc/middle/typeck/astconv.rs | 7 +-- src/librustc/middle/typeck/check/method.rs | 2 +- src/librustc/middle/typeck/check/regionck.rs | 2 +- src/librustc/middle/typeck/check/vtable.rs | 20 ++++++-- src/librustc/middle/typeck/coherence.rs | 4 +- src/librustc/middle/typeck/infer/combine.rs | 8 ++-- src/librustc/middle/typeck/infer/mod.rs | 5 +- src/librustc/util/ppaux.rs | 18 +++++--- .../cast-immutable-mutable-trait.rs | 28 +++++++++++ src/test/run-pass/cast-mutable-trait.rs | 34 ++++++++++++++ 21 files changed, 162 insertions(+), 65 deletions(-) create mode 100644 src/test/compile-fail/cast-immutable-mutable-trait.rs create mode 100644 src/test/run-pass/cast-mutable-trait.rs diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index f52ff056472f9..41ebf14a9a8bc 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 2e1dd8b6dad86..a9a07d1b41d9d 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 e5fc9f2d60391..59ae4812f2778 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 c02417aca8b12..c10086aa56c92 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 d4a1013e83c85..e75e49f18f380 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 827f4afaf783c..51d4622d6a163 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 97dc3fed780f0..7aab6367d405a 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 596c55a68f872..e62e19f636a4e 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 1c94fe2842219..b9e4bad42dd43 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 572e9348f63f0..25e3ed0f400a8 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 f62e366ebdcaa..4212b03c41653 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) -> 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 { 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 a0c12ff1a204c..9f6ab8704cbd6 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( } 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( 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 6b09133e73a11..131cef1c7f2f0 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 5594f2a0f658b..dff794c548bd5 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 8245dc88114c8..cc7519c1db4ed 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, @@ -552,6 +558,14 @@ pub fn early_resolve_expr(ex: @ast::expr, 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, + fmt!("types differ in mutability")); + } + (&ty::ty_box(mt), ty::BoxTraitStore) | (&ty::ty_uniq(mt), ty::UniqTraitStore) | (&ty::ty_rptr(_, mt), ty::RegionTraitStore(*)) => { diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 247b8eae2a8db..2afe674db9c55 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 be1d291cfe5c9..0bdf2842ccac3 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( } } - (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 58de0122c8c9b..3cefe7646def2 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 9b9e0e81b4346..c0c6fe2d9d323 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 0000000000000..1047a99577143 --- /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 or the MIT license +// , 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 0000000000000..633188b9a623b --- /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 or the MIT license +// , 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