mirror of
https://github.com/rust-lang/rust
synced 2024-10-04 15:50:51 +00:00
Auto merge of #23938 - nikomatsakis:invariant, r=pnkfelix
There are still some remnants we could remove from the compiler (e.g. references to "subtraitrefs"; traits still have variance entries in the variance table), but this removes all user-visible bits I believe. r? @pnkfelix Fixes #22806 (since such traits would no longer exist)
This commit is contained in:
commit
2615106a46
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#[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.
|
||||
}
|
||||
|
@ -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.
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -269,84 +272,41 @@ fn clone(&self) -> $t<T> {
|
|||
)
|
||||
}
|
||||
|
||||
/// `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
|
||||
|
@ -444,6 +404,7 @@ unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {}
|
|||
/// [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 {
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
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 {}
|
||||
|
|
|
@ -321,7 +321,6 @@ pub fn collect_language_items(krate: &ast::Crate,
|
|||
ExchangeHeapLangItem, "exchange_heap", exchange_heap;
|
||||
OwnedBoxLangItem, "owned_box", owned_box;
|
||||
|
||||
PhantomFnItem, "phantom_fn", phantom_fn;
|
||||
PhantomDataItem, "phantom_data", phantom_data;
|
||||
|
||||
// Deprecated:
|
||||
|
|
|
@ -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(..) |
|
||||
|
|
|
@ -836,14 +836,6 @@ fn assemble_candidates<'o>(&mut self,
|
|||
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.
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
@ -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() {
|
||||
|
@ -264,10 +264,10 @@ fn relate<R>(relation: &mut R,
|
|||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
|
@ -629,10 +629,10 @@ fn relate<R>(relation: &mut R,
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// 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)
|
||||
|
|
|
@ -117,15 +117,10 @@ fn check_item_well_formed(&mut self, item: &ast::Item) {
|
|||
|
||||
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(
|
||||
|
@ -287,30 +282,7 @@ fn check_variances_for_type_defn(&self,
|
|||
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<_> =
|
||||
|
@ -331,7 +303,7 @@ fn check_variances(&self,
|
|||
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() {
|
||||
|
@ -342,7 +314,7 @@ fn check_variances(&self,
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -377,14 +349,14 @@ fn ty_param_span(&self,
|
|||
|
||||
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(
|
||||
|
|
|
@ -18,34 +18,121 @@
|
|||
//! defined on type `X`, we only consider the definition of the type `X`
|
||||
//! and the definitions of any types it references.
|
||||
//!
|
||||
//! We only infer variance for type parameters found on *types*: structs,
|
||||
//! enums, and traits. We do not infer variance for type parameters found
|
||||
//! on fns or impls. This is because those things are not type definitions
|
||||
//! and variance doesn't really make sense in that context.
|
||||
//!
|
||||
//! It is worth covering what variance means in each case. For structs and
|
||||
//! enums, I think it is fairly straightforward. The variance of the type
|
||||
//! We only infer variance for type parameters found on *data types*
|
||||
//! like structs and enums. In these cases, there is fairly straightforward
|
||||
//! explanation for what variance means. The variance of the type
|
||||
//! or lifetime parameters defines whether `T<A>` is a subtype of `T<B>`
|
||||
//! (resp. `T<'a>` and `T<'b>`) based on the relationship of `A` and `B`
|
||||
//! (resp. `'a` and `'b`). (FIXME #3598 -- we do not currently make use of
|
||||
//! the variances we compute for type parameters.)
|
||||
//! (resp. `'a` and `'b`).
|
||||
//!
|
||||
//! ### Variance on traits
|
||||
//! We do not infer variance for type parameters found on traits, fns,
|
||||
//! or impls. Variance on trait parameters can make indeed make sense
|
||||
//! (and we used to compute it) but it is actually rather subtle in
|
||||
//! meaning and not that useful in practice, so we removed it. See the
|
||||
//! addendum for some details. Variances on fn/impl parameters, otoh,
|
||||
//! doesn't make sense because these parameters are instantiated and
|
||||
//! then forgotten, they don't persist in types or compiled
|
||||
//! byproducts.
|
||||
//!
|
||||
//! The meaning of variance for trait parameters is more subtle and worth
|
||||
//! expanding upon. There are in fact two uses of the variance values we
|
||||
//! compute.
|
||||
//! ### The algorithm
|
||||
//!
|
||||
//! #### Trait variance and object types
|
||||
//! The basic idea is quite straightforward. We iterate over the types
|
||||
//! defined and, for each use of a type parameter X, accumulate a
|
||||
//! constraint indicating that the variance of X must be valid for the
|
||||
//! variance of that use site. We then iteratively refine the variance of
|
||||
//! X until all constraints are met. There is *always* a sol'n, because at
|
||||
//! the limit we can declare all type parameters to be invariant and all
|
||||
//! constraints will be satisfied.
|
||||
//!
|
||||
//! The first is for object types. Just as with structs and enums, we can
|
||||
//! decide the subtyping relationship between two object types `&Trait<A>`
|
||||
//! and `&Trait<B>` based on the relationship of `A` and `B`. Note that
|
||||
//! for object types we ignore the `Self` type parameter -- it is unknown,
|
||||
//! and the nature of dynamic dispatch ensures that we will always call a
|
||||
//! As a simple example, consider:
|
||||
//!
|
||||
//! enum Option<A> { Some(A), None }
|
||||
//! enum OptionalFn<B> { Some(|B|), None }
|
||||
//! enum OptionalMap<C> { Some(|C| -> C), None }
|
||||
//!
|
||||
//! Here, we will generate the constraints:
|
||||
//!
|
||||
//! 1. V(A) <= +
|
||||
//! 2. V(B) <= -
|
||||
//! 3. V(C) <= +
|
||||
//! 4. V(C) <= -
|
||||
//!
|
||||
//! These indicate that (1) the variance of A must be at most covariant;
|
||||
//! (2) the variance of B must be at most contravariant; and (3, 4) the
|
||||
//! variance of C must be at most covariant *and* contravariant. All of these
|
||||
//! results are based on a variance lattice defined as follows:
|
||||
//!
|
||||
//! * Top (bivariant)
|
||||
//! - +
|
||||
//! o Bottom (invariant)
|
||||
//!
|
||||
//! Based on this lattice, the solution V(A)=+, V(B)=-, V(C)=o is the
|
||||
//! optimal solution. Note that there is always a naive solution which
|
||||
//! just declares all variables to be invariant.
|
||||
//!
|
||||
//! You may be wondering why fixed-point iteration is required. The reason
|
||||
//! is that the variance of a use site may itself be a function of the
|
||||
//! variance of other type parameters. In full generality, our constraints
|
||||
//! take the form:
|
||||
//!
|
||||
//! V(X) <= Term
|
||||
//! Term := + | - | * | o | V(X) | Term x Term
|
||||
//!
|
||||
//! Here the notation V(X) indicates the variance of a type/region
|
||||
//! parameter `X` with respect to its defining class. `Term x Term`
|
||||
//! represents the "variance transform" as defined in the paper:
|
||||
//!
|
||||
//! If the variance of a type variable `X` in type expression `E` is `V2`
|
||||
//! and the definition-site variance of the [corresponding] type parameter
|
||||
//! of a class `C` is `V1`, then the variance of `X` in the type expression
|
||||
//! `C<E>` is `V3 = V1.xform(V2)`.
|
||||
//!
|
||||
//! ### Constraints
|
||||
//!
|
||||
//! If I have a struct or enum with where clauses:
|
||||
//!
|
||||
//! struct Foo<T:Bar> { ... }
|
||||
//!
|
||||
//! you might wonder whether the variance of `T` with respect to `Bar`
|
||||
//! affects the variance `T` with respect to `Foo`. I claim no. The
|
||||
//! reason: assume that `T` is invariant w/r/t `Bar` but covariant w/r/t
|
||||
//! `Foo`. And then we have a `Foo<X>` that is upcast to `Foo<Y>`, where
|
||||
//! `X <: Y`. However, while `X : Bar`, `Y : Bar` does not hold. In that
|
||||
//! case, the upcast will be illegal, but not because of a variance
|
||||
//! failure, but rather because the target type `Foo<Y>` is itself just
|
||||
//! not well-formed. Basically we get to assume well-formedness of all
|
||||
//! types involved before considering variance.
|
||||
//!
|
||||
//! ### Addendum: Variance on traits
|
||||
//!
|
||||
//! As mentioned above, we used to permit variance on traits. This was
|
||||
//! computed based on the appearance of trait type parameters in
|
||||
//! method signatures and was used to represent the compatibility of
|
||||
//! vtables in trait objects (and also "virtual" vtables or dictionary
|
||||
//! in trait bounds). One complication was that variance for
|
||||
//! associated types is less obvious, since they can be projected out
|
||||
//! and put to myriad uses, so it's not clear when it is safe to allow
|
||||
//! `X<A>::Bar` to vary (or indeed just what that means). Moreover (as
|
||||
//! covered below) all inputs on any trait with an associated type had
|
||||
//! to be invariant, limiting the applicability. Finally, the
|
||||
//! annotations (`MarkerTrait`, `PhantomFn`) needed to ensure that all
|
||||
//! trait type parameters had a variance were confusing and annoying
|
||||
//! for little benefit.
|
||||
//!
|
||||
//! Just for historical reference,I am going to preserve some text indicating
|
||||
//! how one could interpret variance and trait matching.
|
||||
//!
|
||||
//! #### Variance and object types
|
||||
//!
|
||||
//! Just as with structs and enums, we can decide the subtyping
|
||||
//! relationship between two object types `&Trait<A>` and `&Trait<B>`
|
||||
//! based on the relationship of `A` and `B`. Note that for object
|
||||
//! types we ignore the `Self` type parameter -- it is unknown, and
|
||||
//! the nature of dynamic dispatch ensures that we will always call a
|
||||
//! function that is expected the appropriate `Self` type. However, we
|
||||
//! must be careful with the other type parameters, or else we could end
|
||||
//! up calling a function that is expecting one type but provided another.
|
||||
//! must be careful with the other type parameters, or else we could
|
||||
//! end up calling a function that is expecting one type but provided
|
||||
//! another.
|
||||
//!
|
||||
//! To see what I mean, consider a trait like so:
|
||||
//!
|
||||
|
@ -135,104 +222,24 @@
|
|||
//!
|
||||
//! These conditions are satisfied and so we are happy.
|
||||
//!
|
||||
//! ### The algorithm
|
||||
//! #### Variance and associated types
|
||||
//!
|
||||
//! The basic idea is quite straightforward. We iterate over the types
|
||||
//! defined and, for each use of a type parameter X, accumulate a
|
||||
//! constraint indicating that the variance of X must be valid for the
|
||||
//! variance of that use site. We then iteratively refine the variance of
|
||||
//! X until all constraints are met. There is *always* a sol'n, because at
|
||||
//! the limit we can declare all type parameters to be invariant and all
|
||||
//! constraints will be satisfied.
|
||||
//!
|
||||
//! As a simple example, consider:
|
||||
//!
|
||||
//! enum Option<A> { Some(A), None }
|
||||
//! enum OptionalFn<B> { Some(|B|), None }
|
||||
//! enum OptionalMap<C> { Some(|C| -> C), None }
|
||||
//!
|
||||
//! Here, we will generate the constraints:
|
||||
//!
|
||||
//! 1. V(A) <= +
|
||||
//! 2. V(B) <= -
|
||||
//! 3. V(C) <= +
|
||||
//! 4. V(C) <= -
|
||||
//!
|
||||
//! These indicate that (1) the variance of A must be at most covariant;
|
||||
//! (2) the variance of B must be at most contravariant; and (3, 4) the
|
||||
//! variance of C must be at most covariant *and* contravariant. All of these
|
||||
//! results are based on a variance lattice defined as follows:
|
||||
//!
|
||||
//! * Top (bivariant)
|
||||
//! - +
|
||||
//! o Bottom (invariant)
|
||||
//!
|
||||
//! Based on this lattice, the solution V(A)=+, V(B)=-, V(C)=o is the
|
||||
//! optimal solution. Note that there is always a naive solution which
|
||||
//! just declares all variables to be invariant.
|
||||
//!
|
||||
//! You may be wondering why fixed-point iteration is required. The reason
|
||||
//! is that the variance of a use site may itself be a function of the
|
||||
//! variance of other type parameters. In full generality, our constraints
|
||||
//! take the form:
|
||||
//!
|
||||
//! V(X) <= Term
|
||||
//! Term := + | - | * | o | V(X) | Term x Term
|
||||
//!
|
||||
//! Here the notation V(X) indicates the variance of a type/region
|
||||
//! parameter `X` with respect to its defining class. `Term x Term`
|
||||
//! represents the "variance transform" as defined in the paper:
|
||||
//!
|
||||
//! If the variance of a type variable `X` in type expression `E` is `V2`
|
||||
//! and the definition-site variance of the [corresponding] type parameter
|
||||
//! of a class `C` is `V1`, then the variance of `X` in the type expression
|
||||
//! `C<E>` is `V3 = V1.xform(V2)`.
|
||||
//!
|
||||
//! ### Constraints
|
||||
//!
|
||||
//! If I have a struct or enum with where clauses:
|
||||
//!
|
||||
//! struct Foo<T:Bar> { ... }
|
||||
//!
|
||||
//! you might wonder whether the variance of `T` with respect to `Bar`
|
||||
//! affects the variance `T` with respect to `Foo`. I claim no. The
|
||||
//! reason: assume that `T` is invariant w/r/t `Bar` but covariant w/r/t
|
||||
//! `Foo`. And then we have a `Foo<X>` that is upcast to `Foo<Y>`, where
|
||||
//! `X <: Y`. However, while `X : Bar`, `Y : Bar` does not hold. In that
|
||||
//! case, the upcast will be illegal, but not because of a variance
|
||||
//! failure, but rather because the target type `Foo<Y>` is itself just
|
||||
//! not well-formed. Basically we get to assume well-formedness of all
|
||||
//! types involved before considering variance.
|
||||
//!
|
||||
//! ### Associated types
|
||||
//!
|
||||
//! Any trait with an associated type is invariant with respect to all
|
||||
//! of its inputs. To see why this makes sense, consider what
|
||||
//! subtyping for a trait reference means:
|
||||
//! Traits with associated types -- or at minimum projection
|
||||
//! expressions -- must be invariant with respect to all of their
|
||||
//! inputs. To see why this makes sense, consider what subtyping for a
|
||||
//! trait reference means:
|
||||
//!
|
||||
//! <T as Trait> <: <U as Trait>
|
||||
//!
|
||||
//! means that if I know that `T as Trait`,
|
||||
//! I also know that `U as
|
||||
//! Trait`. Moreover, if you think of it as
|
||||
//! dictionary passing style, it means that
|
||||
//! a dictionary for `<T as Trait>` is safe
|
||||
//! to use where a dictionary for `<U as
|
||||
//! Trait>` is expected.
|
||||
//! means that if I know that `T as Trait`, I also know that `U as
|
||||
//! Trait`. Moreover, if you think of it as dictionary passing style,
|
||||
//! it means that a dictionary for `<T as Trait>` is safe to use where
|
||||
//! a dictionary for `<U as Trait>` is expected.
|
||||
//!
|
||||
//! The problem is that when you can
|
||||
//! project types out from `<T as Trait>`,
|
||||
//! the relationship to types projected out
|
||||
//! of `<U as Trait>` is completely unknown
|
||||
//! unless `T==U` (see #21726 for more
|
||||
//! details). Making `Trait` invariant
|
||||
//! ensures that this is true.
|
||||
//!
|
||||
//! *Historical note: we used to preserve this invariant another way,
|
||||
//! by tweaking the subtyping rules and requiring that when a type `T`
|
||||
//! appeared as part of a projection, that was considered an invariant
|
||||
//! location, but this version does away with the need for those
|
||||
//! somewhat "special-case-feeling" rules.*
|
||||
//! The problem is that when you can project types out from `<T as
|
||||
//! Trait>`, the relationship to types projected out of `<U as Trait>`
|
||||
//! is completely unknown unless `T==U` (see #21726 for more
|
||||
//! details). Making `Trait` invariant ensures that this is true.
|
||||
//!
|
||||
//! Another related reason is that if we didn't make traits with
|
||||
//! associated types invariant, then projection is no longer a
|
||||
|
@ -383,7 +390,6 @@ fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>,
|
|||
|
||||
fn lang_items(tcx: &ty::ctxt) -> Vec<(ast::NodeId,Vec<ty::Variance>)> {
|
||||
let all = vec![
|
||||
(tcx.lang_items.phantom_fn(), vec![ty::Contravariant, ty::Covariant]),
|
||||
(tcx.lang_items.phantom_data(), vec![ty::Covariant]),
|
||||
(tcx.lang_items.unsafe_cell_type(), vec![ty::Invariant]),
|
||||
|
||||
|
@ -520,6 +526,9 @@ fn visit_item(&mut self, item: &ast::Item) {
|
|||
self.add_inferreds_for_item(item.id, false, generics);
|
||||
}
|
||||
ast::ItemTrait(_, ref generics, _, _) => {
|
||||
// Note: all inputs for traits are ultimately
|
||||
// constrained to be invariant. See `visit_item` in
|
||||
// the impl for `ConstraintContext` below.
|
||||
self.add_inferreds_for_item(item.id, true, generics);
|
||||
visit::walk_item(self, item);
|
||||
}
|
||||
|
@ -644,39 +653,9 @@ fn visit_item(&mut self, item: &ast::Item) {
|
|||
|
||||
ast::ItemTrait(..) => {
|
||||
let trait_def = ty::lookup_trait_def(tcx, did);
|
||||
let predicates = ty::lookup_super_predicates(tcx, did);
|
||||
self.add_constraints_from_predicates(&trait_def.generics,
|
||||
predicates.predicates.as_slice(),
|
||||
self.covariant);
|
||||
|
||||
let trait_items = ty::trait_items(tcx, did);
|
||||
for trait_item in &*trait_items {
|
||||
match *trait_item {
|
||||
ty::MethodTraitItem(ref method) => {
|
||||
self.add_constraints_from_predicates(
|
||||
&method.generics,
|
||||
method.predicates.predicates.get_slice(FnSpace),
|
||||
self.contravariant);
|
||||
|
||||
self.add_constraints_from_sig(
|
||||
&method.generics,
|
||||
&method.fty.sig,
|
||||
self.covariant);
|
||||
}
|
||||
ty::TypeTraitItem(ref data) => {
|
||||
// Any trait with an associated type is
|
||||
// invariant with respect to all of its
|
||||
// inputs. See length discussion in the comment
|
||||
// on this module.
|
||||
let projection_ty = ty::mk_projection(tcx,
|
||||
trait_def.trait_ref.clone(),
|
||||
data.name);
|
||||
self.add_constraints_from_ty(&trait_def.generics,
|
||||
projection_ty,
|
||||
self.invariant);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.add_constraints_from_trait_ref(&trait_def.generics,
|
||||
&trait_def.trait_ref,
|
||||
self.invariant);
|
||||
}
|
||||
|
||||
ast::ItemExternCrate(_) |
|
||||
|
@ -1045,69 +1024,6 @@ fn add_constraints_from_substs(&mut self,
|
|||
}
|
||||
}
|
||||
|
||||
fn add_constraints_from_predicates(&mut self,
|
||||
generics: &ty::Generics<'tcx>,
|
||||
predicates: &[ty::Predicate<'tcx>],
|
||||
variance: VarianceTermPtr<'a>) {
|
||||
debug!("add_constraints_from_generics({})",
|
||||
generics.repr(self.tcx()));
|
||||
|
||||
for predicate in predicates.iter() {
|
||||
match *predicate {
|
||||
ty::Predicate::Trait(ty::Binder(ref data)) => {
|
||||
self.add_constraints_from_trait_ref(generics, &*data.trait_ref, variance);
|
||||
}
|
||||
|
||||
ty::Predicate::Equate(ty::Binder(ref data)) => {
|
||||
// A == B is only true if A and B are the same
|
||||
// types, not subtypes of one another, so this is
|
||||
// an invariant position:
|
||||
self.add_constraints_from_ty(generics, data.0, self.invariant);
|
||||
self.add_constraints_from_ty(generics, data.1, self.invariant);
|
||||
}
|
||||
|
||||
ty::Predicate::TypeOutlives(ty::Binder(ref data)) => {
|
||||
// Why contravariant on both? Let's consider:
|
||||
//
|
||||
// Under what conditions is `(T:'t) <: (U:'u)`,
|
||||
// meaning that `(T:'t) => (U:'u)`. The answer is
|
||||
// if `U <: T` or `'u <= 't`. Let's see some examples:
|
||||
//
|
||||
// (T: 'big) => (T: 'small)
|
||||
// where 'small <= 'big
|
||||
//
|
||||
// (&'small Foo: 't) => (&'big Foo: 't)
|
||||
// where 'small <= 'big
|
||||
// note that &'big Foo <: &'small Foo
|
||||
|
||||
let variance_r = self.xform(variance, self.contravariant);
|
||||
self.add_constraints_from_ty(generics, data.0, variance_r);
|
||||
self.add_constraints_from_region(generics, data.1, variance_r);
|
||||
}
|
||||
|
||||
ty::Predicate::RegionOutlives(ty::Binder(ref data)) => {
|
||||
// `'a : 'b` is still true if 'a gets bigger
|
||||
self.add_constraints_from_region(generics, data.0, variance);
|
||||
|
||||
// `'a : 'b` is still true if 'b gets smaller
|
||||
let variance_r = self.xform(variance, self.contravariant);
|
||||
self.add_constraints_from_region(generics, data.1, variance_r);
|
||||
}
|
||||
|
||||
ty::Predicate::Projection(ty::Binder(ref data)) => {
|
||||
self.add_constraints_from_trait_ref(generics,
|
||||
&*data.projection_ty.trait_ref,
|
||||
variance);
|
||||
|
||||
// as the equality predicate above, a binder is a
|
||||
// type equality relation, not a subtyping
|
||||
// relation
|
||||
self.add_constraints_from_ty(generics, data.ty, self.invariant);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds constraints appropriate for a function with signature
|
||||
/// `sig` appearing in a context with ambient variance `variance`
|
||||
fn add_constraints_from_sig(&mut self,
|
||||
|
|
|
@ -11,9 +11,7 @@
|
|||
#![crate_type = "rlib"]
|
||||
#![feature(fundamental)]
|
||||
|
||||
use std::marker::MarkerTrait;
|
||||
|
||||
pub trait MyCopy : MarkerTrait { }
|
||||
pub trait MyCopy { }
|
||||
impl MyCopy for i32 { }
|
||||
|
||||
pub struct MyStruct<T>(T);
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub trait TheTrait<T> : ::std::marker::PhantomFn<T> {
|
||||
pub trait TheTrait<T> {
|
||||
fn the_fn(&self);
|
||||
}
|
||||
|
|
|
@ -12,12 +12,8 @@
|
|||
#![no_std]
|
||||
#![feature(lang_items)]
|
||||
|
||||
#[lang="phantom_fn"]
|
||||
pub trait PhantomFn<A:?Sized,R:?Sized=()> { }
|
||||
impl<A:?Sized, R:?Sized, U:?Sized> PhantomFn<A,R> for U { }
|
||||
|
||||
#[lang="sized"]
|
||||
pub trait Sized : PhantomFn<Self> {}
|
||||
pub trait Sized { }
|
||||
|
||||
#[lang="panic"]
|
||||
fn panic(_: &(&'static str, &'static str, usize)) -> ! { loop {} }
|
||||
|
@ -29,7 +25,7 @@ fn panic(_: &(&'static str, &'static str, usize)) -> ! { loop {} }
|
|||
extern fn eh_personality() {}
|
||||
|
||||
#[lang="copy"]
|
||||
pub trait Copy : PhantomFn<Self> {
|
||||
pub trait Copy {
|
||||
// Empty.
|
||||
}
|
||||
|
||||
|
|
|
@ -16,12 +16,8 @@
|
|||
#![feature(no_std)]
|
||||
#![no_std]
|
||||
|
||||
#[lang="phantom_fn"]
|
||||
pub trait PhantomFn<A:?Sized,R:?Sized=()> { }
|
||||
impl<A:?Sized, R:?Sized, U:?Sized> PhantomFn<A,R> for U { }
|
||||
|
||||
#[lang="sized"]
|
||||
pub trait Sized : PhantomFn<Self> {
|
||||
pub trait Sized {
|
||||
// Empty.
|
||||
}
|
||||
|
||||
|
|
|
@ -18,11 +18,9 @@
|
|||
|
||||
extern crate coherence_copy_like_lib as lib;
|
||||
|
||||
use std::marker::MarkerTrait;
|
||||
|
||||
struct MyType { x: i32 }
|
||||
|
||||
trait MyTrait : MarkerTrait { }
|
||||
trait MyTrait { }
|
||||
impl<T: lib::MyCopy> MyTrait for T { }
|
||||
|
||||
// `MyFundamentalStruct` is declared fundamental, so we can test that
|
||||
|
|
|
@ -18,11 +18,9 @@
|
|||
|
||||
extern crate coherence_copy_like_lib as lib;
|
||||
|
||||
use std::marker::MarkerTrait;
|
||||
|
||||
struct MyType { x: i32 }
|
||||
|
||||
trait MyTrait : MarkerTrait { }
|
||||
trait MyTrait { }
|
||||
impl<T: lib::MyCopy> MyTrait for T { }
|
||||
|
||||
// `MyFundamentalStruct` is declared fundamental, so we can test that
|
||||
|
|
|
@ -8,9 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::marker::PhantomFn;
|
||||
|
||||
trait FromStructReader<'a> : PhantomFn<(Self,&'a ())> { }
|
||||
trait FromStructReader<'a> { }
|
||||
trait ResponseHook {
|
||||
fn get<'a, T: FromStructReader<'a>>(&'a self);
|
||||
}
|
||||
|
|
|
@ -13,12 +13,8 @@
|
|||
#![feature(lang_items, start, no_std)]
|
||||
#![no_std]
|
||||
|
||||
#[lang="phantom_fn"]
|
||||
trait PhantomFn<A:?Sized,R:?Sized=()> { }
|
||||
impl<A:?Sized, R:?Sized, U:?Sized> PhantomFn<A,R> for U { }
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized : PhantomFn<Self> {}
|
||||
trait Sized { }
|
||||
|
||||
#[start]
|
||||
fn main(_: isize, _: *const *const u8) -> isize {
|
||||
|
|
|
@ -41,7 +41,7 @@ fn g<T>(val: T) {
|
|||
fn foo<'a>() {
|
||||
let t: S<&'a isize> = S(marker::PhantomData);
|
||||
let a = &t as &Gettable<&'a isize>;
|
||||
//~^ ERROR cannot infer
|
||||
//~^ ERROR does not fulfill
|
||||
}
|
||||
|
||||
fn foo2<'a>() {
|
||||
|
|
|
@ -12,18 +12,15 @@
|
|||
#![allow(dead_code)]
|
||||
#![deny(unsafe_code)]
|
||||
|
||||
use std::marker::PhantomFn;
|
||||
|
||||
struct Bar;
|
||||
struct Bar2;
|
||||
struct Bar3;
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
mod allowed_unsafe {
|
||||
use std::marker::PhantomFn;
|
||||
fn allowed() { unsafe {} }
|
||||
unsafe fn also_allowed() {}
|
||||
unsafe trait AllowedUnsafe : PhantomFn<Self> {}
|
||||
unsafe trait AllowedUnsafe { }
|
||||
unsafe impl AllowedUnsafe for super::Bar {}
|
||||
}
|
||||
|
||||
|
@ -34,7 +31,7 @@ macro_rules! unsafe_in_macro {
|
|||
}
|
||||
|
||||
unsafe fn baz() {} //~ ERROR: declaration of an `unsafe` function
|
||||
unsafe trait Foo : PhantomFn<Self> {} //~ ERROR: declaration of an `unsafe` trait
|
||||
unsafe trait Foo {} //~ ERROR: declaration of an `unsafe` trait
|
||||
unsafe impl Foo for Bar {} //~ ERROR: implementation of an `unsafe` trait
|
||||
|
||||
trait Baz {
|
||||
|
|
|
@ -13,12 +13,10 @@
|
|||
#![feature(rustc_attrs)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::marker::PhantomFn;
|
||||
|
||||
trait Baz : PhantomFn<Self> {
|
||||
trait Baz {
|
||||
}
|
||||
|
||||
trait Bar<T> : PhantomFn<(Self, T)> {
|
||||
trait Bar<T> {
|
||||
}
|
||||
|
||||
fn make_bar<T:Bar<u32>>(t: &T) -> &Bar<u32> {
|
||||
|
|
|
@ -13,11 +13,8 @@
|
|||
|
||||
#![allow(unused)]
|
||||
|
||||
use std::marker;
|
||||
|
||||
#[rustc_on_unimplemented = "test error `{Self}` with `{Bar}` `{Baz}` `{Quux}`"]
|
||||
trait Foo<Bar, Baz, Quux>
|
||||
: marker::PhantomFn<(Self,Bar,Baz,Quux)>
|
||||
{}
|
||||
|
||||
#[rustc_on_unimplemented="a collection of type `{Self}` cannot be built from an iterator over elements of type `{A}`"]
|
||||
|
@ -28,19 +25,16 @@ trait MyFromIterator<A> {
|
|||
|
||||
#[rustc_on_unimplemented] //~ ERROR this attribute must have a value
|
||||
trait BadAnnotation1
|
||||
: marker::MarkerTrait
|
||||
{}
|
||||
|
||||
#[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"]
|
||||
//~^ ERROR there is no type parameter C on trait BadAnnotation2
|
||||
trait BadAnnotation2<A,B>
|
||||
: marker::PhantomFn<(Self,A,B)>
|
||||
{}
|
||||
|
||||
#[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"]
|
||||
//~^ only named substitution parameters are allowed
|
||||
trait BadAnnotation3<A,B>
|
||||
: marker::PhantomFn<(Self,A,B)>
|
||||
{}
|
||||
|
||||
pub fn main() {
|
||||
|
|
|
@ -11,11 +11,8 @@
|
|||
|
||||
#![feature(on_unimplemented)]
|
||||
|
||||
use std::marker;
|
||||
|
||||
#[rustc_on_unimplemented = "test error `{Self}` with `{Bar}` `{Baz}` `{Quux}`"]
|
||||
trait Foo<Bar, Baz, Quux>
|
||||
: marker::PhantomFn<(Self,Bar,Baz,Quux)>
|
||||
{}
|
||||
|
||||
fn foobar<U: Clone, T: Foo<u8, U, u32>>() -> T {
|
||||
|
|
|
@ -11,15 +11,11 @@
|
|||
#![feature(lang_items, start, no_std)]
|
||||
#![no_std] // makes debugging this test *a lot* easier (during resolve)
|
||||
|
||||
#[lang="phantom_fn"]
|
||||
pub trait PhantomFn<A:?Sized,R:?Sized=()> { }
|
||||
impl<A:?Sized, R:?Sized, U:?Sized> PhantomFn<A,R> for U { }
|
||||
|
||||
#[lang="sized"]
|
||||
pub trait Sized : PhantomFn<Self> {}
|
||||
pub trait Sized {}
|
||||
|
||||
#[lang="copy"]
|
||||
pub trait Copy : PhantomFn<Self> {}
|
||||
pub trait Copy {}
|
||||
|
||||
mod bar {
|
||||
// shouldn't bring in too much
|
||||
|
|
|
@ -11,12 +11,8 @@
|
|||
#![feature(lang_items, start, no_std)]
|
||||
#![no_std] // makes debugging this test *a lot* easier (during resolve)
|
||||
|
||||
#[lang="phantom_fn"]
|
||||
pub trait PhantomFn<A:?Sized,R:?Sized=()> { }
|
||||
impl<A:?Sized, R:?Sized, U:?Sized> PhantomFn<A,R> for U { }
|
||||
|
||||
#[lang = "sized"] pub trait Sized : PhantomFn<Self> {}
|
||||
#[lang="copy"] pub trait Copy : PhantomFn<Self> {}
|
||||
#[lang = "sized"] pub trait Sized {}
|
||||
#[lang="copy"] pub trait Copy {}
|
||||
|
||||
// Test to make sure that private items imported through globs remain private
|
||||
// when they're used.
|
||||
|
|
|
@ -15,11 +15,9 @@
|
|||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::marker::PhantomFn;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub trait TheTrait: PhantomFn<Self, Self> {
|
||||
pub trait TheTrait {
|
||||
type TheAssocType;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,11 +14,9 @@
|
|||
#![allow(dead_code)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::marker::PhantomFn;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub trait TheTrait<'b> : PhantomFn<&'b Self,Self> {
|
||||
pub trait TheTrait<'b> {
|
||||
type TheAssocType;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,11 +15,9 @@
|
|||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::marker::PhantomFn;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub trait TheTrait: PhantomFn<Self, Self> {
|
||||
pub trait TheTrait {
|
||||
type TheAssocType;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,11 +15,9 @@
|
|||
#![allow(dead_code)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::marker::PhantomFn;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub trait TheTrait: PhantomFn<Self, Self> {
|
||||
pub trait TheTrait {
|
||||
type TheAssocType;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,12 +11,10 @@
|
|||
#![feature(box_syntax)]
|
||||
#![allow(warnings)]
|
||||
|
||||
use std::marker::PhantomFn;
|
||||
|
||||
trait A<T> : PhantomFn<(Self,T)> { }
|
||||
trait A<T> { }
|
||||
struct B<'a, T>(&'a (A<T>+'a));
|
||||
|
||||
trait X : ::std::marker::MarkerTrait {}
|
||||
trait X { }
|
||||
|
||||
impl<'a, T> X for B<'a, T> {}
|
||||
|
||||
|
|
|
@ -10,12 +10,10 @@
|
|||
|
||||
#![feature(box_syntax)]
|
||||
|
||||
use std::marker::PhantomFn;
|
||||
|
||||
trait A<T> : PhantomFn<(Self,T)> { }
|
||||
trait A<T> { }
|
||||
struct B<'a, T>(&'a (A<T>+'a));
|
||||
|
||||
trait X : PhantomFn<Self> {}
|
||||
trait X { }
|
||||
impl<'a, T> X for B<'a, T> {}
|
||||
|
||||
fn g<'a, T: 'static>(v: Box<A<T>+'a>) -> Box<X+'static> {
|
||||
|
|
|
@ -11,15 +11,13 @@
|
|||
#![feature(box_syntax)]
|
||||
#![allow(warnings)]
|
||||
|
||||
use std::marker::PhantomFn;
|
||||
|
||||
trait A<T> : PhantomFn<(Self,T)> {}
|
||||
trait A<T> { }
|
||||
struct B<'a, T>(&'a (A<T>+'a));
|
||||
|
||||
trait X : PhantomFn<Self> {}
|
||||
trait X { }
|
||||
impl<'a, T> X for B<'a, T> {}
|
||||
|
||||
fn h<'a, T, U>(v: Box<A<U>+'static>) -> Box<X+'static> {
|
||||
fn h<'a, T, U:'static>(v: Box<A<U>+'static>) -> Box<X+'static> {
|
||||
box B(&*v) as Box<X> //~ ERROR `*v` does not live long enough
|
||||
}
|
||||
|
||||
|
|
|
@ -10,12 +10,10 @@
|
|||
|
||||
#![feature(box_syntax)]
|
||||
|
||||
use std::marker::PhantomFn;
|
||||
|
||||
trait A<T> : PhantomFn<(Self,T)> {}
|
||||
trait A<T> { }
|
||||
struct B<'a, T>(&'a (A<T>+'a));
|
||||
|
||||
trait X : PhantomFn<Self> {}
|
||||
trait X { }
|
||||
impl<'a, T> X for B<'a, T> {}
|
||||
|
||||
fn i<'a, T, U>(v: Box<A<U>+'a>) -> Box<X+'static> {
|
||||
|
|
|
@ -11,11 +11,7 @@
|
|||
#![feature(lang_items, no_std)]
|
||||
#![no_std]
|
||||
|
||||
#[lang="phantom_fn"]
|
||||
pub trait PhantomFn<T:?Sized> { }
|
||||
impl<T:?Sized, U:?Sized> PhantomFn<T> for U { }
|
||||
|
||||
#[lang="sized"] pub trait Sized : PhantomFn<Self> {}
|
||||
#[lang="sized"] pub trait Sized { }
|
||||
|
||||
// error-pattern:requires `start` lang_item
|
||||
|
||||
|
|
|
@ -13,8 +13,7 @@
|
|||
|
||||
use std::marker;
|
||||
|
||||
trait A : marker::PhantomFn<Self> {
|
||||
}
|
||||
trait A { }
|
||||
|
||||
trait B: A {}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ trait Iterator<A> {
|
|||
}
|
||||
|
||||
trait IteratorUtil<A>
|
||||
: ::std::marker::PhantomFn<(),A>
|
||||
{
|
||||
fn zip<B, U: Iterator<U>>(self, other: U) -> ZipIterator<Self, U>;
|
||||
}
|
||||
|
|
|
@ -16,14 +16,12 @@
|
|||
#![feature(unboxed_closures)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::marker::PhantomFn;
|
||||
|
||||
trait Foo<T> {
|
||||
type Output;
|
||||
fn dummy(&self, t: T, u: Self::Output);
|
||||
}
|
||||
|
||||
trait Eq<X: ?Sized> : PhantomFn<(Self,X)> { }
|
||||
trait Eq<X: ?Sized> { }
|
||||
impl<X: ?Sized> Eq<X> for X { }
|
||||
fn eq<A: ?Sized,B: ?Sized +Eq<A>>() { }
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ trait Foo<T> {
|
|||
fn dummy(&self, t: T);
|
||||
}
|
||||
|
||||
trait Eq<X: ?Sized> : marker::PhantomFn<(Self, X)> { }
|
||||
trait Eq<X: ?Sized> { }
|
||||
impl<X: ?Sized> Eq<X> for X { }
|
||||
fn eq<A: ?Sized,B: ?Sized +Eq<A>>() { }
|
||||
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
|
||||
#![allow(dead_code)]
|
||||
|
||||
// Test that even when `T` is only used in contravariant position, it
|
||||
// is treated as invariant.
|
||||
|
||||
trait Get<T> : 'static {
|
||||
fn get(&self, t: T);
|
||||
}
|
||||
|
@ -25,7 +28,8 @@ fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
|
|||
-> Box<Get<&'max i32>>
|
||||
where 'max : 'min
|
||||
{
|
||||
v
|
||||
// Previously OK:
|
||||
v //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
|
||||
#![allow(dead_code)]
|
||||
|
||||
// Test that even when `T` is only used in contravariant position, it
|
||||
// is treated as invariant.
|
||||
|
||||
trait Get<T> {
|
||||
fn get(&self, t: T);
|
||||
}
|
||||
|
@ -23,7 +26,9 @@ fn get_min_from_max<'min, 'max, G>()
|
|||
fn get_max_from_min<'min, 'max, G>()
|
||||
where 'max : 'min, G : Get<&'min i32>
|
||||
{
|
||||
impls_get::<G,&'max i32>()
|
||||
// Previously OK, but now an error because traits are invariant:
|
||||
|
||||
impls_get::<G,&'max i32>() //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn impls_get<G,T>() where G : Get<T> { }
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
|
||||
#![allow(dead_code)]
|
||||
|
||||
// Test that even when `Self` is only used in contravariant position, it
|
||||
// is treated as invariant.
|
||||
|
||||
trait Get {
|
||||
fn get(&self);
|
||||
}
|
||||
|
@ -23,7 +26,10 @@ fn get_min_from_max<'min, 'max, G>()
|
|||
fn get_max_from_min<'min, 'max, G>()
|
||||
where 'max : 'min, G : 'max, &'min G : Get
|
||||
{
|
||||
impls_get::<&'max G>();
|
||||
// Previously OK, but now error because traits are invariant with
|
||||
// respect to all inputs.
|
||||
|
||||
impls_get::<&'max G>(); //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn impls_get<G>() where G : Get { }
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
|
||||
#![allow(dead_code)]
|
||||
|
||||
// Test that even when `T` is only used in covariant position, it
|
||||
// is treated as invariant.
|
||||
|
||||
trait Get<T> : 'static {
|
||||
fn get(&self) -> T;
|
||||
}
|
||||
|
@ -18,7 +21,8 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
|
|||
-> Box<Get<&'min i32>>
|
||||
where 'max : 'min
|
||||
{
|
||||
v
|
||||
// Previously OK, now an error as traits are invariant.
|
||||
v //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
|
||||
#![allow(dead_code)]
|
||||
|
||||
// Test that even when `T` is only used in covariant position, it
|
||||
// is treated as invariant.
|
||||
|
||||
trait Get<T> {
|
||||
fn get(&self) -> T;
|
||||
}
|
||||
|
@ -17,7 +20,8 @@ trait Get<T> {
|
|||
fn get_min_from_max<'min, 'max, G>()
|
||||
where 'max : 'min, G : Get<&'max i32>
|
||||
{
|
||||
impls_get::<G,&'min i32>()
|
||||
// Previously OK, now an error as traits are invariant.
|
||||
impls_get::<G,&'min i32>() //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn get_max_from_min<'min, 'max, G>()
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
|
||||
#![allow(dead_code)]
|
||||
|
||||
// Test that even when `Self` is only used in covariant position, it
|
||||
// is treated as invariant.
|
||||
|
||||
trait Get {
|
||||
fn get() -> Self;
|
||||
}
|
||||
|
@ -17,7 +20,8 @@ trait Get {
|
|||
fn get_min_from_max<'min, 'max, G>()
|
||||
where 'max : 'min, G : 'max, &'max G : Get
|
||||
{
|
||||
impls_get::<&'min G>();
|
||||
// Previously OK, now an error as traits are invariant.
|
||||
impls_get::<&'min G>(); //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn get_max_from_min<'min, 'max, G>()
|
||||
|
|
|
@ -13,11 +13,11 @@
|
|||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_variance]
|
||||
trait Foo: 'static { //~ ERROR types=[[];[-];[]]
|
||||
trait Foo: 'static { //~ ERROR types=[[];[o];[]]
|
||||
}
|
||||
|
||||
#[rustc_variance]
|
||||
trait Bar<T> { //~ ERROR types=[[+];[-];[]]
|
||||
trait Bar<T> { //~ ERROR types=[[o];[o];[]]
|
||||
fn do_it(&self)
|
||||
where T: 'static;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ struct Struct<'a, 'd> { //~ ERROR parameter `'d` is never used
|
|||
field: &'a [i32]
|
||||
}
|
||||
|
||||
trait Trait<'a, 'd> { //~ ERROR parameter `'d` is never used
|
||||
trait Trait<'a, 'd> { // OK on traits
|
||||
fn method(&'a self);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
// influence variance.
|
||||
|
||||
#[rustc_variance]
|
||||
trait Getter<T> { //~ ERROR types=[[+];[-];[]]
|
||||
trait Getter<T> { //~ ERROR types=[[o];[o];[]]
|
||||
fn get(&self) -> T;
|
||||
}
|
||||
|
||||
#[rustc_variance]
|
||||
trait Setter<T> { //~ ERROR types=[[-];[-];[]]
|
||||
trait Setter<T> { //~ ERROR types=[[o];[o];[]]
|
||||
fn get(&self, T);
|
||||
}
|
||||
|
||||
|
@ -37,16 +37,16 @@
|
|||
}
|
||||
|
||||
#[rustc_variance]
|
||||
trait TestTrait<U,T:Setter<U>> { //~ ERROR types=[[-, +];[-];[]]
|
||||
trait TestTrait<U,T:Setter<U>> { //~ ERROR types=[[o, o];[o];[]]
|
||||
fn getter(&self, u: U) -> T;
|
||||
}
|
||||
|
||||
#[rustc_variance]
|
||||
trait TestTrait2<U> : Getter<U> { //~ ERROR types=[[+];[-];[]]
|
||||
trait TestTrait2<U> : Getter<U> { //~ ERROR types=[[o];[o];[]]
|
||||
}
|
||||
|
||||
#[rustc_variance]
|
||||
trait TestTrait3<U> { //~ ERROR types=[[-];[-];[]]
|
||||
trait TestTrait3<U> { //~ ERROR types=[[o];[o];[]]
|
||||
fn getter<T:Getter<U>>(&self);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// 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.
|
||||
//
|
||||
|
@ -8,22 +8,43 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Issue #5781. Tests that subtyping is handled properly in trait matching.
|
||||
// pretty-expanded FIXME #23616
|
||||
|
||||
trait Make<'a> {
|
||||
fn make(x: &'a mut isize) -> Self;
|
||||
#![allow(dead_code)]
|
||||
|
||||
// Get<T> is covariant in T
|
||||
trait Get<T> {
|
||||
fn get(&self) -> T;
|
||||
}
|
||||
|
||||
impl<'a> Make<'a> for &'a mut isize {
|
||||
fn make(x: &'a mut isize) -> &'a mut isize {
|
||||
x
|
||||
struct Cloner<T:Clone> {
|
||||
t: T
|
||||
}
|
||||
|
||||
impl<T:Clone> Get<T> for Cloner<T> {
|
||||
fn get(&self) -> T {
|
||||
self.t.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn f() -> &'static mut isize {
|
||||
let mut x = 1;
|
||||
let y: &'static mut isize = Make::make(&mut x); //~ ERROR `x` does not live long enough
|
||||
y
|
||||
fn get<'a, G>(get: &G) -> i32
|
||||
where G : Get<&'a i32>
|
||||
{
|
||||
// This fails to type-check because, without variance, we can't
|
||||
// use `G : Get<&'a i32>` as evidence that `G : Get<&'b i32>`,
|
||||
// even if `'a : 'b`.
|
||||
pick(get, &22) //~ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
fn pick<'b, G>(get: &'b G, if_odd: &'b i32) -> i32
|
||||
where G : Get<&'b i32>
|
||||
{
|
||||
let v = *get.get();
|
||||
if v % 2 != 0 { v } else { *if_odd }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Cloner { t: &23 };
|
||||
let y = get(&x);
|
||||
assert_eq!(y, 23);
|
||||
}
|
||||
|
|
|
@ -37,12 +37,12 @@
|
|||
}
|
||||
|
||||
#[rustc_variance]
|
||||
trait Getter<A> { //~ ERROR types=[[+];[-];[]]
|
||||
trait Getter<A> { //~ ERROR types=[[o];[o];[]]
|
||||
fn get(&self) -> A;
|
||||
}
|
||||
|
||||
#[rustc_variance]
|
||||
trait Setter<A> { //~ ERROR types=[[-];[o];[]]
|
||||
trait Setter<A> { //~ ERROR types=[[o];[o];[]]
|
||||
fn set(&mut self, a: A);
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@
|
|||
}
|
||||
|
||||
#[rustc_variance]
|
||||
trait GetterInTypeBound<A> { //~ ERROR types=[[-];[-];[]]
|
||||
trait GetterInTypeBound<A> { //~ ERROR types=[[o];[o];[]]
|
||||
// Here, the use of `A` in the method bound *does* affect
|
||||
// variance. Think of it as if the method requested a dictionary
|
||||
// for `T:Getter<A>`. Since this dictionary is an input, it is
|
||||
|
@ -63,12 +63,12 @@
|
|||
}
|
||||
|
||||
#[rustc_variance]
|
||||
trait SetterInTypeBound<A> { //~ ERROR types=[[+];[-];[]]
|
||||
trait SetterInTypeBound<A> { //~ ERROR types=[[o];[o];[]]
|
||||
fn do_it<T:Setter<A>>(&self);
|
||||
}
|
||||
|
||||
#[rustc_variance]
|
||||
struct TestObject<A, R> { //~ ERROR types=[[-, +];[];[]]
|
||||
struct TestObject<A, R> { //~ ERROR types=[[o, o];[];[]]
|
||||
n: Box<Setter<A>+Send>,
|
||||
m: Box<Getter<R>+Send>,
|
||||
}
|
||||
|
|
|
@ -12,6 +12,6 @@
|
|||
|
||||
struct SomeStruct<'a> { x: u32 } //~ ERROR parameter `'a` is never used
|
||||
enum SomeEnum<'a> { Nothing } //~ ERROR parameter `'a` is never used
|
||||
trait SomeTrait<'a> { fn foo(&self); } //~ ERROR parameter `'a` is never used
|
||||
trait SomeTrait<'a> { fn foo(&self); } // OK on traits.
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -21,10 +21,6 @@ enum SomeEnum<A> { Nothing }
|
|||
//~^ ERROR parameter `A` is never used
|
||||
//~| HELP PhantomData
|
||||
|
||||
trait SomeTrait<A> { fn foo(&self); }
|
||||
//~^ ERROR parameter `A` is never used
|
||||
//~| HELP PhantomFn
|
||||
|
||||
// Here T might *appear* used, but in fact it isn't.
|
||||
enum ListCell<T> {
|
||||
//~^ ERROR parameter `T` is never used
|
||||
|
|
|
@ -70,14 +70,10 @@ pub fn bar(a: i32x4, b: i32x4) -> i32x4 {
|
|||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
pub trait Sized : PhantomFn<Self> {}
|
||||
pub trait Sized { }
|
||||
|
||||
#[lang = "copy"]
|
||||
pub trait Copy : PhantomFn<Self> {}
|
||||
|
||||
#[lang="phantom_fn"]
|
||||
pub trait PhantomFn<A:?Sized,R:?Sized=()> { }
|
||||
impl<A:?Sized, R:?Sized, U:?Sized> PhantomFn<A,R> for U { }
|
||||
pub trait Copy { }
|
||||
|
||||
mod core {
|
||||
pub mod marker {
|
||||
|
|
|
@ -11,15 +11,11 @@
|
|||
#![feature(lang_items, no_std)]
|
||||
#![no_std]
|
||||
|
||||
#[lang="phantom_fn"]
|
||||
trait PhantomFn<A:?Sized,R:?Sized=()> { }
|
||||
impl<A:?Sized, R:?Sized, U:?Sized> PhantomFn<A,R> for U { }
|
||||
|
||||
#[lang="copy"]
|
||||
trait Copy : PhantomFn<Self> { }
|
||||
trait Copy { }
|
||||
|
||||
#[lang="sized"]
|
||||
trait Sized : PhantomFn<Self> { }
|
||||
trait Sized { }
|
||||
|
||||
#[lang="start"]
|
||||
fn start(_main: *const u8, _argc: isize, _argv: *const *const u8) -> isize { 0 }
|
||||
|
|
|
@ -16,7 +16,6 @@ fn foo(&self) { }
|
|||
}
|
||||
|
||||
impl Contravariant for for<'a,'b> fn(&'a u8, &'b u8) {
|
||||
//~^ ERROR E0119
|
||||
}
|
||||
|
||||
impl Contravariant for for<'a> fn(&'a u8, &'a u8) {
|
||||
|
@ -29,7 +28,6 @@ fn foo(&self) { }
|
|||
}
|
||||
|
||||
impl Covariant for for<'a,'b> fn(&'a u8, &'b u8) {
|
||||
//~^ ERROR E0119
|
||||
}
|
||||
|
||||
impl Covariant for for<'a> fn(&'a u8, &'a u8) {
|
||||
|
@ -38,7 +36,7 @@ impl Covariant for for<'a> fn(&'a u8, &'a u8) {
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
trait Invariant {
|
||||
fn foo(&self) -> Self { }
|
||||
fn foo(&self) { }
|
||||
}
|
||||
|
||||
impl Invariant for for<'a,'b> fn(&'a u8, &'b u8) {
|
|
@ -15,11 +15,9 @@
|
|||
|
||||
extern crate coherence_copy_like_lib as lib;
|
||||
|
||||
use std::marker::MarkerTrait;
|
||||
|
||||
struct MyType { x: i32 }
|
||||
|
||||
trait MyTrait : MarkerTrait { }
|
||||
trait MyTrait { }
|
||||
impl<T: lib::MyCopy> MyTrait for T { }
|
||||
impl MyTrait for MyType { }
|
||||
impl<'a> MyTrait for &'a MyType { }
|
||||
|
|
|
@ -12,9 +12,7 @@
|
|||
|
||||
// pretty-expanded FIXME #23616
|
||||
|
||||
use std::marker::PhantomFn;
|
||||
|
||||
trait Chromosome<X: Chromosome<i32>> : PhantomFn<(Self,X)> {
|
||||
trait Chromosome<X: Chromosome<i32>> {
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
// pretty-expanded FIXME #23616
|
||||
|
||||
use std::marker::{PhantomData, PhantomFn};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct Handle<T, I>(T, I);
|
||||
|
||||
|
@ -34,7 +34,7 @@ pub fn get_info(&self) -> &String {
|
|||
|
||||
pub type RawBufferHandle<D: Device> = Handle<<D as Device>::Buffer, String>;
|
||||
|
||||
pub trait Device: PhantomFn<Self> {
|
||||
pub trait Device {
|
||||
type Buffer;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,9 +27,7 @@ pub trait Decoder<'v> {
|
|||
fn read(&mut self) -> Value<'v>;
|
||||
}
|
||||
|
||||
pub trait Decodable<'v, D: Decoder<'v>>
|
||||
: marker::PhantomFn<(), &'v isize>
|
||||
{
|
||||
pub trait Decodable<'v, D: Decoder<'v>> {
|
||||
fn decode(d: &mut D) -> Self;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,13 +17,11 @@
|
|||
#![allow(unknown_features)]
|
||||
#![feature(box_syntax)]
|
||||
|
||||
use std::marker::MarkerTrait;
|
||||
|
||||
trait Get {
|
||||
fn get(&self) -> Self;
|
||||
}
|
||||
|
||||
trait MyCopy : MarkerTrait { fn copy(&self) -> Self; }
|
||||
trait MyCopy { fn copy(&self) -> Self; }
|
||||
impl MyCopy for u16 { fn copy(&self) -> Self { *self } }
|
||||
impl MyCopy for u32 { fn copy(&self) -> Self { *self } }
|
||||
impl MyCopy for i32 { fn copy(&self) -> Self { *self } }
|
||||
|
|
|
@ -12,17 +12,17 @@
|
|||
|
||||
// pretty-expanded FIXME #23616
|
||||
|
||||
use std::marker::{PhantomData, PhantomFn};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
trait T1 : PhantomFn<Self> { }
|
||||
pub trait T2 : PhantomFn<Self> { }
|
||||
trait T3<X: T1> : T2 + PhantomFn<X> { }
|
||||
trait T4<X: ?Sized> : PhantomFn<(Self,X)> {}
|
||||
trait T5<X: ?Sized, Y> : PhantomFn<(Self,X,Y)> {}
|
||||
trait T6<Y, X: ?Sized> : PhantomFn<(Self,X,Y)> {}
|
||||
trait T7<X: ?Sized, Y: ?Sized> : PhantomFn<(Self,X,Y)> {}
|
||||
trait T8<X: ?Sized+T2> : PhantomFn<(Self,X)> {}
|
||||
trait T9<X: T2 + ?Sized> : PhantomFn<(Self,X)> {}
|
||||
trait T1 { }
|
||||
pub trait T2 { }
|
||||
trait T3<X: T1> : T2 { }
|
||||
trait T4<X: ?Sized> { }
|
||||
trait T5<X: ?Sized, Y> { }
|
||||
trait T6<Y, X: ?Sized> { }
|
||||
trait T7<X: ?Sized, Y: ?Sized> { }
|
||||
trait T8<X: ?Sized+T2> { }
|
||||
trait T9<X: T2 + ?Sized> { }
|
||||
struct S1<X: ?Sized>(PhantomData<X>);
|
||||
enum E<X: ?Sized> { E1(PhantomData<X>) }
|
||||
impl <X: ?Sized> T1 for S1<X> {}
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// pretty-expanded FIXME #23616
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
// Get<T> is covariant in T
|
||||
trait Get<T> {
|
||||
fn get(&self) -> T;
|
||||
}
|
||||
|
||||
struct Cloner<T:Clone> {
|
||||
t: T
|
||||
}
|
||||
|
||||
impl<T:Clone> Get<T> for Cloner<T> {
|
||||
fn get(&self) -> T {
|
||||
self.t.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn get<'a, G>(get: &G) -> i32
|
||||
where G : Get<&'a i32>
|
||||
{
|
||||
// This call only type checks if we can use `G : Get<&'a i32>` as
|
||||
// evidence that `G : Get<&'b i32>` where `'a : 'b`.
|
||||
pick(get, &22)
|
||||
}
|
||||
|
||||
fn pick<'b, G>(get: &'b G, if_odd: &'b i32) -> i32
|
||||
where G : Get<&'b i32>
|
||||
{
|
||||
let v = *get.get();
|
||||
if v % 2 != 0 { v } else { *if_odd }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Cloner { t: &23 };
|
||||
let y = get(&x);
|
||||
assert_eq!(y, 23);
|
||||
}
|
|
@ -13,18 +13,13 @@
|
|||
|
||||
// pretty-expanded FIXME #23616
|
||||
|
||||
use std::marker::PhantomFn;
|
||||
|
||||
static mut COUNT: u32 = 1;
|
||||
|
||||
trait Bar<'a>
|
||||
: PhantomFn<&'a ()>
|
||||
{
|
||||
trait Bar<'a> {
|
||||
fn bar(&self);
|
||||
}
|
||||
|
||||
trait Baz<'a>
|
||||
: PhantomFn<&'a ()>
|
||||
{
|
||||
fn baz(&self);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue