Skip to content

Commit 9c9bb9c

Browse files
committed
Implement Reflect trait with a variant on the standard OIBIT
semantics that tests the *interface* of trait objects, rather than what they close over.
1 parent a923278 commit 9c9bb9c

File tree

13 files changed

+252
-29
lines changed

13 files changed

+252
-29
lines changed

src/liballoc/boxed.rs

Lines changed: 3 additions & 3 deletions
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
}

src/libcore/any.rs

Lines changed: 13 additions & 11 deletions
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
}

src/libcore/lib.rs

Lines changed: 1 addition & 0 deletions
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;

src/libcore/marker.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,3 +450,45 @@ 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+
/// use std::marker::Reflect;
462+
/// use std::any::Any;
463+
/// fn foo<T:Reflect+'static>(x: &T) {
464+
/// let any: &Any = x;
465+
/// if any.is::<u32>() { println!("u32"); }
466+
/// }
467+
/// ```
468+
///
469+
/// Without the declaration `T:Reflect`, `foo` would not type check
470+
/// (note: as a matter of style, it would be preferable to to write
471+
/// `T:Any`, because `T:Any` implies `T:Reflect` and `T:'static`, but
472+
/// we use `Reflect` here to show how it works). The `Reflect` bound
473+
/// thus serves to alert `foo`'s caller to the fact that `foo` may
474+
/// behave differently depending on whether `T=u32` or not. In
475+
/// particular, thanks to the `Reflect` bound, callers know that a
476+
/// function declared like `fn bar<T>(...)` will always act in
477+
/// precisely the same way no matter what type `T` is supplied,
478+
/// beacuse there are no bounds declared on `T`. (The ability for a
479+
/// caller to reason about what a function may do based solely on what
480+
/// generic bounds are declared is often called the ["parametricity
481+
/// property"][1].)
482+
///
483+
/// [1]: http://en.wikipedia.org/wiki/Parametricity
484+
#[rustc_reflect_like]
485+
#[unstable(feature = "core", reason = "requires RFC and more experience")]
486+
pub trait Reflect : MarkerTrait {
487+
}
488+
489+
#[cfg(stage0)]
490+
impl<T> Reflect for T { }
491+
492+
#[cfg(not(stage0))]
493+
impl Reflect for .. { }
494+

src/librustc/middle/traits/select.rs

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ enum SelectionCandidate<'tcx> {
138138
ParamCandidate(ty::PolyTraitRef<'tcx>),
139139
ImplCandidate(ast::DefId),
140140
DefaultImplCandidate(ast::DefId),
141+
DefaultImplObjectCandidate(ast::DefId),
141142

142143
/// This is a trait matching with a projected type as `Self`, and
143144
/// we found an applicable bound in the trait definition.
@@ -1160,7 +1161,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11601161

11611162
if ty::trait_has_default_impl(self.tcx(), def_id) {
11621163
match self_ty.sty {
1163-
ty::ty_trait(..) |
1164+
ty::ty_trait(..) => {
1165+
// For object types, we don't know what the closed
1166+
// over types are. For most traits, this means we
1167+
// conservatively say nothing; a candidate may be
1168+
// added by `assemble_candidates_from_object_ty`.
1169+
// However, for the kind of magic reflect trait,
1170+
// we consider it to be implemented even for
1171+
// object types, because it just lets you reflect
1172+
// onto the object type, not into the object's
1173+
// interior.
1174+
if ty::has_attr(self.tcx(), def_id, "rustc_reflect_like") {
1175+
candidates.vec.push(DefaultImplObjectCandidate(def_id));
1176+
}
1177+
}
11641178
ty::ty_param(..) |
11651179
ty::ty_projection(..) => {
11661180
// In these cases, we don't know what the actual
@@ -1798,7 +1812,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
17981812
}
17991813

18001814
DefaultImplCandidate(trait_def_id) => {
1801-
let data = try!(self.confirm_default_impl_candidate(obligation, trait_def_id));
1815+
let data = self.confirm_default_impl_candidate(obligation, trait_def_id);
1816+
Ok(VtableDefaultImpl(data))
1817+
}
1818+
1819+
DefaultImplObjectCandidate(trait_def_id) => {
1820+
let data = self.confirm_default_impl_object_candidate(obligation, trait_def_id);
18021821
Ok(VtableDefaultImpl(data))
18031822
}
18041823

@@ -1927,17 +1946,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
19271946
/// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds.
19281947
fn confirm_default_impl_candidate(&mut self,
19291948
obligation: &TraitObligation<'tcx>,
1930-
impl_def_id: ast::DefId)
1931-
-> Result<VtableDefaultImplData<PredicateObligation<'tcx>>,
1932-
SelectionError<'tcx>>
1949+
trait_def_id: ast::DefId)
1950+
-> VtableDefaultImplData<PredicateObligation<'tcx>>
19331951
{
19341952
debug!("confirm_default_impl_candidate({}, {})",
19351953
obligation.repr(self.tcx()),
1936-
impl_def_id.repr(self.tcx()));
1954+
trait_def_id.repr(self.tcx()));
19371955

19381956
let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty());
19391957
match self.constituent_types_for_ty(self_ty) {
1940-
Some(types) => Ok(self.vtable_default_impl(obligation, impl_def_id, types)),
1958+
Some(types) => self.vtable_default_impl(obligation, trait_def_id, types),
19411959
None => {
19421960
self.tcx().sess.bug(
19431961
&format!(
@@ -1947,6 +1965,39 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
19471965
}
19481966
}
19491967

1968+
fn confirm_default_impl_object_candidate(&mut self,
1969+
obligation: &TraitObligation<'tcx>,
1970+
trait_def_id: ast::DefId)
1971+
-> VtableDefaultImplData<PredicateObligation<'tcx>>
1972+
{
1973+
debug!("confirm_default_impl_object_candidate({}, {})",
1974+
obligation.repr(self.tcx()),
1975+
trait_def_id.repr(self.tcx()));
1976+
1977+
assert!(ty::has_attr(self.tcx(), trait_def_id, "rustc_reflect_like"));
1978+
1979+
let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty());
1980+
match self_ty.sty {
1981+
ty::ty_trait(ref data) => {
1982+
// OK to skip the binder, since vtable_default_impl reintroduces it
1983+
let input_types = data.principal.skip_binder().substs.types.get_slice(TypeSpace);
1984+
let assoc_types = data.bounds.projection_bounds
1985+
.iter()
1986+
.map(|pb| pb.skip_binder().ty);
1987+
let all_types: Vec<_> = input_types.iter().cloned()
1988+
.chain(assoc_types)
1989+
.collect();
1990+
self.vtable_default_impl(obligation, trait_def_id, all_types)
1991+
}
1992+
_ => {
1993+
self.tcx().sess.bug(
1994+
&format!(
1995+
"asked to confirm default object implementation for non-object type: {}",
1996+
self_ty.repr(self.tcx())));
1997+
}
1998+
}
1999+
}
2000+
19502001
/// See `confirm_default_impl_candidate`
19512002
fn vtable_default_impl(&mut self,
19522003
obligation: &TraitObligation<'tcx>,
@@ -2530,6 +2581,7 @@ impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> {
25302581
ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)),
25312582
ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)),
25322583
DefaultImplCandidate(t) => format!("DefaultImplCandidate({:?})", t),
2584+
DefaultImplObjectCandidate(t) => format!("DefaultImplObjectCandidate({:?})", t),
25332585
ProjectionCandidate => format!("ProjectionCandidate"),
25342586
FnPointerCandidate => format!("FnPointerCandidate"),
25352587
ObjectCandidate => format!("ObjectCandidate"),

src/libsyntax/feature_gate.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
7474

7575
("rustc_diagnostic_macros", "1.0.0", Active),
7676
("unboxed_closures", "1.0.0", Active),
77+
("reflect", "1.0.0", Active),
7778
("import_shadowing", "1.0.0", Removed),
7879
("advanced_slice_patterns", "1.0.0", Active),
7980
("tuple_indexing", "1.0.0", Accepted),
@@ -281,7 +282,11 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[
281282
// FIXME: #19470 this shouldn't be needed forever
282283
("old_orphan_check", Whitelisted),
283284
("old_impl_check", Whitelisted),
284-
("rustc_paren_sugar", Whitelisted), // FIXME: #18101 temporary unboxed closure hack
285+
286+
("rustc_paren_sugar", Gated("unboxed_closures",
287+
"unboxed_closures are still evolving")),
288+
("rustc_reflect_like", Gated("reflect",
289+
"defining reflective traits is still evolving")),
285290

286291
// Crate level attributes
287292
("crate_name", CrateLevel),

src/test/auxiliary/typeid-intrinsic.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
#![feature(core)]
1212

13-
use std::any::TypeId;
13+
use std::any::{Any, TypeId};
1414

1515
pub struct A;
1616
pub struct B(Option<A>);
@@ -31,4 +31,4 @@ pub unsafe fn id_F() -> TypeId { TypeId::of::<F>() }
3131
pub unsafe fn id_G() -> TypeId { TypeId::of::<G>() }
3232
pub unsafe fn id_H() -> TypeId { TypeId::of::<H>() }
3333

34-
pub unsafe fn foo<T: 'static>() -> TypeId { TypeId::of::<T>() }
34+
pub unsafe fn foo<T: Any>() -> TypeId { TypeId::of::<T>() }

src/test/auxiliary/typeid-intrinsic2.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
#![feature(core)]
1212

13-
use std::any::TypeId;
13+
use std::any::{Any, TypeId};
1414

1515
pub struct A;
1616
pub struct B(Option<A>);
@@ -31,4 +31,4 @@ pub unsafe fn id_F() -> TypeId { TypeId::of::<F>() }
3131
pub unsafe fn id_G() -> TypeId { TypeId::of::<G>() }
3232
pub unsafe fn id_H() -> TypeId { TypeId::of::<H>() }
3333

34-
pub unsafe fn foo<T: 'static>() -> TypeId { TypeId::of::<T>() }
34+
pub unsafe fn foo<T:Any>() -> TypeId { TypeId::of::<T>() }
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that types that appear in assoc bindings in an object
12+
// type are subject to the reflect check.
13+
14+
use std::marker::Reflect;
15+
use std::io::Write;
16+
17+
trait Get {
18+
type Output;
19+
fn get(self) -> Self::Output;
20+
}
21+
22+
struct Struct<T>(T);
23+
24+
fn is_reflect<T:Reflect>() { }
25+
26+
fn a<T>() {
27+
is_reflect::<Box<Get<Output=T>>>(); //~ ERROR not implemented
28+
}
29+
30+
fn ok_a<T: Reflect>() {
31+
is_reflect::<Box<Get<Output=T>>>(); // OK
32+
}
33+
34+
fn main() {
35+
}

0 commit comments

Comments
 (0)