Remove subtyping for object types and replace with an *upcast* coercion.
This upcast coercion currently preserves the vtable for the object, but eventually it can be used to create a derived vtable. The upcast coercion is not introduced into method dispatch; see comment on #18737 for information about why. Fixes #18737.
This commit is contained in:
parent
bde09eea35
commit
5f5ed62298
18 changed files with 187 additions and 101 deletions
|
@ -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<T: 'static>(self) -> Result<Box<T>, Self>;
|
||||
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>>;
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -264,6 +264,15 @@ impl BoxAny for Box<Any> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl BoxAny for Box<Any+Send> {
|
||||
#[inline]
|
||||
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
|
||||
<Box<Any>>::downcast(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: fmt::Display + ?Sized> fmt::Display for Box<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
|
|
@ -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<T: 'static>(&self) -> bool {
|
||||
Any::is::<T>(self)
|
||||
}
|
||||
|
||||
/// Forwards to the method defined on the type `Any`.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
|
||||
Any::downcast_ref::<T>(self)
|
||||
}
|
||||
|
||||
/// Forwards to the method defined on the type `Any`.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
|
||||
Any::downcast_mut::<T>(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TypeID and its methods
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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")
|
||||
})
|
||||
})
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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<UnsizeKind<'tcx>>, 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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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("+")
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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<T>), 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 { 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[..])
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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(_) => { }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {}
|
||||
|
|
Loading…
Reference in a new issue