提交 97303703 编写于 作者: J Josh Matthews

Allow casting to mutable trait objects.

上级 07e087bf
......@@ -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 }
}
......
......@@ -22,6 +22,7 @@
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 @@ fn estimate_sz(u: uint) -> uint {
}
}
}
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) => {
......
......@@ -589,7 +589,7 @@ fn is_subregion_of(cx: Context, r_sub: ty::Region, r_sup: ty::Region) -> bool {
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(
......
......@@ -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) => {
......
......@@ -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);
}
......
......@@ -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,
......
......@@ -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,
......
......@@ -323,7 +323,7 @@ fn visit_ty(&mut self, t: ty::t) {
}
// 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) => {
......
......@@ -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);
......
......@@ -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() {
......
......@@ -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 sflags(substs: &substs) -> uint {
&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_substs(substs: &substs, fldop: &fn(t) -> t) -> substs {
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 @@ fn fold_substs(
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 @@ fn tc_ty(cx: ctxt,
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 @@ fn subtypes_require(cx: ctxt, seen: &mut ~[def_id],
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 @@ fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
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:
......
......@@ -277,9 +277,9 @@ fn mk_pointer<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 @@ fn mk_pointer<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);
}
_ => {}
}
......
......@@ -291,7 +291,7 @@ fn push_inherent_candidates(&self, self_ty: ty::t) {
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);
......
......@@ -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);
......
......@@ -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(*)) => {
......
......@@ -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);
}
_ => {
......
......@@ -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))
}
}
}
......
......@@ -737,10 +737,11 @@ fn resolve_type_vars_in_trait_ref_if_possible(@mut self,
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}
}
......
......@@ -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 @@ fn field_to_str(cx: ctxt, f: field) -> ~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)
......
// 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
// 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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册