Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reflect trait #23712

Merged
merged 5 commits into from
Mar 28, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/liballoc/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,13 +244,13 @@ 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>, Box<Any>>;
fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>>;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl BoxAny for Box<Any> {
#[inline]
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
if self.is::<T>() {
unsafe {
// Get the raw representation of the trait object
Expand All @@ -270,7 +270,7 @@ impl BoxAny for Box<Any> {
#[stable(feature = "rust1", since = "1.0.0")]
impl BoxAny for Box<Any+Send> {
#[inline]
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
<Box<Any>>::downcast(self)
}
}
Expand Down
24 changes: 13 additions & 11 deletions src/libcore/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
//! }
//!
//! // This function wants to log its parameter out prior to doing work with it.
//! fn do_work<T: Debug + 'static>(value: &T) {
//! fn do_work<T: Any + Debug>(value: &T) {
//! log(value);
//! // ...do some other work
//! }
Expand All @@ -76,7 +76,7 @@ use mem::transmute;
use option::Option::{self, Some, None};
use raw::TraitObject;
use intrinsics;
use marker::Sized;
use marker::{Reflect, Sized};

///////////////////////////////////////////////////////////////////////////////
// Any trait
Expand All @@ -88,14 +88,16 @@ use marker::Sized;
///
/// [mod]: ../index.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Any: 'static {
pub trait Any: Reflect + 'static {
/// Get the `TypeId` of `self`
#[unstable(feature = "core",
reason = "this method will likely be replaced by an associated static")]
fn get_type_id(&self) -> TypeId;
}

impl<T: 'static> Any for T {
impl<T> Any for T
where T: Reflect + 'static
{
fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
}

Expand All @@ -107,7 +109,7 @@ impl Any {
/// Returns true if the boxed type is the same as `T`
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is<T: 'static>(&self) -> bool {
pub fn is<T: Any>(&self) -> bool {
// Get TypeId of the type this function is instantiated with
let t = TypeId::of::<T>();

Expand All @@ -122,7 +124,7 @@ impl Any {
/// `None` if it isn't.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
if self.is::<T>() {
unsafe {
// Get the raw representation of the trait object
Expand All @@ -140,7 +142,7 @@ impl Any {
/// `None` if it isn't.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
if self.is::<T>() {
unsafe {
// Get the raw representation of the trait object
Expand All @@ -159,21 +161,21 @@ 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 {
pub fn is<T: Any>(&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> {
pub fn downcast_ref<T: Any>(&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> {
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
Any::downcast_mut::<T>(self)
}
}
Expand Down Expand Up @@ -202,7 +204,7 @@ impl TypeId {
/// instantiated with
#[unstable(feature = "core",
reason = "may grow a `Reflect` bound soon via marker traits")]
pub fn of<T: ?Sized + 'static>() -> TypeId {
pub fn of<T: ?Sized + Any>() -> TypeId {
TypeId {
t: unsafe { intrinsics::type_id::<T>() },
}
Expand Down
1 change: 1 addition & 0 deletions src/libcore/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
#![feature(rustc_attrs)]
#![feature(optin_builtin_traits)]
#![feature(concat_idents)]
#![feature(reflect)]

#[macro_use]
mod macros;
Expand Down
43 changes: 43 additions & 0 deletions src/libcore/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,3 +450,46 @@ pub struct CovariantType<T>;
#[deprecated(since = "1.0.0", reason = "Replace with `PhantomData<Cell<T>>`")]
#[lang="invariant_type"]
pub struct InvariantType<T>;

/// A marker trait indicates a type that can be reflected over. This
/// trait is implemented for all types. Its purpose is to ensure that
/// when you write a generic function that will employ reflection,
/// that must be reflected (no pun intended) in the generic bounds of
/// that function. Here is an example:
///
/// ```
/// #![feature(core)]
/// use std::marker::Reflect;
/// use std::any::Any;
/// fn foo<T:Reflect+'static>(x: &T) {
/// let any: &Any = x;
/// if any.is::<u32>() { println!("u32"); }
/// }
/// ```
///
/// Without the declaration `T:Reflect`, `foo` would not type check
/// (note: as a matter of style, it would be preferable to to write
/// `T:Any`, because `T:Any` implies `T:Reflect` and `T:'static`, but
/// we use `Reflect` here to show how it works). The `Reflect` bound
/// thus serves to alert `foo`'s caller to the fact that `foo` may
/// behave differently depending on whether `T=u32` or not. In
/// particular, thanks to the `Reflect` bound, callers know that a
/// function declared like `fn bar<T>(...)` will always act in
/// precisely the same way no matter what type `T` is supplied,
/// beacuse there are no bounds declared on `T`. (The ability for a
/// caller to reason about what a function may do based solely on what
/// generic bounds are declared is often called the ["parametricity
/// property"][1].)
///
/// [1]: http://en.wikipedia.org/wiki/Parametricity
#[rustc_reflect_like]
#[unstable(feature = "core", reason = "requires RFC and more experience")]
pub trait Reflect : MarkerTrait {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is totally tangential and has probably been raised before, but isn't this saying trait Reflect where Self: MarkerTrait, whereas what we might actually want (and what might actually make sense) would be impl MarkerTrait for Reflect?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This exists solely because Self and type params have to be used by methods or supertraits.

}

#[cfg(stage0)]
impl<T> Reflect for T { }

#[cfg(not(stage0))]
impl Reflect for .. { }

2 changes: 2 additions & 0 deletions src/librustc/middle/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ impl<'tcx> FulfillmentContext<'tcx> {
// debug output much nicer to read and so on.
let obligation = infcx.resolve_type_vars_if_possible(&obligation);

assert!(!obligation.has_escaping_regions());

if !self.duplicate_set.insert(obligation.predicate.clone()) {
debug!("register_predicate({}) -- already seen, skip", obligation.repr(infcx.tcx));
return;
Expand Down
6 changes: 4 additions & 2 deletions src/librustc/middle/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ pub use self::util::get_vtable_index_of_object_method;
pub use self::util::trait_ref_for_builtin_bound;
pub use self::util::supertraits;
pub use self::util::Supertraits;
pub use self::util::supertrait_def_ids;
pub use self::util::SupertraitDefIds;
pub use self::util::transitive_bounds;
pub use self::util::upcast;

Expand Down Expand Up @@ -640,7 +642,7 @@ impl<'tcx> FulfillmentError<'tcx> {
}

impl<'tcx> TraitObligation<'tcx> {
fn self_ty(&self) -> Ty<'tcx> {
self.predicate.0.self_ty()
fn self_ty(&self) -> ty::Binder<Ty<'tcx>> {
ty::Binder(self.predicate.skip_binder().self_ty())
}
}
16 changes: 8 additions & 8 deletions src/librustc/middle/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,36 +53,36 @@ pub enum MethodViolationCode {
}

pub fn is_object_safe<'tcx>(tcx: &ty::ctxt<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>)
trait_def_id: ast::DefId)
-> bool
{
// Because we query yes/no results frequently, we keep a cache:
let cached_result =
tcx.object_safety_cache.borrow().get(&trait_ref.def_id()).cloned();
tcx.object_safety_cache.borrow().get(&trait_def_id).cloned();

let result =
cached_result.unwrap_or_else(|| {
let result = object_safety_violations(tcx, trait_ref.clone()).is_empty();
let result = object_safety_violations(tcx, trait_def_id).is_empty();

// Record just a yes/no result in the cache; this is what is
// queried most frequently. Note that this may overwrite a
// previous result, but always with the same thing.
tcx.object_safety_cache.borrow_mut().insert(trait_ref.def_id(), result);
tcx.object_safety_cache.borrow_mut().insert(trait_def_id, result);

result
});

debug!("is_object_safe({}) = {}", trait_ref.repr(tcx), result);
debug!("is_object_safe({}) = {}", trait_def_id.repr(tcx), result);

result
}

pub fn object_safety_violations<'tcx>(tcx: &ty::ctxt<'tcx>,
sub_trait_ref: ty::PolyTraitRef<'tcx>)
trait_def_id: ast::DefId)
-> Vec<ObjectSafetyViolation<'tcx>>
{
supertraits(tcx, sub_trait_ref)
.flat_map(|tr| object_safety_violations_for_trait(tcx, tr.def_id()).into_iter())
traits::supertrait_def_ids(tcx, trait_def_id)
.flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id).into_iter())
.collect()
}

Expand Down
Loading