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

Remove variances from traits and deprecate PhantomFn/MarkerTrait #23938

Merged
merged 5 commits into from
Apr 3, 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
5 changes: 4 additions & 1 deletion src/libarena/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,13 +192,16 @@ struct TyDesc {
align: usize
}

trait AllTypes { fn dummy(&self) { } }
impl<T:?Sized> AllTypes for T { }

unsafe fn get_tydesc<T>() -> *const TyDesc {
use std::raw::TraitObject;

let ptr = &*(1 as *const T);

// Can use any trait that is implemented for all types.
let obj = mem::transmute::<&marker::MarkerTrait, TraitObject>(ptr);
let obj = mem::transmute::<&AllTypes, TraitObject>(ptr);
obj.vtable as *const TyDesc
}

Expand Down
107 changes: 34 additions & 73 deletions src/libcore/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use hash::Hasher;
#[stable(feature = "rust1", since = "1.0.0")]
#[lang="send"]
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
#[allow(deprecated)]
pub unsafe trait Send : MarkerTrait {
// empty.
}
Expand All @@ -50,6 +51,7 @@ impl !Send for Managed { }
#[lang="sized"]
#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"]
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
#[allow(deprecated)]
pub trait Sized : MarkerTrait {
// Empty.
}
Expand Down Expand Up @@ -203,6 +205,7 @@ pub trait Copy : Clone {
#[stable(feature = "rust1", since = "1.0.0")]
#[lang="sync"]
#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"]
#[allow(deprecated)]
pub unsafe trait Sync : MarkerTrait {
// Empty
}
Expand Down Expand Up @@ -269,84 +272,41 @@ macro_rules! impls{
)
}

/// `MarkerTrait` is intended to be used as the supertrait for traits
/// that don't have any methods but instead serve just to designate
/// categories of types. An example would be the `Send` trait, which
/// indicates types that are sendable: `Send` does not itself offer
/// any methods, but instead is used to gate access to data.
///
/// FIXME. Better documentation needed here!
#[stable(feature = "rust1", since = "1.0.0")]
/// `MarkerTrait` is deprecated and no longer needed.
#[unstable(feature = "core", reason = "deprecated")]
#[deprecated(since = "1.0.0", reason = "No longer needed")]
#[allow(deprecated)]
#[cfg(stage0)]
pub trait MarkerTrait : PhantomFn<Self,Self> { }
// ~~~~~ <-- FIXME(#22806)?
//
// Marker trait has been made invariant so as to avoid inf recursion,
// but we should ideally solve the underlying problem. That's a bit
// complicated.

/// `MarkerTrait` is deprecated and no longer needed.
#[unstable(feature = "core", reason = "deprecated")]
#[deprecated(since = "1.0.0", reason = "No longer needed")]
#[allow(deprecated)]
#[cfg(not(stage0))]
pub trait MarkerTrait { }

#[allow(deprecated)]
impl<T:?Sized> MarkerTrait for T { }

/// `PhantomFn` is a marker trait for use with traits that contain
/// type or lifetime parameters that do not appear in any of their
/// methods. In that case, you can either remove those parameters, or
/// add a `PhantomFn` supertrait that reflects the signature of
/// methods that compiler should "pretend" exists. This most commonly
/// occurs for traits with no methods: in that particular case, you
/// can extend `MarkerTrait`, which is equivalent to
/// `PhantomFn<Self>`.
///
/// # Examples
///
/// As an example, consider a trait with no methods like `Even`, meant
/// to represent types that are "even":
///
/// ```rust,ignore
/// trait Even { }
/// ```
///
/// In this case, because the implicit parameter `Self` is unused, the
/// compiler will issue an error. The only purpose of this trait is to
/// categorize types (and hence instances of those types) as "even" or
/// not, so if we *were* going to have a method, it might look like:
///
/// ```rust,ignore
/// trait Even {
/// fn is_even(self) -> bool { true }
/// }
/// ```
///
/// Therefore, we can model a method like this as follows:
///
/// ```
/// use std::marker::PhantomFn;
/// trait Even : PhantomFn<Self> { }
/// ```
///
/// Another equivalent, but clearer, option would be to use
/// `MarkerTrait`:
///
/// ```
/// # #![feature(core)]
/// use std::marker::MarkerTrait;
/// trait Even : MarkerTrait { }
/// ```
///
/// # Parameters
///
/// - `A` represents the type of the method's argument. You can use a
/// tuple to represent "multiple" arguments. Any types appearing here
/// will be considered "contravariant".
/// - `R`, if supplied, represents the method's return type. This defaults
/// to `()` as it is rarely needed.
///
/// # Additional reading
///
/// More details and background can be found in [RFC 738][738].
///
/// [738]: https://github.com/rust-lang/rfcs/blob/master/text/0738-variance.md
/// `PhantomFn` is a deprecated marker trait that is no longer needed.
#[lang="phantom_fn"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait PhantomFn<A:?Sized,R:?Sized=()> { }
#[unstable(feature = "core", reason = "deprecated")]
#[deprecated(since = "1.0.0", reason = "No longer needed")]
#[cfg(stage0)]
pub trait PhantomFn<A:?Sized,R:?Sized=()> {
}

/// `PhantomFn` is a deprecated marker trait that is no longer needed.
#[unstable(feature = "core", reason = "deprecated")]
#[deprecated(since = "1.0.0", reason = "No longer needed")]
#[cfg(not(stage0))]
pub trait PhantomFn<A:?Sized,R:?Sized=()> {
}

#[allow(deprecated)]
#[cfg(not(stage0))]
impl<A:?Sized,R:?Sized,T:?Sized> PhantomFn<A,R> for T { }

/// `PhantomData<T>` allows you to describe that a type acts as if it stores a value of type `T`,
/// even though it does not. This allows you to inform the compiler about certain safety properties
Expand Down Expand Up @@ -444,6 +404,7 @@ mod impls {
/// [1]: http://en.wikipedia.org/wiki/Parametricity
#[rustc_reflect_like]
#[unstable(feature = "core", reason = "requires RFC and more experience")]
#[allow(deprecated)]
pub trait Reflect : MarkerTrait {
}

Expand Down
1 change: 1 addition & 0 deletions src/libcore/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use marker::{Sized, MarkerTrait};
use ops::Deref;

/// Unsafe trait to indicate what types are usable with the NonZero struct
#[allow(deprecated)]
pub unsafe trait Zeroable : MarkerTrait {}

unsafe impl<T:?Sized> Zeroable for *const T {}
Expand Down
1 change: 0 additions & 1 deletion src/librustc/middle/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,6 @@ lets_do_this! {
ExchangeHeapLangItem, "exchange_heap", exchange_heap;
OwnedBoxLangItem, "owned_box", owned_box;

PhantomFnItem, "phantom_fn", phantom_fn;
PhantomDataItem, "phantom_data", phantom_data;

// Deprecated:
Expand Down
9 changes: 4 additions & 5 deletions src/librustc/middle/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,10 @@ fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>,
match predicate {
ty::Predicate::Trait(ref data) => {
// In the case of a trait predicate, we can skip the "self" type.
Some(data.def_id()) != tcx.lang_items.phantom_fn() &&
data.0.trait_ref.substs.types.get_slice(TypeSpace)
.iter()
.cloned()
.any(is_self)
data.0.trait_ref.substs.types.get_slice(TypeSpace)
.iter()
.cloned()
.any(is_self)
}
ty::Predicate::Projection(..) |
ty::Predicate::TypeOutlives(..) |
Expand Down
8 changes: 0 additions & 8 deletions src/librustc/middle/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -836,14 +836,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ambiguous: false
};

// Check for the `PhantomFn` trait. This is really just a
// special annotation that is *always* considered to match, no
// matter what the type parameters are etc.
if self.tcx().lang_items.phantom_fn() == Some(obligation.predicate.def_id()) {
candidates.vec.push(PhantomFnCandidate);
return Ok(candidates);
}

// Other bounds. Consider both in-scope bounds from fn decl
// and applicable impls. There is a certain set of precedence rules here.

Expand Down
36 changes: 18 additions & 18 deletions src/librustc/middle/ty_relate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,11 @@ fn relate_item_substs<'a,'tcx:'a,R>(relation: &mut R,
relate_substs(relation, opt_variances, a_subst, b_subst)
}

fn relate_substs<'a,'tcx,R>(relation: &mut R,
variances: Option<&ty::ItemVariances>,
a_subst: &Substs<'tcx>,
b_subst: &Substs<'tcx>)
-> RelateResult<'tcx, Substs<'tcx>>
fn relate_substs<'a,'tcx:'a,R>(relation: &mut R,
variances: Option<&ty::ItemVariances>,
a_subst: &Substs<'tcx>,
b_subst: &Substs<'tcx>)
-> RelateResult<'tcx, Substs<'tcx>>
where R: TypeRelation<'a,'tcx>
{
let mut substs = Substs::empty();
Expand Down Expand Up @@ -161,11 +161,11 @@ fn relate_substs<'a,'tcx,R>(relation: &mut R,
Ok(substs)
}

fn relate_type_params<'a,'tcx,R>(relation: &mut R,
variances: Option<&[ty::Variance]>,
a_tys: &[Ty<'tcx>],
b_tys: &[Ty<'tcx>])
-> RelateResult<'tcx, Vec<Ty<'tcx>>>
fn relate_type_params<'a,'tcx:'a,R>(relation: &mut R,
variances: Option<&[ty::Variance]>,
a_tys: &[Ty<'tcx>],
b_tys: &[Ty<'tcx>])
-> RelateResult<'tcx, Vec<Ty<'tcx>>>
where R: TypeRelation<'a,'tcx>
{
if a_tys.len() != b_tys.len() {
Expand Down Expand Up @@ -264,10 +264,10 @@ impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::FnSig<'tcx> {
}
}

fn relate_arg_vecs<'a,'tcx,R>(relation: &mut R,
a_args: &[Ty<'tcx>],
b_args: &[Ty<'tcx>])
-> RelateResult<'tcx, Vec<Ty<'tcx>>>
fn relate_arg_vecs<'a,'tcx:'a,R>(relation: &mut R,
a_args: &[Ty<'tcx>],
b_args: &[Ty<'tcx>])
-> RelateResult<'tcx, Vec<Ty<'tcx>>>
where R: TypeRelation<'a,'tcx>
{
if a_args.len() != b_args.len() {
Expand Down Expand Up @@ -629,10 +629,10 @@ impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Box<T>
///////////////////////////////////////////////////////////////////////////
// Error handling

pub fn expected_found<'a,'tcx,R,T>(relation: &mut R,
a: &T,
b: &T)
-> ty::expected_found<T>
pub fn expected_found<'a,'tcx:'a,R,T>(relation: &mut R,
a: &T,
b: &T)
-> ty::expected_found<T>
where R: TypeRelation<'a,'tcx>, T: Clone
{
expected_found_bool(relation.a_is_expected(), a, b)
Expand Down
42 changes: 7 additions & 35 deletions src/librustc_typeck/check/wf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,10 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {

self.check_variances_for_type_defn(item, ast_generics);
}
ast::ItemTrait(_, ref ast_generics, _, ref items) => {
ast::ItemTrait(_, _, _, ref items) => {
let trait_predicates =
ty::lookup_predicates(ccx.tcx, local_def(item.id));
reject_non_type_param_bounds(
ccx.tcx,
item.span,
&trait_predicates);
self.check_variances(item, ast_generics, &trait_predicates,
self.tcx().lang_items.phantom_fn());
reject_non_type_param_bounds(ccx.tcx, item.span, &trait_predicates);
if ty::trait_has_default_impl(ccx.tcx, local_def(item.id)) {
if !items.is_empty() {
ccx.tcx.sess.span_err(
Expand Down Expand Up @@ -287,30 +282,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
ast_generics: &ast::Generics)
{
let item_def_id = local_def(item.id);
let predicates = ty::lookup_predicates(self.tcx(), item_def_id);
self.check_variances(item,
ast_generics,
&predicates,
self.tcx().lang_items.phantom_data());
}

fn check_variances(&self,
item: &ast::Item,
ast_generics: &ast::Generics,
ty_predicates: &ty::GenericPredicates<'tcx>,
suggested_marker_id: Option<ast::DefId>)
{
let variance_lang_items = &[
self.tcx().lang_items.phantom_fn(),
self.tcx().lang_items.phantom_data(),
];

let item_def_id = local_def(item.id);
let is_lang_item = variance_lang_items.iter().any(|n| *n == Some(item_def_id));
if is_lang_item {
return;
}

let ty_predicates = ty::lookup_predicates(self.tcx(), item_def_id);
let variances = ty::item_variances(self.tcx(), item_def_id);

let mut constrained_parameters: HashSet<_> =
Expand All @@ -331,7 +303,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
continue;
}
let span = self.ty_param_span(ast_generics, item, space, index);
self.report_bivariance(span, param_ty.name, suggested_marker_id);
self.report_bivariance(span, param_ty.name);
}

for (space, index, &variance) in variances.regions.iter_enumerated() {
Expand All @@ -342,7 +314,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
assert_eq!(space, TypeSpace);
let span = ast_generics.lifetimes[index].lifetime.span;
let name = ast_generics.lifetimes[index].lifetime.name;
self.report_bivariance(span, name, suggested_marker_id);
self.report_bivariance(span, name);
}
}

Expand Down Expand Up @@ -377,14 +349,14 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {

fn report_bivariance(&self,
span: Span,
param_name: ast::Name,
suggested_marker_id: Option<ast::DefId>)
param_name: ast::Name)
{
self.tcx().sess.span_err(
span,
&format!("parameter `{}` is never used",
param_name.user_string(self.tcx())));

let suggested_marker_id = self.tcx().lang_items.phantom_data();
match suggested_marker_id {
Some(def_id) => {
self.tcx().sess.fileline_help(
Expand Down
Loading