use cell::{Cell, RefCell, Ref, RefMut, BorrowState};
use char::CharExt;
use iter::{Iterator, IteratorExt};
-use marker::{Copy, Sized};
+use marker::{Copy, PhantomData, Sized};
use mem;
use option::Option;
use option::Option::{Some, None};
f.pad("()")
}
}
+impl<T> Debug for PhantomData<T> {
+ fn fmt(&self, f: &mut Formatter) -> Result {
+ f.pad("PhantomData")
+ }
+}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Copy + Debug> Debug for Cell<T> {
#![stable(feature = "rust1", since = "1.0.0")]
use clone::Clone;
+use cmp;
+use option::Option;
+use hash::Hash;
+use hash::Hasher;
/// Types able to be transferred across thread boundaries.
#[unstable(feature = "core",
#[lang="send"]
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
#[cfg(not(stage0))]
-pub unsafe trait Send {
+pub unsafe trait Send : MarkerTrait {
// empty.
}
#[stable(feature = "rust1", since = "1.0.0")]
#[lang="sized"]
#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"]
-pub trait Sized {
+pub trait Sized : MarkerTrait {
// Empty.
}
/// change: that second example would fail to compile if we made `Foo` non-`Copy`.
#[stable(feature = "rust1", since = "1.0.0")]
#[lang="copy"]
-pub trait Copy {
+pub trait Copy : MarkerTrait {
// Empty.
}
reason = "will be overhauled with new lifetime rules; see RFC 458")]
#[lang="sync"]
#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"]
-pub unsafe trait Sync {
+pub unsafe trait Sync : MarkerTrait {
// Empty
}
-/// A marker type that indicates to the compiler that the instances
-/// of the type itself owns instances of the type parameter `T`.
-///
-/// This is used to indicate that one or more instances of the type
-/// `T` could be dropped when instances of the type itself is dropped,
-/// though that may not be apparent from the other structure of the
-/// type itself. For example, the type may hold a `*mut T`, which the
-/// compiler does not automatically treat as owned.
-#[unstable(feature = "core",
- reason = "Newly added to deal with scoping and destructor changes")]
-#[lang="phantom_data"]
-#[derive(PartialEq, Eq, PartialOrd, Ord)]
-pub struct PhantomData<T: ?Sized>;
-
-impl<T: ?Sized> Copy for PhantomData<T> {}
-impl<T: ?Sized> Clone for PhantomData<T> {
- fn clone(&self) -> PhantomData<T> { *self }
-}
-
-/// A marker type whose type parameter `T` is considered to be
-/// covariant with respect to the type itself. This is (typically)
-/// used to indicate that an instance of the type `T` is being stored
-/// into memory and read from, even though that may not be apparent.
-///
-/// For more information about variance, refer to this Wikipedia
-/// article <http://en.wikipedia.org/wiki/Variance_%28computer_science%29>.
-///
-/// *Note:* It is very unusual to have to add a covariant constraint.
-/// If you are not sure, you probably want to use `InvariantType`.
-///
-/// # Example
-///
-/// Given a struct `S` that includes a type parameter `T`
-/// but does not actually *reference* that type parameter:
-///
-/// ```ignore
-/// use std::mem;
-///
-/// struct S<T> { x: *() }
-/// fn get<T>(s: &S<T>) -> T {
-/// unsafe {
-/// let x: *T = mem::transmute(s.x);
-/// *x
-/// }
-/// }
-/// ```
-///
-/// The type system would currently infer that the value of
-/// the type parameter `T` is irrelevant, and hence a `S<int>` is
-/// a subtype of `S<Box<int>>` (or, for that matter, `S<U>` for
-/// any `U`). But this is incorrect because `get()` converts the
-/// `*()` into a `*T` and reads from it. Therefore, we should include the
-/// a marker field `CovariantType<T>` to inform the type checker that
-/// `S<T>` is a subtype of `S<U>` if `T` is a subtype of `U`
-/// (for example, `S<&'static int>` is a subtype of `S<&'a int>`
-/// for some lifetime `'a`, but not the other way around).
-#[unstable(feature = "core",
- reason = "likely to change with new variance strategy")]
-#[lang="covariant_type"]
-#[derive(PartialEq, Eq, PartialOrd, Ord)]
-pub struct CovariantType<T: ?Sized>;
-
-impl<T: ?Sized> Copy for CovariantType<T> {}
-impl<T: ?Sized> Clone for CovariantType<T> {
- fn clone(&self) -> CovariantType<T> { *self }
-}
-
-/// A marker type whose type parameter `T` is considered to be
-/// contravariant with respect to the type itself. This is (typically)
-/// used to indicate that an instance of the type `T` will be consumed
-/// (but not read from), even though that may not be apparent.
-///
-/// For more information about variance, refer to this Wikipedia
-/// article <http://en.wikipedia.org/wiki/Variance_%28computer_science%29>.
-///
-/// *Note:* It is very unusual to have to add a contravariant constraint.
-/// If you are not sure, you probably want to use `InvariantType`.
-///
-/// # Example
-///
-/// Given a struct `S` that includes a type parameter `T`
-/// but does not actually *reference* that type parameter:
-///
-/// ```
-/// use std::mem;
-///
-/// struct S<T> { x: *const () }
-/// fn get<T>(s: &S<T>, v: T) {
-/// unsafe {
-/// let x: fn(T) = mem::transmute(s.x);
-/// x(v)
-/// }
-/// }
-/// ```
-///
-/// The type system would currently infer that the value of
-/// the type parameter `T` is irrelevant, and hence a `S<int>` is
-/// a subtype of `S<Box<int>>` (or, for that matter, `S<U>` for
-/// any `U`). But this is incorrect because `get()` converts the
-/// `*()` into a `fn(T)` and then passes a value of type `T` to it.
-///
-/// Supplying a `ContravariantType` marker would correct the
-/// problem, because it would mark `S` so that `S<T>` is only a
-/// subtype of `S<U>` if `U` is a subtype of `T`; given that the
-/// function requires arguments of type `T`, it must also accept
-/// arguments of type `U`, hence such a conversion is safe.
-#[unstable(feature = "core",
- reason = "likely to change with new variance strategy")]
-#[lang="contravariant_type"]
-#[derive(PartialEq, Eq, PartialOrd, Ord)]
-pub struct ContravariantType<T: ?Sized>;
-
-impl<T: ?Sized> Copy for ContravariantType<T> {}
-impl<T: ?Sized> Clone for ContravariantType<T> {
- fn clone(&self) -> ContravariantType<T> { *self }
-}
-
-/// A marker type whose type parameter `T` is considered to be
-/// invariant with respect to the type itself. This is (typically)
-/// used to indicate that instances of the type `T` may be read or
-/// written, even though that may not be apparent.
-///
-/// For more information about variance, refer to this Wikipedia
-/// article <http://en.wikipedia.org/wiki/Variance_%28computer_science%29>.
-///
-/// # Example
-///
-/// The Cell type is an example of an `InvariantType` which uses unsafe
-/// code to achieve "interior" mutability:
-///
-/// ```
-/// struct Cell<T> { value: T }
-/// ```
-///
-/// The type system would infer that `value` is only read here
-/// and never written, but in fact `Cell` uses unsafe code to achieve
-/// interior mutability. In order to get correct behavior, the
-/// `InvariantType` marker must be applied.
-#[unstable(feature = "core",
- reason = "likely to change with new variance strategy")]
-#[lang="invariant_type"]
-#[derive(PartialEq, Eq, PartialOrd, Ord)]
-pub struct InvariantType<T: ?Sized>;
-
-#[unstable(feature = "core",
- reason = "likely to change with new variance strategy")]
-impl<T: ?Sized> Copy for InvariantType<T> {}
-#[unstable(feature = "core",
- reason = "likely to change with new variance strategy")]
-impl<T: ?Sized> Clone for InvariantType<T> {
- fn clone(&self) -> InvariantType<T> { *self }
-}
-
-/// As `CovariantType`, but for lifetime parameters. Using
-/// `CovariantLifetime<'a>` indicates that it is ok to substitute
-/// a *longer* lifetime for `'a` than the one you originally
-/// started with (e.g., you could convert any lifetime `'foo` to
-/// `'static`). You almost certainly want `ContravariantLifetime`
-/// instead, or possibly `InvariantLifetime`. The only case where
-/// it would be appropriate is that you have a (type-casted, and
-/// hence hidden from the type system) function pointer with a
-/// signature like `fn(&'a T)` (and no other uses of `'a`). In
-/// this case, it is ok to substitute a larger lifetime for `'a`
-/// (e.g., `fn(&'static T)`), because the function is only
-/// becoming more selective in terms of what it accepts as
-/// argument.
-///
-/// For more information about variance, refer to this Wikipedia
-/// article <http://en.wikipedia.org/wiki/Variance_%28computer_science%29>.
-#[unstable(feature = "core",
- reason = "likely to change with new variance strategy")]
-#[lang="covariant_lifetime"]
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub struct CovariantLifetime<'a>;
-
-/// As `ContravariantType`, but for lifetime parameters. Using
-/// `ContravariantLifetime<'a>` indicates that it is ok to
-/// substitute a *shorter* lifetime for `'a` than the one you
-/// originally started with (e.g., you could convert `'static` to
-/// any lifetime `'foo`). This is appropriate for cases where you
-/// have an unsafe pointer that is actually a pointer into some
-/// memory with lifetime `'a`, and thus you want to limit the
-/// lifetime of your data structure to `'a`. An example of where
-/// this is used is the iterator for vectors.
-///
-/// For more information about variance, refer to this Wikipedia
-/// article <http://en.wikipedia.org/wiki/Variance_%28computer_science%29>.
-#[unstable(feature = "core",
- reason = "likely to change with new variance strategy")]
-#[lang="contravariant_lifetime"]
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub struct ContravariantLifetime<'a>;
-
-/// As `InvariantType`, but for lifetime parameters. Using
-/// `InvariantLifetime<'a>` indicates that it is not ok to
-/// substitute any other lifetime for `'a` besides its original
-/// value. This is appropriate for cases where you have an unsafe
-/// pointer that is actually a pointer into memory with lifetime `'a`,
-/// and this pointer is itself stored in an inherently mutable
-/// location (such as a `Cell`).
-#[unstable(feature = "core",
- reason = "likely to change with new variance strategy")]
-#[lang="invariant_lifetime"]
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub struct InvariantLifetime<'a>;
-
/// A type which is considered "not POD", meaning that it is not
/// implicitly copyable. This is typically embedded in other types to
/// ensure that they are never copied, even if they lack a destructor.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Managed;
+macro_rules! impls{
+ ($t: ident) => (
+ impl<T:?Sized, S: Hasher> Hash<S> for $t<T> {
+ #[inline]
+ fn hash(&self, _: &mut S) {
+ }
+ }
+
+ impl<T:?Sized> cmp::PartialEq for $t<T> {
+ fn eq(&self, _other: &$t<T>) -> bool {
+ true
+ }
+ }
+
+ impl<T:?Sized> cmp::Eq for $t<T> {
+ }
+
+ impl<T:?Sized> cmp::PartialOrd for $t<T> {
+ fn partial_cmp(&self, _other: &$t<T>) -> Option<cmp::Ordering> {
+ Option::Some(cmp::Ordering::Equal)
+ }
+ }
+
+ impl<T:?Sized> cmp::Ord for $t<T> {
+ fn cmp(&self, _other: &$t<T>) -> cmp::Ordering {
+ cmp::Ordering::Equal
+ }
+ }
+
+ impl<T:?Sized> Copy for $t<T> { }
+
+ impl<T:?Sized> Clone for $t<T> {
+ fn clone(&self) -> $t<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!
+pub trait MarkerTrait : PhantomFn<Self> { }
+impl<T:?Sized> MarkerTrait for T { }
+
+/// `PhantomFn` is a marker trait for use with traits that do not
+/// include any methods.
+///
+/// FIXME. Better documentation needed here!
+#[lang="phantom_fn"]
+pub trait PhantomFn<A:?Sized,R:?Sized=()> { }
+
+#[cfg(stage0)] // built into the trait matching system after stage0
+impl<A:?Sized, R:?Sized, U:?Sized> PhantomFn<A,R> for U { }
+
+/// Specific to stage0. You should not be seeing these docs!
+#[cfg(stage0)]
+#[lang="covariant_type"] // only relevant to stage0
+pub struct PhantomData<T:?Sized>;
+
+/// `PhantomData` is a way to tell the compiler about fake fields.
+/// The idea is that if the compiler encounters a `PhantomData<T>`
+/// instance, it will behave *as if* an instance of the type `T` were
+/// present for the purpose of various automatic analyses.
+///
+/// FIXME. Better documentation needed here!
+#[cfg(not(stage0))]
+#[lang="phantom_data"]
+pub struct PhantomData<T:?Sized>;
+
+impls! { PhantomData }
+
+
#[cfg(not(stage0))]
mod impls {
use super::{Send, Sync, Sized};
--- /dev/null
+// Copyright 2014 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.
+
+use middle::ty::{BuiltinBounds};
+use middle::ty::{self, Ty};
+use middle::ty::TyVar;
+use middle::infer::combine::*;
+use middle::infer::{cres};
+use middle::infer::type_variable::{BiTo};
+use util::ppaux::{Repr};
+
+use syntax::ast::{Unsafety};
+
+pub struct Bivariate<'f, 'tcx: 'f> {
+ fields: CombineFields<'f, 'tcx>
+}
+
+#[allow(non_snake_case)]
+pub fn Bivariate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Bivariate<'f, 'tcx> {
+ Bivariate { fields: cf }
+}
+
+impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> {
+ fn tag(&self) -> String { "Bivariate".to_string() }
+ fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
+
+ fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
+ -> cres<'tcx, Ty<'tcx>>
+ {
+ match v {
+ ty::Invariant => self.equate().tys(a, b),
+ ty::Covariant => self.tys(a, b),
+ ty::Contravariant => self.tys(a, b),
+ ty::Bivariant => self.tys(a, b),
+ }
+ }
+
+ fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
+ -> cres<'tcx, ty::Region>
+ {
+ match v {
+ ty::Invariant => self.equate().regions(a, b),
+ ty::Covariant => self.regions(a, b),
+ ty::Contravariant => self.regions(a, b),
+ ty::Bivariant => self.regions(a, b),
+ }
+ }
+
+ fn regions(&self, a: ty::Region, _: ty::Region) -> cres<'tcx, ty::Region> {
+ Ok(a)
+ }
+
+ fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> {
+ debug!("mts({} <: {})",
+ a.repr(self.fields.infcx.tcx),
+ b.repr(self.fields.infcx.tcx));
+
+ if a.mutbl != b.mutbl { return Err(ty::terr_mutability); }
+ let t = try!(self.tys(a.ty, b.ty));
+ Ok(ty::mt { mutbl: a.mutbl, ty: t })
+ }
+
+ fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> {
+ if a != b {
+ Err(ty::terr_unsafety_mismatch(expected_found(self, a, b)))
+ } else {
+ Ok(a)
+ }
+ }
+
+ fn builtin_bounds(&self,
+ a: BuiltinBounds,
+ b: BuiltinBounds)
+ -> cres<'tcx, BuiltinBounds>
+ {
+ if a != b {
+ Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
+ } else {
+ Ok(a)
+ }
+ }
+
+ fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
+ debug!("{}.tys({}, {})", self.tag(),
+ a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
+ if a == b { return Ok(a); }
+
+ let infcx = self.fields.infcx;
+ let a = infcx.type_variables.borrow().replace_if_possible(a);
+ let b = infcx.type_variables.borrow().replace_if_possible(b);
+ match (&a.sty, &b.sty) {
+ (&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => {
+ infcx.type_variables.borrow_mut().relate_vars(a_id, BiTo, b_id);
+ Ok(a)
+ }
+
+ (&ty::ty_infer(TyVar(a_id)), _) => {
+ try!(self.fields.instantiate(b, BiTo, a_id));
+ Ok(a)
+ }
+
+ (_, &ty::ty_infer(TyVar(b_id))) => {
+ try!(self.fields.instantiate(a, BiTo, b_id));
+ Ok(a)
+ }
+
+ _ => {
+ super_tys(self, a, b)
+ }
+ }
+ }
+
+ fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
+ where T : Combineable<'tcx>
+ {
+ let a1 = ty::erase_late_bound_regions(self.tcx(), a);
+ let b1 = ty::erase_late_bound_regions(self.tcx(), b);
+ let c = try!(Combineable::combine(self, &a1, &b1));
+ Ok(ty::Binder(c))
+ }
+}
// is also useful to track which value is the "expected" value in
// terms of error reporting.
+use super::bivariate::Bivariate;
use super::equate::Equate;
use super::glb::Glb;
use super::lub::Lub;
use super::unify::InferCtxtMethodsForSimplyUnifiableTypes;
use super::{InferCtxt, cres};
use super::{MiscVariable, TypeTrace};
-use super::type_variable::{RelationDir, EqTo, SubtypeOf, SupertypeOf};
+use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf};
use middle::subst;
use middle::subst::{ErasedRegions, NonerasedRegions, Substs};
use middle::ty::{BuiltinBounds};
use middle::ty::{self, Ty};
use middle::ty_fold;
-use middle::ty_fold::{TypeFoldable};
+use middle::ty_fold::{TypeFolder, TypeFoldable};
use util::ppaux::Repr;
use std::rc::Rc;
use syntax::codemap::Span;
pub trait Combine<'tcx> : Sized {
- fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx>;
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.infcx().tcx }
fn tag(&self) -> String;
- fn a_is_expected(&self) -> bool;
- fn trace(&self) -> TypeTrace<'tcx>;
- fn equate<'a>(&'a self) -> Equate<'a, 'tcx>;
- fn sub<'a>(&'a self) -> Sub<'a, 'tcx>;
- fn lub<'a>(&'a self) -> Lub<'a, 'tcx>;
- fn glb<'a>(&'a self) -> Glb<'a, 'tcx>;
+ fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx>;
+
+ fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields().infcx }
+ fn a_is_expected(&self) -> bool { self.fields().a_is_expected }
+ fn trace(&self) -> TypeTrace<'tcx> { self.fields().trace.clone() }
+ fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { self.fields().equate() }
+ fn bivariate<'a>(&'a self) -> Bivariate<'a, 'tcx> { self.fields().bivariate() }
+
+ fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { self.fields().sub() }
+ fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields().clone()) }
+ fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields().clone()) }
fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>>;
- fn contratys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>>;
+
+ fn tys_with_variance(&self, variance: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
+ -> cres<'tcx, Ty<'tcx>>;
+
fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>>;
- fn tps(&self,
- _: subst::ParamSpace,
- as_: &[Ty<'tcx>],
- bs: &[Ty<'tcx>])
- -> cres<'tcx, Vec<Ty<'tcx>>> {
- // FIXME -- In general, we treat variance a bit wrong
- // here. For historical reasons, we treat tps and Self
- // as invariant. This is overly conservative.
-
- if as_.len() != bs.len() {
- return Err(ty::terr_ty_param_size(expected_found(self,
- as_.len(),
- bs.len())));
- }
+ fn regions_with_variance(&self, variance: ty::Variance, a: ty::Region, b: ty::Region)
+ -> cres<'tcx, ty::Region>;
- try!(as_.iter().zip(bs.iter())
- .map(|(a, b)| self.equate().tys(*a, *b))
- .collect::<cres<Vec<Ty>>>());
- Ok(as_.to_vec())
- }
+ fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region>;
fn substs(&self,
item_def_id: ast::DefId,
b_subst: &subst::Substs<'tcx>)
-> cres<'tcx, subst::Substs<'tcx>>
{
+ debug!("substs: item_def_id={} a_subst={} b_subst={}",
+ item_def_id.repr(self.infcx().tcx),
+ a_subst.repr(self.infcx().tcx),
+ b_subst.repr(self.infcx().tcx));
+
let variances = if self.infcx().tcx.variance_computed.get() {
Some(ty::item_variances(self.infcx().tcx, item_def_id))
} else {
for &space in &subst::ParamSpace::all() {
let a_tps = a_subst.types.get_slice(space);
let b_tps = b_subst.types.get_slice(space);
- let tps = try!(self.tps(space, a_tps, b_tps));
+ let t_variances = variances.map(|v| v.types.get_slice(space));
+ let tps = try!(relate_type_params(self, t_variances, a_tps, b_tps));
substs.types.replace(space, tps);
}
for &space in &subst::ParamSpace::all() {
let a_regions = a.get_slice(space);
let b_regions = b.get_slice(space);
-
- let mut invariance = Vec::new();
- let r_variances = match variances {
- Some(variances) => {
- variances.regions.get_slice(space)
- }
- None => {
- for _ in a_regions {
- invariance.push(ty::Invariant);
- }
- &invariance[]
- }
- };
-
+ let r_variances = variances.map(|v| v.regions.get_slice(space));
let regions = try!(relate_region_params(self,
r_variances,
a_regions,
return Ok(substs);
+ fn relate_type_params<'tcx, C: Combine<'tcx>>(this: &C,
+ variances: Option<&[ty::Variance]>,
+ a_tys: &[Ty<'tcx>],
+ b_tys: &[Ty<'tcx>])
+ -> cres<'tcx, Vec<Ty<'tcx>>>
+ {
+ if a_tys.len() != b_tys.len() {
+ return Err(ty::terr_ty_param_size(expected_found(this,
+ a_tys.len(),
+ b_tys.len())));
+ }
+
+ range(0, a_tys.len()).map(|i| {
+ let a_ty = a_tys[i];
+ let b_ty = b_tys[i];
+ let v = variances.map_or(ty::Invariant, |v| v[i]);
+ this.tys_with_variance(v, a_ty, b_ty)
+ }).collect()
+ }
+
fn relate_region_params<'tcx, C: Combine<'tcx>>(this: &C,
- variances: &[ty::Variance],
+ variances: Option<&[ty::Variance]>,
a_rs: &[ty::Region],
b_rs: &[ty::Region])
- -> cres<'tcx, Vec<ty::Region>> {
+ -> cres<'tcx, Vec<ty::Region>>
+ {
let tcx = this.infcx().tcx;
- let num_region_params = variances.len();
+ let num_region_params = a_rs.len();
debug!("relate_region_params(\
a_rs={}, \
b_rs.repr(tcx),
variances.repr(tcx));
- assert_eq!(num_region_params, a_rs.len());
+ assert_eq!(num_region_params,
+ variances.map_or(num_region_params,
+ |v| v.len()));
+
assert_eq!(num_region_params, b_rs.len());
- let mut rs = vec!();
- for i in 0..num_region_params {
+
+ (0..a_rs.len()).map(|i| {
let a_r = a_rs[i];
let b_r = b_rs[i];
- let variance = variances[i];
- let r = match variance {
- ty::Invariant => this.equate().regions(a_r, b_r),
- ty::Covariant => this.regions(a_r, b_r),
- ty::Contravariant => this.contraregions(a_r, b_r),
- ty::Bivariant => Ok(a_r),
- };
- rs.push(try!(r));
- }
- Ok(rs)
+ let variance = variances.map_or(ty::Invariant, |v| v[i]);
+ this.regions_with_variance(variance, a_r, b_r)
+ }).collect()
}
}
}
fn args(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
- self.contratys(a, b).and_then(|t| Ok(t))
+ self.tys_with_variance(ty::Contravariant, a, b).and_then(|t| Ok(t))
}
fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety>;
b: &ty::ExistentialBounds<'tcx>)
-> cres<'tcx, ty::ExistentialBounds<'tcx>>
{
- let r = try!(self.contraregions(a.region_bound, b.region_bound));
+ let r = try!(self.regions_with_variance(ty::Contravariant, a.region_bound, b.region_bound));
let nb = try!(self.builtin_bounds(a.builtin_bounds, b.builtin_bounds));
let pb = try!(self.projection_bounds(&a.projection_bounds, &b.projection_bounds));
Ok(ty::ExistentialBounds { region_bound: r,
b: ty::BuiltinBounds)
-> cres<'tcx, ty::BuiltinBounds>;
- fn contraregions(&self, a: ty::Region, b: ty::Region)
- -> cres<'tcx, ty::Region>;
-
- fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region>;
-
fn trait_refs(&self,
a: &ty::TraitRef<'tcx>,
b: &ty::TraitRef<'tcx>)
}
(&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => {
- let r = try!(this.contraregions(*a_r, *b_r));
+ let r = try!(this.regions_with_variance(ty::Contravariant, *a_r, *b_r));
+
// FIXME(14985) If we have mutable references to trait objects, we
// used to use covariant subtyping. I have preserved this behaviour,
// even though it is probably incorrect. So don't go down the usual
Equate((*self).clone())
}
+ fn bivariate(&self) -> Bivariate<'f, 'tcx> {
+ Bivariate((*self).clone())
+ }
+
fn sub(&self) -> Sub<'f, 'tcx> {
Sub((*self).clone())
}
EqTo => {
self.generalize(a_ty, b_vid, false)
}
- SupertypeOf | SubtypeOf => {
+ BiTo | SupertypeOf | SubtypeOf => {
self.generalize(a_ty, b_vid, true)
}
});
// to associate causes/spans with each of the relations in
// the stack to get this right.
match dir {
+ BiTo => {
+ try!(self.bivariate().tys(a_ty, b_ty));
+ }
+
EqTo => {
try!(self.equate().tys(a_ty, b_ty));
}
}
SupertypeOf => {
- try!(self.sub().contratys(a_ty, b_ty));
+ try!(self.sub().tys_with_variance(ty::Contravariant, a_ty, b_ty));
}
}
}
use middle::ty::TyVar;
use middle::infer::combine::*;
use middle::infer::{cres};
-use middle::infer::glb::Glb;
-use middle::infer::InferCtxt;
-use middle::infer::lub::Lub;
-use middle::infer::sub::Sub;
-use middle::infer::{TypeTrace, Subtype};
+use middle::infer::{Subtype};
use middle::infer::type_variable::{EqTo};
use util::ppaux::{Repr};
}
impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> {
- fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields.infcx }
- fn tag(&self) -> String { "eq".to_string() }
- fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
- fn trace(&self) -> TypeTrace<'tcx> { self.fields.trace.clone() }
+ fn tag(&self) -> String { "Equate".to_string() }
+ fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
- fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { Equate(self.fields.clone()) }
- fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { Sub(self.fields.clone()) }
- fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields.clone()) }
- fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields.clone()) }
-
- fn contratys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
+ fn tys_with_variance(&self, _: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
+ -> cres<'tcx, Ty<'tcx>>
+ {
+ // Once we're equating, it doesn't matter what the variance is.
self.tys(a, b)
}
- fn contraregions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
+ fn regions_with_variance(&self, _: ty::Variance, a: ty::Region, b: ty::Region)
+ -> cres<'tcx, ty::Region>
+ {
+ // Once we're equating, it doesn't matter what the variance is.
self.regions(a, b)
}
use super::combine::*;
use super::lattice::*;
-use super::equate::Equate;
use super::higher_ranked::HigherRankedRelations;
-use super::lub::Lub;
-use super::sub::Sub;
-use super::{cres, InferCtxt};
-use super::{TypeTrace, Subtype};
+use super::{cres};
+use super::Subtype;
use middle::ty::{BuiltinBounds};
use middle::ty::{self, Ty};
}
impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> {
- fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields.infcx }
- fn tag(&self) -> String { "glb".to_string() }
- fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
- fn trace(&self) -> TypeTrace<'tcx> { self.fields.trace.clone() }
+ fn tag(&self) -> String { "Glb".to_string() }
+ fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
- fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { Equate(self.fields.clone()) }
- fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { Sub(self.fields.clone()) }
- fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields.clone()) }
- fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields.clone()) }
+ fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
+ -> cres<'tcx, Ty<'tcx>>
+ {
+ match v {
+ ty::Invariant => self.equate().tys(a, b),
+ ty::Covariant => self.tys(a, b),
+ ty::Bivariant => self.bivariate().tys(a, b),
+ ty::Contravariant => self.lub().tys(a, b),
+ }
+ }
+
+ fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
+ -> cres<'tcx, ty::Region>
+ {
+ match v {
+ ty::Invariant => self.equate().regions(a, b),
+ ty::Covariant => self.regions(a, b),
+ ty::Bivariant => self.bivariate().regions(a, b),
+ ty::Contravariant => self.lub().regions(a, b),
+ }
+ }
fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> {
let tcx = self.fields.infcx.tcx;
}
}
- fn contratys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
- self.lub().tys(a, b)
- }
-
fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> {
match (a, b) {
(Unsafety::Normal, _) | (_, Unsafety::Normal) => Ok(Unsafety::Normal),
Ok(self.fields.infcx.region_vars.glb_regions(Subtype(self.trace()), a, b))
}
- fn contraregions(&self, a: ty::Region, b: ty::Region)
- -> cres<'tcx, ty::Region> {
- self.lub().regions(a, b)
- }
-
fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
super_lattice_tys(self, a, b)
}
// except according to those terms.
use super::combine::*;
-use super::equate::Equate;
-use super::glb::Glb;
use super::higher_ranked::HigherRankedRelations;
use super::lattice::*;
-use super::sub::Sub;
-use super::{cres, InferCtxt};
-use super::{TypeTrace, Subtype};
+use super::{cres};
+use super::{Subtype};
use middle::ty::{BuiltinBounds};
use middle::ty::{self, Ty};
}
impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> {
- fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields.infcx }
- fn tag(&self) -> String { "lub".to_string() }
- fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
- fn trace(&self) -> TypeTrace<'tcx> { self.fields.trace.clone() }
+ fn tag(&self) -> String { "Lub".to_string() }
+ fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
- fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { Equate(self.fields.clone()) }
- fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { Sub(self.fields.clone()) }
- fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields.clone()) }
- fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields.clone()) }
+ fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
+ -> cres<'tcx, Ty<'tcx>>
+ {
+ match v {
+ ty::Invariant => self.equate().tys(a, b),
+ ty::Covariant => self.tys(a, b),
+ ty::Bivariant => self.bivariate().tys(a, b),
+ ty::Contravariant => self.glb().tys(a, b),
+ }
+ }
+
+ fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
+ -> cres<'tcx, ty::Region>
+ {
+ match v {
+ ty::Invariant => self.equate().regions(a, b),
+ ty::Covariant => self.regions(a, b),
+ ty::Bivariant => self.bivariate().regions(a, b),
+ ty::Contravariant => self.glb().regions(a, b),
+ }
+ }
fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> {
let tcx = self.tcx();
}
}
- fn contratys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
- self.glb().tys(a, b)
- }
-
fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> {
match (a, b) {
(Unsafety::Unsafe, _) | (_, Unsafety::Unsafe) => Ok(Unsafety::Unsafe),
Ok(a.intersection(b))
}
- fn contraregions(&self, a: ty::Region, b: ty::Region)
- -> cres<'tcx, ty::Region> {
- self.glb().regions(a, b)
- }
-
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
debug!("{}.regions({}, {})",
self.tag(),
use self::unify::{UnificationTable, InferCtxtMethodsForSimplyUnifiableTypes};
use self::error_reporting::ErrorReporting;
+pub mod bivariate;
pub mod combine;
pub mod equate;
pub mod error_reporting;
use super::combine::*;
use super::{cres, CresCompare};
-use super::equate::Equate;
-use super::glb::Glb;
use super::higher_ranked::HigherRankedRelations;
-use super::InferCtxt;
-use super::lub::Lub;
-use super::{TypeTrace, Subtype};
+use super::{Subtype};
use super::type_variable::{SubtypeOf, SupertypeOf};
use middle::ty::{BuiltinBounds};
}
impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
- fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields.infcx }
- fn tag(&self) -> String { "sub".to_string() }
- fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
- fn trace(&self) -> TypeTrace<'tcx> { self.fields.trace.clone() }
-
- fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { Equate(self.fields.clone()) }
- fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { Sub(self.fields.clone()) }
- fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields.clone()) }
- fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields.clone()) }
-
- fn contratys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
- Sub(self.fields.switch_expected()).tys(b, a)
+ fn tag(&self) -> String { "Sub".to_string() }
+ fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
+
+ fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
+ -> cres<'tcx, Ty<'tcx>>
+ {
+ // Once we're equating, it doesn't matter what the variance is.
+ match v {
+ ty::Invariant => self.equate().tys(a, b),
+ ty::Covariant => self.tys(a, b),
+ ty::Bivariant => self.bivariate().tys(a, b),
+ ty::Contravariant => Sub(self.fields.switch_expected()).tys(b, a),
+ }
}
- fn contraregions(&self, a: ty::Region, b: ty::Region)
- -> cres<'tcx, ty::Region> {
- let opp = CombineFields {
- a_is_expected: !self.fields.a_is_expected,
- ..self.fields.clone()
- };
- Sub(opp).regions(b, a)
- }
+ fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
+ -> cres<'tcx, ty::Region>
+ {
+ match v {
+ ty::Invariant => self.equate().regions(a, b),
+ ty::Covariant => self.regions(a, b),
+ ty::Bivariant => self.bivariate().regions(a, b),
+ ty::Contravariant => Sub(self.fields.switch_expected()).regions(b, a),
+ }
+ }
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
debug!("{}.regions({}, {})",
#[derive(Copy, PartialEq, Debug)]
pub enum RelationDir {
- SubtypeOf, SupertypeOf, EqTo
+ SubtypeOf, SupertypeOf, EqTo, BiTo
}
impl RelationDir {
match self {
SubtypeOf => SupertypeOf,
SupertypeOf => SubtypeOf,
- EqTo => EqTo
+ EqTo => EqTo,
+ BiTo => BiTo,
}
}
}
ExchangeHeapLangItem, "exchange_heap", exchange_heap;
OwnedBoxLangItem, "owned_box", owned_box;
+ PhantomFnItem, "phantom_fn", phantom_fn;
PhantomDataItem, "phantom_data", phantom_data;
- CovariantTypeItem, "covariant_type", covariant_type;
- ContravariantTypeItem, "contravariant_type", contravariant_type;
- InvariantTypeItem, "invariant_type", invariant_type;
-
- CovariantLifetimeItem, "covariant_lifetime", covariant_lifetime;
- ContravariantLifetimeItem, "contravariant_lifetime", contravariant_lifetime;
- InvariantLifetimeItem, "invariant_lifetime", invariant_lifetime;
-
NoCopyItem, "no_copy_bound", no_copy_bound;
ManagedItem, "managed_bound", managed_bound;
/// parameters) that would have to be inferred from the impl.
#[derive(PartialEq,Eq,Debug,Clone)]
enum SelectionCandidate<'tcx> {
+ PhantomFnCandidate,
BuiltinCandidate(ty::BuiltinBound),
ParamCandidate(ty::PolyTraitRef<'tcx>),
ImplCandidate(ast::DefId),
stack: &TraitObligationStack<'o, 'tcx>)
-> Result<SelectionCandidateSet<'tcx>, SelectionError<'tcx>>
{
- // Check for overflow.
-
let TraitObligationStack { obligation, .. } = *stack;
let mut candidates = SelectionCandidateSet {
ambiguous: false
};
+ // Check for the `PhantomFn` trait. This is really just a special annotation that
+ // *always* be considered to match, no matter what the type parameters 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.
try!(self.confirm_builtin_candidate(obligation, builtin_bound))))
}
+ PhantomFnCandidate |
ErrorCandidate => {
Ok(VtableBuiltin(VtableBuiltinData { nested: VecPerParamSpace::empty() }))
}
impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self {
+ PhantomFnCandidate => format!("PhantomFnCandidate"),
ErrorCandidate => format!("ErrorCandidate"),
BuiltinCandidate(b) => format!("BuiltinCandidate({:?})", b),
ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)),
--- /dev/null
+// 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.
+
+use middle::ty::{self};
+
+use std::collections::HashSet;
+use std::rc::Rc;
+
+pub fn identify_constrained_type_params<'tcx>(_tcx: &ty::ctxt<'tcx>,
+ predicates: &[ty::Predicate<'tcx>],
+ impl_trait_ref: Option<Rc<ty::TraitRef<'tcx>>>,
+ input_parameters: &mut HashSet<ty::ParamTy>)
+{
+ loop {
+ let num_inputs = input_parameters.len();
+
+ let projection_predicates =
+ predicates.iter()
+ .filter_map(|predicate| {
+ match *predicate {
+ // Ignore higher-ranked binders. For the purposes
+ // of this check, they don't matter because they
+ // only affect named regions, and we're just
+ // concerned about type parameters here.
+ ty::Predicate::Projection(ref data) => Some(data.0.clone()),
+ _ => None,
+ }
+ });
+
+ for projection in projection_predicates {
+ // Special case: watch out for some kind of sneaky attempt
+ // to project out an associated type defined by this very trait.
+ if Some(projection.projection_ty.trait_ref.clone()) == impl_trait_ref {
+ continue;
+ }
+
+ let relies_only_on_inputs =
+ projection.projection_ty.trait_ref.input_types()
+ .iter()
+ .flat_map(|t| t.walk())
+ .filter_map(|t| t.as_opt_param_ty())
+ .all(|t| input_parameters.contains(&t));
+
+ if relies_only_on_inputs {
+ input_parameters.extend(
+ projection.ty.walk().filter_map(|t| t.as_opt_param_ty()));
+ }
+ }
+
+ if input_parameters.len() == num_inputs {
+ break;
+ }
+ }
+}
//! 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.
use self::VarianceTerm::*;
use self::ParamKind::*;
use middle::ty::{self, Ty};
use std::fmt;
use std::rc::Rc;
-use std::iter::repeat;
use syntax::ast;
use syntax::ast_map;
use syntax::ast_util;
empty_variances: Rc<ty::ItemVariances>,
+ // For marker types, UnsafeCell, and other lang items where
+ // variance is hardcoded, records the item-id and the hardcoded
+ // variance.
+ lang_items: Vec<(ast::NodeId, Vec<ty::Variance>)>,
+
// Maps from the node id of a type/generic parameter to the
// corresponding inferred index.
inferred_map: NodeMap<InferredIndex>,
#[derive(Copy, Debug, PartialEq)]
enum ParamKind {
TypeParam,
- RegionParam
+ RegionParam,
}
struct InferredInfo<'a> {
index: uint,
param_id: ast::NodeId,
term: VarianceTermPtr<'a>,
+
+ // Initial value to use for this parameter when inferring
+ // variance. For most parameters, this is Bivariant. But for lang
+ // items and input type parameters on traits, it is different.
+ initial_variance: ty::Variance,
}
fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>,
inferred_map: NodeMap(),
inferred_infos: Vec::new(),
+ lang_items: lang_items(tcx),
+
// cache and share the variance struct used for items with
// no type/region parameters
empty_variances: Rc::new(ty::ItemVariances {
terms_cx
}
+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])];
+
+ all.into_iter()
+ .filter(|&(ref d,_)| d.is_some())
+ .filter(|&(ref d,_)| d.as_ref().unwrap().krate == ast::LOCAL_CRATE)
+ .map(|(d, v)| (d.unwrap().node, v))
+ .collect()
+}
+
impl<'a, 'tcx> TermsContext<'a, 'tcx> {
+ fn add_inferreds_for_item(&mut self,
+ item_id: ast::NodeId,
+ has_self: bool,
+ generics: &ast::Generics)
+ {
+ /*!
+ * Add "inferreds" for the generic parameters declared on this
+ * item. This has a lot of annoying parameters because we are
+ * trying to drive this from the AST, rather than the
+ * ty::Generics, so that we can get span info -- but this
+ * means we must accommodate syntactic distinctions.
+ */
+
+ // NB: In the code below for writing the results back into the
+ // tcx, we rely on the fact that all inferreds for a particular
+ // item are assigned continuous indices.
+
+ let inferreds_on_entry = self.num_inferred();
+
+ if has_self {
+ self.add_inferred(item_id, TypeParam, SelfSpace, 0, item_id);
+ }
+
+ for (i, p) in generics.lifetimes.iter().enumerate() {
+ let id = p.lifetime.id;
+ self.add_inferred(item_id, RegionParam, TypeSpace, i, id);
+ }
+
+ for (i, p) in generics.ty_params.iter().enumerate() {
+ self.add_inferred(item_id, TypeParam, TypeSpace, i, p.id);
+ }
+
+ // If this item has no type or lifetime parameters,
+ // then there are no variances to infer, so just
+ // insert an empty entry into the variance map.
+ // Arguably we could just leave the map empty in this
+ // case but it seems cleaner to be able to distinguish
+ // "invalid item id" from "item id with no
+ // parameters".
+ if self.num_inferred() == inferreds_on_entry {
+ let newly_added =
+ self.tcx.item_variance_map.borrow_mut().insert(
+ ast_util::local_def(item_id),
+ self.empty_variances.clone()).is_none();
+ assert!(newly_added);
+ }
+ }
+
fn add_inferred(&mut self,
item_id: ast::NodeId,
kind: ParamKind,
param_id: ast::NodeId) {
let inf_index = InferredIndex(self.inferred_infos.len());
let term = self.arena.alloc(InferredTerm(inf_index));
+ let initial_variance = self.pick_initial_variance(item_id, space, index);
self.inferred_infos.push(InferredInfo { item_id: item_id,
kind: kind,
space: space,
index: index,
param_id: param_id,
- term: term });
+ term: term,
+ initial_variance: initial_variance });
let newly_added = self.inferred_map.insert(param_id, inf_index).is_none();
assert!(newly_added);
- debug!("add_inferred(item_id={}, \
+ debug!("add_inferred(item_path={}, \
+ item_id={}, \
kind={:?}, \
+ space={:?}, \
index={}, \
- param_id={},
- inf_index={:?})",
- item_id, kind, index, param_id, inf_index);
+ param_id={}, \
+ inf_index={:?}, \
+ initial_variance={:?})",
+ ty::item_path_str(self.tcx, ast_util::local_def(item_id)),
+ item_id, kind, space, index, param_id, inf_index,
+ initial_variance);
+ }
+
+ fn pick_initial_variance(&self,
+ item_id: ast::NodeId,
+ space: ParamSpace,
+ index: uint)
+ -> ty::Variance
+ {
+ match space {
+ SelfSpace | FnSpace => {
+ ty::Bivariant
+ }
+
+ TypeSpace => {
+ match self.lang_items.iter().find(|&&(n, _)| n == item_id) {
+ Some(&(_, ref variances)) => variances[index],
+ None => ty::Bivariant
+ }
+ }
+ }
}
fn num_inferred(&self) -> uint {
fn visit_item(&mut self, item: &ast::Item) {
debug!("add_inferreds for item {}", item.repr(self.tcx));
- let inferreds_on_entry = self.num_inferred();
-
- // NB: In the code below for writing the results back into the
- // tcx, we rely on the fact that all inferreds for a particular
- // item are assigned continuous indices.
- match item.node {
- ast::ItemTrait(..) => {
- self.add_inferred(item.id, TypeParam, SelfSpace, 0, item.id);
- }
- _ => { }
- }
-
match item.node {
ast::ItemEnum(_, ref generics) |
- ast::ItemStruct(_, ref generics) |
+ ast::ItemStruct(_, ref generics) => {
+ self.add_inferreds_for_item(item.id, false, generics);
+ }
ast::ItemTrait(_, ref generics, _, _) => {
- for (i, p) in generics.lifetimes.iter().enumerate() {
- let id = p.lifetime.id;
- self.add_inferred(item.id, RegionParam, TypeSpace, i, id);
- }
- for (i, p) in generics.ty_params.iter().enumerate() {
- self.add_inferred(item.id, TypeParam, TypeSpace, i, p.id);
- }
-
- // If this item has no type or lifetime parameters,
- // then there are no variances to infer, so just
- // insert an empty entry into the variance map.
- // Arguably we could just leave the map empty in this
- // case but it seems cleaner to be able to distinguish
- // "invalid item id" from "item id with no
- // parameters".
- if self.num_inferred() == inferreds_on_entry {
- let newly_added = self.tcx.item_variance_map.borrow_mut().insert(
- ast_util::local_def(item.id),
- self.empty_variances.clone()).is_none();
- assert!(newly_added);
- }
-
+ self.add_inferreds_for_item(item.id, true, generics);
visit::walk_item(self, item);
}
struct ConstraintContext<'a, 'tcx: 'a> {
terms_cx: TermsContext<'a, 'tcx>,
- // These are the def-id of the std::marker::InvariantType,
- // std::marker::InvariantLifetime, and so on. The arrays
- // are indexed by the `ParamKind` (type, lifetime, self). Note
- // that there are no marker types for self, so the entries for
- // self are always None.
- invariant_lang_items: [Option<ast::DefId>; 2],
- covariant_lang_items: [Option<ast::DefId>; 2],
- contravariant_lang_items: [Option<ast::DefId>; 2],
- unsafe_cell_lang_item: Option<ast::DefId>,
-
// These are pointers to common `ConstantTerm` instances
covariant: VarianceTermPtr<'a>,
contravariant: VarianceTermPtr<'a>,
fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>,
krate: &ast::Crate)
- -> ConstraintContext<'a, 'tcx> {
- let mut invariant_lang_items = [None; 2];
- let mut covariant_lang_items = [None; 2];
- let mut contravariant_lang_items = [None; 2];
-
- covariant_lang_items[TypeParam as uint] =
- terms_cx.tcx.lang_items.covariant_type();
- covariant_lang_items[RegionParam as uint] =
- terms_cx.tcx.lang_items.covariant_lifetime();
-
- contravariant_lang_items[TypeParam as uint] =
- terms_cx.tcx.lang_items.contravariant_type();
- contravariant_lang_items[RegionParam as uint] =
- terms_cx.tcx.lang_items.contravariant_lifetime();
-
- invariant_lang_items[TypeParam as uint] =
- terms_cx.tcx.lang_items.invariant_type();
- invariant_lang_items[RegionParam as uint] =
- terms_cx.tcx.lang_items.invariant_lifetime();
-
- let unsafe_cell_lang_item = terms_cx.tcx.lang_items.unsafe_cell_type();
-
+ -> ConstraintContext<'a, 'tcx>
+{
let covariant = terms_cx.arena.alloc(ConstantTerm(ty::Covariant));
let contravariant = terms_cx.arena.alloc(ConstantTerm(ty::Contravariant));
let invariant = terms_cx.arena.alloc(ConstantTerm(ty::Invariant));
let bivariant = terms_cx.arena.alloc(ConstantTerm(ty::Bivariant));
let mut constraint_cx = ConstraintContext {
terms_cx: terms_cx,
-
- invariant_lang_items: invariant_lang_items,
- covariant_lang_items: covariant_lang_items,
- contravariant_lang_items: contravariant_lang_items,
- unsafe_cell_lang_item: unsafe_cell_lang_item,
-
covariant: covariant,
contravariant: contravariant,
invariant: invariant,
match item.node {
ast::ItemEnum(ref enum_definition, _) => {
- let generics = &ty::lookup_item_type(tcx, did).generics;
+ let scheme = ty::lookup_item_type(tcx, did);
+
+ // Not entirely obvious: constraints on structs/enums do not
+ // affect the variance of their type parameters. See discussion
+ // in comment at top of module.
+ //
+ // self.add_constraints_from_generics(&scheme.generics);
// Hack: If we directly call `ty::enum_variants`, it
// annoyingly takes it upon itself to run off and
&**ast_variant,
/*discriminant*/ 0);
for arg_ty in &variant.args {
- self.add_constraints_from_ty(generics, *arg_ty, self.covariant);
+ self.add_constraints_from_ty(&scheme.generics, *arg_ty, self.covariant);
}
}
}
ast::ItemStruct(..) => {
- let generics = &ty::lookup_item_type(tcx, did).generics;
+ let scheme = ty::lookup_item_type(tcx, did);
+
+ // Not entirely obvious: constraints on structs/enums do not
+ // affect the variance of their type parameters. See discussion
+ // in comment at top of module.
+ //
+ // self.add_constraints_from_generics(&scheme.generics);
+
let struct_fields = ty::lookup_struct_fields(tcx, did);
for field_info in &struct_fields {
assert_eq!(field_info.id.krate, ast::LOCAL_CRATE);
let field_ty = ty::node_id_to_type(tcx, field_info.id.node);
- self.add_constraints_from_ty(generics, field_ty, self.covariant);
+ self.add_constraints_from_ty(&scheme.generics, field_ty, self.covariant);
}
}
ast::ItemTrait(..) => {
+ let trait_def = ty::lookup_trait_def(tcx, did);
+ let predicates = ty::predicates(tcx, ty::mk_self_type(tcx), &trait_def.bounds);
+ self.add_constraints_from_predicates(&trait_def.generics,
+ &predicates[],
+ 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_sig(&method.generics,
- &method.fty.sig,
- self.covariant);
+ 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(_) => {}
}
ast::ItemTy(..) |
ast::ItemImpl(..) |
ast::ItemMac(..) => {
- visit::walk_item(self, item);
}
}
+
+ visit::walk_item(self, item);
}
}
-> VarianceTermPtr<'a> {
assert_eq!(param_def_id.krate, item_def_id.krate);
- if self.invariant_lang_items[kind as uint] == Some(item_def_id) {
- self.invariant
- } else if self.covariant_lang_items[kind as uint] == Some(item_def_id) {
- self.covariant
- } else if self.contravariant_lang_items[kind as uint] == Some(item_def_id) {
- self.contravariant
- } else if kind == TypeParam && Some(item_def_id) == self.unsafe_cell_lang_item {
- self.invariant
- } else if param_def_id.krate == ast::LOCAL_CRATE {
+ if param_def_id.krate == ast::LOCAL_CRATE {
// Parameter on an item defined within current crate:
// variance not yet inferred, so return a symbolic
// variance.
}
}
+ fn add_constraints_from_trait_ref(&mut self,
+ generics: &ty::Generics<'tcx>,
+ trait_ref: &ty::TraitRef<'tcx>,
+ variance: VarianceTermPtr<'a>) {
+ debug!("add_constraints_from_trait_ref: trait_ref={} variance={:?}",
+ trait_ref.repr(self.tcx()),
+ variance);
+
+ let trait_def = ty::lookup_trait_def(self.tcx(), trait_ref.def_id);
+
+ self.add_constraints_from_substs(
+ generics,
+ trait_ref.def_id,
+ trait_def.generics.types.as_slice(),
+ trait_def.generics.regions.as_slice(),
+ trait_ref.substs,
+ variance);
+ }
+
/// Adds constraints appropriate for an instance of `ty` appearing
/// in a context with the generics defined in `generics` and
/// ambient variance `variance`
generics: &ty::Generics<'tcx>,
ty: Ty<'tcx>,
variance: VarianceTermPtr<'a>) {
- debug!("add_constraints_from_ty(ty={})", ty.repr(self.tcx()));
+ debug!("add_constraints_from_ty(ty={}, variance={:?})",
+ ty.repr(self.tcx()),
+ variance);
match ty.sty {
ty::ty_bool |
self.add_constraints_from_ty(generics, typ, variance);
}
+
ty::ty_ptr(ref mt) => {
self.add_constraints_from_mt(generics, mt, variance);
}
}
ty::ty_trait(ref data) => {
- let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx(),
- self.tcx().types.err);
- let trait_def = ty::lookup_trait_def(self.tcx(), trait_ref.def_id());
-
- // Traits never declare region parameters in the self
- // space nor anything in the fn space.
- assert!(trait_def.generics.regions.is_empty_in(subst::SelfSpace));
- assert!(trait_def.generics.types.is_empty_in(subst::FnSpace));
- assert!(trait_def.generics.regions.is_empty_in(subst::FnSpace));
+ let poly_trait_ref =
+ data.principal_trait_ref_with_self_ty(self.tcx(),
+ self.tcx().types.err);
// The type `Foo<T+'a>` is contravariant w/r/t `'a`:
let contra = self.contravariant(variance);
self.add_constraints_from_region(generics, data.bounds.region_bound, contra);
- self.add_constraints_from_substs(
- generics,
- trait_ref.def_id(),
- trait_def.generics.types.get_slice(subst::TypeSpace),
- trait_def.generics.regions.get_slice(subst::TypeSpace),
- trait_ref.substs(),
- variance);
+ // Ignore the SelfSpace, it is erased.
+ self.add_constraints_from_trait_ref(generics, &*poly_trait_ref.0, variance);
let projections = data.projection_bounds_with_self_ty(self.tcx(),
self.tcx().types.err);
self.add_constraints_from_sig(generics, sig, variance);
}
- ty::ty_infer(..) | ty::ty_err => {
+ ty::ty_err => {
+ // we encounter this when walking the trait references for object
+ // types, where we use ty_err as the Self type
+ }
+
+ ty::ty_infer(..) => {
self.tcx().sess.bug(
&format!("unexpected type encountered in \
variance inference: {}",
region_param_defs: &[ty::RegionParameterDef],
substs: &subst::Substs<'tcx>,
variance: VarianceTermPtr<'a>) {
- debug!("add_constraints_from_substs(def_id={:?})", def_id);
+ debug!("add_constraints_from_substs(def_id={}, substs={}, variance={:?})",
+ def_id.repr(self.tcx()),
+ substs.repr(self.tcx()),
+ variance);
for p in type_param_defs {
let variance_decl =
p.space, p.index as uint);
let variance_i = self.xform(variance, variance_decl);
let substs_ty = *substs.types.get(p.space, p.index as uint);
+ debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}",
+ variance_decl, variance_i);
self.add_constraints_from_ty(generics, substs_ty, variance_i);
}
}
}
+ 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)) => {
+ self.add_constraints_from_ty(generics, data.0, variance);
+ self.add_constraints_from_ty(generics, data.1, variance);
+ }
+
+ ty::Predicate::TypeOutlives(ty::Binder(ref data)) => {
+ self.add_constraints_from_ty(generics, data.0, variance);
+
+ let variance_r = self.xform(variance, self.contravariant);
+ 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);
+
+ 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,
fn solve_constraints(constraints_cx: ConstraintContext) {
let ConstraintContext { terms_cx, constraints, .. } = constraints_cx;
- let solutions: Vec<_> = repeat(ty::Bivariant).take(terms_cx.num_inferred()).collect();
+
+ let solutions =
+ terms_cx.inferred_infos.iter()
+ .map(|ii| ii.initial_variance)
+ .collect();
+
let mut solutions_cx = SolveContext {
terms_cx: terms_cx,
constraints: constraints,
let mut types = VecPerParamSpace::empty();
let mut regions = VecPerParamSpace::empty();
- while index < num_inferred &&
- inferred_infos[index].item_id == item_id {
+ while index < num_inferred && inferred_infos[index].item_id == item_id {
let info = &inferred_infos[index];
let variance = solutions[index];
debug!("Index {} Info {} / {:?} / {:?} Variance {:?}",
index, info.index, info.kind, info.space, variance);
match info.kind {
- TypeParam => {
- types.push(info.space, variance);
- }
- RegionParam => {
- regions.push(info.space, variance);
- }
+ TypeParam => { types.push(info.space, variance); }
+ RegionParam => { regions.push(info.space, variance); }
}
+
index += 1;
}
(x, ty::Bivariant) | (ty::Bivariant, x) => x,
}
}
+
--- /dev/null
+// 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.
+
+#![allow(dead_code)]
+
+trait Get<T> : 'static {
+ fn get(&self, t: T);
+}
+
+fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
+ -> Box<Get<&'min i32>>
+ where 'max : 'min
+{
+ v //~ ERROR mismatched types
+}
+
+fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
+ -> Box<Get<&'max i32>>
+ where 'max : 'min
+{
+ v
+}
+
+fn main() { }
--- /dev/null
+// 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.
+
+#![allow(dead_code)]
+
+trait Get<T> {
+ fn get(&self, t: T);
+}
+
+fn get_min_from_max<'min, 'max, G>()
+ where 'max : 'min, G : Get<&'max i32>
+{
+ impls_get::<G,&'min i32>() //~ ERROR mismatched types
+}
+
+fn get_max_from_min<'min, 'max, G>()
+ where 'max : 'min, G : Get<&'min i32>
+{
+ impls_get::<G,&'max i32>()
+}
+
+fn impls_get<G,T>() where G : Get<T> { }
+
+fn main() { }
--- /dev/null
+// 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.
+
+#![allow(dead_code)]
+
+trait Get {
+ fn get(&self);
+}
+
+fn get_min_from_max<'min, 'max, G>()
+ where 'max : 'min, G : 'max, &'max G : Get
+{
+ impls_get::<&'min G>(); //~ ERROR mismatched types
+}
+
+fn get_max_from_min<'min, 'max, G>()
+ where 'max : 'min, G : 'max, &'min G : Get
+{
+ impls_get::<&'max G>();
+}
+
+fn impls_get<G>() where G : Get { }
+
+fn main() { }
--- /dev/null
+// 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.
+
+#![allow(dead_code)]
+
+trait Get<T> : 'static {
+ fn get(&self) -> T;
+}
+
+fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
+ -> Box<Get<&'min i32>>
+ where 'max : 'min
+{
+ v
+}
+
+fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
+ -> Box<Get<&'max i32>>
+ where 'max : 'min
+{
+ v //~ ERROR mismatched types
+}
+
+fn main() { }
--- /dev/null
+// 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.
+
+#![allow(dead_code)]
+
+trait Get<T> {
+ fn get(&self) -> T;
+}
+
+fn get_min_from_max<'min, 'max, G>()
+ where 'max : 'min, G : Get<&'max i32>
+{
+ impls_get::<G,&'min i32>()
+}
+
+fn get_max_from_min<'min, 'max, G>()
+ where 'max : 'min, G : Get<&'min i32>
+{
+ impls_get::<G,&'max i32>() //~ ERROR mismatched types
+}
+
+fn impls_get<G,T>() where G : Get<T> { }
+
+fn main() { }
--- /dev/null
+// 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.
+
+#![allow(dead_code)]
+
+trait Get {
+ fn get() -> Self;
+}
+
+fn get_min_from_max<'min, 'max, G>()
+ where 'max : 'min, G : 'max, &'max G : Get
+{
+ impls_get::<&'min G>();
+}
+
+fn get_max_from_min<'min, 'max, G>()
+ where 'max : 'min, G : 'max, &'min G : Get
+{
+ impls_get::<&'max G>(); //~ ERROR mismatched types
+}
+
+fn impls_get<G>() where G : Get { }
+
+fn main() { }
--- /dev/null
+// 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.
+
+#![allow(dead_code)]
+
+trait Get<T> : 'static {
+ fn get(&self, t: T) -> T;
+}
+
+fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
+ -> Box<Get<&'min i32>>
+ where 'max : 'min
+{
+ v //~ ERROR mismatched types
+}
+
+fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
+ -> Box<Get<&'max i32>>
+ where 'max : 'min
+{
+ v //~ ERROR mismatched types
+}
+
+fn main() { }
--- /dev/null
+// 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.
+
+#![allow(dead_code)]
+
+trait Get<T> {
+ fn get(&self, t: T) -> T;
+}
+
+fn get_min_from_max<'min, 'max, G>()
+ where 'max : 'min, G : Get<&'max i32>
+{
+ impls_get::<G,&'min i32>() //~ ERROR mismatched types
+}
+
+fn get_max_from_min<'min, 'max, G>()
+ where 'max : 'min, G : Get<&'min i32>
+{
+ impls_get::<G,&'max i32>() //~ ERROR mismatched types
+}
+
+fn impls_get<G,T>() where G : Get<T> { }
+
+fn main() { }
--- /dev/null
+// 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.
+
+#![allow(dead_code)]
+
+trait Get {
+ fn get(&self) -> Self;
+}
+
+fn get_min_from_max<'min, 'max, G>()
+ where 'max : 'min, &'max G : Get
+{
+ impls_get::<&'min G>(); //~ ERROR mismatched types
+}
+
+fn get_max_from_min<'min, 'max, G>()
+ where 'max : 'min, &'min G : Get
+{
+ impls_get::<&'max G>(); //~ ERROR mismatched types
+}
+
+fn impls_get<G>() where G : Get { }
+
+fn main() { }
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that disallow lifetime parameters that are unused.
+
+use std::marker;
+
+struct Bivariant<'a>; //~ ERROR parameter `'a` is never used
+
+struct Struct<'a, 'd> { //~ ERROR parameter `'d` is never used
+ field: &'a [i32]
+}
+
+trait Trait<'a, 'd> { //~ ERROR parameter `'d` is never used
+ fn method(&'a self);
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that disallow lifetime parameters that are unused.
+
+enum Foo<'a> { //~ ERROR parameter `'a` is never used
+ Foo1(Bar<'a>)
+}
+
+enum Bar<'a> { //~ ERROR parameter `'a` is never used
+ Bar1(Foo<'a>)
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 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.
+
+#![deny(bivariance)]
+#![allow(dead_code)]
+
+// Check that bounds on type parameters (other than `Self`) do not
+// influence variance.
+
+#[rustc_variance]
+trait Getter<T> { //~ ERROR types=[[+];[-];[]]
+ fn get(&self) -> T;
+}
+
+#[rustc_variance]
+trait Setter<T> { //~ ERROR types=[[-];[-];[]]
+ fn get(&self, T);
+}
+
+#[rustc_variance]
+struct TestStruct<U,T:Setter<U>> { //~ ERROR types=[[+, +];[];[]]
+ t: T, u: U
+}
+
+#[rustc_variance]
+enum TestEnum<U,T:Setter<U>> {//~ ERROR types=[[*, +];[];[]]
+ //~^ ERROR parameter `U` is never used
+ Foo(T)
+}
+
+#[rustc_variance]
+trait TestTrait<U,T:Setter<U>> { //~ ERROR types=[[-, +];[-];[]]
+ fn getter(&self, u: U) -> T;
+}
+
+#[rustc_variance]
+trait TestTrait2<U> : Getter<U> { //~ ERROR types=[[+];[-];[]]
+}
+
+#[rustc_variance]
+trait TestTrait3<U> { //~ ERROR types=[[-];[-];[]]
+ fn getter<T:Getter<U>>(&self);
+}
+
+#[rustc_variance]
+struct TestContraStruct<U,T:Setter<U>> { //~ ERROR types=[[*, +];[];[]]
+ //~^ ERROR parameter `U` is never used
+ t: T
+}
+
+#[rustc_variance]
+struct TestBox<U,T:Getter<U>+Setter<U>> { //~ ERROR types=[[*, +];[];[]]
+ //~^ ERROR parameter `U` is never used
+ t: T
+}
+
+pub fn main() { }
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we correctly infer variance for type parameters in
+// various types and traits.
+
+#[rustc_variance]
+struct TestImm<A, B> { //~ ERROR types=[[+, +];[];[]]
+ x: A,
+ y: B,
+}
+
+#[rustc_variance]
+struct TestMut<A, B:'static> { //~ ERROR types=[[+, o];[];[]]
+ x: A,
+ y: &'static mut B,
+}
+
+#[rustc_variance]
+struct TestIndirect<A:'static, B:'static> { //~ ERROR types=[[+, o];[];[]]
+ m: TestMut<A, B>
+}
+
+#[rustc_variance]
+struct TestIndirect2<A:'static, B:'static> { //~ ERROR types=[[o, o];[];[]]
+ n: TestMut<A, B>,
+ m: TestMut<B, A>
+}
+
+#[rustc_variance]
+trait Getter<A> { //~ ERROR types=[[+];[-];[]]
+ fn get(&self) -> A;
+}
+
+#[rustc_variance]
+trait Setter<A> { //~ ERROR types=[[-];[o];[]]
+ fn set(&mut self, a: A);
+}
+
+#[rustc_variance]
+trait GetterSetter<A> { //~ ERROR types=[[o];[o];[]]
+ fn get(&self) -> A;
+ fn set(&mut self, a: A);
+}
+
+#[rustc_variance]
+trait GetterInTypeBound<A> { //~ ERROR types=[[-];[-];[]]
+ // 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
+ // contravariant, and the Getter is covariant w/r/t A, yielding an
+ // overall contravariant result.
+ fn do_it<T:Getter<A>>(&self);
+}
+
+#[rustc_variance]
+trait SetterInTypeBound<A> { //~ ERROR types=[[+];[-];[]]
+ fn do_it<T:Setter<A>>(&self);
+}
+
+#[rustc_variance]
+struct TestObject<A, R> { //~ ERROR types=[[-, +];[];[]]
+ n: Box<Setter<A>+Send>,
+ m: Box<Getter<R>+Send>,
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 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.
+
+#![deny(bivariance)]
+#![allow(dead_code)]
+
+use std::cell::Cell;
+
+// Check that a type parameter which is only used in a trait bound is
+// not considered bivariant.
+
+#[rustc_variance]
+struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR types=[[o, o];[];[]], regions=[[-];[];[]]
+ t: &'a mut (A,B)
+}
+
+#[rustc_variance]
+struct InvariantCell<A> { //~ ERROR types=[[o];[];[]]
+ t: Cell<A>
+}
+
+#[rustc_variance]
+struct InvariantIndirect<A> { //~ ERROR types=[[o];[];[]]
+ t: InvariantCell<A>
+}
+
+#[rustc_variance]
+struct Covariant<A> { //~ ERROR types=[[+];[];[]]
+ t: A, u: fn() -> A
+}
+
+#[rustc_variance]
+struct Contravariant<A> { //~ ERROR types=[[-];[];[]]
+ t: fn(A)
+}
+
+#[rustc_variance]
+enum Enum<A,B,C> { //~ ERROR types=[[+, -, o];[];[]]
+ Foo(Covariant<A>),
+ Bar(Contravariant<B>),
+ Zed(Covariant<C>,Contravariant<C>)
+}
+
+pub fn main() { }
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we report an error for unused type parameters in types.
+
+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
+
+fn main() {}
--- /dev/null
+// Copyright 2012 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.
+
+#![allow(dead_code)]
+
+// Test that we report an error for unused type parameters in types and traits,
+// and that we offer a helpful suggestion.
+
+struct SomeStruct<A> { x: u32 }
+//~^ ERROR parameter `A` is never used
+//~| HELP PhantomData
+
+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
+//~| HELP PhantomData
+ Cons(Box<ListCell<T>>),
+ Nil
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test various uses of structs with distint variances to make sure
+// they permit lifetimes to be approximated as expected.
+
+struct SomeStruct<T>(fn(T));
+
+fn foo<'min,'max>(v: SomeStruct<&'max ()>)
+ -> SomeStruct<&'min ()>
+ where 'max : 'min
+{
+ v //~ ERROR mismatched types
+}
+
+#[rustc_error]
+fn main() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test various uses of structs with distint variances to make sure
+// they permit lifetimes to be approximated as expected.
+
+#![allow(dead_code)]
+
+struct SomeStruct<T>(fn(T));
+
+fn bar<'min,'max>(v: SomeStruct<&'min ()>)
+ -> SomeStruct<&'max ()>
+ where 'max : 'min
+{
+ v
+}
+
+#[rustc_error]
+fn main() { } //~ ERROR compilation successful
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that a covariant struct does not permit the lifetime of a
+// reference to be enlarged.
+
+struct SomeStruct<T>(T);
+
+fn foo<'min,'max>(v: SomeStruct<&'min ()>)
+ -> SomeStruct<&'max ()>
+ where 'max : 'min
+{
+ v //~ ERROR mismatched types
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that a covariant struct permits the lifetime of a reference to
+// be shortened.
+
+#![allow(dead_code)]
+
+struct SomeStruct<T>(T);
+
+fn foo<'min,'max>(v: SomeStruct<&'max ()>)
+ -> SomeStruct<&'min ()>
+ where 'max : 'min
+{
+ v
+}
+
+#[rustc_error] fn main() { } //~ ERROR compilation successful
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test various uses of structs with distint variances to make sure
+// they permit lifetimes to be approximated as expected.
+
+struct SomeStruct<T>(*mut T);
+
+fn foo<'min,'max>(v: SomeStruct<&'max ()>)
+ -> SomeStruct<&'min ()>
+ where 'max : 'min
+{
+ v //~ ERROR mismatched types
+}
+
+fn bar<'min,'max>(v: SomeStruct<&'min ()>)
+ -> SomeStruct<&'max ()>
+ where 'max : 'min
+{
+ v //~ ERROR mismatched types
+}
+
+#[rustc_error]
+fn main() { }
--- /dev/null
+// 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.
+
+// Elaborated version of the opening example from RFC 738. This failed
+// to compile before variance because invariance of `Option` prevented
+// us from approximating the lifetimes of `field1` and `field2` to a
+// common intersection.
+
+#![allow(dead_code)]
+
+struct List<'l> {
+ field1: &'l i32,
+ field2: Option<&'l i32>,
+}
+
+fn foo(field1: &i32, field2: Option<&i32>) -> i32 {
+ let list = List { field1: field1, field2: field2 };
+ *list.field1 + list.field2.cloned().unwrap_or(0)
+}
+
+fn main() {
+ let x = 22;
+ let y = Some(3);
+ let z = None;
+ assert_eq!(foo(&x, y.as_ref()), 25);
+ assert_eq!(foo(&x, z.as_ref()), 22);
+}
--- /dev/null
+// 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.
+
+#![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);
+}
+
+
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that vec is now covariant in its argument type.
+
+#![allow(dead_code)]
+
+fn foo<'a,'b>(v1: Vec<&'a i32>, v2: Vec<&'b i32>) -> i32 {
+ bar(v1, v2).cloned().unwrap_or(0) // only type checks if we can intersect 'a and 'b
+}
+
+fn bar<'c>(v1: Vec<&'c i32>, v2: Vec<&'c i32>) -> Option<&'c i32> {
+ v1.get(0).cloned().or_else(|| v2.get(0).cloned())
+}
+
+fn main() {
+ let x = 22;
+ let y = 44;
+ assert_eq!(foo(vec![&x], vec![&y]), 22);
+ assert_eq!(foo(vec![&y], vec![&x]), 44);
+}