Skip to content

Commit 5b45ede

Browse files
committed
Rollup merge of rust-lang#23712 - nikomatsakis:reflect-trait, r=FlaPer87
This PR introduces a `Reflect` marker trait which is a supertrait of `Any`. The idea is that `Reflect` is defined for all concrete types, but is not defined for type parameters unless there is a `T:Reflect` bound. This is intended to preserve the parametricity property. This allows the `Any` interface to be stabilized without committing us to unbounded reflection that is not easily detectable by the caller. The implementation of `Reflect` relies on an experimental variant of OIBIT. This variant behaves differently for objects, since it requires that all types exposed as part of the object's *interface* are `Reflect`, but isn't concerned about other types that may be closed over. In other words, you don't have to write `Foo+Reflect` in order for `Foo: Reflect` to hold (where `Foo` is a trait). Given that `Any` is slated to stabilization and hence that we are committed to some form of reflection, the goal of this PR is to leave our options open with respect to parametricity. I see the options for full stabilization as follows (I think an RFC would be an appropriate way to confirm whichever of these three routes we take): 1. We make `Reflect` a lang-item. 2. We stabilize some version of the OIBIT variation I implemented as a general mechanism that may be appropriate for other use cases. 3. We give up on preserving parametricity here and just have `impl<T> Reflect for T` instead. In that case, `Reflect` is a harmless but not especially useful trait going forward. cc @aturon cc @alexcrichton cc @glaebhoerl (this is more-or-less your proposal, as I understood it) cc @reem (this is more-or-less what we discussed on IRC at some point) cc @flaper87 (vaguely pertains to OIBIT)
2 parents e65c6e5 + dd8cf92 commit 5b45ede

21 files changed

+568
-173
lines changed

Diff for: src/liballoc/boxed.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -244,13 +244,13 @@ pub trait BoxAny {
244244
/// Returns the boxed value if it is of type `T`, or
245245
/// `Err(Self)` if it isn't.
246246
#[stable(feature = "rust1", since = "1.0.0")]
247-
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>>;
247+
fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>>;
248248
}
249249

250250
#[stable(feature = "rust1", since = "1.0.0")]
251251
impl BoxAny for Box<Any> {
252252
#[inline]
253-
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
253+
fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
254254
if self.is::<T>() {
255255
unsafe {
256256
// Get the raw representation of the trait object
@@ -270,7 +270,7 @@ impl BoxAny for Box<Any> {
270270
#[stable(feature = "rust1", since = "1.0.0")]
271271
impl BoxAny for Box<Any+Send> {
272272
#[inline]
273-
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
273+
fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
274274
<Box<Any>>::downcast(self)
275275
}
276276
}

Diff for: src/libcore/any.rs

+13-11
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
//! }
5656
//!
5757
//! // This function wants to log its parameter out prior to doing work with it.
58-
//! fn do_work<T: Debug + 'static>(value: &T) {
58+
//! fn do_work<T: Any + Debug>(value: &T) {
5959
//! log(value);
6060
//! // ...do some other work
6161
//! }
@@ -76,7 +76,7 @@ use mem::transmute;
7676
use option::Option::{self, Some, None};
7777
use raw::TraitObject;
7878
use intrinsics;
79-
use marker::Sized;
79+
use marker::{Reflect, Sized};
8080

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

98-
impl<T: 'static> Any for T {
98+
impl<T> Any for T
99+
where T: Reflect + 'static
100+
{
99101
fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
100102
}
101103

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

@@ -122,7 +124,7 @@ impl Any {
122124
/// `None` if it isn't.
123125
#[stable(feature = "rust1", since = "1.0.0")]
124126
#[inline]
125-
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
127+
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
126128
if self.is::<T>() {
127129
unsafe {
128130
// Get the raw representation of the trait object
@@ -140,7 +142,7 @@ impl Any {
140142
/// `None` if it isn't.
141143
#[stable(feature = "rust1", since = "1.0.0")]
142144
#[inline]
143-
pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
145+
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
144146
if self.is::<T>() {
145147
unsafe {
146148
// Get the raw representation of the trait object
@@ -159,21 +161,21 @@ impl Any+Send {
159161
/// Forwards to the method defined on the type `Any`.
160162
#[stable(feature = "rust1", since = "1.0.0")]
161163
#[inline]
162-
pub fn is<T: 'static>(&self) -> bool {
164+
pub fn is<T: Any>(&self) -> bool {
163165
Any::is::<T>(self)
164166
}
165167

166168
/// Forwards to the method defined on the type `Any`.
167169
#[stable(feature = "rust1", since = "1.0.0")]
168170
#[inline]
169-
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
171+
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
170172
Any::downcast_ref::<T>(self)
171173
}
172174

173175
/// Forwards to the method defined on the type `Any`.
174176
#[stable(feature = "rust1", since = "1.0.0")]
175177
#[inline]
176-
pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
178+
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
177179
Any::downcast_mut::<T>(self)
178180
}
179181
}
@@ -202,7 +204,7 @@ impl TypeId {
202204
/// instantiated with
203205
#[unstable(feature = "core",
204206
reason = "may grow a `Reflect` bound soon via marker traits")]
205-
pub fn of<T: ?Sized + 'static>() -> TypeId {
207+
pub fn of<T: ?Sized + Any>() -> TypeId {
206208
TypeId {
207209
t: unsafe { intrinsics::type_id::<T>() },
208210
}

Diff for: src/libcore/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
#![feature(rustc_attrs)]
7373
#![feature(optin_builtin_traits)]
7474
#![feature(concat_idents)]
75+
#![feature(reflect)]
7576

7677
#[macro_use]
7778
mod macros;

Diff for: src/libcore/marker.rs

+43
Original file line numberDiff line numberDiff line change
@@ -450,3 +450,46 @@ pub struct CovariantType<T>;
450450
#[deprecated(since = "1.0.0", reason = "Replace with `PhantomData<Cell<T>>`")]
451451
#[lang="invariant_type"]
452452
pub struct InvariantType<T>;
453+
454+
/// A marker trait indicates a type that can be reflected over. This
455+
/// trait is implemented for all types. Its purpose is to ensure that
456+
/// when you write a generic function that will employ reflection,
457+
/// that must be reflected (no pun intended) in the generic bounds of
458+
/// that function. Here is an example:
459+
///
460+
/// ```
461+
/// #![feature(core)]
462+
/// use std::marker::Reflect;
463+
/// use std::any::Any;
464+
/// fn foo<T:Reflect+'static>(x: &T) {
465+
/// let any: &Any = x;
466+
/// if any.is::<u32>() { println!("u32"); }
467+
/// }
468+
/// ```
469+
///
470+
/// Without the declaration `T:Reflect`, `foo` would not type check
471+
/// (note: as a matter of style, it would be preferable to to write
472+
/// `T:Any`, because `T:Any` implies `T:Reflect` and `T:'static`, but
473+
/// we use `Reflect` here to show how it works). The `Reflect` bound
474+
/// thus serves to alert `foo`'s caller to the fact that `foo` may
475+
/// behave differently depending on whether `T=u32` or not. In
476+
/// particular, thanks to the `Reflect` bound, callers know that a
477+
/// function declared like `fn bar<T>(...)` will always act in
478+
/// precisely the same way no matter what type `T` is supplied,
479+
/// beacuse there are no bounds declared on `T`. (The ability for a
480+
/// caller to reason about what a function may do based solely on what
481+
/// generic bounds are declared is often called the ["parametricity
482+
/// property"][1].)
483+
///
484+
/// [1]: http://en.wikipedia.org/wiki/Parametricity
485+
#[rustc_reflect_like]
486+
#[unstable(feature = "core", reason = "requires RFC and more experience")]
487+
pub trait Reflect : MarkerTrait {
488+
}
489+
490+
#[cfg(stage0)]
491+
impl<T> Reflect for T { }
492+
493+
#[cfg(not(stage0))]
494+
impl Reflect for .. { }
495+

Diff for: src/librustc/middle/traits/fulfill.rs

+2
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ impl<'tcx> FulfillmentContext<'tcx> {
163163
// debug output much nicer to read and so on.
164164
let obligation = infcx.resolve_type_vars_if_possible(&obligation);
165165

166+
assert!(!obligation.has_escaping_regions());
167+
166168
if !self.duplicate_set.insert(obligation.predicate.clone()) {
167169
debug!("register_predicate({}) -- already seen, skip", obligation.repr(infcx.tcx));
168170
return;

Diff for: src/librustc/middle/traits/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ pub use self::util::get_vtable_index_of_object_method;
4848
pub use self::util::trait_ref_for_builtin_bound;
4949
pub use self::util::supertraits;
5050
pub use self::util::Supertraits;
51+
pub use self::util::supertrait_def_ids;
52+
pub use self::util::SupertraitDefIds;
5153
pub use self::util::transitive_bounds;
5254
pub use self::util::upcast;
5355

@@ -640,7 +642,7 @@ impl<'tcx> FulfillmentError<'tcx> {
640642
}
641643

642644
impl<'tcx> TraitObligation<'tcx> {
643-
fn self_ty(&self) -> Ty<'tcx> {
644-
self.predicate.0.self_ty()
645+
fn self_ty(&self) -> ty::Binder<Ty<'tcx>> {
646+
ty::Binder(self.predicate.skip_binder().self_ty())
645647
}
646648
}

Diff for: src/librustc/middle/traits/object_safety.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -53,36 +53,36 @@ pub enum MethodViolationCode {
5353
}
5454

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

6363
let result =
6464
cached_result.unwrap_or_else(|| {
65-
let result = object_safety_violations(tcx, trait_ref.clone()).is_empty();
65+
let result = object_safety_violations(tcx, trait_def_id).is_empty();
6666

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

7272
result
7373
});
7474

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

7777
result
7878
}
7979

8080
pub fn object_safety_violations<'tcx>(tcx: &ty::ctxt<'tcx>,
81-
sub_trait_ref: ty::PolyTraitRef<'tcx>)
81+
trait_def_id: ast::DefId)
8282
-> Vec<ObjectSafetyViolation<'tcx>>
8383
{
84-
supertraits(tcx, sub_trait_ref)
85-
.flat_map(|tr| object_safety_violations_for_trait(tcx, tr.def_id()).into_iter())
84+
traits::supertrait_def_ids(tcx, trait_def_id)
85+
.flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id).into_iter())
8686
.collect()
8787
}
8888

0 commit comments

Comments
 (0)