diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 6d865d2bffa8a..808830d464831 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -241,7 +241,7 @@ pub trait BoxAny { /// Returns the boxed value if it is of type `T`, or /// `Err(Self)` if it isn't. #[stable(feature = "rust1", since = "1.0.0")] - fn downcast(self) -> Result, Self>; + fn downcast(self) -> Result, Box>; } #[stable(feature = "rust1", since = "1.0.0")] @@ -264,6 +264,15 @@ impl BoxAny for Box { } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl BoxAny for Box { + #[inline] + fn downcast(self) -> Result, Box> { + >::downcast(self) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Box { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 462b6771b4a9a..6d3fac4c68d34 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -71,6 +71,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use marker::Send; use mem::transmute; use option::Option::{self, Some, None}; use raw::TraitObject; @@ -154,6 +155,31 @@ impl Any { } } +#[cfg(not(stage0))] +impl Any+Send { + /// Forwards to the method defined on the type `Any`. + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is(&self) -> bool { + Any::is::(self) + } + + /// Forwards to the method defined on the type `Any`. + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn downcast_ref(&self) -> Option<&T> { + Any::downcast_ref::(self) + } + + /// Forwards to the method defined on the type `Any`. + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn downcast_mut(&mut self) -> Option<&mut T> { + Any::downcast_mut::(self) + } +} + + /////////////////////////////////////////////////////////////////////////////// // TypeID and its methods /////////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index ed1d876d83619..f705cc8ed99fe 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1102,6 +1102,11 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { this.emit_enum_variant_arg(1, |this| Ok(this.emit_ty(ecx, self_ty))) }) } + ty::UnsizeUpcast(target_ty) => { + this.emit_enum_variant("UnsizeUpcast", 3, 1, |this| { + this.emit_enum_variant_arg(0, |this| Ok(this.emit_ty(ecx, target_ty))) + }) + } } }); } @@ -1707,7 +1712,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { fn read_unsize_kind<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> ty::UnsizeKind<'tcx> { self.read_enum("UnsizeKind", |this| { - let variants = &["UnsizeLength", "UnsizeStruct", "UnsizeVtable"]; + let variants = &["UnsizeLength", "UnsizeStruct", "UnsizeVtable", "UnsizeUpcast"]; this.read_enum_variant(variants, |this, i| { Ok(match i { 0 => { @@ -1741,6 +1746,11 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { this.read_enum_variant_arg(1, |this| Ok(this.read_ty(dcx))).unwrap(); ty::UnsizeVtable(ty_trait, self_ty) } + 3 => { + let target_ty = + this.read_enum_variant_arg(0, |this| Ok(this.read_ty(dcx))).unwrap(); + ty::UnsizeUpcast(target_ty) + } _ => panic!("bad enum variant for ty::UnsizeKind") }) }) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index a1e38a1c8bda7..c0d51f5675ca2 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -857,28 +857,13 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { n: uint) { debug!("walk_autoref expr={}", expr.repr(self.tcx())); - // Match for unique trait coercions first, since we don't need the - // call to cat_expr_autoderefd. - match *autoref { - ty::AutoUnsizeUniq(ty::UnsizeVtable(..)) | - ty::AutoUnsize(ty::UnsizeVtable(..)) => { - assert!(n == 1, format!("Expected exactly 1 deref with Uniq \ - AutoRefs, found: {}", n)); - let cmt_unadjusted = - return_if_err!(self.mc.cat_expr_unadjusted(expr)); - self.delegate_consume(expr.id, expr.span, cmt_unadjusted); - return; - } - _ => {} - } - - let cmt_derefd = return_if_err!( - self.mc.cat_expr_autoderefd(expr, n)); - debug!("walk_adjustment: cmt_derefd={}", - cmt_derefd.repr(self.tcx())); - match *autoref { ty::AutoPtr(r, m, _) => { + let cmt_derefd = return_if_err!( + self.mc.cat_expr_autoderefd(expr, n)); + debug!("walk_adjustment: cmt_derefd={}", + cmt_derefd.repr(self.tcx())); + self.delegate.borrow(expr.id, expr.span, cmt_derefd, @@ -886,7 +871,16 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { ty::BorrowKind::from_mutbl(m), AutoRef); } - ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) | ty::AutoUnsafe(..) => {} + ty::AutoUnsize(_) | + ty::AutoUnsizeUniq(_) => { + assert!(n == 1, format!("Expected exactly 1 deref with Uniq \ + AutoRefs, found: {}", n)); + let cmt_unadjusted = + return_if_err!(self.mc.cat_expr_unadjusted(expr)); + self.delegate_consume(expr.id, expr.span, cmt_unadjusted); + } + ty::AutoUnsafe(..) => { + } } } diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 9add236d54b18..438b61f918a1e 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -314,9 +314,18 @@ pub trait Combine<'tcx> : Sized { } fn builtin_bounds(&self, - a: ty::BuiltinBounds, - b: ty::BuiltinBounds) - -> cres<'tcx, ty::BuiltinBounds>; + a: BuiltinBounds, + b: BuiltinBounds) + -> cres<'tcx, BuiltinBounds> + { + // Two sets of builtin bounds are only relatable if they are + // precisely the same (but see the coercion code). + if a != b { + Err(ty::terr_builtin_bounds(expected_found(self, a, b))) + } else { + Ok(a) + } + } fn trait_refs(&self, a: &ty::TraitRef<'tcx>, diff --git a/src/librustc/middle/infer/equate.rs b/src/librustc/middle/infer/equate.rs index 7194e20b0cf65..2f9f8532b6c52 100644 --- a/src/librustc/middle/infer/equate.rs +++ b/src/librustc/middle/infer/equate.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::ty::{BuiltinBounds}; use middle::ty::{self, Ty}; use middle::ty::TyVar; use middle::infer::combine::*; @@ -73,23 +72,6 @@ impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> { } } - fn builtin_bounds(&self, - a: BuiltinBounds, - b: BuiltinBounds) - -> cres<'tcx, BuiltinBounds> - { - // More bounds is a subtype of fewer bounds. - // - // e.g., fn:Copy() <: fn(), because the former is a function - // that only closes over copyable things, but the latter is - // any function at all. - if a != b { - Err(ty::terr_builtin_bounds(expected_found(self, a, b))) - } else { - Ok(a) - } - } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { debug!("{}.tys({}, {})", self.tag(), a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx)); diff --git a/src/librustc/middle/infer/glb.rs b/src/librustc/middle/infer/glb.rs index 33303808e8491..ba073999ed127 100644 --- a/src/librustc/middle/infer/glb.rs +++ b/src/librustc/middle/infer/glb.rs @@ -14,7 +14,6 @@ use super::higher_ranked::HigherRankedRelations; use super::{cres}; use super::Subtype; -use middle::ty::{BuiltinBounds}; use middle::ty::{self, Ty}; use syntax::ast::{MutImmutable, MutMutable, Unsafety}; use util::ppaux::mt_to_string; @@ -94,15 +93,6 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> { } } - fn builtin_bounds(&self, - a: ty::BuiltinBounds, - b: ty::BuiltinBounds) - -> cres<'tcx, ty::BuiltinBounds> { - // More bounds is a subtype of fewer bounds, so - // the GLB (mutual subtype) is the union. - Ok(a.union(b)) - } - fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> { debug!("{}.regions({}, {})", self.tag(), diff --git a/src/librustc/middle/infer/lub.rs b/src/librustc/middle/infer/lub.rs index 3570effa9fa70..37eace0b15b6d 100644 --- a/src/librustc/middle/infer/lub.rs +++ b/src/librustc/middle/infer/lub.rs @@ -14,7 +14,6 @@ use super::lattice::*; use super::{cres}; use super::{Subtype}; -use middle::ty::{BuiltinBounds}; use middle::ty::{self, Ty}; use syntax::ast::{MutMutable, MutImmutable, Unsafety}; use util::ppaux::mt_to_string; @@ -89,15 +88,6 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> { } } - fn builtin_bounds(&self, - a: ty::BuiltinBounds, - b: ty::BuiltinBounds) - -> cres<'tcx, ty::BuiltinBounds> { - // More bounds is a subtype of fewer bounds, so - // the LUB (mutual supertype) is the intersection. - Ok(a.intersection(b)) - } - fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> { debug!("{}.regions({}, {})", self.tag(), diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs index 33da3092b2a25..5a141d52f628d 100644 --- a/src/librustc/middle/infer/sub.rs +++ b/src/librustc/middle/infer/sub.rs @@ -14,7 +14,6 @@ use super::higher_ranked::HigherRankedRelations; use super::{Subtype}; use super::type_variable::{SubtypeOf, SupertypeOf}; -use middle::ty::{BuiltinBounds}; use middle::ty::{self, Ty}; use middle::ty::TyVar; use util::ppaux::{Repr}; @@ -97,20 +96,6 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { }) } - fn builtin_bounds(&self, a: BuiltinBounds, b: BuiltinBounds) - -> cres<'tcx, BuiltinBounds> { - // More bounds is a subtype of fewer bounds. - // - // e.g., fn:Copy() <: fn(), because the former is a function - // that only closes over copyable things, but the latter is - // any function at all. - if a.is_superset(&b) { - Ok(a) - } else { - Err(ty::terr_builtin_bounds(expected_found(self, a, b))) - } - } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { debug!("{}.tys({}, {})", self.tag(), a.repr(self.tcx()), b.repr(self.tcx())); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 8705e56b09425..90a488f1b8622 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -292,7 +292,8 @@ pub enum UnsizeKind<'tcx> { // An unsize coercion applied to the tail field of a struct. // The uint is the index of the type parameter which is unsized. UnsizeStruct(Box>, uint), - UnsizeVtable(TyTrait<'tcx>, /* the self type of the trait */ Ty<'tcx>) + UnsizeVtable(TyTrait<'tcx>, /* the self type of the trait */ Ty<'tcx>), + UnsizeUpcast(Ty<'tcx>), } #[derive(Clone, Debug)] @@ -4627,6 +4628,9 @@ pub fn unsize_ty<'tcx>(cx: &ctxt<'tcx>, &UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => { mk_trait(cx, principal.clone(), bounds.clone()) } + &UnsizeUpcast(target_ty) => { + target_ty + } } } @@ -6830,6 +6834,7 @@ impl<'tcx> Repr<'tcx> for UnsizeKind<'tcx> { UnsizeLength(n) => format!("UnsizeLength({})", n), UnsizeStruct(ref k, n) => format!("UnsizeStruct({},{})", k.repr(tcx), n), UnsizeVtable(ref a, ref b) => format!("UnsizeVtable({},{})", a.repr(tcx), b.repr(tcx)), + UnsizeUpcast(ref a) => format!("UnsizeUpcast({})", a.repr(tcx)), } } } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index f3a7c1ee6a0c8..f17ba78007bb2 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -480,6 +480,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::UnsizeKind<'tcx> { }, self_ty.fold_with(folder)) } + ty::UnsizeUpcast(t) => ty::UnsizeUpcast(t.fold_with(folder)), } } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 3a0b5832c9f5b..e9b0291704042 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1214,17 +1214,17 @@ impl<'tcx> Repr<'tcx> for ty::ExistentialBounds<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { let mut res = Vec::new(); - let region_str = self.region_bound.user_string(tcx); + let region_str = self.region_bound.repr(tcx); if !region_str.is_empty() { res.push(region_str); } for bound in &self.builtin_bounds { - res.push(bound.user_string(tcx)); + res.push(bound.repr(tcx)); } for projection_bound in &self.projection_bounds { - res.push(projection_bound.user_string(tcx)); + res.push(projection_bound.repr(tcx)); } res.connect("+") diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 8dcabe0a94bb8..6ff230b7065da 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -311,12 +311,16 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, llconst = addr_of(cx, llconst, "autoref", e.id); } Some(box ty::AutoUnsize(ref k)) => { - let info = expr::unsized_info(cx, k, e.id, ty, param_substs, - |t| ty::mk_imm_rptr(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), t)); + let info = + expr::unsized_info( + cx, k, e.id, ty, param_substs, + |t| ty::mk_imm_rptr(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), t), + || const_get_elt(cx, llconst, &[abi::FAT_PTR_EXTRA as u32])); let unsized_ty = ty::unsize_ty(cx.tcx(), ty, k, e.span); let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to(); let base = ptrcast(llconst, ptr_ty); + let prev_const = cx.const_unsized().borrow_mut() .insert(base, llconst); assert!(prev_const.is_none() || prev_const == Some(llconst)); diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index ecdc7c06bb19d..da2b5a43b48cc 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -287,18 +287,50 @@ pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef { // Retrieve the information we are losing (making dynamic) in an unsizing // adjustment. +// // When making a dtor, we need to do different things depending on the // ownership of the object.. mk_ty is a function for turning `unadjusted_ty` // into a type to be destructed. If we want to end up with a Box pointer, // then mk_ty should make a Box pointer (T -> Box), if we want a // borrowed reference then it should be T -> &T. -pub fn unsized_info<'a, 'tcx, F>(ccx: &CrateContext<'a, 'tcx>, - kind: &ty::UnsizeKind<'tcx>, - id: ast::NodeId, - unadjusted_ty: Ty<'tcx>, - param_substs: &'tcx subst::Substs<'tcx>, - mk_ty: F) -> ValueRef where - F: FnOnce(Ty<'tcx>) -> Ty<'tcx>, +// +// The `unadjusted_val` argument is a bit funny. It is intended +// for use in an upcast, where the new vtable for an object will +// be drived from the old one. Hence it is a pointer to the fat +// pointer. +pub fn unsized_info_bcx<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, + kind: &ty::UnsizeKind<'tcx>, + id: ast::NodeId, + unadjusted_ty: Ty<'tcx>, + unadjusted_val: ValueRef, // see above (*) + param_substs: &'tcx subst::Substs<'tcx>, + mk_ty: F) + -> ValueRef + where F: FnOnce(Ty<'tcx>) -> Ty<'tcx> +{ + unsized_info( + bcx.ccx(), + kind, + id, + unadjusted_ty, + param_substs, + mk_ty, + || Load(bcx, GEPi(bcx, unadjusted_val, &[0, abi::FAT_PTR_EXTRA]))) +} + +// Same as `unsize_info_bcx`, but does not require a bcx -- instead it +// takes an extra closure to compute the upcast vtable. +pub fn unsized_info<'ccx, 'tcx, MK_TY, MK_UPCAST_VTABLE>( + ccx: &CrateContext<'ccx, 'tcx>, + kind: &ty::UnsizeKind<'tcx>, + id: ast::NodeId, + unadjusted_ty: Ty<'tcx>, + param_substs: &'tcx subst::Substs<'tcx>, + mk_ty: MK_TY, + mk_upcast_vtable: MK_UPCAST_VTABLE) // see notes above + -> ValueRef + where MK_TY: FnOnce(Ty<'tcx>) -> Ty<'tcx>, + MK_UPCAST_VTABLE: FnOnce() -> ValueRef, { // FIXME(#19596) workaround: `|t| t` causes monomorphization recursion fn identity(t: T) -> T { t } @@ -312,7 +344,8 @@ pub fn unsized_info<'a, 'tcx, F>(ccx: &CrateContext<'a, 'tcx>, let ty_substs = substs.types.get_slice(subst::TypeSpace); // The dtor for a field treats it like a value, so mk_ty // should just be the identity function. - unsized_info(ccx, k, id, ty_substs[tp_index], param_substs, identity) + unsized_info(ccx, k, id, ty_substs[tp_index], param_substs, + identity, mk_upcast_vtable) } _ => ccx.sess().bug(&format!("UnsizeStruct with bad sty: {}", unadjusted_ty.repr(ccx.tcx()))) @@ -330,6 +363,12 @@ pub fn unsized_info<'a, 'tcx, F>(ccx: &CrateContext<'a, 'tcx>, consts::ptrcast(meth::get_vtable(ccx, box_ty, trait_ref, param_substs), Type::vtable_ptr(ccx)) } + &ty::UnsizeUpcast(_) => { + // For now, upcasts are limited to changes in marker + // traits, and hence never actually require an actual + // change to the vtable. + mk_upcast_vtable() + } } } @@ -338,7 +377,8 @@ pub fn unsized_info<'a, 'tcx, F>(ccx: &CrateContext<'a, 'tcx>, fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr, datum: Datum<'tcx, Expr>) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'blk, 'tcx, Expr> +{ let mut bcx = bcx; let mut datum = datum; let adjustment = match bcx.tcx().adjustments.borrow().get(&expr.id).cloned() { @@ -347,10 +387,10 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } Some(adj) => { adj } }; - debug!("unadjusted datum for expr {}: {}, adjustment={}", + debug!("unadjusted datum for expr {}: {} adjustment={:?}", expr.repr(bcx.tcx()), datum.to_string(bcx.ccx()), - adjustment.repr(bcx.tcx())); + adjustment); match adjustment { AdjustReifyFnPointer(_def_id) => { // FIXME(#19925) once fn item types are @@ -434,7 +474,6 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debug!(" AutoUnsize"); unpack_datum!(bcx, unsize_expr(bcx, expr, datum, k)) } - &ty::AutoUnsizeUniq(ty::UnsizeLength(len)) => { debug!(" AutoUnsizeUniq(UnsizeLength)"); unpack_datum!(bcx, unsize_unique_vec(bcx, expr, datum, len)) @@ -459,16 +498,27 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let unsized_ty = ty::unsize_ty(tcx, datum_ty, k, expr.span); debug!("unsized_ty={}", unsized_ty.repr(bcx.tcx())); - let info = unsized_info(bcx.ccx(), k, expr.id, datum_ty, bcx.fcx.param_substs, - |t| ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), t)); + let info = unsized_info_bcx(bcx, k, expr.id, datum_ty, datum.val, bcx.fcx.param_substs, + |t| ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), t)); // Arrange cleanup - let lval = unpack_datum!(bcx, - datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id)); + let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id)); + // Compute the base pointer. This doesn't change the pointer value, // but merely its type. let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), unsized_ty).ptr_to(); - let base = PointerCast(bcx, lval.val, ptr_ty); + let base = if !type_is_sized(bcx.tcx(), lval.ty) { + // Normally, the source is a thin pointer and we are + // adding extra info to make a fat pointer. The exception + // is when we are upcasting an existing object fat pointer + // to use a different vtable. In that case, we want to + // load out the original data pointer so we can repackage + // it. + Load(bcx, get_dataptr(bcx, lval.val)) + } else { + lval.val + }; + let base = PointerCast(bcx, base, ptr_ty); let llty = type_of::type_of(bcx.ccx(), unsized_ty); // HACK(eddyb) get around issues with lifetime intrinsics. @@ -540,8 +590,8 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let base = PointerCast(bcx, get_dataptr(bcx, scratch.val), llbox_ty.ptr_to()); bcx = datum.store_to(bcx, base); - let info = unsized_info(bcx.ccx(), k, expr.id, unboxed_ty, bcx.fcx.param_substs, - |t| ty::mk_uniq(tcx, t)); + let info = unsized_info_bcx(bcx, k, expr.id, unboxed_ty, base, bcx.fcx.param_substs, + |t| ty::mk_uniq(tcx, t)); Store(bcx, info, get_len(bcx, scratch.val)); DatumBlock::new(bcx, scratch.to_expr_datum()) @@ -1373,8 +1423,7 @@ pub fn with_field_tys<'tcx, R, F>(tcx: &ty::ctxt<'tcx>, let def = tcx.def_map.borrow()[node_id].full_def(); match def { def::DefVariant(enum_id, variant_id, _) => { - let variant_info = ty::enum_variant_with_id( - tcx, enum_id, variant_id); + let variant_info = ty::enum_variant_with_id(tcx, enum_id, variant_id); let fields = struct_fields(tcx, variant_id, substs); let fields = monomorphize::normalize_associated_type(tcx, &fields); op(variant_info.disr_val, &fields[..]) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 04a3f423dce11..4e42ec61011ba 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -334,15 +334,33 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let ty = ty::mk_vec(tcx, t_a, None); Some((ty, ty::UnsizeLength(len))) } - (&ty::ty_trait(..), &ty::ty_trait(..)) => { - None + (&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => { + // For now, we only support upcasts from + // `Foo+Send` to `Foo` (really, any time there are + // fewer builtin bounds then before). These are + // convenient because they don't require any sort + // of change to the vtable at runtime. + if data_a.bounds.builtin_bounds != data_b.bounds.builtin_bounds && + data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) + { + let bounds_a1 = ty::ExistentialBounds { + region_bound: data_a.bounds.region_bound, + builtin_bounds: data_b.bounds.builtin_bounds, + projection_bounds: data_a.bounds.projection_bounds.clone(), + }; + let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1); + match self.fcx.infcx().try(|_| self.subtype(ty_a1, ty_b)) { + Ok(_) => Some((ty_b, ty::UnsizeUpcast(ty_b))), + Err(_) => None, + } + } else { + None + } } - (_, &ty::ty_trait(box ty::TyTrait { ref principal, ref bounds })) => { - // FIXME what is the purpose of `ty`? - let ty = ty::mk_trait(tcx, principal.clone(), bounds.clone()); - Some((ty, ty::UnsizeVtable(ty::TyTrait { principal: principal.clone(), - bounds: bounds.clone() }, - ty_a))) + (_, &ty::ty_trait(ref data)) => { + Some((ty_b, ty::UnsizeVtable(ty::TyTrait { principal: data.principal.clone(), + bounds: data.bounds.clone() }, + ty_a))) } (&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b)) if did_a == did_b => { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 6ef6953f707fb..6aefcf5a47cc6 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -176,13 +176,13 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { probe::AutoDeref(num) => { ty::AutoDerefRef { autoderefs: num, - autoref: None + autoref: None, } } probe::AutoUnsizeLength(autoderefs, len) => { ty::AutoDerefRef { autoderefs: autoderefs, - autoref: Some(ty::AutoUnsize(ty::UnsizeLength(len))) + autoref: Some(ty::AutoUnsize(ty::UnsizeLength(len))), } } probe::AutoRef(mutability, ref sub_adjustment) => { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 718804d317fb0..302bcfc060278 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -857,7 +857,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { return self.pick_method(step.self_ty).map(|r| self.adjust(r, adjustment.clone())); - fn consider_reborrow(ty: Ty, d: uint) -> PickAdjustment { + fn consider_reborrow<'tcx>(ty: Ty<'tcx>, d: uint) -> PickAdjustment { // Insert a `&*` or `&mut *` if this is a reference type: match ty.sty { ty::ty_rptr(_, ref mt) => AutoRef(mt.mutbl, box AutoDeref(d+1)), @@ -902,7 +902,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn adjust(&mut self, result: PickResult<'tcx>, adjustment: PickAdjustment) - -> PickResult<'tcx> { + -> PickResult<'tcx> + { match result { Err(e) => Err(e), Ok(mut pick) => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 41951ab2b6200..31bee612b78d4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1592,6 +1592,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { code: traits::ObjectCastObligation(self_ty) }; self.register_region_obligation(self_ty, ty_trait.bounds.region_bound, cause); } + ty::UnsizeUpcast(_) => { } } } diff --git a/src/test/compile-fail/borrowck-consume-unsize-vec.rs b/src/test/compile-fail/borrowck-consume-unsize-vec.rs new file mode 100644 index 0000000000000..32490e0dc7de2 --- /dev/null +++ b/src/test/compile-fail/borrowck-consume-unsize-vec.rs @@ -0,0 +1,22 @@ +// Copyright 2015 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. + +// Check that we report an error if an upcast box is moved twice. + +fn consume(_: Box<[i32]>) { +} + +fn foo(b: Box<[i32;5]>) { + consume(b); + consume(b); //~ ERROR use of moved value +} + +fn main() { +} diff --git a/src/test/compile-fail/borrowck-consume-upcast-box.rs b/src/test/compile-fail/borrowck-consume-upcast-box.rs new file mode 100644 index 0000000000000..5bcafa675c7cb --- /dev/null +++ b/src/test/compile-fail/borrowck-consume-upcast-box.rs @@ -0,0 +1,24 @@ +// Copyright 2015 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. + +// Check that we report an error if an upcast box is moved twice. + +trait Foo { fn dummy(&self); } + +fn consume(_: Box) { +} + +fn foo(b: Box) { + consume(b); + consume(b); //~ ERROR use of moved value +} + +fn main() { +} diff --git a/src/test/compile-fail/retslot-cast.rs b/src/test/compile-fail/retslot-cast.rs index fafae0cb705a8..4ef07ecb4382f 100644 --- a/src/test/compile-fail/retslot-cast.rs +++ b/src/test/compile-fail/retslot-cast.rs @@ -12,9 +12,15 @@ #![allow(warnings)] pub fn fail(x: Option<& (Iterator+Send)>) -> Option<&Iterator> { - // This call used to trigger an LLVM assertion because the return slot had type - // "Option<&Iterator>"* instead of "Option<&(Iterator+Send)>"* - inner(x) + // This call used to trigger an LLVM assertion because the return + // slot had type "Option<&Iterator>"* instead of + // "Option<&(Iterator+Send)>"* -- but this now yields a + // compilation error and I'm not sure how to create a comparable + // test. To ensure that this PARTICULAR failure doesn't occur + // again, though, I've left this test here, so if this ever starts + // to compile again, we can adjust the test appropriately (clearly + // it should never ICE...). -nmatsakis + inner(x) //~ ERROR mismatched types } pub fn inner(x: Option<& (Iterator+Send)>) -> Option<&(Iterator+Send)> { @@ -22,4 +28,4 @@ pub fn inner(x: Option<& (Iterator+Send)>) -> Option<&(Iterator+Send)> { } #[rustc_error] -fn main() {} //~ ERROR compilation successful +fn main() {}