Skip to content

Commit

Permalink
Remove subtyping for object types and replace with an *upcast* coercion.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nikomatsakis committed Mar 17, 2015
1 parent bde09ee commit 5f5ed62
Show file tree
Hide file tree
Showing 18 changed files with 187 additions and 101 deletions.
11 changes: 10 additions & 1 deletion src/liballoc/boxed.rs
Expand Up @@ -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")]
Expand All @@ -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 {
Expand Down
26 changes: 26 additions & 0 deletions src/libcore/any.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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
///////////////////////////////////////////////////////////////////////////////
Expand Down
12 changes: 11 additions & 1 deletion src/librustc/middle/astencode.rs
Expand Up @@ -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)))
})
}
}
});
}
Expand Down Expand Up @@ -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 => {
Expand Down Expand Up @@ -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")
})
})
Expand Down
15 changes: 12 additions & 3 deletions src/librustc/middle/infer/combine.rs
Expand Up @@ -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>,
Expand Down
18 changes: 0 additions & 18 deletions src/librustc/middle/infer/equate.rs
Expand Up @@ -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::*;
Expand Down Expand Up @@ -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));
Expand Down
10 changes: 0 additions & 10 deletions src/librustc/middle/infer/glb.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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(),
Expand Down
10 changes: 0 additions & 10 deletions src/librustc/middle/infer/lub.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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(),
Expand Down
15 changes: 0 additions & 15 deletions src/librustc/middle/infer/sub.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -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()));
Expand Down
7 changes: 6 additions & 1 deletion src/librustc/middle/ty.rs
Expand Up @@ -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)]
Expand Down Expand Up @@ -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
}
}
}

Expand Down Expand Up @@ -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)),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/ty_fold.rs
Expand Up @@ -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)),
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/util/ppaux.rs
Expand Up @@ -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("+")
Expand Down
8 changes: 6 additions & 2 deletions src/librustc_trans/trans/consts.rs
Expand Up @@ -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));
Expand Down

0 comments on commit 5f5ed62

Please sign in to comment.