mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-24 15:54:15 +00:00
Introduce the new phantomdata/phantomfn markers and integrate them
into variance inference; fix various bugs in variance inference so that it considers the correct set of constraints; modify infer to consider the results of variance inference for type arguments.
This commit is contained in:
parent
dfc5c0f1e8
commit
2594d56e32
@ -16,7 +16,7 @@ use any;
|
||||
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};
|
||||
@ -914,6 +914,11 @@ impl Debug for () {
|
||||
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> {
|
||||
|
@ -26,6 +26,10 @@
|
||||
#![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",
|
||||
@ -42,7 +46,7 @@ pub unsafe trait Send: 'static {
|
||||
#[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.
|
||||
}
|
||||
|
||||
@ -50,7 +54,7 @@ pub unsafe trait Send {
|
||||
#[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.
|
||||
}
|
||||
|
||||
@ -155,7 +159,7 @@ pub trait Sized {
|
||||
/// 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.
|
||||
}
|
||||
|
||||
@ -208,216 +212,10 @@ pub trait Copy {
|
||||
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.
|
||||
@ -435,6 +233,83 @@ pub struct NoCopy;
|
||||
#[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};
|
||||
|
128
src/librustc/middle/infer/bivariate.rs
Normal file
128
src/librustc/middle/infer/bivariate.rs
Normal file
@ -0,0 +1,128 @@
|
||||
// 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))
|
||||
}
|
||||
}
|
@ -32,6 +32,7 @@
|
||||
// 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;
|
||||
@ -39,7 +40,7 @@ use super::sub::Sub;
|
||||
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};
|
||||
@ -48,7 +49,7 @@ use middle::ty::{IntType, UintType};
|
||||
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;
|
||||
@ -58,41 +59,32 @@ use syntax::abi;
|
||||
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.
|
||||
fn regions_with_variance(&self, variance: ty::Variance, a: ty::Region, b: ty::Region)
|
||||
-> cres<'tcx, ty::Region>;
|
||||
|
||||
if as_.len() != bs.len() {
|
||||
return Err(ty::terr_ty_param_size(expected_found(self,
|
||||
as_.len(),
|
||||
bs.len())));
|
||||
}
|
||||
|
||||
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,
|
||||
@ -100,6 +92,11 @@ pub trait Combine<'tcx> : Sized {
|
||||
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 {
|
||||
@ -119,7 +116,8 @@ pub trait Combine<'tcx> : Sized {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -132,20 +130,7 @@ pub trait Combine<'tcx> : Sized {
|
||||
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,
|
||||
@ -157,13 +142,34 @@ pub trait Combine<'tcx> : Sized {
|
||||
|
||||
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={}, \
|
||||
@ -173,22 +179,18 @@ pub trait Combine<'tcx> : Sized {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,7 +243,7 @@ pub trait Combine<'tcx> : Sized {
|
||||
}
|
||||
|
||||
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>;
|
||||
@ -309,7 +311,7 @@ pub trait Combine<'tcx> : Sized {
|
||||
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,
|
||||
@ -322,11 +324,6 @@ pub trait Combine<'tcx> : Sized {
|
||||
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>)
|
||||
@ -540,7 +537,8 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C,
|
||||
}
|
||||
|
||||
(&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
|
||||
@ -644,6 +642,10 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> {
|
||||
Equate((*self).clone())
|
||||
}
|
||||
|
||||
fn bivariate(&self) -> Bivariate<'f, 'tcx> {
|
||||
Bivariate((*self).clone())
|
||||
}
|
||||
|
||||
fn sub(&self) -> Sub<'f, 'tcx> {
|
||||
Sub((*self).clone())
|
||||
}
|
||||
@ -697,7 +699,7 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> {
|
||||
EqTo => {
|
||||
self.generalize(a_ty, b_vid, false)
|
||||
}
|
||||
SupertypeOf | SubtypeOf => {
|
||||
BiTo | SupertypeOf | SubtypeOf => {
|
||||
self.generalize(a_ty, b_vid, true)
|
||||
}
|
||||
});
|
||||
@ -721,6 +723,10 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> {
|
||||
// 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));
|
||||
}
|
||||
@ -730,7 +736,7 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> {
|
||||
}
|
||||
|
||||
SupertypeOf => {
|
||||
try!(self.sub().contratys(a_ty, b_ty));
|
||||
try!(self.sub().tys_with_variance(ty::Contravariant, a_ty, b_ty));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,11 +13,7 @@ use middle::ty::{self, 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};
|
||||
|
||||
@ -33,21 +29,20 @@ pub fn Equate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Equate<'f, 'tcx> {
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -10,12 +10,9 @@
|
||||
|
||||
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};
|
||||
@ -34,15 +31,30 @@ pub fn Glb<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Glb<'f, 'tcx> {
|
||||
}
|
||||
|
||||
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;
|
||||
@ -75,10 +87,6 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, '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),
|
||||
@ -104,11 +112,6 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> {
|
||||
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)
|
||||
}
|
||||
|
@ -9,13 +9,10 @@
|
||||
// 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};
|
||||
@ -34,15 +31,30 @@ pub fn Lub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Lub<'f, 'tcx> {
|
||||
}
|
||||
|
||||
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();
|
||||
@ -70,10 +82,6 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, '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),
|
||||
@ -90,11 +98,6 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> {
|
||||
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(),
|
||||
|
@ -45,6 +45,7 @@ use self::lub::Lub;
|
||||
use self::unify::{UnificationTable, InferCtxtMethodsForSimplyUnifiableTypes};
|
||||
use self::error_reporting::ErrorReporting;
|
||||
|
||||
pub mod bivariate;
|
||||
pub mod combine;
|
||||
pub mod equate;
|
||||
pub mod error_reporting;
|
||||
|
@ -10,12 +10,8 @@
|
||||
|
||||
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};
|
||||
@ -37,28 +33,31 @@ pub fn Sub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Sub<'f, 'tcx> {
|
||||
}
|
||||
|
||||
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 tag(&self) -> String { "Sub".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>> {
|
||||
Sub(self.fields.switch_expected()).tys(b, a)
|
||||
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({}, {})",
|
||||
|
@ -48,7 +48,7 @@ type Relation = (RelationDir, ty::TyVid);
|
||||
|
||||
#[derive(Copy, PartialEq, Debug)]
|
||||
pub enum RelationDir {
|
||||
SubtypeOf, SupertypeOf, EqTo
|
||||
SubtypeOf, SupertypeOf, EqTo, BiTo
|
||||
}
|
||||
|
||||
impl RelationDir {
|
||||
@ -56,7 +56,8 @@ impl RelationDir {
|
||||
match self {
|
||||
SubtypeOf => SupertypeOf,
|
||||
SupertypeOf => SubtypeOf,
|
||||
EqTo => EqTo
|
||||
EqTo => EqTo,
|
||||
BiTo => BiTo,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -312,16 +312,9 @@ lets_do_this! {
|
||||
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;
|
||||
|
||||
|
@ -133,6 +133,7 @@ pub enum MethodMatchedData {
|
||||
/// 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),
|
||||
@ -795,8 +796,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
stack: &TraitObligationStack<'o, 'tcx>)
|
||||
-> Result<SelectionCandidateSet<'tcx>, SelectionError<'tcx>>
|
||||
{
|
||||
// Check for overflow.
|
||||
|
||||
let TraitObligationStack { obligation, .. } = *stack;
|
||||
|
||||
let mut candidates = SelectionCandidateSet {
|
||||
@ -804,6 +803,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
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.
|
||||
|
||||
@ -1673,6 +1679,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
try!(self.confirm_builtin_candidate(obligation, builtin_bound))))
|
||||
}
|
||||
|
||||
PhantomFnCandidate |
|
||||
ErrorCandidate => {
|
||||
Ok(VtableBuiltin(VtableBuiltinData { nested: VecPerParamSpace::empty() }))
|
||||
}
|
||||
@ -2339,6 +2346,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
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)),
|
||||
|
61
src/librustc_typeck/constrained_type_params.rs
Normal file
61
src/librustc_typeck/constrained_type_params.rs
Normal file
@ -0,0 +1,61 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -187,6 +187,22 @@
|
||||
//! 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::*;
|
||||
@ -199,7 +215,6 @@ use middle::subst::{ParamSpace, FnSpace, TypeSpace, SelfSpace, VecPerParamSpace}
|
||||
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;
|
||||
@ -258,6 +273,11 @@ struct TermsContext<'a, 'tcx: 'a> {
|
||||
|
||||
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>,
|
||||
@ -269,7 +289,7 @@ struct TermsContext<'a, 'tcx: 'a> {
|
||||
#[derive(Copy, Debug, PartialEq)]
|
||||
enum ParamKind {
|
||||
TypeParam,
|
||||
RegionParam
|
||||
RegionParam,
|
||||
}
|
||||
|
||||
struct InferredInfo<'a> {
|
||||
@ -279,6 +299,11 @@ 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>,
|
||||
@ -291,6 +316,8 @@ 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 {
|
||||
@ -304,7 +331,68 @@ fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>,
|
||||
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,
|
||||
@ -313,21 +401,48 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> {
|
||||
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 {
|
||||
@ -339,44 +454,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -404,16 +488,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> {
|
||||
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>,
|
||||
@ -433,40 +507,14 @@ struct Constraint<'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,
|
||||
@ -487,7 +535,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
|
||||
|
||||
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
|
||||
@ -505,29 +559,48 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
|
||||
&**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(_) => {}
|
||||
}
|
||||
@ -544,9 +617,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
|
||||
ast::ItemTy(..) |
|
||||
ast::ItemImpl(..) |
|
||||
ast::ItemMac(..) => {
|
||||
visit::walk_item(self, item);
|
||||
}
|
||||
}
|
||||
|
||||
visit::walk_item(self, item);
|
||||
}
|
||||
}
|
||||
|
||||
@ -648,15 +722,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||
-> 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.
|
||||
@ -724,6 +790,25 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
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`
|
||||
@ -731,7 +816,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||
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 |
|
||||
@ -754,6 +841,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||
self.add_constraints_from_ty(generics, typ, variance);
|
||||
}
|
||||
|
||||
|
||||
ty::ty_ptr(ref mt) => {
|
||||
self.add_constraints_from_mt(generics, mt, variance);
|
||||
}
|
||||
@ -797,27 +885,16 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
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);
|
||||
@ -845,7 +922,12 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||
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: {}",
|
||||
@ -864,7 +946,10 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||
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 =
|
||||
@ -872,6 +957,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -885,6 +972,51 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
@ -969,7 +1101,12 @@ struct SolveContext<'a, 'tcx: 'a> {
|
||||
|
||||
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,
|
||||
@ -1034,20 +1171,16 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1144,3 +1277,4 @@ fn glb(v1: ty::Variance, v2: ty::Variance) -> ty::Variance {
|
||||
(x, ty::Bivariant) | (ty::Bivariant, x) => x,
|
||||
}
|
||||
}
|
||||
|
||||
|
31
src/test/compile-fail/variance-contravariant-arg-object.rs
Normal file
31
src/test/compile-fail/variance-contravariant-arg-object.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// 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() { }
|
@ -0,0 +1,31 @@
|
||||
// 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() { }
|
@ -0,0 +1,31 @@
|
||||
// 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() { }
|
31
src/test/compile-fail/variance-covariant-arg-object.rs
Normal file
31
src/test/compile-fail/variance-covariant-arg-object.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// 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() { }
|
31
src/test/compile-fail/variance-covariant-arg-trait-match.rs
Normal file
31
src/test/compile-fail/variance-covariant-arg-trait-match.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// 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() { }
|
31
src/test/compile-fail/variance-covariant-self-trait-match.rs
Normal file
31
src/test/compile-fail/variance-covariant-self-trait-match.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// 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() { }
|
31
src/test/compile-fail/variance-invariant-arg-object.rs
Normal file
31
src/test/compile-fail/variance-invariant-arg-object.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// 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() { }
|
31
src/test/compile-fail/variance-invariant-arg-trait-match.rs
Normal file
31
src/test/compile-fail/variance-invariant-arg-trait-match.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// 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() { }
|
31
src/test/compile-fail/variance-invariant-self-trait-match.rs
Normal file
31
src/test/compile-fail/variance-invariant-self-trait-match.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// 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() { }
|
25
src/test/compile-fail/variance-regions-unused-direct.rs
Normal file
25
src/test/compile-fail/variance-regions-unused-direct.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// 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() {}
|
21
src/test/compile-fail/variance-regions-unused-indirect.rs
Normal file
21
src/test/compile-fail/variance-regions-unused-indirect.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// 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() {}
|
64
src/test/compile-fail/variance-trait-bounds.rs
Normal file
64
src/test/compile-fail/variance-trait-bounds.rs
Normal file
@ -0,0 +1,64 @@
|
||||
// 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() { }
|
74
src/test/compile-fail/variance-types-bounds.rs
Normal file
74
src/test/compile-fail/variance-types-bounds.rs
Normal file
@ -0,0 +1,74 @@
|
||||
// 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() {}
|
51
src/test/compile-fail/variance-types.rs
Normal file
51
src/test/compile-fail/variance-types.rs
Normal file
@ -0,0 +1,51 @@
|
||||
// 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() { }
|
17
src/test/compile-fail/variance-unused-region-param.rs
Normal file
17
src/test/compile-fail/variance-unused-region-param.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// 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() {}
|
36
src/test/compile-fail/variance-unused-type-param.rs
Normal file
36
src/test/compile-fail/variance-unused-type-param.rs
Normal file
@ -0,0 +1,36 @@
|
||||
// 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() {}
|
24
src/test/compile-fail/variance-use-contravariant-struct-1.rs
Normal file
24
src/test/compile-fail/variance-use-contravariant-struct-1.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// 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() { }
|
26
src/test/compile-fail/variance-use-contravariant-struct-2.rs
Normal file
26
src/test/compile-fail/variance-use-contravariant-struct-2.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// 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
|
23
src/test/compile-fail/variance-use-covariant-struct-1.rs
Normal file
23
src/test/compile-fail/variance-use-covariant-struct-1.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// 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() { }
|
25
src/test/compile-fail/variance-use-covariant-struct-2.rs
Normal file
25
src/test/compile-fail/variance-use-covariant-struct-2.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// 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
|
31
src/test/compile-fail/variance-use-invariant-struct-1.rs
Normal file
31
src/test/compile-fail/variance-use-invariant-struct-1.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// 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() { }
|
@ -0,0 +1,34 @@
|
||||
// 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);
|
||||
}
|
49
src/test/run-pass/variance-trait-matching.rs
Normal file
49
src/test/run-pass/variance-trait-matching.rs
Normal file
@ -0,0 +1,49 @@
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
28
src/test/run-pass/variance-vec-covariant.rs
Normal file
28
src/test/run-pass/variance-vec-covariant.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user