Implement Reflect
trait with a variant on the standard OIBIT
semantics that tests the *interface* of trait objects, rather than what they close over.
This commit is contained in:
parent
a923278c62
commit
9c9bb9ce1d
13 changed files with 252 additions and 29 deletions
|
@ -244,13 +244,13 @@ pub trait BoxAny {
|
||||||
/// Returns the boxed value if it is of type `T`, or
|
/// Returns the boxed value if it is of type `T`, or
|
||||||
/// `Err(Self)` if it isn't.
|
/// `Err(Self)` if it isn't.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[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")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl BoxAny for Box<Any> {
|
impl BoxAny for Box<Any> {
|
||||||
#[inline]
|
#[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>() {
|
if self.is::<T>() {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Get the raw representation of the trait object
|
// Get the raw representation of the trait object
|
||||||
|
@ -270,7 +270,7 @@ impl BoxAny for Box<Any> {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl BoxAny for Box<Any+Send> {
|
impl BoxAny for Box<Any+Send> {
|
||||||
#[inline]
|
#[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)
|
<Box<Any>>::downcast(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! // This function wants to log its parameter out prior to doing work with it.
|
//! // 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);
|
//! log(value);
|
||||||
//! // ...do some other work
|
//! // ...do some other work
|
||||||
//! }
|
//! }
|
||||||
|
@ -76,7 +76,7 @@ use mem::transmute;
|
||||||
use option::Option::{self, Some, None};
|
use option::Option::{self, Some, None};
|
||||||
use raw::TraitObject;
|
use raw::TraitObject;
|
||||||
use intrinsics;
|
use intrinsics;
|
||||||
use marker::Sized;
|
use marker::{Reflect, Sized};
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Any trait
|
// Any trait
|
||||||
|
@ -88,14 +88,16 @@ use marker::Sized;
|
||||||
///
|
///
|
||||||
/// [mod]: ../index.html
|
/// [mod]: ../index.html
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub trait Any: 'static {
|
pub trait Any: Reflect + 'static {
|
||||||
/// Get the `TypeId` of `self`
|
/// Get the `TypeId` of `self`
|
||||||
#[unstable(feature = "core",
|
#[unstable(feature = "core",
|
||||||
reason = "this method will likely be replaced by an associated static")]
|
reason = "this method will likely be replaced by an associated static")]
|
||||||
fn get_type_id(&self) -> TypeId;
|
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>() }
|
fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +109,7 @@ impl Any {
|
||||||
/// Returns true if the boxed type is the same as `T`
|
/// Returns true if the boxed type is the same as `T`
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[inline]
|
#[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
|
// Get TypeId of the type this function is instantiated with
|
||||||
let t = TypeId::of::<T>();
|
let t = TypeId::of::<T>();
|
||||||
|
|
||||||
|
@ -122,7 +124,7 @@ impl Any {
|
||||||
/// `None` if it isn't.
|
/// `None` if it isn't.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
|
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
|
||||||
if self.is::<T>() {
|
if self.is::<T>() {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Get the raw representation of the trait object
|
// Get the raw representation of the trait object
|
||||||
|
@ -140,7 +142,7 @@ impl Any {
|
||||||
/// `None` if it isn't.
|
/// `None` if it isn't.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[inline]
|
#[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>() {
|
if self.is::<T>() {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Get the raw representation of the trait object
|
// Get the raw representation of the trait object
|
||||||
|
@ -159,21 +161,21 @@ impl Any+Send {
|
||||||
/// Forwards to the method defined on the type `Any`.
|
/// Forwards to the method defined on the type `Any`.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is<T: 'static>(&self) -> bool {
|
pub fn is<T: Any>(&self) -> bool {
|
||||||
Any::is::<T>(self)
|
Any::is::<T>(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Forwards to the method defined on the type `Any`.
|
/// Forwards to the method defined on the type `Any`.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
|
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
|
||||||
Any::downcast_ref::<T>(self)
|
Any::downcast_ref::<T>(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Forwards to the method defined on the type `Any`.
|
/// Forwards to the method defined on the type `Any`.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[inline]
|
#[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)
|
Any::downcast_mut::<T>(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,7 +204,7 @@ impl TypeId {
|
||||||
/// instantiated with
|
/// instantiated with
|
||||||
#[unstable(feature = "core",
|
#[unstable(feature = "core",
|
||||||
reason = "may grow a `Reflect` bound soon via marker traits")]
|
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 {
|
TypeId {
|
||||||
t: unsafe { intrinsics::type_id::<T>() },
|
t: unsafe { intrinsics::type_id::<T>() },
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,7 @@
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
#![feature(optin_builtin_traits)]
|
#![feature(optin_builtin_traits)]
|
||||||
#![feature(concat_idents)]
|
#![feature(concat_idents)]
|
||||||
|
#![feature(reflect)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
|
@ -450,3 +450,45 @@ pub struct CovariantType<T>;
|
||||||
#[deprecated(since = "1.0.0", reason = "Replace with `PhantomData<Cell<T>>`")]
|
#[deprecated(since = "1.0.0", reason = "Replace with `PhantomData<Cell<T>>`")]
|
||||||
#[lang="invariant_type"]
|
#[lang="invariant_type"]
|
||||||
pub struct InvariantType<T>;
|
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:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// 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 {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
|
impl<T> Reflect for T { }
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
impl Reflect for .. { }
|
||||||
|
|
||||||
|
|
|
@ -138,6 +138,7 @@ enum SelectionCandidate<'tcx> {
|
||||||
ParamCandidate(ty::PolyTraitRef<'tcx>),
|
ParamCandidate(ty::PolyTraitRef<'tcx>),
|
||||||
ImplCandidate(ast::DefId),
|
ImplCandidate(ast::DefId),
|
||||||
DefaultImplCandidate(ast::DefId),
|
DefaultImplCandidate(ast::DefId),
|
||||||
|
DefaultImplObjectCandidate(ast::DefId),
|
||||||
|
|
||||||
/// This is a trait matching with a projected type as `Self`, and
|
/// This is a trait matching with a projected type as `Self`, and
|
||||||
/// we found an applicable bound in the trait definition.
|
/// we found an applicable bound in the trait definition.
|
||||||
|
@ -1160,7 +1161,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
|
|
||||||
if ty::trait_has_default_impl(self.tcx(), def_id) {
|
if ty::trait_has_default_impl(self.tcx(), def_id) {
|
||||||
match self_ty.sty {
|
match self_ty.sty {
|
||||||
ty::ty_trait(..) |
|
ty::ty_trait(..) => {
|
||||||
|
// For object types, we don't know what the closed
|
||||||
|
// over types are. For most traits, this means we
|
||||||
|
// conservatively say nothing; a candidate may be
|
||||||
|
// added by `assemble_candidates_from_object_ty`.
|
||||||
|
// However, for the kind of magic reflect trait,
|
||||||
|
// we consider it to be implemented even for
|
||||||
|
// object types, because it just lets you reflect
|
||||||
|
// onto the object type, not into the object's
|
||||||
|
// interior.
|
||||||
|
if ty::has_attr(self.tcx(), def_id, "rustc_reflect_like") {
|
||||||
|
candidates.vec.push(DefaultImplObjectCandidate(def_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
ty::ty_param(..) |
|
ty::ty_param(..) |
|
||||||
ty::ty_projection(..) => {
|
ty::ty_projection(..) => {
|
||||||
// In these cases, we don't know what the actual
|
// In these cases, we don't know what the actual
|
||||||
|
@ -1798,7 +1812,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultImplCandidate(trait_def_id) => {
|
DefaultImplCandidate(trait_def_id) => {
|
||||||
let data = try!(self.confirm_default_impl_candidate(obligation, trait_def_id));
|
let data = self.confirm_default_impl_candidate(obligation, trait_def_id);
|
||||||
|
Ok(VtableDefaultImpl(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultImplObjectCandidate(trait_def_id) => {
|
||||||
|
let data = self.confirm_default_impl_object_candidate(obligation, trait_def_id);
|
||||||
Ok(VtableDefaultImpl(data))
|
Ok(VtableDefaultImpl(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1927,17 +1946,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
/// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds.
|
/// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds.
|
||||||
fn confirm_default_impl_candidate(&mut self,
|
fn confirm_default_impl_candidate(&mut self,
|
||||||
obligation: &TraitObligation<'tcx>,
|
obligation: &TraitObligation<'tcx>,
|
||||||
impl_def_id: ast::DefId)
|
trait_def_id: ast::DefId)
|
||||||
-> Result<VtableDefaultImplData<PredicateObligation<'tcx>>,
|
-> VtableDefaultImplData<PredicateObligation<'tcx>>
|
||||||
SelectionError<'tcx>>
|
|
||||||
{
|
{
|
||||||
debug!("confirm_default_impl_candidate({}, {})",
|
debug!("confirm_default_impl_candidate({}, {})",
|
||||||
obligation.repr(self.tcx()),
|
obligation.repr(self.tcx()),
|
||||||
impl_def_id.repr(self.tcx()));
|
trait_def_id.repr(self.tcx()));
|
||||||
|
|
||||||
let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty());
|
let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty());
|
||||||
match self.constituent_types_for_ty(self_ty) {
|
match self.constituent_types_for_ty(self_ty) {
|
||||||
Some(types) => Ok(self.vtable_default_impl(obligation, impl_def_id, types)),
|
Some(types) => self.vtable_default_impl(obligation, trait_def_id, types),
|
||||||
None => {
|
None => {
|
||||||
self.tcx().sess.bug(
|
self.tcx().sess.bug(
|
||||||
&format!(
|
&format!(
|
||||||
|
@ -1947,6 +1965,39 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn confirm_default_impl_object_candidate(&mut self,
|
||||||
|
obligation: &TraitObligation<'tcx>,
|
||||||
|
trait_def_id: ast::DefId)
|
||||||
|
-> VtableDefaultImplData<PredicateObligation<'tcx>>
|
||||||
|
{
|
||||||
|
debug!("confirm_default_impl_object_candidate({}, {})",
|
||||||
|
obligation.repr(self.tcx()),
|
||||||
|
trait_def_id.repr(self.tcx()));
|
||||||
|
|
||||||
|
assert!(ty::has_attr(self.tcx(), trait_def_id, "rustc_reflect_like"));
|
||||||
|
|
||||||
|
let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty());
|
||||||
|
match self_ty.sty {
|
||||||
|
ty::ty_trait(ref data) => {
|
||||||
|
// OK to skip the binder, since vtable_default_impl reintroduces it
|
||||||
|
let input_types = data.principal.skip_binder().substs.types.get_slice(TypeSpace);
|
||||||
|
let assoc_types = data.bounds.projection_bounds
|
||||||
|
.iter()
|
||||||
|
.map(|pb| pb.skip_binder().ty);
|
||||||
|
let all_types: Vec<_> = input_types.iter().cloned()
|
||||||
|
.chain(assoc_types)
|
||||||
|
.collect();
|
||||||
|
self.vtable_default_impl(obligation, trait_def_id, all_types)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.tcx().sess.bug(
|
||||||
|
&format!(
|
||||||
|
"asked to confirm default object implementation for non-object type: {}",
|
||||||
|
self_ty.repr(self.tcx())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// See `confirm_default_impl_candidate`
|
/// See `confirm_default_impl_candidate`
|
||||||
fn vtable_default_impl(&mut self,
|
fn vtable_default_impl(&mut self,
|
||||||
obligation: &TraitObligation<'tcx>,
|
obligation: &TraitObligation<'tcx>,
|
||||||
|
@ -2530,6 +2581,7 @@ impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> {
|
||||||
ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)),
|
ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)),
|
||||||
ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)),
|
ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)),
|
||||||
DefaultImplCandidate(t) => format!("DefaultImplCandidate({:?})", t),
|
DefaultImplCandidate(t) => format!("DefaultImplCandidate({:?})", t),
|
||||||
|
DefaultImplObjectCandidate(t) => format!("DefaultImplObjectCandidate({:?})", t),
|
||||||
ProjectionCandidate => format!("ProjectionCandidate"),
|
ProjectionCandidate => format!("ProjectionCandidate"),
|
||||||
FnPointerCandidate => format!("FnPointerCandidate"),
|
FnPointerCandidate => format!("FnPointerCandidate"),
|
||||||
ObjectCandidate => format!("ObjectCandidate"),
|
ObjectCandidate => format!("ObjectCandidate"),
|
||||||
|
|
|
@ -74,6 +74,7 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
|
||||||
|
|
||||||
("rustc_diagnostic_macros", "1.0.0", Active),
|
("rustc_diagnostic_macros", "1.0.0", Active),
|
||||||
("unboxed_closures", "1.0.0", Active),
|
("unboxed_closures", "1.0.0", Active),
|
||||||
|
("reflect", "1.0.0", Active),
|
||||||
("import_shadowing", "1.0.0", Removed),
|
("import_shadowing", "1.0.0", Removed),
|
||||||
("advanced_slice_patterns", "1.0.0", Active),
|
("advanced_slice_patterns", "1.0.0", Active),
|
||||||
("tuple_indexing", "1.0.0", Accepted),
|
("tuple_indexing", "1.0.0", Accepted),
|
||||||
|
@ -281,7 +282,11 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[
|
||||||
// FIXME: #19470 this shouldn't be needed forever
|
// FIXME: #19470 this shouldn't be needed forever
|
||||||
("old_orphan_check", Whitelisted),
|
("old_orphan_check", Whitelisted),
|
||||||
("old_impl_check", Whitelisted),
|
("old_impl_check", Whitelisted),
|
||||||
("rustc_paren_sugar", Whitelisted), // FIXME: #18101 temporary unboxed closure hack
|
|
||||||
|
("rustc_paren_sugar", Gated("unboxed_closures",
|
||||||
|
"unboxed_closures are still evolving")),
|
||||||
|
("rustc_reflect_like", Gated("reflect",
|
||||||
|
"defining reflective traits is still evolving")),
|
||||||
|
|
||||||
// Crate level attributes
|
// Crate level attributes
|
||||||
("crate_name", CrateLevel),
|
("crate_name", CrateLevel),
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
#![feature(core)]
|
#![feature(core)]
|
||||||
|
|
||||||
use std::any::TypeId;
|
use std::any::{Any, TypeId};
|
||||||
|
|
||||||
pub struct A;
|
pub struct A;
|
||||||
pub struct B(Option<A>);
|
pub struct B(Option<A>);
|
||||||
|
@ -31,4 +31,4 @@ pub unsafe fn id_F() -> TypeId { TypeId::of::<F>() }
|
||||||
pub unsafe fn id_G() -> TypeId { TypeId::of::<G>() }
|
pub unsafe fn id_G() -> TypeId { TypeId::of::<G>() }
|
||||||
pub unsafe fn id_H() -> TypeId { TypeId::of::<H>() }
|
pub unsafe fn id_H() -> TypeId { TypeId::of::<H>() }
|
||||||
|
|
||||||
pub unsafe fn foo<T: 'static>() -> TypeId { TypeId::of::<T>() }
|
pub unsafe fn foo<T: Any>() -> TypeId { TypeId::of::<T>() }
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
#![feature(core)]
|
#![feature(core)]
|
||||||
|
|
||||||
use std::any::TypeId;
|
use std::any::{Any, TypeId};
|
||||||
|
|
||||||
pub struct A;
|
pub struct A;
|
||||||
pub struct B(Option<A>);
|
pub struct B(Option<A>);
|
||||||
|
@ -31,4 +31,4 @@ pub unsafe fn id_F() -> TypeId { TypeId::of::<F>() }
|
||||||
pub unsafe fn id_G() -> TypeId { TypeId::of::<G>() }
|
pub unsafe fn id_G() -> TypeId { TypeId::of::<G>() }
|
||||||
pub unsafe fn id_H() -> TypeId { TypeId::of::<H>() }
|
pub unsafe fn id_H() -> TypeId { TypeId::of::<H>() }
|
||||||
|
|
||||||
pub unsafe fn foo<T: 'static>() -> TypeId { TypeId::of::<T>() }
|
pub unsafe fn foo<T:Any>() -> TypeId { TypeId::of::<T>() }
|
||||||
|
|
35
src/test/compile-fail/reflect-assoc.rs
Normal file
35
src/test/compile-fail/reflect-assoc.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// 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 <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.
|
||||||
|
|
||||||
|
// Test that types that appear in assoc bindings in an object
|
||||||
|
// type are subject to the reflect check.
|
||||||
|
|
||||||
|
use std::marker::Reflect;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
trait Get {
|
||||||
|
type Output;
|
||||||
|
fn get(self) -> Self::Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Struct<T>(T);
|
||||||
|
|
||||||
|
fn is_reflect<T:Reflect>() { }
|
||||||
|
|
||||||
|
fn a<T>() {
|
||||||
|
is_reflect::<Box<Get<Output=T>>>(); //~ ERROR not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ok_a<T: Reflect>() {
|
||||||
|
is_reflect::<Box<Get<Output=T>>>(); // OK
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
47
src/test/compile-fail/reflect-object-param.rs
Normal file
47
src/test/compile-fail/reflect-object-param.rs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
// 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 <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.
|
||||||
|
|
||||||
|
// Test that types that appear in input types in an object type are
|
||||||
|
// subject to the reflect check.
|
||||||
|
|
||||||
|
use std::marker::Reflect;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
trait Get<T> {
|
||||||
|
fn get(self) -> T;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Struct<T>(T);
|
||||||
|
|
||||||
|
fn is_reflect<T:Reflect>() { }
|
||||||
|
|
||||||
|
fn a<T>() {
|
||||||
|
is_reflect::<T>(); //~ ERROR not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ok_a<T: Reflect>() {
|
||||||
|
is_reflect::<T>(); // OK
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b<T>() {
|
||||||
|
is_reflect::<Box<Get<T>>>(); //~ ERROR not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ok_b<T: Reflect>() {
|
||||||
|
is_reflect::<Box<Get<T>>>(); // OK
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c<T>() {
|
||||||
|
is_reflect::<Box<Get<Struct<T>>>>(); //~ ERROR not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
is_reflect::<Box<Get<Struct<()>>>>(); // OK
|
||||||
|
}
|
39
src/test/compile-fail/reflect.rs
Normal file
39
src/test/compile-fail/reflect.rs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
// 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 <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.
|
||||||
|
|
||||||
|
// Test that there is no way to get a generic type `T` to be
|
||||||
|
// considered as `Reflect` (or accessible via something that is
|
||||||
|
// considered `Reflect`) without a reflect bound, but that any
|
||||||
|
// concrete type works fine. Note that object types are tested
|
||||||
|
// separately.
|
||||||
|
|
||||||
|
use std::marker::Reflect;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
struct Struct<T>(T);
|
||||||
|
|
||||||
|
fn is_reflect<T:Reflect>() { }
|
||||||
|
|
||||||
|
fn c<T>() {
|
||||||
|
is_reflect::<Struct<T>>(); //~ ERROR not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ok_c<T: Reflect>() {
|
||||||
|
is_reflect::<Struct<T>>(); // OK
|
||||||
|
}
|
||||||
|
|
||||||
|
fn d<T>() {
|
||||||
|
is_reflect::<(i32, T)>(); //~ ERROR not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
is_reflect::<&i32>(); // OK
|
||||||
|
is_reflect::<Box<Write>>(); // OK
|
||||||
|
}
|
|
@ -30,7 +30,7 @@ impl Wrap for int {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is<T:'static>(x: &Any) -> bool {
|
fn is<T:Any>(x: &Any) -> bool {
|
||||||
x.is::<T>()
|
x.is::<T>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
#![feature(unboxed_closures, core)]
|
#![feature(unboxed_closures, core)]
|
||||||
|
|
||||||
use std::any::TypeId;
|
use std::any::{Any, TypeId};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Bare fns
|
// Bare fns
|
||||||
|
@ -63,7 +63,7 @@ fn main() {
|
||||||
assert!(a != b);
|
assert!(a != b);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn id<T:'static>(_: T) -> TypeId {
|
fn id<T:Any>(_: T) -> TypeId {
|
||||||
TypeId::of::<T>()
|
TypeId::of::<T>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue