diff options
204 files changed, 3681 insertions, 3683 deletions
diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index 94211592698..be99c4c0bc7 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -29,14 +29,12 @@ //! use std::collections::BinaryHeap; //! use std::uint; //! -//! #[deriving(Eq, PartialEq)] +//! #[deriving(Copy, Eq, PartialEq)] //! struct State { //! cost: uint, //! position: uint //! } //! -//! impl Copy for State {} -//! //! // The priority queue depends on `Ord`. //! // Explicitly implement the trait so the queue becomes a min-heap //! // instead of a max-heap. diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 8f75113c01d..4ef2e681992 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -762,8 +762,8 @@ mod test { expected: &'b [int], } - impl<'a, 'b> FnMut(&int) -> bool for Counter<'a, 'b> { - extern "rust-call" fn call_mut(&mut self, (&x,): (&int,)) -> bool { + impl<'a, 'b, 'c> FnMut(&'c int) -> bool for Counter<'a, 'b> { + extern "rust-call" fn call_mut(&mut self, (&x,): (&'c int,)) -> bool { assert_eq!(x, self.expected[*self.i]); *self.i += 1; true diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index 49b66ce25f5..caa2051c3f9 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -301,14 +301,12 @@ mod test { use super::{EnumSet, CLike}; - #[deriving(PartialEq, Show)] + #[deriving(Copy, PartialEq, Show)] #[repr(uint)] enum Foo { A, B, C } - impl Copy for Foo {} - impl CLike for Foo { fn to_uint(&self) -> uint { *self as uint @@ -507,6 +505,7 @@ mod test { #[should_fail] fn test_overflow() { #[allow(dead_code)] + #[deriving(Copy)] #[repr(uint)] enum Bar { V00, V01, V02, V03, V04, V05, V06, V07, V08, V09, @@ -518,8 +517,6 @@ mod test { V60, V61, V62, V63, V64, V65, V66, V67, V68, V69, } - impl Copy for Bar {} - impl CLike for Bar { fn to_uint(&self) -> uint { *self as uint diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index d3790e320ad..3bf10192e59 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -91,7 +91,7 @@ use alloc::boxed::Box; use core::borrow::{BorrowFrom, BorrowFromMut, ToOwned}; use core::cmp; use core::iter::{range_step, MultiplicativeIterator}; -use core::kinds::{Copy, Sized}; +use core::kinds::Sized; use core::mem::size_of; use core::mem; use core::ops::FnMut; @@ -177,18 +177,16 @@ impl ElementSwaps { } } +#[deriving(Copy)] enum Direction { Pos, Neg } -impl Copy for Direction {} - /// An `Index` and `Direction` together. +#[deriving(Copy)] struct SizeDirection { size: uint, dir: Direction, } -impl Copy for SizeDirection {} - impl Iterator<(uint, uint)> for ElementSwaps { #[inline] fn next(&mut self) -> Option<(uint, uint)> { diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs index bb2fed19e2a..f6bc4dbde38 100644 --- a/src/libcore/atomic.rs +++ b/src/libcore/atomic.rs @@ -16,7 +16,6 @@ pub use self::Ordering::*; use intrinsics; use cell::UnsafeCell; -use kinds::Copy; /// A boolean type which can be safely shared between threads. #[stable] @@ -53,6 +52,7 @@ pub struct AtomicPtr<T> { /// Rust's memory orderings are [the same as /// C++'s](http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync). #[stable] +#[deriving(Copy)] pub enum Ordering { /// No ordering constraints, only atomic operations. #[stable] @@ -77,8 +77,6 @@ pub enum Ordering { SeqCst, } -impl Copy for Ordering {} - /// An `AtomicBool` initialized to `false`. #[unstable = "may be renamed, pending conventions for static initalizers"] pub const INIT_ATOMIC_BOOL: AtomicBool = diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index af82e6a00f3..6e793be67e2 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -43,7 +43,7 @@ pub use self::Ordering::*; -use kinds::{Copy, Sized}; +use kinds::Sized; use option::Option::{mod, Some, None}; /// Trait for values that can be compared for equality and inequality. @@ -94,7 +94,7 @@ pub trait Eq<Sized? Rhs = Self> for Sized?: PartialEq<Rhs> { } /// An ordering is, e.g, a result of a comparison between two values. -#[deriving(Clone, PartialEq, Show)] +#[deriving(Clone, Copy, PartialEq, Show)] #[stable] pub enum Ordering { /// An ordering where a compared value is less [than another]. @@ -105,8 +105,6 @@ pub enum Ordering { Greater = 1i, } -impl Copy for Ordering {} - impl Ordering { /// Reverse the `Ordering`, so that `Less` becomes `Greater` and /// vice versa. diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index cc940cd9e20..79fb11f3854 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -44,10 +44,9 @@ pub type Result = result::Result<(), Error>; /// occurred. Any extra information must be arranged to be transmitted through /// some other means. #[experimental = "core and I/O reconciliation may alter this definition"] +#[deriving(Copy)] pub struct Error; -impl Copy for Error {} - /// A collection of methods that are required to format a message into a stream. /// /// This trait is the type which this modules requires when formatting @@ -104,6 +103,7 @@ enum Void {} /// compile time it is ensured that the function and the value have the correct /// types, and then this struct is used to canonicalize arguments to one type. #[experimental = "implementation detail of the `format_args!` macro"] +#[deriving(Copy)] pub struct Argument<'a> { value: &'a Void, formatter: fn(&Void, &mut Formatter) -> Result, @@ -137,8 +137,6 @@ impl<'a> Argument<'a> { } } -impl<'a> Copy for Argument<'a> {} - impl<'a> Arguments<'a> { /// When using the format_args!() macro, this function is used to generate the /// Arguments structure. diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index 13cfcacf8da..cd8f226172a 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -16,7 +16,6 @@ use fmt; use iter::DoubleEndedIteratorExt; -use kinds::Copy; use num::{Int, cast}; use slice::SliceExt; @@ -109,14 +108,12 @@ radix! { UpperHex, 16, "0x", x @ 0 ... 9 => b'0' + x, x @ 10 ... 15 => b'A' + (x - 10) } /// A radix with in the range of `2..36`. -#[deriving(Clone, PartialEq)] +#[deriving(Clone, Copy, PartialEq)] #[unstable = "may be renamed or move to a different module"] pub struct Radix { base: u8, } -impl Copy for Radix {} - impl Radix { fn new(base: u8) -> Radix { assert!(2 <= base && base <= 36, "the base must be in the range of 2..36: {}", base); @@ -137,10 +134,9 @@ impl GenericRadix for Radix { /// A helper type for formatting radixes. #[unstable = "may be renamed or move to a different module"] +#[deriving(Copy)] pub struct RadixFmt<T, R>(T, R); -impl<T,R> Copy for RadixFmt<T,R> where T: Copy, R: Copy {} - /// Constructs a radix formatter in the range of `2..36`. /// /// # Example diff --git a/src/libcore/fmt/rt.rs b/src/libcore/fmt/rt.rs index 748bd0bc4bd..35dd0390f30 100644 --- a/src/libcore/fmt/rt.rs +++ b/src/libcore/fmt/rt.rs @@ -20,17 +20,16 @@ pub use self::Alignment::*; pub use self::Count::*; pub use self::Position::*; pub use self::Flag::*; -use kinds::Copy; #[doc(hidden)] +#[deriving(Copy)] pub struct Argument<'a> { pub position: Position, pub format: FormatSpec, } -impl<'a> Copy for Argument<'a> {} - #[doc(hidden)] +#[deriving(Copy)] pub struct FormatSpec { pub fill: char, pub align: Alignment, @@ -39,10 +38,8 @@ pub struct FormatSpec { pub width: Count, } -impl Copy for FormatSpec {} - /// Possible alignments that can be requested as part of a formatting directive. -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub enum Alignment { /// Indication that contents should be left-aligned. AlignLeft, @@ -54,27 +51,24 @@ pub enum Alignment { AlignUnknown, } -impl Copy for Alignment {} - #[doc(hidden)] +#[deriving(Copy)] pub enum Count { CountIs(uint), CountIsParam(uint), CountIsNextParam, CountImplied, } -impl Copy for Count {} - #[doc(hidden)] +#[deriving(Copy)] pub enum Position { ArgumentNext, ArgumentIs(uint) } -impl Copy for Position {} - /// Flags which can be passed to formatting via a directive. /// /// These flags are discovered through the `flags` field of the `Formatter` /// structure. The flag in that structure is a union of these flags into a /// `uint` where each flag's discriminant is the corresponding bit. +#[deriving(Copy)] pub enum Flag { /// A flag which enables number formatting to always print the sign of a /// number. @@ -89,5 +83,3 @@ pub enum Flag { /// being aware of the sign to be printed. FlagSignAwareZeroPad, } - -impl Copy for Flag {} diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index 15f6768edce..e10f5a9fed1 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -30,6 +30,7 @@ use default::Default; use super::{Hash, Hasher, Writer}; /// `SipState` computes a SipHash 2-4 hash over a stream of bytes. +#[deriving(Copy)] pub struct SipState { k0: u64, k1: u64, @@ -42,8 +43,6 @@ pub struct SipState { ntail: uint, // how many bytes in tail are valid } -impl Copy for SipState {} - // sadly, these macro definitions can't appear later, // because they're needed in the following defs; // this design could be improved. diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index e2afee9905d..d8f103fa0f3 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -42,11 +42,10 @@ #![experimental] #![allow(missing_docs)] -use kinds::Copy; - pub type GlueFn = extern "Rust" fn(*const i8); #[lang="ty_desc"] +#[deriving(Copy)] pub struct TyDesc { // sizeof(T) pub size: uint, @@ -61,8 +60,6 @@ pub struct TyDesc { pub name: &'static str, } -impl Copy for TyDesc {} - extern "rust-intrinsic" { // NB: These intrinsics take unsafe pointers because they mutate aliased @@ -540,13 +537,11 @@ extern "rust-intrinsic" { /// `TypeId` represents a globally unique identifier for a type #[lang="type_id"] // This needs to be kept in lockstep with the code in trans/intrinsic.rs and // middle/lang_items.rs -#[deriving(Clone, PartialEq, Eq, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Show)] pub struct TypeId { t: u64, } -impl Copy for TypeId {} - impl TypeId { /// Returns the `TypeId` of the type this generic function has been instantiated with pub fn of<T: 'static>() -> TypeId { diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index de5c0defb1a..1f83aad9c7c 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -59,7 +59,6 @@ pub use self::MinMaxResult::*; use clone::Clone; use cmp; use cmp::Ord; -use kinds::Copy; use mem; use num::{ToPrimitive, Int}; use ops::{Add, Deref, FnMut}; @@ -1168,7 +1167,7 @@ impl<A, I> CloneIteratorExt for I where I: Iterator<A> + Clone { } /// An iterator that repeats endlessly -#[deriving(Clone)] +#[deriving(Clone, Copy)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] pub struct Cycle<T> { @@ -1176,8 +1175,6 @@ pub struct Cycle<T> { iter: T, } -impl<T:Copy> Copy for Cycle<T> {} - impl<A, T: Clone + Iterator<A>> Iterator<A> for Cycle<T> { #[inline] fn next(&mut self) -> Option<A> { @@ -1635,13 +1632,12 @@ impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<(uint, A)> for Enumerat /// An iterator with a `peek()` that returns an optional reference to the next element. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable] +#[deriving(Copy)] pub struct Peekable<A, T> { iter: T, peeked: Option<A>, } -impl<T:Copy,A:Copy> Copy for Peekable<A,T> {} - impl<A, T: Iterator<A>> Iterator<A> for Peekable<A, T> { #[inline] fn next(&mut self) -> Option<A> { @@ -2267,7 +2263,7 @@ impl<A, St, F> Iterator<A> for Unfold<A, St, F> where F: FnMut(&mut St) -> Optio /// An infinite iterator starting at `start` and advancing by `step` with each /// iteration -#[deriving(Clone)] +#[deriving(Clone, Copy)] #[unstable = "may be renamed"] pub struct Counter<A> { /// The current state the counter is at (next value to be yielded) @@ -2276,8 +2272,6 @@ pub struct Counter<A> { step: A, } -impl<A:Copy> Copy for Counter<A> {} - /// Creates a new counter with the specified start/step #[inline] #[unstable = "may be renamed"] @@ -2301,7 +2295,7 @@ impl<A: Add<A, A> + Clone> Iterator<A> for Counter<A> { } /// An iterator over the range [start, stop) -#[deriving(Clone)] +#[deriving(Clone, Copy)] #[unstable = "may be refactored due to numerics reform or ops reform"] pub struct Range<A> { state: A, @@ -2309,8 +2303,6 @@ pub struct Range<A> { one: A, } -impl<A:Copy> Copy for Range<A> {} - /// Returns an iterator over the given range [start, stop) (that is, starting /// at start (inclusive), and ending at stop (exclusive)). /// diff --git a/src/libcore/kinds.rs b/src/libcore/kinds.rs index 69f65e23389..93fd3f1b9f1 100644 --- a/src/libcore/kinds.rs +++ b/src/libcore/kinds.rs @@ -225,11 +225,9 @@ pub mod marker { /// For more information about variance, refer to this Wikipedia /// article <http://en.wikipedia.org/wiki/Variance_%28computer_science%29>. #[lang="covariant_lifetime"] - #[deriving(Clone, PartialEq, Eq, PartialOrd, Ord)] + #[deriving(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct CovariantLifetime<'a>; - impl<'a> Copy for 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 @@ -243,11 +241,9 @@ pub mod marker { /// For more information about variance, refer to this Wikipedia /// article <http://en.wikipedia.org/wiki/Variance_%28computer_science%29>. #[lang="contravariant_lifetime"] - #[deriving(Clone, PartialEq, Eq, PartialOrd, Ord)] + #[deriving(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct ContravariantLifetime<'a>; - impl<'a> Copy for 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 diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index fcb2ca93054..b4f867b4bb4 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1225,7 +1225,7 @@ impl_num_cast! { f32, to_f32 } impl_num_cast! { f64, to_f64 } /// Used for representing the classification of floating point numbers -#[deriving(PartialEq, Show)] +#[deriving(Copy, PartialEq, Show)] #[unstable = "may be renamed"] pub enum FPCategory { /// "Not a Number", often obtained by dividing by zero @@ -1240,8 +1240,6 @@ pub enum FPCategory { FPNormal, } -impl Copy for FPCategory {} - /// A built-in floating point number. // FIXME(#5527): In a future version of Rust, many of these functions will // become constants. diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 0090da3cdad..6e4beb2356e 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -88,10 +88,9 @@ pub trait Drop { /// calling `add`, and therefore, `main` prints `Adding!`. /// /// ```rust +/// #[deriving(Copy)] /// struct Foo; /// -/// impl Copy for Foo {} -/// /// impl Add<Foo, Foo> for Foo { /// fn add(&self, _rhs: &Foo) -> Foo { /// println!("Adding!"); @@ -170,10 +169,9 @@ add_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64 } /// calling `sub`, and therefore, `main` prints `Subtracting!`. /// /// ```rust +/// #[deriving(Copy)] /// struct Foo; /// -/// impl Copy for Foo {} -/// /// impl Sub<Foo, Foo> for Foo { /// fn sub(&self, _rhs: &Foo) -> Foo { /// println!("Subtracting!"); @@ -252,10 +250,9 @@ sub_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64 } /// calling `mul`, and therefore, `main` prints `Multiplying!`. /// /// ```rust +/// #[deriving(Copy)] /// struct Foo; /// -/// impl Copy for Foo {} -/// /// impl Mul<Foo, Foo> for Foo { /// fn mul(&self, _rhs: &Foo) -> Foo { /// println!("Multiplying!"); @@ -334,10 +331,9 @@ mul_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64 } /// calling `div`, and therefore, `main` prints `Dividing!`. /// /// ``` +/// #[deriving(Copy)] /// struct Foo; /// -/// impl Copy for Foo {} -/// /// impl Div<Foo, Foo> for Foo { /// fn div(&self, _rhs: &Foo) -> Foo { /// println!("Dividing!"); @@ -416,10 +412,9 @@ div_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64 } /// calling `rem`, and therefore, `main` prints `Remainder-ing!`. /// /// ``` +/// #[deriving(Copy)] /// struct Foo; /// -/// impl Copy for Foo {} -/// /// impl Rem<Foo, Foo> for Foo { /// fn rem(&self, _rhs: &Foo) -> Foo { /// println!("Remainder-ing!"); @@ -527,10 +522,9 @@ rem_float_impl! { f64, fmod } /// `neg`, and therefore, `main` prints `Negating!`. /// /// ``` +/// #[deriving(Copy)] /// struct Foo; /// -/// impl Copy for Foo {} -/// /// impl Neg<Foo> for Foo { /// fn neg(&self) -> Foo { /// println!("Negating!"); @@ -639,10 +633,9 @@ neg_uint_impl! { u64, i64 } /// `not`, and therefore, `main` prints `Not-ing!`. /// /// ``` +/// #[deriving(Copy)] /// struct Foo; /// -/// impl Copy for Foo {} -/// /// impl Not<Foo> for Foo { /// fn not(&self) -> Foo { /// println!("Not-ing!"); @@ -724,10 +717,9 @@ not_impl! { bool uint u8 u16 u32 u64 int i8 i16 i32 i64 } /// calling `bitand`, and therefore, `main` prints `Bitwise And-ing!`. /// /// ``` +/// #[deriving(Copy)] /// struct Foo; /// -/// impl Copy for Foo {} -/// /// impl BitAnd<Foo, Foo> for Foo { /// fn bitand(&self, _rhs: &Foo) -> Foo { /// println!("Bitwise And-ing!"); @@ -806,10 +798,9 @@ bitand_impl! { bool uint u8 u16 u32 u64 int i8 i16 i32 i64 } /// calling `bitor`, and therefore, `main` prints `Bitwise Or-ing!`. /// /// ``` +/// #[deriving(Copy)] /// struct Foo; /// -/// impl Copy for Foo {} -/// /// impl BitOr<Foo, Foo> for Foo { /// fn bitor(&self, _rhs: &Foo) -> Foo { /// println!("Bitwise Or-ing!"); @@ -888,10 +879,9 @@ bitor_impl! { bool uint u8 u16 u32 u64 int i8 i16 i32 i64 } /// calling `bitxor`, and therefore, `main` prints `Bitwise Xor-ing!`. /// /// ``` +/// #[deriving(Copy)] /// struct Foo; /// -/// impl Copy for Foo {} -/// /// impl BitXor<Foo, Foo> for Foo { /// fn bitxor(&self, _rhs: &Foo) -> Foo { /// println!("Bitwise Xor-ing!"); @@ -970,10 +960,9 @@ bitxor_impl! { bool uint u8 u16 u32 u64 int i8 i16 i32 i64 } /// calling `shl`, and therefore, `main` prints `Shifting left!`. /// /// ``` +/// #[deriving(Copy)] /// struct Foo; /// -/// impl Copy for Foo {} -/// /// impl Shl<Foo, Foo> for Foo { /// fn shl(&self, _rhs: &Foo) -> Foo { /// println!("Shifting left!"); @@ -1056,10 +1045,9 @@ shl_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 } /// calling `shr`, and therefore, `main` prints `Shifting right!`. /// /// ``` +/// #[deriving(Copy)] /// struct Foo; /// -/// impl Copy for Foo {} -/// /// impl Shr<Foo, Foo> for Foo { /// fn shr(&self, _rhs: &Foo) -> Foo { /// println!("Shifting right!"); @@ -1139,10 +1127,9 @@ shr_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 } /// calling `index`, and therefore, `main` prints `Indexing!`. /// /// ``` +/// #[deriving(Copy)] /// struct Foo; /// -/// impl Copy for Foo {} -/// /// impl Index<Foo, Foo> for Foo { /// fn index<'a>(&'a self, _index: &Foo) -> &'a Foo { /// println!("Indexing!"); @@ -1169,10 +1156,9 @@ pub trait Index<Sized? Index, Sized? Result> for Sized? { /// calling `index_mut`, and therefore, `main` prints `Indexing!`. /// /// ``` +/// #[deriving(Copy)] /// struct Foo; /// -/// impl Copy for Foo {} -/// /// impl IndexMut<Foo, Foo> for Foo { /// fn index_mut<'a>(&'a mut self, _index: &Foo) -> &'a mut Foo { /// println!("Indexing!"); @@ -1199,10 +1185,9 @@ pub trait IndexMut<Sized? Index, Sized? Result> for Sized? { /// calling `slice_to`, and therefore, `main` prints `Slicing!`. /// /// ```ignore +/// #[deriving(Copy)] /// struct Foo; /// -/// impl Copy for Foo {} -/// /// impl Slice<Foo, Foo> for Foo { /// fn as_slice_<'a>(&'a self) -> &'a Foo { /// println!("Slicing!"); @@ -1247,10 +1232,9 @@ pub trait Slice<Sized? Idx, Sized? Result> for Sized? { /// calling `slice_from_mut`, and therefore, `main` prints `Slicing!`. /// /// ```ignore +/// #[deriving(Copy)] /// struct Foo; /// -/// impl Copy for Foo {} -/// /// impl SliceMut<Foo, Foo> for Foo { /// fn as_mut_slice_<'a>(&'a mut self) -> &'a mut Foo { /// println!("Slicing!"); diff --git a/src/libcore/option.rs b/src/libcore/option.rs index deb1cea1c0e..314b47fc647 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -149,7 +149,6 @@ use cmp::{Eq, Ord}; use default::Default; use iter::{Iterator, IteratorExt, DoubleEndedIterator, FromIterator}; use iter::{ExactSizeIterator}; -use kinds::Copy; use mem; use result::Result; use result::Result::{Ok, Err}; @@ -164,7 +163,7 @@ use ops::{Deref, FnOnce}; // which basically means it must be `Option`. /// The `Option` type. -#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Show, Hash)] +#[deriving(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Show, Hash)] #[stable] pub enum Option<T> { /// No value @@ -920,7 +919,3 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> { } } } - -#[stable] -impl<T:Copy> Copy for Option<T> {} - diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs index be2f4e590a3..d70c96d8c16 100644 --- a/src/libcore/raw.rs +++ b/src/libcore/raw.rs @@ -33,25 +33,23 @@ impl<T> Copy for Slice<T> {} /// The representation of a Rust closure #[repr(C)] +#[deriving(Copy)] pub struct Closure { pub code: *mut (), pub env: *mut (), } -impl Copy for Closure {} - /// The representation of a Rust trait object. /// /// This struct does not have a `Repr` implementation /// because there is no way to refer to all trait objects generically. #[repr(C)] +#[deriving(Copy)] pub struct TraitObject { pub data: *mut (), pub vtable: *mut (), } -impl Copy for TraitObject {} - /// This trait is meant to map equivalences between raw structs and their /// corresponding rust values. pub trait Repr<T> for Sized? { diff --git a/src/libcore/result.rs b/src/libcore/result.rs index e12666a2adf..00a2a3d5854 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -232,7 +232,6 @@ use self::Result::*; -use kinds::Copy; use std::fmt::Show; use slice; use slice::AsSlice; @@ -244,7 +243,7 @@ use ops::{FnMut, FnOnce}; /// `Result` is a type that represents either success (`Ok`) or failure (`Err`). /// /// See the [`std::result`](index.html) module documentation for details. -#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Show, Hash)] +#[deriving(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Show, Hash)] #[must_use] #[stable] pub enum Result<T, E> { @@ -919,6 +918,3 @@ pub fn fold<T, } Ok(init) } - -impl<T:Copy,U:Copy> Copy for Result<T,U> {} - diff --git a/src/libcore/simd.rs b/src/libcore/simd.rs index 252a24e3aa9..0b0e6ff95c6 100644 --- a/src/libcore/simd.rs +++ b/src/libcore/simd.rs @@ -37,93 +37,70 @@ #![allow(non_camel_case_types)] #![allow(missing_docs)] -use kinds::Copy; - #[experimental] #[simd] -#[deriving(Show)] +#[deriving(Copy, Show)] #[repr(C)] pub struct i8x16(pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8); -impl Copy for i8x16 {} - #[experimental] #[simd] -#[deriving(Show)] +#[deriving(Copy, Show)] #[repr(C)] pub struct i16x8(pub i16, pub i16, pub i16, pub i16, pub i16, pub i16, pub i16, pub i16); -impl Copy for i16x8 {} - #[experimental] #[simd] -#[deriving(Show)] +#[deriving(Copy, Show)] #[repr(C)] pub struct i32x4(pub i32, pub i32, pub i32, pub i32); -impl Copy for i32x4 {} - #[experimental] #[simd] -#[deriving(Show)] +#[deriving(Copy, Show)] #[repr(C)] pub struct i64x2(pub i64, pub i64); -impl Copy for i64x2 {} - #[experimental] #[simd] -#[deriving(Show)] +#[deriving(Copy, Show)] #[repr(C)] pub struct u8x16(pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8); -impl Copy for u8x16 {} - #[experimental] #[simd] -#[deriving(Show)] +#[deriving(Copy, Show)] #[repr(C)] pub struct u16x8(pub u16, pub u16, pub u16, pub u16, pub u16, pub u16, pub u16, pub u16); -impl Copy for u16x8 {} - #[experimental] #[simd] -#[deriving(Show)] +#[deriving(Copy, Show)] #[repr(C)] pub struct u32x4(pub u32, pub u32, pub u32, pub u32); -impl Copy for u32x4 {} - #[experimental] #[simd] -#[deriving(Show)] +#[deriving(Copy, Show)] #[repr(C)] pub struct u64x2(pub u64, pub u64); -impl Copy for u64x2 {} - #[experimental] #[simd] -#[deriving(Show)] +#[deriving(Copy, Show)] #[repr(C)] pub struct f32x4(pub f32, pub f32, pub f32, pub f32); -impl Copy for f32x4 {} - #[experimental] #[simd] -#[deriving(Show)] +#[deriving(Copy, Show)] #[repr(C)] pub struct f64x2(pub f64, pub f64); - -impl Copy for f64x2 {} - diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 2ee60955245..f5d117bca9f 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -1229,7 +1229,7 @@ impl<'a, T> DoubleEndedIterator<&'a mut [T]> for MutChunks<'a, T> { /// index of the matching element. `NotFound` means the search /// succeeded, and the contained value is an index where a matching /// value could be inserted while maintaining sort order. -#[deriving(PartialEq, Show)] +#[deriving(Copy, PartialEq, Show)] #[experimental = "needs review"] pub enum BinarySearchResult { /// The index of the found value. @@ -1238,8 +1238,6 @@ pub enum BinarySearchResult { NotFound(uint) } -impl Copy for BinarySearchResult {} - #[experimental = "needs review"] impl BinarySearchResult { /// Converts a `Found` to `Some`, `NotFound` to `None`. diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 28110cf7b1a..a89a7970ae9 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -21,17 +21,18 @@ pub use self::Searcher::{Naive, TwoWay, TwoWayLong}; use char::Char; use char; +use clone::Clone; use cmp::{Eq, mod}; use default::Default; use iter::{Map, Iterator, IteratorExt, DoubleEndedIterator}; use iter::{DoubleEndedIteratorExt, ExactSizeIterator}; use iter::range; -use kinds::{Copy, Sized}; +use kinds::Sized; use mem; use num::Int; use option::Option; use option::Option::{None, Some}; -use ops::FnMut; +use ops::{Fn, FnMut}; use ptr::RawPtr; use raw::{Repr, Slice}; use slice::{mod, SliceExt}; @@ -164,13 +165,11 @@ Section: Iterators /// Iterator for the char (representing *Unicode Scalar Values*) of a string /// /// Created with the method `.chars()`. -#[deriving(Clone)] +#[deriving(Clone, Copy)] pub struct Chars<'a> { iter: slice::Items<'a, u8> } -impl<'a> Copy for Chars<'a> {} - // Return the initial codepoint accumulator for the first byte. // The first byte is special, only want bottom 5 bits for width 2, 4 bits // for width 3, and 3 bits for width 4 @@ -316,7 +315,23 @@ impl<'a> DoubleEndedIterator<(uint, char)> for CharOffsets<'a> { /// External iterator for a string's bytes. /// Use with the `std::iter` module. -pub type Bytes<'a> = Map<&'a u8, u8, slice::Items<'a, u8>, fn(&u8) -> u8>; +pub type Bytes<'a> = Map<&'a u8, u8, slice::Items<'a, u8>, BytesFn>; + +/// A temporary new type wrapper that ensures that the `Bytes` iterator +/// is cloneable. +#[deriving(Copy)] +#[experimental = "iterator type instability"] +pub struct BytesFn(fn(&u8) -> u8); + +impl<'a> Fn(&'a u8) -> u8 for BytesFn { + extern "rust-call" fn call(&self, (ptr,): (&'a u8,)) -> u8 { + (self.0)(ptr) + } +} + +impl Clone for BytesFn { + fn clone(&self) -> BytesFn { *self } +} /// An iterator over the substrings of a string, separated by `sep`. #[deriving(Clone)] @@ -981,7 +996,7 @@ pub struct Utf16Items<'a> { iter: slice::Items<'a, u16> } /// The possibilities for values decoded from a `u16` stream. -#[deriving(PartialEq, Eq, Clone, Show)] +#[deriving(Copy, PartialEq, Eq, Clone, Show)] pub enum Utf16Item { /// A valid codepoint. ScalarValue(char), @@ -989,8 +1004,6 @@ pub enum Utf16Item { LoneSurrogate(u16) } -impl Copy for Utf16Item {} - impl Utf16Item { /// Convert `self` to a `char`, taking `LoneSurrogate`s to the /// replacement character (U+FFFD). @@ -1127,6 +1140,7 @@ pub fn utf8_char_width(b: u8) -> uint { /// Struct that contains a `char` and the index of the first byte of /// the next `char` in a string. This can be used as a data structure /// for iterating over the UTF-8 bytes of a string. +#[deriving(Copy)] pub struct CharRange { /// Current `char` pub ch: char, @@ -1134,8 +1148,6 @@ pub struct CharRange { pub next: uint, } -impl Copy for CharRange {} - /// Mask of the value bits of a continuation byte const CONT_MASK: u8 = 0b0011_1111u8; /// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte @@ -2009,7 +2021,7 @@ impl StrPrelude for str { fn bytes(&self) -> Bytes { fn deref(&x: &u8) -> u8 { x } - self.as_bytes().iter().map(deref) + self.as_bytes().iter().map(BytesFn(deref)) } #[inline] diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 444806e78c1..3099bf559e4 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -35,7 +35,7 @@ use std::string; /// A piece is a portion of the format string which represents the next part /// to emit. These are emitted as a stream by the `Parser` class. -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub enum Piece<'a> { /// A literal string which should directly be emitted String(&'a str), @@ -44,10 +44,8 @@ pub enum Piece<'a> { NextArgument(Argument<'a>), } -impl<'a> Copy for Piece<'a> {} - /// Representation of an argument specification. -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub struct Argument<'a> { /// Where to find this argument pub position: Position<'a>, @@ -55,10 +53,8 @@ pub struct Argument<'a> { pub format: FormatSpec<'a>, } -impl<'a> Copy for Argument<'a> {} - /// Specification for the formatting of an argument in the format string. -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub struct FormatSpec<'a> { /// Optionally specified character to fill alignment with pub fill: Option<char>, @@ -76,10 +72,8 @@ pub struct FormatSpec<'a> { pub ty: &'a str } -impl<'a> Copy for FormatSpec<'a> {} - /// Enum describing where an argument for a format can be located. -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub enum Position<'a> { /// The argument will be in the next position. This is the default. ArgumentNext, @@ -89,10 +83,8 @@ pub enum Position<'a> { ArgumentNamed(&'a str), } -impl<'a> Copy for Position<'a> {} - /// Enum of alignments which are supported. -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub enum Alignment { /// The value will be aligned to the left. AlignLeft, @@ -104,11 +96,9 @@ pub enum Alignment { AlignUnknown, } -impl Copy for Alignment {} - /// Various flags which can be applied to format strings. The meaning of these /// flags is defined by the formatters themselves. -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub enum Flag { /// A `+` will be used to denote positive numbers. FlagSignPlus, @@ -122,11 +112,9 @@ pub enum Flag { FlagSignAwareZeroPad, } -impl Copy for Flag {} - /// A count is used for the precision and width parameters of an integer, and /// can reference either an argument or a literal integer. -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub enum Count<'a> { /// The count is specified explicitly. CountIs(uint), @@ -140,8 +128,6 @@ pub enum Count<'a> { CountImplied, } -impl<'a> Copy for Count<'a> {} - /// The parser structure for interpreting the input format string. This is /// modelled as an iterator over `Piece` structures to form a stream of tokens /// being output. diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index 38729eece5a..b45d0c9b01e 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -118,7 +118,7 @@ pub enum Name { } /// Describes whether an option has an argument. -#[deriving(Clone, PartialEq, Eq)] +#[deriving(Clone, Copy, PartialEq, Eq)] pub enum HasArg { /// The option requires an argument. Yes, @@ -128,10 +128,8 @@ pub enum HasArg { Maybe, } -impl Copy for HasArg {} - /// Describes how often an option may occur. -#[deriving(Clone, PartialEq, Eq)] +#[deriving(Clone, Copy, PartialEq, Eq)] pub enum Occur { /// The option occurs once. Req, @@ -141,8 +139,6 @@ pub enum Occur { Multi, } -impl Copy for Occur {} - /// A description of a possible option. #[deriving(Clone, PartialEq, Eq)] pub struct Opt { @@ -211,7 +207,7 @@ pub enum Fail { } /// The type of failure that occurred. -#[deriving(PartialEq, Eq)] +#[deriving(Copy, PartialEq, Eq)] #[allow(missing_docs)] pub enum FailType { ArgumentMissing_, @@ -221,8 +217,6 @@ pub enum FailType { UnexpectedArgument_, } -impl Copy for FailType {} - /// The result of parsing a command line with a set of options. pub type Result = result::Result<Matches, Fail>; @@ -839,22 +833,22 @@ pub fn short_usage(program_name: &str, opts: &[OptGroup]) -> String { line } +#[deriving(Copy)] enum SplitWithinState { A, // leading whitespace, initial state B, // words C, // internal and trailing whitespace } -impl Copy for SplitWithinState {} +#[deriving(Copy)] enum Whitespace { Ws, // current char is whitespace Cr // current char is not whitespace } -impl Copy for Whitespace {} +#[deriving(Copy)] enum LengthLimit { UnderLim, // current char makes current substring still fit in limit OverLim // current char makes current substring no longer fit in limit } -impl Copy for LengthLimit {} /// Splits a string into substrings with possibly internal whitespace, diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 257ce79b588..2bf9af90271 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -232,11 +232,9 @@ struct DefaultLogger { } /// Wraps the log level with fmt implementations. -#[deriving(PartialEq, PartialOrd)] +#[deriving(Copy, PartialEq, PartialOrd)] pub struct LogLevel(pub u32); -impl Copy for LogLevel {} - impl fmt::Show for LogLevel { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let LogLevel(level) = *self; @@ -341,14 +339,13 @@ pub struct LogRecord<'a> { } #[doc(hidden)] +#[deriving(Copy)] pub struct LogLocation { pub module_path: &'static str, pub file: &'static str, pub line: uint, } -impl Copy for LogLocation {} - /// Tests whether a given module's name is enabled for a particular level of /// logging. This is the second layer of defense about determining whether a /// module's log statement should be emitted or not. diff --git a/src/librand/chacha.rs b/src/librand/chacha.rs index 5cbc5a0a61c..6fc92e1e94f 100644 --- a/src/librand/chacha.rs +++ b/src/librand/chacha.rs @@ -29,14 +29,13 @@ const CHACHA_ROUNDS: uint = 20; // Cryptographically secure from 8 upwards as of /// [1]: D. J. Bernstein, [*ChaCha, a variant of /// Salsa20*](http://cr.yp.to/chacha.html) +#[deriving(Copy)] pub struct ChaChaRng { buffer: [u32, ..STATE_WORDS], // Internal buffer of output state: [u32, ..STATE_WORDS], // Initial state index: uint, // Index into state } -impl Copy for ChaChaRng {} - static EMPTY: ChaChaRng = ChaChaRng { buffer: [0, ..STATE_WORDS], state: [0, ..STATE_WORDS], diff --git a/src/librand/distributions/exponential.rs b/src/librand/distributions/exponential.rs index 9a9f31e9339..431a530726a 100644 --- a/src/librand/distributions/exponential.rs +++ b/src/librand/distributions/exponential.rs @@ -10,7 +10,6 @@ //! The exponential distribution. -use core::kinds::Copy; use core::num::Float; use {Rng, Rand}; @@ -30,10 +29,9 @@ use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample}; /// Generate Normal Random /// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield /// College, Oxford +#[deriving(Copy)] pub struct Exp1(pub f64); -impl Copy for Exp1 {} - // This could be done via `-rng.gen::<f64>().ln()` but that is slower. impl Rand for Exp1 { #[inline] @@ -69,13 +67,12 @@ impl Rand for Exp1 { /// let v = exp.ind_sample(&mut rand::task_rng()); /// println!("{} is from a Exp(2) distribution", v); /// ``` +#[deriving(Copy)] pub struct Exp { /// `lambda` stored as `1/lambda`, since this is what we scale by. lambda_inverse: f64 } -impl Copy for Exp {} - impl Exp { /// Construct a new `Exp` with the given shape parameter /// `lambda`. Panics if `lambda <= 0`. diff --git a/src/librand/distributions/normal.rs b/src/librand/distributions/normal.rs index f5261f1db82..16413af6267 100644 --- a/src/librand/distributions/normal.rs +++ b/src/librand/distributions/normal.rs @@ -10,7 +10,6 @@ //! The normal and derived distributions. -use core::kinds::Copy; use core::num::Float; use {Rng, Rand, Open01}; @@ -29,10 +28,9 @@ use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample}; /// Generate Normal Random /// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield /// College, Oxford +#[deriving(Copy)] pub struct StandardNormal(pub f64); -impl Copy for StandardNormal {} - impl Rand for StandardNormal { fn rand<R:Rng>(rng: &mut R) -> StandardNormal { #[inline] @@ -86,13 +84,12 @@ impl Rand for StandardNormal { /// let v = normal.ind_sample(&mut rand::task_rng()); /// println!("{} is from a N(2, 9) distribution", v) /// ``` +#[deriving(Copy)] pub struct Normal { mean: f64, std_dev: f64, } -impl Copy for Normal {} - impl Normal { /// Construct a new `Normal` distribution with the given mean and /// standard deviation. @@ -135,12 +132,11 @@ impl IndependentSample<f64> for Normal { /// let v = log_normal.ind_sample(&mut rand::task_rng()); /// println!("{} is from an ln N(2, 9) distribution", v) /// ``` +#[deriving(Copy)] pub struct LogNormal { norm: Normal } -impl Copy for LogNormal {} - impl LogNormal { /// Construct a new `LogNormal` distribution with the given mean /// and standard deviation. diff --git a/src/librand/isaac.rs b/src/librand/isaac.rs index 2499d7f529f..3cb1f51a6a8 100644 --- a/src/librand/isaac.rs +++ b/src/librand/isaac.rs @@ -29,6 +29,7 @@ const RAND_SIZE_UINT: uint = 1 << (RAND_SIZE_LEN as uint); /// /// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number /// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html) +#[deriving(Copy)] pub struct IsaacRng { cnt: u32, rsl: [u32, ..RAND_SIZE_UINT], @@ -38,8 +39,6 @@ pub struct IsaacRng { c: u32 } -impl Copy for IsaacRng {} - static EMPTY: IsaacRng = IsaacRng { cnt: 0, rsl: [0, ..RAND_SIZE_UINT], @@ -265,6 +264,7 @@ const RAND_SIZE_64: uint = 1 << RAND_SIZE_64_LEN; /// /// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number /// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html) +#[deriving(Copy)] pub struct Isaac64Rng { cnt: uint, rsl: [u64, .. RAND_SIZE_64], @@ -274,8 +274,6 @@ pub struct Isaac64Rng { c: u64, } -impl Copy for Isaac64Rng {} - static EMPTY_64: Isaac64Rng = Isaac64Rng { cnt: 0, rsl: [0, .. RAND_SIZE_64], diff --git a/src/librand/lib.rs b/src/librand/lib.rs index dfcdad481a9..514ff81da51 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -501,6 +501,7 @@ pub struct Closed01<F>(pub F); #[cfg(not(test))] mod std { pub use core::{option, fmt}; // panic!() + pub use core::kinds; } #[cfg(test)] diff --git a/src/librand/reseeding.rs b/src/librand/reseeding.rs index 46ee67940f2..94a11c040e4 100644 --- a/src/librand/reseeding.rs +++ b/src/librand/reseeding.rs @@ -133,10 +133,9 @@ pub trait Reseeder<R> { /// Reseed an RNG using a `Default` instance. This reseeds by /// replacing the RNG with the result of a `Default::default` call. +#[deriving(Copy)] pub struct ReseedWithDefault; -impl Copy for ReseedWithDefault {} - impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault { fn reseed(&mut self, rng: &mut R) { *rng = Default::default(); diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index bb7af92eb54..19e79b1eb7b 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -41,15 +41,13 @@ use std::str; pub mod io; /// Common data structures -#[deriving(Clone)] +#[deriving(Clone, Copy)] pub struct Doc<'a> { pub data: &'a [u8], pub start: uint, pub end: uint, } -impl<'doc> Copy for Doc<'doc> {} - impl<'doc> Doc<'doc> { pub fn new(data: &'doc [u8]) -> Doc<'doc> { Doc { data: data, start: 0u, end: data.len() } @@ -73,7 +71,7 @@ pub struct TaggedDoc<'a> { pub doc: Doc<'a>, } -#[deriving(Show)] +#[deriving(Copy, Show)] pub enum EbmlEncoderTag { EsUint, // 0 EsU64, // 1 @@ -107,8 +105,6 @@ pub enum EbmlEncoderTag { EsLabel, // Used only when debugging } -impl Copy for EbmlEncoderTag {} - #[deriving(Show)] pub enum Error { IntTooBig(uint), @@ -151,13 +147,12 @@ pub mod reader { ) } + #[deriving(Copy)] pub struct Res { pub val: uint, pub next: uint } - impl Copy for Res {} - #[inline(never)] fn vuint_at_slow(data: &[u8], start: uint) -> DecodeResult<Res> { let a = data[start]; diff --git a/src/libregex/parse.rs b/src/libregex/parse.rs index 60cf45aeddc..78558a32266 100644 --- a/src/libregex/parse.rs +++ b/src/libregex/parse.rs @@ -77,14 +77,12 @@ pub enum Repeater { OneMore, } -#[deriving(Show, Clone)] +#[deriving(Copy, Show, Clone)] pub enum Greed { Greedy, Ungreedy, } -impl Copy for Greed {} - impl Greed { pub fn is_greedy(&self) -> bool { match *self { diff --git a/src/libregex/re.rs b/src/libregex/re.rs index 53181bfbb7e..151587e423a 100644 --- a/src/libregex/re.rs +++ b/src/libregex/re.rs @@ -126,6 +126,7 @@ pub struct ExDynamic { } #[doc(hidden)] +#[deriving(Copy)] pub struct ExNative { #[doc(hidden)] pub original: &'static str, @@ -135,8 +136,6 @@ pub struct ExNative { pub prog: fn(MatchKind, &str, uint, uint) -> Vec<Option<uint>> } -impl Copy for ExNative {} - impl Clone for ExNative { fn clone(&self) -> ExNative { *self diff --git a/src/libregex/vm.rs b/src/libregex/vm.rs index 15a678d2e74..990d5a159f6 100644 --- a/src/libregex/vm.rs +++ b/src/libregex/vm.rs @@ -50,6 +50,7 @@ use unicode::regex::PERLW; pub type CaptureLocs = Vec<Option<uint>>; /// Indicates the type of match to be performed by the VM. +#[deriving(Copy)] pub enum MatchKind { /// Only checks if a match exists or not. Does not return location. Exists, @@ -60,8 +61,6 @@ pub enum MatchKind { Submatches, } -impl Copy for MatchKind {} - /// Runs an NFA simulation on the compiled expression given on the search text /// `input`. The search begins at byte index `start` and ends at byte index /// `end`. (The range is specified here so that zero-width assertions will work @@ -96,6 +95,7 @@ struct Nfa<'r, 't> { /// Indicates the next action to take after a single non-empty instruction /// is processed. +#[deriving(Copy)] pub enum StepState { /// This is returned if and only if a Match instruction is reached and /// we only care about the existence of a match. It instructs the VM to @@ -109,8 +109,6 @@ pub enum StepState { StepContinue, } -impl Copy for StepState {} - impl<'r, 't> Nfa<'r, 't> { fn run(&mut self) -> CaptureLocs { let ncaps = match self.which { diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 8c25bc702b3..88b12aa5660 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -56,10 +56,9 @@ declare_lint! { "suggest using `loop { }` instead of `while true { }`" } +#[deriving(Copy)] pub struct WhileTrue; -impl Copy for WhileTrue {} - impl LintPass for WhileTrue { fn get_lints(&self) -> LintArray { lint_array!(WHILE_TRUE) @@ -83,10 +82,9 @@ declare_lint! { "detects unnecessary type casts that can be removed" } +#[deriving(Copy)] pub struct UnusedCasts; -impl Copy for UnusedCasts {} - impl LintPass for UnusedCasts { fn get_lints(&self) -> LintArray { lint_array!(UNUSED_TYPECASTS) @@ -126,13 +124,12 @@ declare_lint! { "shift exceeds the type's number of bits" } +#[deriving(Copy)] pub struct TypeLimits { /// Id of the last visited negated expression negated_expr_id: ast::NodeId, } -impl Copy for TypeLimits {} - impl TypeLimits { pub fn new() -> TypeLimits { TypeLimits { @@ -442,10 +439,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ImproperCTypesVisitor<'a, 'tcx> { } } +#[deriving(Copy)] pub struct ImproperCTypes; -impl Copy for ImproperCTypes {} - impl LintPass for ImproperCTypes { fn get_lints(&self) -> LintArray { lint_array!(IMPROPER_CTYPES) @@ -486,10 +482,9 @@ declare_lint! { "use of owned (Box type) heap memory" } +#[deriving(Copy)] pub struct BoxPointers; -impl Copy for BoxPointers {} - impl BoxPointers { fn check_heap_type<'a, 'tcx>(&self, cx: &Context<'a, 'tcx>, span: Span, ty: Ty<'tcx>) { @@ -627,10 +622,9 @@ declare_lint! { "detects attributes that were not used by the compiler" } +#[deriving(Copy)] pub struct UnusedAttributes; -impl Copy for UnusedAttributes {} - impl LintPass for UnusedAttributes { fn get_lints(&self) -> LintArray { lint_array!(UNUSED_ATTRIBUTES) @@ -711,10 +705,9 @@ declare_lint! { "path statements with no effect" } +#[deriving(Copy)] pub struct PathStatements; -impl Copy for PathStatements {} - impl LintPass for PathStatements { fn get_lints(&self) -> LintArray { lint_array!(PATH_STATEMENTS) @@ -746,10 +739,9 @@ declare_lint! { "unused result of an expression in a statement" } +#[deriving(Copy)] pub struct UnusedResults; -impl Copy for UnusedResults {} - impl LintPass for UnusedResults { fn get_lints(&self) -> LintArray { lint_array!(UNUSED_MUST_USE, UNUSED_RESULTS) @@ -815,10 +807,9 @@ declare_lint! { "types, variants, traits and type parameters should have camel case names" } +#[deriving(Copy)] pub struct NonCamelCaseTypes; -impl Copy for NonCamelCaseTypes {} - impl NonCamelCaseTypes { fn check_case(&self, cx: &Context, sort: &str, ident: ast::Ident, span: Span) { fn is_camel_case(ident: ast::Ident) -> bool { @@ -939,10 +930,9 @@ declare_lint! { "methods, functions, lifetime parameters and modules should have snake case names" } +#[deriving(Copy)] pub struct NonSnakeCase; -impl Copy for NonSnakeCase {} - impl NonSnakeCase { fn check_snake_case(&self, cx: &Context, sort: &str, ident: ast::Ident, span: Span) { fn is_snake_case(ident: ast::Ident) -> bool { @@ -1053,10 +1043,9 @@ declare_lint! { "static constants should have uppercase identifiers" } +#[deriving(Copy)] pub struct NonUpperCaseGlobals; -impl Copy for NonUpperCaseGlobals {} - impl LintPass for NonUpperCaseGlobals { fn get_lints(&self) -> LintArray { lint_array!(NON_UPPER_CASE_GLOBALS) @@ -1107,10 +1096,9 @@ declare_lint! { "`if`, `match`, `while` and `return` do not need parentheses" } +#[deriving(Copy)] pub struct UnusedParens; -impl Copy for UnusedParens {} - impl UnusedParens { fn check_unused_parens_core(&self, cx: &Context, value: &ast::Expr, msg: &str, struct_lit_needs_parens: bool) { @@ -1202,10 +1190,9 @@ declare_lint! { "unnecessary braces around an imported item" } +#[deriving(Copy)] pub struct UnusedImportBraces; -impl Copy for UnusedImportBraces {} - impl LintPass for UnusedImportBraces { fn get_lints(&self) -> LintArray { lint_array!(UNUSED_IMPORT_BRACES) @@ -1242,10 +1229,9 @@ declare_lint! { "using `Struct { x: x }` instead of `Struct { x }`" } +#[deriving(Copy)] pub struct NonShorthandFieldPatterns; -impl Copy for NonShorthandFieldPatterns {} - impl LintPass for NonShorthandFieldPatterns { fn get_lints(&self) -> LintArray { lint_array!(NON_SHORTHAND_FIELD_PATTERNS) @@ -1276,10 +1262,9 @@ declare_lint! { "unnecessary use of an `unsafe` block" } +#[deriving(Copy)] pub struct UnusedUnsafe; -impl Copy for UnusedUnsafe {} - impl LintPass for UnusedUnsafe { fn get_lints(&self) -> LintArray { lint_array!(UNUSED_UNSAFE) @@ -1302,10 +1287,9 @@ declare_lint! { "usage of an `unsafe` block" } +#[deriving(Copy)] pub struct UnsafeBlocks; -impl Copy for UnsafeBlocks {} - impl LintPass for UnsafeBlocks { fn get_lints(&self) -> LintArray { lint_array!(UNSAFE_BLOCKS) @@ -1327,10 +1311,9 @@ declare_lint! { "detect mut variables which don't need to be mutable" } +#[deriving(Copy)] pub struct UnusedMut; -impl Copy for UnusedMut {} - impl UnusedMut { fn check_unused_mut_pat(&self, cx: &Context, pats: &[P<ast::Pat>]) { // collect all mutable pattern and group their NodeIDs by their Identifier to @@ -1397,10 +1380,9 @@ declare_lint! { "detects unnecessary allocations that can be eliminated" } +#[deriving(Copy)] pub struct UnusedAllocation; -impl Copy for UnusedAllocation {} - impl LintPass for UnusedAllocation { fn get_lints(&self) -> LintArray { lint_array!(UNUSED_ALLOCATION) @@ -1589,10 +1571,9 @@ impl LintPass for MissingDoc { } } +#[deriving(Copy)] pub struct MissingCopyImplementations; -impl Copy for MissingCopyImplementations {} - impl LintPass for MissingCopyImplementations { fn get_lints(&self) -> LintArray { lint_array!(MISSING_COPY_IMPLEMENTATIONS) @@ -1665,10 +1646,9 @@ declare_lint! { /// Checks for use of items with `#[deprecated]`, `#[experimental]` and /// `#[unstable]` attributes, or no stability attribute. +#[deriving(Copy)] pub struct Stability; -impl Copy for Stability {} - impl Stability { fn lint(&self, cx: &Context, id: ast::DefId, span: Span) { let stability = stability::lookup(cx.tcx, id); @@ -1784,9 +1764,7 @@ impl LintPass for Stability { method_num: index, .. }) => { - ty::trait_item(cx.tcx, - trait_ref.def_id, - index).def_id() + ty::trait_item(cx.tcx, trait_ref.def_id, index).def_id() } } } @@ -1905,10 +1883,9 @@ declare_lint!{ /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. +#[deriving(Copy)] pub struct HardwiredLints; -impl Copy for HardwiredLints {} - impl LintPass for HardwiredLints { fn get_lints(&self) -> LintArray { lint_array!( diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 79d57305f96..009a1d444dc 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -42,6 +42,7 @@ use syntax::ast; pub use lint::context::{Context, LintStore, raw_emit_lint, check_crate, gather_attrs}; /// Specification of a single lint. +#[deriving(Copy)] pub struct Lint { /// A string identifier for the lint. /// @@ -64,8 +65,6 @@ pub struct Lint { pub desc: &'static str, } -impl Copy for Lint {} - impl Lint { /// Get the lint's name, with ASCII letters converted to lowercase. pub fn name_lower(&self) -> String { @@ -175,14 +174,12 @@ pub trait LintPass { pub type LintPassObject = Box<LintPass + 'static>; /// Identifies a lint known to the compiler. -#[deriving(Clone)] +#[deriving(Clone, Copy)] pub struct LintId { // Identity is based on pointer equality of this field. lint: &'static Lint, } -impl Copy for LintId {} - impl PartialEq for LintId { fn eq(&self, other: &LintId) -> bool { (self.lint as *const Lint) == (other.lint as *const Lint) @@ -213,13 +210,11 @@ impl LintId { } /// Setting for how to handle a lint. -#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord)] +#[deriving(Clone, Copy, PartialEq, PartialOrd, Eq, Ord)] pub enum Level { Allow, Warn, Deny, Forbid } -impl Copy for Level {} - impl Level { /// Convert a level to a lower-case string. pub fn as_str(self) -> &'static str { @@ -244,7 +239,7 @@ impl Level { } /// How a lint level was set. -#[deriving(Clone, PartialEq, Eq)] +#[deriving(Clone, Copy, PartialEq, Eq)] pub enum LintSource { /// Lint is at the default level as declared /// in rustc or a plugin. @@ -257,8 +252,6 @@ pub enum LintSource { CommandLine, } -impl Copy for LintSource {} - pub type LevelSource = (Level, LintSource); pub mod builtin; diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index b698e4fcc7f..03e436e98df 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -113,7 +113,7 @@ pub const tag_items_data_item_reexport_def_id: uint = 0x39; pub const tag_items_data_item_reexport_name: uint = 0x3a; // used to encode crate_ctxt side tables -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] #[repr(uint)] pub enum astencode_tag { // Reserves 0x40 -- 0x5f tag_ast = 0x40, @@ -145,7 +145,6 @@ pub enum astencode_tag { // Reserves 0x40 -- 0x5f tag_table_object_cast_map = 0x57, } -impl Copy for astencode_tag {} static first_astencode_tag: uint = tag_ast as uint; static last_astencode_tag: uint = tag_table_object_cast_map as uint; impl astencode_tag { diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 4cbb1babf9a..a474af7c6e1 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -33,14 +33,13 @@ use syntax::parse::token; use std::collections::hash_map::HashMap; +#[deriving(Copy)] pub struct MethodInfo { pub name: ast::Name, pub def_id: ast::DefId, pub vis: ast::Visibility, } -impl Copy for MethodInfo {} - pub fn get_symbol(cstore: &cstore::CStore, def: ast::DefId) -> String { let cdata = cstore.get_crate_data(def.krate); decoder::get_symbol(cdata.data(), def.node) diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index cede093fae6..d5247472c34 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -48,23 +48,19 @@ pub struct crate_metadata { pub span: Span, } -#[deriving(Show, PartialEq, Clone)] +#[deriving(Copy, Show, PartialEq, Clone)] pub enum LinkagePreference { RequireDynamic, RequireStatic, } -impl Copy for LinkagePreference {} - -#[deriving(Clone, PartialEq, FromPrimitive)] +#[deriving(Copy, Clone, PartialEq, FromPrimitive)] pub enum NativeLibraryKind { NativeStatic, // native static library (.a archive) NativeFramework, // OSX-specific NativeUnknown, // default way to specify a dynamic library } -impl Copy for NativeLibraryKind {} - // Where a crate came from on the local filesystem. One of these two options // must be non-None. #[deriving(PartialEq, Clone)] diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index b78112f1f78..b89c5dbcd08 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -450,15 +450,13 @@ pub fn get_symbol(data: &[u8], id: ast::NodeId) -> String { } // Something that a name can resolve to. -#[deriving(Clone,Show)] +#[deriving(Copy, Clone, Show)] pub enum DefLike { DlDef(def::Def), DlImpl(ast::DefId), DlField } -impl Copy for DefLike {} - /// Iterates over the language items in the given crate. pub fn each_lang_item<F>(cdata: Cmd, mut f: F) -> bool where F: FnMut(ast::NodeId, uint) -> bool, @@ -704,7 +702,7 @@ pub fn get_enum_variants<'tcx>(intr: Rc<IdentInterner>, cdata: Cmd, id: ast::Nod let name = item_name(&*intr, item); let (ctor_ty, arg_tys, arg_names) = match ctor_ty.sty { ty::ty_bare_fn(ref f) => - (Some(ctor_ty), f.sig.inputs.clone(), None), + (Some(ctor_ty), f.sig.0.inputs.clone(), None), _ => { // Nullary or struct enum variant. let mut arg_names = Vec::new(); let arg_tys = get_struct_fields(intr.clone(), cdata, did.node) diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index 507fb751303..0b859abc531 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -20,13 +20,12 @@ use std::os; use util::fs as myfs; +#[deriving(Copy)] pub enum FileMatch { FileMatches, FileDoesntMatch, } -impl Copy for FileMatch {} - // A module for searching for libraries // FIXME (#2658): I'm not happy how this module turned out. Should // probably just be folded into cstore. diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index d649c649131..9d3a2c1d667 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -21,7 +21,7 @@ pub use self::DefIdSource::*; use middle::region; use middle::subst; use middle::subst::VecPerParamSpace; -use middle::ty::{mod, Ty}; +use middle::ty::{mod, AsPredicate, Ty}; use std::rc::Rc; use std::str; @@ -44,7 +44,7 @@ use syntax::parse::token; // def-id will depend on where it originated from. Therefore, the conversion // function is given an indicator of the source of the def-id. See // astencode.rs for more information. -#[deriving(Show)] +#[deriving(Copy, Show)] pub enum DefIdSource { // Identifies a struct, trait, enum, etc. NominalType, @@ -62,7 +62,6 @@ pub enum DefIdSource { UnboxedClosureSource } -impl Copy for DefIdSource {} pub type conv_did<'a> = |source: DefIdSource, ast::DefId|: 'a -> ast::DefId; @@ -414,7 +413,7 @@ fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> { } 'x' => { assert_eq!(next(st), '['); - let trait_ref = parse_trait_ref(st, |x,y| conv(x,y)); + let trait_ref = ty::Binder(parse_trait_ref(st, |x,y| conv(x,y))); let bounds = parse_existential_bounds(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); return ty::mk_trait(st.tcx, trait_ref, bounds); @@ -603,7 +602,7 @@ fn parse_bare_fn_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, } } -fn parse_sig<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> ty::FnSig<'tcx> { +fn parse_sig<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> ty::PolyFnSig<'tcx> { assert_eq!(next(st), '['); let mut inputs = Vec::new(); while peek(st) != ']' { @@ -622,9 +621,9 @@ fn parse_sig<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> ty::FnSig<' } _ => ty::FnConverging(parse_ty(st, |x,y| conv(x,y))) }; - ty::FnSig {inputs: inputs, - output: output, - variadic: variadic} + ty::Binder(ty::FnSig {inputs: inputs, + output: output, + variadic: variadic}) } // Rust metadata parsing @@ -669,13 +668,13 @@ pub fn parse_predicate<'a,'tcx>(st: &mut PState<'a, 'tcx>, -> ty::Predicate<'tcx> { match next(st) { - 't' => ty::Predicate::Trait(Rc::new(parse_trait_ref(st, conv))), - 'e' => ty::Predicate::Equate(parse_ty(st, |x,y| conv(x,y)), - parse_ty(st, |x,y| conv(x,y))), - 'r' => ty::Predicate::RegionOutlives(parse_region(st, |x,y| conv(x,y)), - parse_region(st, |x,y| conv(x,y))), - 'o' => ty::Predicate::TypeOutlives(parse_ty(st, |x,y| conv(x,y)), - parse_region(st, |x,y| conv(x,y))), + 't' => Rc::new(ty::Binder(parse_trait_ref(st, conv))).as_predicate(), + 'e' => ty::Binder(ty::EquatePredicate(parse_ty(st, |x,y| conv(x,y)), + parse_ty(st, |x,y| conv(x,y)))).as_predicate(), + 'r' => ty::Binder(ty::OutlivesPredicate(parse_region(st, |x,y| conv(x,y)), + parse_region(st, |x,y| conv(x,y)))).as_predicate(), + 'o' => ty::Binder(ty::OutlivesPredicate(parse_ty(st, |x,y| conv(x,y)), + parse_region(st, |x,y| conv(x,y)))).as_predicate(), c => panic!("Encountered invalid character in metadata: {}", c) } } @@ -759,10 +758,12 @@ fn parse_bounds<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) loop { match next(st) { 'R' => { - param_bounds.region_bounds.push(parse_region(st, |x, y| conv (x, y))); + param_bounds.region_bounds.push( + parse_region(st, |x, y| conv (x, y))); } 'I' => { - param_bounds.trait_bounds.push(Rc::new(parse_trait_ref(st, |x,y| conv(x,y)))); + param_bounds.trait_bounds.push( + Rc::new(ty::Binder(parse_trait_ref(st, |x,y| conv(x,y))))); } '.' => { return param_bounds; diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 2a057da7db3..5d7d85d4679 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -251,7 +251,7 @@ fn enc_sty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { mywrite!(w, "x["); - enc_trait_ref(w, cx, principal); + enc_trait_ref(w, cx, &principal.0); enc_existential_bounds(w, cx, bounds); mywrite!(w, "]"); } @@ -351,18 +351,18 @@ pub fn enc_closure_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, } fn enc_fn_sig<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, - fsig: &ty::FnSig<'tcx>) { + fsig: &ty::PolyFnSig<'tcx>) { mywrite!(w, "["); - for ty in fsig.inputs.iter() { + for ty in fsig.0.inputs.iter() { enc_ty(w, cx, *ty); } mywrite!(w, "]"); - if fsig.variadic { + if fsig.0.variadic { mywrite!(w, "V"); } else { mywrite!(w, "N"); } - match fsig.output { + match fsig.0.output { ty::FnConverging(result_type) => { enc_ty(w, cx, result_type); } @@ -401,7 +401,7 @@ pub fn enc_bounds<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, for tp in bs.trait_bounds.iter() { mywrite!(w, "I"); - enc_trait_ref(w, cx, &**tp); + enc_trait_ref(w, cx, &tp.0); } mywrite!(w, "."); @@ -425,19 +425,19 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter, match *p { ty::Predicate::Trait(ref trait_ref) => { mywrite!(w, "t"); - enc_trait_ref(w, cx, &**trait_ref); + enc_trait_ref(w, cx, &trait_ref.0); } - ty::Predicate::Equate(a, b) => { + ty::Predicate::Equate(ty::Binder(ty::EquatePredicate(a, b))) => { mywrite!(w, "e"); enc_ty(w, cx, a); enc_ty(w, cx, b); } - ty::Predicate::RegionOutlives(a, b) => { + ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => { mywrite!(w, "r"); enc_region(w, cx, a); enc_region(w, cx, b); } - ty::Predicate::TypeOutlives(a, b) => { + ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => { mywrite!(w, "o"); enc_ty(w, cx, a); enc_region(w, cx, b); diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index a37f9cb939d..69fbd59fd92 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1113,7 +1113,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { this.emit_enum_variant("UnsizeVtable", 2, 4, |this| { this.emit_enum_variant_arg(0, |this| { try!(this.emit_struct_field("principal", 0, |this| { - Ok(this.emit_trait_ref(ecx, &*principal)) + Ok(this.emit_trait_ref(ecx, &principal.0)) })); this.emit_struct_field("bounds", 1, |this| { Ok(this.emit_existential_bounds(ecx, b)) @@ -1277,7 +1277,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, rbml_w.tag(c::tag_table_object_cast_map, |rbml_w| { rbml_w.id(id); rbml_w.tag(c::tag_table_val, |rbml_w| { - rbml_w.emit_trait_ref(ecx, &**trait_ref); + rbml_w.emit_trait_ref(ecx, &trait_ref.0); }) }) } @@ -1356,6 +1356,8 @@ trait rbml_decoder_decoder_helpers<'tcx> { fn read_tys<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Vec<Ty<'tcx>>; fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Rc<ty::TraitRef<'tcx>>; + fn read_poly_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) + -> Rc<ty::PolyTraitRef<'tcx>>; fn read_type_param_def<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::TypeParameterDef<'tcx>; fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) @@ -1548,6 +1550,19 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { }).unwrap()) } + fn read_poly_trait_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) + -> Rc<ty::PolyTraitRef<'tcx>> { + Rc::new(ty::Binder(self.read_opaque(|this, doc| { + let ty = tydecode::parse_trait_ref_data( + doc.data, + dcx.cdata.cnum, + doc.start, + dcx.tcx, + |s, a| this.convert_def_id(dcx, s, a)); + Ok(ty) + }).unwrap())) + } + fn read_type_param_def<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> ty::TypeParameterDef<'tcx> { self.read_opaque(|this, doc| { @@ -1753,7 +1768,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { 2 => { let ty_trait = try!(this.read_enum_variant_arg(0, |this| { let principal = try!(this.read_struct_field("principal", 0, |this| { - Ok(this.read_trait_ref(dcx)) + Ok(this.read_poly_trait_ref(dcx)) })); Ok(ty::TyTrait { principal: (*principal).clone(), @@ -1926,7 +1941,7 @@ fn decode_side_tables(dcx: &DecodeContext, dcx.tcx.method_map.borrow_mut().insert(method_call, method); } c::tag_table_object_cast_map => { - let trait_ref = val_dsr.read_trait_ref(dcx); + let trait_ref = val_dsr.read_poly_trait_ref(dcx); dcx.tcx.object_cast_map.borrow_mut() .insert(id, trait_ref); } diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 0e10155beb4..82bed254031 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -26,14 +26,13 @@ struct CFGBuilder<'a, 'tcx: 'a> { loop_scopes: Vec<LoopScope>, } +#[deriving(Copy)] struct LoopScope { loop_id: ast::NodeId, // id of loop/while node continue_index: CFGIndex, // where to go on a `loop` break_index: CFGIndex, // where to go on a `break } -impl Copy for LoopScope {} - pub fn construct(tcx: &ty::ctxt, blk: &ast::Block) -> CFG { let mut graph = graph::Graph::new(); diff --git a/src/librustc/middle/cfg/mod.rs b/src/librustc/middle/cfg/mod.rs index bc512a73a4b..a74fff5630b 100644 --- a/src/librustc/middle/cfg/mod.rs +++ b/src/librustc/middle/cfg/mod.rs @@ -26,12 +26,11 @@ pub struct CFG { pub exit: CFGIndex, } +#[deriving(Copy)] pub struct CFGNodeData { pub id: ast::NodeId } -impl Copy for CFGNodeData {} - pub struct CFGEdgeData { pub exiting_scopes: Vec<ast::NodeId> } diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs index c4ad089d76e..cb454f94dc7 100644 --- a/src/librustc/middle/check_loop.rs +++ b/src/librustc/middle/check_loop.rs @@ -16,20 +16,17 @@ use syntax::codemap::Span; use syntax::visit::Visitor; use syntax::visit; -#[deriving(Clone, PartialEq)] +#[deriving(Clone, Copy, PartialEq)] enum Context { Normal, Loop, Closure } -impl Copy for Context {} - +#[deriving(Copy)] struct CheckLoopVisitor<'a> { sess: &'a Session, cx: Context } -impl<'a> Copy for CheckLoopVisitor<'a> {} - pub fn check_crate(sess: &Session, krate: &ast::Crate) { visit::walk_crate(&mut CheckLoopVisitor { sess: sess, cx: Normal }, krate) } diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 034bf3e840a..79e776c3308 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -127,13 +127,12 @@ enum Usefulness { NotUseful } +#[deriving(Copy)] enum WitnessPreference { ConstructWitness, LeaveOutWitness } -impl Copy for WitnessPreference {} - impl<'a, 'tcx, 'v> Visitor<'v> for MatchCheckCtxt<'a, 'tcx> { fn visit_expr(&mut self, ex: &ast::Expr) { check_expr(self, ex); diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs index 65412ff8eff..21e94d69366 100644 --- a/src/librustc/middle/check_static.rs +++ b/src/librustc/middle/check_static.rs @@ -31,7 +31,6 @@ use middle::infer; use middle::traits; use middle::mem_categorization as mc; use middle::expr_use_visitor as euv; -use util::common::ErrorReported; use util::nodemap::NodeSet; use syntax::ast; @@ -40,7 +39,7 @@ use syntax::visit::Visitor; use syntax::codemap::Span; use syntax::visit; -#[deriving(Eq, PartialEq)] +#[deriving(Copy, Eq, PartialEq)] enum Mode { InConstant, InStatic, @@ -48,8 +47,6 @@ enum Mode { InNothing, } -impl Copy for Mode {} - struct CheckStaticVisitor<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, mode: Mode, @@ -122,17 +119,12 @@ impl<'a, 'tcx> CheckStaticVisitor<'a, 'tcx> { let ty = ty::node_id_to_type(self.tcx, e.id); let infcx = infer::new_infer_ctxt(self.tcx); let mut fulfill_cx = traits::FulfillmentContext::new(); - match traits::trait_ref_for_builtin_bound(self.tcx, ty::BoundSync, ty) { - Ok(trait_ref) => { - fulfill_cx.register_trait_ref(self.tcx, trait_ref, - traits::ObligationCause::dummy()); - let env = ty::empty_parameter_environment(); - if !fulfill_cx.select_all_or_error(&infcx, &env, self.tcx).is_ok() { - self.tcx.sess.span_err(e.span, "shared static items must have a \ - type which implements Sync"); - } - } - Err(ErrorReported) => { } + fulfill_cx.register_builtin_bound(self.tcx, ty, ty::BoundSync, + traits::ObligationCause::dummy()); + let env = ty::empty_parameter_environment(); + if !fulfill_cx.select_all_or_error(&infcx, &env, self.tcx).is_ok() { + self.tcx.sess.span_err(e.span, "shared static items must have a \ + type which implements Sync"); } } } diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index f0d52d1ac23..9b943356547 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -62,14 +62,13 @@ use std::collections::hash_map::Vacant; // - Non-constants: everything else. // +#[deriving(Copy)] pub enum constness { integral_const, general_const, non_const } -impl Copy for constness {} - type constness_cache = DefIdMap<constness>; pub fn join(a: constness, b: constness) -> constness { diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 9373a5704b2..17ebd1b94a7 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -27,14 +27,12 @@ use syntax::visit; use syntax::print::{pp, pprust}; use util::nodemap::NodeMap; -#[deriving(Show)] +#[deriving(Copy, Show)] pub enum EntryOrExit { Entry, Exit, } -impl Copy for EntryOrExit {} - #[deriving(Clone)] pub struct DataFlowContext<'a, 'tcx: 'a, O> { tcx: &'a ty::ctxt<'tcx>, diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index 8573dc747bb..20a0dbdc1ee 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -15,7 +15,7 @@ use middle::subst::ParamSpace; use syntax::ast; use syntax::ast_util::local_def; -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum Def { DefFn(ast::DefId, bool /* is_ctor */), DefStaticMethod(/* method */ ast::DefId, MethodProvenance), @@ -56,15 +56,13 @@ pub enum Def { DefMethod(ast::DefId /* method */, Option<ast::DefId> /* trait */, MethodProvenance), } -impl Copy for Def {} - -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum MethodProvenance { FromTrait(ast::DefId), FromImpl(ast::DefId), } -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum TyParamProvenance { FromSelf(ast::DefId), FromParam(ast::DefId), @@ -81,8 +79,6 @@ impl MethodProvenance { } } -impl Copy for MethodProvenance {} - impl TyParamProvenance { pub fn def_id(&self) -> ast::DefId { match *self { @@ -92,8 +88,6 @@ impl TyParamProvenance { } } -impl Copy for TyParamProvenance {} - impl Def { pub fn def_id(&self) -> ast::DefId { match *self { diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index d16ce3ad678..0c0cba6e53e 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -23,15 +23,13 @@ use syntax::codemap::Span; use syntax::visit; use syntax::visit::Visitor; -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] enum UnsafeContext { SafeContext, UnsafeFn, UnsafeBlock(ast::NodeId), } -impl Copy for UnsafeContext {} - fn type_is_unsafe_function(ty: Ty) -> bool { match ty.sty { ty::ty_bare_fn(ref f) => f.unsafety == ast::Unsafety::Unsafe, diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 901944cd016..abc3c8d0d8f 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -95,7 +95,7 @@ pub trait Delegate<'tcx> { mode: MutateMode); } -#[deriving(PartialEq, Show)] +#[deriving(Copy, PartialEq, Show)] pub enum LoanCause { ClosureCapture(Span), AddrOf, @@ -107,26 +107,20 @@ pub enum LoanCause { MatchDiscriminant } -impl kinds::Copy for LoanCause {} - -#[deriving(PartialEq, Show)] +#[deriving(Copy, PartialEq, Show)] pub enum ConsumeMode { Copy, // reference to x where x has a type that copies Move(MoveReason), // reference to x where x has a type that moves } -impl kinds::Copy for ConsumeMode {} - -#[deriving(PartialEq,Show)] +#[deriving(Copy, PartialEq, Show)] pub enum MoveReason { DirectRefMove, PatBindingMove, CaptureMove, } -impl kinds::Copy for MoveReason {} - -#[deriving(PartialEq,Show)] +#[deriving(Copy, PartialEq, Show)] pub enum MatchMode { NonBindingMatch, BorrowingMatch, @@ -134,8 +128,6 @@ pub enum MatchMode { MovingMatch, } -impl kinds::Copy for MatchMode {} - #[deriving(PartialEq,Show)] enum TrackMatchMode<T> { Unknown, @@ -205,23 +197,20 @@ impl<T> TrackMatchMode<T> { } } -#[deriving(PartialEq,Show)] +#[deriving(Copy, PartialEq, Show)] pub enum MutateMode { Init, JustWrite, // x = y WriteAndRead, // x += y } -impl kinds::Copy for MutateMode {} - +#[deriving(Copy)] enum OverloadedCallType { FnOverloadedCall, FnMutOverloadedCall, FnOnceOverloadedCall, } -impl kinds::Copy for OverloadedCallType {} - impl OverloadedCallType { fn from_trait_id(tcx: &ty::ctxt, trait_id: ast::DefId) -> OverloadedCallType { diff --git a/src/librustc/middle/fast_reject.rs b/src/librustc/middle/fast_reject.rs index 6780177933f..297d6bcb03c 100644 --- a/src/librustc/middle/fast_reject.rs +++ b/src/librustc/middle/fast_reject.rs @@ -14,7 +14,7 @@ use syntax::ast; use self::SimplifiedType::*; /// See `simplify_type -#[deriving(Clone, PartialEq, Eq, Hash)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash)] pub enum SimplifiedType { BoolSimplifiedType, CharSimplifiedType, @@ -33,8 +33,6 @@ pub enum SimplifiedType { ParameterSimplifiedType, } -impl Copy for SimplifiedType {} - /// Tries to simplify a type by dropping type parameters, deref'ing away any reference types, etc. /// The idea is to get something simple that we can use to quickly decide if two types could unify /// during method lookup. @@ -60,7 +58,7 @@ pub fn simplify_type(tcx: &ty::ctxt, ty::ty_vec(..) => Some(VecSimplifiedType), ty::ty_ptr(_) => Some(PtrSimplifiedType), ty::ty_trait(ref trait_info) => { - Some(TraitSimplifiedType(trait_info.principal.def_id)) + Some(TraitSimplifiedType(trait_info.principal.def_id())) } ty::ty_struct(def_id, _) => { Some(StructSimplifiedType(def_id)) @@ -83,10 +81,10 @@ pub fn simplify_type(tcx: &ty::ctxt, Some(TupleSimplifiedType(tys.len())) } ty::ty_closure(ref f) => { - Some(FunctionSimplifiedType(f.sig.inputs.len())) + Some(FunctionSimplifiedType(f.sig.0.inputs.len())) } ty::ty_bare_fn(ref f) => { - Some(FunctionSimplifiedType(f.sig.inputs.len())) + Some(FunctionSimplifiedType(f.sig.0.inputs.len())) } ty::ty_param(_) => { if can_simplify_params { diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs index 4c03ed2a480..e73fcd93e05 100644 --- a/src/librustc/middle/graph.rs +++ b/src/librustc/middle/graph.rs @@ -60,30 +60,24 @@ impl<E: Show> Show for Edge<E> { } } -#[deriving(Clone, PartialEq, Show)] +#[deriving(Clone, Copy, PartialEq, Show)] pub struct NodeIndex(pub uint); #[allow(non_upper_case_globals)] pub const InvalidNodeIndex: NodeIndex = NodeIndex(uint::MAX); -impl Copy for NodeIndex {} - -#[deriving(PartialEq, Show)] +#[deriving(Copy, PartialEq, Show)] pub struct EdgeIndex(pub uint); #[allow(non_upper_case_globals)] pub const InvalidEdgeIndex: EdgeIndex = EdgeIndex(uint::MAX); -impl Copy for EdgeIndex {} - // Use a private field here to guarantee no more instances are created: -#[deriving(Show)] +#[deriving(Copy, Show)] pub struct Direction { repr: uint } #[allow(non_upper_case_globals)] pub const Outgoing: Direction = Direction { repr: 0 }; #[allow(non_upper_case_globals)] pub const Incoming: Direction = Direction { repr: 1 }; -impl Copy for Direction {} - impl NodeIndex { fn get(&self) -> uint { let NodeIndex(v) = *self; v } /// Returns unique id (unique with respect to the graph holding associated node). diff --git a/src/librustc/middle/infer/coercion.rs b/src/librustc/middle/infer/coercion.rs index e268160a42b..805d4532aa1 100644 --- a/src/librustc/middle/infer/coercion.rs +++ b/src/librustc/middle/infer/coercion.rs @@ -60,10 +60,9 @@ //! sort of a minor point so I've opted to leave it for later---after all //! we may want to adjust precisely when coercions occur. -use super::{CoerceResult, resolve_type, Coercion}; +use super::{CoerceResult, Coercion}; use super::combine::{CombineFields, Combine}; use super::sub::Sub; -use super::resolve::try_resolve_tvar_shallow; use middle::subst; use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe}; @@ -197,18 +196,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { pub fn unpack_actual_value<T, F>(&self, a: Ty<'tcx>, f: F) -> T where F: FnOnce(&ty::sty<'tcx>) -> T, { - match resolve_type(self.get_ref().infcx, None, - a, try_resolve_tvar_shallow) { - Ok(t) => { - f(&t.sty) - } - Err(e) => { - self.get_ref().infcx.tcx.sess.span_bug( - self.get_ref().trace.origin.span(), - format!("failed to resolve even without \ - any force options: {}", e).as_slice()); - } - } + f(&self.get_ref().infcx.shallow_resolve(a).sty) } // ~T -> &T or &mut T -> &T (including where T = [U] or str) @@ -286,7 +274,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let ty = ty::mk_rptr(self.get_ref().infcx.tcx, r_borrow, ty::mt{ty: ty, mutbl: mt_b.mutbl}); - try!(self.get_ref().infcx.try(|| sub.tys(ty, b))); + try!(self.get_ref().infcx.try(|_| sub.tys(ty, b))); debug!("Success, coerced with AutoDerefRef(1, \ AutoPtr(AutoUnsize({})))", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { @@ -309,7 +297,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let ty = ty::mk_ptr(self.get_ref().infcx.tcx, ty::mt{ty: ty, mutbl: mt_b.mutbl}); - try!(self.get_ref().infcx.try(|| sub.tys(ty, b))); + try!(self.get_ref().infcx.try(|_| sub.tys(ty, b))); debug!("Success, coerced with AutoDerefRef(1, \ AutoPtr(AutoUnsize({})))", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { @@ -327,7 +315,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match self.unsize_ty(t_a, sty_a, t_b) { Some((ty, kind)) => { let ty = ty::mk_uniq(self.get_ref().infcx.tcx, ty); - try!(self.get_ref().infcx.try(|| sub.tys(ty, b))); + try!(self.get_ref().infcx.try(|_| sub.tys(ty, b))); debug!("Success, coerced with AutoDerefRef(1, \ AutoUnsizeUniq({}))", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { @@ -366,7 +354,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } (_, &ty::ty_trait(box ty::TyTrait { ref principal, bounds })) => { // FIXME what is the purpose of `ty`? - let ty = ty::mk_trait(tcx, (*principal).clone(), bounds); + let ty = ty::mk_trait(tcx, principal.clone(), bounds); Some((ty, ty::UnsizeVtable(ty::TyTrait { principal: (*principal).clone(), bounds: bounds }, ty_a))) @@ -384,7 +372,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let mut result = None; let mut tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate(); for (i, (tp_a, tp_b)) in tps { - if self.get_ref().infcx.try(|| sub.tys(*tp_a, *tp_b)).is_ok() { + if self.get_ref().infcx.try(|_| sub.tys(*tp_a, *tp_b)).is_ok() { continue; } match @@ -397,7 +385,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let mut new_substs = substs_a.clone(); new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp; let ty = ty::mk_struct(tcx, did_a, new_substs); - if self.get_ref().infcx.try(|| sub.tys(ty, ty_b)).is_err() { + if self.get_ref().infcx.try(|_| sub.tys(ty, ty_b)).is_err() { debug!("Unsized type parameter '{}', but still \ could not match types {} and {}", ppaux::ty_to_string(tcx, *tp_a), @@ -476,7 +464,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => { debug!("mutbl={} b_mutbl={}", mutbl, b_mutbl); // FIXME what is purpose of this type `tr`? - let tr = ty::mk_trait(tcx, (*principal).clone(), bounds); + let tr = ty::mk_trait(tcx, principal.clone(), bounds); try!(self.subtype(mk_ty(tr), b)); Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: 1, diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 26bba55594b..82ddbcee5a7 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -195,7 +195,7 @@ pub trait Combine<'tcx> { b: &ty::BareFnTy<'tcx>) -> cres<'tcx, ty::BareFnTy<'tcx>> { let unsafety = try!(self.unsafeties(a.unsafety, b.unsafety)); let abi = try!(self.abi(a.abi, b.abi)); - let sig = try!(self.fn_sigs(&a.sig, &b.sig)); + let sig = try!(self.binders(&a.sig, &b.sig)); Ok(ty::BareFnTy {unsafety: unsafety, abi: abi, sig: sig}) @@ -222,7 +222,7 @@ pub trait Combine<'tcx> { let unsafety = try!(self.unsafeties(a.unsafety, b.unsafety)); let onceness = try!(self.oncenesses(a.onceness, b.onceness)); let bounds = try!(self.existential_bounds(a.bounds, b.bounds)); - let sig = try!(self.fn_sigs(&a.sig, &b.sig)); + let sig = try!(self.binders(&a.sig, &b.sig)); let abi = try!(self.abi(a.abi, b.abi)); Ok(ty::ClosureTy { unsafety: unsafety, @@ -234,7 +234,43 @@ pub trait Combine<'tcx> { }) } - fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) -> cres<'tcx, ty::FnSig<'tcx>>; + fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) -> cres<'tcx, ty::FnSig<'tcx>> { + if a.variadic != b.variadic { + return Err(ty::terr_variadic_mismatch(expected_found(self, a.variadic, b.variadic))); + } + + let inputs = try!(argvecs(self, + a.inputs.as_slice(), + b.inputs.as_slice())); + + let output = try!(match (a.output, b.output) { + (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) => + Ok(ty::FnConverging(try!(self.tys(a_ty, b_ty)))), + (ty::FnDiverging, ty::FnDiverging) => + Ok(ty::FnDiverging), + (a, b) => + Err(ty::terr_convergence_mismatch( + expected_found(self, a != ty::FnDiverging, b != ty::FnDiverging))), + }); + + return Ok(ty::FnSig {inputs: inputs, + output: output, + variadic: a.variadic}); + + + fn argvecs<'tcx, C: Combine<'tcx>>(combiner: &C, + a_args: &[Ty<'tcx>], + b_args: &[Ty<'tcx>]) + -> cres<'tcx, Vec<Ty<'tcx>>> + { + if a_args.len() == b_args.len() { + a_args.iter().zip(b_args.iter()) + .map(|(a, b)| combiner.args(*a, *b)).collect() + } else { + Err(ty::terr_arg_count) + } + } + } fn args(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { self.contratys(a, b).and_then(|t| Ok(t)) @@ -301,11 +337,47 @@ pub trait Combine<'tcx> { fn trait_refs(&self, a: &ty::TraitRef<'tcx>, b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>>; + -> cres<'tcx, ty::TraitRef<'tcx>> + { + // Different traits cannot be related + if a.def_id != b.def_id { + Err(ty::terr_traits(expected_found(self, a.def_id, b.def_id))) + } else { + let substs = try!(self.substs(a.def_id, &a.substs, &b.substs)); + Ok(ty::TraitRef { def_id: a.def_id, substs: substs }) + } + } + + fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>> + where T : Combineable<'tcx>; // this must be overridden to do correctly, so as to account for higher-ranked // behavior } +pub trait Combineable<'tcx> : Repr<'tcx> + TypeFoldable<'tcx> { + fn combine<C:Combine<'tcx>>(combiner: &C, a: &Self, b: &Self) -> cres<'tcx, Self>; +} + +impl<'tcx> Combineable<'tcx> for ty::TraitRef<'tcx> { + fn combine<C:Combine<'tcx>>(combiner: &C, + a: &ty::TraitRef<'tcx>, + b: &ty::TraitRef<'tcx>) + -> cres<'tcx, ty::TraitRef<'tcx>> + { + combiner.trait_refs(a, b) + } +} + +impl<'tcx> Combineable<'tcx> for ty::FnSig<'tcx> { + fn combine<C:Combine<'tcx>>(combiner: &C, + a: &ty::FnSig<'tcx>, + b: &ty::FnSig<'tcx>) + -> cres<'tcx, ty::FnSig<'tcx>> + { + combiner.fn_sigs(a, b) + } +} + #[deriving(Clone)] pub struct CombineFields<'a, 'tcx: 'a> { pub infcx: &'a InferCtxt<'a, 'tcx>, @@ -410,7 +482,7 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, (&ty::ty_trait(ref a_), &ty::ty_trait(ref b_)) => { debug!("Trying to match traits {} and {}", a, b); - let principal = try!(this.trait_refs(&a_.principal, &b_.principal)); + let principal = try!(this.binders(&a_.principal, &b_.principal)); let bounds = try!(this.existential_bounds(a_.bounds, b_.bounds)); Ok(ty::mk_trait(tcx, principal, bounds)) } @@ -706,14 +778,38 @@ impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> { fn fold_region(&mut self, r: ty::Region) -> ty::Region { match r { - ty::ReLateBound(..) | ty::ReEarlyBound(..) => r, - _ if self.make_region_vars => { - // FIXME: This is non-ideal because we don't give a - // very descriptive origin for this region variable. - self.infcx.next_region_var(MiscVariable(self.span)) + // Never make variables for regions bound within the type itself. + ty::ReLateBound(..) => { return r; } + + // Early-bound regions should really have been substituted away before + // we get to this point. + ty::ReEarlyBound(..) => { + self.tcx().sess.span_bug( + self.span, + format!("Encountered early bound region when generalizing: {}", + r.repr(self.tcx()))[]); + } + + // Always make a fresh region variable for skolemized regions; + // the higher-ranked decision procedures rely on this. + ty::ReInfer(ty::ReSkolemized(..)) => { } + + // For anything else, we make a region variable, unless we + // are *equating*, in which case it's just wasteful. + ty::ReEmpty | + ty::ReStatic | + ty::ReScope(..) | + ty::ReInfer(ty::ReVar(..)) | + ty::ReFree(..) => { + if !self.make_region_vars { + return r; + } } - _ => r, } + + // FIXME: This is non-ideal because we don't give a + // very descriptive origin for this region variable. + self.infcx.next_region_var(MiscVariable(self.span)) } } diff --git a/src/librustc/middle/infer/equate.rs b/src/librustc/middle/infer/equate.rs index 1738b8db99b..2a4d20f4dd3 100644 --- a/src/librustc/middle/infer/equate.rs +++ b/src/librustc/middle/infer/equate.rs @@ -133,15 +133,10 @@ impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> { } } - fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) - -> cres<'tcx, ty::FnSig<'tcx>> { - try!(self.sub().fn_sigs(a, b)); - self.sub().fn_sigs(b, a) - } - - fn trait_refs(&self, a: &ty::TraitRef<'tcx>, b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>> { - try!(self.sub().trait_refs(a, b)); - self.sub().trait_refs(b, a) + fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>> + where T : Combineable<'tcx> + { + try!(self.sub().binders(a, b)); + self.sub().binders(b, a) } } diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index ab685dd5dbc..b4c1c0b396b 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -395,7 +395,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<String> { match *values { infer::Types(ref exp_found) => self.expected_found_str(exp_found), - infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found) + infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), + infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found) } } @@ -1640,7 +1641,7 @@ pub trait Resolvable<'tcx> { impl<'tcx> Resolvable<'tcx> for Ty<'tcx> { fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Ty<'tcx> { - infcx.resolve_type_vars_if_possible(*self) + infcx.resolve_type_vars_if_possible(self) } fn contains_error(&self) -> bool { ty::type_is_error(*self) @@ -1650,13 +1651,23 @@ impl<'tcx> Resolvable<'tcx> for Ty<'tcx> { impl<'tcx> Resolvable<'tcx> for Rc<ty::TraitRef<'tcx>> { fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Rc<ty::TraitRef<'tcx>> { - Rc::new(infcx.resolve_type_vars_in_trait_ref_if_possible(&**self)) + Rc::new(infcx.resolve_type_vars_if_possible(&**self)) } fn contains_error(&self) -> bool { ty::trait_ref_contains_error(&**self) } } +impl<'tcx> Resolvable<'tcx> for Rc<ty::PolyTraitRef<'tcx>> { + fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) + -> Rc<ty::PolyTraitRef<'tcx>> { + Rc::new(infcx.resolve_type_vars_if_possible(&**self)) + } + fn contains_error(&self) -> bool { + ty::trait_ref_contains_error(&self.0) + } +} + fn lifetimes_in_scope(tcx: &ty::ctxt, scope_id: ast::NodeId) -> Vec<ast::LifetimeDef> { diff --git a/src/librustc/middle/infer/skolemize.rs b/src/librustc/middle/infer/freshen.rs index 8336131c54a..ebff854060c 100644 --- a/src/librustc/middle/infer/skolemize.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -8,21 +8,21 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Skolemization is the process of replacing unknown variables with fresh types. The idea is that -//! the type, after skolemization, contains no inference variables but instead contains either a +//! Freshening is the process of replacing unknown variables with fresh types. The idea is that +//! the type, after freshening, contains no inference variables but instead contains either a //! value for each variable or fresh "arbitrary" types wherever a variable would have been. //! -//! Skolemization is used primarily to get a good type for inserting into a cache. The result +//! Freshening is used primarily to get a good type for inserting into a cache. The result //! summarizes what the type inferencer knows "so far". The primary place it is used right now is //! in the trait matching algorithm, which needs to be able to cache whether an `impl` self type //! matches some other type X -- *without* affecting `X`. That means if that if the type `X` is in //! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending //! on what type that type variable is ultimately assigned, the match may or may not succeed. //! -//! Note that you should be careful not to allow the output of skolemization to leak to the user in -//! error messages or in any other form. Skolemization is only really useful as an internal detail. +//! Note that you should be careful not to allow the output of freshening to leak to the user in +//! error messages or in any other form. Freshening is only really useful as an internal detail. //! -//! __An important detail concerning regions.__ The skolemizer also replaces *all* regions with +//! __An important detail concerning regions.__ The freshener also replaces *all* regions with //! 'static. The reason behind this is that, in general, we do not take region relationships into //! account when making type-overloaded decisions. This is important because of the design of the //! region inferencer, which is not based on unification but rather on accumulating and then @@ -39,26 +39,26 @@ use std::collections::hash_map; use super::InferCtxt; use super::unify::InferCtxtMethodsForSimplyUnifiableTypes; -pub struct TypeSkolemizer<'a, 'tcx:'a> { +pub struct TypeFreshener<'a, 'tcx:'a> { infcx: &'a InferCtxt<'a, 'tcx>, - skolemization_count: uint, - skolemization_map: hash_map::HashMap<ty::InferTy, Ty<'tcx>>, + freshen_count: uint, + freshen_map: hash_map::HashMap<ty::InferTy, Ty<'tcx>>, } -impl<'a, 'tcx> TypeSkolemizer<'a, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeSkolemizer<'a, 'tcx> { - TypeSkolemizer { +impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { + pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeFreshener<'a, 'tcx> { + TypeFreshener { infcx: infcx, - skolemization_count: 0, - skolemization_map: hash_map::HashMap::new(), + freshen_count: 0, + freshen_map: hash_map::HashMap::new(), } } - fn skolemize<F>(&mut self, - opt_ty: Option<Ty<'tcx>>, - key: ty::InferTy, - skolemizer: F) - -> Ty<'tcx> where + fn freshen<F>(&mut self, + opt_ty: Option<Ty<'tcx>>, + key: ty::InferTy, + freshener: F) + -> Ty<'tcx> where F: FnOnce(uint) -> ty::InferTy, { match opt_ty { @@ -66,12 +66,12 @@ impl<'a, 'tcx> TypeSkolemizer<'a, 'tcx> { None => { } } - match self.skolemization_map.entry(key) { + match self.freshen_map.entry(key) { hash_map::Occupied(entry) => *entry.get(), hash_map::Vacant(entry) => { - let index = self.skolemization_count; - self.skolemization_count += 1; - let t = ty::mk_infer(self.infcx.tcx, skolemizer(index)); + let index = self.freshen_count; + self.freshen_count += 1; + let t = ty::mk_infer(self.infcx.tcx, freshener(index)); entry.set(t); t } @@ -79,7 +79,7 @@ impl<'a, 'tcx> TypeSkolemizer<'a, 'tcx> { } } -impl<'a, 'tcx> TypeFolder<'tcx> for TypeSkolemizer<'a, 'tcx> { +impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { fn tcx<'b>(&'b self) -> &'b ty::ctxt<'tcx> { self.infcx.tcx } @@ -106,37 +106,37 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeSkolemizer<'a, 'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match t.sty { ty::ty_infer(ty::TyVar(v)) => { - self.skolemize(self.infcx.type_variables.borrow().probe(v), + self.freshen(self.infcx.type_variables.borrow().probe(v), ty::TyVar(v), - ty::SkolemizedTy) + ty::FreshTy) } ty::ty_infer(ty::IntVar(v)) => { - self.skolemize(self.infcx.probe_var(v), - ty::IntVar(v), - ty::SkolemizedIntTy) + self.freshen(self.infcx.probe_var(v), + ty::IntVar(v), + ty::FreshIntTy) } ty::ty_infer(ty::FloatVar(v)) => { - self.skolemize(self.infcx.probe_var(v), - ty::FloatVar(v), - ty::SkolemizedIntTy) + self.freshen(self.infcx.probe_var(v), + ty::FloatVar(v), + ty::FreshIntTy) } - ty::ty_infer(ty::SkolemizedTy(c)) | - ty::ty_infer(ty::SkolemizedIntTy(c)) => { - if c >= self.skolemization_count { + ty::ty_infer(ty::FreshTy(c)) | + ty::ty_infer(ty::FreshIntTy(c)) => { + if c >= self.freshen_count { self.tcx().sess.bug( - format!("Encountered a skolemized type with id {} \ + format!("Encountered a freshend type with id {} \ but our counter is only at {}", c, - self.skolemization_count).as_slice()); + self.freshen_count).as_slice()); } t } ty::ty_open(..) => { - self.tcx().sess.bug("Cannot skolemize an open existential type"); + self.tcx().sess.bug("Cannot freshen an open existential type"); } ty::ty_bool | diff --git a/src/librustc/middle/infer/glb.rs b/src/librustc/middle/infer/glb.rs index 9fc4e095c43..434be32fe5f 100644 --- a/src/librustc/middle/infer/glb.rs +++ b/src/librustc/middle/infer/glb.rs @@ -121,13 +121,9 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> { super_lattice_tys(self, a, b) } - fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) - -> cres<'tcx, ty::FnSig<'tcx>> { - self.higher_ranked_glb(a, b) - } - - fn trait_refs(&self, a: &ty::TraitRef<'tcx>, b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>> { + fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>> + where T : Combineable<'tcx> + { self.higher_ranked_glb(a, b) } } diff --git a/src/librustc/middle/infer/higher_ranked/doc.rs b/src/librustc/middle/infer/higher_ranked/doc.rs index 2bad3616a05..f6f254c0e8d 100644 --- a/src/librustc/middle/infer/higher_ranked/doc.rs +++ b/src/librustc/middle/infer/higher_ranked/doc.rs @@ -249,19 +249,21 @@ //! in T and try to, in some cases, replace them with bound regions to //! yield the final result. //! -//! To decide whether to replace a region `R` that appears in `T` with a -//! bound region, the algorithms make use of two bits of information. -//! First is a set `V` that contains all region variables created as part -//! of the LUB/GLB computation. `V` will contain the region variables -//! created to replace the bound regions in the input types, but it also -//! contains 'intermediate' variables created to represent the LUB/GLB of -//! individual regions. Basically, when asked to compute the LUB/GLB of a -//! region variable with another region, the inferencer cannot oblige -//! immediately since the values of that variables are not known. -//! Therefore, it creates a new variable that is related to the two -//! regions. For example, the LUB of two variables `$x` and `$y` is a -//! fresh variable `$z` that is constrained such that `$x <= $z` and `$y -//! <= $z`. So `V` will contain these intermediate variables as well. +//! To decide whether to replace a region `R` that appears in `T` with +//! a bound region, the algorithms make use of two bits of +//! information. First is a set `V` that contains all region +//! variables created as part of the LUB/GLB computation (roughly; see +//! `region_vars_confined_to_snapshot()` for full details). `V` will +//! contain the region variables created to replace the bound regions +//! in the input types, but it also contains 'intermediate' variables +//! created to represent the LUB/GLB of individual regions. +//! Basically, when asked to compute the LUB/GLB of a region variable +//! with another region, the inferencer cannot oblige immediately +//! since the values of that variables are not known. Therefore, it +//! creates a new variable that is related to the two regions. For +//! example, the LUB of two variables `$x` and `$y` is a fresh +//! variable `$z` that is constrained such that `$x <= $z` and `$y <= +//! $z`. So `V` will contain these intermediate variables as well. //! //! The other important factor in deciding how to replace a region in T is //! the function `Tainted($r)` which, for a region variable, identifies diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index be053afcca4..ab0f98ec74a 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -11,37 +11,40 @@ //! Helper routines for higher-ranked things. See the `doc` module at //! the end of the file for details. -use super::{combine, cres, InferCtxt, HigherRankedType}; -use super::combine::Combine; -use super::region_inference::{RegionMark}; +use super::{CombinedSnapshot, cres, InferCtxt, HigherRankedType, SkolemizationMap}; +use super::combine::{Combine, Combineable}; -use middle::ty::{mod, Ty, replace_late_bound_regions}; -use middle::ty_fold::{mod, HigherRankedFoldable, TypeFoldable}; +use middle::ty::{mod, Binder}; +use middle::ty_fold::{mod, TypeFoldable}; use syntax::codemap::Span; -use util::nodemap::FnvHashMap; -use util::ppaux::{bound_region_to_string, Repr}; - -pub trait HigherRankedCombineable<'tcx>: HigherRankedFoldable<'tcx> + - TypeFoldable<'tcx> + Repr<'tcx> { - fn super_combine<C:Combine<'tcx>>(combiner: &C, a: &Self, b: &Self) -> cres<'tcx, Self>; -} +use util::nodemap::{FnvHashMap, FnvHashSet}; +use util::ppaux::Repr; pub trait HigherRankedRelations<'tcx> { - fn higher_ranked_sub<T>(&self, a: &T, b: &T) -> cres<'tcx, T> - where T : HigherRankedCombineable<'tcx>; + fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>> + where T : Combineable<'tcx>; + + fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>> + where T : Combineable<'tcx>; + + fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>> + where T : Combineable<'tcx>; +} - fn higher_ranked_lub<T>(&self, a: &T, b: &T) -> cres<'tcx, T> - where T : HigherRankedCombineable<'tcx>; +trait InferCtxtExt<'tcx> { + fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec<ty::Region>; - fn higher_ranked_glb<T>(&self, a: &T, b: &T) -> cres<'tcx, T> - where T : HigherRankedCombineable<'tcx>; + fn region_vars_confined_to_snapshot(&self, + snapshot: &CombinedSnapshot) + -> Vec<ty::RegionVid>; } impl<'tcx,C> HigherRankedRelations<'tcx> for C where C : Combine<'tcx> { - fn higher_ranked_sub<T>(&self, a: &T, b: &T) -> cres<'tcx, T> - where T : HigherRankedCombineable<'tcx> + fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>) + -> cres<'tcx, Binder<T>> + where T : Combineable<'tcx> { debug!("higher_ranked_sub(a={}, b={})", a.repr(self.tcx()), b.repr(self.tcx())); @@ -54,114 +57,95 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C // please see the large comment at the end of the file in the (inlined) module // `doc`. - // Make a mark so we can examine "all bindings that were + // Start a snapshot so we can examine "all bindings that were // created as part of this type comparison". - let mark = self.infcx().region_vars.mark(); - - // First, we instantiate each bound region in the subtype with a fresh - // region variable. - let (a_prime, _) = - self.infcx().replace_late_bound_regions_with_fresh_var( - self.trace().origin.span(), - HigherRankedType, - a); - - // Second, we instantiate each bound region in the supertype with a - // fresh concrete region. - let (b_prime, skol_map) = { - replace_late_bound_regions(self.tcx(), b, |br, _| { - let skol = self.infcx().region_vars.new_skolemized(br); - debug!("Bound region {} skolemized to {}", - bound_region_to_string(self.tcx(), "", false, br), - skol); - skol - }) - }; - - debug!("a_prime={}", a_prime.repr(self.tcx())); - debug!("b_prime={}", b_prime.repr(self.tcx())); - - // Compare types now that bound regions have been replaced. - let result = try!(HigherRankedCombineable::super_combine(self, &a_prime, &b_prime)); - - // Presuming type comparison succeeds, we need to check - // that the skolemized regions do not "leak". - let new_vars = - self.infcx().region_vars.vars_created_since_mark(mark); - for (&skol_br, &skol) in skol_map.iter() { - let tainted = self.infcx().region_vars.tainted(mark, skol); - for tainted_region in tainted.iter() { - // Each skolemized should only be relatable to itself - // or new variables: - match *tainted_region { - ty::ReInfer(ty::ReVar(ref vid)) => { - if new_vars.iter().any(|x| x == vid) { continue; } - } - _ => { - if *tainted_region == skol { continue; } + return self.infcx().try(|snapshot| { + // First, we instantiate each bound region in the subtype with a fresh + // region variable. + let (a_prime, _) = + self.infcx().replace_late_bound_regions_with_fresh_var( + self.trace().origin.span(), + HigherRankedType, + a); + + // Second, we instantiate each bound region in the supertype with a + // fresh concrete region. + let (b_prime, skol_map) = + self.infcx().skolemize_late_bound_regions(b, snapshot); + + debug!("a_prime={}", a_prime.repr(self.tcx())); + debug!("b_prime={}", b_prime.repr(self.tcx())); + + // Compare types now that bound regions have been replaced. + let result = try!(Combineable::combine(self, &a_prime, &b_prime)); + + // Presuming type comparison succeeds, we need to check + // that the skolemized regions do not "leak". + match leak_check(self.infcx(), &skol_map, snapshot) { + Ok(()) => { } + Err((skol_br, tainted_region)) => { + if self.a_is_expected() { + debug!("Not as polymorphic!"); + return Err(ty::terr_regions_insufficiently_polymorphic(skol_br, + tainted_region)); + } else { + debug!("Overly polymorphic!"); + return Err(ty::terr_regions_overly_polymorphic(skol_br, + tainted_region)); } - }; - - // A is not as polymorphic as B: - if self.a_is_expected() { - debug!("Not as polymorphic!"); - return Err(ty::terr_regions_insufficiently_polymorphic( - skol_br, *tainted_region)); - } else { - debug!("Overly polymorphic!"); - return Err(ty::terr_regions_overly_polymorphic( - skol_br, *tainted_region)); } } - } - debug!("higher_ranked_sub: OK result={}", - result.repr(self.tcx())); + debug!("higher_ranked_sub: OK result={}", + result.repr(self.tcx())); - return Ok(result); + Ok(ty::Binder(result)) + }); } - fn higher_ranked_lub<T>(&self, a: &T, b: &T) -> cres<'tcx, T> - where T : HigherRankedCombineable<'tcx> + fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>> + where T : Combineable<'tcx> { - // Make a mark so we can examine "all bindings that were + // Start a snapshot so we can examine "all bindings that were // created as part of this type comparison". - let mark = self.infcx().region_vars.mark(); - - // Instantiate each bound region with a fresh region variable. - let span = self.trace().origin.span(); - let (a_with_fresh, a_map) = - self.infcx().replace_late_bound_regions_with_fresh_var( - span, HigherRankedType, a); - let (b_with_fresh, _) = - self.infcx().replace_late_bound_regions_with_fresh_var( - span, HigherRankedType, b); - - // Collect constraints. - let result0 = - try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh)); - debug!("lub result0 = {}", result0.repr(self.tcx())); - - // Generalize the regions appearing in result0 if possible - let new_vars = self.infcx().region_vars.vars_created_since_mark(mark); - let span = self.trace().origin.span(); - let result1 = - fold_regions_in( - self.tcx(), - &result0, - |r, debruijn| generalize_region(self.infcx(), span, mark, debruijn, - new_vars.as_slice(), &a_map, r)); - - debug!("lub({},{}) = {}", - a.repr(self.tcx()), - b.repr(self.tcx()), - result1.repr(self.tcx())); - - return Ok(result1); + return self.infcx().try(|snapshot| { + // Instantiate each bound region with a fresh region variable. + let span = self.trace().origin.span(); + let (a_with_fresh, a_map) = + self.infcx().replace_late_bound_regions_with_fresh_var( + span, HigherRankedType, a); + let (b_with_fresh, _) = + self.infcx().replace_late_bound_regions_with_fresh_var( + span, HigherRankedType, b); + + // Collect constraints. + let result0 = + try!(Combineable::combine(self, &a_with_fresh, &b_with_fresh)); + let result0 = + self.infcx().resolve_type_vars_if_possible(&result0); + debug!("lub result0 = {}", result0.repr(self.tcx())); + + // Generalize the regions appearing in result0 if possible + let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot); + let span = self.trace().origin.span(); + let result1 = + fold_regions_in( + self.tcx(), + &result0, + |r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn, + new_vars.as_slice(), &a_map, r)); + + debug!("lub({},{}) = {}", + a.repr(self.tcx()), + b.repr(self.tcx()), + result1.repr(self.tcx())); + + Ok(ty::Binder(result1)) + }); fn generalize_region(infcx: &InferCtxt, span: Span, - mark: RegionMark, + snapshot: &CombinedSnapshot, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], a_map: &FnvHashMap<ty::BoundRegion, ty::Region>, @@ -174,7 +158,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C return r0; } - let tainted = infcx.region_vars.tainted(mark, r0); + let tainted = infcx.tainted_regions(snapshot, r0); // Variables created during LUB computation which are // *related* to regions that pre-date the LUB computation @@ -209,53 +193,55 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C } } - fn higher_ranked_glb<T>(&self, a: &T, b: &T) -> cres<'tcx, T> - where T : HigherRankedCombineable<'tcx> + fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>> + where T : Combineable<'tcx> { debug!("{}.higher_ranked_glb({}, {})", self.tag(), a.repr(self.tcx()), b.repr(self.tcx())); - // Make a mark so we can examine "all bindings that were + // Make a snapshot so we can examine "all bindings that were // created as part of this type comparison". - let mark = self.infcx().region_vars.mark(); - - // Instantiate each bound region with a fresh region variable. - let (a_with_fresh, a_map) = - self.infcx().replace_late_bound_regions_with_fresh_var( - self.trace().origin.span(), HigherRankedType, a); - let (b_with_fresh, b_map) = - self.infcx().replace_late_bound_regions_with_fresh_var( - self.trace().origin.span(), HigherRankedType, b); - let a_vars = var_ids(self, &a_map); - let b_vars = var_ids(self, &b_map); - - // Collect constraints. - let result0 = - try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh)); - debug!("glb result0 = {}", result0.repr(self.tcx())); - - // Generalize the regions appearing in fn_ty0 if possible - let new_vars = self.infcx().region_vars.vars_created_since_mark(mark); - let span = self.trace().origin.span(); - let result1 = - fold_regions_in( - self.tcx(), - &result0, - |r, debruijn| generalize_region(self.infcx(), span, mark, debruijn, - new_vars.as_slice(), - &a_map, a_vars.as_slice(), b_vars.as_slice(), - r)); - - debug!("glb({},{}) = {}", - a.repr(self.tcx()), - b.repr(self.tcx()), - result1.repr(self.tcx())); - - return Ok(result1); + return self.infcx().try(|snapshot| { + // Instantiate each bound region with a fresh region variable. + let (a_with_fresh, a_map) = + self.infcx().replace_late_bound_regions_with_fresh_var( + self.trace().origin.span(), HigherRankedType, a); + let (b_with_fresh, b_map) = + self.infcx().replace_late_bound_regions_with_fresh_var( + self.trace().origin.span(), HigherRankedType, b); + let a_vars = var_ids(self, &a_map); + let b_vars = var_ids(self, &b_map); + + // Collect constraints. + let result0 = + try!(Combineable::combine(self, &a_with_fresh, &b_with_fresh)); + let result0 = + self.infcx().resolve_type_vars_if_possible(&result0); + debug!("glb result0 = {}", result0.repr(self.tcx())); + + // Generalize the regions appearing in result0 if possible + let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot); + let span = self.trace().origin.span(); + let result1 = + fold_regions_in( + self.tcx(), + &result0, + |r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn, + new_vars.as_slice(), + &a_map, a_vars.as_slice(), b_vars.as_slice(), + r)); + + debug!("glb({},{}) = {}", + a.repr(self.tcx()), + b.repr(self.tcx()), + result1.repr(self.tcx())); + + Ok(ty::Binder(result1)) + }); fn generalize_region(infcx: &InferCtxt, span: Span, - mark: RegionMark, + snapshot: &CombinedSnapshot, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], a_map: &FnvHashMap<ty::BoundRegion, ty::Region>, @@ -267,7 +253,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C return r0; } - let tainted = infcx.region_vars.tainted(mark, r0); + let tainted = infcx.tainted_regions(snapshot, r0); let mut a_r = None; let mut b_r = None; @@ -345,67 +331,6 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C } } -impl<'tcx> HigherRankedCombineable<'tcx> for ty::FnSig<'tcx> { - fn super_combine<C:Combine<'tcx>>(combiner: &C, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) - -> cres<'tcx, ty::FnSig<'tcx>> - { - if a.variadic != b.variadic { - return Err(ty::terr_variadic_mismatch( - combine::expected_found(combiner, a.variadic, b.variadic))); - } - - let inputs = try!(argvecs(combiner, - a.inputs.as_slice(), - b.inputs.as_slice())); - - let output = try!(match (a.output, b.output) { - (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) => - Ok(ty::FnConverging(try!(combiner.tys(a_ty, b_ty)))), - (ty::FnDiverging, ty::FnDiverging) => - Ok(ty::FnDiverging), - (a, b) => - Err(ty::terr_convergence_mismatch( - combine::expected_found(combiner, a != ty::FnDiverging, b != ty::FnDiverging))), - }); - - return Ok(ty::FnSig {inputs: inputs, - output: output, - variadic: a.variadic}); - - - fn argvecs<'tcx, C: Combine<'tcx>>(combiner: &C, - a_args: &[Ty<'tcx>], - b_args: &[Ty<'tcx>]) - -> cres<'tcx, Vec<Ty<'tcx>>> - { - if a_args.len() == b_args.len() { - a_args.iter().zip(b_args.iter()) - .map(|(a, b)| combiner.args(*a, *b)).collect() - } else { - Err(ty::terr_arg_count) - } - } - } -} - -impl<'tcx> HigherRankedCombineable<'tcx> for ty::TraitRef<'tcx> { - fn super_combine<C:Combine<'tcx>>(combiner: &C, - a: &ty::TraitRef<'tcx>, - b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>> - { - // Different traits cannot be related - if a.def_id != b.def_id { - Err(ty::terr_traits( - combine::expected_found(combiner, a.def_id, b.def_id))) - } else { - let substs = try!(combiner.substs(a.def_id, &a.substs, &b.substs)); - Ok(ty::TraitRef { def_id: a.def_id, - substs: substs }) - } - } -} - fn var_ids<'tcx, T: Combine<'tcx>>(combiner: &T, map: &FnvHashMap<ty::BoundRegion, ty::Region>) -> Vec<ty::RegionVid> { @@ -426,11 +351,14 @@ fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool { } } -fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, value: &T, mut fldr: F) -> T where - T: HigherRankedFoldable<'tcx>, - F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region, +fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, + unbound_value: &T, + mut fldr: F) + -> T + where T : Combineable<'tcx>, + F : FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region, { - value.fold_contents(&mut ty_fold::RegionFolder::new(tcx, |region, current_depth| { + unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, &mut |region, current_depth| { // we should only be encountering "escaping" late-bound regions here, // because the ones at the current level should have been replaced // with fresh variables @@ -443,3 +371,244 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, value: &T, mut fldr: F) -> })) } +impl<'a,'tcx> InferCtxtExt<'tcx> for InferCtxt<'a,'tcx> { + fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec<ty::Region> { + self.region_vars.tainted(&snapshot.region_vars_snapshot, r) + } + + fn region_vars_confined_to_snapshot(&self, + snapshot: &CombinedSnapshot) + -> Vec<ty::RegionVid> + { + /*! + * Returns the set of region variables that do not affect any + * types/regions which existed before `snapshot` was + * started. This is used in the sub/lub/glb computations. The + * idea here is that when we are computing lub/glb of two + * regions, we sometimes create intermediate region variables. + * Those region variables may touch some of the skolemized or + * other "forbidden" regions we created to replace bound + * regions, but they don't really represent an "external" + * constraint. + * + * However, sometimes fresh variables are created for other + * purposes too, and those *may* represent an external + * constraint. In particular, when a type variable is + * instantiated, we create region variables for all the + * regions that appear within, and if that type variable + * pre-existed the snapshot, then those region variables + * represent external constraints. + * + * An example appears in the unit test + * `sub_free_bound_false_infer`. In this test, we want to + * know whether + * + * ```rust + * fn(_#0t) <: for<'a> fn(&'a int) + * ``` + * + * Note that the subtype has a type variable. Because the type + * variable can't be instantiated with a region that is bound + * in the fn signature, this comparison ought to fail. But if + * we're not careful, it will succeed. + * + * The reason is that when we walk through the subtyping + * algorith, we begin by replacing `'a` with a skolemized + * variable `'1`. We then have `fn(_#0t) <: fn(&'1 int)`. This + * can be made true by unifying `_#0t` with `&'1 int`. In the + * process, we create a fresh variable for the skolemized + * region, `'$2`, and hence we have that `_#0t == &'$2 + * int`. However, because `'$2` was created during the sub + * computation, if we're not careful we will erroneously + * assume it is one of the transient region variables + * representing a lub/glb internally. Not good. + * + * To prevent this, we check for type variables which were + * unified during the snapshot, and say that any region + * variable created during the snapshot but which finds its + * way into a type variable is considered to "escape" the + * snapshot. + */ + + let mut region_vars = + self.region_vars.vars_created_since_snapshot(&snapshot.region_vars_snapshot); + + let escaping_types = + self.type_variables.borrow().types_escaping_snapshot(&snapshot.type_snapshot); + + let escaping_region_vars: FnvHashSet<_> = + escaping_types + .iter() + .flat_map(|&t| ty_fold::collect_regions(self.tcx, &t).into_iter()) + .collect(); + + region_vars.retain(|®ion_vid| { + let r = ty::ReInfer(ty::ReVar(region_vid)); + !escaping_region_vars.contains(&r) + }); + + debug!("region_vars_confined_to_snapshot: region_vars={} escaping_types={}", + region_vars.repr(self.tcx), + escaping_types.repr(self.tcx)); + + region_vars + } +} + +pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, + binder: &ty::Binder<T>, + snapshot: &CombinedSnapshot) + -> (T, SkolemizationMap) + where T : TypeFoldable<'tcx> + Repr<'tcx> +{ + /*! + * Replace all regions bound by `binder` with skolemized regions and + * return a map indicating which bound-region was replaced with what + * skolemized region. This is the first step of checking subtyping + * when higher-ranked things are involved. See `doc.rs` for more details. + */ + + let (result, map) = ty::replace_late_bound_regions(infcx.tcx, binder, |br, _| { + infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot) + }); + + debug!("skolemize_bound_regions(binder={}, result={}, map={})", + binder.repr(infcx.tcx), + result.repr(infcx.tcx), + map.repr(infcx.tcx)); + + (result, map) +} + +pub fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + skol_map: &SkolemizationMap, + snapshot: &CombinedSnapshot) + -> Result<(),(ty::BoundRegion,ty::Region)> +{ + /*! + * Searches the region constriants created since `snapshot` was started + * and checks to determine whether any of the skolemized regions created + * in `skol_map` would "escape" -- meaning that they are related to + * other regions in some way. If so, the higher-ranked subtyping doesn't + * hold. See `doc.rs` for more details. + */ + + debug!("leak_check: skol_map={}", + skol_map.repr(infcx.tcx)); + + let new_vars = infcx.region_vars_confined_to_snapshot(snapshot); + for (&skol_br, &skol) in skol_map.iter() { + let tainted = infcx.tainted_regions(snapshot, skol); + for &tainted_region in tainted.iter() { + // Each skolemized should only be relatable to itself + // or new variables: + match tainted_region { + ty::ReInfer(ty::ReVar(vid)) => { + if new_vars.iter().any(|&x| x == vid) { continue; } + } + _ => { + if tainted_region == skol { continue; } + } + }; + + debug!("{} (which replaced {}) is tainted by {}", + skol.repr(infcx.tcx), + skol_br.repr(infcx.tcx), + tainted_region.repr(infcx.tcx)); + + // A is not as polymorphic as B: + return Err((skol_br, tainted_region)); + } + } + Ok(()) +} + +/// This code converts from skolemized regions back to late-bound +/// regions. It works by replacing each region in the taint set of a +/// skolemized region with a bound-region. The bound region will be bound +/// by the outer-most binder in `value`; the caller must ensure that there is +/// such a binder and it is the right place. +/// +/// This routine is only intended to be used when the leak-check has +/// passed; currently, it's used in the trait matching code to create +/// a set of nested obligations frmo an impl that matches against +/// something higher-ranked. More details can be found in +/// `middle::traits::doc.rs`. +/// +/// As a brief example, consider the obligation `for<'a> Fn(&'a int) +/// -> &'a int`, and the impl: +/// +/// impl<A,R> Fn<A,R> for SomethingOrOther +/// where A : Clone +/// { ... } +/// +/// Here we will have replaced `'a` with a skolemized region +/// `'0`. This means that our substitution will be `{A=>&'0 +/// int, R=>&'0 int}`. +/// +/// When we apply the substitution to the bounds, we will wind up with +/// `&'0 int : Clone` as a predicate. As a last step, we then go and +/// replace `'0` with a late-bound region `'a`. The depth is matched +/// to the depth of the predicate, in this case 1, so that the final +/// predicate is `for<'a> &'a int : Clone`. +pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, + skol_map: SkolemizationMap, + snapshot: &CombinedSnapshot, + value: &T) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> +{ + debug_assert!(leak_check(infcx, &skol_map, snapshot).is_ok()); + + debug!("plug_leaks(skol_map={}, value={})", + skol_map.repr(infcx.tcx), + value.repr(infcx.tcx)); + + // Compute a mapping from the "taint set" of each skolemized + // region back to the `ty::BoundRegion` that it originally + // represented. Because `leak_check` passed, we know that that + // these taint sets are mutually disjoint. + let inv_skol_map: FnvHashMap<ty::Region, ty::BoundRegion> = + skol_map + .into_iter() + .flat_map(|(skol_br, skol)| { + infcx.tainted_regions(snapshot, skol) + .into_iter() + .map(move |tainted_region| (tainted_region, skol_br)) + }) + .collect(); + + debug!("plug_leaks: inv_skol_map={}", + inv_skol_map.repr(infcx.tcx)); + + // Remove any instantiated type variables from `value`; those can hide + // references to regions from the `fold_regions` code below. + let value = infcx.resolve_type_vars_if_possible(value); + + // Map any skolemization byproducts back to a late-bound + // region. Put that late-bound region at whatever the outermost + // binder is that we encountered in `value`. The caller is + // responsible for ensuring that (a) `value` contains at least one + // binder and (b) that binder is the one we want to use. + let result = ty_fold::fold_regions(infcx.tcx, &value, |r, current_depth| { + match inv_skol_map.get(&r) { + None => r, + Some(br) => { + // It is the responsibility of the caller to ensure + // that each skolemized region appears within a + // binder. In practice, this routine is only used by + // trait checking, and all of the skolemized regions + // appear inside predicates, which always have + // binders, so this assert is satisfied. + assert!(current_depth > 1); + + ty::ReLateBound(ty::DebruijnIndex::new(current_depth - 1), br.clone()) + } + } + }); + + debug!("plug_leaks: result={}", + result.repr(infcx.tcx)); + + result +} diff --git a/src/librustc/middle/infer/lub.rs b/src/librustc/middle/infer/lub.rs index f27b07c9c9d..f4909b28891 100644 --- a/src/librustc/middle/infer/lub.rs +++ b/src/librustc/middle/infer/lub.rs @@ -113,17 +113,13 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> { Ok(self.infcx().region_vars.lub_regions(Subtype(self.trace()), a, b)) } - fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) - -> cres<'tcx, ty::FnSig<'tcx>> { - self.higher_ranked_lub(a, b) - } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { super_lattice_tys(self, a, b) } - fn trait_refs(&self, a: &ty::TraitRef<'tcx>, b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>> { + fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>> + where T : Combineable<'tcx> + { self.higher_ranked_lub(a, b) } } diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 14153907ee7..25eadae5b92 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -19,21 +19,14 @@ pub use self::TypeOrigin::*; pub use self::ValuePairs::*; pub use self::fixup_err::*; pub use middle::ty::IntVarValue; -pub use self::resolve::resolve_and_force_all_but_regions; -pub use self::resolve::{force_all, not_regions}; -pub use self::resolve::{force_ivar}; -pub use self::resolve::{force_tvar, force_rvar}; -pub use self::resolve::{resolve_ivar, resolve_all}; -pub use self::resolve::{resolve_nested_tvar}; -pub use self::resolve::{resolve_rvar}; -pub use self::skolemize::TypeSkolemizer; +pub use self::freshen::TypeFreshener; use middle::subst; use middle::subst::Substs; use middle::ty::{TyVid, IntVid, FloatVid, RegionVid}; use middle::ty::replace_late_bound_regions; use middle::ty::{mod, Ty}; -use middle::ty_fold::{HigherRankedFoldable, TypeFolder, TypeFoldable}; +use middle::ty_fold::{TypeFolder, TypeFoldable}; use std::cell::{RefCell}; use std::rc::Rc; use syntax::ast; @@ -42,12 +35,11 @@ use syntax::codemap::Span; use util::common::indent; use util::nodemap::FnvHashMap; use util::ppaux::{ty_to_string}; -use util::ppaux::{trait_ref_to_string, Repr}; +use util::ppaux::{Repr, UserString}; use self::coercion::Coerce; use self::combine::{Combine, CombineFields}; use self::region_inference::{RegionVarBindings, RegionSnapshot}; -use self::resolve::{resolver}; use self::equate::Equate; use self::sub::Sub; use self::lub::Lub; @@ -60,12 +52,12 @@ pub mod doc; pub mod equate; pub mod error_reporting; pub mod glb; -pub mod higher_ranked; +mod higher_ranked; pub mod lattice; pub mod lub; pub mod region_inference; pub mod resolve; -mod skolemize; +mod freshen; pub mod sub; pub mod type_variable; pub mod unify; @@ -98,10 +90,14 @@ pub struct InferCtxt<'a, 'tcx: 'a> { RegionVarBindings<'a, 'tcx>, } +/// A map returned by `skolemize_late_bound_regions()` indicating the skolemized +/// region that each late-bound region was replaced with. +pub type SkolemizationMap = FnvHashMap<ty::BoundRegion,ty::Region>; + /// Why did we require that the two types be related? /// /// See `error_reporting.rs` for more details -#[deriving(Clone, Show)] +#[deriving(Clone, Copy, Show)] pub enum TypeOrigin { // Not yet categorized in a better way Misc(Span), @@ -135,13 +131,12 @@ pub enum TypeOrigin { EquatePredicate(Span), } -impl Copy for TypeOrigin {} - /// See `error_reporting.rs` for more details #[deriving(Clone, Show)] pub enum ValuePairs<'tcx> { Types(ty::expected_found<Ty<'tcx>>), TraitRefs(ty::expected_found<Rc<ty::TraitRef<'tcx>>>), + PolyTraitRefs(ty::expected_found<Rc<ty::PolyTraitRef<'tcx>>>), } /// The trace designates the path through inference that we took to @@ -226,7 +221,7 @@ pub enum SubregionOrigin<'tcx> { } /// Times when we replace late-bound regions with variables: -#[deriving(Clone, Show)] +#[deriving(Clone, Copy, Show)] pub enum LateBoundRegionConversionTime { /// when a fn is called FnCall, @@ -235,8 +230,6 @@ pub enum LateBoundRegionConversionTime { HigherRankedType, } -impl Copy for LateBoundRegionConversionTime {} - /// Reasons to create a region inference variable /// /// See `error_reporting.rs` for more details @@ -273,15 +266,13 @@ pub enum RegionVariableOrigin<'tcx> { BoundRegionInCoherence(ast::Name), } -#[deriving(Show)] +#[deriving(Copy, Show)] pub enum fixup_err { unresolved_int_ty(IntVid), unresolved_float_ty(FloatVid), unresolved_ty(TyVid) } -impl Copy for fixup_err {} - pub fn fixup_err_to_string(f: fixup_err) -> String { match f { unresolved_int_ty(_) => { @@ -353,7 +344,7 @@ pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, b: Ty<'tcx>) -> ures<'tcx> { debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); - cx.probe(|| { + cx.probe(|_| { let trace = TypeTrace { origin: Misc(codemap::DUMMY_SP), values: Types(expected_found(true, a, b)) @@ -366,7 +357,7 @@ pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> ures<'tcx> { debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); - cx.probe(|| { + cx.probe(|_| { let trace = TypeTrace { origin: Misc(codemap::DUMMY_SP), values: Types(expected_found(true, a, b)) @@ -410,17 +401,17 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, || cx.eq_types(a_is_expected, origin, a, b)) } -pub fn mk_sub_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, +pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a_is_expected: bool, origin: TypeOrigin, - a: Rc<ty::TraitRef<'tcx>>, - b: Rc<ty::TraitRef<'tcx>>) + a: Rc<ty::PolyTraitRef<'tcx>>, + b: Rc<ty::PolyTraitRef<'tcx>>) -> ures<'tcx> { debug!("mk_sub_trait_refs({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); cx.commit_if_ok( - || cx.sub_trait_refs(a_is_expected, origin, a.clone(), b.clone())) + || cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone())) } fn expected_found<T>(a_is_expected: bool, @@ -453,22 +444,6 @@ pub fn mk_coercety<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, }) } -// See comment on the type `resolve_state` below -pub fn resolve_type<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, - span: Option<Span>, - a: Ty<'tcx>, - modes: uint) - -> fres<Ty<'tcx>> { - let mut resolver = resolver(cx, modes, span); - cx.commit_unconditionally(|| resolver.resolve_type_chk(a)) -} - -pub fn resolve_region(cx: &InferCtxt, r: ty::Region, modes: uint) - -> fres<ty::Region> { - let mut resolver = resolver(cx, modes, None); - resolver.resolve_region_chk(r) -} - trait then<'tcx> { fn then<T, F>(&self, f: F) -> Result<T, ty::type_err<'tcx>> where T: Clone, @@ -520,6 +495,7 @@ pub fn uok<'tcx>() -> ures<'tcx> { Ok(()) } +#[must_use = "once you start a snapshot, you should always consume it"] pub struct CombinedSnapshot { type_snapshot: type_variable::Snapshot, int_snapshot: unify::Snapshot<ty::IntVid>, @@ -528,8 +504,8 @@ pub struct CombinedSnapshot { } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn skolemize<T:TypeFoldable<'tcx>>(&self, t: T) -> T { - t.fold_with(&mut self.skolemizer()) + pub fn freshen<T:TypeFoldable<'tcx>>(&self, t: T) -> T { + t.fold_with(&mut self.freshener()) } pub fn type_var_diverges(&'a self, ty: Ty) -> bool { @@ -539,8 +515,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - pub fn skolemizer<'b>(&'b self) -> TypeSkolemizer<'b, 'tcx> { - skolemize::TypeSkolemizer::new(self) + pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> { + freshen::TypeFreshener::new(self) } pub fn combine_fields<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) @@ -629,16 +605,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E> where F: FnOnce() -> Result<T, E> { - self.commit_unconditionally(move || self.try(move || f())) + self.commit_unconditionally(move || self.try(move |_| f())) } /// Execute `f`, unroll bindings on panic pub fn try<T, E, F>(&self, f: F) -> Result<T, E> where - F: FnOnce() -> Result<T, E> + F: FnOnce(&CombinedSnapshot) -> Result<T, E> { debug!("try()"); let snapshot = self.start_snapshot(); - let r = f(); + let r = f(&snapshot); debug!("try() -- r.is_ok() = {}", r.is_ok()); match r { Ok(_) => { @@ -653,11 +629,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Execute `f` then unroll any bindings it creates pub fn probe<R, F>(&self, f: F) -> R where - F: FnOnce() -> R, + F: FnOnce(&CombinedSnapshot) -> R, { debug!("probe()"); let snapshot = self.start_snapshot(); - let r = f(); + let r = f(&snapshot); self.rollback_to(snapshot); r } @@ -715,15 +691,93 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.commit_if_ok(|| { let trace = TypeTrace { origin: origin, - values: TraitRefs(expected_found(a_is_expected, - a.clone(), b.clone())) + values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) }; self.sub(a_is_expected, trace).trait_refs(&*a, &*b).to_ures() }) } -} -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { + pub fn sub_poly_trait_refs(&self, + a_is_expected: bool, + origin: TypeOrigin, + a: Rc<ty::PolyTraitRef<'tcx>>, + b: Rc<ty::PolyTraitRef<'tcx>>) + -> ures<'tcx> + { + debug!("sub_poly_trait_refs({} <: {})", + a.repr(self.tcx), + b.repr(self.tcx)); + self.commit_if_ok(|| { + let trace = TypeTrace { + origin: origin, + values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) + }; + self.sub(a_is_expected, trace).binders(&*a, &*b).to_ures() + }) + } + + pub fn skolemize_late_bound_regions<T>(&self, + value: &ty::Binder<T>, + snapshot: &CombinedSnapshot) + -> (T, SkolemizationMap) + where T : TypeFoldable<'tcx> + Repr<'tcx> + { + /*! See `higher_ranked::skolemize_late_bound_regions` */ + + higher_ranked::skolemize_late_bound_regions(self, value, snapshot) + } + + pub fn leak_check(&self, + skol_map: &SkolemizationMap, + snapshot: &CombinedSnapshot) + -> ures<'tcx> + { + /*! See `higher_ranked::leak_check` */ + + match higher_ranked::leak_check(self, skol_map, snapshot) { + Ok(()) => Ok(()), + Err((br, r)) => Err(ty::terr_regions_insufficiently_polymorphic(br, r)) + } + } + + pub fn plug_leaks<T>(&self, + skol_map: SkolemizationMap, + snapshot: &CombinedSnapshot, + value: &T) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> + { + /*! See `higher_ranked::leak_check` */ + + higher_ranked::plug_leaks(self, skol_map, snapshot, value) + } + + pub fn equality_predicate(&self, + span: Span, + predicate: &ty::PolyEquatePredicate<'tcx>) + -> ures<'tcx> { + self.try(|snapshot| { + let (ty::EquatePredicate(a, b), skol_map) = + self.skolemize_late_bound_regions(predicate, snapshot); + let origin = EquatePredicate(span); + let () = try!(mk_eqty(self, false, origin, a, b)); + self.leak_check(&skol_map, snapshot) + }) + } + + pub fn region_outlives_predicate(&self, + span: Span, + predicate: &ty::PolyRegionOutlivesPredicate) + -> ures<'tcx> { + self.try(|snapshot| { + let (ty::OutlivesPredicate(r_a, r_b), skol_map) = + self.skolemize_late_bound_regions(predicate, snapshot); + let origin = RelateRegionParamBound(span); + let () = mk_subr(self, origin, r_b, r_a); // `b : a` ==> `a <= b` + self.leak_check(&skol_map, snapshot) + }) + } + pub fn next_ty_var_id(&self, diverging: bool) -> TyVid { self.type_variables .borrow_mut() @@ -821,7 +875,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { ty_to_string(self.tcx, - self.resolve_type_vars_if_possible(t)) + self.resolve_type_vars_if_possible(&t)) } pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String { @@ -830,24 +884,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn trait_ref_to_string(&self, t: &Rc<ty::TraitRef<'tcx>>) -> String { - let t = self.resolve_type_vars_in_trait_ref_if_possible(&**t); - trait_ref_to_string(self.tcx, &t) - } - - pub fn contains_unbound_type_variables(&self, typ: Ty<'tcx>) -> Ty<'tcx> { - match resolve_type(self, - None, - typ, resolve_nested_tvar | resolve_ivar) { - Ok(new_type) => new_type, - Err(_) => typ - } + let t = self.resolve_type_vars_if_possible(&**t); + t.user_string(self.tcx) } pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> { match typ.sty { ty::ty_infer(ty::TyVar(v)) => { + // Not entirely obvious: if `typ` is a type variable, + // it can be resolved to an int/float variable, which + // can then be recursively resolved, hence the + // recursion. Note though that we prevent type + // variables from unifying to other type variables + // directly (though they may be embedded + // structurally), and we prevent cycles in any case, + // so this recursion should always be of very limited + // depth. self.type_variables.borrow() .probe(v) + .map(|t| self.shallow_resolve(t)) .unwrap_or(typ) } @@ -867,35 +922,32 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - pub fn resolve_type_vars_if_possible(&self, typ: Ty<'tcx>) -> Ty<'tcx> { - match resolve_type(self, - None, - typ, resolve_nested_tvar | resolve_ivar) { - Ok(new_type) => new_type, - Err(_) => typ - } + pub fn resolve_type_vars_if_possible<T:TypeFoldable<'tcx>>(&self, value: &T) -> T { + /*! + * Where possible, replaces type/int/float variables in + * `value` with their final value. Note that region variables + * are unaffected. If a type variable has not been unified, it + * is left as is. This is an idempotent operation that does + * not affect inference state in any way and so you can do it + * at will. + */ + + let mut r = resolve::OpportunisticTypeResolver::new(self); + value.fold_with(&mut r) } - pub fn resolve_type_vars_in_trait_ref_if_possible(&self, - trait_ref: &ty::TraitRef<'tcx>) - -> ty::TraitRef<'tcx> { - // make up a dummy type just to reuse/abuse the resolve machinery - let dummy0 = ty::mk_trait(self.tcx, - (*trait_ref).clone(), - ty::region_existential_bound(ty::ReStatic)); - let dummy1 = self.resolve_type_vars_if_possible(dummy0); - match dummy1.sty { - ty::ty_trait(box ty::TyTrait { ref principal, .. }) => { - (*principal).clone() - } - _ => { - self.tcx.sess.bug( - format!("resolve_type_vars_if_possible() yielded {} \ - when supplied with {}", - self.ty_to_string(dummy0), - self.ty_to_string(dummy1)).as_slice()); - } - } + pub fn fully_resolve<T:TypeFoldable<'tcx>>(&self, value: &T) -> fres<T> { + /*! + * Attempts to resolve all type/region variables in + * `value`. Region inference must have been run already (e.g., + * by calling `resolve_regions_and_report_errors`). If some + * variable was never unified, an `Err` results. + * + * This method is idempotent, but it not typically not invoked + * except during the writeback phase. + */ + + resolve::fully_resolve(self, value) } // [Note-Type-error-reporting] @@ -929,9 +981,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { debug!("hi! expected_ty = {}, actual_ty = {}", expected_ty, actual_ty); - let resolved_expected = expected_ty.map(|e_ty| { - self.resolve_type_vars_if_possible(e_ty) - }); + let resolved_expected = expected_ty.map(|e_ty| self.resolve_type_vars_if_possible(&e_ty)); match resolved_expected { Some(t) if ty::type_is_error(t) => (), @@ -958,7 +1008,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err: Option<&ty::type_err<'tcx>>) where M: FnOnce(String) -> String, { - let actual_ty = self.resolve_type_vars_if_possible(actual_ty); + let actual_ty = self.resolve_type_vars_if_possible(&actual_ty); // Don't report an error if actual type is ty_err. if ty::type_is_error(actual_ty) { @@ -989,9 +1039,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, span: Span, lbrct: LateBoundRegionConversionTime, - value: &T) + value: &ty::Binder<T>) -> (T, FnvHashMap<ty::BoundRegion,ty::Region>) - where T : HigherRankedFoldable<'tcx> + where T : TypeFoldable<'tcx> + Repr<'tcx> { ty::replace_late_bound_regions( self.tcx, diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index ca2860ae6b3..bcaf39cc8db 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -40,7 +40,7 @@ mod doc; mod graphviz; // A constraint that influences the inference process. -#[deriving(Clone, PartialEq, Eq, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash, Show)] pub enum Constraint { // One region variable is subregion of another ConstrainVarSubVar(RegionVid, RegionVid), @@ -52,8 +52,6 @@ pub enum Constraint { ConstrainVarSubReg(RegionVid, Region), } -impl Copy for Constraint {} - // Something we have to verify after region inference is done, but // which does not directly influence the inference process pub enum Verify<'tcx> { @@ -69,19 +67,16 @@ pub enum Verify<'tcx> { VerifyParamBound(ty::ParamTy, SubregionOrigin<'tcx>, Region, Vec<Region>), } -#[deriving(PartialEq, Eq, Hash)] +#[deriving(Copy, PartialEq, Eq, Hash)] pub struct TwoRegions { a: Region, b: Region, } -impl Copy for TwoRegions {} - -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub enum UndoLogEntry { OpenSnapshot, CommitedSnapshot, - Mark, AddVar(RegionVid), AddConstraint(Constraint), AddVerify(uint), @@ -89,15 +84,11 @@ pub enum UndoLogEntry { AddCombination(CombineMapType, TwoRegions) } -impl Copy for UndoLogEntry {} - -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub enum CombineMapType { Lub, Glb } -impl Copy for CombineMapType {} - #[deriving(Clone, Show)] pub enum RegionResolutionError<'tcx> { /// `ConcreteFailure(o, a, b)`: @@ -225,19 +216,12 @@ pub struct RegionVarBindings<'a, 'tcx: 'a> { } #[deriving(Show)] +#[allow(missing_copy_implementations)] pub struct RegionSnapshot { - length: uint + length: uint, + skolemization_count: uint, } -impl Copy for RegionSnapshot {} - -#[deriving(Show)] -pub struct RegionMark { - length: uint -} - -impl Copy for RegionMark {} - impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { pub fn new(tcx: &'a ty::ctxt<'tcx>) -> RegionVarBindings<'a, 'tcx> { RegionVarBindings { @@ -263,14 +247,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { let length = self.undo_log.borrow().len(); debug!("RegionVarBindings: start_snapshot({})", length); self.undo_log.borrow_mut().push(OpenSnapshot); - RegionSnapshot { length: length } - } - - pub fn mark(&self) -> RegionMark { - let length = self.undo_log.borrow().len(); - debug!("RegionVarBindings: mark({})", length); - self.undo_log.borrow_mut().push(Mark); - RegionMark { length: length } + RegionSnapshot { length: length, skolemization_count: self.skolemization_count.get() } } pub fn commit(&self, snapshot: RegionSnapshot) { @@ -284,6 +261,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } else { (*undo_log)[snapshot.length] = CommitedSnapshot; } + self.skolemization_count.set(snapshot.skolemization_count); } pub fn rollback_to(&self, snapshot: RegionSnapshot) { @@ -296,7 +274,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { OpenSnapshot => { panic!("Failure to observe stack discipline"); } - Mark | CommitedSnapshot => { } + CommitedSnapshot => { } AddVar(vid) => { let mut var_origins = self.var_origins.borrow_mut(); var_origins.pop().unwrap(); @@ -322,6 +300,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } let c = undo_log.pop().unwrap(); assert!(c == OpenSnapshot); + self.skolemization_count.set(snapshot.skolemization_count); } pub fn num_vars(&self) -> uint { @@ -340,7 +319,25 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { return vid; } - pub fn new_skolemized(&self, br: ty::BoundRegion) -> Region { + /// Creates a new skolemized region. Skolemized regions are fresh + /// regions used when performing higher-ranked computations. They + /// must be used in a very particular way and are never supposed + /// to "escape" out into error messages or the code at large. + /// + /// The idea is to always create a snapshot. Skolemized regions + /// can be created in the context of this snapshot, but once the + /// snapshot is commited or rolled back, their numbers will be + /// recycled, so you must be finished with them. See the extensive + /// comments in `higher_ranked.rs` to see how it works (in + /// particular, the subtyping comparison). + /// + /// The `snapshot` argument to this function is not really used; + /// it's just there to make it explicit which snapshot bounds the + /// skolemized region that results. + pub fn new_skolemized(&self, br: ty::BoundRegion, snapshot: &RegionSnapshot) -> Region { + assert!(self.in_snapshot()); + assert!(self.undo_log.borrow()[snapshot.length] == OpenSnapshot); + let sc = self.skolemization_count.get(); self.skolemization_count.set(sc + 1); ReInfer(ReSkolemized(sc, br)) @@ -597,8 +594,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { ReInfer(ReVar(c)) } - pub fn vars_created_since_mark(&self, mark: RegionMark) - -> Vec<RegionVid> + pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot) + -> Vec<RegionVid> { self.undo_log.borrow() .slice_from(mark.length) @@ -613,7 +610,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { /// Computes all regions that have been related to `r0` in any way since the mark `mark` was /// made---`r0` itself will be the first entry. This is used when checking whether skolemized /// regions are being improperly related to other regions. - pub fn tainted(&self, mark: RegionMark, r0: Region) -> Vec<Region> { + pub fn tainted(&self, mark: &RegionSnapshot, r0: Region) -> Vec<Region> { debug!("tainted(mark={}, r0={})", mark, r0.repr(self.tcx)); let _indenter = indenter(); @@ -668,7 +665,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } } &AddCombination(..) | - &Mark | &AddVar(..) | &OpenSnapshot | &CommitedSnapshot => { @@ -936,15 +932,12 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // ______________________________________________________________________ -#[deriving(PartialEq, Show)] +#[deriving(Copy, PartialEq, Show)] enum Classification { Expanding, Contracting } -impl Copy for Classification {} - +#[deriving(Copy)] pub enum VarValue { NoValue, Value(Region), ErrorValue } -impl Copy for VarValue {} - struct VarData { classification: Classification, value: VarValue, diff --git a/src/librustc/middle/infer/resolve.rs b/src/librustc/middle/infer/resolve.rs index eaf363ffc74..12400de31ed 100644 --- a/src/librustc/middle/infer/resolve.rs +++ b/src/librustc/middle/infer/resolve.rs @@ -8,253 +8,108 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Resolution is the process of removing type variables and replacing -// them with their inferred values. Unfortunately our inference has -// become fairly complex and so there are a number of options to -// control *just how much* you want to resolve and how you want to do -// it. -// -// # Controlling the scope of resolution -// -// The options resolve_* determine what kinds of variables get -// resolved. Generally resolution starts with a top-level type -// variable; we will always resolve this. However, once we have -// resolved that variable, we may end up with a type that still -// contains type variables. For example, if we resolve `<T0>` we may -// end up with something like `[<T1>]`. If the option -// `resolve_nested_tvar` is passed, we will then go and recursively -// resolve `<T1>`. -// -// The options `resolve_rvar` controls whether we resolve region -// variables. The options `resolve_fvar` and `resolve_ivar` control -// whether we resolve floating point and integral variables, -// respectively. -// -// # What do if things are unconstrained -// -// Sometimes we will encounter a variable that has no constraints, and -// therefore cannot sensibly be mapped to any particular result. By -// default, we will leave such variables as is (so you will get back a -// variable in your result). The options force_* will cause the -// resolution to fail in this case instead, except for the case of -// integral variables, which resolve to `int` if forced. -// -// # resolve_all and force_all -// -// The options are a bit set, so you can use the *_all to resolve or -// force all kinds of variables (including those we may add in the -// future). If you want to resolve everything but one type, you are -// probably better off writing `resolve_all - resolve_ivar`. - -#![allow(non_upper_case_globals)] - -use super::{fixup_err, fres, InferCtxt}; -use super::{unresolved_int_ty,unresolved_float_ty,unresolved_ty}; - -use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid}; -use middle::ty::{IntType, UintType}; +use super::{InferCtxt, fixup_err, fres, unresolved_ty, unresolved_int_ty, unresolved_float_ty}; use middle::ty::{mod, Ty}; -use middle::ty_fold; -use syntax::codemap::Span; -use util::ppaux::{Repr, ty_to_string}; - -pub const resolve_nested_tvar: uint = 0b0000000001; -pub const resolve_rvar: uint = 0b0000000010; -pub const resolve_ivar: uint = 0b0000000100; -pub const resolve_fvar: uint = 0b0000001000; -pub const resolve_all: uint = 0b0000001111; -pub const force_tvar: uint = 0b0000100000; -pub const force_rvar: uint = 0b0001000000; -pub const force_ivar: uint = 0b0010000000; -pub const force_fvar: uint = 0b0100000000; -pub const force_all: uint = 0b0111100000; - -pub const not_regions: uint = !(force_rvar | resolve_rvar); - -pub const try_resolve_tvar_shallow: uint = 0; -pub const resolve_and_force_all_but_regions: uint = - (resolve_all | force_all) & not_regions; - -pub struct ResolveState<'a, 'tcx: 'a> { +use middle::ty_fold::{mod, TypeFoldable}; +use util::ppaux::Repr; + +/////////////////////////////////////////////////////////////////////////// +// OPPORTUNISTIC TYPE RESOLVER + +/// The opportunistic type resolver can be used at any time. It simply replaces +/// type variables that have been unified with the things they have +/// been unified with (similar to `shallow_resolve`, but deep). This is +/// useful for printing messages etc but also required at various +/// points for correctness. +pub struct OpportunisticTypeResolver<'a, 'tcx:'a> { infcx: &'a InferCtxt<'a, 'tcx>, - modes: uint, - err: Option<fixup_err>, - type_depth: uint, } -pub fn resolver<'a, 'tcx>(infcx: &'a InferCtxt<'a, 'tcx>, - modes: uint, - _: Option<Span>) - -> ResolveState<'a, 'tcx> { - ResolveState { - infcx: infcx, - modes: modes, - err: None, - type_depth: 0, +impl<'a, 'tcx> OpportunisticTypeResolver<'a, 'tcx> { + pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> OpportunisticTypeResolver<'a, 'tcx> { + OpportunisticTypeResolver { infcx: infcx } } } -impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for ResolveState<'a, 'tcx> { +impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for OpportunisticTypeResolver<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.infcx.tcx } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - self.resolve_type(t) - } - - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - self.resolve_region(r) - } -} - -impl<'a, 'tcx> ResolveState<'a, 'tcx> { - pub fn should(&mut self, mode: uint) -> bool { - (self.modes & mode) == mode - } - - pub fn resolve_type_chk(&mut self, typ: Ty<'tcx>) -> fres<Ty<'tcx>> { - self.err = None; - - debug!("Resolving {} (modes={:x})", - ty_to_string(self.infcx.tcx, typ), - self.modes); - - // n.b. This is a hokey mess because the current fold doesn't - // allow us to pass back errors in any useful way. - - let rty = self.resolve_type(typ); - match self.err { - None => { - debug!("Resolved {} to {} (modes={:x})", - ty_to_string(self.infcx.tcx, typ), - ty_to_string(self.infcx.tcx, rty), - self.modes); - return Ok(rty); - } - Some(e) => { - return Err(e); - } - } - } - - pub fn resolve_region_chk(&mut self, - orig: ty::Region) - -> fres<ty::Region> { - self.err = None; - let resolved = self.resolve_region(orig); - match self.err { - None => Ok(resolved), - Some(e) => Err(e) + if !ty::type_has_ty_infer(t) { + t // micro-optimize -- if there is nothing in this type that this fold affects... + } else { + let t0 = self.infcx.shallow_resolve(t); + ty_fold::super_fold_ty(self, t0) } } +} - pub fn resolve_type(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> { - debug!("resolve_type({})", typ.repr(self.infcx.tcx)); - - if !ty::type_needs_infer(typ) { - return typ; - } - - if self.type_depth > 0 && !self.should(resolve_nested_tvar) { - return typ; - } - - match typ.sty { - ty::ty_infer(TyVar(vid)) => { - self.resolve_ty_var(vid) - } - ty::ty_infer(IntVar(vid)) => { - self.resolve_int_var(vid) - } - ty::ty_infer(FloatVar(vid)) => { - self.resolve_float_var(vid) - } - _ => { - if self.modes & resolve_all == 0 { - // if we are only resolving top-level type - // variables, and this is not a top-level type - // variable, then shortcircuit for efficiency - typ - } else { - self.type_depth += 1; - let result = ty_fold::super_fold_ty(self, typ); - self.type_depth -= 1; - result - } - } - } +/////////////////////////////////////////////////////////////////////////// +// FULL TYPE RESOLUTION + +/// Full type resolution replaces all type and region variables with +/// their concrete results. If any variable cannot be replaced (never unified, etc) +/// then an `Err` result is returned. +pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a,'tcx>, value: &T) -> fres<T> + where T : TypeFoldable<'tcx> +{ + let mut full_resolver = FullTypeResolver { infcx: infcx, err: None }; + let result = value.fold_with(&mut full_resolver); + match full_resolver.err { + None => Ok(result), + Some(e) => Err(e), } +} - pub fn resolve_region(&mut self, orig: ty::Region) -> ty::Region { - debug!("Resolve_region({})", orig.repr(self.infcx.tcx)); - match orig { - ty::ReInfer(ty::ReVar(rid)) => self.resolve_region_var(rid), - _ => orig - } - } +// N.B. This type is not public because the protocol around checking the +// `err` field is not enforcable otherwise. +struct FullTypeResolver<'a, 'tcx:'a> { + infcx: &'a InferCtxt<'a, 'tcx>, + err: Option<fixup_err>, +} - pub fn resolve_region_var(&mut self, rid: RegionVid) -> ty::Region { - if !self.should(resolve_rvar) { - return ty::ReInfer(ty::ReVar(rid)); - } - self.infcx.region_vars.resolve_var(rid) +impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { + fn tcx(&self) -> &ty::ctxt<'tcx> { + self.infcx.tcx } - pub fn resolve_ty_var(&mut self, vid: TyVid) -> Ty<'tcx> { - let tcx = self.infcx.tcx; - let tv = self.infcx.type_variables.borrow(); - match tv.probe(vid) { - Some(t) => { - self.resolve_type(t) - } - None => { - if self.should(force_tvar) { + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if !ty::type_needs_infer(t) { + t // micro-optimize -- if there is nothing in this type that this fold affects... + } else { + let t = self.infcx.shallow_resolve(t); + match t.sty { + ty::ty_infer(ty::TyVar(vid)) => { self.err = Some(unresolved_ty(vid)); + ty::mk_err() + } + ty::ty_infer(ty::IntVar(vid)) => { + self.err = Some(unresolved_int_ty(vid)); + ty::mk_err() + } + ty::ty_infer(ty::FloatVar(vid)) => { + self.err = Some(unresolved_float_ty(vid)); + ty::mk_err() + } + ty::ty_infer(_) => { + self.infcx.tcx.sess.bug( + format!("Unexpected type in full type resolver: {}", + t.repr(self.infcx.tcx))[]); + } + _ => { + ty_fold::super_fold_ty(self, t) } - ty::mk_var(tcx, vid) - } - } - } - - pub fn resolve_int_var(&mut self, vid: IntVid) -> Ty<'tcx> { - if !self.should(resolve_ivar) { - return ty::mk_int_var(self.infcx.tcx, vid); - } - - let tcx = self.infcx.tcx; - let table = &self.infcx.int_unification_table; - let node = table.borrow_mut().get(tcx, vid); - match node.value { - Some(IntType(t)) => ty::mk_mach_int(t), - Some(UintType(t)) => ty::mk_mach_uint(t), - None => { - if self.should(force_ivar) { - // As a last resort, emit an error. - self.err = Some(unresolved_int_ty(vid)); } - ty::mk_int_var(self.infcx.tcx, vid) - } } } - pub fn resolve_float_var(&mut self, vid: FloatVid) -> Ty<'tcx> { - if !self.should(resolve_fvar) { - return ty::mk_float_var(self.infcx.tcx, vid); - } - - let tcx = self.infcx.tcx; - let table = &self.infcx.float_unification_table; - let node = table.borrow_mut().get(tcx, vid); - match node.value { - Some(t) => ty::mk_mach_float(t), - None => { - if self.should(force_fvar) { - // As a last resort, emit an error. - self.err = Some(unresolved_float_ty(vid)); - } - ty::mk_float_var(self.infcx.tcx, vid) - } + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + match r { + ty::ReInfer(ty::ReVar(rid)) => self.infcx.region_vars.resolve_var(rid), + _ => r, } } } + diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs index 00c79bc726c..2b8adfb7c1e 100644 --- a/src/librustc/middle/infer/sub.rs +++ b/src/librustc/middle/infer/sub.rs @@ -155,13 +155,9 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { } } - fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) - -> cres<'tcx, ty::FnSig<'tcx>> { - self.higher_ranked_sub(a, b) - } - - fn trait_refs(&self, a: &ty::TraitRef<'tcx>, b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>> { + fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>> + where T : Combineable<'tcx> + { self.higher_ranked_sub(a, b) } } diff --git a/src/librustc/middle/infer/type_variable.rs b/src/librustc/middle/infer/type_variable.rs index 766e930486c..5e857154871 100644 --- a/src/librustc/middle/infer/type_variable.rs +++ b/src/librustc/middle/infer/type_variable.rs @@ -13,7 +13,9 @@ use self::TypeVariableValue::*; use self::UndoEntry::*; use middle::ty::{mod, Ty}; +use std::cmp::min; use std::mem; +use std::uint; use util::snapshot_vec as sv; pub struct TypeVariableTable<'tcx> { @@ -44,13 +46,11 @@ struct Delegate; type Relation = (RelationDir, ty::TyVid); -#[deriving(PartialEq,Show)] +#[deriving(Copy, PartialEq, Show)] pub enum RelationDir { SubtypeOf, SupertypeOf, EqTo } -impl Copy for RelationDir {} - impl RelationDir { fn opposite(self) -> RelationDir { match self { @@ -78,7 +78,6 @@ impl<'tcx> TypeVariableTable<'tcx> { /// /// Precondition: neither `a` nor `b` are known. pub fn relate_vars(&mut self, a: ty::TyVid, dir: RelationDir, b: ty::TyVid) { - if a != b { self.relations(a).push((dir, b)); self.relations(b).push((dir.opposite(), a)); @@ -151,6 +150,49 @@ impl<'tcx> TypeVariableTable<'tcx> { pub fn commit(&mut self, s: Snapshot) { self.values.commit(s.snapshot); } + + pub fn types_escaping_snapshot(&self, s: &Snapshot) -> Vec<Ty<'tcx>> { + /*! + * Find the set of type variables that existed *before* `s` + * but which have only been unified since `s` started, and + * return the types with which they were unified. So if we had + * a type variable `V0`, then we started the snapshot, then we + * created a type variable `V1`, unifed `V0` with `T0`, and + * unified `V1` with `T1`, this function would return `{T0}`. + */ + + let mut new_elem_threshold = uint::MAX; + let mut escaping_types = Vec::new(); + let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); + debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len()); + for action in actions_since_snapshot.iter() { + match *action { + sv::UndoLog::NewElem(index) => { + // if any new variables were created during the + // snapshot, remember the lower index (which will + // always be the first one we see). Note that this + // action must precede those variables being + // specified. + new_elem_threshold = min(new_elem_threshold, index); + debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold); + } + + sv::UndoLog::Other(SpecifyVar(vid, _)) => { + if vid.index < new_elem_threshold { + // quick check to see if this variable was + // created since the snapshot started or not. + let escaping_type = self.probe(vid).unwrap(); + escaping_types.push(escaping_type); + } + debug!("SpecifyVar({}) new_elem_threshold={}", vid, new_elem_threshold); + } + + _ => { } + } + } + + escaping_types + } } impl<'tcx> sv::SnapshotVecDelegate<TypeVariableData<'tcx>,UndoEntry> for Delegate { diff --git a/src/librustc/middle/infer/unify.rs b/src/librustc/middle/infer/unify.rs index a2dd4d62913..0b81823e9ed 100644 --- a/src/librustc/middle/infer/unify.rs +++ b/src/librustc/middle/infer/unify.rs @@ -90,10 +90,9 @@ pub struct Node<K,V> { pub rank: uint, } +#[deriving(Copy)] pub struct Delegate; -impl Copy for Delegate {} - // We can't use V:LatticeValue, much as I would like to, // because frequently the pattern is that V=Option<U> for some // other type parameter U, and we have no way to say diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index acfdf6fefb5..ea19111ce3d 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -124,8 +124,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> { let typ = ty::node_id_to_type(self.tcx, expr.id); match typ.sty { ty_bare_fn(ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => { - if let ty::FnConverging(to) = bare_fn_ty.sig.output { - let from = bare_fn_ty.sig.inputs[0]; + if let ty::FnConverging(to) = bare_fn_ty.sig.0.output { + let from = bare_fn_ty.sig.0.inputs[0]; self.check_transmute(expr.span, from, to, expr.id); } } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 8d5528b3709..2ffc5d8a510 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -45,13 +45,11 @@ macro_rules! lets_do_this { $( $variant:ident, $name:expr, $method:ident; )* ) => { -#[deriving(FromPrimitive, PartialEq, Eq, Hash)] +#[deriving(Copy, FromPrimitive, PartialEq, Eq, Hash)] pub enum LangItem { $($variant),* } -impl Copy for LangItem {} - pub struct LanguageItems { pub items: Vec<Option<ast::DefId>>, pub missing: Vec<LangItem>, diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index c76d9bc6b1f..b76d798941e 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -135,16 +135,12 @@ enum LoopKind<'a> { ForLoop(&'a ast::Pat), } -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] struct Variable(uint); -impl Copy for Variable {} - -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] struct LiveNode(uint); -impl Copy for LiveNode {} - impl Variable { fn get(&self) -> uint { let Variable(v) = *self; v } } @@ -159,7 +155,7 @@ impl Clone for LiveNode { } } -#[deriving(PartialEq, Show)] +#[deriving(Copy, PartialEq, Show)] enum LiveNodeKind { FreeVarNode(Span), ExprNode(Span), @@ -167,8 +163,6 @@ enum LiveNodeKind { ExitNode } -impl Copy for LiveNodeKind {} - fn live_node_kind_to_string(lnk: LiveNodeKind, cx: &ty::ctxt) -> String { let cm = cx.sess.codemap(); match lnk { @@ -247,15 +241,13 @@ struct CaptureInfo { var_nid: NodeId } -#[deriving(Show)] +#[deriving(Copy, Show)] struct LocalInfo { id: NodeId, ident: ast::Ident } -impl Copy for LocalInfo {} - -#[deriving(Show)] +#[deriving(Copy, Show)] enum VarKind { Arg(NodeId, ast::Ident), Local(LocalInfo), @@ -263,8 +255,6 @@ enum VarKind { CleanExit } -impl Copy for VarKind {} - struct IrMaps<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, @@ -536,15 +526,13 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) { // Actually we compute just a bit more than just liveness, but we use // the same basic propagation framework in all cases. -#[deriving(Clone)] +#[deriving(Clone, Copy)] struct Users { reader: LiveNode, writer: LiveNode, used: bool } -impl Copy for Users {} - fn invalid_users() -> Users { Users { reader: invalid_node(), @@ -553,6 +541,7 @@ fn invalid_users() -> Users { } } +#[deriving(Copy)] struct Specials { exit_ln: LiveNode, fallthrough_ln: LiveNode, @@ -560,8 +549,6 @@ struct Specials { clean_exit_var: Variable } -impl Copy for Specials {} - static ACC_READ: uint = 1u; static ACC_WRITE: uint = 2u; static ACC_USE: uint = 4u; @@ -1534,6 +1521,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { .unwrap() .closure_type .sig + .0 .output, _ => ty::ty_fn_ret(fn_ty) } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 0e05eb4dcdd..dce75579ca0 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -101,7 +101,7 @@ pub enum categorization<'tcx> { } // Represents any kind of upvar -#[deriving(Clone, PartialEq, Show)] +#[deriving(Clone, Copy, PartialEq, Show)] pub struct Upvar { pub id: ty::UpvarId, // Unboxed closure kinds are used even for old-style closures for simplicity @@ -110,10 +110,8 @@ pub struct Upvar { pub is_unboxed: bool } -impl Copy for Upvar {} - // different kinds of pointers: -#[deriving(Clone, PartialEq, Eq, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash, Show)] pub enum PointerKind { OwnedPtr, BorrowedPtr(ty::BorrowKind, ty::Region), @@ -121,57 +119,45 @@ pub enum PointerKind { UnsafePtr(ast::Mutability) } -impl Copy for PointerKind {} - // We use the term "interior" to mean "something reachable from the // base without a pointer dereference", e.g. a field -#[deriving(Clone, PartialEq, Eq, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash, Show)] pub enum InteriorKind { InteriorField(FieldName), InteriorElement(ElementKind), } -impl Copy for InteriorKind {} - -#[deriving(Clone, PartialEq, Eq, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash, Show)] pub enum FieldName { NamedField(ast::Name), PositionalField(uint) } -impl Copy for FieldName {} - -#[deriving(Clone, PartialEq, Eq, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash, Show)] pub enum ElementKind { VecElement, OtherElement, } -impl Copy for ElementKind {} - -#[deriving(Clone, PartialEq, Eq, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash, Show)] pub enum MutabilityCategory { McImmutable, // Immutable. McDeclared, // Directly declared as mutable. McInherited, // Inherited from the fact that owner is mutable. } -impl Copy for MutabilityCategory {} - // A note about the provenance of a `cmt`. This is used for // special-case handling of upvars such as mutability inference. // Upvar categorization can generate a variable number of nested // derefs. The note allows detecting them without deep pattern // matching on the categorization. -#[deriving(Clone, PartialEq, Show)] +#[deriving(Clone, Copy, PartialEq, Show)] pub enum Note { NoteClosureEnv(ty::UpvarId), // Deref through closure env NoteUpvarRef(ty::UpvarId), // Deref through by-ref upvar NoteNone // Nothing special } -impl Copy for Note {} - // `cmt`: "Category, Mutability, and Type". // // a complete categorization of a value indicating where it originated @@ -200,13 +186,12 @@ pub type cmt<'tcx> = Rc<cmt_<'tcx>>; // We pun on *T to mean both actual deref of a ptr as well // as accessing of components: +#[deriving(Copy)] pub enum deref_kind { deref_ptr(PointerKind), deref_interior(InteriorKind), } -impl Copy for deref_kind {} - // Categorizes a derefable type. Note that we include vectors and strings as // derefable (we model an index as the combination of a deref and then a // pointer adjustment). @@ -1394,13 +1379,13 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { } } +#[deriving(Copy)] pub enum InteriorSafety { InteriorUnsafe, InteriorSafe } -impl Copy for InteriorSafety {} - +#[deriving(Copy)] pub enum AliasableReason { AliasableBorrowed, AliasableClosure(ast::NodeId), // Aliasable due to capture Fn closure env @@ -1409,8 +1394,6 @@ pub enum AliasableReason { AliasableStaticMut(InteriorSafety), } -impl Copy for AliasableReason {} - impl<'tcx> cmt_<'tcx> { pub fn guarantor(&self) -> cmt<'tcx> { //! Returns `self` after stripping away any owned pointer derefs or diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 390729df012..e0d5a3a50e6 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -36,13 +36,11 @@ use syntax::visit::{Visitor, FnKind}; /// placate the same deriving in `ty::FreeRegion`, but we may want to /// actually attach a more meaningful ordering to scopes than the one /// generated via deriving here. -#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Encodable, Decodable, Show)] +#[deriving(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash, Encodable, Decodable, Show)] pub enum CodeExtent { Misc(ast::NodeId) } -impl Copy for CodeExtent {} - impl CodeExtent { /// Creates a scope that represents the dynamic extent associated /// with `node_id`. @@ -117,6 +115,7 @@ pub struct RegionMaps { terminating_scopes: RefCell<FnvHashSet<CodeExtent>>, } +#[deriving(Copy)] pub struct Context { var_parent: Option<ast::NodeId>, @@ -124,8 +123,6 @@ pub struct Context { parent: Option<ast::NodeId>, } -impl Copy for Context {} - struct RegionResolutionVisitor<'a> { sess: &'a Session, diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 734453db693..e1e376c537c 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -89,13 +89,12 @@ use std::uint; // Definition mapping pub type DefMap = RefCell<NodeMap<Def>>; +#[deriving(Copy)] struct binding_info { span: Span, binding_mode: BindingMode, } -impl Copy for binding_info {} - // Map from the name in a pattern to its binding mode. type BindingMap = HashMap<Name,binding_info>; @@ -118,7 +117,7 @@ pub type ExternalExports = DefIdSet; // FIXME: dox pub type LastPrivateMap = NodeMap<LastPrivate>; -#[deriving(Show)] +#[deriving(Copy, Show)] pub enum LastPrivate { LastMod(PrivateDep), // `use` directives (imports) can refer to two separate definitions in the @@ -132,25 +131,19 @@ pub enum LastPrivate { type_used: ImportUse}, } -impl Copy for LastPrivate {} - -#[deriving(Show)] +#[deriving(Copy, Show)] pub enum PrivateDep { AllPublic, DependsOn(DefId), } -impl Copy for PrivateDep {} - // How an import is used. -#[deriving(PartialEq, Show)] +#[deriving(Copy, PartialEq, Show)] pub enum ImportUse { Unused, // The import is not used. Used, // The import is used. } -impl Copy for ImportUse {} - impl LastPrivate { fn or(self, other: LastPrivate) -> LastPrivate { match (self, other) { @@ -160,24 +153,20 @@ impl LastPrivate { } } -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] enum PatternBindingMode { RefutableMode, LocalIrrefutableMode, ArgumentIrrefutableMode, } -impl Copy for PatternBindingMode {} - -#[deriving(PartialEq, Eq, Hash, Show)] +#[deriving(Copy, PartialEq, Eq, Hash, Show)] enum Namespace { TypeNS, ValueNS } -impl Copy for Namespace {} - -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] enum NamespaceError { NoError, ModuleError, @@ -185,8 +174,6 @@ enum NamespaceError { ValueError } -impl Copy for NamespaceError {} - /// A NamespaceResult represents the result of resolving an import in /// a particular namespace. The result is either definitely-resolved, /// definitely- unresolved, or unknown. @@ -247,13 +234,12 @@ impl<'a, 'v> Visitor<'v> for Resolver<'a> { } /// Contains data for specific types of import directives. +#[deriving(Copy)] enum ImportDirectiveSubclass { SingleImport(Name /* target */, Name /* source */), GlobImport } -impl Copy for ImportDirectiveSubclass {} - /// The context that we thread through while building the reduced graph. #[deriving(Clone)] enum ReducedGraphParent { @@ -293,6 +279,7 @@ enum FallbackSuggestion { TraitMethod(String), } +#[deriving(Copy)] enum TypeParameters<'a> { NoTypeParameters, HasTypeParameters( @@ -310,11 +297,9 @@ enum TypeParameters<'a> { RibKind) } -impl<'a> Copy for TypeParameters<'a> {} - // The rib kind controls the translation of local // definitions (`DefLocal`) to upvars (`DefUpvar`). -#[deriving(Show)] +#[deriving(Copy, Show)] enum RibKind { // No translation needs to be applied. NormalRibKind, @@ -337,38 +322,31 @@ enum RibKind { ConstantItemRibKind } -impl Copy for RibKind {} - // Methods can be required or provided. RequiredMethod methods only occur in traits. -#[deriving(Show)] +#[deriving(Copy, Show)] enum MethodSort { RequiredMethod, ProvidedMethod(NodeId) } -impl Copy for MethodSort {} - +#[deriving(Copy)] enum UseLexicalScopeFlag { DontUseLexicalScope, UseLexicalScope } -impl Copy for UseLexicalScopeFlag {} - enum ModulePrefixResult { NoPrefixFound, PrefixFound(Rc<Module>, uint) } -#[deriving(Clone, Eq, PartialEq)] +#[deriving(Clone, Copy, Eq, PartialEq)] pub enum TraitItemKind { NonstaticMethodTraitItemKind, StaticMethodTraitItemKind, TypeTraitItemKind, } -impl Copy for TraitItemKind {} - impl TraitItemKind { pub fn from_explicit_self_category(explicit_self_category: ExplicitSelfCategory) @@ -381,7 +359,7 @@ impl TraitItemKind { } } -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] enum NameSearchType { /// We're doing a name search in order to resolve a `use` directive. ImportSearch, @@ -391,19 +369,16 @@ enum NameSearchType { PathSearch, } -impl Copy for NameSearchType {} - +#[deriving(Copy)] enum BareIdentifierPatternResolution { FoundStructOrEnumVariant(Def, LastPrivate), FoundConst(Def, LastPrivate), BareIdentifierPatternUnresolved } -impl Copy for BareIdentifierPatternResolution {} - // Specifies how duplicates should be handled when adding a child item if // another item exists with the same name in some namespace. -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] enum DuplicateCheckingMode { ForbidDuplicateModules, ForbidDuplicateTypesAndModules, @@ -412,8 +387,6 @@ enum DuplicateCheckingMode { OverwriteDuplicates } -impl Copy for DuplicateCheckingMode {} - /// One local scope. #[deriving(Show)] struct Rib { @@ -543,7 +516,7 @@ enum ParentLink { } /// The type of module this is. -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] enum ModuleKind { NormalModuleKind, TraitModuleKind, @@ -552,8 +525,6 @@ enum ModuleKind { AnonymousModuleKind, } -impl Copy for ModuleKind {} - /// One node in the tree of modules. struct Module { parent_link: ParentLink, @@ -645,15 +616,13 @@ struct TypeNsDef { } // Records a possibly-private value definition. -#[deriving(Clone, Show)] +#[deriving(Clone, Copy, Show)] struct ValueNsDef { modifiers: DefModifiers, // see note in ImportResolution about how to use this def: Def, value_span: Option<Span>, } -impl Copy for ValueNsDef {} - // Records the definitions (at most one for each namespace) that a name is // bound to. struct NameBindings { @@ -662,6 +631,7 @@ struct NameBindings { } /// Ways in which a trait can be referenced +#[deriving(Copy)] enum TraitReferenceType { TraitImplementation, // impl SomeTrait for T { ... } TraitDerivation, // trait T : SomeTrait { ... } @@ -670,8 +640,6 @@ enum TraitReferenceType { TraitQPath, // <T as SomeTrait>:: } -impl Copy for TraitReferenceType {} - impl NameBindings { fn new() -> NameBindings { NameBindings { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 1923142be9e..2202137d149 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -34,7 +34,7 @@ use syntax::visit; use syntax::visit::Visitor; use util::nodemap::NodeMap; -#[deriving(Clone, PartialEq, Eq, Hash, Encodable, Decodable, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Show)] pub enum DefRegion { DefStaticRegion, DefEarlyBoundRegion(/* space */ subst::ParamSpace, @@ -46,8 +46,6 @@ pub enum DefRegion { /* lifetime decl */ ast::NodeId), } -impl Copy for DefRegion {} - // maps the id of each lifetime reference to the lifetime decl // that it corresponds to pub type NamedRegionMap = NodeMap<DefRegion>; @@ -108,7 +106,8 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { ast::ItemTy(_, ref generics) | ast::ItemEnum(_, ref generics) | ast::ItemStruct(_, ref generics) | - ast::ItemTrait(_, ref generics, _, _, _) => { + ast::ItemTrait(_, ref generics, _, _, _) | + ast::ItemImpl(_, ref generics, _, _, _) => { // These kinds of items have only early bound lifetime parameters. let lifetimes = &generics.lifetimes; let early_scope = EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE); @@ -117,12 +116,6 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { visit::walk_item(this, item); }); } - ast::ItemImpl(_, ref generics, _, _, _) => { - // Impls have both early- and late-bound lifetimes. - this.visit_early_late(subst::TypeSpace, generics, |this| { - visit::walk_item(this, item); - }) - } } }); } diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 1cf25cd1dc8..30a47ff9132 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -187,7 +187,7 @@ impl RegionSubsts { /////////////////////////////////////////////////////////////////////////// // ParamSpace -#[deriving(PartialOrd, Ord, PartialEq, Eq, +#[deriving(Copy, PartialOrd, Ord, PartialEq, Eq, Clone, Hash, Encodable, Decodable, Show)] pub enum ParamSpace { TypeSpace, // Type parameters attached to a type definition, trait, or impl @@ -196,8 +196,6 @@ pub enum ParamSpace { FnSpace, // Type parameters attached to a method or fn } -impl Copy for ParamSpace {} - impl ParamSpace { pub fn all() -> [ParamSpace, ..4] { [TypeSpace, SelfSpace, AssocSpace, FnSpace] diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 822979c8601..9804f6d222a 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -17,7 +17,8 @@ use super::util; use middle::subst; use middle::subst::Subst; use middle::ty::{mod, Ty}; -use middle::infer::{mod, InferCtxt}; +use middle::infer::InferCtxt; +use std::rc::Rc; use syntax::ast; use syntax::codemap::DUMMY_SP; use util::ppaux::Repr; @@ -37,18 +38,14 @@ pub fn impl_can_satisfy(infcx: &InferCtxt, let impl1_substs = util::fresh_substs_for_impl(infcx, DUMMY_SP, impl1_def_id); let impl1_trait_ref = - ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap() - .subst(infcx.tcx, &impl1_substs); - let impl1_trait_ref = - infcx.replace_late_bound_regions_with_fresh_var(DUMMY_SP, - infer::FnCall, - &impl1_trait_ref).0; + (*ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap()).subst(infcx.tcx, &impl1_substs); // Determine whether `impl2` can provide an implementation for those // same types. let param_env = ty::empty_parameter_environment(); let mut selcx = SelectionContext::intercrate(infcx, ¶m_env, infcx.tcx); - let obligation = Obligation::new(ObligationCause::dummy(), impl1_trait_ref); + let obligation = Obligation::new(ObligationCause::dummy(), + Rc::new(ty::Binder(impl1_trait_ref))); debug!("impl_can_satisfy(obligation={})", obligation.repr(infcx.tcx)); selcx.evaluate_impl(impl2_def_id, &obligation) } @@ -143,7 +140,7 @@ pub fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { } ty::ty_trait(ref tt) => { - tt.principal.def_id.krate == ast::LOCAL_CRATE + tt.principal.def_id().krate == ast::LOCAL_CRATE } // Type parameters may be bound to types that are not local to diff --git a/src/librustc/middle/traits/doc.rs b/src/librustc/middle/traits/doc.rs index 62246b77ee9..80697cb3a41 100644 --- a/src/librustc/middle/traits/doc.rs +++ b/src/librustc/middle/traits/doc.rs @@ -8,399 +8,513 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! # TRAIT RESOLUTION -//! -//! This document describes the general process and points out some non-obvious -//! things. -//! -//! ## Major concepts -//! -//! Trait resolution is the process of pairing up an impl with each -//! reference to a trait. So, for example, if there is a generic function like: -//! -//! fn clone_slice<T:Clone>(x: &[T]) -> Vec<T> { ... } -//! -//! and then a call to that function: -//! -//! let v: Vec<int> = clone_slice([1, 2, 3].as_slice()) -//! -//! it is the job of trait resolution to figure out (in which case) -//! whether there exists an impl of `int : Clone` -//! -//! Note that in some cases, like generic functions, we may not be able to -//! find a specific impl, but we can figure out that the caller must -//! provide an impl. To see what I mean, consider the body of `clone_slice`: -//! -//! fn clone_slice<T:Clone>(x: &[T]) -> Vec<T> { -//! let mut v = Vec::new(); -//! for e in x.iter() { -//! v.push((*e).clone()); // (*) -//! } -//! } -//! -//! The line marked `(*)` is only legal if `T` (the type of `*e`) -//! implements the `Clone` trait. Naturally, since we don't know what `T` -//! is, we can't find the specific impl; but based on the bound `T:Clone`, -//! we can say that there exists an impl which the caller must provide. -//! -//! We use the term *obligation* to refer to a trait reference in need of -//! an impl. -//! -//! ## Overview -//! -//! Trait resolution consists of three major parts: -//! -//! - SELECTION: Deciding how to resolve a specific obligation. For -//! example, selection might decide that a specific obligation can be -//! resolved by employing an impl which matches the self type, or by -//! using a parameter bound. In the case of an impl, Selecting one -//! obligation can create *nested obligations* because of where clauses -//! on the impl itself. It may also require evaluating those nested -//! obligations to resolve ambiguities. -//! -//! - FULFILLMENT: The fulfillment code is what tracks that obligations -//! are completely fulfilled. Basically it is a worklist of obligations -//! to be selected: once selection is successful, the obligation is -//! removed from the worklist and any nested obligations are enqueued. -//! -//! - COHERENCE: The coherence checks are intended to ensure that there -//! are never overlapping impls, where two impls could be used with -//! equal precedence. -//! -//! ## Selection -//! -//! Selection is the process of deciding whether an obligation can be -//! resolved and, if so, how it is to be resolved (via impl, where clause, etc). -//! The main interface is the `select()` function, which takes an obligation -//! and returns a `SelectionResult`. There are three possible outcomes: -//! -//! - `Ok(Some(selection))` -- yes, the obligation can be resolved, and -//! `selection` indicates how. If the impl was resolved via an impl, -//! then `selection` may also indicate nested obligations that are required -//! by the impl. -//! -//! - `Ok(None)` -- we are not yet sure whether the obligation can be -//! resolved or not. This happens most commonly when the obligation -//! contains unbound type variables. -//! -//! - `Err(err)` -- the obligation definitely cannot be resolved due to a -//! type error, or because there are no impls that could possibly apply, -//! etc. -//! -//! The basic algorithm for selection is broken into two big phases: -//! candidate assembly and confirmation. -//! -//! ### Candidate assembly -//! -//! Searches for impls/where-clauses/etc that might -//! possibly be used to satisfy the obligation. Each of those is called -//! a candidate. To avoid ambiguity, we want to find exactly one -//! candidate that is definitively applicable. In some cases, we may not -//! know whether an impl/where-clause applies or not -- this occurs when -//! the obligation contains unbound inference variables. -//! -//! The basic idea for candidate assembly is to do a first pass in which -//! we identify all possible candidates. During this pass, all that we do -//! is try and unify the type parameters. (In particular, we ignore any -//! nested where clauses.) Presuming that this unification succeeds, the -//! impl is added as a candidate. -//! -//! Once this first pass is done, we can examine the set of candidates. If -//! it is a singleton set, then we are done: this is the only impl in -//! scope that could possibly apply. Otherwise, we can winnow down the set -//! of candidates by using where clauses and other conditions. If this -//! reduced set yields a single, unambiguous entry, we're good to go, -//! otherwise the result is considered ambiguous. -//! -//! #### The basic process: Inferring based on the impls we see -//! -//! This process is easier if we work through some examples. Consider -//! the following trait: -//! -//! ``` -//! trait Convert<Target> { -//! fn convert(&self) -> Target; -//! } -//! ``` -//! -//! This trait just has one method. It's about as simple as it gets. It -//! converts from the (implicit) `Self` type to the `Target` type. If we -//! wanted to permit conversion between `int` and `uint`, we might -//! implement `Convert` like so: -//! -//! ```rust -//! impl Convert<uint> for int { ... } // int -> uint -//! impl Convert<int> for uint { ... } // uint -> uint -//! ``` -//! -//! Now imagine there is some code like the following: -//! -//! ```rust -//! let x: int = ...; -//! let y = x.convert(); -//! ``` -//! -//! The call to convert will generate a trait reference `Convert<$Y> for -//! int`, where `$Y` is the type variable representing the type of -//! `y`. When we match this against the two impls we can see, we will find -//! that only one remains: `Convert<uint> for int`. Therefore, we can -//! select this impl, which will cause the type of `$Y` to be unified to -//! `uint`. (Note that while assembling candidates, we do the initial -//! unifications in a transaction, so that they don't affect one another.) -//! -//! There are tests to this effect in src/test/run-pass: -//! -//! traits-multidispatch-infer-convert-source-and-target.rs -//! traits-multidispatch-infer-convert-target.rs -//! -//! #### Winnowing: Resolving ambiguities -//! -//! But what happens if there are multiple impls where all the types -//! unify? Consider this example: -//! -//! ```rust -//! trait Get { -//! fn get(&self) -> Self; -//! } -//! -//! impl<T:Copy> Get for T { -//! fn get(&self) -> T { *self } -//! } -//! -//! impl<T:Get> Get for Box<T> { -//! fn get(&self) -> Box<T> { box get_it(&**self) } -//! } -//! ``` -//! -//! What happens when we invoke `get_it(&box 1_u16)`, for example? In this -//! case, the `Self` type is `Box<u16>` -- that unifies with both impls, -//! because the first applies to all types, and the second to all -//! boxes. In the olden days we'd have called this ambiguous. But what we -//! do now is do a second *winnowing* pass that considers where clauses -//! and attempts to remove candidates -- in this case, the first impl only -//! applies if `Box<u16> : Copy`, which doesn't hold. After winnowing, -//! then, we are left with just one candidate, so we can proceed. There is -//! a test of this in `src/test/run-pass/traits-conditional-dispatch.rs`. -//! -//! #### Matching -//! -//! The subroutines that decide whether a particular impl/where-clause/etc -//! applies to a particular obligation. At the moment, this amounts to -//! unifying the self types, but in the future we may also recursively -//! consider some of the nested obligations, in the case of an impl. -//! -//! #### Lifetimes and selection -//! -//! Because of how that lifetime inference works, it is not possible to -//! give back immediate feedback as to whether a unification or subtype -//! relationship between lifetimes holds or not. Therefore, lifetime -//! matching is *not* considered during selection. This is reflected in -//! the fact that subregion assignment is infallible. This may yield -//! lifetime constraints that will later be found to be in error (in -//! contrast, the non-lifetime-constraints have already been checked -//! during selection and can never cause an error, though naturally they -//! may lead to other errors downstream). -//! -//! #### Where clauses -//! -//! Besides an impl, the other major way to resolve an obligation is via a -//! where clause. The selection process is always given a *parameter -//! environment* which contains a list of where clauses, which are -//! basically obligations that can assume are satisfiable. We will iterate -//! over that list and check whether our current obligation can be found -//! in that list, and if so it is considered satisfied. More precisely, we -//! want to check whether there is a where-clause obligation that is for -//! the same trait (or some subtrait) and for which the self types match, -//! using the definition of *matching* given above. -//! -//! Consider this simple example: -//! -//! trait A1 { ... } -//! trait A2 : A1 { ... } -//! -//! trait B { ... } -//! -//! fn foo<X:A2+B> { ... } -//! -//! Clearly we can use methods offered by `A1`, `A2`, or `B` within the -//! body of `foo`. In each case, that will incur an obligation like `X : -//! A1` or `X : A2`. The parameter environment will contain two -//! where-clauses, `X : A2` and `X : B`. For each obligation, then, we -//! search this list of where-clauses. To resolve an obligation `X:A1`, -//! we would note that `X:A2` implies that `X:A1`. -//! -//! ### Confirmation -//! -//! Confirmation unifies the output type parameters of the trait with the -//! values found in the obligation, possibly yielding a type error. If we -//! return to our example of the `Convert` trait from the previous -//! section, confirmation is where an error would be reported, because the -//! impl specified that `T` would be `uint`, but the obligation reported -//! `char`. Hence the result of selection would be an error. -//! -//! ### Selection during translation -//! -//! During type checking, we do not store the results of trait selection. -//! We simply wish to verify that trait selection will succeed. Then -//! later, at trans time, when we have all concrete types available, we -//! can repeat the trait selection. In this case, we do not consider any -//! where-clauses to be in scope. We know that therefore each resolution -//! will resolve to a particular impl. -//! -//! One interesting twist has to do with nested obligations. In general, in trans, -//! we only need to do a "shallow" selection for an obligation. That is, we wish to -//! identify which impl applies, but we do not (yet) need to decide how to select -//! any nested obligations. Nonetheless, we *do* currently do a complete resolution, -//! and that is because it can sometimes inform the results of type inference. That is, -//! we do not have the full substitutions in terms of the type varibales of the impl available -//! to us, so we must run trait selection to figure everything out. -//! -//! Here is an example: -//! -//! trait Foo { ... } -//! impl<U,T:Bar<U>> Foo for Vec<T> { ... } -//! -//! impl Bar<uint> for int { ... } -//! -//! After one shallow round of selection for an obligation like `Vec<int> -//! : Foo`, we would know which impl we want, and we would know that -//! `T=int`, but we do not know the type of `U`. We must select the -//! nested obligation `int : Bar<U>` to find out that `U=uint`. -//! -//! It would be good to only do *just as much* nested resolution as -//! necessary. Currently, though, we just do a full resolution. -//! -//! ## Method matching -//! -//! Method dispach follows a slightly different path than normal trait -//! selection. This is because it must account for the transformed self -//! type of the receiver and various other complications. The procedure is -//! described in `select.rs` in the "METHOD MATCHING" section. -//! -//! # Caching and subtle considerations therewith -//! -//! In general we attempt to cache the results of trait selection. This -//! is a somewhat complex process. Part of the reason for this is that we -//! want to be able to cache results even when all the types in the trait -//! reference are not fully known. In that case, it may happen that the -//! trait selection process is also influencing type variables, so we have -//! to be able to not only cache the *result* of the selection process, -//! but *replay* its effects on the type variables. -//! -//! ## An example -//! -//! The high-level idea of how the cache works is that we first replace -//! all unbound inference variables with skolemized versions. Therefore, -//! if we had a trait reference `uint : Foo<$1>`, where `$n` is an unbound -//! inference variable, we might replace it with `uint : Foo<%0>`, where -//! `%n` is a skolemized type. We would then look this up in the cache. -//! If we found a hit, the hit would tell us the immediate next step to -//! take in the selection process: i.e., apply impl #22, or apply where -//! clause `X : Foo<Y>`. Let's say in this case there is no hit. -//! Therefore, we search through impls and where clauses and so forth, and -//! we come to the conclusion that the only possible impl is this one, -//! with def-id 22: -//! -//! impl Foo<int> for uint { ... } // Impl #22 -//! -//! We would then record in the cache `uint : Foo<%0> ==> -//! ImplCandidate(22)`. Next we would confirm `ImplCandidate(22)`, which -//! would (as a side-effect) unify `$1` with `int`. -//! -//! Now, at some later time, we might come along and see a `uint : -//! Foo<$3>`. When skolemized, this would yield `uint : Foo<%0>`, just as -//! before, and hence the cache lookup would succeed, yielding -//! `ImplCandidate(22)`. We would confirm `ImplCandidate(22)` which would -//! (as a side-effect) unify `$3` with `int`. -//! -//! ## Where clauses and the local vs global cache -//! -//! One subtle interaction is that the results of trait lookup will vary -//! depending on what where clauses are in scope. Therefore, we actually -//! have *two* caches, a local and a global cache. The local cache is -//! attached to the `ParameterEnvironment` and the global cache attached -//! to the `tcx`. We use the local cache whenever the result might depend -//! on the where clauses that are in scope. The determination of which -//! cache to use is done by the method `pick_candidate_cache` in -//! `select.rs`. -//! -//! There are two cases where we currently use the local cache. The -//! current rules are probably more conservative than necessary. -//! -//! ### Trait references that involve parameter types -//! -//! The most obvious case where you need the local environment is -//! when the trait reference includes parameter types. For example, -//! consider the following function: -//! -//! impl<T> Vec<T> { -//! fn foo(x: T) -//! where T : Foo -//! { ... } -//! -//! fn bar(x: T) -//! { ... } -//! } -//! -//! If there is an obligation `T : Foo`, or `int : Bar<T>`, or whatever, -//! clearly the results from `foo` and `bar` are potentially different, -//! since the set of where clauses in scope are different. -//! -//! ### Trait references with unbound variables when where clauses are in scope -//! -//! There is another less obvious interaction which involves unbound variables -//! where *only* where clauses are in scope (no impls). This manifested as -//! issue #18209 (`run-pass/trait-cache-issue-18209.rs`). Consider -//! this snippet: -//! -//! ``` -//! pub trait Foo { -//! fn load_from() -> Box<Self>; -//! fn load() -> Box<Self> { -//! Foo::load_from() -//! } -//! } -//! ``` -//! -//! The default method will incur an obligation `$0 : Foo` from the call -//! to `load_from`. If there are no impls, this can be eagerly resolved to -//! `VtableParam(Self : Foo)` and cached. Because the trait reference -//! doesn't involve any parameters types (only the resolution does), this -//! result was stored in the global cache, causing later calls to -//! `Foo::load_from()` to get nonsense. -//! -//! To fix this, we always use the local cache if there are unbound -//! variables and where clauses in scope. This is more conservative than -//! necessary as far as I can tell. However, it still seems to be a simple -//! rule and I observe ~99% hit rate on rustc, so it doesn't seem to hurt -//! us in particular. -//! -//! Here is an example of the kind of subtle case that I would be worried -//! about with a more complex rule (although this particular case works -//! out ok). Imagine the trait reference doesn't directly reference a -//! where clause, but the where clause plays a role in the winnowing -//! phase. Something like this: -//! -//! ``` -//! pub trait Foo<T> { ... } -//! pub trait Bar { ... } -//! impl<U,T:Bar> Foo<U> for T { ... } // Impl A -//! impl Foo<char> for uint { ... } // Impl B -//! ``` -//! -//! Now, in some function, we have no where clauses in scope, and we have -//! an obligation `$1 : Foo<$0>`. We might then conclude that `$0=char` -//! and `$1=uint`: this is because for impl A to apply, `uint:Bar` would -//! have to hold, and we know it does not or else the coherence check -//! would have failed. So we might enter into our global cache: `$1 : -//! Foo<$0> => Impl B`. Then we come along in a different scope, where a -//! generic type `A` is around with the bound `A:Bar`. Now suddenly the -//! impl is viable. -//! -//! The flaw in this imaginary DOOMSDAY SCENARIO is that we would not -//! currently conclude that `$1 : Foo<$0>` implies that `$0 == uint` and -//! `$1 == char`, even though it is true that (absent type parameters) -//! there is no other type the user could enter. However, it is not -//! *completely* implausible that we *could* draw this conclusion in the -//! future; we wouldn't have to guess types, in particular, we could be -//! led by the impls. +/*! + +# TRAIT RESOLUTION + +This document describes the general process and points out some non-obvious +things. + +## Major concepts + +Trait resolution is the process of pairing up an impl with each +reference to a trait. So, for example, if there is a generic function like: + + fn clone_slice<T:Clone>(x: &[T]) -> Vec<T> { ... } + +and then a call to that function: + + let v: Vec<int> = clone_slice([1, 2, 3].as_slice()) + +it is the job of trait resolution to figure out (in which case) +whether there exists an impl of `int : Clone` + +Note that in some cases, like generic functions, we may not be able to +find a specific impl, but we can figure out that the caller must +provide an impl. To see what I mean, consider the body of `clone_slice`: + + fn clone_slice<T:Clone>(x: &[T]) -> Vec<T> { + let mut v = Vec::new(); + for e in x.iter() { + v.push((*e).clone()); // (*) + } + } + +The line marked `(*)` is only legal if `T` (the type of `*e`) +implements the `Clone` trait. Naturally, since we don't know what `T` +is, we can't find the specific impl; but based on the bound `T:Clone`, +we can say that there exists an impl which the caller must provide. + +We use the term *obligation* to refer to a trait reference in need of +an impl. + +## Overview + +Trait resolution consists of three major parts: + +- SELECTION: Deciding how to resolve a specific obligation. For + example, selection might decide that a specific obligation can be + resolved by employing an impl which matches the self type, or by + using a parameter bound. In the case of an impl, Selecting one + obligation can create *nested obligations* because of where clauses + on the impl itself. It may also require evaluating those nested + obligations to resolve ambiguities. + +- FULFILLMENT: The fulfillment code is what tracks that obligations + are completely fulfilled. Basically it is a worklist of obligations + to be selected: once selection is successful, the obligation is + removed from the worklist and any nested obligations are enqueued. + +- COHERENCE: The coherence checks are intended to ensure that there + are never overlapping impls, where two impls could be used with + equal precedence. + +## Selection + +Selection is the process of deciding whether an obligation can be +resolved and, if so, how it is to be resolved (via impl, where clause, etc). +The main interface is the `select()` function, which takes an obligation +and returns a `SelectionResult`. There are three possible outcomes: + +- `Ok(Some(selection))` -- yes, the obligation can be resolved, and + `selection` indicates how. If the impl was resolved via an impl, + then `selection` may also indicate nested obligations that are required + by the impl. + +- `Ok(None)` -- we are not yet sure whether the obligation can be + resolved or not. This happens most commonly when the obligation + contains unbound type variables. + +- `Err(err)` -- the obligation definitely cannot be resolved due to a + type error, or because there are no impls that could possibly apply, + etc. + +The basic algorithm for selection is broken into two big phases: +candidate assembly and confirmation. + +### Candidate assembly + +Searches for impls/where-clauses/etc that might +possibly be used to satisfy the obligation. Each of those is called +a candidate. To avoid ambiguity, we want to find exactly one +candidate that is definitively applicable. In some cases, we may not +know whether an impl/where-clause applies or not -- this occurs when +the obligation contains unbound inference variables. + +The basic idea for candidate assembly is to do a first pass in which +we identify all possible candidates. During this pass, all that we do +is try and unify the type parameters. (In particular, we ignore any +nested where clauses.) Presuming that this unification succeeds, the +impl is added as a candidate. + +Once this first pass is done, we can examine the set of candidates. If +it is a singleton set, then we are done: this is the only impl in +scope that could possibly apply. Otherwise, we can winnow down the set +of candidates by using where clauses and other conditions. If this +reduced set yields a single, unambiguous entry, we're good to go, +otherwise the result is considered ambiguous. + +#### The basic process: Inferring based on the impls we see + +This process is easier if we work through some examples. Consider +the following trait: + +``` +trait Convert<Target> { + fn convert(&self) -> Target; +} +``` + +This trait just has one method. It's about as simple as it gets. It +converts from the (implicit) `Self` type to the `Target` type. If we +wanted to permit conversion between `int` and `uint`, we might +implement `Convert` like so: + +```rust +impl Convert<uint> for int { ... } // int -> uint +impl Convert<int> for uint { ... } // uint -> uint +``` + +Now imagine there is some code like the following: + +```rust +let x: int = ...; +let y = x.convert(); +``` + +The call to convert will generate a trait reference `Convert<$Y> for +int`, where `$Y` is the type variable representing the type of +`y`. When we match this against the two impls we can see, we will find +that only one remains: `Convert<uint> for int`. Therefore, we can +select this impl, which will cause the type of `$Y` to be unified to +`uint`. (Note that while assembling candidates, we do the initial +unifications in a transaction, so that they don't affect one another.) + +There are tests to this effect in src/test/run-pass: + + traits-multidispatch-infer-convert-source-and-target.rs + traits-multidispatch-infer-convert-target.rs + +#### Winnowing: Resolving ambiguities + +But what happens if there are multiple impls where all the types +unify? Consider this example: + +```rust +trait Get { + fn get(&self) -> Self; +} + +impl<T:Copy> Get for T { + fn get(&self) -> T { *self } +} + +impl<T:Get> Get for Box<T> { + fn get(&self) -> Box<T> { box get_it(&**self) } +} +``` + +What happens when we invoke `get_it(&box 1_u16)`, for example? In this +case, the `Self` type is `Box<u16>` -- that unifies with both impls, +because the first applies to all types, and the second to all +boxes. In the olden days we'd have called this ambiguous. But what we +do now is do a second *winnowing* pass that considers where clauses +and attempts to remove candidates -- in this case, the first impl only +applies if `Box<u16> : Copy`, which doesn't hold. After winnowing, +then, we are left with just one candidate, so we can proceed. There is +a test of this in `src/test/run-pass/traits-conditional-dispatch.rs`. + +#### Matching + +The subroutines that decide whether a particular impl/where-clause/etc +applies to a particular obligation. At the moment, this amounts to +unifying the self types, but in the future we may also recursively +consider some of the nested obligations, in the case of an impl. + +#### Lifetimes and selection + +Because of how that lifetime inference works, it is not possible to +give back immediate feedback as to whether a unification or subtype +relationship between lifetimes holds or not. Therefore, lifetime +matching is *not* considered during selection. This is reflected in +the fact that subregion assignment is infallible. This may yield +lifetime constraints that will later be found to be in error (in +contrast, the non-lifetime-constraints have already been checked +during selection and can never cause an error, though naturally they +may lead to other errors downstream). + +#### Where clauses + +Besides an impl, the other major way to resolve an obligation is via a +where clause. The selection process is always given a *parameter +environment* which contains a list of where clauses, which are +basically obligations that can assume are satisfiable. We will iterate +over that list and check whether our current obligation can be found +in that list, and if so it is considered satisfied. More precisely, we +want to check whether there is a where-clause obligation that is for +the same trait (or some subtrait) and for which the self types match, +using the definition of *matching* given above. + +Consider this simple example: + + trait A1 { ... } + trait A2 : A1 { ... } + + trait B { ... } + + fn foo<X:A2+B> { ... } + +Clearly we can use methods offered by `A1`, `A2`, or `B` within the +body of `foo`. In each case, that will incur an obligation like `X : +A1` or `X : A2`. The parameter environment will contain two +where-clauses, `X : A2` and `X : B`. For each obligation, then, we +search this list of where-clauses. To resolve an obligation `X:A1`, +we would note that `X:A2` implies that `X:A1`. + +### Confirmation + +Confirmation unifies the output type parameters of the trait with the +values found in the obligation, possibly yielding a type error. If we +return to our example of the `Convert` trait from the previous +section, confirmation is where an error would be reported, because the +impl specified that `T` would be `uint`, but the obligation reported +`char`. Hence the result of selection would be an error. + +### Selection during translation + +During type checking, we do not store the results of trait selection. +We simply wish to verify that trait selection will succeed. Then +later, at trans time, when we have all concrete types available, we +can repeat the trait selection. In this case, we do not consider any +where-clauses to be in scope. We know that therefore each resolution +will resolve to a particular impl. + +One interesting twist has to do with nested obligations. In general, in trans, +we only need to do a "shallow" selection for an obligation. That is, we wish to +identify which impl applies, but we do not (yet) need to decide how to select +any nested obligations. Nonetheless, we *do* currently do a complete resolution, +and that is because it can sometimes inform the results of type inference. That is, +we do not have the full substitutions in terms of the type varibales of the impl available +to us, so we must run trait selection to figure everything out. + +Here is an example: + + trait Foo { ... } + impl<U,T:Bar<U>> Foo for Vec<T> { ... } + + impl Bar<uint> for int { ... } + +After one shallow round of selection for an obligation like `Vec<int> +: Foo`, we would know which impl we want, and we would know that +`T=int`, but we do not know the type of `U`. We must select the +nested obligation `int : Bar<U>` to find out that `U=uint`. + +It would be good to only do *just as much* nested resolution as +necessary. Currently, though, we just do a full resolution. + +# Higher-ranked trait bounds + +One of the more subtle concepts at work are *higher-ranked trait +bounds*. An example of such a bound is `for<'a> MyTrait<&'a int>`. +Let's walk through how selection on higher-ranked trait references +works. + +## Basic matching and skolemization leaks + +Let's walk through the test `compile-fail/hrtb-just-for-static.rs` to see +how it works. The test starts with the trait `Foo`: + +```rust +trait Foo<X> { + fn foo(&self, x: X) { } +} +``` + +Let's say we have a function `want_hrtb` that wants a type which +implements `Foo<&'a int>` for any `'a`: + +```rust +fn want_hrtb<T>() where T : for<'a> Foo<&'a int> { ... } +``` + +Now we have a struct `AnyInt` that implements `Foo<&'a int>` for any +`'a`: + +```rust +struct AnyInt; +impl<'a> Foo<&'a int> for AnyInt { } +``` + +And the question is, does `AnyInt : for<'a> Foo<&'a int>`? We want the +answer to be yes. The algorithm for figuring it out is closely related +to the subtyping for higher-ranked types (which is described in +`middle::infer::higher_ranked::doc`, but also in a [paper by SPJ] that +I recommend you read). + +1. Skolemize the obligation. +2. Match the impl against the skolemized obligation. +3. Check for skolemization leaks. + +[paper by SPJ]: http://research.microsoft.com/en-us/um/people/simonpj/papers/higher-rank/ + +So let's work through our example. The first thing we would do is to +skolemize the obligation, yielding `AnyInt : Foo<&'0 int>` (here `'0` +represents skolemized region #0). Note that now have no quantifiers; +in terms of the compiler type, this changes from a `ty::PolyTraitRef` +to a `TraitRef`. We would then create the `TraitRef` from the impl, +using fresh variables for it's bound regions (and thus getting +`Foo<&'$a int>`, where `'$a` is the inference variable for `'a`). Next +we relate the two trait refs, yielding a graph with the constraint +that `'0 == '$a`. Finally, we check for skolemization "leaks" -- a +leak is basically any attempt to relate a skolemized region to another +skolemized region, or to any region that pre-existed the impl match. +The leak check is done by searching from the skolemized region to find +the set of regions that it is related to in any way. This is called +the "taint" set. To pass the check, that set must consist *solely* of +itself and region variables from the impl. If the taint set includes +any other region, then the match is a failure. In this case, the taint +set for `'0` is `{'0, '$a}`, and hence the check will succeed. + +Let's consider a failure case. Imagine we also have a struct + +```rust +struct StaticInt; +impl Foo<&'static int> for StaticInt; +``` + +We want the obligation `StaticInt : for<'a> Foo<&'a int>` to be +considered unsatisfied. The check begins just as before. `'a` is +skolemized to `'0` and the impl trait reference is instantiated to +`Foo<&'static int>`. When we relate those two, we get a constraint +like `'static == '0`. This means that the taint set for `'0` is `{'0, +'static}`, which fails the leak check. + +## Higher-ranked trait obligations + +Once the basic matching is done, we get to another interesting topic: +how to deal with impl obligations. I'll work through a simple example +here. Imagine we have the traits `Foo` and `Bar` and an associated impl: + +``` +trait Foo<X> { + fn foo(&self, x: X) { } +} + +trait Bar<X> { + fn bar(&self, x: X) { } +} + +impl<X,F> Foo<X> for F + where F : Bar<X> +{ +} +``` + +Now let's say we have a obligation `for<'a> Foo<&'a int>` and we match +this impl. What obligation is generated as a result? We want to get +`for<'a> Bar<&'a int>`, but how does that happen? + +After the matching, we are in a position where we have a skolemized +substitution like `X => &'0 int`. If we apply this substitution to the +impl obligations, we get `F : Bar<&'0 int>`. Obviously this is not +directly usable because the skolemized region `'0` cannot leak out of +our computation. + +What we do is to create an inverse mapping from the taint set of `'0` +back to the original bound region (`'a`, here) that `'0` resulted +from. (This is done in `higher_ranked::plug_leaks`). We know that the +leak check passed, so this taint set consists solely of the skolemized +region itself plus various intermediate region variables. We then walk +the trait-reference and convert every region in that taint set back to +a late-bound region, so in this case we'd wind up with `for<'a> F : +Bar<&'a int>`. + +# Caching and subtle considerations therewith + +In general we attempt to cache the results of trait selection. This +is a somewhat complex process. Part of the reason for this is that we +want to be able to cache results even when all the types in the trait +reference are not fully known. In that case, it may happen that the +trait selection process is also influencing type variables, so we have +to be able to not only cache the *result* of the selection process, +but *replay* its effects on the type variables. + +## An example + +The high-level idea of how the cache works is that we first replace +all unbound inference variables with skolemized versions. Therefore, +if we had a trait reference `uint : Foo<$1>`, where `$n` is an unbound +inference variable, we might replace it with `uint : Foo<%0>`, where +`%n` is a skolemized type. We would then look this up in the cache. +If we found a hit, the hit would tell us the immediate next step to +take in the selection process: i.e., apply impl #22, or apply where +clause `X : Foo<Y>`. Let's say in this case there is no hit. +Therefore, we search through impls and where clauses and so forth, and +we come to the conclusion that the only possible impl is this one, +with def-id 22: + + impl Foo<int> for uint { ... } // Impl #22 + +We would then record in the cache `uint : Foo<%0> ==> +ImplCandidate(22)`. Next we would confirm `ImplCandidate(22)`, which +would (as a side-effect) unify `$1` with `int`. + +Now, at some later time, we might come along and see a `uint : +Foo<$3>`. When skolemized, this would yield `uint : Foo<%0>`, just as +before, and hence the cache lookup would succeed, yielding +`ImplCandidate(22)`. We would confirm `ImplCandidate(22)` which would +(as a side-effect) unify `$3` with `int`. + +## Where clauses and the local vs global cache + +One subtle interaction is that the results of trait lookup will vary +depending on what where clauses are in scope. Therefore, we actually +have *two* caches, a local and a global cache. The local cache is +attached to the `ParameterEnvironment` and the global cache attached +to the `tcx`. We use the local cache whenever the result might depend +on the where clauses that are in scope. The determination of which +cache to use is done by the method `pick_candidate_cache` in +`select.rs`. + +There are two cases where we currently use the local cache. The +current rules are probably more conservative than necessary. + +### Trait references that involve parameter types + +The most obvious case where you need the local environment is +when the trait reference includes parameter types. For example, +consider the following function: + + impl<T> Vec<T> { + fn foo(x: T) + where T : Foo + { ... } + + fn bar(x: T) + { ... } + } + +If there is an obligation `T : Foo`, or `int : Bar<T>`, or whatever, +clearly the results from `foo` and `bar` are potentially different, +since the set of where clauses in scope are different. + +### Trait references with unbound variables when where clauses are in scope + +There is another less obvious interaction which involves unbound variables +where *only* where clauses are in scope (no impls). This manifested as +issue #18209 (`run-pass/trait-cache-issue-18209.rs`). Consider +this snippet: + +``` +pub trait Foo { + fn load_from() -> Box<Self>; + fn load() -> Box<Self> { + Foo::load_from() + } +} +``` + +The default method will incur an obligation `$0 : Foo` from the call +to `load_from`. If there are no impls, this can be eagerly resolved to +`VtableParam(Self : Foo)` and cached. Because the trait reference +doesn't involve any parameters types (only the resolution does), this +result was stored in the global cache, causing later calls to +`Foo::load_from()` to get nonsense. + +To fix this, we always use the local cache if there are unbound +variables and where clauses in scope. This is more conservative than +necessary as far as I can tell. However, it still seems to be a simple +rule and I observe ~99% hit rate on rustc, so it doesn't seem to hurt +us in particular. + +Here is an example of the kind of subtle case that I would be worried +about with a more complex rule (although this particular case works +out ok). Imagine the trait reference doesn't directly reference a +where clause, but the where clause plays a role in the winnowing +phase. Something like this: + +``` +pub trait Foo<T> { ... } +pub trait Bar { ... } +impl<U,T:Bar> Foo<U> for T { ... } // Impl A +impl Foo<char> for uint { ... } // Impl B +``` + +Now, in some function, we have no where clauses in scope, and we have +an obligation `$1 : Foo<$0>`. We might then conclude that `$0=char` +and `$1=uint`: this is because for impl A to apply, `uint:Bar` would +have to hold, and we know it does not or else the coherence check +would have failed. So we might enter into our global cache: `$1 : +Foo<$0> => Impl B`. Then we come along in a different scope, where a +generic type `A` is around with the bound `A:Bar`. Now suddenly the +impl is viable. + +The flaw in this imaginary DOOMSDAY SCENARIO is that we would not +currently conclude that `$1 : Foo<$0>` implies that `$0 == uint` and +`$1 == char`, even though it is true that (absent type parameters) +there is no other type the user could enter. However, it is not +*completely* implausible that we *could* draw this conclusion in the +future; we wouldn't have to guess types, in particular, we could be +led by the impls. + +*/ diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 412c188f5f4..213d97b4b34 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use middle::infer::InferCtxt; use middle::mem_categorization::Typer; use middle::ty::{mod, Ty}; -use middle::infer::{mod, InferCtxt}; use std::collections::HashSet; use std::collections::hash_map::{Occupied, Vacant}; use std::default::Default; @@ -28,7 +28,7 @@ use super::ObligationCause; use super::PredicateObligation; use super::Selection; use super::select::SelectionContext; -use super::trait_ref_for_builtin_bound; +use super::poly_trait_ref_for_builtin_bound; use super::Unimplemented; /// The fulfillment context is used to drive trait resolution. It @@ -107,7 +107,7 @@ impl<'tcx> FulfillmentContext<'tcx> { builtin_bound: ty::BuiltinBound, cause: ObligationCause<'tcx>) { - match trait_ref_for_builtin_bound(tcx, builtin_bound, ty) { + match poly_trait_ref_for_builtin_bound(tcx, builtin_bound, ty) { Ok(trait_ref) => { self.register_trait_ref(tcx, trait_ref, cause); } @@ -117,7 +117,7 @@ impl<'tcx> FulfillmentContext<'tcx> { pub fn register_trait_ref<'a>(&mut self, tcx: &ty::ctxt<'tcx>, - trait_ref: Rc<ty::TraitRef<'tcx>>, + trait_ref: Rc<ty::PolyTraitRef<'tcx>>, cause: ObligationCause<'tcx>) { /*! @@ -329,30 +329,47 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, } } - ty::Predicate::Equate(a, b) => { - let origin = infer::EquatePredicate(predicate.cause.span); - match infer::mk_eqty(selcx.infcx(), false, origin, a, b) { - Ok(()) => { - true - } + ty::Predicate::Equate(ref binder) => { + match selcx.infcx().equality_predicate(predicate.cause.span, binder) { + Ok(()) => { } Err(_) => { errors.push( FulfillmentError::new( predicate.clone(), CodeSelectionError(Unimplemented))); - true } } + true } - ty::Predicate::RegionOutlives(r_a, r_b) => { - let origin = infer::RelateRegionParamBound(predicate.cause.span); - let () = infer::mk_subr(selcx.infcx(), origin, r_b, r_a); // `b : a` ==> `a <= b` + ty::Predicate::RegionOutlives(ref binder) => { + match selcx.infcx().region_outlives_predicate(predicate.cause.span, binder) { + Ok(()) => { } + Err(_) => { + errors.push( + FulfillmentError::new( + predicate.clone(), + CodeSelectionError(Unimplemented))); + } + } + true } - ty::Predicate::TypeOutlives(t_a, r_b) => { - register_region_obligation(tcx, t_a, r_b, predicate.cause, region_obligations); + ty::Predicate::TypeOutlives(ref binder) => { + // For now, we just check that there are no higher-ranked + // regions. If there are, we will call this obligation an + // error. Eventually we should be able to support some + // cases here, I imagine (e.g., `for<'a> int : 'a`). + if ty::count_late_bound_regions(selcx.tcx(), binder) != 0 { + errors.push( + FulfillmentError::new( + predicate.clone(), + CodeSelectionError(Unimplemented))); + } else { + let ty::OutlivesPredicate(t_a, r_b) = binder.0; + register_region_obligation(tcx, t_a, r_b, predicate.cause, region_obligations); + } true } } @@ -385,3 +402,4 @@ fn register_region_obligation<'tcx>(tcx: &ty::ctxt<'tcx>, } } + diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 936304c5eb4..3289acd0c2e 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -33,7 +33,7 @@ pub use self::util::supertraits; pub use self::util::Supertraits; pub use self::util::search_trait_and_supertraits_from_bound; pub use self::util::transitive_bounds; -pub use self::util::trait_ref_for_builtin_bound; +pub use self::util::poly_trait_ref_for_builtin_bound; mod coherence; mod fulfill; @@ -54,7 +54,7 @@ pub struct Obligation<'tcx, T> { } pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; -pub type TraitObligation<'tcx> = Obligation<'tcx, Rc<ty::TraitRef<'tcx>>>; +pub type TraitObligation<'tcx> = Obligation<'tcx, Rc<ty::PolyTraitRef<'tcx>>>; /// Why did we incur this obligation? Used for error reporting. #[deriving(Copy, Clone)] @@ -115,7 +115,9 @@ pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; pub enum SelectionError<'tcx> { Unimplemented, Overflow, - OutputTypeParameterMismatch(Rc<ty::TraitRef<'tcx>>, Rc<ty::TraitRef<'tcx>>, ty::type_err<'tcx>), + OutputTypeParameterMismatch(Rc<ty::PolyTraitRef<'tcx>>, + Rc<ty::PolyTraitRef<'tcx>>, + ty::type_err<'tcx>), } pub struct FulfillmentError<'tcx> { @@ -226,7 +228,7 @@ pub struct VtableBuiltinData<N> { #[deriving(PartialEq,Eq,Clone)] pub struct VtableParamData<'tcx> { // In the above example, this would `Eq` - pub bound: Rc<ty::TraitRef<'tcx>>, + pub bound: Rc<ty::PolyTraitRef<'tcx>>, } /// True if neither the trait nor self type is local. Note that `impl_def_id` must refer to an impl @@ -278,7 +280,7 @@ impl<'tcx,O> Obligation<'tcx,O> { } } -impl<'tcx> Obligation<'tcx,Rc<ty::TraitRef<'tcx>>> { +impl<'tcx> TraitObligation<'tcx> { pub fn self_ty(&self) -> Ty<'tcx> { self.trait_ref.self_ty() } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index f551ff06165..8ba28b61006 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -28,9 +28,9 @@ use super::{util}; use middle::fast_reject; use middle::mem_categorization::Typer; use middle::subst::{Subst, Substs, VecPerParamSpace}; -use middle::ty::{mod, Ty}; +use middle::ty::{mod, AsPredicate, RegionEscape, Ty}; use middle::infer; -use middle::infer::{InferCtxt, TypeSkolemizer}; +use middle::infer::{InferCtxt, TypeFreshener}; use middle::ty_fold::TypeFoldable; use std::cell::RefCell; use std::collections::hash_map::HashMap; @@ -44,12 +44,12 @@ pub struct SelectionContext<'cx, 'tcx:'cx> { param_env: &'cx ty::ParameterEnvironment<'tcx>, typer: &'cx (Typer<'tcx>+'cx), - /// Skolemizer used specifically for skolemizing entries on the + /// Freshener used specifically for skolemizing entries on the /// obligation stack. This ensures that all entries on the stack /// at one time will have the same set of skolemized entries, /// which is important for checking for trait bounds that /// recursively require themselves. - skolemizer: TypeSkolemizer<'cx, 'tcx>, + freshener: TypeFreshener<'cx, 'tcx>, /// If true, indicates that the evaluation should be conservative /// and consider the possibility of types outside this crate. @@ -73,15 +73,15 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> { obligation: &'prev TraitObligation<'tcx>, /// Trait ref from `obligation` but skolemized with the - /// selection-context's skolemizer. Used to check for recursion. - skol_trait_ref: Rc<ty::TraitRef<'tcx>>, + /// selection-context's freshener. Used to check for recursion. + fresh_trait_ref: Rc<ty::PolyTraitRef<'tcx>>, previous: Option<&'prev TraitObligationStack<'prev, 'tcx>> } #[deriving(Clone)] pub struct SelectionCache<'tcx> { - hashmap: RefCell<HashMap<Rc<ty::TraitRef<'tcx>>, + hashmap: RefCell<HashMap<Rc<ty::PolyTraitRef<'tcx>>, SelectionResult<'tcx, Candidate<'tcx>>>>, } @@ -91,7 +91,7 @@ pub enum MethodMatchResult { MethodDidNotMatch, } -#[deriving(Show)] +#[deriving(Copy, Show)] pub enum MethodMatchedData { // In the case of a precise match, we don't really need to store // how the match was found. So don't. @@ -102,8 +102,6 @@ pub enum MethodMatchedData { CoerciveMethodMatch(/* impl we matched */ ast::DefId) } -impl Copy for MethodMatchedData {} - /// The selection process begins by considering all impls, where /// clauses, and so forth that might resolve an obligation. Sometimes /// we'll be able to say definitively that (e.g.) an impl does not @@ -172,7 +170,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { infcx: infcx, param_env: param_env, typer: typer, - skolemizer: infcx.skolemizer(), + freshener: infcx.freshener(), intercrate: false, } } @@ -185,7 +183,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { infcx: infcx, param_env: param_env, typer: typer, - skolemizer: infcx.skolemizer(), + freshener: infcx.freshener(), intercrate: true, } } @@ -288,8 +286,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.evaluate_obligation_recursively(previous_stack, &obligation) } - ty::Predicate::Equate(a, b) => { - match infer::can_mk_eqty(self.infcx, a, b) { + ty::Predicate::Equate(ref p) => { + let result = self.infcx.probe(|_| { + self.infcx.equality_predicate(obligation.cause.span, p) + }); + match result { Ok(()) => EvaluatedToOk, Err(_) => EvaluatedToErr(Unimplemented), } @@ -347,16 +348,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // This suffices to allow chains like `FnMut` implemented in // terms of `Fn` etc, but we could probably make this more // precise still. - let input_types = stack.skol_trait_ref.input_types(); - let unbound_input_types = input_types.iter().any(|&t| ty::type_is_skolemized(t)); + let input_types = stack.fresh_trait_ref.0.input_types(); + let unbound_input_types = input_types.iter().any(|&t| ty::type_is_fresh(t)); if unbound_input_types && (self.intercrate || stack.iter().skip(1).any( - |prev| stack.skol_trait_ref.def_id == prev.skol_trait_ref.def_id)) + |prev| stack.fresh_trait_ref.def_id() == prev.fresh_trait_ref.def_id())) { debug!("evaluate_stack({}) --> unbound argument, recursion --> ambiguous", - stack.skol_trait_ref.repr(self.tcx())); + stack.fresh_trait_ref.repr(self.tcx())); return EvaluatedToAmbig; } @@ -373,19 +374,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `Option<Box<List<T>>>` is `Send` if `Box<List<T>>` is // `Send`. // - // Note that we do this comparison using the `skol_trait_ref` + // Note that we do this comparison using the `fresh_trait_ref` // fields. Because these have all been skolemized using - // `self.skolemizer`, we can be sure that (a) this will not + // `self.freshener`, we can be sure that (a) this will not // affect the inferencer state and (b) that if we see two // skolemized types with the same index, they refer to the // same unbound type variable. if stack.iter() .skip(1) // skip top-most frame - .any(|prev| stack.skol_trait_ref == prev.skol_trait_ref) + .any(|prev| stack.fresh_trait_ref == prev.fresh_trait_ref) { debug!("evaluate_stack({}) --> recursive", - stack.skol_trait_ref.repr(self.tcx())); + stack.fresh_trait_ref.repr(self.tcx())); return EvaluatedToOk; } @@ -407,13 +408,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { impl_def_id.repr(self.tcx()), obligation.repr(self.tcx())); - self.infcx.probe(|| { - match self.match_impl(impl_def_id, obligation) { + self.infcx.probe(|snapshot| { + let (skol_obligation_trait_ref, skol_map) = + self.infcx().skolemize_late_bound_regions(&*obligation.trait_ref, snapshot); + match self.match_impl(impl_def_id, obligation, snapshot, + &skol_map, Rc::new(skol_obligation_trait_ref)) { Ok(substs) => { let vtable_impl = self.vtable_impl(impl_def_id, substs, obligation.cause, - obligation.recursion_depth + 1); + obligation.recursion_depth + 1, + skol_map, + snapshot); self.winnow_selection(None, VtableImpl(vtable_impl)).may_apply() } Err(()) => { @@ -445,20 +451,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // Check the cache. Note that we skolemize the trait-ref - // separately rather than using `stack.skol_trait_ref` -- this + // separately rather than using `stack.fresh_trait_ref` -- this // is because we want the unbound variables to be replaced // with fresh skolemized types starting from index 0. - let cache_skol_trait_ref = - self.infcx.skolemize(stack.obligation.trait_ref.clone()); - debug!("candidate_from_obligation(cache_skol_trait_ref={}, obligation={})", - cache_skol_trait_ref.repr(self.tcx()), + let cache_fresh_trait_ref = + self.infcx.freshen(stack.obligation.trait_ref.clone()); + debug!("candidate_from_obligation(cache_fresh_trait_ref={}, obligation={})", + cache_fresh_trait_ref.repr(self.tcx()), stack.repr(self.tcx())); assert!(!stack.obligation.trait_ref.has_escaping_regions()); - match self.check_candidate_cache(cache_skol_trait_ref.clone()) { + match self.check_candidate_cache(cache_fresh_trait_ref.clone()) { Some(c) => { - debug!("CACHE HIT: cache_skol_trait_ref={}, candidate={}", - cache_skol_trait_ref.repr(self.tcx()), + debug!("CACHE HIT: cache_fresh_trait_ref={}, candidate={}", + cache_fresh_trait_ref.repr(self.tcx()), c.repr(self.tcx())); return c; } @@ -467,9 +473,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If no match, compute result and insert into cache. let candidate = self.candidate_from_obligation_no_cache(stack); - debug!("CACHE MISS: cache_skol_trait_ref={}, candidate={}", - cache_skol_trait_ref.repr(self.tcx()), candidate.repr(self.tcx())); - self.insert_candidate_cache(cache_skol_trait_ref, candidate.clone()); + debug!("CACHE MISS: cache_fresh_trait_ref={}, candidate={}", + cache_fresh_trait_ref.repr(self.tcx()), candidate.repr(self.tcx())); + self.insert_candidate_cache(cache_fresh_trait_ref, candidate.clone()); candidate } @@ -569,7 +575,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn pick_candidate_cache(&self, - cache_skol_trait_ref: &Rc<ty::TraitRef<'tcx>>) + cache_fresh_trait_ref: &Rc<ty::PolyTraitRef<'tcx>>) -> &SelectionCache<'tcx> { // High-level idea: we have to decide whether to consult the @@ -591,7 +597,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If the trait refers to any parameters in scope, then use // the cache of the param-environment. if - cache_skol_trait_ref.input_types().iter().any( + cache_fresh_trait_ref.0.input_types().iter().any( |&t| ty::type_has_self(t) || ty::type_has_params(t)) { return &self.param_env.selection_cache; @@ -604,7 +610,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // See the discussion in doc.rs for more details. if !self.param_env.caller_bounds.is_empty() && - cache_skol_trait_ref.input_types().iter().any( + cache_fresh_trait_ref.0.input_types().iter().any( |&t| ty::type_has_ty_infer(t)) { return &self.param_env.selection_cache; @@ -615,21 +621,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn check_candidate_cache(&mut self, - cache_skol_trait_ref: Rc<ty::TraitRef<'tcx>>) + cache_fresh_trait_ref: Rc<ty::PolyTraitRef<'tcx>>) -> Option<SelectionResult<'tcx, Candidate<'tcx>>> { - let cache = self.pick_candidate_cache(&cache_skol_trait_ref); + let cache = self.pick_candidate_cache(&cache_fresh_trait_ref); let hashmap = cache.hashmap.borrow(); - hashmap.get(&cache_skol_trait_ref).map(|c| (*c).clone()) + hashmap.get(&cache_fresh_trait_ref).map(|c| (*c).clone()) } fn insert_candidate_cache(&mut self, - cache_skol_trait_ref: Rc<ty::TraitRef<'tcx>>, + cache_fresh_trait_ref: Rc<ty::PolyTraitRef<'tcx>>, candidate: SelectionResult<'tcx, Candidate<'tcx>>) { - let cache = self.pick_candidate_cache(&cache_skol_trait_ref); + let cache = self.pick_candidate_cache(&cache_fresh_trait_ref); let mut hashmap = cache.hashmap.borrow_mut(); - hashmap.insert(cache_skol_trait_ref, candidate); + hashmap.insert(cache_fresh_trait_ref, candidate); } fn assemble_candidates<'o>(&mut self, @@ -648,7 +654,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Other bounds. Consider both in-scope bounds from fn decl // and applicable impls. There is a certain set of precedence rules here. - match self.tcx().lang_items.to_builtin_kind(obligation.trait_ref.def_id) { + match self.tcx().lang_items.to_builtin_kind(obligation.trait_ref.def_id()) { Some(ty::BoundCopy) => { debug!("obligation self ty is {}", obligation.self_ty().repr(self.tcx())); @@ -696,7 +702,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("assemble_candidates_from_caller_bounds({})", obligation.repr(self.tcx())); - let caller_trait_refs: Vec<Rc<ty::TraitRef>> = + let caller_trait_refs: Vec<_> = self.param_env.caller_bounds.predicates.iter() .filter_map(|o| o.to_trait()) .collect(); @@ -708,8 +714,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let matching_bounds = all_bounds.filter( |bound| self.infcx.probe( - || self.match_trait_refs(obligation, - (*bound).clone())).is_ok()); + |_| self.match_where_clause(obligation, bound.clone())).is_ok()); let param_candidates = matching_bounds.map( @@ -731,7 +736,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut CandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { - let kind = match self.fn_family_trait_kind(obligation.trait_ref.def_id) { + let kind = match self.fn_family_trait_kind(obligation.trait_ref.def_id()) { Some(k) => k, None => { return Ok(()); } }; @@ -779,7 +784,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // We provide a `Fn` impl for fn pointers. There is no need to provide // the other traits (e.g. `FnMut`) since those are provided by blanket // impls. - if Some(obligation.trait_ref.def_id) != self.tcx().lang_items.fn_trait() { + if Some(obligation.trait_ref.def_id()) != self.tcx().lang_items.fn_trait() { return Ok(()); } @@ -793,11 +798,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::ty_bare_fn(ty::BareFnTy { unsafety: ast::Unsafety::Normal, abi: abi::Rust, - sig: ty::FnSig { + sig: ty::Binder(ty::FnSig { inputs: _, output: ty::FnConverging(_), variadic: false - } + }) }) => { candidates.vec.push(FnPointerCandidate); } @@ -814,10 +819,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut CandidateSet<'tcx>) -> Result<(), SelectionError<'tcx>> { - let all_impls = self.all_impls(obligation.trait_ref.def_id); + let all_impls = self.all_impls(obligation.trait_ref.def_id()); for &impl_def_id in all_impls.iter() { - self.infcx.probe(|| { - match self.match_impl(impl_def_id, obligation) { + self.infcx.probe(|snapshot| { + let (skol_obligation_trait_ref, skol_map) = + self.infcx().skolemize_late_bound_regions(&*obligation.trait_ref, snapshot); + match self.match_impl(impl_def_id, obligation, snapshot, + &skol_map, Rc::new(skol_obligation_trait_ref)) { Ok(_) => { candidates.vec.push(ImplCandidate(impl_def_id)); } @@ -845,15 +853,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidate: &Candidate<'tcx>) -> EvaluationResult<'tcx> { - /*! - * Further evaluate `candidate` to decide whether all type parameters match - * and whether nested obligations are met. Returns true if `candidate` remains - * viable after this further scrutiny. - */ - - debug!("winnow_candidate: depth={} candidate={}", - stack.obligation.recursion_depth, candidate.repr(self.tcx())); - let result = self.infcx.probe(|| { + debug!("winnow_candidate: candidate={}", candidate.repr(self.tcx())); + let result = self.infcx.probe(|_| { let candidate = (*candidate).clone(); match self.confirm_candidate(stack.obligation, candidate) { Ok(selection) => self.winnow_selection(Some(stack), selection), @@ -916,18 +917,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidate_i.repr(self.tcx()), candidate_j.repr(self.tcx())); - self.infcx.probe(|| { + self.infcx.probe(|snapshot| { + let (skol_obligation_trait_ref, skol_map) = + self.infcx().skolemize_late_bound_regions( + &*stack.obligation.trait_ref, snapshot); let impl_substs = - self.rematch_impl(impl_def_id, stack.obligation); + self.rematch_impl(impl_def_id, stack.obligation, snapshot, + &skol_map, Rc::new(skol_obligation_trait_ref)); let impl_trait_ref = ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap(); let impl_trait_ref = impl_trait_ref.subst(self.tcx(), &impl_substs); + let poly_impl_trait_ref = + Rc::new(ty::Binder((*impl_trait_ref).clone())); let origin = infer::RelateOutputImplTypes(stack.obligation.cause.span); self.infcx - .sub_trait_refs(false, origin, - impl_trait_ref, vt.bound.clone()) + .sub_poly_trait_refs(false, origin, poly_impl_trait_ref, vt.bound.clone()) .is_ok() }) } @@ -1071,26 +1077,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => { + ty::ty_trait(ref data) => { match bound { ty::BoundSized => { Err(Unimplemented) } ty::BoundCopy | ty::BoundSync | ty::BoundSend => { - if bounds.builtin_bounds.contains(&bound) { + if data.bounds.builtin_bounds.contains(&bound) { Ok(If(Vec::new())) } else { // Recursively check all supertraits to find out if any further // bounds are required and thus we must fulfill. - // We have to create a temp trait ref here since TyTraits don't - // have actual self type info (which is required for the - // supertraits iterator). - let tmp_tr = Rc::new(ty::TraitRef { - def_id: principal.def_id, - substs: principal.substs.with_self_ty(ty::mk_err()) - }); + let tmp_tr = data.principal_trait_ref_with_self_ty(ty::mk_err()); for tr in util::supertraits(self.tcx(), tmp_tr) { - let td = ty::lookup_trait_def(self.tcx(), tr.def_id); + let td = ty::lookup_trait_def(self.tcx(), tr.def_id()); if td.bounds.builtin_bounds.contains(&bound) { return Ok(If(Vec::new())) @@ -1276,8 +1276,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::ty_open(_) | - ty::ty_infer(ty::SkolemizedTy(_)) | - ty::ty_infer(ty::SkolemizedIntTy(_)) => { + ty::ty_infer(ty::FreshTy(_)) | + ty::ty_infer(ty::FreshIntTy(_)) => { self.tcx().sess.bug( format!( "asked to assemble builtin bounds of unexpected type: {}", @@ -1404,10 +1404,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.repr(self.tcx()), param.repr(self.tcx())); - let () = try!(self.confirm(obligation.cause, - obligation.trait_ref.clone(), - param.bound.clone())); - Ok(param) + // During evaluation, we already checked that this + // where-clause trait-ref could be unified with the obligation + // trait-ref. Repeat that unification now without any + // transactional boundary; it should not fail. + match self.confirm_poly_trait_refs(obligation.cause, + obligation.trait_ref.clone(), + param.bound.clone()) { + Ok(()) => Ok(param), + Err(_) => { + self.tcx().sess.bug( + format!("Where clause `{}` was applicable to `{}` but now is not", + param.bound.repr(self.tcx()), + obligation.repr(self.tcx())).as_slice()); + } + } } fn confirm_builtin_candidate(&mut self, @@ -1454,8 +1465,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligations.push(Obligation { cause: obligation.cause, recursion_depth: obligation.recursion_depth+1, - trait_ref: ty::Predicate::TypeOutlives(obligation.self_ty(), - ty::ReStatic) + trait_ref: ty::Binder(ty::OutlivesPredicate(obligation.self_ty(), + ty::ReStatic)).as_predicate(), }); } @@ -1480,23 +1491,44 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // First, create the substitutions by matching the impl again, // this time not in a probe. - let substs = self.rematch_impl(impl_def_id, obligation); - debug!("confirm_impl_candidate substs={}", substs); - Ok(self.vtable_impl(impl_def_id, substs, obligation.cause, obligation.recursion_depth + 1)) + self.infcx.try(|snapshot| { + let (skol_obligation_trait_ref, skol_map) = + self.infcx().skolemize_late_bound_regions(&*obligation.trait_ref, snapshot); + let substs = self.rematch_impl(impl_def_id, obligation, + snapshot, &skol_map, Rc::new(skol_obligation_trait_ref)); + debug!("confirm_impl_candidate substs={}", substs); + Ok(self.vtable_impl(impl_def_id, substs, obligation.cause, + obligation.recursion_depth + 1, skol_map, snapshot)) + }) } fn vtable_impl(&mut self, impl_def_id: ast::DefId, substs: Substs<'tcx>, cause: ObligationCause<'tcx>, - recursion_depth: uint) + recursion_depth: uint, + skol_map: infer::SkolemizationMap, + snapshot: &infer::CombinedSnapshot) -> VtableImplData<'tcx, PredicateObligation<'tcx>> { + debug!("vtable_impl(impl_def_id={}, substs={}, recursion_depth={}, skol_map={})", + impl_def_id.repr(self.tcx()), + substs.repr(self.tcx()), + recursion_depth, + skol_map.repr(self.tcx())); + let impl_predicates = self.impl_predicates(cause, recursion_depth, impl_def_id, - &substs); + &substs, + skol_map, + snapshot); + + debug!("vtable_impl: impl_def_id={} impl_predicates={}", + impl_def_id.repr(self.tcx()), + impl_predicates.repr(self.tcx())); + VtableImplData { impl_def_id: impl_def_id, substs: substs, nested: impl_predicates } @@ -1526,23 +1558,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } }; - let arguments_tuple = ty::mk_tup(self.tcx(), sig.inputs.to_vec()); - let output_type = sig.output.unwrap(); + let arguments_tuple = ty::mk_tup(self.tcx(), sig.0.inputs.to_vec()); + let output_type = sig.0.output.unwrap(); let substs = Substs::new_trait( vec![arguments_tuple, output_type], vec![], vec![], self_ty); - let trait_ref = Rc::new(ty::TraitRef { - def_id: obligation.trait_ref.def_id, + let trait_ref = Rc::new(ty::Binder(ty::TraitRef { + def_id: obligation.trait_ref.def_id(), substs: substs, - }); + })); - let () = - try!(self.confirm(obligation.cause, - obligation.trait_ref.clone(), - trait_ref)); + try!(self.confirm_poly_trait_refs(obligation.cause, + obligation.trait_ref.clone(), + trait_ref)); Ok(self_ty) } @@ -1569,26 +1600,69 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let closure_sig = &closure_type.sig; - let arguments_tuple = closure_sig.inputs[0]; + let arguments_tuple = closure_sig.0.inputs[0]; let substs = Substs::new_trait( vec![arguments_tuple.subst(self.tcx(), substs), - closure_sig.output.unwrap().subst(self.tcx(), substs)], + closure_sig.0.output.unwrap().subst(self.tcx(), substs)], vec![], vec![], obligation.self_ty()); - let trait_ref = Rc::new(ty::TraitRef { - def_id: obligation.trait_ref.def_id, + let trait_ref = Rc::new(ty::Binder(ty::TraitRef { + def_id: obligation.trait_ref.def_id(), substs: substs, - }); + })); debug!("confirm_unboxed_closure_candidate(closure_def_id={}, trait_ref={})", closure_def_id.repr(self.tcx()), trait_ref.repr(self.tcx())); - self.confirm(obligation.cause, - obligation.trait_ref.clone(), - trait_ref) + self.confirm_poly_trait_refs(obligation.cause, + obligation.trait_ref.clone(), + trait_ref) + } + + /// In the case of unboxed closure types and fn pointers, + /// we currently treat the input type parameters on the trait as + /// outputs. This means that when we have a match we have only + /// considered the self type, so we have to go back and make sure + /// to relate the argument types too. This is kind of wrong, but + /// since we control the full set of impls, also not that wrong, + /// and it DOES yield better error messages (since we don't report + /// errors as if there is no applicable impl, but rather report + /// errors are about mismatched argument types. + /// + /// Here is an example. Imagine we have an unboxed closure expression + /// and we desugared it so that the type of the expression is + /// `Closure`, and `Closure` expects an int as argument. Then it + /// is "as if" the compiler generated this impl: + /// + /// impl Fn(int) for Closure { ... } + /// + /// Now imagine our obligation is `Fn(uint) for Closure`. So far + /// we have matched the self-type `Closure`. At this point we'll + /// compare the `int` to `uint` and generate an error. + /// + /// Note that this checking occurs *after* the impl has selected, + /// because these output type parameters should not affect the + /// selection of the impl. Therefore, if there is a mismatch, we + /// report an error to the user. + fn confirm_poly_trait_refs(&mut self, + obligation_cause: ObligationCause, + obligation_trait_ref: Rc<ty::PolyTraitRef<'tcx>>, + expected_trait_ref: Rc<ty::PolyTraitRef<'tcx>>) + -> Result<(), SelectionError<'tcx>> + { + let origin = infer::RelateOutputImplTypes(obligation_cause.span); + + let obligation_trait_ref = obligation_trait_ref.clone(); + match self.infcx.sub_poly_trait_refs(false, + origin, + expected_trait_ref.clone(), + obligation_trait_ref.clone()) { + Ok(()) => Ok(()), + Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) + } } /////////////////////////////////////////////////////////////////////////// @@ -1603,10 +1677,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn rematch_impl(&mut self, impl_def_id: ast::DefId, - obligation: &TraitObligation<'tcx>) + obligation: &TraitObligation<'tcx>, + snapshot: &infer::CombinedSnapshot, + skol_map: &infer::SkolemizationMap, + skol_obligation_trait_ref: Rc<ty::TraitRef<'tcx>>) -> Substs<'tcx> { - match self.match_impl(impl_def_id, obligation) { + match self.match_impl(impl_def_id, obligation, snapshot, + skol_map, skol_obligation_trait_ref) { Ok(substs) => { substs } @@ -1622,11 +1700,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn match_impl(&mut self, impl_def_id: ast::DefId, - obligation: &TraitObligation<'tcx>) + obligation: &TraitObligation<'tcx>, + snapshot: &infer::CombinedSnapshot, + skol_map: &infer::SkolemizationMap, + skol_obligation_trait_ref: Rc<ty::TraitRef<'tcx>>) -> Result<Substs<'tcx>, ()> { - let impl_trait_ref = ty::impl_trait_ref(self.tcx(), - impl_def_id).unwrap(); + let impl_trait_ref = ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap(); // Before we create the substitutions and everything, first // consider a "quick reject". This avoids creating more types @@ -1642,10 +1722,37 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let impl_trait_ref = impl_trait_ref.subst(self.tcx(), &impl_substs); - match self.match_trait_refs(obligation, impl_trait_ref) { - Ok(()) => Ok(impl_substs), - Err(()) => Err(()) + debug!("match_impl(impl_def_id={}, obligation={}, \ + impl_trait_ref={}, skol_obligation_trait_ref={})", + impl_def_id.repr(self.tcx()), + obligation.repr(self.tcx()), + impl_trait_ref.repr(self.tcx()), + skol_obligation_trait_ref.repr(self.tcx())); + + let origin = infer::RelateOutputImplTypes(obligation.cause.span); + match self.infcx.sub_trait_refs(false, + origin, + impl_trait_ref, + skol_obligation_trait_ref) { + Ok(()) => { } + Err(e) => { + debug!("match_impl: failed sub_trait_refs due to `{}`", + ty::type_err_to_str(self.tcx(), &e)); + return Err(()); + } + } + + match self.infcx.leak_check(skol_map, snapshot) { + Ok(()) => { } + Err(e) => { + debug!("match_impl: failed leak check due to `{}`", + ty::type_err_to_str(self.tcx(), &e)); + return Err(()); + } } + + debug!("match_impl: success impl_substs={}", impl_substs.repr(self.tcx())); + Ok(impl_substs) } fn fast_reject_trait_refs(&mut self, @@ -1671,20 +1778,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } - fn match_trait_refs(&mut self, - obligation: &TraitObligation<'tcx>, - trait_ref: Rc<ty::TraitRef<'tcx>>) + fn match_where_clause(&mut self, + obligation: &TraitObligation<'tcx>, + where_clause_trait_ref: Rc<ty::PolyTraitRef<'tcx>>) -> Result<(),()> { - debug!("match_trait_refs: obligation={} trait_ref={}", + debug!("match_where_clause: obligation={} where_clause_trait_ref={}", obligation.repr(self.tcx()), - trait_ref.repr(self.tcx())); + where_clause_trait_ref.repr(self.tcx())); let origin = infer::RelateOutputImplTypes(obligation.cause.span); - match self.infcx.sub_trait_refs(false, - origin, - trait_ref, - obligation.trait_ref.clone()) { + match self.infcx.sub_poly_trait_refs(false, + origin, + where_clause_trait_ref, + obligation.trait_ref.clone()) { Ok(()) => Ok(()), Err(_) => Err(()), } @@ -1759,78 +1866,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } /////////////////////////////////////////////////////////////////////////// - // Confirmation - // - // The final step of selection: once we know how an obligation is - // is resolved, we confirm that selection in order to have - // side-effects on the typing environment. This step also unifies - // the output type parameters from the obligation with those found - // on the impl/bound, which may yield type errors. - - /// Relates the output type parameters from an impl to the - /// trait. This may lead to type errors. The confirmation step - /// is separated from the main match procedure because these - /// type errors do not cause us to select another impl. - /// - /// As an example, consider matching the obligation - /// `Iterator<char> for Elems<int>` using the following impl: - /// - /// impl<T> Iterator<T> for Elems<T> { ... } - /// - /// The match phase will succeed with substitution `T=int`. - /// The confirm step will then try to unify `int` and `char` - /// and yield an error. - fn confirm_impl_vtable(&mut self, - impl_def_id: ast::DefId, - obligation_cause: ObligationCause<'tcx>, - obligation_trait_ref: Rc<ty::TraitRef<'tcx>>, - substs: &Substs<'tcx>) - -> Result<(), SelectionError<'tcx>> - { - let impl_trait_ref = ty::impl_trait_ref(self.tcx(), - impl_def_id).unwrap(); - let impl_trait_ref = impl_trait_ref.subst(self.tcx(), - substs); - self.confirm(obligation_cause, obligation_trait_ref, impl_trait_ref) - } - - /// After we have determined which impl applies, and with what substitutions, there is one last - /// step. We have to go back and relate the "output" type parameters from the obligation to the - /// types that are specified in the impl. - /// - /// For example, imagine we have: - /// - /// impl<T> Iterator<T> for Vec<T> { ... } - /// - /// and our obligation is `Iterator<Foo> for Vec<int>` (note the mismatch in the obligation - /// types). Up until this step, no error would be reported: the self type is `Vec<int>`, and - /// that matches `Vec<T>` with the substitution `T=int`. At this stage, we could then go and - /// check that the type parameters to the `Iterator` trait match. (In terms of the parameters, - /// the `expected_trait_ref` here would be `Iterator<int> for Vec<int>`, and the - /// `obligation_trait_ref` would be `Iterator<Foo> for Vec<int>`. - /// - /// Note that this checking occurs *after* the impl has selected, because these output type - /// parameters should not affect the selection of the impl. Therefore, if there is a mismatch, - /// we report an error to the user. - fn confirm(&mut self, - obligation_cause: ObligationCause, - obligation_trait_ref: Rc<ty::TraitRef<'tcx>>, - expected_trait_ref: Rc<ty::TraitRef<'tcx>>) - -> Result<(), SelectionError<'tcx>> - { - let origin = infer::RelateOutputImplTypes(obligation_cause.span); - - let obligation_trait_ref = obligation_trait_ref.clone(); - match self.infcx.sub_trait_refs(false, - origin, - expected_trait_ref.clone(), - obligation_trait_ref.clone()) { - Ok(()) => Ok(()), - Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) - } - } - - /////////////////////////////////////////////////////////////////////////// // Miscellany fn push_stack<'o,'s:'o>(&mut self, @@ -1838,11 +1873,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &'o TraitObligation<'tcx>) -> TraitObligationStack<'o, 'tcx> { - let skol_trait_ref = obligation.trait_ref.fold_with(&mut self.skolemizer); + let fresh_trait_ref = obligation.trait_ref.fold_with(&mut self.freshener); TraitObligationStack { obligation: obligation, - skol_trait_ref: skol_trait_ref, + fresh_trait_ref: fresh_trait_ref, previous: previous_stack.map(|p| p), // FIXME variance } } @@ -1861,11 +1896,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { cause: ObligationCause<'tcx>, recursion_depth: uint, impl_def_id: ast::DefId, - impl_substs: &Substs<'tcx>) + impl_substs: &Substs<'tcx>, + skol_map: infer::SkolemizationMap, + snapshot: &infer::CombinedSnapshot) -> VecPerParamSpace<PredicateObligation<'tcx>> { let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics; let bounds = impl_generics.to_bounds(self.tcx(), impl_substs); + let bounds = self.infcx().plug_leaks(skol_map, snapshot, &bounds); util::predicates_for_generics(self.tcx(), cause, recursion_depth, &bounds) } diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index d8956246d32..27824ba5c6e 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -47,7 +47,7 @@ struct StackEntry<'tcx> { pub fn elaborate_trait_ref<'cx, 'tcx>( tcx: &'cx ty::ctxt<'tcx>, - trait_ref: Rc<ty::TraitRef<'tcx>>) + trait_ref: Rc<ty::PolyTraitRef<'tcx>>) -> Elaborator<'cx, 'tcx> { elaborate_predicates(tcx, vec![ty::Predicate::Trait(trait_ref)]) @@ -55,7 +55,7 @@ pub fn elaborate_trait_ref<'cx, 'tcx>( pub fn elaborate_trait_refs<'cx, 'tcx>( tcx: &'cx ty::ctxt<'tcx>, - trait_refs: &[Rc<ty::TraitRef<'tcx>>]) + trait_refs: &[Rc<ty::PolyTraitRef<'tcx>>]) -> Elaborator<'cx, 'tcx> { let predicates = trait_refs.iter() @@ -174,7 +174,7 @@ pub struct Supertraits<'cx, 'tcx:'cx> { } pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, - trait_ref: Rc<ty::TraitRef<'tcx>>) + trait_ref: Rc<ty::PolyTraitRef<'tcx>>) -> Supertraits<'cx, 'tcx> { let elaborator = elaborate_trait_ref(tcx, trait_ref); @@ -182,15 +182,15 @@ pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, } pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, - bounds: &[Rc<ty::TraitRef<'tcx>>]) + bounds: &[Rc<ty::PolyTraitRef<'tcx>>]) -> Supertraits<'cx, 'tcx> { let elaborator = elaborate_trait_refs(tcx, bounds); Supertraits { elaborator: elaborator } } -impl<'cx, 'tcx> Iterator<Rc<ty::TraitRef<'tcx>>> for Supertraits<'cx, 'tcx> { - fn next(&mut self) -> Option<Rc<ty::TraitRef<'tcx>>> { +impl<'cx, 'tcx> Iterator<Rc<ty::PolyTraitRef<'tcx>>> for Supertraits<'cx, 'tcx> { + fn next(&mut self) -> Option<Rc<ty::PolyTraitRef<'tcx>>> { loop { match self.elaborator.next() { None => { @@ -266,18 +266,18 @@ pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>, }) } -pub fn trait_ref_for_builtin_bound<'tcx>( +pub fn poly_trait_ref_for_builtin_bound<'tcx>( tcx: &ty::ctxt<'tcx>, builtin_bound: ty::BuiltinBound, param_ty: Ty<'tcx>) - -> Result<Rc<ty::TraitRef<'tcx>>, ErrorReported> + -> Result<Rc<ty::PolyTraitRef<'tcx>>, ErrorReported> { match tcx.lang_items.from_builtin_kind(builtin_bound) { Ok(def_id) => { - Ok(Rc::new(ty::TraitRef { + Ok(Rc::new(ty::Binder(ty::TraitRef { def_id: def_id, substs: Substs::empty().with_self_ty(param_ty) - })) + }))) } Err(e) => { tcx.sess.err(e.as_slice()); @@ -294,7 +294,7 @@ pub fn predicate_for_builtin_bound<'tcx>( param_ty: Ty<'tcx>) -> Result<PredicateObligation<'tcx>, ErrorReported> { - let trait_ref = try!(trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty)); + let trait_ref = try!(poly_trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty)); Ok(Obligation { cause: cause, recursion_depth: recursion_depth, @@ -306,14 +306,14 @@ pub fn predicate_for_builtin_bound<'tcx>( /// of caller obligations), search through the trait and supertraits to find one where `test(d)` is /// true, where `d` is the def-id of the trait/supertrait. If any is found, return `Some(p)` where /// `p` is the path to that trait/supertrait. Else `None`. -pub fn search_trait_and_supertraits_from_bound<'tcx, F>(tcx: &ty::ctxt<'tcx>, - caller_bound: Rc<ty::TraitRef<'tcx>>, - mut test: F) - -> Option<VtableParamData<'tcx>> where - F: FnMut(ast::DefId) -> bool, +pub fn search_trait_and_supertraits_from_bound<'tcx,F>(tcx: &ty::ctxt<'tcx>, + caller_bound: Rc<ty::PolyTraitRef<'tcx>>, + mut test: F) + -> Option<VtableParamData<'tcx>> + where F: FnMut(ast::DefId) -> bool, { for bound in transitive_bounds(tcx, &[caller_bound]) { - if test(bound.def_id) { + if test(bound.def_id()) { let vtable_param = VtableParamData { bound: bound }; return Some(vtable_param); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 0ad07bed7d9..acf1fced72c 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -60,7 +60,7 @@ use middle::subst::{mod, Subst, Substs, VecPerParamSpace}; use middle::traits::ObligationCause; use middle::traits; use middle::ty; -use middle::ty_fold::{mod, TypeFoldable, TypeFolder, HigherRankedFoldable}; +use middle::ty_fold::{mod, TypeFoldable, TypeFolder}; use util::ppaux::{note_and_explain_region, bound_region_ptr_to_string}; use util::ppaux::{trait_store_to_string, ty_to_string}; use util::ppaux::{Repr, UserString}; @@ -107,22 +107,18 @@ pub struct CrateAnalysis<'tcx> { pub name: String, } -#[deriving(PartialEq, Eq, Hash)] +#[deriving(Copy, PartialEq, Eq, Hash)] pub struct field<'tcx> { pub name: ast::Name, pub mt: mt<'tcx> } -impl<'tcx> Copy for field<'tcx> {} - -#[deriving(Clone, Show)] +#[deriving(Clone, Copy, Show)] pub enum ImplOrTraitItemContainer { TraitContainer(ast::DefId), ImplContainer(ast::DefId), } -impl Copy for ImplOrTraitItemContainer {} - impl ImplOrTraitItemContainer { pub fn id(&self) -> ast::DefId { match *self { @@ -177,14 +173,12 @@ impl<'tcx> ImplOrTraitItem<'tcx> { } } -#[deriving(Clone)] +#[deriving(Clone, Copy)] pub enum ImplOrTraitItemId { MethodTraitItemId(ast::DefId), TypeTraitItemId(ast::DefId), } -impl Copy for ImplOrTraitItemId {} - impl ImplOrTraitItemId { pub fn def_id(&self) -> ast::DefId { match *self { @@ -238,7 +232,7 @@ impl<'tcx> Method<'tcx> { } } -#[deriving(Clone)] +#[deriving(Clone, Copy)] pub struct AssociatedType { pub name: ast::Name, pub vis: ast::Visibility, @@ -246,17 +240,13 @@ pub struct AssociatedType { pub container: ImplOrTraitItemContainer, } -impl Copy for AssociatedType {} - -#[deriving(Clone, PartialEq, Eq, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash, Show)] pub struct mt<'tcx> { pub ty: Ty<'tcx>, pub mutbl: ast::Mutability, } -impl<'tcx> Copy for mt<'tcx> {} - -#[deriving(Clone, PartialEq, Eq, Hash, Encodable, Decodable, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Show)] pub enum TraitStore { /// Box<Trait> UniqTraitStore, @@ -264,9 +254,7 @@ pub enum TraitStore { RegionTraitStore(Region, ast::Mutability), } -impl Copy for TraitStore {} - -#[deriving(Clone, Show)] +#[deriving(Clone, Copy, Show)] pub struct field_ty { pub name: Name, pub id: DefId, @@ -274,33 +262,28 @@ pub struct field_ty { pub origin: ast::DefId, // The DefId of the struct in which the field is declared. } -impl Copy for field_ty {} - // Contains information needed to resolve types and (in the future) look up // the types of AST nodes. -#[deriving(PartialEq, Eq, Hash)] +#[deriving(Copy, PartialEq, Eq, Hash)] pub struct creader_cache_key { pub cnum: CrateNum, pub pos: uint, pub len: uint } -impl Copy for creader_cache_key {} - +#[deriving(Copy)] pub enum ast_ty_to_ty_cache_entry<'tcx> { atttce_unresolved, /* not resolved yet */ atttce_resolved(Ty<'tcx>) /* resolved to a type, irrespective of region */ } -impl<'tcx> Copy for ast_ty_to_ty_cache_entry<'tcx> {} - #[deriving(Clone, PartialEq, Decodable, Encodable)] pub struct ItemVariances { pub types: VecPerParamSpace<Variance>, pub regions: VecPerParamSpace<Variance>, } -#[deriving(Clone, PartialEq, Decodable, Encodable, Show)] +#[deriving(Clone, Copy, PartialEq, Decodable, Encodable, Show)] pub enum Variance { Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type Invariant, // T<A> <: T<B> iff B == A -- e.g., type of mutable cell @@ -308,8 +291,6 @@ pub enum Variance { Bivariant, // T<A> <: T<B> -- e.g., unused type parameter } -impl Copy for Variance {} - #[deriving(Clone, Show)] pub enum AutoAdjustment<'tcx> { AdjustAddEnv(ty::TraitStore), @@ -449,14 +430,12 @@ pub fn type_of_adjust<'tcx>(cx: &ctxt<'tcx>, adj: &AutoAdjustment<'tcx>) -> Opti } } -#[deriving(Clone, Encodable, Decodable, PartialEq, PartialOrd, Show)] +#[deriving(Clone, Copy, Encodable, Decodable, PartialEq, PartialOrd, Show)] pub struct param_index { pub space: subst::ParamSpace, pub index: uint } -impl Copy for param_index {} - #[deriving(Clone, Show)] pub enum MethodOrigin<'tcx> { // fully statically resolved method @@ -478,7 +457,9 @@ pub enum MethodOrigin<'tcx> { #[deriving(Clone, Show)] pub struct MethodParam<'tcx> { // the precise trait reference that occurs as a bound -- this may - // be a supertrait of what the user actually typed. + // be a supertrait of what the user actually typed. Note that it + // never contains bound regions; those regions should have been + // instantiated with fresh variables at this point. pub trait_ref: Rc<ty::TraitRef<'tcx>>, // index of uint in the list of methods for the trait @@ -511,8 +492,6 @@ pub struct MethodCallee<'tcx> { pub substs: subst::Substs<'tcx> } -impl Copy for MethodCall {} - /// With method calls, we store some extra information in /// side tables (i.e method_map). We use /// MethodCall as a key to index into these tables instead of @@ -525,21 +504,19 @@ impl Copy for MethodCall {} /// needed to add to the side tables. Thus to disambiguate /// we also keep track of whether there's an adjustment in /// our key. -#[deriving(Clone, PartialEq, Eq, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash, Show)] pub struct MethodCall { pub expr_id: ast::NodeId, pub adjustment: ExprAdjustment } -#[deriving(Clone, PartialEq, Eq, Hash, Show, Encodable, Decodable)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash, Show, Encodable, Decodable)] pub enum ExprAdjustment { NoAdjustment, AutoDeref(uint), AutoObject } -impl Copy for ExprAdjustment {} - impl MethodCall { pub fn expr(id: ast::NodeId) -> MethodCall { MethodCall { @@ -609,10 +586,11 @@ pub enum vtable_origin<'tcx> { // For every explicit cast into an object type, maps from the cast // expr to the associated trait ref. -pub type ObjectCastMap<'tcx> = RefCell<NodeMap<Rc<ty::TraitRef<'tcx>>>>; +pub type ObjectCastMap<'tcx> = RefCell<NodeMap<Rc<ty::PolyTraitRef<'tcx>>>>; /// A restriction that certain types must be the same size. The use of /// `transmute` gives rise to these restrictions. +#[deriving(Copy)] pub struct TransmuteRestriction<'tcx> { /// The span from whence the restriction comes. pub span: Span, @@ -624,8 +602,6 @@ pub struct TransmuteRestriction<'tcx> { pub id: ast::NodeId, } -impl<'tcx> Copy for TransmuteRestriction<'tcx> {} - /// The data structure to keep track of all the information that typechecker /// generates so that so that it can be reused and doesn't have to be redone /// later on. @@ -908,7 +884,7 @@ pub fn type_escapes_depth(ty: Ty, depth: uint) -> bool { pub struct BareFnTy<'tcx> { pub unsafety: ast::Unsafety, pub abi: abi::Abi, - pub sig: FnSig<'tcx>, + pub sig: PolyFnSig<'tcx>, } #[deriving(Clone, PartialEq, Eq, Hash, Show)] @@ -917,11 +893,11 @@ pub struct ClosureTy<'tcx> { pub onceness: ast::Onceness, pub store: TraitStore, pub bounds: ExistentialBounds, - pub sig: FnSig<'tcx>, + pub sig: PolyFnSig<'tcx>, pub abi: abi::Abi, } -#[deriving(Clone, PartialEq, Eq, Hash)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash)] pub enum FnOutput<'tcx> { FnConverging(Ty<'tcx>), FnDiverging @@ -936,18 +912,12 @@ impl<'tcx> FnOutput<'tcx> { } } -impl<'tcx> Copy for FnOutput<'tcx> {} - /// Signature of a function type, which I have arbitrarily /// decided to use to refer to the input/output types. /// /// - `inputs` is the list of arguments and their modes. /// - `output` is the return type. /// - `variadic` indicates whether this is a varidic function. (only true for foreign fns) -/// -/// Note that a `FnSig` introduces a level of region binding, to -/// account for late-bound parameters that appear in the types of the -/// fn's arguments or the fn's return type. #[deriving(Clone, PartialEq, Eq, Hash)] pub struct FnSig<'tcx> { pub inputs: Vec<Ty<'tcx>>, @@ -955,15 +925,15 @@ pub struct FnSig<'tcx> { pub variadic: bool } -#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub type PolyFnSig<'tcx> = Binder<FnSig<'tcx>>; + +#[deriving(Clone, Copy, PartialEq, Eq, Hash, Show)] pub struct ParamTy { pub space: subst::ParamSpace, pub idx: uint, pub def_id: DefId } -impl Copy for ParamTy {} - /// A [De Bruijn index][dbi] is a standard means of representing /// regions (and perhaps later types) in a higher-ranked setting. In /// particular, imagine a type like this: @@ -1003,7 +973,7 @@ impl Copy for ParamTy {} /// is the outer fn. /// /// [dbi]: http://en.wikipedia.org/wiki/De_Bruijn_index -#[deriving(Clone, PartialEq, Eq, Hash, Encodable, Decodable, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Show)] pub struct DebruijnIndex { // We maintain the invariant that this is never 0. So 1 indicates // the innermost binder. To ensure this, create with `DebruijnIndex::new`. @@ -1011,7 +981,7 @@ pub struct DebruijnIndex { } /// Representation of regions: -#[deriving(Clone, PartialEq, Eq, Hash, Encodable, Decodable, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Show)] pub enum Region { // Region bound in a type or fn declaration which will be // substituted 'early' -- that is, at the same time when type @@ -1052,15 +1022,13 @@ pub enum Region { /// Upvars do not get their own node-id. Instead, we use the pair of /// the original var id (that is, the root variable that is referenced /// by the upvar) and the id of the closure expression. -#[deriving(Clone, PartialEq, Eq, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash, Show)] pub struct UpvarId { pub var_id: ast::NodeId, pub closure_expr_id: ast::NodeId, } -impl Copy for UpvarId {} - -#[deriving(Clone, PartialEq, Eq, Hash, Show, Encodable, Decodable)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash, Show, Encodable, Decodable)] pub enum BorrowKind { /// Data must be immutable and is aliasable. ImmBorrow, @@ -1106,8 +1074,6 @@ pub enum BorrowKind { MutBorrow } -impl Copy for BorrowKind {} - /// Information describing the borrowing of an upvar. This is computed /// during `typeck`, specifically by `regionck`. The general idea is /// that the compiler analyses treat closures like: @@ -1155,7 +1121,7 @@ impl Copy for BorrowKind {} /// - Through mutation, the borrowed upvars can actually escape /// the closure, so sometimes it is necessary for them to be larger /// than the closure lifetime itself. -#[deriving(PartialEq, Clone, Encodable, Decodable, Show)] +#[deriving(Copy, PartialEq, Clone, Encodable, Decodable, Show)] pub struct UpvarBorrow { pub kind: BorrowKind, pub region: ty::Region, @@ -1163,8 +1129,6 @@ pub struct UpvarBorrow { pub type UpvarBorrowMap = FnvHashMap<UpvarId, UpvarBorrow>; -impl Copy for UpvarBorrow {} - impl Region { pub fn is_bound(&self) -> bool { match *self { @@ -1182,9 +1146,7 @@ impl Region { } } -impl Copy for Region {} - -#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Encodable, Decodable, Show)] +#[deriving(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash, Encodable, Decodable, Show)] /// A "free" region `fr` can be interpreted as "some region /// at least as big as the scope `fr.scope`". pub struct FreeRegion { @@ -1192,9 +1154,7 @@ pub struct FreeRegion { pub bound_region: BoundRegion } -impl Copy for FreeRegion {} - -#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Encodable, Decodable, Show)] +#[deriving(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash, Encodable, Decodable, Show)] pub enum BoundRegion { /// An anonymous region parameter for a given fn (&T) BrAnon(uint), @@ -1213,8 +1173,6 @@ pub enum BoundRegion { BrEnv } -impl Copy for BoundRegion {} - #[inline] pub fn mk_prim_t<'tcx>(primitive: &'tcx TyS<'static>) -> Ty<'tcx> { // FIXME(#17596) Ty<'tcx> is incorrectly invariant w.r.t 'tcx. @@ -1308,10 +1266,25 @@ pub enum sty<'tcx> { #[deriving(Clone, PartialEq, Eq, Hash, Show)] pub struct TyTrait<'tcx> { // Principal trait reference. - pub principal: TraitRef<'tcx>, // would use Rc<TraitRef>, but it runs afoul of some static rules + pub principal: PolyTraitRef<'tcx>, pub bounds: ExistentialBounds } +impl<'tcx> TyTrait<'tcx> { + /// Object types don't have a self-type specified. Therefore, when + /// we convert the principal trait-ref into a normal trait-ref, + /// you must give *some* self-type. A common choice is `mk_err()` + /// or some skolemized type. + pub fn principal_trait_ref_with_self_ty(&self, self_ty: Ty<'tcx>) + -> Rc<ty::PolyTraitRef<'tcx>> + { + Rc::new(ty::Binder(ty::TraitRef { + def_id: self.principal.def_id(), + substs: self.principal.substs().with_self_ty(self_ty), + })) + } +} + /// A complete reference to a trait. These take numerous guises in syntax, /// but perhaps the most recognizable form is in a where clause: /// @@ -1333,30 +1306,43 @@ pub struct TraitRef<'tcx> { pub substs: Substs<'tcx>, } -/// Binder serves as a synthetic binder for lifetimes. It is used when -/// we wish to replace the escaping higher-ranked lifetimes in a type -/// or something else that is not itself a binder (this is because the -/// `replace_late_bound_regions` function replaces all lifetimes bound -/// by the binder supplied to it; but a type is not a binder, so you -/// must introduce an artificial one). -#[deriving(Clone, PartialEq, Eq, Hash, Show)] -pub struct Binder<T> { - pub value: T -} +pub type PolyTraitRef<'tcx> = Binder<TraitRef<'tcx>>; -pub fn bind<T>(value: T) -> Binder<T> { - Binder { value: value } +impl<'tcx> PolyTraitRef<'tcx> { + pub fn self_ty(&self) -> Ty<'tcx> { + self.0.self_ty() + } + + pub fn def_id(&self) -> ast::DefId { + self.0.def_id + } + + pub fn substs(&self) -> &Substs<'tcx> { + &self.0.substs + } + + pub fn input_types(&self) -> &[Ty<'tcx>] { + self.0.input_types() + } } -#[deriving(Clone, PartialEq)] +/// Binder is a binder for higher-ranked lifetimes. It is part of the +/// compiler's representation for things like `for<'a> Fn(&'a int)` +/// (which would be represented by the type `PolyTraitRef == +/// Binder<TraitRef>`). Note that when we skolemize, instantiate, +/// erase, or otherwise "discharge" these bound reons, we change the +/// type from `Binder<T>` to just `T` (see +/// e.g. `liberate_late_bound_regions`). +#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub struct Binder<T>(pub T); + +#[deriving(Clone, Copy, PartialEq)] pub enum IntVarValue { IntType(ast::IntTy), UintType(ast::UintTy), } -impl Copy for IntVarValue {} - -#[deriving(Clone, Show)] +#[deriving(Clone, Copy, Show)] pub enum terr_vstore_kind { terr_vec, terr_str, @@ -1364,18 +1350,14 @@ pub enum terr_vstore_kind { terr_trait } -impl Copy for terr_vstore_kind {} - -#[deriving(Clone, Show)] +#[deriving(Clone, Copy, Show)] pub struct expected_found<T> { pub expected: T, pub found: T } -impl<T:Copy> Copy for expected_found<T> {} - // Data structures used in type unification -#[deriving(Clone, Show)] +#[deriving(Clone, Copy, Show)] pub enum type_err<'tcx> { terr_mismatch, terr_unsafety_mismatch(expected_found<ast::Unsafety>), @@ -1408,15 +1390,13 @@ pub enum type_err<'tcx> { terr_convergence_mismatch(expected_found<bool>) } -impl<'tcx> Copy for type_err<'tcx> {} - /// Bounds suitable for a named type parameter like `A` in `fn foo<A>` /// as well as the existential type parameter in an object type. #[deriving(PartialEq, Eq, Hash, Clone, Show)] pub struct ParamBounds<'tcx> { pub region_bounds: Vec<ty::Region>, pub builtin_bounds: BuiltinBounds, - pub trait_bounds: Vec<Rc<TraitRef<'tcx>>> + pub trait_bounds: Vec<Rc<PolyTraitRef<'tcx>>> } /// Bounds suitable for an existentially quantified type parameter @@ -1424,17 +1404,15 @@ pub struct ParamBounds<'tcx> { /// major difference between this case and `ParamBounds` is that /// general purpose trait bounds are omitted and there must be /// *exactly one* region. -#[deriving(PartialEq, Eq, Hash, Clone, Show)] +#[deriving(Copy, PartialEq, Eq, Hash, Clone, Show)] pub struct ExistentialBounds { pub region_bound: ty::Region, pub builtin_bounds: BuiltinBounds } -impl Copy for ExistentialBounds {} - pub type BuiltinBounds = EnumSet<BuiltinBound>; -#[deriving(Clone, Encodable, PartialEq, Eq, Decodable, Hash, Show)] +#[deriving(Copy, Clone, Encodable, PartialEq, Eq, Decodable, Hash, Show)] #[repr(uint)] pub enum BuiltinBound { BoundSend, @@ -1443,8 +1421,6 @@ pub enum BuiltinBound { BoundSync, } -impl Copy for BuiltinBound {} - pub fn empty_builtin_bounds() -> BuiltinBounds { EnumSet::new() } @@ -1472,57 +1448,49 @@ impl CLike for BuiltinBound { } } -#[deriving(Clone, PartialEq, Eq, Hash)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash)] pub struct TyVid { pub index: uint } -impl Copy for TyVid {} - -#[deriving(Clone, PartialEq, Eq, Hash)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash)] pub struct IntVid { pub index: uint } -impl Copy for IntVid {} - -#[deriving(Clone, PartialEq, Eq, Hash)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash)] pub struct FloatVid { pub index: uint } -impl Copy for FloatVid {} - -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash)] pub struct RegionVid { pub index: uint } -impl Copy for RegionVid {} - -#[deriving(Clone, PartialEq, Eq, Hash)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash)] pub enum InferTy { TyVar(TyVid), IntVar(IntVid), FloatVar(FloatVid), - SkolemizedTy(uint), + + /// A `FreshTy` is one that is generated as a replacement for an + /// unbound type variable. This is convenient for caching etc. See + /// `middle::infer::freshen` for more details. + FreshTy(uint), // FIXME -- once integral fallback is impl'd, we should remove // this type. It's only needed to prevent spurious errors for // integers whose type winds up never being constrained. - SkolemizedIntTy(uint), + FreshIntTy(uint), } -impl Copy for InferTy {} - -#[deriving(Clone, Encodable, Decodable, Eq, Hash, Show)] +#[deriving(Clone, Copy, Encodable, Decodable, Eq, Hash, Show)] pub enum InferRegion { ReVar(RegionVid), ReSkolemized(uint, BoundRegion) } -impl Copy for InferRegion {} - impl cmp::PartialEq for InferRegion { fn eq(&self, other: &InferRegion) -> bool { match ((*self), *other) { @@ -1577,8 +1545,8 @@ impl fmt::Show for InferTy { TyVar(ref v) => v.fmt(f), IntVar(ref v) => v.fmt(f), FloatVar(ref v) => v.fmt(f), - SkolemizedTy(v) => write!(f, "SkolemizedTy({})", v), - SkolemizedIntTy(v) => write!(f, "SkolemizedIntTy({})", v), + FreshTy(v) => write!(f, "FreshTy({})", v), + FreshIntTy(v) => write!(f, "FreshIntTy({})", v), } } } @@ -1657,30 +1625,67 @@ pub enum Predicate<'tcx> { /// Corresponds to `where Foo : Bar<A,B,C>`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` /// would be the parameters in the `TypeSpace`. - Trait(Rc<TraitRef<'tcx>>), + Trait(Rc<PolyTraitRef<'tcx>>), /// where `T1 == T2`. - Equate(/* T1 */ Ty<'tcx>, /* T2 */ Ty<'tcx>), + Equate(PolyEquatePredicate<'tcx>), /// where 'a : 'b - RegionOutlives(/* 'a */ Region, /* 'b */ Region), + RegionOutlives(PolyRegionOutlivesPredicate), /// where T : 'a - TypeOutlives(Ty<'tcx>, Region), + TypeOutlives(PolyTypeOutlivesPredicate<'tcx>), +} + +#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub struct EquatePredicate<'tcx>(pub Ty<'tcx>, pub Ty<'tcx>); // `0 == 1` +pub type PolyEquatePredicate<'tcx> = ty::Binder<EquatePredicate<'tcx>>; + +#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub struct OutlivesPredicate<A,B>(pub A, pub B); // `A : B` +pub type PolyOutlivesPredicate<A,B> = ty::Binder<OutlivesPredicate<A,B>>; +pub type PolyRegionOutlivesPredicate = PolyOutlivesPredicate<ty::Region, ty::Region>; +pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate<Ty<'tcx>, ty::Region>; + +pub trait AsPredicate<'tcx> { + fn as_predicate(&self) -> Predicate<'tcx>; +} + +impl<'tcx> AsPredicate<'tcx> for Rc<PolyTraitRef<'tcx>> { + fn as_predicate(&self) -> Predicate<'tcx> { + Predicate::Trait(self.clone()) + } +} + +impl<'tcx> AsPredicate<'tcx> for PolyEquatePredicate<'tcx> { + fn as_predicate(&self) -> Predicate<'tcx> { + Predicate::Equate(self.clone()) + } +} + +impl<'tcx> AsPredicate<'tcx> for PolyRegionOutlivesPredicate { + fn as_predicate(&self) -> Predicate<'tcx> { + Predicate::RegionOutlives(self.clone()) + } +} + +impl<'tcx> AsPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { + fn as_predicate(&self) -> Predicate<'tcx> { + Predicate::TypeOutlives(self.clone()) + } } impl<'tcx> Predicate<'tcx> { pub fn has_escaping_regions(&self) -> bool { match *self { Predicate::Trait(ref trait_ref) => trait_ref.has_escaping_regions(), - Predicate::Equate(a, b) => (ty::type_has_escaping_regions(a) || - ty::type_has_escaping_regions(b)), - Predicate::RegionOutlives(a, b) => a.escapes_depth(0) || b.escapes_depth(0), - Predicate::TypeOutlives(a, b) => ty::type_has_escaping_regions(a) || b.escapes_depth(0), + Predicate::Equate(ref p) => p.has_escaping_regions(), + Predicate::RegionOutlives(ref p) => p.has_escaping_regions(), + Predicate::TypeOutlives(ref p) => p.has_escaping_regions(), } } - pub fn to_trait(&self) -> Option<Rc<TraitRef<'tcx>>> { + pub fn to_trait(&self) -> Option<Rc<PolyTraitRef<'tcx>>> { match *self { Predicate::Trait(ref t) => { Some(t.clone()) @@ -1748,14 +1753,6 @@ impl<'tcx> TraitRef<'tcx> { // associated types. self.substs.types.as_slice() } - - pub fn has_escaping_regions(&self) -> bool { - self.substs.has_regions_escaping_depth(1) - } - - pub fn has_bound_regions(&self) -> bool { - self.substs.has_regions_escaping_depth(0) - } } /// When type checking, we use the `ParameterEnvironment` to track @@ -1943,15 +1940,13 @@ pub struct UnboxedClosure<'tcx> { pub kind: UnboxedClosureKind, } -#[deriving(Clone, PartialEq, Eq, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Show)] pub enum UnboxedClosureKind { FnUnboxedClosureKind, FnMutUnboxedClosureKind, FnOnceUnboxedClosureKind, } -impl Copy for UnboxedClosureKind {} - impl UnboxedClosureKind { pub fn trait_did(&self, cx: &ctxt) -> ast::DefId { let result = match *self { @@ -2160,7 +2155,7 @@ impl FlagComputation { &ty_trait(box TyTrait { ref principal, ref bounds }) => { let mut computation = FlagComputation::new(); - computation.add_substs(&principal.substs); + computation.add_substs(principal.substs()); self.add_bound_computation(&computation); self.add_bounds(bounds); @@ -2208,12 +2203,12 @@ impl FlagComputation { } } - fn add_fn_sig(&mut self, fn_sig: &FnSig) { + fn add_fn_sig(&mut self, fn_sig: &PolyFnSig) { let mut computation = FlagComputation::new(); - computation.add_tys(fn_sig.inputs[]); + computation.add_tys(fn_sig.0.inputs[]); - if let ty::FnConverging(output) = fn_sig.output { + if let ty::FnConverging(output) = fn_sig.0.output { computation.add_ty(output); } @@ -2356,17 +2351,17 @@ pub fn mk_ctor_fn<'tcx>(cx: &ctxt<'tcx>, BareFnTy { unsafety: ast::Unsafety::Normal, abi: abi::Rust, - sig: FnSig { + sig: ty::Binder(FnSig { inputs: input_args, output: ty::FnConverging(output), variadic: false - } + }) }) } pub fn mk_trait<'tcx>(cx: &ctxt<'tcx>, - principal: ty::TraitRef<'tcx>, + principal: ty::PolyTraitRef<'tcx>, bounds: ExistentialBounds) -> Ty<'tcx> { // take a copy of substs so that we own the vectors inside @@ -2439,7 +2434,7 @@ pub fn maybe_walk_ty<'tcx>(ty: Ty<'tcx>, f: |Ty<'tcx>| -> bool) { maybe_walk_ty(tm.ty, f); } ty_trait(box TyTrait { ref principal, .. }) => { - for subty in principal.substs.types.iter() { + for subty in principal.substs().types.iter() { maybe_walk_ty(*subty, |x| f(x)); } } @@ -2452,14 +2447,14 @@ pub fn maybe_walk_ty<'tcx>(ty: Ty<'tcx>, f: |Ty<'tcx>| -> bool) { } ty_tup(ref ts) => { for tt in ts.iter() { maybe_walk_ty(*tt, |x| f(x)); } } ty_bare_fn(ref ft) => { - for a in ft.sig.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); } - if let ty::FnConverging(output) = ft.sig.output { + for a in ft.sig.0.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); } + if let ty::FnConverging(output) = ft.sig.0.output { maybe_walk_ty(output, f); } } ty_closure(ref ft) => { - for a in ft.sig.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); } - if let ty::FnConverging(output) = ft.sig.output { + for a in ft.sig.0.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); } + if let ty::FnConverging(output) = ft.sig.0.output { maybe_walk_ty(output, f); } } @@ -2732,13 +2727,11 @@ pub fn type_needs_unwind_cleanup<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool { /// The reason we compute type contents and not kinds is that it is /// easier for me (nmatsakis) to think about what is contained within /// a type than to think about what is *not* contained within a type. -#[deriving(Clone)] +#[deriving(Clone, Copy)] pub struct TypeContents { pub bits: u64 } -impl Copy for TypeContents {} - macro_rules! def_type_content_sets { (mod $mname:ident { $($name:ident = $bits:expr),+ }) => { #[allow(non_snake_case)] @@ -2961,7 +2954,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { } // Scalar and unique types are sendable, and durable - ty_infer(ty::SkolemizedIntTy(_)) | + ty_infer(ty::FreshIntTy(_)) | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | ty_bare_fn(_) | ty::ty_char => { TC::None @@ -3182,7 +3175,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { fn kind_bounds_to_contents<'tcx>(cx: &ctxt<'tcx>, bounds: BuiltinBounds, - traits: &[Rc<TraitRef<'tcx>>]) + traits: &[Rc<PolyTraitRef<'tcx>>]) -> TypeContents { let _i = indenter(); let mut tc = TC::All; @@ -3198,7 +3191,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { // those inherited from traits with builtin-kind-supertraits. fn each_inherited_builtin_bound<'tcx, F>(cx: &ctxt<'tcx>, bounds: BuiltinBounds, - traits: &[Rc<TraitRef<'tcx>>], + traits: &[Rc<PolyTraitRef<'tcx>>], mut f: F) where F: FnMut(BuiltinBound), { @@ -3207,7 +3200,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { } each_bound_trait_and_supertraits(cx, traits, |trait_ref| { - let trait_def = lookup_trait_def(cx, trait_ref.def_id); + let trait_def = lookup_trait_def(cx, trait_ref.def_id()); for bound in trait_def.bounds.builtin_bounds.iter() { f(bound); } @@ -3380,15 +3373,13 @@ pub fn is_instantiable<'tcx>(cx: &ctxt<'tcx>, r_ty: Ty<'tcx>) -> bool { /// /// The ordering of the cases is significant. They are sorted so that cmp::max /// will keep the "more erroneous" of two values. -#[deriving(PartialOrd, Ord, Eq, PartialEq, Show)] +#[deriving(Copy, PartialOrd, Ord, Eq, PartialEq, Show)] pub enum Representability { Representable, ContainsRecursive, SelfRecursive, } -impl Copy for Representability {} - /// Check whether a type is representable. This means it cannot contain unboxed /// structural recursion. This check is needed for structs and enums. pub fn is_type_representable<'tcx>(cx: &ctxt<'tcx>, sp: Span, ty: Ty<'tcx>) @@ -3567,10 +3558,10 @@ pub fn type_is_integral(ty: Ty) -> bool { } } -pub fn type_is_skolemized(ty: Ty) -> bool { +pub fn type_is_fresh(ty: Ty) -> bool { match ty.sty { - ty_infer(SkolemizedTy(_)) => true, - ty_infer(SkolemizedIntTy(_)) => true, + ty_infer(FreshTy(_)) => true, + ty_infer(FreshIntTy(_)) => true, _ => false } } @@ -3828,15 +3819,15 @@ pub fn node_id_item_substs<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId) -> ItemSubsts pub fn fn_is_variadic(fty: Ty) -> bool { match fty.sty { - ty_bare_fn(ref f) => f.sig.variadic, - ty_closure(ref f) => f.sig.variadic, + ty_bare_fn(ref f) => f.sig.0.variadic, + ty_closure(ref f) => f.sig.0.variadic, ref s => { panic!("fn_is_variadic() called on non-fn type: {}", s) } } } -pub fn ty_fn_sig<'tcx>(fty: Ty<'tcx>) -> &'tcx FnSig<'tcx> { +pub fn ty_fn_sig<'tcx>(fty: Ty<'tcx>) -> &'tcx PolyFnSig<'tcx> { match fty.sty { ty_bare_fn(ref f) => &f.sig, ty_closure(ref f) => &f.sig, @@ -3857,7 +3848,7 @@ pub fn ty_fn_abi(fty: Ty) -> abi::Abi { // Type accessors for substructures of types pub fn ty_fn_args<'tcx>(fty: Ty<'tcx>) -> &'tcx [Ty<'tcx>] { - ty_fn_sig(fty).inputs.as_slice() + ty_fn_sig(fty).0.inputs.as_slice() } pub fn ty_closure_store(fty: Ty) -> TraitStore { @@ -3876,8 +3867,8 @@ pub fn ty_closure_store(fty: Ty) -> TraitStore { pub fn ty_fn_ret<'tcx>(fty: Ty<'tcx>) -> FnOutput<'tcx> { match fty.sty { - ty_bare_fn(ref f) => f.sig.output, - ty_closure(ref f) => f.sig.output, + ty_bare_fn(ref f) => f.sig.0.output, + ty_closure(ref f) => f.sig.0.output, ref s => { panic!("ty_fn_ret() called on non-fn type: {}", s) } @@ -4165,6 +4156,7 @@ pub fn expr_is_lval(tcx: &ctxt, e: &ast::Expr) -> bool { /// two kinds of rvalues is an artifact of trans which reflects how we will /// generate code for that kind of expression. See trans/expr.rs for more /// information. +#[deriving(Copy)] pub enum ExprKind { LvalueExpr, RvalueDpsExpr, @@ -4172,8 +4164,6 @@ pub enum ExprKind { RvalueStmtExpr } -impl Copy for ExprKind {} - pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { if tcx.method_map.borrow().contains_key(&MethodCall::expr(expr.id)) { // Overloaded operations are generally calls, and hence they are @@ -4393,7 +4383,7 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String { ty_bare_fn(_) => "extern fn".to_string(), ty_closure(_) => "fn".to_string(), ty_trait(ref inner) => { - format!("trait {}", item_path_str(cx, inner.principal.def_id)) + format!("trait {}", item_path_str(cx, inner.principal.def_id())) } ty_struct(id, _) => { format!("struct {}", item_path_str(cx, id)) @@ -4403,8 +4393,8 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String { ty_infer(TyVar(_)) => "inferred type".to_string(), ty_infer(IntVar(_)) => "integral variable".to_string(), ty_infer(FloatVar(_)) => "floating-point variable".to_string(), - ty_infer(SkolemizedTy(_)) => "skolemized type".to_string(), - ty_infer(SkolemizedIntTy(_)) => "skolemized integral type".to_string(), + ty_infer(FreshTy(_)) => "skolemized type".to_string(), + ty_infer(FreshIntTy(_)) => "skolemized integral type".to_string(), ty_param(ref p) => { if p.space == subst::SelfSpace { "Self".to_string() @@ -4728,15 +4718,13 @@ pub fn associated_type_parameter_index(cx: &ctxt, cx.sess.bug("couldn't find associated type parameter index") } -#[deriving(PartialEq, Eq)] +#[deriving(Copy, PartialEq, Eq)] pub struct AssociatedTypeInfo { pub def_id: ast::DefId, pub index: uint, pub name: ast::Name, } -impl Copy for AssociatedTypeInfo {} - impl PartialOrd for AssociatedTypeInfo { fn partial_cmp(&self, other: &AssociatedTypeInfo) -> Option<Ordering> { Some(self.index.cmp(&other.index)) @@ -4770,7 +4758,8 @@ pub fn impl_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) ast::ItemImpl(_, _, ref opt_trait, _, _) => { match opt_trait { &Some(ref t) => { - Some(ty::node_id_to_trait_ref(cx, t.ref_id)) + let trait_ref = ty::node_id_to_trait_ref(cx, t.ref_id); + Some(trait_ref) } &None => None } @@ -4813,7 +4802,7 @@ pub fn try_add_builtin_trait( pub fn ty_to_def_id(ty: Ty) -> Option<ast::DefId> { match ty.sty { ty_trait(ref tt) => - Some(tt.principal.def_id), + Some(tt.principal.def_id()), ty_struct(id, _) | ty_enum(id, _) | ty_unboxed_closure(id, _, _) => @@ -4915,13 +4904,12 @@ pub fn item_path_str(cx: &ctxt, id: ast::DefId) -> String { with_path(cx, id, |path| ast_map::path_to_string(path)).to_string() } +#[deriving(Copy)] pub enum DtorKind { NoDtor, TraitDtor(DefId, bool) } -impl Copy for DtorKind {} - impl DtorKind { pub fn is_present(&self) -> bool { match *self { @@ -5073,10 +5061,10 @@ pub fn lookup_trait_def<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) /// Given a reference to a trait, returns the "superbounds" declared /// on the trait, with appropriate substitutions applied. pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, - trait_ref: &TraitRef<'tcx>) + trait_ref: &PolyTraitRef<'tcx>) -> Vec<ty::Predicate<'tcx>> { - let trait_def = lookup_trait_def(tcx, trait_ref.def_id); + let trait_def = lookup_trait_def(tcx, trait_ref.def_id()); debug!("bounds_for_trait_ref(trait_def={}, trait_ref={})", trait_def.repr(tcx), trait_ref.repr(tcx)); @@ -5149,8 +5137,9 @@ pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, trait_def.bounds.trait_bounds .iter() .map(|bound_trait_ref| { - ty::TraitRef::new(bound_trait_ref.def_id, - bound_trait_ref.substs.subst(tcx, &trait_ref.substs)) + ty::Binder( + ty::TraitRef::new(bound_trait_ref.def_id(), + bound_trait_ref.substs().subst(tcx, trait_ref.substs()))) }) .map(|bound_trait_ref| Rc::new(bound_trait_ref)) .collect(); @@ -5161,9 +5150,9 @@ pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, // The region bounds and builtin bounds do not currently introduce // binders so we can just substitute in a straightforward way here. let region_bounds = - trait_def.bounds.region_bounds.subst(tcx, &trait_ref.substs); + trait_def.bounds.region_bounds.subst(tcx, trait_ref.substs()); let builtin_bounds = - trait_def.bounds.builtin_bounds.subst(tcx, &trait_ref.substs); + trait_def.bounds.builtin_bounds.subst(tcx, trait_ref.substs()); let bounds = ty::ParamBounds { trait_bounds: trait_bounds, @@ -5183,18 +5172,21 @@ pub fn predicates<'tcx>( let mut vec = Vec::new(); for builtin_bound in bounds.builtin_bounds.iter() { - match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) { - Ok(trait_ref) => { vec.push(Predicate::Trait(trait_ref)); } + match traits::poly_trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) { + Ok(trait_ref) => { vec.push(trait_ref.as_predicate()); } Err(ErrorReported) => { } } } for ®ion_bound in bounds.region_bounds.iter() { - vec.push(Predicate::TypeOutlives(param_ty, region_bound)); + // account for the binder being introduced below; no need to shift `param_ty` + // because, at present at least, it can only refer to early-bound regions + let region_bound = ty_fold::shift_region(region_bound, 1); + vec.push(ty::Binder(ty::OutlivesPredicate(param_ty, region_bound)).as_predicate()); } for bound_trait_ref in bounds.trait_bounds.iter() { - vec.push(Predicate::Trait((*bound_trait_ref).clone())); + vec.push(bound_trait_ref.as_predicate()); } vec @@ -5335,14 +5327,13 @@ pub fn tup_fields<'tcx>(v: &[Ty<'tcx>]) -> Vec<field<'tcx>> { }).collect() } +#[deriving(Copy)] pub struct UnboxedClosureUpvar<'tcx> { pub def: def::Def, pub span: Span, pub ty: Ty<'tcx>, } -impl<'tcx> Copy for UnboxedClosureUpvar<'tcx> {} - // Returns a list of `UnboxedClosureUpvar`s for each upvar. pub fn unboxed_closure_upvars<'tcx>(tcx: &ctxt<'tcx>, closure_id: ast::DefId, substs: &Substs<'tcx>) -> Vec<UnboxedClosureUpvar<'tcx>> { @@ -5483,18 +5474,6 @@ pub fn normalize_ty<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { subst::Substs { regions: subst::ErasedRegions, types: substs.types.fold_with(self) } } - - fn fold_fn_sig(&mut self, - sig: &ty::FnSig<'tcx>) - -> ty::FnSig<'tcx> { - // The binder-id is only relevant to bound regions, which - // are erased at trans time. - ty::FnSig { - inputs: sig.inputs.fold_with(self), - output: sig.output.fold_with(self), - variadic: sig.variadic, - } - } } } @@ -5545,10 +5524,10 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> uint { // relation on the supertraits from each bounded trait's constraint // list. pub fn each_bound_trait_and_supertraits<'tcx, F>(tcx: &ctxt<'tcx>, - bounds: &[Rc<TraitRef<'tcx>>], + bounds: &[Rc<PolyTraitRef<'tcx>>], mut f: F) -> bool where - F: FnMut(Rc<TraitRef<'tcx>>) -> bool, + F: FnMut(Rc<PolyTraitRef<'tcx>>) -> bool, { for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { if !f(bound_trait_ref) { @@ -5559,18 +5538,18 @@ pub fn each_bound_trait_and_supertraits<'tcx, F>(tcx: &ctxt<'tcx>, } pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>, - opt_principal: Option<&TraitRef<'tcx>>, // None for boxed closures + opt_principal: Option<&PolyTraitRef<'tcx>>, // None for closures others: BuiltinBounds) -> Vec<ty::Region> { // Since we don't actually *know* the self type for an object, // this "open(err)" serves as a kind of dummy standin -- basically // a skolemized type. - let open_ty = ty::mk_infer(tcx, SkolemizedTy(0)); + let open_ty = ty::mk_infer(tcx, FreshTy(0)); let opt_trait_ref = opt_principal.map_or(Vec::new(), |principal| { - let substs = principal.substs.with_self_ty(open_ty); - vec!(Rc::new(ty::TraitRef::new(principal.def_id, substs))) + let substs = principal.substs().with_self_ty(open_ty); + vec!(Rc::new(ty::Binder(ty::TraitRef::new(principal.def_id(), substs)))) }); let param_bounds = ty::ParamBounds { @@ -5583,19 +5562,27 @@ pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>, ty::required_region_bounds(tcx, open_ty, predicates) } -/// Given a type which must meet the builtin bounds and trait bounds, returns a set of lifetimes -/// which the type must outlive. +/// Given a set of predicates that apply to an object type, returns +/// the region bounds that the (erased) `Self` type must +/// outlive. Precisely *because* the `Self` type is erased, the +/// parameter `erased_self_ty` must be supplied to indicate what type +/// has been used to represent `Self` in the predicates +/// themselves. This should really be a unique type; `FreshTy(0)` is a +/// popular choice (see `object_region_bounds` above). /// -/// Requires that trait definitions have been processed. +/// Requires that trait definitions have been processed so that we can +/// elaborate predicates and walk supertraits. pub fn required_region_bounds<'tcx>(tcx: &ctxt<'tcx>, - param_ty: Ty<'tcx>, + erased_self_ty: Ty<'tcx>, predicates: Vec<ty::Predicate<'tcx>>) -> Vec<ty::Region> { - debug!("required_region_bounds(param_ty={}, predicates={})", - param_ty.repr(tcx), + debug!("required_region_bounds(erased_self_ty={}, predicates={})", + erased_self_ty.repr(tcx), predicates.repr(tcx)); + assert!(!erased_self_ty.has_escaping_regions()); + traits::elaborate_predicates(tcx, predicates) .filter_map(|predicate| { match predicate { @@ -5604,9 +5591,22 @@ pub fn required_region_bounds<'tcx>(tcx: &ctxt<'tcx>, ty::Predicate::RegionOutlives(..) => { None } - ty::Predicate::TypeOutlives(t, r) => { - if t == param_ty { - Some(r) + ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => { + // Search for a bound of the form `erased_self_ty + // : 'a`, but be wary of something like `for<'a> + // erased_self_ty : 'a` (we interpret a + // higher-ranked bound like that as 'static, + // though at present the code in `fulfill.rs` + // considers such bounds to be unsatisfiable, so + // it's kind of a moot point since you could never + // construct such an object, but this seems + // correct even if that code changes). + if t == erased_self_ty && !r.has_escaping_regions() { + if r.has_escaping_regions() { + Some(ty::ReStatic) + } else { + Some(r) + } } else { None } @@ -5824,12 +5824,12 @@ pub fn trait_item_of_item(tcx: &ctxt, def_id: ast::DefId) /// Creates a hash of the type `Ty` which will be the same no matter what crate /// context it's calculated within. This is used by the `type_id` intrinsic. -pub fn hash_crate_independent(tcx: &ctxt, ty: Ty, svh: &Svh) -> u64 { +pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) -> u64 { let mut state = sip::SipState::new(); helper(tcx, ty, svh, &mut state); return state.result(); - fn helper(tcx: &ctxt, ty: Ty, svh: &Svh, state: &mut sip::SipState) { + fn helper<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh, state: &mut sip::SipState) { macro_rules! byte( ($b:expr) => { ($b as u8).hash(state) } ); macro_rules! hash( ($e:expr) => { $e.hash(state) } ); @@ -5862,7 +5862,7 @@ pub fn hash_crate_independent(tcx: &ctxt, ty: Ty, svh: &Svh) -> u64 { let mt = |state: &mut sip::SipState, mt: mt| { mt.mutbl.hash(state); }; - let fn_sig = |state: &mut sip::SipState, sig: &FnSig| { + let fn_sig = |state: &mut sip::SipState, sig: &Binder<FnSig<'tcx>>| { let sig = anonymize_late_bound_regions(tcx, sig); for a in sig.inputs.iter() { helper(tcx, *a, svh, state); } if let ty::FnConverging(output) = sig.output { @@ -5938,7 +5938,7 @@ pub fn hash_crate_independent(tcx: &ctxt, ty: Ty, svh: &Svh) -> u64 { } ty_trait(box TyTrait { ref principal, bounds }) => { byte!(17); - did(state, principal.def_id); + did(state, principal.def_id()); hash!(bounds); let principal = anonymize_late_bound_regions(tcx, principal); @@ -6033,7 +6033,7 @@ pub fn construct_parameter_environment<'tcx>( // let bounds = generics.to_bounds(tcx, &free_substs); - let bounds = liberate_late_bound_regions(tcx, free_id_scope, &bind(bounds)).value; + let bounds = liberate_late_bound_regions(tcx, free_id_scope, &ty::Binder(bounds)); // // Compute region bounds. For now, these relations are stored in a @@ -6088,16 +6088,20 @@ pub fn construct_parameter_environment<'tcx>( Predicate::Trait(..) | Predicate::Equate(..) | Predicate::TypeOutlives(..) => { // No region bounds here } - Predicate::RegionOutlives(ty::ReFree(fr_a), ty::ReFree(fr_b)) => { - // Record that `'a:'b`. Or, put another way, `'b <= 'a`. - tcx.region_maps.relate_free_regions(fr_b, fr_a); - } - Predicate::RegionOutlives(r_a, r_b) => { - // All named regions are instantiated with free regions. - tcx.sess.bug( - format!("record_region_bounds: non free region: {} / {}", - r_a.repr(tcx), - r_b.repr(tcx)).as_slice()); + Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => { + match (r_a, r_b) { + (ty::ReFree(fr_a), ty::ReFree(fr_b)) => { + // Record that `'a:'b`. Or, put another way, `'b <= 'a`. + tcx.region_maps.relate_free_regions(fr_b, fr_a); + } + _ => { + // All named regions are instantiated with free regions. + tcx.sess.bug( + format!("record_region_bounds: non free region: {} / {}", + r_a.repr(tcx), + r_b.repr(tcx)).as_slice()); + } + } } } } @@ -6178,7 +6182,7 @@ impl<'tcx> mc::Typer<'tcx> for ty::ctxt<'tcx> { } /// The category of explicit self. -#[deriving(Clone, Eq, PartialEq, Show)] +#[deriving(Clone, Copy, Eq, PartialEq, Show)] pub enum ExplicitSelfCategory { StaticExplicitSelfCategory, ByValueExplicitSelfCategory, @@ -6186,8 +6190,6 @@ pub enum ExplicitSelfCategory { ByBoxExplicitSelfCategory, } -impl Copy for ExplicitSelfCategory {} - /// Pushes all the lifetimes in the given type onto the given list. A /// "lifetime in a type" is a lifetime specified by a reference or a lifetime /// in a list of type substitutions. This does *not* traverse into nominal @@ -6200,7 +6202,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>, accumulator.push(region) } ty_trait(ref t) => { - accumulator.push_all(t.principal.substs.regions().as_slice()); + accumulator.push_all(t.principal.substs().regions().as_slice()); } ty_enum(_, ref substs) | ty_struct(_, ref substs) => { @@ -6248,7 +6250,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>, } /// A free variable referred to in a function. -#[deriving(Encodable, Decodable)] +#[deriving(Copy, Encodable, Decodable)] pub struct Freevar { /// The variable being accessed free. pub def: def::Def, @@ -6257,8 +6259,6 @@ pub struct Freevar { pub span: Span } -impl Copy for Freevar {} - pub type FreevarMap = NodeMap<Vec<Freevar>>; pub type CaptureModeMap = NodeMap<ast::CaptureClause>; @@ -6289,25 +6289,35 @@ impl<'tcx> AutoDerefRef<'tcx> { /// Replace any late-bound regions bound in `value` with free variants attached to scope-id /// `scope_id`. -pub fn liberate_late_bound_regions<'tcx, HR>( +pub fn liberate_late_bound_regions<'tcx, T>( tcx: &ty::ctxt<'tcx>, scope: region::CodeExtent, - value: &HR) - -> HR - where HR : HigherRankedFoldable<'tcx> + value: &Binder<T>) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> { replace_late_bound_regions( tcx, value, |br, _| ty::ReFree(ty::FreeRegion{scope: scope, bound_region: br})).0 } +pub fn count_late_bound_regions<'tcx, T>( + tcx: &ty::ctxt<'tcx>, + value: &Binder<T>) + -> uint + where T : TypeFoldable<'tcx> + Repr<'tcx> +{ + let (_, skol_map) = replace_late_bound_regions(tcx, value, |_, _| ty::ReStatic); + skol_map.len() +} + /// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also /// method lookup and a few other places where precise region relationships are not required. -pub fn erase_late_bound_regions<'tcx, HR>( +pub fn erase_late_bound_regions<'tcx, T>( tcx: &ty::ctxt<'tcx>, - value: &HR) - -> HR - where HR : HigherRankedFoldable<'tcx> + value: &Binder<T>) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> { replace_late_bound_regions(tcx, value, |_, _| ty::ReStatic).0 } @@ -6320,8 +6330,12 @@ pub fn erase_late_bound_regions<'tcx, HR>( /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become /// structurally identical. For example, `for<'a, 'b> fn(&'a int, &'b int)` and /// `for<'a, 'b> fn(&'b int, &'a int)` will become identical after anonymization. -pub fn anonymize_late_bound_regions<'tcx, HR>(tcx: &ctxt<'tcx>, sig: &HR) -> HR - where HR: HigherRankedFoldable<'tcx> { +pub fn anonymize_late_bound_regions<'tcx, T>( + tcx: &ctxt<'tcx>, + sig: &Binder<T>) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx>, +{ let mut counter = 0; replace_late_bound_regions(tcx, sig, |_, db| { counter += 1; @@ -6330,39 +6344,35 @@ pub fn anonymize_late_bound_regions<'tcx, HR>(tcx: &ctxt<'tcx>, sig: &HR) -> HR } /// Replaces the late-bound-regions in `value` that are bound by `value`. -pub fn replace_late_bound_regions<'tcx, HR, F>( +pub fn replace_late_bound_regions<'tcx, T, F>( tcx: &ty::ctxt<'tcx>, - value: &HR, + binder: &Binder<T>, mut mapf: F) --> (HR, FnvHashMap<ty::BoundRegion, ty::Region>) where - HR : HigherRankedFoldable<'tcx>, - F: FnMut(BoundRegion, DebruijnIndex) -> ty::Region, + -> (T, FnvHashMap<ty::BoundRegion,ty::Region>) + where T : TypeFoldable<'tcx> + Repr<'tcx>, + F : FnMut(BoundRegion, DebruijnIndex) -> ty::Region, { - debug!("replace_late_bound_regions({})", value.repr(tcx)); + debug!("replace_late_bound_regions({})", binder.repr(tcx)); let mut map = FnvHashMap::new(); - let value = { - let mut f = ty_fold::RegionFolder::new(tcx, |region, current_depth| { - debug!("region={}", region.repr(tcx)); - match region { - ty::ReLateBound(debruijn, br) if debruijn.depth == current_depth => { - * match map.entry(br) { - Vacant(entry) => entry.set(mapf(br, debruijn)), - Occupied(entry) => entry.into_mut(), - } - } - _ => { - region + + // Note: fold the field `0`, not the binder, so that late-bound + // regions bound by `binder` are considered free. + let value = ty_fold::fold_regions(tcx, &binder.0, |region, current_depth| { + debug!("region={}", region.repr(tcx)); + match region { + ty::ReLateBound(debruijn, br) if debruijn.depth == current_depth => { + * match map.entry(br) { + Vacant(entry) => entry.set(mapf(br, debruijn)), + Occupied(entry) => entry.into_mut(), } } - }); + _ => { + region + } + } + }); - // Note: use `fold_contents` not `fold_with`. If we used - // `fold_with`, it would consider the late-bound regions bound - // by `value` to be bound, but we want to consider them as - // `free`. - value.fold_contents(&mut f) - }; debug!("resulting map: {} value: {}", map, value.repr(tcx)); (value, map) } @@ -6378,8 +6388,6 @@ impl DebruijnIndex { } } -impl Copy for DebruijnIndex {} - impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { match *self { @@ -6440,9 +6448,9 @@ impl<'tcx> Repr<'tcx> for ty::Predicate<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { match *self { Predicate::Trait(ref a) => a.repr(tcx), - Predicate::Equate(a, b) => format!("Equate({},{})", a.repr(tcx), b.repr(tcx)), - Predicate::RegionOutlives(a, b) => format!("Outlives({}:{})", a.repr(tcx), b.repr(tcx)), - Predicate::TypeOutlives(a, b) => format!("Outlives({}:{})", a.repr(tcx), b.repr(tcx)), + Predicate::Equate(ref pair) => format!("Equate({})", pair.repr(tcx)), + Predicate::RegionOutlives(ref pair) => format!("Outlives({})", pair.repr(tcx)), + Predicate::TypeOutlives(ref pair) => format!("Outlives({})", pair.repr(tcx)), } } } @@ -6498,14 +6506,13 @@ pub fn make_substs_for_receiver_types<'tcx>(tcx: &ty::ctxt<'tcx>, trait_ref.substs.clone().with_method(meth_tps, meth_regions) } +#[deriving(Copy)] pub enum CopyImplementationError { FieldDoesNotImplementCopy(ast::Name), VariantDoesNotImplementCopy(ast::Name), TypeIsStructural, } -impl Copy for CopyImplementationError {} - pub fn can_type_implement_copy<'tcx>(tcx: &ctxt<'tcx>, self_type: Ty<'tcx>, param_env: &ParameterEnvironment<'tcx>) @@ -6538,3 +6545,49 @@ pub fn can_type_implement_copy<'tcx>(tcx: &ctxt<'tcx>, Ok(()) } + +pub trait RegionEscape { + fn has_escaping_regions(&self) -> bool { + self.has_regions_escaping_depth(0) + } + + fn has_regions_escaping_depth(&self, depth: uint) -> bool; +} + +impl<'tcx> RegionEscape for Ty<'tcx> { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + ty::type_escapes_depth(*self, depth) + } +} + +impl RegionEscape for Region { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.escapes_depth(depth) + } +} + +impl<'tcx> RegionEscape for TraitRef<'tcx> { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) && + self.substs.regions().iter().any(|t| t.has_regions_escaping_depth(depth)) + } +} + +impl<'tcx,T:RegionEscape> RegionEscape for Binder<T> { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.0.has_regions_escaping_depth(depth + 1) + } +} + +impl<'tcx> RegionEscape for EquatePredicate<'tcx> { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth) + } +} + +impl<T:RegionEscape,U:RegionEscape> RegionEscape for OutlivesPredicate<T,U> { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth) + } +} + diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 4877512ce58..71e42a9dbb3 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -93,8 +93,8 @@ pub trait TypeFolder<'tcx> { } fn fold_fn_sig(&mut self, - sig: &ty::FnSig<'tcx>) - -> ty::FnSig<'tcx> { + sig: &ty::FnSig<'tcx>) + -> ty::FnSig<'tcx> { super_fold_fn_sig(self, sig) } @@ -183,7 +183,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> { impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> { fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Binder<T> { folder.enter_region_binder(); - let result = ty::bind(self.value.fold_with(folder)); + let result = ty::Binder(self.0.fold_with(folder)); folder.exit_region_binder(); result } @@ -409,15 +409,12 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref a) => ty::Predicate::Trait(a.fold_with(folder)), - ty::Predicate::Equate(ref a, ref b) => - ty::Predicate::Equate(a.fold_with(folder), - b.fold_with(folder)), - ty::Predicate::RegionOutlives(ref a, ref b) => - ty::Predicate::RegionOutlives(a.fold_with(folder), - b.fold_with(folder)), - ty::Predicate::TypeOutlives(ref a, ref b) => - ty::Predicate::TypeOutlives(a.fold_with(folder), - b.fold_with(folder)), + ty::Predicate::Equate(ref binder) => + ty::Predicate::Equate(binder.fold_with(folder)), + ty::Predicate::RegionOutlives(ref binder) => + ty::Predicate::RegionOutlives(binder.fold_with(folder)), + ty::Predicate::TypeOutlives(ref binder) => + ty::Predicate::TypeOutlives(binder.fold_with(folder)), } } } @@ -501,6 +498,23 @@ impl<'tcx> TypeFoldable<'tcx> for traits::VtableParamData<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> { + fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::EquatePredicate<'tcx> { + ty::EquatePredicate(self.0.fold_with(folder), + self.1.fold_with(folder)) + } +} + +impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate<T,U> + where T : TypeFoldable<'tcx>, + U : TypeFoldable<'tcx>, +{ + fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::OutlivesPredicate<T,U> { + ty::OutlivesPredicate(self.0.fold_with(folder), + self.1.fold_with(folder)) + } +} + /////////////////////////////////////////////////////////////////////////// // "super" routines: these are the default implementations for TypeFolder. // @@ -533,16 +547,6 @@ pub fn super_fold_fn_sig<'tcx, T: TypeFolder<'tcx>>(this: &mut T, sig: &ty::FnSig<'tcx>) -> ty::FnSig<'tcx> { - this.enter_region_binder(); - let result = super_fold_fn_sig_contents(this, sig); - this.exit_region_binder(); - result -} - -pub fn super_fold_fn_sig_contents<'tcx, T: TypeFolder<'tcx>>(this: &mut T, - sig: &ty::FnSig<'tcx>) - -> ty::FnSig<'tcx> -{ ty::FnSig { inputs: sig.inputs.fold_with(this), output: sig.output.fold_with(this), variadic: sig.variadic } @@ -584,16 +588,6 @@ pub fn super_fold_trait_ref<'tcx, T: TypeFolder<'tcx>>(this: &mut T, t: &ty::TraitRef<'tcx>) -> ty::TraitRef<'tcx> { - this.enter_region_binder(); - let result = super_fold_trait_ref_contents(this, t); - this.exit_region_binder(); - result -} - -pub fn super_fold_trait_ref_contents<'tcx, T: TypeFolder<'tcx>>(this: &mut T, - t: &ty::TraitRef<'tcx>) - -> ty::TraitRef<'tcx> -{ ty::TraitRef { def_id: t.def_id, substs: t.substs.fold_with(this), @@ -707,40 +701,6 @@ pub fn super_fold_item_substs<'tcx, T: TypeFolder<'tcx>>(this: &mut T, } /////////////////////////////////////////////////////////////////////////// -// Higher-ranked things - -/// Designates a "binder" for late-bound regions. -pub trait HigherRankedFoldable<'tcx>: Repr<'tcx> { - /// Folds the contents of `self`, ignoring the region binder created - /// by `self`. - fn fold_contents<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self; -} - -impl<'tcx> HigherRankedFoldable<'tcx> for ty::FnSig<'tcx> { - fn fold_contents<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::FnSig<'tcx> { - super_fold_fn_sig_contents(folder, self) - } -} - -impl<'tcx> HigherRankedFoldable<'tcx> for ty::TraitRef<'tcx> { - fn fold_contents<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TraitRef<'tcx> { - super_fold_trait_ref_contents(folder, self) - } -} - -impl<'tcx, T:TypeFoldable<'tcx>+Repr<'tcx>> HigherRankedFoldable<'tcx> for ty::Binder<T> { - fn fold_contents<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Binder<T> { - ty::bind(self.value.fold_with(folder)) - } -} - -impl<'tcx, T:HigherRankedFoldable<'tcx>> HigherRankedFoldable<'tcx> for Rc<T> { - fn fold_contents<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Rc<T> { - Rc::new((**self).fold_contents(folder)) - } -} - -/////////////////////////////////////////////////////////////////////////// // Some sample folders pub struct BottomUpFolder<'a, 'tcx: 'a, F> where F: FnMut(Ty<'tcx>) -> Ty<'tcx> { @@ -751,7 +711,7 @@ pub struct BottomUpFolder<'a, 'tcx: 'a, F> where F: FnMut(Ty<'tcx>) -> Ty<'tcx> impl<'a, 'tcx, F> TypeFolder<'tcx> for BottomUpFolder<'a, 'tcx, F> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>, { - fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.tcx } + fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { let t1 = super_fold_ty(self, ty); @@ -770,18 +730,17 @@ impl<'a, 'tcx, F> TypeFolder<'tcx> for BottomUpFolder<'a, 'tcx, F> where /// regions (aka "lifetimes") that are bound within a type are not /// visited by this folder; only regions that occur free will be /// visited by `fld_r`. -/// -/// (The distinction between "free" and "bound" is represented by -/// keeping track of each `FnSig` in the lexical context of the -/// current position of the fold.) -pub struct RegionFolder<'a, 'tcx: 'a, F> where F: FnMut(ty::Region, uint) -> ty::Region { + +pub struct RegionFolder<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, current_depth: uint, - fld_r: F, + fld_r: &'a mut (FnMut(ty::Region, uint) -> ty::Region + 'a), } -impl<'a, 'tcx, F> RegionFolder<'a, 'tcx, F> where F: FnMut(ty::Region, uint) -> ty::Region { - pub fn new(tcx: &'a ty::ctxt<'tcx>, fld_r: F) -> RegionFolder<'a, 'tcx, F> { +impl<'a, 'tcx> RegionFolder<'a, 'tcx> { + pub fn new<F>(tcx: &'a ty::ctxt<'tcx>, fld_r: &'a mut F) -> RegionFolder<'a, 'tcx> + where F : FnMut(ty::Region, uint) -> ty::Region + { RegionFolder { tcx: tcx, current_depth: 1, @@ -790,10 +749,27 @@ impl<'a, 'tcx, F> RegionFolder<'a, 'tcx, F> where F: FnMut(ty::Region, uint) -> } } -impl<'a, 'tcx, F> TypeFolder<'tcx> for RegionFolder<'a, 'tcx, F> where - F: FnMut(ty::Region, uint) -> ty::Region, +pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> Vec<ty::Region> + where T : TypeFoldable<'tcx> +{ + let mut vec = Vec::new(); + fold_regions(tcx, value, |r, _| { vec.push(r); r }); + vec +} + +pub fn fold_regions<'tcx,T,F>(tcx: &ty::ctxt<'tcx>, + value: &T, + mut f: F) + -> T + where F : FnMut(ty::Region, uint) -> ty::Region, + T : TypeFoldable<'tcx>, { - fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.tcx } + value.fold_with(&mut RegionFolder::new(tcx, &mut f)) +} + +impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> +{ + fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx } fn enter_region_binder(&mut self) { self.current_depth += 1; @@ -813,7 +789,7 @@ impl<'a, 'tcx, F> TypeFolder<'tcx> for RegionFolder<'a, 'tcx, F> where _ => { debug!("RegionFolder.fold_region({}) folding free region (current_depth={})", r.repr(self.tcx()), self.current_depth); - (self.fld_r)(r, self.current_depth) + self.fld_r.call_mut((r, self.current_depth)) } } } @@ -869,7 +845,7 @@ pub fn shift_regions<'tcx, T:TypeFoldable<'tcx>+Repr<'tcx>>(tcx: &ty::ctxt<'tcx> debug!("shift_regions(value={}, amount={})", value.repr(tcx), amount); - value.fold_with(&mut RegionFolder::new(tcx, |region, _current_depth| { + value.fold_with(&mut RegionFolder::new(tcx, &mut |region, _current_depth| { shift_region(region, amount) })) } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 59da0af417c..0c014d615ca 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -47,7 +47,7 @@ pub struct Config { pub uint_type: UintTy, } -#[deriving(Clone, PartialEq)] +#[deriving(Clone, Copy, PartialEq)] pub enum OptLevel { No, // -O0 Less, // -O1 @@ -55,18 +55,14 @@ pub enum OptLevel { Aggressive // -O3 } -impl Copy for OptLevel {} - -#[deriving(Clone, PartialEq)] +#[deriving(Clone, Copy, PartialEq)] pub enum DebugInfoLevel { NoDebugInfo, LimitedDebugInfo, FullDebugInfo, } -impl Copy for DebugInfoLevel {} - -#[deriving(Clone, PartialEq, PartialOrd, Ord, Eq)] +#[deriving(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)] pub enum OutputType { OutputTypeBitcode, OutputTypeAssembly, @@ -75,8 +71,6 @@ pub enum OutputType { OutputTypeExe, } -impl Copy for OutputType {} - #[deriving(Clone)] pub struct Options { // The crate config requested for the session, which may be combined @@ -220,16 +214,14 @@ pub fn basic_options() -> Options { // users can have their own entry // functions that don't start a // scheduler -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub enum EntryFnType { EntryMain, EntryStart, EntryNone, } -impl Copy for EntryFnType {} - -#[deriving(PartialEq, PartialOrd, Clone, Ord, Eq, Hash)] +#[deriving(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash)] pub enum CrateType { CrateTypeExecutable, CrateTypeDylib, @@ -237,8 +229,6 @@ pub enum CrateType { CrateTypeStaticlib, } -impl Copy for CrateType {} - macro_rules! debugging_opts { ([ $opt:ident ] $cnt:expr ) => ( pub const $opt: u64 = 1 << $cnt; diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 51e18c80d05..bc6fb1be075 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -22,11 +22,9 @@ use syntax::visit::Visitor; // Useful type to use with `Result<>` indicate that an error has already // been reported to the user, so no need to continue checking. -#[deriving(Clone,Show)] +#[deriving(Clone, Copy, Show)] pub struct ErrorReported; -impl Copy for ErrorReported {} - pub fn time<T, U, F>(do_it: bool, what: &str, u: U, f: F) -> T where F: FnOnce(U) -> T, { diff --git a/src/librustc/util/nodemap.rs b/src/librustc/util/nodemap.rs index d1816c655fa..2b05961bb6a 100644 --- a/src/librustc/util/nodemap.rs +++ b/src/librustc/util/nodemap.rs @@ -68,11 +68,9 @@ pub mod DefIdSet { /// /// This uses FNV hashing, as described here: /// http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function -#[deriving(Clone, Default)] +#[deriving(Clone, Copy, Default)] pub struct FnvHasher; -impl Copy for FnvHasher {} - #[allow(missing_copy_implementations)] pub struct FnvState(u64); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 13b5c262bf7..b0124977c9f 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -23,7 +23,10 @@ use middle::ty::{ty_param, ty_ptr, ty_rptr, ty_tup, ty_open}; use middle::ty::{ty_unboxed_closure}; use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer}; use middle::ty; +use middle::ty_fold::TypeFoldable; +use std::collections::HashMap; +use std::hash::{Hash, Hasher}; use std::rc::Rc; use syntax::abi; use syntax::ast_map; @@ -40,7 +43,7 @@ pub trait Repr<'tcx> for Sized? { } /// Produces a string suitable for showing to the user. -pub trait UserString<'tcx> { +pub trait UserString<'tcx> : Repr<'tcx> { fn user_string(&self, tcx: &ctxt<'tcx>) -> String; } @@ -248,21 +251,12 @@ pub fn vec_map_to_string<T, F>(ts: &[T], f: F) -> String where format!("[{}]", tstrs.connect(", ")) } -pub fn fn_sig_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::FnSig<'tcx>) -> String { - format!("fn{} -> {}", typ.inputs.repr(cx), typ.output.repr(cx)) -} - -pub fn trait_ref_to_string<'tcx>(cx: &ctxt<'tcx>, - trait_ref: &ty::TraitRef<'tcx>) -> String { - trait_ref.user_string(cx).to_string() -} - pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { fn bare_fn_to_string<'tcx>(cx: &ctxt<'tcx>, unsafety: ast::Unsafety, abi: abi::Abi, ident: Option<ast::Ident>, - sig: &ty::FnSig<'tcx>) + sig: &ty::PolyFnSig<'tcx>) -> String { let mut s = String::new(); match unsafety { @@ -336,15 +330,15 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { s: &mut String, bra: char, ket: char, - sig: &ty::FnSig<'tcx>, + sig: &ty::PolyFnSig<'tcx>, bounds: &str) { s.push(bra); - let strs = sig.inputs + let strs = sig.0.inputs .iter() .map(|a| ty_to_string(cx, *a)) .collect::<Vec<_>>(); s.push_str(strs.connect(", ").as_slice()); - if sig.variadic { + if sig.0.variadic { s.push_str(", ..."); } s.push(ket); @@ -354,7 +348,7 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { s.push_str(bounds); } - match sig.output { + match sig.0.output { ty::FnConverging(t) => { if !ty::type_is_nil(t) { s.push_str(" -> "); @@ -374,8 +368,8 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { ty::IntVar(ref vid) if print_var_ids => vid.repr(cx), ty::FloatVar(ref vid) if print_var_ids => vid.repr(cx), ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => format!("_"), - ty::SkolemizedTy(v) => format!("SkolemizedTy({})", v), - ty::SkolemizedIntTy(v) => format!("SkolemizedIntTy({})", v) + ty::FreshTy(v) => format!("FreshTy({})", v), + ty::FreshIntTy(v) => format!("FreshIntTy({})", v) } } @@ -433,16 +427,11 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { - let base = ty::item_path_str(cx, principal.def_id); - let trait_def = ty::lookup_trait_def(cx, principal.def_id); - let did = trait_def.trait_ref.def_id; - let ty = parameterized(cx, base.as_slice(), - &principal.substs, &trait_def.generics, - did); + let principal = principal.user_string(cx); let bound_str = bounds.user_string(cx); let bound_sep = if bound_str.is_empty() { "" } else { " + " }; format!("{}{}{}", - ty, + principal, bound_sep, bound_str) } @@ -749,7 +738,7 @@ impl<'tcx> Repr<'tcx> for ty::TraitRef<'tcx> { // tells you everything you need to know. let base = ty::item_path_str(tcx, self.def_id); let trait_def = ty::lookup_trait_def(tcx, self.def_id); - format!("<{} : {}>", + format!("TraitRef({}, {})", self.substs.self_ty().repr(tcx), parameterized(tcx, base.as_slice(), &self.substs, &trait_def.generics, self.def_id)) } @@ -1018,7 +1007,7 @@ impl<'tcx> Repr<'tcx> for ty::BareFnTy<'tcx> { impl<'tcx> Repr<'tcx> for ty::FnSig<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { - fn_sig_to_string(tcx, self) + format!("fn{} -> {}", self.inputs.repr(tcx), self.output.repr(tcx)) } } @@ -1161,7 +1150,9 @@ impl<'tcx> UserString<'tcx> for ty::BuiltinBounds { } } -impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> { +impl<'tcx, T> UserString<'tcx> for ty::Binder<T> + where T : UserString<'tcx> + TypeFoldable<'tcx> +{ fn user_string(&self, tcx: &ctxt<'tcx>) -> String { // Replace any anonymous late-bound regions with named // variants, using gensym'd identifiers, so that we can @@ -1169,7 +1160,7 @@ impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> { // the output. We'll probably want to tweak this over time to // decide just how much information to give. let mut names = Vec::new(); - let (trait_ref, _) = ty::replace_late_bound_regions(tcx, self, |br, debruijn| { + let (unbound_value, _) = ty::replace_late_bound_regions(tcx, self, |br, debruijn| { ty::ReLateBound(debruijn, match br { ty::BrNamed(_, name) => { names.push(token::get_name(name)); @@ -1178,7 +1169,7 @@ impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> { ty::BrAnon(_) | ty::BrFresh(_) | ty::BrEnv => { - let name = token::gensym("r"); + let name = token::gensym("'r"); names.push(token::get_name(name)); ty::BrNamed(ast_util::local_def(ast::DUMMY_NODE_ID), name) } @@ -1186,19 +1177,21 @@ impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> { }); let names: Vec<_> = names.iter().map(|s| s.get()).collect(); - // Let the base string be either `SomeTrait` for `for<'a,'b> SomeTrait`, - // depending on whether there are bound regions. - let path_str = ty::item_path_str(tcx, self.def_id); - let base = - if names.is_empty() { - path_str - } else { - format!("for<{}> {}", names.connect(","), path_str) - }; + let value_str = unbound_value.user_string(tcx); + if names.len() == 0 { + value_str + } else { + format!("for<{}> {}", names.connect(","), value_str) + } + } +} +impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> { + fn user_string(&self, tcx: &ctxt<'tcx>) -> String { + let path_str = ty::item_path_str(tcx, self.def_id); let trait_def = ty::lookup_trait_def(tcx, self.def_id); - let did = trait_def.trait_ref.def_id; - parameterized(tcx, base.as_slice(), &trait_ref.substs, &trait_def.generics, did) + parameterized(tcx, path_str.as_slice(), &self.substs, + &trait_def.generics, self.def_id) } } @@ -1340,6 +1333,73 @@ impl<'tcx, A:Repr<'tcx>, B:Repr<'tcx>> Repr<'tcx> for (A,B) { impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for ty::Binder<T> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { - format!("Binder({})", self.value.repr(tcx)) + format!("Binder({})", self.0.repr(tcx)) + } +} + +impl<'tcx, S, H, K, V> Repr<'tcx> for HashMap<K,V,H> + where K : Hash<S> + Eq + Repr<'tcx>, + V : Repr<'tcx>, + H : Hasher<S> +{ + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("HashMap({})", + self.iter() + .map(|(k,v)| format!("{} => {}", k.repr(tcx), v.repr(tcx))) + .collect::<Vec<String>>() + .connect(", ")) + } +} + +impl<'tcx, T, U> Repr<'tcx> for ty::OutlivesPredicate<T,U> + where T : Repr<'tcx> + TypeFoldable<'tcx>, + U : Repr<'tcx> + TypeFoldable<'tcx>, +{ + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("OutlivesPredicate({}, {})", + self.0.repr(tcx), + self.1.repr(tcx)) + } +} + +impl<'tcx, T, U> UserString<'tcx> for ty::OutlivesPredicate<T,U> + where T : UserString<'tcx> + TypeFoldable<'tcx>, + U : UserString<'tcx> + TypeFoldable<'tcx>, +{ + fn user_string(&self, tcx: &ctxt<'tcx>) -> String { + format!("{} : {}", + self.0.user_string(tcx), + self.1.user_string(tcx)) + } +} + +impl<'tcx> Repr<'tcx> for ty::EquatePredicate<'tcx> { + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("EquatePredicate({}, {})", + self.0.repr(tcx), + self.1.repr(tcx)) + } +} + +impl<'tcx> UserString<'tcx> for ty::EquatePredicate<'tcx> { + fn user_string(&self, tcx: &ctxt<'tcx>) -> String { + format!("{} == {}", + self.0.user_string(tcx), + self.1.user_string(tcx)) + } +} + +impl<'tcx> UserString<'tcx> for ty::Predicate<'tcx> { + fn user_string(&self, tcx: &ctxt<'tcx>) -> String { + match *self { + ty::Predicate::Trait(ref trait_ref) => { + format!("{} : {}", + trait_ref.self_ty().user_string(tcx), + trait_ref.user_string(tcx)) + } + ty::Predicate::Equate(ref predicate) => predicate.user_string(tcx), + ty::Predicate::RegionOutlives(ref predicate) => predicate.user_string(tcx), + ty::Predicate::TypeOutlives(ref predicate) => predicate.user_string(tcx), + } } } diff --git a/src/librustc/util/snapshot_vec.rs b/src/librustc/util/snapshot_vec.rs index e80e8dc5351..749c39d7a6b 100644 --- a/src/librustc/util/snapshot_vec.rs +++ b/src/librustc/util/snapshot_vec.rs @@ -23,7 +23,7 @@ use self::UndoLog::*; use std::mem; #[deriving(PartialEq)] -enum UndoLog<T,U> { +pub enum UndoLog<T,U> { /// Indicates where a snapshot started. OpenSnapshot, @@ -113,6 +113,12 @@ impl<T,U,D:SnapshotVecDelegate<T,U>> SnapshotVec<T,U,D> { Snapshot { length: length } } + pub fn actions_since_snapshot(&self, + snapshot: &Snapshot) + -> &[UndoLog<T,U>] { + self.undo_log[snapshot.length..] + } + fn assert_open_snapshot(&self, snapshot: &Snapshot) { // Or else there was a failure to follow a stack discipline: assert!(self.undo_log.len() > snapshot.length); diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 7f469db3186..9be87b533f2 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -56,11 +56,9 @@ pub mod gather_loans; pub mod move_data; -#[deriving(Clone)] +#[deriving(Clone, Copy)] pub struct LoanDataFlowOperator; -impl Copy for LoanDataFlowOperator {} - pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>; impl<'a, 'tcx, 'v> Visitor<'v> for BorrowckCtxt<'a, 'tcx> { @@ -325,14 +323,12 @@ impl<'tcx> LoanPath<'tcx> { // b2b39e8700e37ad32b486b9a8409b50a8a53aa51#commitcomment-7892003 static DOWNCAST_PRINTED_OPERATOR : &'static str = " as "; -#[deriving(PartialEq, Eq, Hash, Show)] +#[deriving(Copy, PartialEq, Eq, Hash, Show)] pub enum LoanPathElem { LpDeref(mc::PointerKind), // `*LV` in doc.rs LpInterior(mc::InteriorKind) // `LV.f` in doc.rs } -impl Copy for LoanPathElem {} - pub fn closure_to_block(closure_id: ast::NodeId, tcx: &ty::ctxt) -> ast::NodeId { match tcx.map.get(closure_id) { @@ -494,21 +490,18 @@ pub struct BckError<'tcx> { code: bckerr_code } +#[deriving(Copy)] pub enum AliasableViolationKind { MutabilityViolation, BorrowViolation(euv::LoanCause) } -impl Copy for AliasableViolationKind {} - -#[deriving(Show)] +#[deriving(Copy, Show)] pub enum MovedValueUseKind { MovedInUse, MovedInCapture, } -impl Copy for MovedValueUseKind {} - /////////////////////////////////////////////////////////////////////////// // Misc diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 00b1377af73..d033fd808aa 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -78,11 +78,9 @@ pub struct FlowedMoveData<'a, 'tcx: 'a> { } /// Index into `MoveData.paths`, used like a pointer -#[deriving(PartialEq, Eq, PartialOrd, Ord, Show)] +#[deriving(Copy, PartialEq, Eq, PartialOrd, Ord, Show)] pub struct MovePathIndex(uint); -impl Copy for MovePathIndex {} - impl MovePathIndex { fn get(&self) -> uint { let MovePathIndex(v) = *self; v @@ -100,11 +98,9 @@ static InvalidMovePathIndex: MovePathIndex = MovePathIndex(uint::MAX); /// Index into `MoveData.moves`, used like a pointer -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub struct MoveIndex(uint); -impl Copy for MoveIndex {} - impl MoveIndex { fn get(&self) -> uint { let MoveIndex(v) = *self; v @@ -134,7 +130,7 @@ pub struct MovePath<'tcx> { pub next_sibling: MovePathIndex, } -#[deriving(PartialEq, Show)] +#[deriving(Copy, PartialEq, Show)] pub enum MoveKind { Declared, // When declared, variables start out "moved". MoveExpr, // Expression or binding that moves a variable @@ -142,8 +138,7 @@ pub enum MoveKind { Captured // Closure creation that moves a value } -impl Copy for MoveKind {} - +#[deriving(Copy)] pub struct Move { /// Path being moved. pub path: MovePathIndex, @@ -158,8 +153,7 @@ pub struct Move { pub next_move: MoveIndex } -impl Copy for Move {} - +#[deriving(Copy)] pub struct Assignment { /// Path being assigned. pub path: MovePathIndex, @@ -171,8 +165,7 @@ pub struct Assignment { pub span: Span, } -impl Copy for Assignment {} - +#[deriving(Copy)] pub struct VariantMatch { /// downcast to the variant. pub path: MovePathIndex, @@ -187,20 +180,14 @@ pub struct VariantMatch { pub mode: euv::MatchMode } -impl Copy for VariantMatch {} - -#[deriving(Clone)] +#[deriving(Clone, Copy)] pub struct MoveDataFlowOperator; -impl Copy for MoveDataFlowOperator {} - pub type MoveDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, MoveDataFlowOperator>; -#[deriving(Clone)] +#[deriving(Clone, Copy)] pub struct AssignDataFlowOperator; -impl Copy for AssignDataFlowOperator {} - pub type AssignDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, AssignDataFlowOperator>; fn loan_path_is_precise(loan_path: &LoanPath) -> bool { diff --git a/src/librustc_borrowck/graphviz.rs b/src/librustc_borrowck/graphviz.rs index 9d41efd678c..3427be1443b 100644 --- a/src/librustc_borrowck/graphviz.rs +++ b/src/librustc_borrowck/graphviz.rs @@ -25,15 +25,13 @@ use rustc::middle::dataflow::{DataFlowOperator, DataFlowContext, EntryOrExit}; use rustc::middle::dataflow; use std::rc::Rc; -#[deriving(Show)] +#[deriving(Show, Copy)] pub enum Variant { Loans, Moves, Assigns, } -impl Copy for Variant {} - impl Variant { pub fn short_name(&self) -> &'static str { match *self { diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 57004d71c75..2eb9d2c67a7 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -39,7 +39,7 @@ use std::option; use std::str::FromStr; use arena::TypedArena; -#[deriving(PartialEq, Show)] +#[deriving(Copy, PartialEq, Show)] pub enum PpSourceMode { PpmNormal, PpmExpanded, @@ -49,16 +49,12 @@ pub enum PpSourceMode { PpmExpandedHygiene, } -impl Copy for PpSourceMode {} - -#[deriving(PartialEq, Show)] +#[deriving(Copy, PartialEq, Show)] pub enum PpMode { PpmSource(PpSourceMode), PpmFlowGraph, } -impl Copy for PpMode {} - pub fn parse_pretty(sess: &Session, name: &str) -> (PpMode, Option<UserIdentifiedItem>) { let mut split = name.splitn(1, '='); let first = split.next().unwrap(); diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 508af4c28e6..b2c661cc58a 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -25,6 +25,7 @@ use rustc_typeck::middle::infer::combine::Combine; use rustc_typeck::middle::infer; use rustc_typeck::middle::infer::lub::Lub; use rustc_typeck::middle::infer::glb::Glb; +use rustc_typeck::middle::infer::sub::Sub; use rustc_typeck::util::ppaux::{ty_to_string, Repr, UserString}; use rustc::session::{mod,config}; use syntax::{abi, ast, ast_map, ast_util}; @@ -274,11 +275,11 @@ impl<'a, 'tcx> Env<'a, 'tcx> { onceness: ast::Many, store: ty::RegionTraitStore(region_bound, ast::MutMutable), bounds: ty::region_existential_bound(region_bound), - sig: ty::FnSig { + sig: ty::Binder(ty::FnSig { inputs: input_tys.to_vec(), output: ty::FnConverging(output_ty), variadic: false, - }, + }), abi: abi::Rust, }) } @@ -341,6 +342,11 @@ impl<'a, 'tcx> Env<'a, 'tcx> { infer::TypeTrace::dummy() } + pub fn sub(&self) -> Sub<'a, 'tcx> { + let trace = self.dummy_type_trace(); + Sub(self.infcx.combine_fields(true, trace)) + } + pub fn lub(&self) -> Lub<'a, 'tcx> { let trace = self.dummy_type_trace(); Lub(self.infcx.combine_fields(true, trace)) @@ -359,6 +365,33 @@ impl<'a, 'tcx> Env<'a, 'tcx> { } } + /// Checks that `t1 <: t2` is true (this may register additional + /// region checks). + pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { + match self.sub().tys(t1, t2) { + Ok(_) => { } + Err(ref e) => { + panic!("unexpected error computing sub({},{}): {}", + t1.repr(self.infcx.tcx), + t2.repr(self.infcx.tcx), + ty::type_err_to_str(self.infcx.tcx, e)); + } + } + } + + /// Checks that `t1 <: t2` is false (this may register additional + /// region checks). + pub fn check_not_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { + match self.sub().tys(t1, t2) { + Err(_) => { } + Ok(_) => { + panic!("unexpected success computing sub({},{})", + t1.repr(self.infcx.tcx), + t2.repr(self.infcx.tcx)); + } + } + } + /// Checks that `LUB(t1,t2) == t_lub` pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) { match self.lub().tys(t1, t2) { @@ -422,6 +455,74 @@ fn contravariant_region_ptr_err() { } #[test] +fn sub_free_bound_false() { + //! Test that: + //! + //! fn(&'a int) <: for<'b> fn(&'b int) + //! + //! does NOT hold. + + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_rptr_free1 = env.t_rptr_free(0, 1); + let t_rptr_bound1 = env.t_rptr_late_bound(1); + env.check_not_sub(env.t_fn(&[t_rptr_free1], ty::mk_int()), + env.t_fn(&[t_rptr_bound1], ty::mk_int())); + }) +} + +#[test] +fn sub_bound_free_true() { + //! Test that: + //! + //! for<'a> fn(&'a int) <: fn(&'b int) + //! + //! DOES hold. + + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_rptr_bound1 = env.t_rptr_late_bound(1); + let t_rptr_free1 = env.t_rptr_free(0, 1); + env.check_sub(env.t_fn(&[t_rptr_bound1], ty::mk_int()), + env.t_fn(&[t_rptr_free1], ty::mk_int())); + }) +} + +#[test] +fn sub_free_bound_false_infer() { + //! Test that: + //! + //! fn(_#1) <: for<'b> fn(&'b int) + //! + //! does NOT hold for any instantiation of `_#1`. + + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_infer1 = env.infcx.next_ty_var(); + let t_rptr_bound1 = env.t_rptr_late_bound(1); + env.check_not_sub(env.t_fn(&[t_infer1], ty::mk_int()), + env.t_fn(&[t_rptr_bound1], ty::mk_int())); + }) +} + +#[test] +fn lub_free_bound_infer() { + //! Test result of: + //! + //! LUB(fn(_#1), for<'b> fn(&'b int)) + //! + //! This should yield `fn(&'_ int)`. We check + //! that it yields `fn(&'x int)` for some free `'x`, + //! anyhow. + + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_infer1 = env.infcx.next_ty_var(); + let t_rptr_bound1 = env.t_rptr_late_bound(1); + let t_rptr_free1 = env.t_rptr_free(0, 1); + env.check_lub(env.t_fn(&[t_infer1], ty::mk_int()), + env.t_fn(&[t_rptr_bound1], ty::mk_int()), + env.t_fn(&[t_rptr_free1], ty::mk_int())); + }); +} + +#[test] fn lub_bound_bound() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { let t_rptr_bound1 = env.t_rptr_late_bound(1); @@ -525,6 +626,28 @@ fn glb_bound_free() { } #[test] +fn glb_bound_free_infer() { + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_rptr_bound1 = env.t_rptr_late_bound(1); + let t_infer1 = env.infcx.next_ty_var(); + + // compute GLB(fn(_) -> int, for<'b> fn(&'b int) -> int), + // which should yield for<'b> fn(&'b int) -> int + env.check_glb(env.t_fn(&[t_rptr_bound1], ty::mk_int()), + env.t_fn(&[t_infer1], ty::mk_int()), + env.t_fn(&[t_rptr_bound1], ty::mk_int())); + + // as a side-effect, computing GLB should unify `_` with + // `&'_ int` + let t_resolve1 = env.infcx.shallow_resolve(t_infer1); + match t_resolve1.sty { + ty::ty_rptr(..) => { } + _ => { panic!("t_resolve1={}", t_resolve1.repr(env.infcx.tcx)); } + } + }) +} + +#[test] fn glb_bound_static() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { let t_rptr_bound1 = env.t_rptr_late_bound(1); diff --git a/src/librustc_llvm/diagnostic.rs b/src/librustc_llvm/diagnostic.rs index 04196feafd2..3bf9c2d44f7 100644 --- a/src/librustc_llvm/diagnostic.rs +++ b/src/librustc_llvm/diagnostic.rs @@ -17,6 +17,7 @@ use libc::c_char; use {ValueRef, TwineRef, DebugLocRef, DiagnosticInfoRef}; +#[deriving(Copy)] pub enum OptimizationDiagnosticKind { OptimizationRemark, OptimizationMissed, @@ -24,8 +25,6 @@ pub enum OptimizationDiagnosticKind { OptimizationFailure, } -impl Copy for OptimizationDiagnosticKind {} - impl OptimizationDiagnosticKind { pub fn describe(self) -> &'static str { match self { @@ -69,6 +68,7 @@ impl OptimizationDiagnostic { } } +#[deriving(Copy)] pub enum Diagnostic { Optimization(OptimizationDiagnostic), @@ -76,8 +76,6 @@ pub enum Diagnostic { UnknownDiagnostic(DiagnosticInfoRef), } -impl Copy for Diagnostic {} - impl Diagnostic { pub unsafe fn unpack(di: DiagnosticInfoRef) -> Diagnostic { let kind = super::LLVMGetDiagInfoKind(di); diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 8b036b25015..3528b510ea1 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -68,7 +68,7 @@ pub const False: Bool = 0 as Bool; // Consts for the LLVM CallConv type, pre-cast to uint. -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub enum CallConv { CCallConv = 0, FastCallConv = 8, @@ -78,20 +78,18 @@ pub enum CallConv { X86_64_Win64 = 79, } -impl Copy for CallConv {} - +#[deriving(Copy)] pub enum Visibility { LLVMDefaultVisibility = 0, HiddenVisibility = 1, ProtectedVisibility = 2, } -impl Copy for Visibility {} - // This enum omits the obsolete (and no-op) linkage types DLLImportLinkage, // DLLExportLinkage, GhostLinkage and LinkOnceODRAutoHideLinkage. // LinkerPrivateLinkage and LinkerPrivateWeakLinkage are not included either; // they've been removed in upstream LLVM commit r203866. +#[deriving(Copy)] pub enum Linkage { ExternalLinkage = 0, AvailableExternallyLinkage = 1, @@ -106,10 +104,8 @@ pub enum Linkage { CommonLinkage = 14, } -impl Copy for Linkage {} - #[repr(C)] -#[deriving(Show)] +#[deriving(Copy, Show)] pub enum DiagnosticSeverity { Error, Warning, @@ -117,8 +113,6 @@ pub enum DiagnosticSeverity { Note, } -impl Copy for DiagnosticSeverity {} - bitflags! { flags Attribute : u32 { const ZExtAttribute = 1 << 0, @@ -152,6 +146,7 @@ bitflags! { #[repr(u64)] +#[deriving(Copy)] pub enum OtherAttribute { // The following are not really exposed in // the LLVM c api so instead to add these @@ -172,22 +167,18 @@ pub enum OtherAttribute { NonNullAttribute = 1 << 44, } -impl Copy for OtherAttribute {} - +#[deriving(Copy)] pub enum SpecialAttribute { DereferenceableAttribute(u64) } -impl Copy for SpecialAttribute {} - #[repr(C)] +#[deriving(Copy)] pub enum AttributeSet { ReturnIndex = 0, FunctionIndex = !0 } -impl Copy for AttributeSet {} - pub trait AttrHelper { fn apply_llfn(&self, idx: c_uint, llfn: ValueRef); fn apply_callsite(&self, idx: c_uint, callsite: ValueRef); @@ -274,6 +265,7 @@ impl AttrBuilder { } // enum for the LLVM IntPredicate type +#[deriving(Copy)] pub enum IntPredicate { IntEQ = 32, IntNE = 33, @@ -287,9 +279,8 @@ pub enum IntPredicate { IntSLE = 41, } -impl Copy for IntPredicate {} - // enum for the LLVM RealPredicate type +#[deriving(Copy)] pub enum RealPredicate { RealPredicateFalse = 0, RealOEQ = 1, @@ -309,11 +300,9 @@ pub enum RealPredicate { RealPredicateTrue = 15, } -impl Copy for RealPredicate {} - // The LLVM TypeKind type - must stay in sync with the def of // LLVMTypeKind in llvm/include/llvm-c/Core.h -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] #[repr(C)] pub enum TypeKind { Void = 0, @@ -334,9 +323,8 @@ pub enum TypeKind { X86_MMX = 15, } -impl Copy for TypeKind {} - #[repr(C)] +#[deriving(Copy)] pub enum AtomicBinOp { AtomicXchg = 0, AtomicAdd = 1, @@ -351,9 +339,8 @@ pub enum AtomicBinOp { AtomicUMin = 10, } -impl Copy for AtomicBinOp {} - #[repr(C)] +#[deriving(Copy)] pub enum AtomicOrdering { NotAtomic = 0, Unordered = 1, @@ -365,17 +352,15 @@ pub enum AtomicOrdering { SequentiallyConsistent = 7 } -impl Copy for AtomicOrdering {} - // Consts for the LLVMCodeGenFileType type (in include/llvm/c/TargetMachine.h) #[repr(C)] +#[deriving(Copy)] pub enum FileType { AssemblyFileType = 0, ObjectFileType = 1 } -impl Copy for FileType {} - +#[deriving(Copy)] pub enum MetadataType { MD_dbg = 0, MD_tbaa = 1, @@ -385,17 +370,14 @@ pub enum MetadataType { MD_tbaa_struct = 5 } -impl Copy for MetadataType {} - // Inline Asm Dialect +#[deriving(Copy)] pub enum AsmDialect { AD_ATT = 0, AD_Intel = 1 } -impl Copy for AsmDialect {} - -#[deriving(PartialEq, Clone)] +#[deriving(Copy, PartialEq, Clone)] #[repr(C)] pub enum CodeGenOptLevel { CodeGenLevelNone = 0, @@ -404,9 +386,7 @@ pub enum CodeGenOptLevel { CodeGenLevelAggressive = 3, } -impl Copy for CodeGenOptLevel {} - -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] #[repr(C)] pub enum RelocMode { RelocDefault = 0, @@ -415,9 +395,8 @@ pub enum RelocMode { RelocDynamicNoPic = 3, } -impl Copy for RelocMode {} - #[repr(C)] +#[deriving(Copy)] pub enum CodeGenModel { CodeModelDefault = 0, CodeModelJITDefault = 1, @@ -427,9 +406,8 @@ pub enum CodeGenModel { CodeModelLarge = 5, } -impl Copy for CodeGenModel {} - #[repr(C)] +#[deriving(Copy)] pub enum DiagnosticKind { DK_InlineAsm = 0, DK_StackSize, @@ -441,8 +419,6 @@ pub enum DiagnosticKind { DK_OptimizationFailure, } -impl Copy for DiagnosticKind {} - // Opaque pointer types #[allow(missing_copy_implementations)] pub enum Module_opaque {} @@ -537,6 +513,7 @@ pub mod debuginfo { pub type DIArray = DIDescriptor; pub type DISubrange = DIDescriptor; + #[deriving(Copy)] pub enum DIDescriptorFlags { FlagPrivate = 1 << 0, FlagProtected = 1 << 1, @@ -555,8 +532,6 @@ pub mod debuginfo { FlagLValueReference = 1 << 14, FlagRValueReference = 1 << 15 } - - impl Copy for DIDescriptorFlags {} } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index df7df2f08d9..489d29492c2 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -33,7 +33,7 @@ use std::sync::{Arc, Mutex}; use std::thread; use libc::{c_uint, c_int, c_void}; -#[deriving(Clone, PartialEq, PartialOrd, Ord, Eq)] +#[deriving(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)] pub enum OutputType { OutputTypeBitcode, OutputTypeAssembly, @@ -42,8 +42,6 @@ pub enum OutputType { OutputTypeExe, } -impl Copy for OutputType {} - pub fn llvm_err(handler: &diagnostic::Handler, msg: String) -> ! { unsafe { let cstr = llvm::LLVMRustGetLastError(); diff --git a/src/librustc_trans/save/recorder.rs b/src/librustc_trans/save/recorder.rs index c15ff1d7f0a..37d9e5d9940 100644 --- a/src/librustc_trans/save/recorder.rs +++ b/src/librustc_trans/save/recorder.rs @@ -61,6 +61,7 @@ macro_rules! svec { }) } +#[deriving(Copy)] pub enum Row { Variable, Enum, @@ -87,8 +88,6 @@ pub enum Row { FnRef, } -impl Copy for Row {} - impl<'a> FmtStrs<'a> { pub fn new(rec: Box<Recorder>, span: SpanUtils<'a>, krate: String) -> FmtStrs<'a> { FmtStrs { diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index bf17043f0e4..1401f1ad1f5 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -228,11 +228,9 @@ use syntax::codemap::Span; use syntax::fold::Folder; use syntax::ptr::P; -#[deriving(Show)] +#[deriving(Copy, Show)] struct ConstantExpr<'a>(&'a ast::Expr); -impl<'a> Copy for ConstantExpr<'a> {} - impl<'a> ConstantExpr<'a> { fn eq(self, other: ConstantExpr<'a>, tcx: &ty::ctxt) -> bool { let ConstantExpr(expr) = self; @@ -301,7 +299,7 @@ impl<'a, 'tcx> Opt<'a, 'tcx> { } } -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub enum BranchKind { NoBranch, Single, @@ -310,23 +308,19 @@ pub enum BranchKind { CompareSliceLength } -impl Copy for BranchKind {} - pub enum OptResult<'blk, 'tcx: 'blk> { SingleResult(Result<'blk, 'tcx>), RangeResult(Result<'blk, 'tcx>, Result<'blk, 'tcx>), LowerBound(Result<'blk, 'tcx>) } -#[deriving(Clone)] +#[deriving(Clone, Copy)] pub enum TransBindingMode { TrByCopy(/* llbinding */ ValueRef), TrByMove, TrByRef, } -impl Copy for TransBindingMode {} - /// Information about a pattern binding: /// - `llmatch` is a pointer to a stack slot. The stack slot contains a /// pointer into the value being matched. Hence, llmatch has type `T**` @@ -334,7 +328,7 @@ impl Copy for TransBindingMode {} /// - `trmode` is the trans binding mode /// - `id` is the node id of the binding /// - `ty` is the Rust type of the binding -#[deriving(Clone)] +#[deriving(Clone, Copy)] pub struct BindingInfo<'tcx> { pub llmatch: ValueRef, pub trmode: TransBindingMode, @@ -343,8 +337,6 @@ pub struct BindingInfo<'tcx> { pub ty: Ty<'tcx>, } -impl<'tcx> Copy for BindingInfo<'tcx> {} - type BindingsMap<'tcx> = FnvHashMap<Ident, BindingInfo<'tcx>>; struct ArmData<'p, 'blk, 'tcx: 'blk> { diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 0c2c86fc32d..f7edb281b9e 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -281,14 +281,12 @@ struct Case<'tcx> { } -#[deriving(Eq, PartialEq, Show)] +#[deriving(Copy, Eq, PartialEq, Show)] pub enum PointerField { ThinPointer(uint), FatPointer(uint) } -impl Copy for PointerField {} - impl<'tcx> Case<'tcx> { fn is_zerolen<'a>(&self, cx: &CrateContext<'a, 'tcx>, scapegoat: Ty<'tcx>) -> bool { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index f1d839e916d..25fbaa66776 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -282,10 +282,10 @@ pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>, name: &str) -> ValueRef { let (inputs, output, abi, env) = match fn_ty.sty { ty::ty_bare_fn(ref f) => { - (f.sig.inputs.clone(), f.sig.output, f.abi, None) + (f.sig.0.inputs.clone(), f.sig.0.output, f.abi, None) } ty::ty_closure(ref f) => { - (f.sig.inputs.clone(), f.sig.output, f.abi, Some(Type::i8p(ccx))) + (f.sig.0.inputs.clone(), f.sig.0.output, f.abi, Some(Type::i8p(ccx))) } ty::ty_unboxed_closure(closure_did, _, ref substs) => { let unboxed_closures = ccx.tcx().unboxed_closures.borrow(); @@ -293,8 +293,8 @@ pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let function_type = unboxed_closure.closure_type.clone(); let self_type = self_type_for_unboxed_closure(ccx, closure_did, fn_ty); let llenvironment_type = type_of_explicit_arg(ccx, self_type); - (function_type.sig.inputs.iter().map(|t| t.subst(ccx.tcx(), substs)).collect(), - function_type.sig.output.subst(ccx.tcx(), substs), + (function_type.sig.0.inputs.iter().map(|t| t.subst(ccx.tcx(), substs)).collect(), + function_type.sig.0.output.subst(ccx.tcx(), substs), RustCall, Some(llenvironment_type)) } @@ -565,10 +565,9 @@ pub fn maybe_name_value(cx: &CrateContext, v: ValueRef, s: &str) { // Used only for creating scalar comparison glue. +#[deriving(Copy)] pub enum scalar_type { nil_type, signed_int, unsigned_int, floating_point, } -impl Copy for scalar_type {} - pub fn compare_scalar_types<'blk, 'tcx>(cx: Block<'blk, 'tcx>, lhs: ValueRef, rhs: ValueRef, @@ -1792,14 +1791,12 @@ pub fn build_return_block<'blk, 'tcx>(fcx: &FunctionContext<'blk, 'tcx>, } } -#[deriving(Clone, Eq, PartialEq)] +#[deriving(Clone, Copy, Eq, PartialEq)] pub enum IsUnboxedClosureFlag { NotUnboxedClosure, IsUnboxedClosure, } -impl Copy for IsUnboxedClosureFlag {} - // trans_closure: Builds an LLVM function out of a source function. // If the function closes over its environment a closure will be // returned. @@ -1998,7 +1995,7 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let tcx = ccx.tcx(); let result_ty = match ctor_ty.sty { - ty::ty_bare_fn(ref bft) => bft.sig.output.unwrap(), + ty::ty_bare_fn(ref bft) => bft.sig.0.output.unwrap(), _ => ccx.sess().bug( format!("trans_enum_variant_constructor: \ unexpected ctor return type {}", @@ -2070,7 +2067,7 @@ fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx let ctor_ty = ctor_ty.subst(ccx.tcx(), param_substs); let result_ty = match ctor_ty.sty { - ty::ty_bare_fn(ref bft) => bft.sig.output, + ty::ty_bare_fn(ref bft) => bft.sig.0.output, _ => ccx.sess().bug( format!("trans_enum_variant_or_tuple_like_struct: \ unexpected ctor return type {}", @@ -2194,6 +2191,7 @@ pub fn llvm_linkage_by_name(name: &str) -> Option<Linkage> { /// Enum describing the origin of an LLVM `Value`, for linkage purposes. +#[deriving(Copy)] pub enum ValueOrigin { /// The LLVM `Value` is in this context because the corresponding item was /// assigned to the current compilation unit. @@ -2204,8 +2202,6 @@ pub enum ValueOrigin { InlinedCopy, } -impl Copy for ValueOrigin {} - /// Set the appropriate linkage for an LLVM `ValueRef` (function or global). /// If the `llval` is the direct translation of a specific Rust item, `id` /// should be set to the `NodeId` of that item. (This mapping should be @@ -2439,7 +2435,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty< // at either 1 or 2 depending on whether there's an env slot or not let mut first_arg_offset = if has_env { 2 } else { 1 }; let mut attrs = llvm::AttrBuilder::new(); - let ret_ty = fn_sig.output; + let ret_ty = fn_sig.0.output; // These have an odd calling convention, so we need to manually // unpack the input ty's @@ -2447,15 +2443,15 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty< ty::ty_unboxed_closure(_, _, _) => { assert!(abi == RustCall); - match fn_sig.inputs[0].sty { + match fn_sig.0.inputs[0].sty { ty::ty_tup(ref inputs) => inputs.clone(), _ => ccx.sess().bug("expected tuple'd inputs") } }, ty::ty_bare_fn(_) if abi == RustCall => { - let mut inputs = vec![fn_sig.inputs[0]]; + let mut inputs = vec![fn_sig.0.inputs[0]]; - match fn_sig.inputs[1].sty { + match fn_sig.0.inputs[1].sty { ty::ty_tup(ref t_in) => { inputs.push_all(t_in.as_slice()); inputs @@ -2463,7 +2459,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty< _ => ccx.sess().bug("expected tuple'd inputs") } } - _ => fn_sig.inputs.clone() + _ => fn_sig.0.inputs.clone() }; if let ty::FnConverging(ret_ty) = ret_ty { diff --git a/src/librustc_trans/trans/basic_block.rs b/src/librustc_trans/trans/basic_block.rs index dca106a3897..476f5e2d618 100644 --- a/src/librustc_trans/trans/basic_block.rs +++ b/src/librustc_trans/trans/basic_block.rs @@ -13,10 +13,9 @@ use llvm::{BasicBlockRef}; use trans::value::{Users, Value}; use std::iter::{Filter, Map}; +#[deriving(Copy)] pub struct BasicBlock(pub BasicBlockRef); -impl Copy for BasicBlock {} - pub type Preds = Map< Value, BasicBlock, diff --git a/src/librustc_trans/trans/cabi.rs b/src/librustc_trans/trans/cabi.rs index 7aabd998f7a..ad2a6db1222 100644 --- a/src/librustc_trans/trans/cabi.rs +++ b/src/librustc_trans/trans/cabi.rs @@ -20,7 +20,7 @@ use trans::cabi_arm; use trans::cabi_mips; use trans::type_::Type; -#[deriving(Clone, PartialEq)] +#[deriving(Clone, Copy, PartialEq)] pub enum ArgKind { /// Pass the argument directly using the normal converted /// LLVM type or by coercing to another specified type @@ -31,13 +31,11 @@ pub enum ArgKind { Ignore, } -impl Copy for ArgKind {} - /// Information about how a specific C type /// should be passed to or returned from a function /// /// This is borrowed from clang's ABIInfo.h -#[deriving(Clone)] +#[deriving(Clone, Copy)] pub struct ArgType { pub kind: ArgKind, /// Original LLVM type @@ -50,8 +48,6 @@ pub struct ArgType { pub attr: option::Option<Attribute> } -impl Copy for ArgType {} - impl ArgType { pub fn direct(ty: Type, cast: option::Option<Type>, pad: option::Option<Type>, diff --git a/src/librustc_trans/trans/cabi_x86_64.rs b/src/librustc_trans/trans/cabi_x86_64.rs index 4a6bc58051c..9b678a4f3ae 100644 --- a/src/librustc_trans/trans/cabi_x86_64.rs +++ b/src/librustc_trans/trans/cabi_x86_64.rs @@ -24,7 +24,7 @@ use trans::type_::Type; use std::cmp; -#[deriving(Clone, PartialEq)] +#[deriving(Clone, Copy, PartialEq)] enum RegClass { NoClass, Int, @@ -40,8 +40,6 @@ enum RegClass { Memory } -impl Copy for RegClass {} - trait TypeMethods { fn is_reg_ty(&self) -> bool; } diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index ff2f686fff8..3376479b7a4 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -57,13 +57,12 @@ use syntax::ast; use syntax::ast_map; use syntax::ptr::P; +#[deriving(Copy)] pub struct MethodData { pub llfn: ValueRef, pub llself: ValueRef, } -impl Copy for MethodData {} - pub enum CalleeData<'tcx> { Closure(Datum<'tcx, Lvalue>), @@ -280,9 +279,9 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( match bare_fn_ty.sty { ty::ty_bare_fn(ty::BareFnTy { unsafety: ast::Unsafety::Normal, abi: synabi::Rust, - sig: ty::FnSig { inputs: ref input_tys, - output: output_ty, - variadic: false }}) => + sig: ty::Binder(ty::FnSig { inputs: ref input_tys, + output: output_ty, + variadic: false })}) => { (input_tys, output_ty) } @@ -296,12 +295,12 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( let tuple_fn_ty = ty::mk_bare_fn(tcx, ty::BareFnTy { unsafety: ast::Unsafety::Normal, abi: synabi::RustCall, - sig: ty::FnSig { + sig: ty::Binder(ty::FnSig { inputs: vec![bare_fn_ty_ref, tuple_input_ty], output: output_ty, variadic: false - }}); + })}); debug!("tuple_fn_ty: {}", tuple_fn_ty.repr(tcx)); // @@ -422,7 +421,6 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>( match impl_or_trait_item { ty::MethodTraitItem(method) => { let trait_ref = ty::impl_trait_ref(tcx, impl_id).unwrap(); - let trait_ref = ty::erase_late_bound_regions(tcx, &trait_ref); // Compute the first substitution let first_subst = @@ -657,8 +655,8 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, let mut bcx = callee.bcx; let (abi, ret_ty) = match callee_ty.sty { - ty::ty_bare_fn(ref f) => (f.abi, f.sig.output), - ty::ty_closure(ref f) => (f.abi, f.sig.output), + ty::ty_bare_fn(ref f) => (f.abi, f.sig.0.output), + ty::ty_closure(ref f) => (f.abi, f.sig.0.output), _ => panic!("expected bare rust fn or closure in trans_call_inner") }; @@ -1050,13 +1048,12 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, bcx } +#[deriving(Copy)] pub enum AutorefArg { DontAutorefArg, DoAutorefArg(ast::NodeId) } -impl Copy for AutorefArg {} - pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, formal_arg_ty: Ty<'tcx>, arg_datum: Datum<'tcx, Expr>, diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index e8857de7b73..fb2c432ef5c 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -50,13 +50,11 @@ pub struct CleanupScope<'blk, 'tcx: 'blk> { cached_landing_pad: Option<BasicBlockRef>, } -#[deriving(Show)] +#[deriving(Copy, Show)] pub struct CustomScopeIndex { index: uint } -impl Copy for CustomScopeIndex {} - pub const EXIT_BREAK: uint = 0; pub const EXIT_LOOP: uint = 1; pub const EXIT_MAX: uint = 2; @@ -83,22 +81,19 @@ impl<'blk, 'tcx: 'blk> fmt::Show for CleanupScopeKind<'blk, 'tcx> { } } -#[deriving(PartialEq, Show)] +#[deriving(Copy, PartialEq, Show)] pub enum EarlyExitLabel { UnwindExit, ReturnExit, LoopExit(ast::NodeId, uint) } -impl Copy for EarlyExitLabel {} - +#[deriving(Copy)] pub struct CachedEarlyExit { label: EarlyExitLabel, cleanup_block: BasicBlockRef, } -impl Copy for CachedEarlyExit {} - pub trait Cleanup<'tcx> { fn must_unwind(&self) -> bool; fn clean_on_unwind(&self) -> bool; @@ -111,14 +106,12 @@ pub trait Cleanup<'tcx> { pub type CleanupObj<'tcx> = Box<Cleanup<'tcx>+'tcx>; -#[deriving(Show)] +#[deriving(Copy, Show)] pub enum ScopeId { AstScope(ast::NodeId), CustomScope(CustomScopeIndex) } -impl Copy for ScopeId {} - impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { /// Invoked when we start to trans the code contained within a new cleanup scope. fn push_ast_cleanup_scope(&self, debug_loc: NodeInfo) { @@ -876,6 +869,7 @@ impl EarlyExitLabel { /////////////////////////////////////////////////////////////////////////// // Cleanup types +#[deriving(Copy)] pub struct DropValue<'tcx> { is_immediate: bool, must_unwind: bool, @@ -884,8 +878,6 @@ pub struct DropValue<'tcx> { zero: bool } -impl<'tcx> Copy for DropValue<'tcx> {} - impl<'tcx> Cleanup<'tcx> for DropValue<'tcx> { fn must_unwind(&self) -> bool { self.must_unwind @@ -915,21 +907,18 @@ impl<'tcx> Cleanup<'tcx> for DropValue<'tcx> { } } -#[deriving(Show)] +#[deriving(Copy, Show)] pub enum Heap { HeapExchange } -impl Copy for Heap {} - +#[deriving(Copy)] pub struct FreeValue<'tcx> { ptr: ValueRef, heap: Heap, content_ty: Ty<'tcx> } -impl<'tcx> Copy for FreeValue<'tcx> {} - impl<'tcx> Cleanup<'tcx> for FreeValue<'tcx> { fn must_unwind(&self) -> bool { true @@ -957,6 +946,7 @@ impl<'tcx> Cleanup<'tcx> for FreeValue<'tcx> { } } +#[deriving(Copy)] pub struct FreeSlice { ptr: ValueRef, size: ValueRef, @@ -964,8 +954,6 @@ pub struct FreeSlice { heap: Heap, } -impl Copy for FreeSlice {} - impl<'tcx> Cleanup<'tcx> for FreeSlice { fn must_unwind(&self) -> bool { true @@ -993,12 +981,11 @@ impl<'tcx> Cleanup<'tcx> for FreeSlice { } } +#[deriving(Copy)] pub struct LifetimeEnd { ptr: ValueRef, } -impl Copy for LifetimeEnd {} - impl<'tcx> Cleanup<'tcx> for LifetimeEnd { fn must_unwind(&self) -> bool { false diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index 1811388662c..d5d954f5a90 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -102,13 +102,12 @@ use syntax::ast_util; // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#[deriving(Copy)] pub struct EnvValue<'tcx> { action: ast::CaptureClause, datum: Datum<'tcx, Lvalue> } -impl<'tcx> Copy for EnvValue<'tcx> {} - impl<'tcx> EnvValue<'tcx> { pub fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String { format!("{}({})", self.action, self.datum.to_string(ccx)) @@ -658,9 +657,9 @@ pub fn get_wrapper_for_bare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let arena = TypedArena::new(); let empty_param_substs = Substs::trans_empty(); - let fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, true, f.sig.output, + let fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, true, f.sig.0.output, &empty_param_substs, None, &arena); - let bcx = init_function(&fcx, true, f.sig.output); + let bcx = init_function(&fcx, true, f.sig.0.output); let args = create_datums_for_fn_args(&fcx, ty::ty_fn_args(closure_ty) @@ -676,7 +675,7 @@ pub fn get_wrapper_for_bare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llargs.extend(args.iter().map(|arg| arg.val)); let retval = Call(bcx, fn_ptr, llargs.as_slice(), None); - match f.sig.output { + match f.sig.0.output { ty::FnConverging(output_type) => { if return_type_is_void(ccx, output_type) || fcx.llretslotptr.get().is_some() { RetVoid(bcx); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 83938fa3357..4dd4e27c9c0 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -119,6 +119,7 @@ pub fn gensym_name(name: &str) -> PathElem { PathName(token::gensym(format!("{}:{}", name, num).as_slice())) } +#[deriving(Copy)] pub struct tydesc_info<'tcx> { pub ty: Ty<'tcx>, pub tydesc: ValueRef, @@ -127,8 +128,6 @@ pub struct tydesc_info<'tcx> { pub name: ValueRef, } -impl<'tcx> Copy for tydesc_info<'tcx> {} - /* * A note on nomenclature of linking: "extern", "foreign", and "upcall". * @@ -155,13 +154,12 @@ impl<'tcx> Copy for tydesc_info<'tcx> {} * */ +#[deriving(Copy)] pub struct NodeInfo { pub id: ast::NodeId, pub span: Span, } -impl Copy for NodeInfo {} - pub fn expr_info(expr: &ast::Expr) -> NodeInfo { NodeInfo { id: expr.id, span: expr.span } } @@ -764,7 +762,7 @@ pub fn expr_ty_adjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ex: &ast::Expr) -> T /// guarantee to us that all nested obligations *could be* resolved if we wanted to. pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, span: Span, - trait_ref: Rc<ty::TraitRef<'tcx>>) + trait_ref: Rc<ty::PolyTraitRef<'tcx>>) -> traits::Vtable<'tcx, ()> { let tcx = ccx.tcx(); @@ -783,7 +781,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debug!("trans fulfill_obligation: trait_ref={}", trait_ref.repr(ccx.tcx())); - ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id); + ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id()); let infcx = infer::new_infer_ctxt(tcx); // Parameter environment is used to give details about type parameters, @@ -848,12 +846,12 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } - // Use skolemize to simultaneously replace all type variables with + // Use freshen to simultaneously replace all type variables with // their bindings and replace all regions with 'static. This is // sort of overkill because we do not expect there to be any - // unbound type variables, hence no skolemized types should ever - // be inserted. - let vtable = vtable.fold_with(&mut infcx.skolemizer()); + // unbound type variables, hence no `TyFresh` types should ever be + // inserted. + let vtable = vtable.fold_with(&mut infcx.freshener()); info!("Cache miss: {}", trait_ref.repr(ccx.tcx())); ccx.trait_cache().borrow_mut().insert(trait_ref, @@ -863,7 +861,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } // Key used to lookup values supplied for type parameters in an expr. -#[deriving(PartialEq, Show)] +#[deriving(Copy, PartialEq, Show)] pub enum ExprOrMethodCall { // Type parameters for a path like `None::<int>` ExprId(ast::NodeId), @@ -872,8 +870,6 @@ pub enum ExprOrMethodCall { MethodCall(ty::MethodCall) } -impl Copy for ExprOrMethodCall {} - pub fn node_id_substs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, node: ExprOrMethodCall) -> subst::Substs<'tcx> { diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 89fa6a72e88..af003b01157 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -99,7 +99,7 @@ pub struct LocalCrateContext<'tcx> { monomorphized: RefCell<FnvHashMap<MonoId<'tcx>, ValueRef>>, monomorphizing: RefCell<DefIdMap<uint>>, /// Cache generated vtables - vtables: RefCell<FnvHashMap<(Ty<'tcx>, Rc<ty::TraitRef<'tcx>>), ValueRef>>, + vtables: RefCell<FnvHashMap<(Ty<'tcx>, Rc<ty::PolyTraitRef<'tcx>>), ValueRef>>, /// Cache of constant strings, const_cstr_cache: RefCell<FnvHashMap<InternedString, ValueRef>>, @@ -150,7 +150,7 @@ pub struct LocalCrateContext<'tcx> { /// contexts around the same size. n_llvm_insns: Cell<uint>, - trait_cache: RefCell<FnvHashMap<Rc<ty::TraitRef<'tcx>>, + trait_cache: RefCell<FnvHashMap<Rc<ty::PolyTraitRef<'tcx>>, traits::Vtable<'tcx, ()>>>, } @@ -601,7 +601,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local.monomorphizing } - pub fn vtables<'a>(&'a self) -> &'a RefCell<FnvHashMap<(Ty<'tcx>, Rc<ty::TraitRef<'tcx>>), + pub fn vtables<'a>(&'a self) -> &'a RefCell<FnvHashMap<(Ty<'tcx>, Rc<ty::PolyTraitRef<'tcx>>), ValueRef>> { &self.local.vtables } @@ -699,7 +699,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.local.n_llvm_insns.set(self.local.n_llvm_insns.get() + 1); } - pub fn trait_cache(&self) -> &RefCell<FnvHashMap<Rc<ty::TraitRef<'tcx>>, + pub fn trait_cache(&self) -> &RefCell<FnvHashMap<Rc<ty::PolyTraitRef<'tcx>>, traits::Vtable<'tcx, ()>>> { &self.local.trait_cache } diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs index e32b5792e5d..75473dc58bf 100644 --- a/src/librustc_trans/trans/datum.rs +++ b/src/librustc_trans/trans/datum.rs @@ -33,7 +33,7 @@ use syntax::ast; /// describes where the value is stored, what Rust type the value has, /// whether it is addressed by reference, and so forth. Please refer /// the section on datums in `doc.rs` for more details. -#[deriving(Clone)] +#[deriving(Clone, Copy)] pub struct Datum<'tcx, K> { /// The llvm value. This is either a pointer to the Rust value or /// the value itself, depending on `kind` below. @@ -46,8 +46,6 @@ pub struct Datum<'tcx, K> { pub kind: K, } -impl<'tcx,K:Copy> Copy for Datum<'tcx,K> {} - pub struct DatumBlock<'blk, 'tcx: 'blk, K> { pub bcx: Block<'blk, 'tcx>, pub datum: Datum<'tcx, K>, @@ -65,11 +63,9 @@ pub enum Expr { LvalueExpr, } -#[deriving(Clone, Show)] +#[deriving(Clone, Copy, Show)] pub struct Lvalue; -impl Copy for Lvalue {} - #[deriving(Show)] pub struct Rvalue { pub mode: RvalueMode @@ -86,7 +82,7 @@ impl Drop for Rvalue { fn drop(&mut self) { } } -#[deriving(PartialEq, Eq, Hash, Show)] +#[deriving(Copy, PartialEq, Eq, Hash, Show)] pub enum RvalueMode { /// `val` is a pointer to the actual value (and thus has type *T) ByRef, @@ -95,8 +91,6 @@ pub enum RvalueMode { ByValue, } -impl Copy for RvalueMode {} - pub fn immediate_rvalue<'tcx>(val: ValueRef, ty: Ty<'tcx>) -> Datum<'tcx, Rvalue> { return Datum::new(val, ty, Rvalue::new(ByValue)); } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index e9730f7af0e..9a5e6830da1 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -248,11 +248,9 @@ static FLAGS_NONE: c_uint = 0; // Public Interface of debuginfo module //=----------------------------------------------------------------------------- -#[deriving(Show, Hash, Eq, PartialEq, Clone)] +#[deriving(Copy, Show, Hash, Eq, PartialEq, Clone)] struct UniqueTypeId(ast::Name); -impl Copy for UniqueTypeId {} - // The TypeMap is where the CrateDebugContext holds the type metadata nodes // created so far. The metadata nodes are indexed by UniqueTypeId, and, for // faster lookup, also by Ty. The TypeMap is responsible for creating @@ -429,8 +427,8 @@ impl<'tcx> TypeMap<'tcx> { from_def_id_and_substs(self, cx, - trait_data.principal.def_id, - &trait_data.principal.substs, + trait_data.principal.def_id(), + trait_data.principal.substs(), &mut unique_type_id); }, ty::ty_bare_fn(ty::BareFnTy{ unsafety, abi, ref sig } ) => { @@ -442,7 +440,7 @@ impl<'tcx> TypeMap<'tcx> { unique_type_id.push_str(" fn("); - for ¶meter_type in sig.inputs.iter() { + for ¶meter_type in sig.0.inputs.iter() { let parameter_type_id = self.get_unique_type_id_of_type(cx, parameter_type); let parameter_type_id = @@ -451,12 +449,12 @@ impl<'tcx> TypeMap<'tcx> { unique_type_id.push(','); } - if sig.variadic { + if sig.0.variadic { unique_type_id.push_str("..."); } unique_type_id.push_str(")->"); - match sig.output { + match sig.0.output { ty::FnConverging(ret_ty) => { let return_type_id = self.get_unique_type_id_of_type(cx, ret_ty); let return_type_id = self.get_unique_type_id_as_string(return_type_id); @@ -575,7 +573,7 @@ impl<'tcx> TypeMap<'tcx> { } }; - for ¶meter_type in sig.inputs.iter() { + for ¶meter_type in sig.0.inputs.iter() { let parameter_type_id = self.get_unique_type_id_of_type(cx, parameter_type); let parameter_type_id = @@ -584,13 +582,13 @@ impl<'tcx> TypeMap<'tcx> { unique_type_id.push(','); } - if sig.variadic { + if sig.0.variadic { unique_type_id.push_str("..."); } unique_type_id.push_str("|->"); - match sig.output { + match sig.0.output { ty::FnConverging(ret_ty) => { let return_type_id = self.get_unique_type_id_of_type(cx, ret_ty); let return_type_id = self.get_unique_type_id_as_string(return_type_id); @@ -2320,14 +2318,13 @@ impl<'tcx> VariantMemberDescriptionFactory<'tcx> { } } +#[deriving(Copy)] enum EnumDiscriminantInfo { RegularDiscriminant(DIType), OptimizedDiscriminant(adt::PointerField), NoDiscriminant } -impl Copy for EnumDiscriminantInfo {} - // Returns a tuple of (1) type_metadata_stub of the variant, (2) the llvm_type // of the variant, and (3) a MemberDescriptionFactory for producing the // descriptions of the fields of the variant. This is a rudimentary version of a @@ -2787,13 +2784,13 @@ fn vec_slice_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, unique_type_id: UniqueTypeId, - signature: &ty::FnSig<'tcx>, + signature: &ty::PolyFnSig<'tcx>, span: Span) -> MetadataCreationResult { - let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs.len() + 1); + let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.0.inputs.len() + 1); // return type - signature_metadata.push(match signature.output { + signature_metadata.push(match signature.0.output { ty::FnConverging(ret_ty) => match ret_ty.sty { ty::ty_tup(ref tys) if tys.is_empty() => ptr::null_mut(), _ => type_metadata(cx, ret_ty, span) @@ -2802,7 +2799,7 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }); // regular arguments - for &argument_type in signature.inputs.iter() { + for &argument_type in signature.0.inputs.iter() { signature_metadata.push(type_metadata(cx, argument_type, span)); } @@ -2834,7 +2831,7 @@ fn trait_pointer_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // But it does not describe the trait's methods. let def_id = match trait_type.sty { - ty::ty_trait(box ty::TyTrait { ref principal, .. }) => principal.def_id, + ty::ty_trait(box ty::TyTrait { ref principal, .. }) => principal.def_id(), _ => { let pp_type_name = ppaux::ty_to_string(cx.tcx(), trait_type); cx.sess().bug(format!("debuginfo: Unexpected trait-object type in \ @@ -3047,14 +3044,12 @@ impl MetadataCreationResult { } } -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] enum DebugLocation { KnownLocation { scope: DIScope, line: uint, col: uint }, UnknownLocation } -impl Copy for DebugLocation {} - impl DebugLocation { fn new(scope: DIScope, line: uint, col: uint) -> DebugLocation { KnownLocation { @@ -3765,8 +3760,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push(']'); }, ty::ty_trait(ref trait_data) => { - push_item_name(cx, trait_data.principal.def_id, false, output); - push_type_params(cx, &trait_data.principal.substs, output); + push_item_name(cx, trait_data.principal.def_id(), false, output); + push_type_params(cx, trait_data.principal.substs(), output); }, ty::ty_bare_fn(ty::BareFnTy{ unsafety, abi, ref sig } ) => { if unsafety == ast::Unsafety::Unsafe { @@ -3781,8 +3776,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push_str("fn("); - if sig.inputs.len() > 0 { - for ¶meter_type in sig.inputs.iter() { + if sig.0.inputs.len() > 0 { + for ¶meter_type in sig.0.inputs.iter() { push_debuginfo_type_name(cx, parameter_type, true, output); output.push_str(", "); } @@ -3790,8 +3785,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.pop(); } - if sig.variadic { - if sig.inputs.len() > 0 { + if sig.0.variadic { + if sig.0.inputs.len() > 0 { output.push_str(", ..."); } else { output.push_str("..."); @@ -3800,7 +3795,7 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push(')'); - match sig.output { + match sig.0.output { ty::FnConverging(result_type) if ty::type_is_nil(result_type) => {} ty::FnConverging(result_type) => { output.push_str(" -> "); @@ -3841,8 +3836,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } }; - if sig.inputs.len() > 0 { - for ¶meter_type in sig.inputs.iter() { + if sig.0.inputs.len() > 0 { + for ¶meter_type in sig.0.inputs.iter() { push_debuginfo_type_name(cx, parameter_type, true, output); output.push_str(", "); } @@ -3850,8 +3845,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.pop(); } - if sig.variadic { - if sig.inputs.len() > 0 { + if sig.0.variadic { + if sig.0.inputs.len() > 0 { output.push_str(", ..."); } else { output.push_str("..."); @@ -3860,7 +3855,7 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push(param_list_closing_char); - match sig.output { + match sig.0.output { ty::FnConverging(result_type) if ty::type_is_nil(result_type) => {} ty::FnConverging(result_type) => { output.push_str(" -> "); diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 304142453a9..dd87879b737 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -73,14 +73,12 @@ use std::rc::Rc; // These are passed around by the code generating functions to track the // destination of a computation's value. -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub enum Dest { SaveIn(ValueRef), Ignore, } -impl Copy for Dest {} - impl Dest { pub fn to_string(&self, ccx: &CrateContext) -> String { match *self { @@ -316,10 +314,10 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx.ty_to_string(unadjusted_ty)).as_slice()) }, &ty::UnsizeVtable(ty::TyTrait { ref principal, .. }, _) => { - let substs = principal.substs.with_self_ty(unadjusted_ty).erase_regions(); + let substs = principal.substs().with_self_ty(unadjusted_ty).erase_regions(); let trait_ref = - Rc::new(ty::TraitRef { def_id: principal.def_id, - substs: substs }); + Rc::new(ty::Binder(ty::TraitRef { def_id: principal.def_id(), + substs: substs })); let trait_ref = trait_ref.subst(bcx.tcx(), bcx.fcx.param_substs); let box_ty = mk_ty(unadjusted_ty); PointerCast(bcx, @@ -1889,7 +1887,7 @@ fn float_cast(bcx: Block, } else { llsrc }; } -#[deriving(PartialEq, Show)] +#[deriving(Copy, PartialEq, Show)] pub enum cast_kind { cast_pointer, cast_integral, @@ -1898,8 +1896,6 @@ pub enum cast_kind { cast_other, } -impl Copy for cast_kind {} - pub fn cast_type_kind<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> cast_kind { match t.sty { ty::ty_char => cast_integral, diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 615d5467f84..d0720319930 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -22,7 +22,6 @@ use trans::machine; use trans::type_::Type; use trans::type_of::*; use trans::type_of; -use middle::ty::FnSig; use middle::ty::{mod, Ty}; use middle::subst::{Subst, Substs}; use std::cmp; @@ -41,7 +40,7 @@ use util::ppaux::Repr; struct ForeignTypes<'tcx> { /// Rust signature of the function - fn_sig: ty::FnSig<'tcx>, + fn_sig: ty::PolyFnSig<'tcx>, /// Adapter object for handling native ABI rules (trust me, you /// don't want to know) @@ -179,7 +178,7 @@ pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Make sure the calling convention is right for variadic functions // (should've been caught if not in typeck) - if tys.fn_sig.variadic { + if tys.fn_sig.0.variadic { assert!(cc == llvm::CCallConv); } @@ -386,7 +385,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debug!("llforeign_ret_ty={}", ccx.tn().type_to_string(llforeign_ret_ty)); if llrust_ret_ty == llforeign_ret_ty { - match fn_sig.output { + match fn_sig.0.output { ty::FnConverging(result_ty) => { base::store_ty(bcx, llforeign_retval, llretptr, result_ty) } @@ -632,7 +631,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }; // Push Rust return pointer, using null if it will be unused. - let rust_uses_outptr = match tys.fn_sig.output { + let rust_uses_outptr = match tys.fn_sig.0.output { ty::FnConverging(ret_ty) => type_of::return_uses_outptr(ccx, ret_ty), ty::FnDiverging => false }; @@ -665,7 +664,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return_ty={}", ccx.tn().val_to_string(slot), ccx.tn().type_to_string(llrust_ret_ty), - tys.fn_sig.output.repr(tcx)); + tys.fn_sig.0.output.repr(tcx)); llrust_args.push(slot); return_alloca = Some(slot); } @@ -680,8 +679,8 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Build up the arguments to the call to the rust function. // Careful to adapt for cases where the native convention uses // a pointer and Rust does not or vice versa. - for i in range(0, tys.fn_sig.inputs.len()) { - let rust_ty = tys.fn_sig.inputs[i]; + for i in range(0, tys.fn_sig.0.inputs.len()) { + let rust_ty = tys.fn_sig.0.inputs[i]; let llrust_ty = tys.llsig.llarg_tys[i]; let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty); let llforeign_arg_ty = tys.fn_ty.arg_tys[i]; @@ -826,10 +825,10 @@ pub fn link_name(i: &ast::ForeignItem) -> InternedString { /// because foreign functions just plain ignore modes. They also don't pass aggregate values by /// pointer like we do. fn foreign_signature<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - fn_sig: &ty::FnSig<'tcx>, arg_tys: &[Ty<'tcx>]) + fn_sig: &ty::PolyFnSig<'tcx>, arg_tys: &[Ty<'tcx>]) -> LlvmSignature { let llarg_tys = arg_tys.iter().map(|&arg| arg_type_of(ccx, arg)).collect(); - let (llret_ty, ret_def) = match fn_sig.output { + let (llret_ty, ret_def) = match fn_sig.0.output { ty::FnConverging(ret_ty) => (type_of::arg_type_of(ccx, ret_ty), !return_type_is_void(ccx, ret_ty)), ty::FnDiverging => @@ -853,7 +852,7 @@ fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty::ty_bare_fn(ref fn_ty) => fn_ty.sig.clone(), _ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type") }; - let llsig = foreign_signature(ccx, &fn_sig, fn_sig.inputs.as_slice()); + let llsig = foreign_signature(ccx, &fn_sig, fn_sig.0.inputs.as_slice()); let fn_ty = cabi::compute_abi_info(ccx, llsig.llarg_tys.as_slice(), llsig.llret_ty, @@ -913,7 +912,7 @@ fn lltype_for_fn_from_foreign_types(ccx: &CrateContext, tys: &ForeignTypes) -> T llargument_tys.push(llarg_ty); } - if tys.fn_sig.variadic { + if tys.fn_sig.0.variadic { Type::variadic_func(llargument_tys.as_slice(), &llreturn_ty) } else { Type::func(llargument_tys.as_slice(), &llreturn_ty) diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 4575d8a41e5..dea095ecaf5 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -227,8 +227,8 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let fty = ty::lookup_item_type(bcx.tcx(), dtor_did).ty.subst(bcx.tcx(), substs); let self_ty = match fty.sty { ty::ty_bare_fn(ref f) => { - assert!(f.sig.inputs.len() == 1); - f.sig.inputs[0] + assert!(f.sig.0.inputs.len() == 1); + f.sig.0.inputs[0] } _ => bcx.sess().bug(format!("Expected function type, found {}", bcx.ty_to_string(fty)).as_slice()) diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 890652401d7..a6f7c849f4d 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -150,7 +150,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let tcx = bcx.tcx(); let ret_ty = match callee_ty.sty { - ty::ty_bare_fn(ref f) => f.sig.output, + ty::ty_bare_fn(ref f) => f.sig.0.output, _ => panic!("expected bare_fn in trans_intrinsic_call") }; let foreign_item = tcx.map.expect_foreign_item(node); diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 9a2bc38acdf..f1c3c9be396 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -133,16 +133,16 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, method_num }) => { let trait_ref = - Rc::new(trait_ref.subst(bcx.tcx(), bcx.fcx.param_substs)); + Rc::new(ty::Binder((**trait_ref).subst(bcx.tcx(), bcx.fcx.param_substs))); let span = bcx.tcx().map.span(method_call.expr_id); debug!("method_call={} trait_ref={}", method_call, trait_ref.repr(bcx.tcx())); let origin = fulfill_obligation(bcx.ccx(), span, - (*trait_ref).clone()); + trait_ref.clone()); debug!("origin = {}", origin.repr(bcx.tcx())); - trans_monomorphized_callee(bcx, method_call, trait_ref.def_id, + trans_monomorphized_callee(bcx, method_call, trait_ref.def_id(), method_num, origin) } @@ -239,8 +239,8 @@ pub fn trans_static_method_callee(bcx: Block, rcvr_assoc, Vec::new())); debug!("trait_substs={}", trait_substs.repr(bcx.tcx())); - let trait_ref = Rc::new(ty::TraitRef { def_id: trait_id, - substs: trait_substs }); + let trait_ref = Rc::new(ty::Binder(ty::TraitRef { def_id: trait_id, + substs: trait_substs })); let vtbl = fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref); @@ -480,8 +480,8 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ty::ty_bare_fn(ref f) if f.abi == Rust || f.abi == RustCall => { type_of_rust_fn(ccx, Some(Type::i8p(ccx)), - f.sig.inputs.slice_from(1), - f.sig.output, + f.sig.0.inputs.slice_from(1), + f.sig.0.output, f.abi) } _ => { @@ -515,7 +515,7 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// This will hopefully change now that DST is underway. pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, box_ty: Ty<'tcx>, - trait_ref: Rc<ty::TraitRef<'tcx>>) + trait_ref: Rc<ty::PolyTraitRef<'tcx>>) -> ValueRef { debug!("get_vtable(box_ty={}, trait_ref={})", @@ -670,7 +670,7 @@ fn emit_vtable_methods<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pub fn trans_trait_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, Expr>, id: ast::NodeId, - trait_ref: Rc<ty::TraitRef<'tcx>>, + trait_ref: Rc<ty::PolyTraitRef<'tcx>>, dest: expr::Dest) -> Block<'blk, 'tcx> { let mut bcx = bcx; diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs index 9234dfc48bd..05797d74fee 100644 --- a/src/librustc_trans/trans/mod.rs +++ b/src/librustc_trans/trans/mod.rs @@ -54,13 +54,12 @@ mod basic_block; mod llrepr; mod cleanup; +#[deriving(Copy)] pub struct ModuleTranslation { pub llcx: ContextRef, pub llmod: ModuleRef, } -impl Copy for ModuleTranslation {} - pub struct CrateTranslation { pub modules: Vec<ModuleTranslation>, pub metadata_module: ModuleTranslation, diff --git a/src/librustc_trans/trans/tvec.rs b/src/librustc_trans/trans/tvec.rs index 18ea8055a4e..e09032ac2d0 100644 --- a/src/librustc_trans/trans/tvec.rs +++ b/src/librustc_trans/trans/tvec.rs @@ -89,6 +89,7 @@ pub fn make_drop_glue_unboxed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }) } +#[deriving(Copy)] pub struct VecTypes<'tcx> { pub unit_ty: Ty<'tcx>, pub llunit_ty: Type, @@ -96,8 +97,6 @@ pub struct VecTypes<'tcx> { pub llunit_alloc_size: u64 } -impl<'tcx> Copy for VecTypes<'tcx> {} - impl<'tcx> VecTypes<'tcx> { pub fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String { format!("VecTypes {{unit_ty={}, llunit_ty={}, \ diff --git a/src/librustc_trans/trans/type_.rs b/src/librustc_trans/trans/type_.rs index 70b1e99ce8e..51a0533a7bb 100644 --- a/src/librustc_trans/trans/type_.rs +++ b/src/librustc_trans/trans/type_.rs @@ -25,14 +25,12 @@ use std::cell::RefCell; use libc::c_uint; -#[deriving(Clone, PartialEq, Show)] +#[deriving(Clone, Copy, PartialEq, Show)] #[repr(C)] pub struct Type { rf: TypeRef } -impl Copy for Type {} - macro_rules! ty { ($e:expr) => ( Type::from_ref(unsafe { $e })) } diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index adc919c91bf..2801e0ccead 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -146,16 +146,16 @@ pub fn type_of_fn_from_ty<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fty: Ty<'tcx>) ty::ty_closure(ref f) => { type_of_rust_fn(cx, Some(Type::i8p(cx)), - f.sig.inputs.as_slice(), - f.sig.output, + f.sig.0.inputs.as_slice(), + f.sig.0.output, f.abi) } ty::ty_bare_fn(ref f) => { if f.abi == abi::Rust || f.abi == abi::RustCall { type_of_rust_fn(cx, None, - f.sig.inputs.as_slice(), - f.sig.output, + f.sig.0.inputs.as_slice(), + f.sig.0.output, f.abi) } else { foreign::lltype_for_foreign_fn(cx, fty) @@ -443,14 +443,13 @@ pub fn align_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) } // Want refinements! (Or case classes, I guess +#[deriving(Copy)] pub enum named_ty { a_struct, an_enum, an_unboxed_closure, } -impl Copy for named_ty {} - pub fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, what: named_ty, did: ast::DefId, diff --git a/src/librustc_trans/trans/value.rs b/src/librustc_trans/trans/value.rs index c7cf86fb184..4f9b8c5ea37 100644 --- a/src/librustc_trans/trans/value.rs +++ b/src/librustc_trans/trans/value.rs @@ -14,10 +14,9 @@ use trans::basic_block::BasicBlock; use trans::common::Block; use libc::c_uint; +#[deriving(Copy)] pub struct Value(pub ValueRef); -impl Copy for Value {} - macro_rules! opt_val { ($e:expr) => ( unsafe { match $e { @@ -126,10 +125,9 @@ impl Value { } /// Wrapper for LLVM UseRef +#[deriving(Copy)] pub struct Use(UseRef); -impl Copy for Use {} - impl Use { pub fn get(&self) -> UseRef { let Use(v) = *self; v diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 87eda76db29..4f4bebabead 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -53,8 +53,7 @@ use middle::def; use middle::resolve_lifetime as rl; use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs}; use middle::subst::{VecPerParamSpace}; -use middle::ty::{mod, Ty}; -use middle::ty_fold; +use middle::ty::{mod, RegionEscape, Ty}; use rscope::{mod, UnelidableRscope, RegionScope, SpecificRscope, ShiftedRscope, BindingRscope}; use TypeAndSubsts; @@ -524,6 +523,20 @@ fn convert_parenthesized_parameters<'tcx,AC>(this: &AC, vec![input_ty, output] } +pub fn instantiate_poly_trait_ref<'tcx,AC,RS>( + this: &AC, + rscope: &RS, + ast_trait_ref: &ast::PolyTraitRef, + self_ty: Option<Ty<'tcx>>, + allow_eq: AllowEqConstraints) + -> Rc<ty::PolyTraitRef<'tcx>> + where AC: AstConv<'tcx>, RS: RegionScope +{ + let trait_ref = + instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, self_ty, allow_eq); + let trait_ref = (*trait_ref).clone(); + Rc::new(ty::Binder(trait_ref)) // Ugh. +} /// Instantiates the path for the given trait reference, assuming that it's /// bound to a valid trait type. Returns the def_id for the defining trait. @@ -537,9 +550,7 @@ pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC, where AC: AstConv<'tcx>, RS: RegionScope { - match ::lookup_def_tcx(this.tcx(), - ast_trait_ref.path.span, - ast_trait_ref.ref_id) { + match ::lookup_def_tcx(this.tcx(), ast_trait_ref.path.span, ast_trait_ref.ref_id) { def::DefTrait(trait_def_id) => { let trait_ref = Rc::new(ast_path_to_trait_ref(this, rscope, @@ -749,7 +760,7 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, rscope: &RS, ty: &ast::Ty, bounds: &[ast::TyParamBound]) - -> Result<ty::TraitRef<'tcx>, ErrorReported> + -> Result<ty::PolyTraitRef<'tcx>, ErrorReported> where AC : AstConv<'tcx>, RS : RegionScope { /*! @@ -767,12 +778,12 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, ast::TyPath(ref path, id) => { match this.tcx().def_map.borrow().get(&id) { Some(&def::DefTrait(trait_def_id)) => { - return Ok(ast_path_to_trait_ref(this, - rscope, - trait_def_id, - None, - path, - AllowEqConstraints::Allow)); + return Ok(ty::Binder(ast_path_to_trait_ref(this, + rscope, + trait_def_id, + None, + path, + AllowEqConstraints::Allow))); } _ => { span_err!(this.tcx().sess, ty.span, E0172, "expected a reference to a trait"); @@ -814,7 +825,7 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC, rscope: &RS, span: Span, - trait_ref: ty::TraitRef<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, bounds: &[ast::TyParamBound]) -> Ty<'tcx> where AC : AstConv<'tcx>, RS : RegionScope @@ -982,12 +993,12 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( def::DefTrait(trait_def_id) => { // N.B. this case overlaps somewhat with // TyObjectSum, see that fn for details - let result = ast_path_to_trait_ref(this, - rscope, - trait_def_id, - None, - path, - AllowEqConstraints::Allow); + let result = ty::Binder(ast_path_to_trait_ref(this, + rscope, + trait_def_id, + None, + path, + AllowEqConstraints::Allow)); trait_ref_to_object_type(this, rscope, path.span, result, &[]) } def::DefTy(did, _) | def::DefStruct(did) => { @@ -1039,7 +1050,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( let ty_param_defs = tcx.ty_param_defs.borrow(); let tp_def = &(*ty_param_defs)[did.node]; let assoc_tys = tp_def.bounds.trait_bounds.iter() - .filter_map(|b| find_assoc_ty(this, &**b, assoc_ident)) + .filter_map(|b| find_assoc_ty(this, &b.0, assoc_ident)) .collect(); (assoc_tys, token::get_name(tp_def.name).to_string()) } @@ -1189,10 +1200,9 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>( let (self_ty, mut implied_output_region) = match opt_self_info { None => (None, None), Some(self_info) => { - // Shift regions in the self type by 1 to account for the binding - // level introduced by the function itself. - let untransformed_self_ty = - ty_fold::shift_regions(this.tcx(), 1, &self_info.untransformed_self_ty); + // This type comes from an impl or trait; no late-bound + // regions should be present. + assert!(!self_info.untransformed_self_ty.has_escaping_regions()); // Figure out and record the explicit self category. let explicit_self_category = @@ -1203,19 +1213,19 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>( (None, None) } ty::ByValueExplicitSelfCategory => { - (Some(untransformed_self_ty), None) + (Some(self_info.untransformed_self_ty), None) } ty::ByReferenceExplicitSelfCategory(region, mutability) => { (Some(ty::mk_rptr(this.tcx(), region, ty::mt { - ty: untransformed_self_ty, + ty: self_info.untransformed_self_ty, mutbl: mutability })), Some(region)) } ty::ByBoxExplicitSelfCategory => { - (Some(ty::mk_uniq(this.tcx(), untransformed_self_ty)), None) + (Some(ty::mk_uniq(this.tcx(), self_info.untransformed_self_ty)), None) } } } @@ -1267,11 +1277,11 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>( (ty::BareFnTy { unsafety: unsafety, abi: abi, - sig: ty::FnSig { + sig: ty::Binder(ty::FnSig { inputs: self_and_input_tys, output: output_ty, variadic: decl.variadic - } + }), }, explicit_self_category_result) } @@ -1409,9 +1419,9 @@ pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>( store: store, bounds: bounds, abi: abi, - sig: ty::FnSig {inputs: input_tys, - output: output_ty, - variadic: decl.variadic} + sig: ty::Binder(ty::FnSig {inputs: input_tys, + output: output_ty, + variadic: decl.variadic}), } } @@ -1423,7 +1433,7 @@ pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( this: &AC, rscope: &RS, span: Span, - principal_trait_ref: Option<&ty::TraitRef<'tcx>>, // None for boxed closures + principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, // None for boxed closures ast_bounds: &[ast::TyParamBound]) -> ty::ExistentialBounds { @@ -1450,11 +1460,11 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>( let main_trait_bound = match partitioned_bounds.trait_bounds.remove(0) { Some(trait_bound) => { - Some(instantiate_trait_ref(this, - rscope, - &trait_bound.trait_ref, - None, - AllowEqConstraints::Allow)) + Some(instantiate_poly_trait_ref(this, + rscope, + trait_bound, + None, + AllowEqConstraints::Allow)) } None => { this.tcx().sess.span_err( @@ -1481,7 +1491,7 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>( this: &AC, rscope: &RS, span: Span, - principal_trait_ref: Option<&ty::TraitRef<'tcx>>, // None for boxed closures + principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, // None for boxed closures partitioned_bounds: PartitionedBounds) -> ty::ExistentialBounds where AC: AstConv<'tcx>, RS:RegionScope @@ -1519,7 +1529,7 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>( fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, explicit_region_bounds: &[&ast::Lifetime], - principal_trait_ref: Option<&ty::TraitRef<'tcx>>, + principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, builtin_bounds: ty::BuiltinBounds) -> Option<ty::Region> { @@ -1579,7 +1589,7 @@ fn compute_region_bound<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( rscope: &RS, span: Span, region_bounds: &[&ast::Lifetime], - principal_trait_ref: Option<&ty::TraitRef<'tcx>>, // None for closures + principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, // None for closures builtin_bounds: ty::BuiltinBounds) -> ty::Region { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index b88da5d9387..44cc5fce53d 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -9,7 +9,7 @@ // except according to those terms. use middle::def; -use middle::infer::{mod, resolve}; +use middle::infer; use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const}; use middle::subst::{Subst, Substs}; use middle::ty::{mod, Ty}; @@ -18,6 +18,7 @@ use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation}; use check::{instantiate_path, structurally_resolved_type, valid_range_bounds}; use require_same_types; use util::nodemap::FnvHashMap; +use util::ppaux::Repr; use std::cmp; use std::collections::hash_map::{Occupied, Vacant}; @@ -33,6 +34,10 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; + debug!("check_pat(pat={},expected={})", + pat.repr(tcx), + expected.repr(tcx)); + match pat.node { ast::PatWild(_) => { fcx.write_ty(pat.id, expected); @@ -143,11 +148,8 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, ast::PatRegion(ref inner) => { let inner_ty = fcx.infcx().next_ty_var(); - let mutbl = infer::resolve_type( - fcx.infcx(), Some(pat.span), - expected, resolve::try_resolve_tvar_shallow) - .ok() - .and_then(|t| ty::deref(t, true)) + let mutbl = + ty::deref(fcx.infcx().shallow_resolve(expected), true) .map_or(ast::MutImmutable, |mt| mt.mutbl); let mt = ty::mt { ty: inner_ty, mutbl: mutbl }; @@ -214,23 +216,21 @@ pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, inner: &ast::Pat) -> bool { let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; - match infer::resolve_type( - fcx.infcx(), Some(span), - expected, resolve::try_resolve_tvar_shallow) { - Ok(t) if pat_is_binding(&tcx.def_map, inner) => { - ty::deref(t, true).map_or(true, |mt| match mt.ty.sty { - ty::ty_trait(_) => { - // This is "x = SomeTrait" being reduced from - // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error. - span_err!(tcx.sess, span, E0033, - "type `{}` cannot be dereferenced", - fcx.infcx().ty_to_string(t)); - false - } - _ => true - }) - } - _ => true + if pat_is_binding(&tcx.def_map, inner) { + let expected = fcx.infcx().shallow_resolve(expected); + ty::deref(expected, true).map_or(true, |mt| match mt.ty.sty { + ty::ty_trait(_) => { + // This is "x = SomeTrait" being reduced from + // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error. + span_err!(tcx.sess, span, E0033, + "type `{}` cannot be dereferenced", + fcx.infcx().ty_to_string(expected)); + false + } + _ => true + }) + } else { + true } } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index e3fec2c8b1d..2ade3040d6c 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -129,7 +129,7 @@ fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, // Tuple up the arguments and insert the resulting function type into // the `unboxed_closures` table. - fn_ty.sig.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.inputs)]; + fn_ty.sig.0.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.0.inputs)]; debug!("unboxed_closure for {} --> sig={} kind={}", expr_def_id.repr(fcx.tcx()), @@ -180,7 +180,7 @@ fn deduce_unboxed_closure_expectations_from_expected_type<'a,'tcx>( fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>( fcx: &FnCtxt<'a,'tcx>, - trait_ref: &ty::TraitRef<'tcx>) + trait_ref: &ty::PolyTraitRef<'tcx>) -> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)> { let tcx = fcx.tcx(); @@ -188,15 +188,15 @@ fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>( debug!("deduce_unboxed_closure_expectations_from_object_type({})", trait_ref.repr(tcx)); - let kind = match tcx.lang_items.fn_trait_kind(trait_ref.def_id) { + let kind = match tcx.lang_items.fn_trait_kind(trait_ref.def_id()) { Some(k) => k, None => { return None; } }; debug!("found object type {}", kind); - let arg_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 0); - let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(arg_param_ty); + let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0); + let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty); debug!("arg_param_ty {}", arg_param_ty.repr(tcx)); let input_tys = match arg_param_ty.sty { @@ -205,8 +205,8 @@ fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>( }; debug!("input_tys {}", input_tys.repr(tcx)); - let ret_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 1); - let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(ret_param_ty); + let ret_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 1); + let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty); debug!("ret_param_ty {}", ret_param_ty.repr(tcx)); let fn_sig = ty::FnSig { diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 980097eaead..9af9eaf75f5 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -12,8 +12,6 @@ use check::FnCtxt; use middle::ty::{mod, Ty}; use middle::infer; -use middle::infer::resolve_type; -use middle::infer::resolve::try_resolve_tvar_shallow; use std::result::Result::{Err, Ok}; use syntax::ast; @@ -63,12 +61,7 @@ pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, debug!("demand::coerce(expected = {}, expr_ty = {})", expected.repr(fcx.ccx.tcx), expr_ty.repr(fcx.ccx.tcx)); - let expected = if ty::type_needs_infer(expected) { - resolve_type(fcx.infcx(), - None, - expected, - try_resolve_tvar_shallow).unwrap_or(expected) - } else { expected }; + let expected = fcx.infcx().resolve_type_vars_if_possible(&expected); match fcx.mk_assignty(expr, expr_ty, expected) { Ok(()) => { /* ok */ } Err(ref err) => { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 7463652a931..2c220f29826 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -16,9 +16,9 @@ use middle::traits; use middle::ty::{mod, Ty}; use middle::ty::{MethodCall, MethodCallee, MethodObject, MethodOrigin, MethodParam, MethodStatic, MethodTraitObject, MethodTypeParam}; +use middle::ty_fold::TypeFoldable; use middle::infer; use middle::infer::InferCtxt; -use middle::ty_fold::HigherRankedFoldable; use syntax::ast; use syntax::codemap::Span; use std::rc::Rc; @@ -114,7 +114,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // Create the final `MethodCallee`. let fty = ty::mk_bare_fn(self.tcx(), ty::BareFnTy { - sig: method_sig, + sig: ty::Binder(method_sig), unsafety: pick.method_ty.fty.unsafety, abi: pick.method_ty.fty.abi.clone(), }); @@ -222,17 +222,19 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // argument type), but those cases have already // been ruled out when we deemed the trait to be // "object safe". - let substs = data.principal.substs.clone().with_self_ty(object_ty); - let original_trait_ref = - Rc::new(ty::TraitRef::new(data.principal.def_id, substs)); - let upcast_trait_ref = this.upcast(original_trait_ref.clone(), trait_def_id); - debug!("original_trait_ref={} upcast_trait_ref={} target_trait={}", - original_trait_ref.repr(this.tcx()), + let original_poly_trait_ref = + data.principal_trait_ref_with_self_ty(object_ty); + let upcast_poly_trait_ref = + this.upcast(original_poly_trait_ref.clone(), trait_def_id); + let upcast_trait_ref = + this.replace_late_bound_regions_with_fresh_var(&*upcast_poly_trait_ref); + debug!("original_poly_trait_ref={} upcast_trait_ref={} target_trait={}", + original_poly_trait_ref.repr(this.tcx()), upcast_trait_ref.repr(this.tcx()), trait_def_id.repr(this.tcx())); let substs = upcast_trait_ref.substs.clone(); let origin = MethodTraitObject(MethodObject { - trait_ref: upcast_trait_ref, + trait_ref: Rc::new(upcast_trait_ref), object_trait_id: trait_def_id, method_num: method_num, real_index: real_index, @@ -272,16 +274,21 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { &trait_def.generics, self.infcx().next_ty_var()); - let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs.clone())); + let trait_ref = + Rc::new(ty::TraitRef::new(trait_def_id, substs.clone())); let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref, method_num: method_num }); (substs, origin) } - probe::WhereClausePick(ref trait_ref, method_num) => { - let origin = MethodTypeParam(MethodParam { trait_ref: (*trait_ref).clone(), + probe::WhereClausePick(ref poly_trait_ref, method_num) => { + // Where clauses can have bound regions in them. We need to instantiate + // those to convert from a poly-trait-ref to a trait-ref. + let trait_ref = self.replace_late_bound_regions_with_fresh_var(&**poly_trait_ref); + let substs = trait_ref.substs.clone(); + let origin = MethodTypeParam(MethodParam { trait_ref: Rc::new(trait_ref), method_num: method_num }); - (trait_ref.substs.clone(), origin) + (substs, origin) } } } @@ -378,25 +385,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { all_substs: subst::Substs<'tcx>) -> InstantiatedMethodSig<'tcx> { - // If this method comes from an impl (as opposed to a trait), - // it may have late-bound regions from the impl that appear in - // the substitutions, method signature, and - // bounds. Instantiate those at this point. (If it comes from - // a trait, this step has no effect, as there are no - // late-bound regions to instantiate.) - // - // The binder level here corresponds to the impl. - let (all_substs, (method_sig, method_generics)) = - self.replace_late_bound_regions_with_fresh_var( - &ty::bind((all_substs, - (pick.method_ty.fty.sig.clone(), - pick.method_ty.generics.clone())))).value; - - debug!("late-bound lifetimes from impl instantiated, \ - all_substs={} method_sig={} method_generics={}", - all_substs.repr(self.tcx()), - method_sig.repr(self.tcx()), - method_generics.repr(self.tcx())); + debug!("instantiate_method_sig(pick={}, all_substs={})", + pick.repr(self.tcx()), + all_substs.repr(self.tcx())); // Instantiate the bounds on the method with the // type/early-bound-regions substitutions performed. The only @@ -426,8 +417,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { all_substs.clone() } }; - let method_bounds = - method_generics.to_bounds(self.tcx(), &method_bounds_substs); + let method_bounds = pick.method_ty.generics.to_bounds(self.tcx(), &method_bounds_substs); debug!("method_bounds after subst = {}", method_bounds.repr(self.tcx())); @@ -435,7 +425,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // Substitute the type/early-bound-regions into the method // signature. In addition, the method signature may bind // late-bound regions, so instantiate those. - let method_sig = method_sig.subst(self.tcx(), &all_substs); + let method_sig = pick.method_ty.fty.sig.subst(self.tcx(), &all_substs); let method_sig = self.replace_late_bound_regions_with_fresh_var(&method_sig); debug!("late-bound lifetimes from method instantiated, method_sig={}", @@ -481,7 +471,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { _ => return, }; - match sig.inputs[0].sty { + match sig.0.inputs[0].sty { ty::ty_rptr(_, ty::mt { ty: _, mutbl: ast::MutMutable, @@ -637,12 +627,12 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { } fn upcast(&mut self, - source_trait_ref: Rc<ty::TraitRef<'tcx>>, + source_trait_ref: Rc<ty::PolyTraitRef<'tcx>>, target_trait_def_id: ast::DefId) - -> Rc<ty::TraitRef<'tcx>> + -> Rc<ty::PolyTraitRef<'tcx>> { for super_trait_ref in traits::supertraits(self.tcx(), source_trait_ref.clone()) { - if super_trait_ref.def_id == target_trait_def_id { + if super_trait_ref.def_id() == target_trait_def_id { return super_trait_ref; } } @@ -654,8 +644,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { target_trait_def_id.repr(self.tcx()))[]); } - fn replace_late_bound_regions_with_fresh_var<T>(&self, value: &T) -> T - where T : HigherRankedFoldable<'tcx> + fn replace_late_bound_regions_with_fresh_var<T>(&self, value: &ty::Binder<T>) -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> { self.infcx().replace_late_bound_regions_with_fresh_var( self.span, infer::FnCall, value).0 diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index d97a9c9e39b..3b7eb22e56c 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -46,14 +46,12 @@ pub enum MethodError { // A pared down enum describing just the places from which a method // candidate can arise. Used for error reporting only. -#[deriving(PartialOrd, Ord, PartialEq, Eq)] +#[deriving(Copy, PartialOrd, Ord, PartialEq, Eq)] pub enum CandidateSource { ImplSource(ast::DefId), TraitSource(/* trait id */ ast::DefId), } -impl Copy for CandidateSource {} - type MethodIndex = uint; // just for doc purposes /// Determines whether the type `self_ty` supports a method name `method_name` or not. @@ -100,7 +98,7 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, call_expr.repr(fcx.tcx()), self_expr.repr(fcx.tcx())); - let self_ty = fcx.infcx().resolve_type_vars_if_possible(self_ty); + let self_ty = fcx.infcx().resolve_type_vars_if_possible(&self_ty); let pick = try!(probe::probe(fcx, span, method_name, self_ty, call_expr.id)); Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types)) } @@ -169,9 +167,10 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs)); // Construct an obligation + let poly_trait_ref = Rc::new(ty::Binder((*trait_ref).clone())); let obligation = traits::Obligation::misc(span, fcx.body_id, - ty::Predicate::Trait(trait_ref.clone())); + poly_trait_ref.as_predicate()); // Now we want to know if this can be matched let mut selcx = traits::SelectionContext::new(fcx.infcx(), @@ -194,9 +193,6 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, // Substitute the trait parameters into the method type and // instantiate late-bound regions to get the actual method type. - // - // Note that as the method comes from a trait, it can only have - // late-bound regions from the fn itself, not the impl. let ref bare_fn_ty = method_ty.fty; let fn_sig = bare_fn_ty.sig.subst(tcx, &trait_ref.substs); let fn_sig = fcx.infcx().replace_late_bound_regions_with_fresh_var(span, @@ -204,7 +200,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, &fn_sig).0; let transformed_self_ty = fn_sig.inputs[0]; let fty = ty::mk_bare_fn(tcx, ty::BareFnTy { - sig: fn_sig, + sig: ty::Binder(fn_sig), unsafety: bare_fn_ty.unsafety, abi: bare_fn_ty.abi.clone(), }); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 80e511b8fdf..b5776f9aeb3 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -19,8 +19,7 @@ use middle::subst; use middle::subst::Subst; use middle::traits; use middle::ty::{mod, Ty}; -use middle::ty::{MethodObject}; -use middle::ty_fold::HigherRankedFoldable; +use middle::ty_fold::TypeFoldable; use middle::infer; use middle::infer::InferCtxt; use syntax::ast; @@ -58,11 +57,11 @@ struct Candidate<'tcx> { enum CandidateKind<'tcx> { InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>), - ObjectCandidate(MethodObject<'tcx>), + ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ uint, /* real_index */ uint), ExtensionImplCandidate(/* Impl */ ast::DefId, Rc<ty::TraitRef<'tcx>>, subst::Substs<'tcx>, MethodIndex), UnboxedClosureCandidate(/* Trait */ ast::DefId, MethodIndex), - WhereClauseCandidate(Rc<ty::TraitRef<'tcx>>, MethodIndex), + WhereClauseCandidate(Rc<ty::PolyTraitRef<'tcx>>, MethodIndex), } pub struct Pick<'tcx> { @@ -77,7 +76,7 @@ pub enum PickKind<'tcx> { ObjectPick(/* Trait */ ast::DefId, /* method_num */ uint, /* real_index */ uint), ExtensionImplPick(/* Impl */ ast::DefId, MethodIndex), TraitPick(/* Trait */ ast::DefId, MethodIndex), - WhereClausePick(/* Trait */ Rc<ty::TraitRef<'tcx>>, MethodIndex), + WhereClausePick(/* Trait */ Rc<ty::PolyTraitRef<'tcx>>, MethodIndex), } pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError>; @@ -149,7 +148,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // this creates one big transaction so that all type variables etc // that we create during the probe process are removed later let mut dummy = Some((steps, opt_simplified_steps)); // FIXME(#18101) need once closures - fcx.infcx().probe(|| { + fcx.infcx().probe(|_| { let (steps, opt_simplified_steps) = dummy.take().unwrap(); let mut probe_cx = ProbeContext::new(fcx, span, method_name, steps, opt_simplified_steps); probe_cx.assemble_inherent_candidates(); @@ -231,9 +230,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self_ty.repr(self.tcx())); match self_ty.sty { - ty::ty_trait(box ty::TyTrait { ref principal, bounds, .. }) => { - self.assemble_inherent_candidates_from_object(self_ty, &*principal, bounds); - self.assemble_inherent_impl_candidates_for_type(principal.def_id); + ty::ty_trait(box ref data) => { + self.assemble_inherent_candidates_from_object(self_ty, data); + self.assemble_inherent_impl_candidates_for_type(data.principal.def_id()); } ty::ty_enum(did, _) | ty::ty_struct(did, _) | @@ -290,8 +289,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn assemble_inherent_candidates_from_object(&mut self, self_ty: Ty<'tcx>, - principal: &ty::TraitRef<'tcx>, - _bounds: ty::ExistentialBounds) { + data: &ty::TyTrait<'tcx>) { debug!("assemble_inherent_candidates_from_object(self_ty={})", self_ty.repr(self.tcx())); @@ -304,29 +302,17 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // a substitution that replaces `Self` with the object type // itself. Hence, a `&self` method will wind up with an // argument type like `&Trait`. - let rcvr_substs = principal.substs.clone().with_self_ty(self_ty); - let trait_ref = Rc::new(ty::TraitRef { - def_id: principal.def_id, - substs: rcvr_substs.clone() - }); - + let trait_ref = data.principal_trait_ref_with_self_ty(self_ty); self.elaborate_bounds(&[trait_ref.clone()], false, |this, new_trait_ref, m, method_num| { let vtable_index = - get_method_index(tcx, &*new_trait_ref, - trait_ref.clone(), method_num); + get_method_index(tcx, &*new_trait_ref, trait_ref.clone(), method_num); - let xform_self_ty = - this.xform_self_ty(&m, &new_trait_ref.substs); + let xform_self_ty = this.xform_self_ty(&m, new_trait_ref.substs()); this.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, method_ty: m, - kind: ObjectCandidate(MethodObject { - trait_ref: new_trait_ref, - object_trait_id: principal.def_id, - method_num: method_num, - real_index: vtable_index - }) + kind: ObjectCandidate(new_trait_ref.def_id(), method_num, vtable_index) }); }); } @@ -358,27 +344,27 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.elaborate_bounds(bounds.as_slice(), true, |this, trait_ref, m, method_num| { let xform_self_ty = - this.xform_self_ty(&m, &trait_ref.substs); + this.xform_self_ty(&m, trait_ref.substs()); debug!("found match: trait_ref={} substs={} m={}", trait_ref.repr(this.tcx()), - trait_ref.substs.repr(this.tcx()), + trait_ref.substs().repr(this.tcx()), m.repr(this.tcx())); assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(), - trait_ref.substs.types.get_slice(subst::TypeSpace).len()); + trait_ref.substs().types.get_slice(subst::TypeSpace).len()); assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(), - trait_ref.substs.regions().get_slice(subst::TypeSpace).len()); + trait_ref.substs().regions().get_slice(subst::TypeSpace).len()); assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(), - trait_ref.substs.types.get_slice(subst::SelfSpace).len()); + trait_ref.substs().types.get_slice(subst::SelfSpace).len()); assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(), - trait_ref.substs.regions().get_slice(subst::SelfSpace).len()); + trait_ref.substs().regions().get_slice(subst::SelfSpace).len()); // Because this trait derives from a where-clause, it // should not contain any inference variables or other // artifacts. This means it is safe to put into the // `WhereClauseCandidate` and (eventually) into the // `WhereClausePick`. - assert!(trait_ref.substs.types.iter().all(|&t| !ty::type_needs_infer(t))); + assert!(trait_ref.substs().types.iter().all(|&t| !ty::type_needs_infer(t))); this.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, @@ -392,10 +378,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // create the candidates. fn elaborate_bounds( &mut self, - bounds: &[Rc<ty::TraitRef<'tcx>>], + bounds: &[Rc<ty::PolyTraitRef<'tcx>>], num_includes_types: bool, mk_cand: for<'b> |this: &mut ProbeContext<'b, 'tcx>, - tr: Rc<ty::TraitRef<'tcx>>, + tr: Rc<ty::PolyTraitRef<'tcx>>, m: Rc<ty::Method<'tcx>>, method_num: uint|) { @@ -405,12 +391,12 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { let mut cache = HashSet::new(); for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { // Already visited this trait, skip it. - if !cache.insert(bound_trait_ref.def_id) { + if !cache.insert(bound_trait_ref.def_id()) { continue; } let (pos, method) = match trait_method(tcx, - bound_trait_ref.def_id, + bound_trait_ref.def_id(), self.method_name, num_includes_types) { Some(v) => v, @@ -418,7 +404,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { }; if !self.has_applicable_self(&*method) { - self.record_static_candidate(TraitSource(bound_trait_ref.def_id)); + self.record_static_candidate(TraitSource(bound_trait_ref.def_id())); } else { mk_cand(self, bound_trait_ref, method, pos); } @@ -756,7 +742,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self_ty.repr(self.tcx()), probe.repr(self.tcx())); - self.infcx().probe(|| { + self.infcx().probe(|_| { // First check that the self type can be related. match self.make_sub_ty(self_ty, probe.xform_self_ty) { Ok(()) => { } @@ -779,7 +765,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // Erase any late-bound regions bound in the impl // which appear in the bounds. - let impl_bounds = self.erase_late_bound_regions(&ty::bind(impl_bounds)).value; + let impl_bounds = self.erase_late_bound_regions(&ty::Binder(impl_bounds)); // Convert the bounds into obligations. let obligations = @@ -881,9 +867,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn xform_self_ty(&self, method: &Rc<ty::Method<'tcx>>, substs: &subst::Substs<'tcx>) - -> Ty<'tcx> { + -> Ty<'tcx> + { debug!("xform_self_ty(self_ty={}, substs={})", - method.fty.sig.inputs[0].repr(self.tcx()), + method.fty.sig.0.inputs[0].repr(self.tcx()), substs.repr(self.tcx())); // It is possible for type parameters or early-bound lifetimes @@ -916,15 +903,13 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { } // Replace early-bound regions and types. - let xform_self_ty = method.fty.sig.inputs[0].subst(self.tcx(), substs); + let xform_self_ty = method.fty.sig.0.inputs[0].subst(self.tcx(), substs); // Replace late-bound regions bound in the impl or - // where-clause (2 levels of binding). - let xform_self_ty = - self.erase_late_bound_regions(&ty::bind(ty::bind(xform_self_ty))).value.value; - - // Replace late-bound regions bound in the method (1 level of binding). - self.erase_late_bound_regions(&ty::bind(xform_self_ty)).value + // where-clause (2 levels of binding) and method (1 level of binding). + self.erase_late_bound_regions( + &self.erase_late_bound_regions( + &ty::Binder(ty::Binder(xform_self_ty)))) } fn impl_substs(&self, @@ -962,8 +947,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { /// region got replaced with the same variable, which requires a bit more coordination /// and/or tracking the substitution and /// so forth. - fn erase_late_bound_regions<T>(&self, value: &T) -> T - where T : HigherRankedFoldable<'tcx> + fn erase_late_bound_regions<T>(&self, value: &ty::Binder<T>) -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> { ty::erase_late_bound_regions(self.tcx(), value) } @@ -1007,8 +992,8 @@ fn trait_method<'tcx>(tcx: &ty::ctxt<'tcx>, // Determine the index of a method in the list of all methods belonging // to a trait and its supertraits. fn get_method_index<'tcx>(tcx: &ty::ctxt<'tcx>, - trait_ref: &ty::TraitRef<'tcx>, - subtrait: Rc<ty::TraitRef<'tcx>>, + trait_ref: &ty::PolyTraitRef<'tcx>, + subtrait: Rc<ty::PolyTraitRef<'tcx>>, n_method: uint) -> uint { // We need to figure the "real index" of the method in a // listing of all the methods of an object. We do this by @@ -1017,10 +1002,10 @@ fn get_method_index<'tcx>(tcx: &ty::ctxt<'tcx>, // methods from them. let mut method_count = n_method; ty::each_bound_trait_and_supertraits(tcx, &[subtrait], |bound_ref| { - if bound_ref.def_id == trait_ref.def_id { + if bound_ref.def_id() == trait_ref.def_id() { false } else { - let trait_items = ty::trait_items(tcx, bound_ref.def_id); + let trait_items = ty::trait_items(tcx, bound_ref.def_id()); for trait_item in trait_items.iter() { match *trait_item { ty::MethodTraitItem(_) => method_count += 1, @@ -1042,8 +1027,8 @@ impl<'tcx> Candidate<'tcx> { InherentImplCandidate(def_id, _) => { InherentImplPick(def_id) } - ObjectCandidate(ref data) => { - ObjectPick(data.trait_ref.def_id, data.method_num, data.real_index) + ObjectCandidate(def_id, method_num, real_index) => { + ObjectPick(def_id, method_num, real_index) } ExtensionImplCandidate(def_id, _, _, index) => { ExtensionImplPick(def_id, index) @@ -1057,7 +1042,7 @@ impl<'tcx> Candidate<'tcx> { // inference variables or other artifacts. This // means they are safe to put into the // `WhereClausePick`. - assert!(trait_ref.substs.types.iter().all(|&t| !ty::type_needs_infer(t))); + assert!(trait_ref.substs().types.iter().all(|&t| !ty::type_needs_infer(t))); WhereClausePick((*trait_ref).clone(), index) } @@ -1068,10 +1053,10 @@ impl<'tcx> Candidate<'tcx> { fn to_source(&self) -> CandidateSource { match self.kind { InherentImplCandidate(def_id, _) => ImplSource(def_id), - ObjectCandidate(ref obj) => TraitSource(obj.trait_ref.def_id), + ObjectCandidate(def_id, _, _) => TraitSource(def_id), ExtensionImplCandidate(def_id, _, _, _) => ImplSource(def_id), UnboxedClosureCandidate(trait_def_id, _) => TraitSource(trait_def_id), - WhereClauseCandidate(ref trait_ref, _) => TraitSource(trait_ref.def_id), + WhereClauseCandidate(ref trait_ref, _) => TraitSource(trait_ref.def_id()), } } @@ -1084,10 +1069,12 @@ impl<'tcx> Candidate<'tcx> { UnboxedClosureCandidate(trait_def_id, method_num) => { Some((trait_def_id, method_num)) } - ExtensionImplCandidate(_, ref trait_ref, _, method_num) | - WhereClauseCandidate(ref trait_ref, method_num) => { + ExtensionImplCandidate(_, ref trait_ref, _, method_num) => { Some((trait_ref.def_id, method_num)) } + WhereClauseCandidate(ref trait_ref, method_num) => { + Some((trait_ref.def_id(), method_num)) + } } } } @@ -1105,8 +1092,8 @@ impl<'tcx> Repr<'tcx> for CandidateKind<'tcx> { match *self { InherentImplCandidate(ref a, ref b) => format!("InherentImplCandidate({},{})", a.repr(tcx), b.repr(tcx)), - ObjectCandidate(ref a) => - format!("ObjectCandidate({})", a.repr(tcx)), + ObjectCandidate(a, b, c) => + format!("ObjectCandidate({},{},{})", a.repr(tcx), b, c), ExtensionImplCandidate(ref a, ref b, ref c, ref d) => format!("ExtensionImplCandidate({},{},{},{})", a.repr(tcx), b.repr(tcx), c.repr(tcx), d), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index def82ecd6c8..bbc33826f35 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -166,6 +166,7 @@ pub struct Inherited<'a, 'tcx: 'a> { /// When type-checking an expression, we propagate downward /// whatever type hint we are able in the form of an `Expectation`. +#[deriving(Copy)] enum Expectation<'tcx> { /// We know nothing about what type this expression should have. NoExpectation, @@ -177,8 +178,6 @@ enum Expectation<'tcx> { ExpectCastableToType(Ty<'tcx>), } -impl<'tcx> Copy for Expectation<'tcx> {} - impl<'tcx> Expectation<'tcx> { // Disregard "castable to" expectations because they // can lead us astray. Consider for example `if cond @@ -506,7 +505,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for GatherLocalsVisitor<'a, 'tcx> { fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, unsafety: ast::Unsafety, unsafety_id: ast::NodeId, - fn_sig: &ty::FnSig<'tcx>, + fn_sig: &ty::PolyFnSig<'tcx>, decl: &ast::FnDecl, fn_id: ast::NodeId, body: &ast::Block, @@ -625,23 +624,20 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) { let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id); check_bare_fn(ccx, &**decl, &**body, it.id, fn_pty.ty, param_env); } - ast::ItemImpl(_, _, ref opt_trait_ref, _, ref impl_items) => { + ast::ItemImpl(_, _, _, _, ref impl_items) => { debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id); let impl_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); - match *opt_trait_ref { - Some(ref ast_trait_ref) => { - let impl_trait_ref = - ty::node_id_to_trait_ref(ccx.tcx, ast_trait_ref.ref_id); + match ty::impl_trait_ref(ccx.tcx, local_def(it.id)) { + Some(impl_trait_ref) => { check_impl_items_against_trait(ccx, it.span, - ast_trait_ref, &*impl_trait_ref, impl_items.as_slice()); - } - None => { } - } + } + None => { } + } for impl_item in impl_items.iter() { match *impl_item { @@ -722,12 +718,7 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let param_env = ParameterEnvironment::for_item(ccx.tcx, method.id); let fty = ty::node_id_to_type(ccx.tcx, method.id); - debug!("fty (raw): {}", fty.repr(ccx.tcx)); - - let body_id = method.pe_body().id; - let fty = liberate_late_bound_regions( - ccx.tcx, CodeExtent::from_node_id(body_id), &ty::bind(fty)).value; - debug!("fty (liberated): {}", fty.repr(ccx.tcx)); + debug!("check_method_body: fty={}", fty.repr(ccx.tcx)); check_bare_fn(ccx, &*method.pe_fn_decl(), @@ -739,7 +730,6 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_span: Span, - ast_trait_ref: &ast::TraitRef, impl_trait_ref: &ty::TraitRef<'tcx>, impl_items: &[ast::ImplItem]) { // Locate trait methods @@ -772,21 +762,16 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_method.span, impl_method.pe_body().id, &**trait_method_ty, - impl_trait_ref); + &*impl_trait_ref); } _ => { // This is span_bug as it should have already been // caught in resolve. - tcx.sess - .span_bug(impl_method.span, - format!("item `{}` is of a \ - different kind from \ - its trait `{}`", - token::get_name( - impl_item_ty.name()), - pprust::path_to_string( - &ast_trait_ref.path)) - .as_slice()); + tcx.sess.span_bug( + impl_method.span, + format!("item `{}` is of a different kind from its trait `{}`", + token::get_name(impl_item_ty.name()), + impl_trait_ref.repr(tcx)).as_slice()); } } } @@ -795,11 +780,9 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // caught in resolve. tcx.sess.span_bug( impl_method.span, - format!( - "method `{}` is not a member of trait `{}`", - token::get_name(impl_item_ty.name()), - pprust::path_to_string( - &ast_trait_ref.path)).as_slice()); + format!("method `{}` is not a member of trait `{}`", + token::get_name(impl_item_ty.name()), + impl_trait_ref.repr(tcx)).as_slice()); } } } @@ -812,27 +795,19 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // corresponding type definition in the trait. let opt_associated_type = trait_items.iter() - .find(|ti| { - ti.name() == typedef_ty.name() - }); + .find(|ti| ti.name() == typedef_ty.name()); match opt_associated_type { Some(associated_type) => { match (associated_type, &typedef_ty) { - (&ty::TypeTraitItem(_), - &ty::TypeTraitItem(_)) => {} + (&ty::TypeTraitItem(_), &ty::TypeTraitItem(_)) => {} _ => { // This is `span_bug` as it should have // already been caught in resolve. - tcx.sess - .span_bug(typedef.span, - format!("item `{}` is of a \ - different kind from \ - its trait `{}`", - token::get_name( - typedef_ty.name()), - pprust::path_to_string( - &ast_trait_ref.path)) - .as_slice()); + tcx.sess.span_bug( + typedef.span, + format!("item `{}` is of a different kind from its trait `{}`", + token::get_name(typedef_ty.name()), + impl_trait_ref.repr(tcx)).as_slice()); } } } @@ -845,8 +820,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, "associated type `{}` is not a member of \ trait `{}`", token::get_name(typedef_ty.name()), - pprust::path_to_string( - &ast_trait_ref.path)).as_slice()); + impl_trait_ref.repr(tcx)).as_slice()); } } } @@ -854,8 +828,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } // Check for missing items from trait - let provided_methods = ty::provided_trait_methods(tcx, - impl_trait_ref.def_id); + let provided_methods = ty::provided_trait_methods(tcx, impl_trait_ref.def_id); let mut missing_methods = Vec::new(); for trait_item in trait_items.iter() { match *trait_item { @@ -870,8 +843,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } }); let is_provided = - provided_methods.iter().any( - |m| m.name == trait_method.name); + provided_methods.iter().any(|m| m.name == trait_method.name); if !is_implemented && !is_provided { missing_methods.push(format!("`{}`", token::get_name(trait_method.name))); } @@ -919,27 +891,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, debug!("compare_impl_method(impl_trait_ref={})", impl_trait_ref.repr(tcx)); - let impl_m_body_scope = CodeExtent::from_node_id(impl_m_body_id); - - // The impl's trait ref may bind late-bound regions from the impl. - // Liberate them and assign them the scope of the method body. - // - // An example would be: - // - // impl<'a> Foo<&'a T> for &'a U { ... } - // - // Here, the region parameter `'a` is late-bound, so the - // trait reference associated with the impl will be - // - // for<'a> Foo<&'a T> - // - // liberating will convert this into: - // - // Foo<&'A T> - // - // where `'A` is the `ReFree` version of `'a`. - let impl_trait_ref = liberate_late_bound_regions(tcx, impl_m_body_scope, impl_trait_ref); - debug!("impl_trait_ref (liberated) = {}", impl_trait_ref.repr(tcx)); @@ -996,15 +947,15 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, return; } - if impl_m.fty.sig.inputs.len() != trait_m.fty.sig.inputs.len() { + if impl_m.fty.sig.0.inputs.len() != trait_m.fty.sig.0.inputs.len() { span_err!(tcx.sess, impl_m_span, E0050, "method `{}` has {} parameter{} \ but the declaration in trait `{}` has {}", token::get_name(trait_m.name), - impl_m.fty.sig.inputs.len(), - if impl_m.fty.sig.inputs.len() == 1 {""} else {"s"}, + impl_m.fty.sig.0.inputs.len(), + if impl_m.fty.sig.0.inputs.len() == 1 {""} else {"s"}, ty::item_path_str(tcx, trait_m.def_id), - trait_m.fty.sig.inputs.len()); + trait_m.fty.sig.0.inputs.len()); return; } @@ -1081,7 +1032,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, if !check_region_bounds_on_impl_method(tcx, impl_m_span, impl_m, - impl_m_body_scope, &trait_m.generics, &impl_m.generics, &trait_to_skol_substs, @@ -1106,7 +1056,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, // `Bound<&'a T>`, the lifetime `'a` will be late-bound with a // depth of 3 (it is nested within 3 binders: the impl, method, // and trait-ref itself). So when we do the liberation, we have - // two introduce two `ty::bind` scopes, one for the impl and one + // two introduce two `ty::Binder` scopes, one for the impl and one // the method. // // The only late-bounded regions that can possibly appear here are @@ -1120,11 +1070,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, .map(|trait_param_def| &trait_param_def.bounds); let impl_bounds = impl_m.generics.types.get_slice(subst::FnSpace).iter() - .map(|impl_param_def| - liberate_late_bound_regions( - tcx, - impl_m_body_scope, - &ty::bind(ty::bind(impl_param_def.bounds.clone()))).value.value); + .map(|impl_param_def| &impl_param_def.bounds); for (i, (trait_param_bounds, impl_param_bounds)) in trait_bounds.zip(impl_bounds).enumerate() { @@ -1167,30 +1113,27 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, let trait_bound = trait_bound.subst(tcx, &trait_to_skol_substs); let infcx = infer::new_infer_ctxt(tcx); - infer::mk_sub_trait_refs(&infcx, - true, - infer::Misc(impl_m_span), - trait_bound, - impl_trait_bound.clone()).is_ok() + infer::mk_sub_poly_trait_refs(&infcx, + true, + infer::Misc(impl_m_span), + trait_bound, + impl_trait_bound.clone()).is_ok() }); if !found_match_in_trait { span_err!(tcx.sess, impl_m_span, E0052, - "in method `{}`, type parameter {} requires bound `{}`, which is not \ - required by the corresponding type parameter in the trait declaration", - token::get_name(trait_m.name), - i, - ppaux::trait_ref_to_string(tcx, &*impl_trait_bound)); + "in method `{}`, type parameter {} requires bound `{}`, which is not \ + required by the corresponding type parameter in the trait declaration", + token::get_name(trait_m.name), + i, + impl_trait_bound.user_string(tcx)); } } } - // Compute skolemized form of impl and trait method tys. Note - // that we must liberate the late-bound regions from the impl. + // Compute skolemized form of impl and trait method tys. let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone()); let impl_fty = impl_fty.subst(tcx, &impl_to_skol_substs); - let impl_fty = liberate_late_bound_regions( - tcx, impl_m_body_scope, &ty::bind(impl_fty)).value; let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone()); let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs); @@ -1252,7 +1195,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, fn check_region_bounds_on_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, impl_m: &ty::Method<'tcx>, - impl_m_body_scope: CodeExtent, trait_generics: &ty::Generics<'tcx>, impl_generics: &ty::Generics<'tcx>, trait_to_skol_substs: &Substs<'tcx>, @@ -1302,16 +1244,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, let impl_bounds = impl_param.bounds.subst(tcx, impl_to_skol_substs); - // The bounds may reference late-bound regions from the - // impl declaration. In that case, we want to replace - // those with the liberated variety so as to match the - // versions appearing in the `trait_to_skol_substs`. - // There are two-levels of binder to be aware of: the - // impl, and the method. - let impl_bounds = - ty::liberate_late_bound_regions( - tcx, impl_m_body_scope, &ty::bind(ty::bind(impl_bounds))).value.value; - debug!("check_region_bounds_on_impl_method: \ trait_param={} \ impl_param={} \ @@ -1390,13 +1322,7 @@ fn check_cast(fcx: &FnCtxt, let t_1 = fcx.to_ty(t); let t_1 = structurally_resolved_type(fcx, span, t_1); - if ty::type_is_scalar(t_1) { - // Supply the type as a hint so as to influence integer - // literals and other things that might care. - check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1)) - } else { - check_expr(fcx, e) - } + check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1)); let t_e = fcx.expr_ty(e); @@ -1638,7 +1564,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn default_diverging_type_variables_to_nil(&self) { for (_, &ref ty) in self.inh.node_types.borrow_mut().iter_mut() { - if self.infcx().type_var_diverges(self.infcx().resolve_type_vars_if_possible(*ty)) { + if self.infcx().type_var_diverges(self.infcx().resolve_type_vars_if_possible(ty)) { demand::eqtype(self, codemap::DUMMY_SP, *ty, ty::mk_nil(self.tcx())); } } @@ -1653,7 +1579,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn write_object_cast(&self, key: ast::NodeId, - trait_ref: Rc<ty::TraitRef<'tcx>>) { + trait_ref: Rc<ty::PolyTraitRef<'tcx>>) { debug!("write_object_cast key={} trait_ref={}", key, trait_ref.repr(self.tcx())); self.inh.object_cast_map.borrow_mut().insert(key, trait_ref); @@ -1751,7 +1677,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_unsize_obligations(span, &**u) } ty::UnsizeVtable(ref ty_trait, self_ty) => { - vtable::check_object_safety(self.tcx(), &ty_trait.principal, span); + vtable::check_object_safety(self.tcx(), ty_trait, span); + // If the type is `Foo+'a`, ensures that the type // being cast to `Foo+'a` implements `Foo`: vtable::register_object_cast_obligations(self, @@ -2048,14 +1975,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } -#[deriving(Show)] +#[deriving(Copy, Show)] pub enum LvaluePreference { PreferMutLvalue, NoPreference } -impl Copy for LvaluePreference {} - /// Executes an autoderef loop for the type `t`. At each step, invokes `should_stop` to decide /// whether to terminate the loop. Returns the final type and number of derefs that it performed. /// @@ -2486,7 +2411,7 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let method_type = match method { Some(ref method) => method.ty, None => { - let true_expr_type = fcx.infcx().resolve_type_vars_if_possible(expr_type); + let true_expr_type = fcx.infcx().resolve_type_vars_if_possible(&expr_type); if !ty::type_is_error(true_expr_type) { let ty_string = fcx.infcx().ty_to_string(true_expr_type); @@ -2572,13 +2497,13 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // HACK(eddyb) ignore self in the definition (see above). check_argument_types(fcx, sp, - fty.sig.inputs.slice_from(1), + fty.sig.0.inputs.slice_from(1), callee_expr, args_no_rcvr, autoref_args, - fty.sig.variadic, + fty.sig.0.variadic, tuple_arguments); - fty.sig.output + fty.sig.0.output } _ => { fcx.tcx().sess.span_bug(callee_expr.span, @@ -2928,14 +2853,12 @@ pub fn lookup_tup_field_ty<'tcx>(tcx: &ty::ctxt<'tcx>, // Controls whether the arguments are automatically referenced. This is useful // for overloaded binary and unary operators. -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub enum AutorefArgs { Yes, No, } -impl Copy for AutorefArgs {} - /// Controls whether the arguments are tupled. This is used for the call /// operator. /// @@ -2992,11 +2915,11 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // This is the "default" function signature, used in case of error. // In that case, we check each argument against "error" in order to // set up all the node type bindings. - let error_fn_sig = FnSig { + let error_fn_sig = ty::Binder(FnSig { inputs: err_args(args.len()), output: ty::FnConverging(ty::mk_err()), variadic: false - }; + }); let fn_sig = match *fn_sty { ty::ty_bare_fn(ty::BareFnTy {ref sig, ..}) | @@ -3976,7 +3899,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, vtable::select_new_fcx_obligations(fcx); debug!("ExprForLoop each item has type {}", - fcx.infcx().resolve_type_vars_if_possible(typ).repr(fcx.tcx())); + fcx.infcx().resolve_type_vars_if_possible(&typ).repr(fcx.tcx())); let pcx = pat_ctxt { fcx: fcx, @@ -4371,11 +4294,11 @@ impl<'tcx> Expectation<'tcx> { } ExpectCastableToType(t) => { ExpectCastableToType( - fcx.infcx().resolve_type_vars_if_possible(t)) + fcx.infcx().resolve_type_vars_if_possible(&t)) } ExpectHasType(t) => { ExpectHasType( - fcx.infcx().resolve_type_vars_if_possible(t)) + fcx.infcx().resolve_type_vars_if_possible(&t)) } } } @@ -5096,7 +5019,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fcx.infcx().replace_late_bound_regions_with_fresh_var( span, infer::FnCall, - &ty::bind((polytype.ty, bounds))).0.value; + &ty::Binder((polytype.ty, bounds))).0; debug!("after late-bounds have been replaced: ty_late_bound={}", ty_late_bound.repr(fcx.tcx())); debug!("after late-bounds have been replaced: bounds={}", bounds.repr(fcx.tcx())); @@ -5712,11 +5635,11 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { let fty = ty::mk_bare_fn(tcx, ty::BareFnTy { unsafety: ast::Unsafety::Unsafe, abi: abi::RustIntrinsic, - sig: FnSig { + sig: ty::Binder(FnSig { inputs: inputs, output: output, variadic: false, - } + }), }); let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id)); let i_n_tps = i_ty.generics.types.len(subst::FnSpace); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index bfa3c384da7..33c015a9a08 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -124,8 +124,6 @@ use middle::region::CodeExtent; use middle::traits; use middle::ty::{ReScope}; use middle::ty::{mod, Ty, MethodCall}; -use middle::infer::resolve_and_force_all_but_regions; -use middle::infer::resolve_type; use middle::infer; use middle::pat_util; use util::nodemap::{DefIdMap, NodeMap, FnvHashMap}; @@ -307,11 +305,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { /// of b will be `&<R0>.int` and then `*b` will require that `<R0>` be bigger than the let and /// the `*b` expression, so we will effectively resolve `<R0>` to be the block B. pub fn resolve_type(&self, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> { - match resolve_type(self.fcx.infcx(), None, unresolved_ty, - resolve_and_force_all_but_regions) { - Ok(t) => t, - Err(_) => ty::mk_err() - } + self.fcx.infcx().resolve_type_vars_if_possible(&unresolved_ty) } /// Try to resolve the type for the given node. @@ -1187,7 +1181,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, // Treat overloaded autoderefs as if an AutoRef adjustment // was applied on the base type, as that is always the case. let fn_sig = ty::ty_fn_sig(method.ty); - let self_ty = fn_sig.inputs[0]; + let self_ty = fn_sig.0.inputs[0]; let (m, r) = match self_ty.sty { ty::ty_rptr(r, ref m) => (m.mutbl, r), _ => rcx.tcx().sess.span_bug(deref_expr.span, @@ -1204,7 +1198,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, // Specialized version of constrain_call. type_must_outlive(rcx, infer::CallRcvr(deref_expr.span), self_ty, r_deref_expr); - match fn_sig.output { + match fn_sig.0.output { ty::FnConverging(return_type) => { type_must_outlive(rcx, infer::CallReturn(deref_expr.span), return_type, r_deref_expr); diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 415a3d53fb2..4db795a1fda 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -9,7 +9,7 @@ // except according to those terms. use check::{FnCtxt, structurally_resolved_type}; -use middle::subst::{SelfSpace, FnSpace}; +use middle::subst::{FnSpace}; use middle::traits; use middle::traits::{SelectionError, OutputTypeParameterMismatch, Overflow, Unimplemented}; use middle::traits::{Obligation, ObligationCause}; @@ -44,7 +44,7 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Ensure that if ~T is cast to ~Trait, then T : Trait push_cast_obligation(fcx, cast_expr, object_trait, referent_ty); - check_object_safety(fcx.tcx(), &object_trait.principal, source_expr.span); + check_object_safety(fcx.tcx(), object_trait, source_expr.span); } (&ty::ty_rptr(referent_region, ty::mt { ty: referent_ty, @@ -68,7 +68,7 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, target_region, referent_region); - check_object_safety(fcx.tcx(), &object_trait.principal, source_expr.span); + check_object_safety(fcx.tcx(), object_trait, source_expr.span); } } @@ -132,24 +132,19 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // self by value, has no type parameters and does not use the `Self` type, except // in self position. pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>, - object_trait: &ty::TraitRef<'tcx>, - span: Span) { - - let mut object = object_trait.clone(); - if object.substs.types.len(SelfSpace) == 0 { - object.substs.types.push(SelfSpace, ty::mk_err()); - } - - let object = Rc::new(object); - for tr in traits::supertraits(tcx, object) { + object_trait: &ty::TyTrait<'tcx>, + span: Span) +{ + let object_trait_ref = object_trait.principal_trait_ref_with_self_ty(ty::mk_err()); + for tr in traits::supertraits(tcx, object_trait_ref) { check_object_safety_inner(tcx, &*tr, span); } } fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>, - object_trait: &ty::TraitRef<'tcx>, + object_trait: &ty::PolyTraitRef<'tcx>, span: Span) { - let trait_items = ty::trait_items(tcx, object_trait.def_id); + let trait_items = ty::trait_items(tcx, object_trait.def_id()); let mut errors = Vec::new(); for item in trait_items.iter() { @@ -163,7 +158,7 @@ fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>, let mut errors = errors.iter().flat_map(|x| x.iter()).peekable(); if errors.peek().is_some() { - let trait_name = ty::item_path_str(tcx, object_trait.def_id); + let trait_name = ty::item_path_str(tcx, object_trait.def_id()); span_err!(tcx.sess, span, E0038, "cannot convert to a trait object because trait `{}` is not object-safe", trait_name); @@ -212,12 +207,12 @@ fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>, } }; let ref sig = method.fty.sig; - for &input_ty in sig.inputs[1..].iter() { + for &input_ty in sig.0.inputs[1..].iter() { if let Some(msg) = check_for_self_ty(input_ty) { msgs.push(msg); } } - if let ty::FnConverging(result_type) = sig.output { + if let ty::FnConverging(result_type) = sig.0.output { if let Some(msg) = check_for_self_ty(result_type) { msgs.push(msg); } @@ -237,7 +232,7 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, object_trait: &ty::TyTrait<'tcx>, referent_ty: Ty<'tcx>) - -> Rc<ty::TraitRef<'tcx>> + -> Rc<ty::PolyTraitRef<'tcx>> { // We can only make objects from sized types. fcx.register_builtin_bound( @@ -256,17 +251,9 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, referent_ty.repr(fcx.tcx()), object_trait_ty.repr(fcx.tcx())); - // Take the type parameters from the object type, but set - // the Self type (which is unknown, for the object type) - // to be the type we are casting from. - let mut object_substs = object_trait.principal.substs.clone(); - assert!(object_substs.self_ty().is_none()); - object_substs.types.push(SelfSpace, referent_ty); - // Create the obligation for casting from T to Trait. let object_trait_ref = - Rc::new(ty::TraitRef { def_id: object_trait.principal.def_id, - substs: object_substs }); + object_trait.principal_trait_ref_with_self_ty(referent_ty); let object_obligation = Obligation::new( ObligationCause::new(span, @@ -328,36 +315,13 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match *error { Overflow => { // We could track the stack here more precisely if we wanted, I imagine. - match obligation.trait_ref { - ty::Predicate::Trait(ref trait_ref) => { - let trait_ref = - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(&**trait_ref); - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "overflow evaluating the trait `{}` for the type `{}`", - trait_ref.user_string(fcx.tcx()), - trait_ref.self_ty().user_string(fcx.tcx())).as_slice()); - } - - ty::Predicate::Equate(a, b) => { - let a = fcx.infcx().resolve_type_vars_if_possible(a); - let b = fcx.infcx().resolve_type_vars_if_possible(b); - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "overflow checking whether the types `{}` and `{}` are equal", - a.user_string(fcx.tcx()), - b.user_string(fcx.tcx())).as_slice()); - } - - ty::Predicate::TypeOutlives(..) | - ty::Predicate::RegionOutlives(..) => { - fcx.tcx().sess.span_err( - obligation.cause.span, - format!("overflow evaluating lifetime predicate").as_slice()); - } - } + let predicate = + fcx.infcx().resolve_type_vars_if_possible(&obligation.trait_ref); + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "overflow evaluating the requirement `{}`", + predicate.user_string(fcx.tcx())).as_slice()); let current_limit = fcx.tcx().sess.recursion_limit.get(); let suggested_limit = current_limit * 2; @@ -372,9 +336,7 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Unimplemented => { match obligation.trait_ref { ty::Predicate::Trait(ref trait_ref) => { - let trait_ref = - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( - &**trait_ref); + let trait_ref = fcx.infcx().resolve_type_vars_if_possible(&**trait_ref); if !ty::type_is_error(trait_ref.self_ty()) { fcx.tcx().sess.span_err( obligation.cause.span, @@ -382,41 +344,51 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, "the trait `{}` is not implemented for the type `{}`", trait_ref.user_string(fcx.tcx()), trait_ref.self_ty().user_string(fcx.tcx())).as_slice()); - note_obligation_cause(fcx, obligation); } } - ty::Predicate::Equate(a, b) => { - let a = fcx.infcx().resolve_type_vars_if_possible(a); - let b = fcx.infcx().resolve_type_vars_if_possible(b); - let err = infer::can_mk_eqty(fcx.infcx(), a, b).unwrap_err(); + ty::Predicate::Equate(ref predicate) => { + let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate); + let err = fcx.infcx().equality_predicate(obligation.cause.span, + &predicate).unwrap_err(); fcx.tcx().sess.span_err( obligation.cause.span, format!( - "mismatched types: the types `{}` and `{}` are not equal ({})", - a.user_string(fcx.tcx()), - b.user_string(fcx.tcx()), + "the requirement `{}` is not satisfied (`{}`)", + predicate.user_string(fcx.tcx()), ty::type_err_to_str(fcx.tcx(), &err)).as_slice()); } - ty::Predicate::TypeOutlives(..) | - ty::Predicate::RegionOutlives(..) => { - // these kinds of predicates turn into - // constraints, and hence errors show up in region - // inference. - fcx.tcx().sess.span_bug( + ty::Predicate::RegionOutlives(ref predicate) => { + let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate); + let err = fcx.infcx().region_outlives_predicate(obligation.cause.span, + &predicate).unwrap_err(); + fcx.tcx().sess.span_err( obligation.cause.span, - format!("region predicate error {}", - obligation.repr(fcx.tcx())).as_slice()); + format!( + "the requirement `{}` is not satisfied (`{}`)", + predicate.user_string(fcx.tcx()), + ty::type_err_to_str(fcx.tcx(), &err)).as_slice()); + } + + ty::Predicate::TypeOutlives(ref predicate) => { + let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate); + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "the requirement `{}` is not satisfied", + predicate.user_string(fcx.tcx())).as_slice()); } } + + note_obligation_cause(fcx, obligation); } OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => { let expected_trait_ref = - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( + fcx.infcx().resolve_type_vars_if_possible( &**expected_trait_ref); let actual_trait_ref = - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( + fcx.infcx().resolve_type_vars_if_possible( &**actual_trait_ref); if !ty::type_is_error(actual_trait_ref.self_ty()) { fcx.tcx().sess.span_err( @@ -443,7 +415,7 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let trait_ref = match obligation.trait_ref { ty::Predicate::Trait(ref trait_ref) => { - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(&**trait_ref) + fcx.infcx().resolve_type_vars_if_possible(&**trait_ref) } _ => { fcx.tcx().sess.span_bug( @@ -458,7 +430,7 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, trait_ref.repr(fcx.tcx()), self_ty.repr(fcx.tcx()), obligation.repr(fcx.tcx())); - let all_types = &trait_ref.substs.types; + let all_types = &trait_ref.substs().types; if all_types.iter().any(|&t| ty::type_is_error(t)) { } else if all_types.iter().any(|&t| ty::type_needs_infer(t)) { // This is kind of a hack: it frequently happens that some earlier @@ -477,7 +449,7 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // anyway. In that case, why inundate the user. if !fcx.tcx().sess.has_errors() { if fcx.ccx.tcx.lang_items.sized_trait() - .map_or(false, |sized_id| sized_id == trait_ref.def_id) { + .map_or(false, |sized_id| sized_id == trait_ref.def_id()) { fcx.tcx().sess.span_err( obligation.cause.span, format!( diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 8c82429e1c2..c09ce3db6dd 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -166,12 +166,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // Find the impl self type as seen from the "inside" -- // that is, with all type parameters converted from bound - // to free, and any late-bound regions on the impl - // liberated. + // to free. let self_ty = ty::node_id_to_type(fcx.tcx(), item.id); let self_ty = self_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs); - let self_ty = liberate_late_bound_regions( - fcx.tcx(), item_scope, &ty::bind(self_ty)).value; bounds_checker.check_traits_in_ty(self_ty); @@ -182,7 +179,6 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { Some(t) => { t } }; let trait_ref = (*trait_ref).subst(fcx.tcx(), &fcx.inh.param_env.free_substs); - let trait_ref = liberate_late_bound_regions(fcx.tcx(), item_scope, &trait_ref); // There are special rules that apply to drop. if @@ -222,7 +218,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { traits::ItemObligation(trait_ref.def_id)); // Find the supertrait bounds. This will add `int:Bar`. - let predicates = ty::predicates_for_trait_ref(fcx.tcx(), &trait_ref); + let poly_trait_ref = ty::Binder(trait_ref); + let predicates = ty::predicates_for_trait_ref(fcx.tcx(), &poly_trait_ref); for predicate in predicates.into_iter() { fcx.register_predicate(traits::Obligation::new(cause, predicate)); } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 8d94cf5dd5e..700d1211606 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -19,8 +19,6 @@ use middle::def; use middle::pat_util; use middle::ty::{mod, Ty, MethodCall, MethodCallee}; use middle::ty_fold::{TypeFolder,TypeFoldable}; -use middle::infer::{force_all, resolve_all, resolve_region}; -use middle::infer::resolve_type; use middle::infer; use write_substs_to_tcx; use write_ty_to_tcx; @@ -337,14 +335,15 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } - fn resolve<T:ResolveIn<'tcx>>(&self, t: &T, reason: ResolveReason) -> T { - t.resolve_in(&mut Resolver::new(self.fcx, reason)) + fn resolve<T:TypeFoldable<'tcx>>(&self, t: &T, reason: ResolveReason) -> T { + t.fold_with(&mut Resolver::new(self.fcx, reason)) } } /////////////////////////////////////////////////////////////////////////// // Resolution reason. +#[deriving(Copy)] enum ResolveReason { ResolvingExpr(Span), ResolvingLocal(Span), @@ -353,8 +352,6 @@ enum ResolveReason { ResolvingUnboxedClosure(ast::DefId), } -impl Copy for ResolveReason {} - impl ResolveReason { fn span(&self, tcx: &ty::ctxt) -> Span { match *self { @@ -376,19 +373,6 @@ impl ResolveReason { } /////////////////////////////////////////////////////////////////////////// -// Convenience methods for resolving different kinds of things. - -trait ResolveIn<'tcx> { - fn resolve_in<'a>(&self, resolver: &mut Resolver<'a, 'tcx>) -> Self; -} - -impl<'tcx, T: TypeFoldable<'tcx>> ResolveIn<'tcx> for T { - fn resolve_in<'a>(&self, resolver: &mut Resolver<'a, 'tcx>) -> T { - self.fold_with(resolver) - } -} - -/////////////////////////////////////////////////////////////////////////// // The Resolver. This is the type folding engine that detects // unresolved types and so forth. @@ -465,13 +449,11 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !ty::type_needs_infer(t) { - return t; - } - - match resolve_type(self.infcx, None, t, resolve_all | force_all) { + match self.infcx.fully_resolve(&t) { Ok(t) => t, Err(e) => { + debug!("Resolver::fold_ty: input type `{}` not fully resolvable", + t.repr(self.tcx)); self.report_error(e); ty::mk_err() } @@ -479,7 +461,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { } fn fold_region(&mut self, r: ty::Region) -> ty::Region { - match resolve_region(self.infcx, r, resolve_all | force_all) { + match self.infcx.fully_resolve(&r) { Ok(r) => r, Err(e) => { self.report_error(e); diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index a55f3c61919..5d0bb6622c2 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -19,6 +19,7 @@ use metadata::csearch::{each_impl, get_impl_trait}; use metadata::csearch; use middle::subst::{mod, Subst}; +use middle::ty::RegionEscape; use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId}; use middle::ty::{ParameterEnvironment, TypeTraitItemId, lookup_item_type}; use middle::ty::{Ty, ty_bool, ty_char, ty_closure, ty_enum, ty_err}; @@ -26,12 +27,11 @@ use middle::ty::{ty_param, Polytype, ty_ptr}; use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup}; use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_open}; use middle::ty::{ty_uint, ty_unboxed_closure, ty_uniq, ty_bare_fn}; -use middle::ty::{type_is_ty_var}; use middle::ty; use CrateCtxt; use middle::infer::combine::Combine; use middle::infer::InferCtxt; -use middle::infer::{new_infer_ctxt, resolve_ivar, resolve_type}; +use middle::infer::{new_infer_ctxt}; use std::collections::{HashSet}; use std::cell::RefCell; use std::rc::Rc; @@ -52,80 +52,35 @@ mod orphan; mod overlap; mod unsafety; -fn get_base_type<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, - span: Span, - original_type: Ty<'tcx>) - -> Option<Ty<'tcx>> { - let resolved_type = match resolve_type(inference_context, - Some(span), - original_type, - resolve_ivar) { - Ok(resulting_type) if !type_is_ty_var(resulting_type) => resulting_type, - _ => { - inference_context.tcx.sess.span_fatal(span, - "the type of this value must be known in order \ - to determine the base type"); - } - }; - - match resolved_type.sty { - ty_enum(..) | ty_struct(..) | ty_unboxed_closure(..) => { - debug!("(getting base type) found base type"); - Some(resolved_type) +// Returns the def ID of the base type, if there is one. +fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, + span: Span, + ty: Ty<'tcx>) + -> Option<DefId> { + match ty.sty { + ty_enum(def_id, _) | + ty_struct(def_id, _) => { + Some(def_id) } - _ if ty::type_is_trait(resolved_type) => { - debug!("(getting base type) found base type (trait)"); - Some(resolved_type) + ty_trait(ref t) => { + Some(t.principal.def_id()) } ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) | ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) | - ty_infer(..) | ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) | + ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) | ty_ptr(_) | ty_rptr(_, _) => { - debug!("(getting base type) no base type; found {}", - original_type.sty); None } - ty_trait(..) => panic!("should have been caught") - } -} -// Returns the def ID of the base type, if there is one. -fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, - span: Span, - original_type: Ty<'tcx>) - -> Option<DefId> { - match get_base_type(inference_context, span, original_type) { - None => None, - Some(base_type) => { - match base_type.sty { - ty_enum(def_id, _) | - ty_struct(def_id, _) | - ty_unboxed_closure(def_id, _, _) => { - Some(def_id) - } - ty_ptr(ty::mt {ty, ..}) | - ty_rptr(_, ty::mt {ty, ..}) | - ty_uniq(ty) => { - match ty.sty { - ty_trait(box ty::TyTrait { ref principal, .. }) => { - Some(principal.def_id) - } - _ => { - panic!("get_base_type() returned a type that wasn't an \ - enum, struct, or trait"); - } - } - } - ty_trait(box ty::TyTrait { ref principal, .. }) => { - Some(principal.def_id) - } - _ => { - panic!("get_base_type() returned a type that wasn't an \ - enum, struct, or trait"); - } - } + ty_infer(..) | ty_unboxed_closure(..) => { + // `ty` comes from a user declaration so we should only expect types + // that the user can type + inference_context.tcx.sess.span_bug( + span, + format!("coherence encountered unexpected type searching for base type: {}", + ty.repr(inference_context.tcx))[]); } } } @@ -504,6 +459,9 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { let trait_impls = trait_impls.borrow().clone(); for &impl_did in trait_impls.iter() { + debug!("check_implementations_of_copy: impl_did={}", + impl_did.repr(tcx)); + if impl_did.krate != ast::LOCAL_CRATE { debug!("check_implementations_of_copy(): impl not in this \ crate"); @@ -511,10 +469,16 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } let self_type = self.get_self_type_for_implementation(impl_did); + debug!("check_implementations_of_copy: self_type={} (bound)", + self_type.repr(tcx)); + let span = tcx.map.span(impl_did.node); - let param_env = ParameterEnvironment::for_item(tcx, - impl_did.node); + let param_env = ParameterEnvironment::for_item(tcx, impl_did.node); let self_type = self_type.ty.subst(tcx, ¶m_env.free_substs); + assert!(!self_type.has_escaping_regions()); + + debug!("check_implementations_of_copy: self_type={} (free)", + self_type.repr(tcx)); match ty::can_type_implement_copy(tcx, self_type, ¶m_env) { Ok(()) => {} diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 1803bf766dd..bb8efd29910 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -55,7 +55,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { self.check_def_id(item.span, def_id); } ty::ty_trait(box ty::TyTrait{ ref principal, ..}) => { - self.check_def_id(item.span, principal.def_id); + self.check_def_id(item.span, principal.def_id()); } _ => { span_err!(self.tcx.sess, item.span, E0118, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 91947f67dd7..4612acb04b2 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -42,10 +42,9 @@ use middle::region; use middle::resolve_lifetime; use middle::subst; use middle::subst::{Substs}; -use middle::ty::{ImplContainer, ImplOrTraitItemContainer, TraitContainer}; -use middle::ty::{Polytype}; -use middle::ty::{mod, Ty}; -use middle::ty_fold::TypeFolder; +use middle::ty::{AsPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; +use middle::ty::{mod, RegionEscape, Ty, Polytype}; +use middle::ty_fold::{mod, TypeFolder, TypeFoldable}; use middle::infer; use rscope::*; use {CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx}; @@ -227,7 +226,7 @@ pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ast::StructVariantKind(ref struct_def) => { let pty = Polytype { - generics: ty_generics_for_type( + generics: ty_generics_for_type_or_impl( ccx, generics, DontCreateTypeParametersForAssociatedTypes), @@ -240,7 +239,7 @@ pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }; let pty = Polytype { - generics: ty_generics_for_type( + generics: ty_generics_for_type_or_impl( ccx, generics, DontCreateTypeParametersForAssociatedTypes), @@ -491,6 +490,7 @@ fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } +#[deriving(Copy)] enum ConvertMethodContext<'a> { /// Used when converting implementation methods. ImplConvertMethodContext, @@ -499,8 +499,6 @@ enum ConvertMethodContext<'a> { TraitConvertMethodContext(ast::DefId, &'a [ast::TraitItem]), } -impl<'a> Copy for ConvertMethodContext<'a> {} - fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, convert_method_context: ConvertMethodContext, container: ImplOrTraitItemContainer, @@ -652,7 +650,7 @@ fn is_associated_type_valid_for_param(ty: Ty, if let ty::ty_param(param_ty) = ty.sty { let type_parameter = generics.types.get(param_ty.space, param_ty.idx); for trait_bound in type_parameter.bounds.trait_bounds.iter() { - if trait_bound.def_id == trait_id { + if trait_bound.def_id() == trait_id { return true } } @@ -1051,7 +1049,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { ref selfty, ref impl_items) => { // Create generics from the generics specified in the impl head. - let ty_generics = ty_generics_for_impl( + let ty_generics = ty_generics_for_type_or_impl( ccx, generics, CreateTypeParametersForAssociatedTypes); @@ -1483,7 +1481,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) let pty = { let ty = ccx.to_ty(&ExplicitRscope, &**t); Polytype { - generics: ty_generics_for_type( + generics: ty_generics_for_type_or_impl( ccx, generics, DontCreateTypeParametersForAssociatedTypes), @@ -1496,7 +1494,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) } ast::ItemEnum(_, ref generics) => { // Create a new generic polytype. - let ty_generics = ty_generics_for_type( + let ty_generics = ty_generics_for_type_or_impl( ccx, generics, DontCreateTypeParametersForAssociatedTypes); @@ -1514,7 +1512,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) tcx.sess.span_bug(it.span, "invoked ty_of_item on trait"); } ast::ItemStruct(_, ref generics) => { - let ty_generics = ty_generics_for_type( + let ty_generics = ty_generics_for_type_or_impl( ccx, generics, DontCreateTypeParametersForAssociatedTypes); @@ -1581,11 +1579,11 @@ fn ty_of_trait_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn ty_generics_for_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - generics: &ast::Generics, - create_type_parameters_for_associated_types: - CreateTypeParametersForAssociatedTypesFlag) - -> ty::Generics<'tcx> { +fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + generics: &ast::Generics, + create_type_parameters_for_associated_types: + CreateTypeParametersForAssociatedTypesFlag) + -> ty::Generics<'tcx> { ty_generics(ccx, subst::TypeSpace, generics.lifetimes.as_slice(), @@ -1638,8 +1636,8 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let param_id = trait_id; let self_trait_ref = - Rc::new(ty::TraitRef { def_id: local_def(trait_id), - substs: (*substs).clone() }); + Rc::new(ty::Binder(ty::TraitRef { def_id: local_def(trait_id), + substs: (*substs).clone() })); let def = ty::TypeParameterDef { space: subst::SelfSpace, @@ -1665,24 +1663,6 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics } -fn ty_generics_for_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - generics: &ast::Generics, - create_type_parameters_for_associated_types: - CreateTypeParametersForAssociatedTypesFlag) - -> ty::Generics<'tcx> -{ - let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics); - debug!("ty_generics_for_impl: early_lifetimes={}", - early_lifetimes); - ty_generics(ccx, - subst::TypeSpace, - early_lifetimes.as_slice(), - generics.ty_params.as_slice(), - ty::Generics::empty(), - &generics.where_clause, - create_type_parameters_for_associated_types) -} - fn ty_generics_for_fn_or_method<'tcx,AC>( this: &AC, generics: &ast::Generics, @@ -1920,8 +1900,12 @@ fn ty_generics<'tcx,AC>(this: &AC, for region_param_def in result.regions.get_slice(space).iter() { let region = region_param_def.to_early_bound_region(); for &bound_region in region_param_def.bounds.iter() { - result.predicates.push(space, ty::Predicate::RegionOutlives(region, - bound_region)); + // account for new binder introduced in the predicate below; no need + // to shift `region` because it is never a late-bound region + let bound_region = ty_fold::shift_region(bound_region, 1); + result.predicates.push( + space, + ty::Binder(ty::OutlivesPredicate(region, bound_region)).as_predicate()); } } } @@ -2015,7 +1999,7 @@ fn compute_bounds<'tcx,AC>(this: &AC, ¶m_bounds, span); - param_bounds.trait_bounds.sort_by(|a,b| a.def_id.cmp(&b.def_id)); + param_bounds.trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id())); param_bounds } @@ -2031,13 +2015,13 @@ fn check_bounds_compatible<'tcx>(tcx: &ty::ctxt<'tcx>, tcx, param_bounds.trait_bounds.as_slice(), |trait_ref| { - let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id); + let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id()); if trait_def.bounds.builtin_bounds.contains(&ty::BoundSized) { span_err!(tcx.sess, span, E0129, "incompatible bounds on type parameter `{}`, \ bound `{}` does not allow unsized type", name_of_bounded_thing.user_string(tcx), - ppaux::trait_ref_to_string(tcx, &*trait_ref)); + trait_ref.user_string(tcx)); } true }); @@ -2057,14 +2041,14 @@ fn conv_param_bounds<'tcx,AC>(this: &AC, trait_bounds, region_bounds } = astconv::partition_bounds(this.tcx(), span, all_bounds.as_slice()); - let trait_bounds: Vec<Rc<ty::TraitRef>> = + let trait_bounds: Vec<Rc<ty::PolyTraitRef>> = trait_bounds.into_iter() .map(|bound| { - astconv::instantiate_trait_ref(this, - &ExplicitRscope, - &bound.trait_ref, - Some(param_ty.to_ty(this.tcx())), - AllowEqConstraints::Allow) + astconv::instantiate_poly_trait_ref(this, + &ExplicitRscope, + bound, + Some(param_ty.to_ty(this.tcx())), + AllowEqConstraints::Allow) }) .collect(); let region_bounds: Vec<ty::Region> = @@ -2155,9 +2139,9 @@ pub fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty::BareFnTy { abi: abi, unsafety: ast::Unsafety::Unsafe, - sig: ty::FnSig {inputs: input_tys, - output: output, - variadic: decl.variadic} + sig: ty::Binder(ty::FnSig {inputs: input_tys, + output: output, + variadic: decl.variadic}), }); let pty = Polytype { generics: ty_generics_for_fn_or_method, @@ -2183,8 +2167,12 @@ pub fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, subst::Substs::new(types, regions) } -/// Verifies that the explicit self type of a method matches the impl or -/// trait. +/// Verifies that the explicit self type of a method matches the impl +/// or trait. This is a bit weird but basically because right now we +/// don't handle the general case, but instead map it to one of +/// several pre-defined options using various heuristics, this method +/// comes back to check after the fact that explicit type the user +/// wrote actually matches what the pre-defined option said. fn check_method_self_type<'a, 'tcx, RS:RegionScope>( crate_context: &CrateCtxt<'a, 'tcx>, rs: &RS, @@ -2206,19 +2194,21 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( // contain late-bound regions from the method, but not the // trait (since traits only have early-bound region // parameters). - assert!(!ty::type_escapes_depth(required_type, 1)); + assert!(!base_type.has_regions_escaping_depth(1)); let required_type_free = - ty::liberate_late_bound_regions( - crate_context.tcx, body_scope, &ty::bind(required_type)).value; - - // The "base type" comes from the impl. It may have late-bound - // regions from the impl or the method. - let base_type_free = // liberate impl regions: - ty::liberate_late_bound_regions( - crate_context.tcx, body_scope, &ty::bind(ty::bind(base_type))).value.value; - let base_type_free = // liberate method regions: - ty::liberate_late_bound_regions( - crate_context.tcx, body_scope, &ty::bind(base_type_free)).value; + liberate_early_bound_regions( + crate_context.tcx, body_scope, + &ty::liberate_late_bound_regions( + crate_context.tcx, body_scope, &ty::Binder(required_type))); + + // The "base type" comes from the impl. It too may have late-bound + // regions from the method. + assert!(!base_type.has_regions_escaping_depth(1)); + let base_type_free = + liberate_early_bound_regions( + crate_context.tcx, body_scope, + &ty::liberate_late_bound_regions( + crate_context.tcx, body_scope, &ty::Binder(base_type))); debug!("required_type={} required_type_free={} \ base_type={} base_type_free={}", @@ -2239,4 +2229,30 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( })); infcx.resolve_regions_and_report_errors(body_id); } + + fn liberate_early_bound_regions<'tcx,T>( + tcx: &ty::ctxt<'tcx>, + scope: region::CodeExtent, + value: &T) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> + { + /*! + * Convert early-bound regions into free regions; normally this is done by + * applying the `free_substs` from the `ParameterEnvironment`, but this particular + * method-self-type check is kind of hacky and done very early in the process, + * before we really have a `ParameterEnvironment` to check. + */ + + ty_fold::fold_regions(tcx, value, |region, _| { + match region { + ty::ReEarlyBound(id, _, _, name) => { + let def_id = local_def(id); + ty::ReFree(ty::FreeRegion { scope: scope, + bound_region: ty::BrNamed(def_id, name) }) + } + _ => region + } + }) + } } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index d55d642f746..5fc2466674e 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -228,11 +228,11 @@ fn check_main_fn_ty(ccx: &CrateCtxt, let se_ty = ty::mk_bare_fn(tcx, ty::BareFnTy { unsafety: ast::Unsafety::Normal, abi: abi::Rust, - sig: ty::FnSig { + sig: ty::Binder(ty::FnSig { inputs: Vec::new(), output: ty::FnConverging(ty::mk_nil(tcx)), variadic: false - } + }) }); require_same_types(tcx, None, false, main_span, main_t, se_ty, @@ -276,14 +276,14 @@ fn check_start_fn_ty(ccx: &CrateCtxt, let se_ty = ty::mk_bare_fn(tcx, ty::BareFnTy { unsafety: ast::Unsafety::Normal, abi: abi::Rust, - sig: ty::FnSig { + sig: ty::Binder(ty::FnSig { inputs: vec!( ty::mk_int(), ty::mk_imm_ptr(tcx, ty::mk_imm_ptr(tcx, ty::mk_u8())) ), output: ty::FnConverging(ty::mk_int()), variadic: false - } + }), }); require_same_types(tcx, None, false, start_span, start_t, se_ty, diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index 39c7a87837c..f43e8579022 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -36,10 +36,9 @@ pub trait RegionScope { // A scope in which all regions must be explicitly named. This is used // for types that appear in structs and so on. +#[deriving(Copy)] pub struct ExplicitRscope; -impl Copy for ExplicitRscope {} - impl RegionScope for ExplicitRscope { fn default_region_bound(&self, _span: Span) -> Option<ty::Region> { None diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index 8fe14bae0f5..ef0d1bc3859 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -229,19 +229,16 @@ pub fn infer_variance(tcx: &ty::ctxt) { type VarianceTermPtr<'a> = &'a VarianceTerm<'a>; -#[deriving(Show)] +#[deriving(Copy, Show)] struct InferredIndex(uint); -impl Copy for InferredIndex {} - +#[deriving(Copy)] enum VarianceTerm<'a> { ConstantTerm(ty::Variance), TransformTerm(VarianceTermPtr<'a>, VarianceTermPtr<'a>), InferredTerm(InferredIndex), } -impl<'a> Copy for VarianceTerm<'a> {} - impl<'a> fmt::Show for VarianceTerm<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -268,14 +265,12 @@ struct TermsContext<'a, 'tcx: 'a> { inferred_infos: Vec<InferredInfo<'a>> , } -#[deriving(Show, PartialEq)] +#[deriving(Copy, Show, PartialEq)] enum ParamKind { TypeParam, RegionParam } -impl Copy for ParamKind {} - struct InferredInfo<'a> { item_id: ast::NodeId, kind: ParamKind, @@ -427,13 +422,12 @@ struct ConstraintContext<'a, 'tcx: 'a> { /// Declares that the variable `decl_id` appears in a location with /// variance `variance`. +#[deriving(Copy)] struct Constraint<'a> { inferred: InferredIndex, variance: &'a VarianceTerm<'a>, } -impl<'a> Copy for Constraint<'a> {} - fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>, krate: &ast::Crate) -> ConstraintContext<'a, 'tcx> { @@ -777,13 +771,13 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => { - let trait_def = ty::lookup_trait_def(self.tcx(), principal.def_id); + let trait_def = ty::lookup_trait_def(self.tcx(), principal.def_id()); let generics = &trait_def.generics; // Traits DO have a Self type parameter, but it is // erased from object types. assert!(!generics.types.is_empty_in(subst::SelfSpace) && - principal.substs.types.is_empty_in(subst::SelfSpace)); + principal.substs().types.is_empty_in(subst::SelfSpace)); // Traits never declare region parameters in the self // space. @@ -799,10 +793,10 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_region(bounds.region_bound, contra); self.add_constraints_from_substs( - principal.def_id, + principal.def_id(), generics.types.get_slice(subst::TypeSpace), generics.regions.get_slice(subst::TypeSpace), - &principal.substs, + principal.substs(), variance); } @@ -878,13 +872,13 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { /// Adds constraints appropriate for a function with signature /// `sig` appearing in a context with ambient variance `variance` fn add_constraints_from_sig(&mut self, - sig: &ty::FnSig<'tcx>, + sig: &ty::PolyFnSig<'tcx>, variance: VarianceTermPtr<'a>) { let contra = self.contravariant(variance); - for &input in sig.inputs.iter() { + for &input in sig.0.inputs.iter() { self.add_constraints_from_ty(input, contra); } - if let ty::FnConverging(result_type) = sig.output { + if let ty::FnConverging(result_type) = sig.0.output { self.add_constraints_from_ty(result_type, variance); } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d640f055388..ed923202795 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -575,6 +575,12 @@ impl Clean<TyParamBound> for ty::BuiltinBound { } } +impl<'tcx> Clean<TyParamBound> for ty::PolyTraitRef<'tcx> { + fn clean(&self, cx: &DocContext) -> TyParamBound { + self.0.clean(cx) + } +} + impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> { fn clean(&self, cx: &DocContext) -> TyParamBound { let tcx = match cx.tcx_opt() { @@ -913,7 +919,7 @@ impl<'tcx> Clean<Type> for ty::FnOutput<'tcx> { } } -impl<'a, 'tcx> Clean<FnDecl> for (ast::DefId, &'a ty::FnSig<'tcx>) { +impl<'a, 'tcx> Clean<FnDecl> for (ast::DefId, &'a ty::PolyFnSig<'tcx>) { fn clean(&self, cx: &DocContext) -> FnDecl { let (did, sig) = *self; let mut names = if did.node != 0 { @@ -925,10 +931,10 @@ impl<'a, 'tcx> Clean<FnDecl> for (ast::DefId, &'a ty::FnSig<'tcx>) { let _ = names.next(); } FnDecl { - output: Return(sig.output.clean(cx)), + output: Return(sig.0.output.clean(cx)), attrs: Vec::new(), inputs: Arguments { - values: sig.inputs.iter().map(|t| { + values: sig.0.inputs.iter().map(|t| { Argument { type_: t.clean(cx), id: 0, @@ -1082,14 +1088,14 @@ impl<'tcx> Clean<Item> for ty::Method<'tcx> { ty::StaticExplicitSelfCategory => (ast::SelfStatic.clean(cx), self.fty.sig.clone()), s => { - let sig = ty::FnSig { - inputs: self.fty.sig.inputs[1..].to_vec(), - ..self.fty.sig.clone() - }; + let sig = ty::Binder(ty::FnSig { + inputs: self.fty.sig.0.inputs[1..].to_vec(), + ..self.fty.sig.0.clone() + }); let s = match s { ty::ByValueExplicitSelfCategory => SelfValue, ty::ByReferenceExplicitSelfCategory(..) => { - match self.fty.sig.inputs[0].sty { + match self.fty.sig.0.inputs[0].sty { ty::ty_rptr(r, mt) => { SelfBorrowed(r.clean(cx), mt.mutbl.clean(cx)) } @@ -1097,7 +1103,7 @@ impl<'tcx> Clean<Item> for ty::Method<'tcx> { } } ty::ByBoxExplicitSelfCategory => { - SelfExplicit(self.fty.sig.inputs[0].clean(cx)) + SelfExplicit(self.fty.sig.0.inputs[0].clean(cx)) } ty::StaticExplicitSelfCategory => unreachable!(), }; @@ -1182,7 +1188,7 @@ pub enum Type { PolyTraitRef(Vec<TyParamBound>), } -#[deriving(Clone, Encodable, Decodable, PartialEq, Eq, Hash)] +#[deriving(Clone, Copy, Encodable, Decodable, PartialEq, Eq, Hash)] pub enum PrimitiveType { Int, I8, I16, I32, I64, Uint, U8, U16, U32, U64, @@ -1194,9 +1200,7 @@ pub enum PrimitiveType { PrimitiveTuple, } -impl Copy for PrimitiveType {} - -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Copy, Encodable, Decodable)] pub enum TypeKind { TypeEnum, TypeFunction, @@ -1209,8 +1213,6 @@ pub enum TypeKind { TypeTypedef, } -impl Copy for TypeKind {} - impl PrimitiveType { fn from_str(s: &str) -> Option<PrimitiveType> { match s.as_slice() { @@ -1391,8 +1393,10 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> { } ty::ty_struct(did, ref substs) | ty::ty_enum(did, ref substs) | - ty::ty_trait(box ty::TyTrait { principal: ty::TraitRef { def_id: did, ref substs }, - .. }) => { + ty::ty_trait(box ty::TyTrait { + principal: ty::Binder(ty::TraitRef { def_id: did, ref substs }), + .. }) => + { let fqn = csearch::get_item_path(cx.tcx(), did); let fqn: Vec<String> = fqn.into_iter().map(|i| { i.to_string() @@ -1865,14 +1869,12 @@ impl Clean<Item> for doctree::Constant { } } -#[deriving(Show, Clone, Encodable, Decodable, PartialEq)] +#[deriving(Copy, Show, Clone, Encodable, Decodable, PartialEq)] pub enum Mutability { Mutable, Immutable, } -impl Copy for Mutability {} - impl Clean<Mutability> for ast::Mutability { fn clean(&self, _: &DocContext) -> Mutability { match self { diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 6592ca498dc..83552884d7f 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -70,7 +70,7 @@ impl Module { } } -#[deriving(Show, Clone, Encodable, Decodable)] +#[deriving(Copy, Show, Clone, Encodable, Decodable)] pub enum StructType { /// A normal struct Plain, @@ -82,8 +82,6 @@ pub enum StructType { Unit } -impl Copy for StructType {} - pub enum TypeBound { RegionBound, TraitBound(ast::TraitRef) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 1e243906b23..5572bcb6aa8 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -29,15 +29,19 @@ use html::render::{cache, CURRENT_LOCATION_KEY}; /// Helper to render an optional visibility with a space after it (if the /// visibility is preset) +#[deriving(Copy)] pub struct VisSpace(pub Option<ast::Visibility>); /// Similarly to VisSpace, this structure is used to render a function style with a /// space after it. +#[deriving(Copy)] pub struct UnsafetySpace(pub ast::Unsafety); /// Wrapper struct for properly emitting a method declaration. pub struct Method<'a>(pub &'a clean::SelfTy, pub &'a clean::FnDecl); /// Similar to VisSpace, but used for mutability +#[deriving(Copy)] pub struct MutableSpace(pub clean::Mutability); /// Similar to VisSpace, but used for mutability +#[deriving(Copy)] pub struct RawMutableSpace(pub clean::Mutability); /// Wrapper struct for properly emitting the stability level. pub struct Stability<'a>(pub &'a Option<clean::Stability>); @@ -48,11 +52,6 @@ pub struct WhereClause<'a>(pub &'a clean::Generics); /// Wrapper struct for emitting type parameter bounds. pub struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]); -impl Copy for VisSpace {} -impl Copy for UnsafetySpace {} -impl Copy for MutableSpace {} -impl Copy for RawMutableSpace {} - impl VisSpace { pub fn get(&self) -> Option<ast::Visibility> { let VisSpace(v) = *self; v diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index 580b7fbe1a3..7c346539f6a 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -19,7 +19,7 @@ use clean; /// discriminants. JavaScript then is used to decode them into the original value. /// Consequently, every change to this type should be synchronized to /// the `itemTypes` mapping table in `static/main.js`. -#[deriving(PartialEq, Clone)] +#[deriving(Copy, PartialEq, Clone)] pub enum ItemType { Module = 0, Struct = 1, @@ -41,8 +41,6 @@ pub enum ItemType { Constant = 18, } -impl Copy for ItemType {} - impl ItemType { pub fn from_item(item: &clean::Item) -> ItemType { match item.inner { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 3e6cffa1304..8831b5e7d96 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -225,13 +225,12 @@ struct Source<'a>(&'a str); // Helper structs for rendering items/sidebars and carrying along contextual // information +#[deriving(Copy)] struct Item<'a> { cx: &'a Context, item: &'a clean::Item, } -impl<'a> Copy for Item<'a> {} - struct Sidebar<'a> { cx: &'a Context, item: &'a clean::Item, } /// Struct representing one entry in the JS search index. These are all emitted diff --git a/src/librustdoc/stability_summary.rs b/src/librustdoc/stability_summary.rs index 4fbd249660f..2f3079f75b9 100644 --- a/src/librustdoc/stability_summary.rs +++ b/src/librustdoc/stability_summary.rs @@ -27,6 +27,7 @@ use html::render::cache; #[deriving(Zero, Encodable, Decodable, PartialEq, Eq)] /// The counts for each stability level. +#[deriving(Copy)] pub struct Counts { pub deprecated: uint, pub experimental: uint, @@ -39,8 +40,6 @@ pub struct Counts { pub unmarked: uint, } -impl Copy for Counts {} - impl Add<Counts, Counts> for Counts { fn add(self, other: Counts) -> Counts { Counts { diff --git a/src/libserialize/base64.rs b/src/libserialize/base64.rs index 8ded963b928..f1dffa55bb0 100644 --- a/src/libserialize/base64.rs +++ b/src/libserialize/base64.rs @@ -19,6 +19,7 @@ use std::fmt; use std::error; /// Available encoding character sets +#[deriving(Copy)] pub enum CharacterSet { /// The standard character set (uses `+` and `/`) Standard, @@ -26,9 +27,8 @@ pub enum CharacterSet { UrlSafe } -impl Copy for CharacterSet {} - /// Available newline types +#[deriving(Copy)] pub enum Newline { /// A linefeed (i.e. Unix-style newline) LF, @@ -36,9 +36,8 @@ pub enum Newline { CRLF } -impl Copy for Newline {} - /// Contains configuration parameters for `to_base64`. +#[deriving(Copy)] pub struct Config { /// Character set to use pub char_set: CharacterSet, @@ -50,8 +49,6 @@ pub struct Config { pub line_length: Option<uint> } -impl Copy for Config {} - /// Configuration for RFC 4648 standard base64 encoding pub static STANDARD: Config = Config {char_set: Standard, newline: Newline::CRLF, pad: true, line_length: None}; @@ -180,6 +177,7 @@ pub trait FromBase64 for Sized? { } /// Errors that can occur when decoding a base64 encoded string +#[deriving(Copy)] pub enum FromBase64Error { /// The input contained a character not part of the base64 format InvalidBase64Byte(u8, uint), @@ -187,8 +185,6 @@ pub enum FromBase64Error { InvalidBase64Length, } -impl Copy for FromBase64Error {} - impl fmt::Show for FromBase64Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { diff --git a/src/libserialize/hex.rs b/src/libserialize/hex.rs index 22392056ddf..977a31c240b 100644 --- a/src/libserialize/hex.rs +++ b/src/libserialize/hex.rs @@ -61,6 +61,7 @@ pub trait FromHex for Sized? { } /// Errors that can occur when decoding a hex encoded string +#[deriving(Copy)] pub enum FromHexError { /// The input contained a character not part of the hex format InvalidHexCharacter(char, uint), @@ -68,8 +69,6 @@ pub enum FromHexError { InvalidHexLength, } -impl Copy for FromHexError {} - impl fmt::Show for FromHexError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 6d143329b0c..d3d1aa1d788 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -226,7 +226,7 @@ pub type Array = Vec<Json>; pub type Object = BTreeMap<string::String, Json>; /// The errors that can arise while parsing a JSON stream. -#[deriving(Clone, PartialEq)] +#[deriving(Clone, Copy, PartialEq)] pub enum ErrorCode { InvalidSyntax, InvalidNumber, @@ -247,17 +247,13 @@ pub enum ErrorCode { NotUtf8, } -impl Copy for ErrorCode {} - -#[deriving(Clone, PartialEq, Show)] +#[deriving(Clone, Copy, PartialEq, Show)] pub enum ParserError { /// msg, line, col SyntaxError(ErrorCode, uint, uint), IoError(io::IoErrorKind, &'static str), } -impl Copy for ParserError {} - // Builder and Parser have the same errors. pub type BuilderError = ParserError; diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index c436de0d193..2c4dc5313bb 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -18,7 +18,6 @@ use core::kinds::Sized; use fmt; use iter::IteratorExt; -use kinds::Copy; use mem; use ops::FnMut; use option::Option; @@ -29,11 +28,9 @@ use string::{String, IntoString}; use vec::Vec; /// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero. -#[deriving(Clone, PartialEq, PartialOrd, Ord, Eq, Hash)] +#[deriving(Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)] pub struct Ascii { chr: u8 } -impl Copy for Ascii {} - impl Ascii { /// Converts an ascii character into a `u8`. #[inline] diff --git a/src/libstd/comm/mod.rs b/src/libstd/comm/mod.rs index 8f945fec4d5..9043cb8c7d6 100644 --- a/src/libstd/comm/mod.rs +++ b/src/libstd/comm/mod.rs @@ -391,7 +391,7 @@ pub struct SyncSender<T> { /// This enumeration is the list of the possible reasons that try_recv could not /// return data when called. -#[deriving(PartialEq, Clone, Show)] +#[deriving(PartialEq, Clone, Copy, Show)] #[experimental = "this is likely to be removed in changing try_recv()"] pub enum TryRecvError { /// This channel is currently empty, but the sender(s) have not yet @@ -402,8 +402,6 @@ pub enum TryRecvError { Disconnected, } -impl Copy for TryRecvError {} - /// This enumeration is the list of the possible error outcomes for the /// `SyncSender::try_send` method. #[deriving(PartialEq, Clone, Show)] diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs index 758dab1a107..291f384d619 100644 --- a/src/libstd/dynamic_lib.rs +++ b/src/libstd/dynamic_lib.rs @@ -215,7 +215,6 @@ pub mod dl { use c_str::{CString, ToCStr}; use libc; - use kinds::Copy; use ops::FnOnce; use ptr; use result::*; @@ -265,6 +264,7 @@ pub mod dl { dlclose(handle as *mut libc::c_void); () } + #[deriving(Copy)] pub enum Rtld { Lazy = 1, Now = 2, @@ -272,8 +272,6 @@ pub mod dl { Local = 0, } - impl Copy for Rtld {} - #[link_name = "dl"] extern { fn dlopen(filename: *const libc::c_char, diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 5807a3bc466..dbf61b132e0 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -232,7 +232,6 @@ use error::{FromError, Error}; use fmt; use int; use iter::{Iterator, IteratorExt}; -use kinds::Copy; use mem::transmute; use ops::{BitOr, BitXor, BitAnd, Sub, Not, FnOnce}; use option::Option; @@ -367,7 +366,7 @@ impl FromError<IoError> for Box<Error> { } /// A list specifying general categories of I/O error. -#[deriving(PartialEq, Eq, Clone, Show)] +#[deriving(Copy, PartialEq, Eq, Clone, Show)] pub enum IoErrorKind { /// Any I/O error not part of this list. OtherIoError, @@ -422,8 +421,6 @@ pub enum IoErrorKind { NoProgress, } -impl Copy for IoErrorKind {} - /// A trait that lets you add a `detail` to an IoError easily trait UpdateIoError<T> { /// Returns an IoError with updated description and detail @@ -1561,6 +1558,7 @@ impl<T: Buffer> BufferPrelude for T { /// When seeking, the resulting cursor is offset from a base by the offset given /// to the `seek` function. The base used is specified by this enumeration. +#[deriving(Copy)] pub enum SeekStyle { /// Seek from the beginning of the stream SeekSet, @@ -1570,8 +1568,6 @@ pub enum SeekStyle { SeekCur, } -impl Copy for SeekStyle {} - /// An object implementing `Seek` internally has some form of cursor which can /// be moved within a stream of bytes. The stream typically has a fixed size, /// allowing seeking relative to either end. @@ -1685,6 +1681,7 @@ pub fn standard_error(kind: IoErrorKind) -> IoError { /// A mode specifies how a file should be opened or created. These modes are /// passed to `File::open_mode` and are used to control where the file is /// positioned when it is initially opened. +#[deriving(Copy)] pub enum FileMode { /// Opens a file positioned at the beginning. Open, @@ -1694,10 +1691,9 @@ pub enum FileMode { Truncate, } -impl Copy for FileMode {} - /// Access permissions with which the file should be opened. `File`s /// opened with `Read` will return an error if written to. +#[deriving(Copy)] pub enum FileAccess { /// Read-only access, requests to write will result in an error Read, @@ -1707,10 +1703,8 @@ pub enum FileAccess { ReadWrite, } -impl Copy for FileAccess {} - /// Different kinds of files which can be identified by a call to stat -#[deriving(PartialEq, Show, Hash, Clone)] +#[deriving(Copy, PartialEq, Show, Hash, Clone)] pub enum FileType { /// This is a normal file, corresponding to `S_IFREG` RegularFile, @@ -1731,8 +1725,6 @@ pub enum FileType { Unknown, } -impl Copy for FileType {} - /// A structure used to describe metadata information about a file. This /// structure is created through the `stat` method on a `Path`. /// @@ -1750,7 +1742,7 @@ impl Copy for FileType {} /// println!("byte size: {}", info.size); /// # } /// ``` -#[deriving(Hash)] +#[deriving(Copy, Hash)] pub struct FileStat { /// The size of the file, in bytes pub size: u64, @@ -1784,14 +1776,12 @@ pub struct FileStat { pub unstable: UnstableFileStat, } -impl Copy for FileStat {} - /// This structure represents all of the possible information which can be /// returned from a `stat` syscall which is not contained in the `FileStat` /// structure. This information is not necessarily platform independent, and may /// have different meanings or no meaning at all on some platforms. #[unstable] -#[deriving(Hash)] +#[deriving(Copy, Hash)] pub struct UnstableFileStat { /// The ID of the device containing the file. pub device: u64, @@ -1815,8 +1805,6 @@ pub struct UnstableFileStat { pub gen: u64, } -impl Copy for UnstableFileStat {} - bitflags! { #[doc = "A set of permissions for a file or directory is represented"] #[doc = "by a set of flags which are or'd together."] diff --git a/src/libstd/io/net/addrinfo.rs b/src/libstd/io/net/addrinfo.rs index fc81ab7b57a..69ba64d856e 100644 --- a/src/libstd/io/net/addrinfo.rs +++ b/src/libstd/io/net/addrinfo.rs @@ -22,23 +22,22 @@ pub use self::Protocol::*; use iter::IteratorExt; use io::{IoResult}; use io::net::ip::{SocketAddr, IpAddr}; -use kinds::Copy; use option::Option; use option::Option::{Some, None}; use sys; use vec::Vec; /// Hints to the types of sockets that are desired when looking up hosts +#[deriving(Copy)] pub enum SocketType { Stream, Datagram, Raw } -impl Copy for SocketType {} - /// Flags which can be or'd into the `flags` field of a `Hint`. These are used /// to manipulate how a query is performed. /// /// The meaning of each of these flags can be found with `man -s 3 getaddrinfo` +#[deriving(Copy)] pub enum Flag { AddrConfig, All, @@ -49,21 +48,19 @@ pub enum Flag { V4Mapped, } -impl Copy for Flag {} - /// A transport protocol associated with either a hint or a return value of /// `lookup` +#[deriving(Copy)] pub enum Protocol { TCP, UDP } -impl Copy for Protocol {} - /// This structure is used to provide hints when fetching addresses for a /// remote host to control how the lookup is performed. /// /// For details on these fields, see their corresponding definitions via /// `man -s 3 getaddrinfo` +#[deriving(Copy)] pub struct Hint { pub family: uint, pub socktype: Option<SocketType>, @@ -71,8 +68,7 @@ pub struct Hint { pub flags: uint, } -impl Copy for Hint {} - +#[deriving(Copy)] pub struct Info { pub address: SocketAddr, pub family: uint, @@ -81,8 +77,6 @@ pub struct Info { pub flags: uint, } -impl Copy for Info {} - /// Easy name resolution. Given a hostname, returns the list of IP addresses for /// that hostname. pub fn get_host_addresses(host: &str) -> IoResult<Vec<IpAddr>> { diff --git a/src/libstd/io/net/ip.rs b/src/libstd/io/net/ip.rs index 5a3f5bd4668..71776b6c46a 100644 --- a/src/libstd/io/net/ip.rs +++ b/src/libstd/io/net/ip.rs @@ -18,7 +18,6 @@ pub use self::IpAddr::*; use fmt; -use kinds::Copy; use io::{mod, IoResult, IoError}; use io::net; use iter::{Iterator, IteratorExt}; @@ -32,14 +31,12 @@ use vec::Vec; pub type Port = u16; -#[deriving(PartialEq, Eq, Clone, Hash)] +#[deriving(Copy, PartialEq, Eq, Clone, Hash)] pub enum IpAddr { Ipv4Addr(u8, u8, u8, u8), Ipv6Addr(u16, u16, u16, u16, u16, u16, u16, u16) } -impl Copy for IpAddr {} - impl fmt::Show for IpAddr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -65,14 +62,12 @@ impl fmt::Show for IpAddr { } } -#[deriving(PartialEq, Eq, Clone, Hash)] +#[deriving(Copy, PartialEq, Eq, Clone, Hash)] pub struct SocketAddr { pub ip: IpAddr, pub port: Port, } -impl Copy for SocketAddr {} - impl fmt::Show for SocketAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.ip { diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index 60360a2bc64..9da1117f227 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -461,7 +461,7 @@ pub struct ProcessOutput { } /// Describes what to do with a standard io stream for a child process. -#[deriving(Clone)] +#[deriving(Clone, Copy)] pub enum StdioContainer { /// This stream will be ignored. This is the equivalent of attaching the /// stream to `/dev/null` @@ -481,11 +481,9 @@ pub enum StdioContainer { CreatePipe(bool /* readable */, bool /* writable */), } -impl Copy for StdioContainer {} - /// Describes the result of a process after it has terminated. /// Note that Windows have no signals, so the result is usually ExitStatus. -#[deriving(PartialEq, Eq, Clone)] +#[deriving(PartialEq, Eq, Clone, Copy)] pub enum ProcessExit { /// Normal termination with an exit status. ExitStatus(int), @@ -494,8 +492,6 @@ pub enum ProcessExit { ExitSignal(int), } -impl Copy for ProcessExit {} - impl fmt::Show for ProcessExit { /// Format a ProcessExit enum, to nicely present the information. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index faa52226a03..18fabcbd1a2 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -81,20 +81,18 @@ impl<R: Buffer> Buffer for LimitReader<R> { } /// A `Writer` which ignores bytes written to it, like /dev/null. +#[deriving(Copy)] pub struct NullWriter; -impl Copy for NullWriter {} - impl Writer for NullWriter { #[inline] fn write(&mut self, _buf: &[u8]) -> io::IoResult<()> { Ok(()) } } /// A `Reader` which returns an infinite stream of 0 bytes, like /dev/zero. +#[deriving(Copy)] pub struct ZeroReader; -impl Copy for ZeroReader {} - impl Reader for ZeroReader { #[inline] fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> { @@ -113,10 +111,9 @@ impl Buffer for ZeroReader { } /// A `Reader` which is always at EOF, like /dev/null. +#[deriving(Copy)] pub struct NullReader; -impl Copy for NullReader {} - impl Reader for NullReader { #[inline] fn read(&mut self, _buf: &mut [u8]) -> io::IoResult<uint> { diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index 2b319640d1b..016c4bd532a 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -17,7 +17,6 @@ pub use self::SignificantDigits::*; pub use self::SignFormat::*; use char::{mod, Char}; -use kinds::Copy; use num::{mod, Int, Float, FPNaN, FPInfinite, ToPrimitive}; use ops::FnMut; use slice::{SliceExt, CloneSliceExt}; @@ -26,6 +25,7 @@ use string::String; use vec::Vec; /// A flag that specifies whether to use exponential (scientific) notation. +#[deriving(Copy)] pub enum ExponentFormat { /// Do not use exponential notation. ExpNone, @@ -38,10 +38,9 @@ pub enum ExponentFormat { ExpBin, } -impl Copy for ExponentFormat {} - /// The number of digits used for emitting the fractional part of a number, if /// any. +#[deriving(Copy)] pub enum SignificantDigits { /// All calculable digits will be printed. /// @@ -57,9 +56,8 @@ pub enum SignificantDigits { DigExact(uint) } -impl Copy for SignificantDigits {} - /// How to emit the sign of a number. +#[deriving(Copy)] pub enum SignFormat { /// No sign will be printed. The exponent sign will also be emitted. SignNone, @@ -71,8 +69,6 @@ pub enum SignFormat { SignAll, } -impl Copy for SignFormat {} - /// Converts an integral number to its string representation as a byte vector. /// This is meant to be a common base implementation for all integral string /// conversion functions like `to_string()` or `to_str_radix()`. diff --git a/src/libstd/os.rs b/src/libstd/os.rs index a049ea01b6d..dcc73f7844a 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -361,6 +361,7 @@ pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static st } /// A low-level OS in-memory pipe. +#[deriving(Copy)] pub struct Pipe { /// A file descriptor representing the reading end of the pipe. Data written /// on the `out` file descriptor can be read from this file descriptor. @@ -370,8 +371,6 @@ pub struct Pipe { pub writer: c_int, } -impl Copy for Pipe {} - /// Creates a new low-level OS in-memory pipe. /// /// This function can fail to succeed if there are no more resources available @@ -861,6 +860,7 @@ pub enum MapOption { impl Copy for MapOption {} /// Possible errors when creating a map. +#[deriving(Copy)] pub enum MapError { /// # The following are POSIX-specific /// @@ -905,8 +905,6 @@ pub enum MapError { ErrMapViewOfFile(uint) } -impl Copy for MapError {} - impl fmt::Show for MapError { fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result { let str = match *self { diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index 5cbefb0d3d8..b498b3e8ad0 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -22,7 +22,6 @@ use hash; use io::Writer; use iter::{AdditiveIterator, DoubleEndedIteratorExt, Extend}; use iter::{Iterator, IteratorExt, Map}; -use kinds::Copy; use mem; use option::Option; use option::Option::{Some, None}; @@ -970,7 +969,7 @@ pub fn is_sep_byte_verbatim(u: &u8) -> bool { } /// Prefix types for Path -#[deriving(PartialEq, Clone, Show)] +#[deriving(Copy, PartialEq, Clone, Show)] pub enum PathPrefix { /// Prefix `\\?\`, uint is the length of the following component VerbatimPrefix(uint), @@ -986,8 +985,6 @@ pub enum PathPrefix { DiskPrefix } -impl Copy for PathPrefix {} - fn parse_prefix<'a>(mut path: &'a str) -> Option<PathPrefix> { if path.starts_with("\\\\") { // \\ diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index d8e1fc25654..0035e5747aa 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -225,7 +225,6 @@ use cell::RefCell; use clone::Clone; use io::IoResult; use iter::{Iterator, IteratorExt}; -use kinds::Copy; use mem; use rc::Rc; use result::Result::{Ok, Err}; @@ -246,12 +245,11 @@ pub mod reader; /// The standard RNG. This is designed to be efficient on the current /// platform. +#[deriving(Copy)] pub struct StdRng { rng: IsaacWordRng, } -impl Copy for StdRng {} - impl StdRng { /// Create a randomly seeded instance of `StdRng`. /// diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index 5d5440b887d..f572141642c 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -384,7 +384,6 @@ pub mod eabi { pub use self::EXCEPTION_DISPOSITION::*; use rt::libunwind as uw; use libc::{c_void, c_int}; - use kinds::Copy; #[repr(C)] #[allow(missing_copy_implementations)] @@ -397,6 +396,7 @@ pub mod eabi { pub struct DISPATCHER_CONTEXT; #[repr(C)] + #[deriving(Copy)] pub enum EXCEPTION_DISPOSITION { ExceptionContinueExecution, ExceptionContinueSearch, @@ -404,8 +404,6 @@ pub mod eabi { ExceptionCollidedUnwind } - impl Copy for EXCEPTION_DISPOSITION {} - type _Unwind_Personality_Fn = extern "C" fn( version: c_int, diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 85ed27853c4..7cb14e8e4bc 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -13,7 +13,6 @@ #![experimental] use {fmt, i64}; -use kinds::Copy; use ops::{Add, Sub, Mul, Div, Neg, FnOnce}; use option::Option; use option::Option::{Some, None}; @@ -47,7 +46,7 @@ macro_rules! try_opt { /// ISO 8601 time duration with nanosecond precision. /// This also allows for the negative duration; see individual methods for details. -#[deriving(Clone, PartialEq, Eq, PartialOrd, Ord)] +#[deriving(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Duration { secs: i64, nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC @@ -65,8 +64,6 @@ pub const MAX: Duration = Duration { nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI }; -impl Copy for Duration {} - impl Duration { /// Makes a new `Duration` with given number of weeks. /// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60), with overflow checks. diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index 71d29bca401..70bad90aea1 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -15,7 +15,7 @@ pub use self::AbiArchitecture::*; use std::fmt; -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub enum Os { OsWindows, OsMacos, @@ -26,9 +26,7 @@ pub enum Os { OsDragonfly, } -impl Copy for Os {} - -#[deriving(PartialEq, Eq, Hash, Encodable, Decodable, Clone)] +#[deriving(Copy, PartialEq, Eq, Hash, Encodable, Decodable, Clone)] pub enum Abi { // NB: This ordering MUST match the AbiDatas array below. // (This is ensured by the test indices_are_correct().) @@ -48,10 +46,8 @@ pub enum Abi { RustCall, } -impl Copy for Abi {} - #[allow(non_camel_case_types)] -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub enum Architecture { X86, X86_64, @@ -60,8 +56,7 @@ pub enum Architecture { Mipsel } -impl Copy for Architecture {} - +#[deriving(Copy)] pub struct AbiData { abi: Abi, @@ -69,8 +64,7 @@ pub struct AbiData { name: &'static str, } -impl Copy for AbiData {} - +#[deriving(Copy)] pub enum AbiArchitecture { /// Not a real ABI (e.g., intrinsic) RustArch, @@ -81,9 +75,6 @@ pub enum AbiArchitecture { } #[allow(non_upper_case_globals)] -impl Copy for AbiArchitecture {} - -#[allow(non_upper_case_globals)] static AbiDatas: &'static [AbiData] = &[ // Platform-specific ABIs AbiData {abi: Cdecl, name: "cdecl" }, diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index d4860766d47..be8f32bc4d5 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -80,14 +80,12 @@ use serialize::{Encodable, Decodable, Encoder, Decoder}; /// table) and a SyntaxContext to track renaming and /// macro expansion per Flatt et al., "Macros /// That Work Together" -#[deriving(Clone, Hash, PartialOrd, Eq, Ord)] +#[deriving(Clone, Copy, Hash, PartialOrd, Eq, Ord)] pub struct Ident { pub name: Name, pub ctxt: SyntaxContext } -impl Copy for Ident {} - impl Ident { /// Construct an identifier with the given name and an empty context: pub fn new(name: Name) -> Ident { Ident {name: name, ctxt: EMPTY_CTXT}} @@ -160,11 +158,9 @@ pub const ILLEGAL_CTXT : SyntaxContext = 1; /// A name is a part of an identifier, representing a string or gensym. It's /// the result of interning. -#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Encodable, Decodable, Clone)] +#[deriving(Copy, Eq, Ord, PartialEq, PartialOrd, Hash, Encodable, Decodable, Clone)] pub struct Name(pub u32); -impl Copy for Name {} - impl Name { pub fn as_str<'a>(&'a self) -> &'a str { unsafe { @@ -201,15 +197,13 @@ impl<D:Decoder<E>, E> Decodable<D, E> for Ident { /// Function name (not all functions have names) pub type FnIdent = Option<Ident>; -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct Lifetime { pub id: NodeId, pub span: Span, pub name: Name } -impl Copy for Lifetime {} - #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct LifetimeDef { pub lifetime: Lifetime, @@ -353,14 +347,12 @@ pub type CrateNum = u32; pub type NodeId = u32; -#[deriving(Clone, Eq, Ord, PartialOrd, PartialEq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, Eq, Ord, PartialOrd, PartialEq, Encodable, Decodable, Hash, Show)] pub struct DefId { pub krate: CrateNum, pub node: NodeId, } -impl Copy for DefId {} - /// Item definitions in the currently-compiled crate would have the CrateNum /// LOCAL_CRATE in their DefId. pub const LOCAL_CRATE: CrateNum = 0; @@ -513,15 +505,13 @@ pub struct FieldPat { pub is_shorthand: bool, } -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum BindingMode { BindByRef(Mutability), BindByValue(Mutability), } -impl Copy for BindingMode {} - -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum PatWildKind { /// Represents the wildcard pattern `_` PatWildSingle, @@ -530,8 +520,6 @@ pub enum PatWildKind { PatWildMulti, } -impl Copy for PatWildKind {} - #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum Pat_ { /// Represents a wildcard pattern (either `_` or `..`) @@ -561,15 +549,13 @@ pub enum Pat_ { PatMac(Mac), } -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum Mutability { MutMutable, MutImmutable, } -impl Copy for Mutability {} - -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum BinOp { BiAdd, BiSub, @@ -591,9 +577,7 @@ pub enum BinOp { BiGt, } -impl Copy for BinOp {} - -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum UnOp { UnUniq, UnDeref, @@ -601,8 +585,6 @@ pub enum UnOp { UnNeg } -impl Copy for UnOp {} - pub type Stmt = Spanned<Stmt_>; #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] @@ -634,14 +616,12 @@ pub enum MacStmtStyle { /// Where a local declaration came from: either a true `let ... = /// ...;`, or one desugared from the pattern of a for loop. -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum LocalSource { LocalLet, LocalFor, } -impl Copy for LocalSource {} - // FIXME (pending discussion of #1697, #2178...): local should really be // a refinement on pat. /// Local represents a `let` statement, e.g., `let <pat>:<ty> = <expr>;` @@ -683,22 +663,18 @@ pub struct Field { pub type SpannedIdent = Spanned<Ident>; -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum BlockCheckMode { DefaultBlock, UnsafeBlock(UnsafeSource), } -impl Copy for BlockCheckMode {} - -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum UnsafeSource { CompilerGenerated, UserProvided, } -impl Copy for UnsafeSource {} - #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct Expr { pub id: NodeId, @@ -775,23 +751,19 @@ pub struct QPath { pub item_name: Ident, } -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum MatchSource { MatchNormal, MatchIfLetDesugar, MatchWhileLetDesugar, } -impl Copy for MatchSource {} - -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum CaptureClause { CaptureByValue, CaptureByRef, } -impl Copy for CaptureClause {} - /// A delimited sequence of token trees #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct Delimited { @@ -842,14 +814,12 @@ pub struct SequenceRepetition { /// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star) /// for token sequences. -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum KleeneOp { ZeroOrMore, OneOrMore, } -impl Copy for KleeneOp {} - /// When the main rust parser encounters a syntax-extension invocation, it /// parses the arguments to the invocation as a token-tree. This is a very /// loose structure, such that all sorts of different AST-fragments can @@ -959,24 +929,20 @@ pub enum Mac_ { MacInvocTT(Path, Vec<TokenTree> , SyntaxContext), // new macro-invocation } -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum StrStyle { CookedStr, RawStr(uint) } -impl Copy for StrStyle {} - pub type Lit = Spanned<Lit_>; -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum Sign { Minus, Plus } -impl Copy for Sign {} - impl<T> Sign where T: Int { pub fn new(n: T) -> Sign { if n < Int::zero() { @@ -987,15 +953,13 @@ impl<T> Sign where T: Int { } } -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum LitIntType { SignedIntLit(IntTy, Sign), UnsignedIntLit(UintTy), UnsuffixedIntLit(Sign) } -impl Copy for LitIntType {} - impl LitIntType { pub fn suffix_len(&self) -> uint { match *self { @@ -1082,7 +1046,7 @@ pub struct Typedef { pub typ: P<Ty>, } -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash)] pub enum IntTy { TyI, TyI8, @@ -1091,8 +1055,6 @@ pub enum IntTy { TyI64, } -impl Copy for IntTy {} - impl fmt::Show for IntTy { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", ast_util::int_ty_to_string(*self, None)) @@ -1109,7 +1071,7 @@ impl IntTy { } } -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash)] pub enum UintTy { TyU, TyU8, @@ -1118,8 +1080,6 @@ pub enum UintTy { TyU64, } -impl Copy for UintTy {} - impl UintTy { pub fn suffix_len(&self) -> uint { match *self { @@ -1136,14 +1096,12 @@ impl fmt::Show for UintTy { } } -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash)] pub enum FloatTy { TyF32, TyF64, } -impl Copy for FloatTy {} - impl fmt::Show for FloatTy { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", ast_util::float_ty_to_string(*self)) @@ -1177,7 +1135,7 @@ pub struct Ty { } /// Not represented directly in the AST, referred to by name through a ty_path. -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum PrimTy { TyInt(IntTy), TyUint(UintTy), @@ -1187,16 +1145,12 @@ pub enum PrimTy { TyChar } -impl Copy for PrimTy {} - -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash)] pub enum Onceness { Once, Many } -impl Copy for Onceness {} - impl fmt::Show for Onceness { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -1259,14 +1213,12 @@ pub enum Ty_ { TyInfer, } -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum AsmDialect { AsmAtt, AsmIntel } -impl Copy for AsmDialect {} - #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct InlineAsm { pub asm: InternedString, @@ -1433,14 +1385,12 @@ pub struct Variant_ { pub type Variant = Spanned<Variant_>; -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum PathListItem_ { PathListIdent { name: Ident, id: NodeId }, PathListMod { id: NodeId } } -impl Copy for PathListItem_ {} - impl PathListItem_ { pub fn id(&self) -> NodeId { match *self { @@ -1494,19 +1444,15 @@ pub type Attribute = Spanned<Attribute_>; /// Distinguishes between Attributes that decorate items and Attributes that /// are contained as statements within items. These two cases need to be /// distinguished for pretty-printing. -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum AttrStyle { AttrOuter, AttrInner, } -impl Copy for AttrStyle {} - -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct AttrId(pub uint); -impl Copy for AttrId {} - /// Doc-comments are promoted to attributes that have is_sugared_doc = true #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct Attribute_ { @@ -1536,14 +1482,12 @@ pub struct PolyTraitRef { pub trait_ref: TraitRef } -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum Visibility { Public, Inherited, } -impl Copy for Visibility {} - impl Visibility { pub fn inherit_from(&self, parent_visibility: Visibility) -> Visibility { match self { @@ -1572,15 +1516,13 @@ impl StructField_ { pub type StructField = Spanned<StructField_>; -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum StructFieldKind { NamedField(Ident, Visibility), /// Element of a tuple-like struct UnnamedField(Visibility), } -impl Copy for StructFieldKind {} - impl StructFieldKind { pub fn is_unnamed(&self) -> bool { match *self { @@ -1682,15 +1624,13 @@ impl ForeignItem_ { } } -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum UnboxedClosureKind { FnUnboxedClosureKind, FnMutUnboxedClosureKind, FnOnceUnboxedClosureKind, } -impl Copy for UnboxedClosureKind {} - /// The data we save and restore about an inlined item or method. This is not /// part of the AST that we parse from a file, but it becomes part of the tree /// that we trans. diff --git a/src/libsyntax/ast_map/blocks.rs b/src/libsyntax/ast_map/blocks.rs index 6decfd1c3ad..7c89245f53e 100644 --- a/src/libsyntax/ast_map/blocks.rs +++ b/src/libsyntax/ast_map/blocks.rs @@ -41,10 +41,9 @@ use visit; /// - The default implementation for a trait method. /// /// To construct one, use the `Code::from_node` function. +#[deriving(Copy)] pub struct FnLikeNode<'a> { node: ast_map::Node<'a> } -impl<'a> Copy for FnLikeNode<'a> {} - /// MaybeFnLike wraps a method that indicates if an object /// corresponds to some FnLikeNode. pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; } @@ -82,13 +81,12 @@ impl MaybeFnLike for ast::Expr { /// Carries either an FnLikeNode or a Block, as these are the two /// constructs that correspond to "code" (as in, something from which /// we can construct a control-flow graph). +#[deriving(Copy)] pub enum Code<'a> { FnLikeCode(FnLikeNode<'a>), BlockCode(&'a Block), } -impl<'a> Copy for Code<'a> {} - impl<'a> Code<'a> { pub fn id(&self) -> ast::NodeId { match *self { diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index 6089f39e828..a95c9e19906 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -32,14 +32,12 @@ use std::slice; pub mod blocks; -#[deriving(Clone, PartialEq)] +#[deriving(Clone, Copy, PartialEq)] pub enum PathElem { PathMod(Name), PathName(Name) } -impl Copy for PathElem {} - impl PathElem { pub fn name(&self) -> Name { match *self { @@ -102,7 +100,7 @@ pub fn path_to_string<PI: Iterator<PathElem>>(path: PI) -> String { }).to_string() } -#[deriving(Show)] +#[deriving(Copy, Show)] pub enum Node<'ast> { NodeItem(&'ast Item), NodeForeignItem(&'ast ForeignItem), @@ -122,11 +120,9 @@ pub enum Node<'ast> { NodeLifetime(&'ast Lifetime), } -impl<'ast> Copy for Node<'ast> {} - /// Represents an entry and its parent Node ID /// The odd layout is to bring down the total size. -#[deriving(Show)] +#[deriving(Copy, Show)] enum MapEntry<'ast> { /// Placeholder for holes in the map. NotPresent, @@ -151,8 +147,6 @@ enum MapEntry<'ast> { RootInlinedParent(&'ast InlinedParent) } -impl<'ast> Copy for MapEntry<'ast> {} - impl<'ast> Clone for MapEntry<'ast> { fn clone(&self) -> MapEntry<'ast> { *self diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 5243f07f327..02771809ae6 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -343,14 +343,12 @@ pub fn empty_generics() -> Generics { // ______________________________________________________________________ // Enumerating the IDs which appear in an AST -#[deriving(Encodable, Decodable, Show)] +#[deriving(Copy, Encodable, Decodable, Show)] pub struct IdRange { pub min: NodeId, pub max: NodeId, } -impl Copy for IdRange {} - impl IdRange { pub fn max() -> IdRange { IdRange { diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 598da6a5df0..127cc5ed51d 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -277,7 +277,7 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option<InternedString> { first_attr_value_str_by_name(attrs, "crate_name") } -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub enum InlineAttr { InlineNone, InlineHint, @@ -285,8 +285,6 @@ pub enum InlineAttr { InlineNever, } -impl Copy for InlineAttr {} - /// Determine what `#[inline]` attribute is present in `attrs`, if any. pub fn find_inline_attr(attrs: &[Attribute]) -> InlineAttr { // FIXME (#2809)---validate the usage of #[inline] and #[inline] @@ -349,7 +347,7 @@ pub struct Stability { } /// The available stability levels. -#[deriving(Encodable,Decodable,PartialEq,PartialOrd,Clone,Show)] +#[deriving(Copy,Encodable,Decodable,PartialEq,PartialOrd,Clone,Show)] pub enum StabilityLevel { Deprecated, Experimental, @@ -359,8 +357,6 @@ pub enum StabilityLevel { Locked } -impl Copy for StabilityLevel {} - pub fn find_stability_generic<'a, AM: AttrMetaMethods, I: Iterator<&'a AM>> @@ -468,7 +464,7 @@ fn int_type_of_word(s: &str) -> Option<IntType> { } } -#[deriving(PartialEq, Show, Encodable, Decodable)] +#[deriving(Copy, PartialEq, Show, Encodable, Decodable)] pub enum ReprAttr { ReprAny, ReprInt(Span, IntType), @@ -476,8 +472,6 @@ pub enum ReprAttr { ReprPacked, } -impl Copy for ReprAttr {} - impl ReprAttr { pub fn is_ffi_safe(&self) -> bool { match *self { @@ -489,14 +483,12 @@ impl ReprAttr { } } -#[deriving(Eq, Hash, PartialEq, Show, Encodable, Decodable)] +#[deriving(Copy, Eq, Hash, PartialEq, Show, Encodable, Decodable)] pub enum IntType { SignedInt(ast::IntTy), UnsignedInt(ast::UintTy) } -impl Copy for IntType {} - impl IntType { #[inline] pub fn is_signed(self) -> bool { diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 17cafc2441f..b7c0678cf13 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -31,19 +31,15 @@ pub trait Pos { /// A byte offset. Keep this small (currently 32-bits), as AST contains /// a lot of them. -#[deriving(Clone, PartialEq, Eq, Hash, PartialOrd, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Show)] pub struct BytePos(pub u32); -impl Copy for BytePos {} - /// A character offset. Because of multibyte utf8 characters, a byte offset /// is not equivalent to a character offset. The CodeMap will convert BytePos /// values to CharPos values as necessary. -#[deriving(PartialEq, Hash, PartialOrd, Show)] +#[deriving(Copy, PartialEq, Hash, PartialOrd, Show)] pub struct CharPos(pub uint); -impl Copy for CharPos {} - // FIXME: Lots of boilerplate in these impls, but so far my attempts to fix // have been unsuccessful @@ -121,7 +117,7 @@ impl Sub<CharPos, CharPos> for CharPos { /// are *absolute* positions from the beginning of the codemap, not positions /// relative to FileMaps. Methods on the CodeMap can be used to relate spans back /// to the original source. -#[deriving(Clone, Show, Hash)] +#[deriving(Clone, Copy, Show, Hash)] pub struct Span { pub lo: BytePos, pub hi: BytePos, @@ -130,18 +126,14 @@ pub struct Span { pub expn_id: ExpnId } -impl Copy for Span {} - pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), expn_id: NO_EXPANSION }; -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct Spanned<T> { pub node: T, pub span: Span, } -impl<T:Copy> Copy for Spanned<T> {} - impl PartialEq for Span { fn eq(&self, other: &Span) -> bool { return (*self).lo == (*other).lo && (*self).hi == (*other).hi; @@ -219,7 +211,7 @@ pub struct FileMapAndLine { pub fm: Rc<FileMap>, pub line: uint } pub struct FileMapAndBytePos { pub fm: Rc<FileMap>, pub pos: BytePos } /// The syntax with which a macro was invoked. -#[deriving(Clone, Hash, Show)] +#[deriving(Clone, Copy, Hash, Show)] pub enum MacroFormat { /// e.g. #[deriving(...)] <item> MacroAttribute, @@ -227,8 +219,6 @@ pub enum MacroFormat { MacroBang } -impl Copy for MacroFormat {} - #[deriving(Clone, Hash, Show)] pub struct NameAndSpan { /// The name of the macro that was invoked to create the thing @@ -264,11 +254,9 @@ pub struct ExpnInfo { pub callee: NameAndSpan } -#[deriving(PartialEq, Eq, Clone, Show, Hash, Encodable, Decodable)] +#[deriving(Copy, PartialEq, Eq, Clone, Show, Hash, Encodable, Decodable)] pub struct ExpnId(u32); -impl Copy for ExpnId {} - pub const NO_EXPANSION: ExpnId = ExpnId(-1); impl ExpnId { @@ -290,6 +278,7 @@ pub struct FileLines { } /// Identifies an offset of a multi-byte character in a FileMap +#[deriving(Copy)] pub struct MultiByteChar { /// The absolute offset of the character in the CodeMap pub pos: BytePos, @@ -297,8 +286,6 @@ pub struct MultiByteChar { pub bytes: uint, } -impl Copy for MultiByteChar {} - /// A single source in the CodeMap pub struct FileMap { /// The name of the file that the source came from, source that doesn't diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 3a816987922..4d765f49aca 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -28,7 +28,7 @@ use term; /// maximum number of lines we will print for each error; arbitrary. static MAX_LINES: uint = 6u; -#[deriving(Clone)] +#[deriving(Clone, Copy)] pub enum RenderSpan { /// A FullSpan renders with both with an initial line for the /// message, prefixed by file:linenum, followed by a summary of @@ -40,8 +40,6 @@ pub enum RenderSpan { FileLine(Span), } -impl Copy for RenderSpan {} - impl RenderSpan { fn span(self) -> Span { match self { @@ -56,15 +54,13 @@ impl RenderSpan { } } -#[deriving(Clone)] +#[deriving(Clone, Copy)] pub enum ColorConfig { Auto, Always, Never } -impl Copy for ColorConfig {} - pub trait Emitter { fn emit(&mut self, cmsp: Option<(&codemap::CodeMap, Span)>, msg: &str, code: Option<&str>, lvl: Level); @@ -75,16 +71,14 @@ pub trait Emitter { /// This structure is used to signify that a task has panicked with a fatal error /// from the diagnostics. You can use this with the `Any` trait to figure out /// how a rustc task died (if so desired). +#[deriving(Copy)] pub struct FatalError; -impl Copy for FatalError {} - /// Signifies that the compiler died with an explicit call to `.bug` /// or `.span_bug` rather than a failed assertion, etc. +#[deriving(Copy)] pub struct ExplicitBug; -impl Copy for ExplicitBug {} - /// A span-handler is like a handler but also /// accepts span information for source-location /// reporting. @@ -228,7 +222,7 @@ pub fn mk_handler(e: Box<Emitter + Send>) -> Handler { } } -#[deriving(PartialEq, Clone)] +#[deriving(Copy, PartialEq, Clone)] pub enum Level { Bug, Fatal, @@ -238,8 +232,6 @@ pub enum Level { Help, } -impl Copy for Level {} - impl fmt::Show for Level { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use std::fmt::Show; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 354b53bfc01..3947a602809 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -223,13 +223,12 @@ impl MacResult for MacItems { /// Fill-in macro expansion result, to allow compilation to continue /// after hitting errors. +#[deriving(Copy)] pub struct DummyResult { expr_only: bool, span: Span } -impl Copy for DummyResult {} - impl DummyResult { /// Create a default MacResult that can be anything. /// diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs index bd1962de56e..10e14e0c975 100644 --- a/src/libsyntax/ext/deriving/cmp/ord.rs +++ b/src/libsyntax/ext/deriving/cmp/ord.rs @@ -83,12 +83,11 @@ pub fn expand_deriving_ord<F>(cx: &mut ExtCtxt, trait_def.expand(cx, mitem, item, push) } +#[deriving(Copy)] pub enum OrderingOp { PartialCmpOp, LtOp, LeOp, GtOp, GeOp, } -impl Copy for OrderingOp {} - pub fn some_ordering_collapsed(cx: &mut ExtCtxt, span: Span, op: OrderingOp, diff --git a/src/libsyntax/ext/mtwt.rs b/src/libsyntax/ext/mtwt.rs index 33936e6213f..ae979020bc7 100644 --- a/src/libsyntax/ext/mtwt.rs +++ b/src/libsyntax/ext/mtwt.rs @@ -39,7 +39,7 @@ pub struct SCTable { rename_memo: RefCell<HashMap<(SyntaxContext,Ident,Name),SyntaxContext>>, } -#[deriving(PartialEq, Encodable, Decodable, Hash, Show)] +#[deriving(Copy, PartialEq, Encodable, Decodable, Hash, Show)] pub enum SyntaxContext_ { EmptyCtxt, Mark (Mrk,SyntaxContext), @@ -56,8 +56,6 @@ pub enum SyntaxContext_ { IllegalCtxt } -impl Copy for SyntaxContext_ {} - /// A list of ident->name renamings pub type RenameList = Vec<(Ident, Name)>; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9656629e14d..0e0a87c74f8 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -97,6 +97,7 @@ enum Status { } /// A set of features to be used by later passes. +#[deriving(Copy)] pub struct Features { pub default_type_params: bool, pub unboxed_closures: bool, @@ -107,8 +108,6 @@ pub struct Features { pub opt_out_copy: bool, } -impl Copy for Features {} - impl Features { pub fn new() -> Features { Features { diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs index a17d66476c0..95bae63f58f 100644 --- a/src/libsyntax/parse/lexer/comments.rs +++ b/src/libsyntax/parse/lexer/comments.rs @@ -24,7 +24,7 @@ use std::str; use std::string::String; use std::uint; -#[deriving(Clone, PartialEq)] +#[deriving(Clone, Copy, PartialEq)] pub enum CommentStyle { /// No code on either side of each line of the comment Isolated, @@ -36,8 +36,6 @@ pub enum CommentStyle { BlankLine, } -impl Copy for CommentStyle {} - #[deriving(Clone)] pub struct Comment { pub style: CommentStyle, diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index 3a7cc77515d..a6ddcbf9ac4 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -22,7 +22,7 @@ use parse::token; use ptr::P; /// The specific types of unsupported syntax -#[deriving(PartialEq, Eq, Hash)] +#[deriving(Copy, PartialEq, Eq, Hash)] pub enum ObsoleteSyntax { ObsoleteOwnedType, ObsoleteOwnedExpr, @@ -36,8 +36,6 @@ pub enum ObsoleteSyntax { ObsoleteProcExpr, } -impl Copy for ObsoleteSyntax {} - pub trait ParserObsoleteMethods { /// Reports an obsolete syntax non-fatal error. fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c234c172fd8..3ad224b93ce 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -104,7 +104,7 @@ type ItemInfo = (Ident, Item_, Option<Vec<Attribute> >); /// How to parse a path. There are four different kinds of paths, all of which /// are parsed somewhat differently. -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub enum PathParsingMode { /// A path with no type parameters; e.g. `foo::bar::Baz` NoTypesAllowed, @@ -116,8 +116,6 @@ pub enum PathParsingMode { LifetimeAndTypesWithColons, } -impl Copy for PathParsingMode {} - enum ItemOrViewItem { /// Indicates a failure to parse any kind of item. The attributes are /// returned. diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 641239f1f8b..dad369792d7 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -28,7 +28,7 @@ use std::path::BytesContainer; use std::rc::Rc; #[allow(non_camel_case_types)] -#[deriving(Clone, Encodable, Decodable, PartialEq, Eq, Hash, Show)] +#[deriving(Clone, Copy, Encodable, Decodable, PartialEq, Eq, Hash, Show)] pub enum BinOpToken { Plus, Minus, @@ -42,10 +42,8 @@ pub enum BinOpToken { Shr, } -impl Copy for BinOpToken {} - /// A delimeter token -#[deriving(Clone, Encodable, Decodable, PartialEq, Eq, Hash, Show)] +#[deriving(Clone, Copy, Encodable, Decodable, PartialEq, Eq, Hash, Show)] pub enum DelimToken { /// A round parenthesis: `(` or `)` Paren, @@ -55,16 +53,14 @@ pub enum DelimToken { Brace, } -impl Copy for DelimToken {} - -#[deriving(Clone, Encodable, Decodable, PartialEq, Eq, Hash, Show)] +#[deriving(Clone, Copy, Encodable, Decodable, PartialEq, Eq, Hash, Show)] pub enum IdentStyle { /// `::` follows the identifier with no whitespace in-between. ModName, Plain, } -#[deriving(Clone, Encodable, Decodable, PartialEq, Eq, Hash, Show)] +#[deriving(Clone, Copy, Encodable, Decodable, PartialEq, Eq, Hash, Show)] pub enum Lit { Byte(ast::Name), Char(ast::Name), @@ -89,10 +85,6 @@ impl Lit { } } -impl Copy for Lit {} - -impl Copy for IdentStyle {} - #[allow(non_camel_case_types)] #[deriving(Clone, Encodable, Decodable, PartialEq, Eq, Hash, Show)] pub enum Token { @@ -438,13 +430,12 @@ macro_rules! declare_special_idents_and_keywords {( pub use self::Keyword::*; use ast; + #[deriving(Copy)] pub enum Keyword { $( $sk_variant, )* $( $rk_variant, )* } - impl Copy for Keyword {} - impl Keyword { pub fn to_name(&self) -> ast::Name { match *self { diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index c4e040a0f7c..bfa47a46e74 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -66,30 +66,24 @@ pub use self::Token::*; use std::io; use std::string; -#[deriving(Clone, PartialEq)] +#[deriving(Clone, Copy, PartialEq)] pub enum Breaks { Consistent, Inconsistent, } -impl Copy for Breaks {} - -#[deriving(Clone)] +#[deriving(Clone, Copy)] pub struct BreakToken { offset: int, blank_space: int } -impl Copy for BreakToken {} - -#[deriving(Clone)] +#[deriving(Clone, Copy)] pub struct BeginToken { offset: int, breaks: Breaks } -impl Copy for BeginToken {} - #[deriving(Clone)] pub enum Token { String(string::String, int), @@ -153,20 +147,18 @@ pub fn buf_str(toks: Vec<Token>, return s.into_string(); } +#[deriving(Copy)] pub enum PrintStackBreak { Fits, Broken(Breaks), } -impl Copy for PrintStackBreak {} - +#[deriving(Copy)] pub struct PrintStackElem { offset: int, pbreak: PrintStackBreak } -impl Copy for PrintStackElem {} - static SIZE_INFINITY: int = 0xffff; pub fn mk_printer(out: Box<io::Writer+'static>, linewidth: uint) -> Printer { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 1dd61a5ce19..d2cc0cba317 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -45,19 +45,17 @@ pub trait PpAnn { fn post(&self, _state: &mut State, _node: AnnNode) -> IoResult<()> { Ok(()) } } +#[deriving(Copy)] pub struct NoAnn; -impl Copy for NoAnn {} - impl PpAnn for NoAnn {} +#[deriving(Copy)] pub struct CurrentCommentAndLiteral { cur_cmnt: uint, cur_lit: uint, } -impl Copy for CurrentCommentAndLiteral {} - pub struct State<'a> { pub s: pp::Printer, cm: Option<&'a CodeMap>, diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 95d7906b443..b89e9a59349 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -32,6 +32,7 @@ use codemap::Span; use ptr::P; use owned_slice::OwnedSlice; +#[deriving(Copy)] pub enum FnKind<'a> { /// fn foo() or extern "Abi" fn foo() FkItemFn(Ident, &'a Generics, Unsafety, Abi), @@ -44,8 +45,6 @@ pub enum FnKind<'a> { FkFnBlock, } -impl<'a> Copy for FnKind<'a> {} - /// Each method of the Visitor trait is a hook to be potentially /// overridden. Each method's default implementation recursively visits /// the substructure of the input via the corresponding `walk` method; @@ -105,8 +104,11 @@ pub trait Visitor<'v> { None => () } } + fn visit_lifetime_bound(&mut self, lifetime: &'v Lifetime) { + walk_lifetime_bound(self, lifetime) + } fn visit_lifetime_ref(&mut self, lifetime: &'v Lifetime) { - self.visit_name(lifetime.span, lifetime.name) + walk_lifetime_ref(self, lifetime) } fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) { walk_lifetime_def(self, lifetime) @@ -214,10 +216,20 @@ pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v LifetimeDef) { visitor.visit_name(lifetime_def.lifetime.span, lifetime_def.lifetime.name); for bound in lifetime_def.bounds.iter() { - visitor.visit_lifetime_ref(bound); + visitor.visit_lifetime_bound(bound); } } +pub fn walk_lifetime_bound<'v, V: Visitor<'v>>(visitor: &mut V, + lifetime_ref: &'v Lifetime) { + visitor.visit_lifetime_ref(lifetime_ref) +} + +pub fn walk_lifetime_ref<'v, V: Visitor<'v>>(visitor: &mut V, + lifetime_ref: &'v Lifetime) { + visitor.visit_name(lifetime_ref.span, lifetime_ref.name) +} + pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V, explicit_self: &'v ExplicitSelf) { match explicit_self.node { @@ -550,7 +562,7 @@ pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, visitor.visit_poly_trait_ref(typ); } RegionTyParamBound(ref lifetime) => { - visitor.visit_lifetime_ref(lifetime); + visitor.visit_lifetime_bound(lifetime); } } } diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index e8824b1ad2c..a4ebcfe8a56 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -165,13 +165,13 @@ pub mod color { /// Terminal attributes pub mod attr { pub use self::Attr::*; - use std::kinds::Copy; /// Terminal attributes for use with term.attr(). /// /// Most attributes can only be turned on and must be turned off with term.reset(). /// The ones that can be turned off explicitly take a boolean value. /// Color is also represented as an attribute for convenience. + #[deriving(Copy)] pub enum Attr { /// Bold (or possibly bright) mode Bold, @@ -194,8 +194,6 @@ pub mod attr { /// Convenience attribute to set the background color BackgroundColor(super::color::Color) } - - impl Copy for Attr {} } /// A terminal with similar capabilities to an ANSI Terminal diff --git a/src/libterm/terminfo/parm.rs b/src/libterm/terminfo/parm.rs index c81bff6a1ae..4ecbc54c590 100644 --- a/src/libterm/terminfo/parm.rs +++ b/src/libterm/terminfo/parm.rs @@ -16,7 +16,7 @@ use self::FormatState::*; use self::FormatOp::*; use std::mem::replace; -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] enum States { Nothing, Percent, @@ -33,17 +33,13 @@ enum States { SeekIfEndPercent(int) } -impl Copy for States {} - -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] enum FormatState { FormatStateFlags, FormatStateWidth, FormatStatePrecision } -impl Copy for FormatState {} - /// Types of parameters a capability can use #[allow(missing_docs)] #[deriving(Clone)] @@ -446,7 +442,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) Ok(output) } -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] struct Flags { width: uint, precision: uint, @@ -456,8 +452,6 @@ struct Flags { space: bool } -impl Copy for Flags {} - impl Flags { fn new() -> Flags { Flags{ width: 0, precision: 0, alternate: false, @@ -465,6 +459,7 @@ impl Flags { } } +#[deriving(Copy)] enum FormatOp { FormatDigit, FormatOctal, @@ -473,8 +468,6 @@ enum FormatOp { FormatString } -impl Copy for FormatOp {} - impl FormatOp { fn from_char(c: char) -> FormatOp { match c { diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 56af8785a76..5b04a1fed89 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -110,15 +110,13 @@ impl Show for TestName { } } -#[deriving(Clone)] +#[deriving(Clone, Copy)] enum NamePadding { PadNone, PadOnLeft, PadOnRight, } -impl Copy for NamePadding {} - impl TestDesc { fn padded_name(&self, column_count: uint, align: NamePadding) -> String { let mut name = String::from_str(self.name.as_slice()); @@ -215,14 +213,12 @@ pub struct TestDescAndFn { pub testfn: TestFn, } -#[deriving(Clone, Encodable, Decodable, PartialEq, Show)] +#[deriving(Clone, Copy, Encodable, Decodable, PartialEq, Show)] pub struct Metric { value: f64, noise: f64 } -impl Copy for Metric {} - impl Metric { pub fn new(value: f64, noise: f64) -> Metric { Metric {value: value, noise: noise} @@ -240,7 +236,7 @@ impl Clone for MetricMap { } /// Analysis of a single change in metric -#[deriving(PartialEq, Show)] +#[deriving(Copy, PartialEq, Show)] pub enum MetricChange { LikelyNoise, MetricAdded, @@ -249,8 +245,6 @@ pub enum MetricChange { Regression(f64) } -impl Copy for MetricChange {} - pub type MetricDiff = BTreeMap<String,MetricChange>; // The default console test runner. It accepts the command line @@ -287,14 +281,13 @@ pub fn test_main_static(args: &[String], tests: &[TestDescAndFn]) { test_main(args, owned_tests) } +#[deriving(Copy)] pub enum ColorConfig { AutoColor, AlwaysColor, NeverColor, } -impl Copy for ColorConfig {} - pub struct TestOpts { pub filter: Option<Regex>, pub run_ignored: bool, diff --git a/src/libtime/lib.rs b/src/libtime/lib.rs index 4129086e9ec..1b7f5cdc4af 100644 --- a/src/libtime/lib.rs +++ b/src/libtime/lib.rs @@ -76,14 +76,12 @@ mod imp { } /// A record specifying a time value in seconds and nanoseconds. -#[deriving(Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable, Show)] pub struct Timespec { pub sec: i64, pub nsec: i32, } -impl Copy for Timespec {} - /* * Timespec assumes that pre-epoch Timespecs have negative sec and positive * nsec fields. Darwin's and Linux's struct timespec functions handle pre- @@ -268,7 +266,7 @@ pub fn tzset() { /// also called a broken-down time value. // FIXME: use c_int instead of i32? #[repr(C)] -#[deriving(Clone, PartialEq, Eq, Show)] +#[deriving(Clone, Copy, PartialEq, Eq, Show)] pub struct Tm { /// Seconds after the minute - [0, 60] pub tm_sec: i32, @@ -309,8 +307,6 @@ pub struct Tm { pub tm_nsec: i32, } -impl Copy for Tm {} - pub fn empty_tm() -> Tm { Tm { tm_sec: 0_i32, @@ -452,7 +448,7 @@ impl Tm { } } -#[deriving(PartialEq)] +#[deriving(Copy, PartialEq)] pub enum ParseError { InvalidSecond, InvalidMinute, @@ -470,8 +466,6 @@ pub enum ParseError { UnexpectedCharacter(char, char), } -impl Copy for ParseError {} - impl Show for ParseError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { diff --git a/src/test/compile-fail/bad-match.rs b/src/test/compile-fail/bad-match.rs index 39c3ed3e2a3..728b577df1d 100644 --- a/src/test/compile-fail/bad-match.rs +++ b/src/test/compile-fail/bad-match.rs @@ -14,3 +14,6 @@ fn main() { let int x = 5; match x; } + +fn main() { +} diff --git a/src/test/compile-fail/hrtb-conflate-regions.rs b/src/test/compile-fail/hrtb-conflate-regions.rs new file mode 100644 index 00000000000..5eb8fd69312 --- /dev/null +++ b/src/test/compile-fail/hrtb-conflate-regions.rs @@ -0,0 +1,40 @@ +// 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. + +// Test that an impl with only one bound region `'a` cannot be used to +// satisfy a constraint where there are two bound regions. + +trait Foo<X> { + fn foo(&self, x: X) { } +} + +fn want_foo2<T>() + where T : for<'a,'b> Foo<(&'a int, &'b int)> +{ +} + +fn want_foo1<T>() + where T : for<'z> Foo<(&'z int, &'z int)> +{ +} + +/////////////////////////////////////////////////////////////////////////// +// Expressed as a where clause + +struct SomeStruct; + +impl<'a> Foo<(&'a int, &'a int)> for SomeStruct +{ +} + +fn a() { want_foo1::<SomeStruct>(); } // OK -- foo wants just one region +fn b() { want_foo2::<SomeStruct>(); } //~ ERROR not implemented + +fn main() { } diff --git a/src/test/compile-fail/hrtb-just-for-static.rs b/src/test/compile-fail/hrtb-just-for-static.rs new file mode 100644 index 00000000000..36a45400eec --- /dev/null +++ b/src/test/compile-fail/hrtb-just-for-static.rs @@ -0,0 +1,37 @@ +// 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. + +// Test a case where you have an impl of `Foo<X>` for all `X` that +// is being applied to `for<'a> Foo<&'a mut X>`. Issue #19730. + +trait Foo<X> { + fn foo(&self, x: X) { } +} + +fn want_hrtb<T>() + where T : for<'a> Foo<&'a int> +{ +} + +// AnyInt implements Foo<&'a int> for any 'a, so it is a match. +struct AnyInt; +impl<'a> Foo<&'a int> for AnyInt { } +fn give_any() { + want_hrtb::<AnyInt>() +} + +// StaticInt only implements Foo<&'static int>, so it is an error. +struct StaticInt; +impl Foo<&'static int> for StaticInt { } +fn give_static() { + want_hrtb::<StaticInt>() //~ ERROR `for<'a> Foo<&'a int>` is not implemented +} + +fn main() { } diff --git a/src/test/compile-fail/hrtb-perfect-forwarding.rs b/src/test/compile-fail/hrtb-perfect-forwarding.rs new file mode 100644 index 00000000000..a8ee2154fc3 --- /dev/null +++ b/src/test/compile-fail/hrtb-perfect-forwarding.rs @@ -0,0 +1,66 @@ +// 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. + +// Test a case where you have an impl of `Foo<X>` for all `X` that +// is being applied to `for<'a> Foo<&'a mut X>`. Issue #19730. + +trait Foo<X> { + fn foo(&mut self, x: X) { } +} + +trait Bar<X> { + fn bar(&mut self, x: X) { } +} + +impl<'a,X,F> Foo<X> for &'a mut F + where F : Foo<X> + Bar<X> +{ +} + +impl<'a,X,F> Bar<X> for &'a mut F + where F : Bar<X> +{ +} + +fn no_hrtb<'b,T>(mut t: T) + where T : Bar<&'b int> +{ + // OK -- `T : Bar<&'b int>`, and thus the impl above ensures that + // `&mut T : Bar<&'b int>`. + no_hrtb(&mut t); +} + +fn bar_hrtb<T>(mut t: T) + where T : for<'b> Bar<&'b int> +{ + // OK -- `T : for<'b> Bar<&'b int>`, and thus the impl above + // ensures that `&mut T : for<'b> Bar<&'b int>`. This is an + // example of a "perfect forwarding" impl. + bar_hrtb(&mut t); +} + +fn foo_hrtb_bar_not<'b,T>(mut t: T) + where T : for<'a> Foo<&'a int> + Bar<&'b int> +{ + // Not OK -- The forwarding impl for `Foo` requires that `Bar` also + // be implemented. Thus to satisfy `&mut T : for<'a> Foo<&'a + // int>`, we require `T : for<'a> Bar<&'a int>`, but the where + // clause only specifies `T : Bar<&'b int>`. + foo_hrtb_bar_not(&mut t); //~ ERROR `for<'a> Bar<&'a int>` is not implemented for the type `T` +} + +fn foo_hrtb_bar_hrtb<T>(mut t: T) + where T : for<'a> Foo<&'a int> + for<'b> Bar<&'b int> +{ + // OK -- now we have `T : for<'b> Bar&'b int>`. + foo_hrtb_bar_hrtb(&mut t); +} + +fn main() { } diff --git a/src/test/compile-fail/hrtb-type-outlives.rs b/src/test/compile-fail/hrtb-type-outlives.rs new file mode 100644 index 00000000000..9fe8f9ab46d --- /dev/null +++ b/src/test/compile-fail/hrtb-type-outlives.rs @@ -0,0 +1,59 @@ +// 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. + +// Test what happens when a HR obligation is applied to an impl with +// "outlives" bounds. Currently we're pretty conservative here; this +// will probably improve in time. + +trait Foo<X> { + fn foo(&self, x: X) { } +} + +fn want_foo<T>() + where T : for<'a> Foo<&'a int> +{ +} + +/////////////////////////////////////////////////////////////////////////// +// Expressed as a where clause + +struct SomeStruct<X> { + x: X +} + +impl<'a,X> Foo<&'a int> for SomeStruct<X> + where X : 'a +{ +} + +fn one() { + // In fact there is no good reason for this to be an error, but + // whatever, I'm mostly concerned it doesn't ICE right now: + want_foo::<SomeStruct<uint>>(); + //~^ ERROR requirement `for<'a> uint : 'a` is not satisfied +} + +/////////////////////////////////////////////////////////////////////////// +// Expressed as shorthand + +struct AnotherStruct<X> { + x: X +} + +impl<'a,X:'a> Foo<&'a int> for AnotherStruct<X> +{ +} + +fn two() { + want_foo::<AnotherStruct<uint>>(); + //~^ ERROR requirement `for<'a> uint : 'a` is not satisfied +} + +fn main() { } diff --git a/src/test/compile-fail/issue-14366.rs b/src/test/compile-fail/issue-14366.rs index 01a15023fba..d03885ca713 100644 --- a/src/test/compile-fail/issue-14366.rs +++ b/src/test/compile-fail/issue-14366.rs @@ -11,5 +11,4 @@ fn main() { let _x = "test" as &::std::any::Any; //~^ ERROR the trait `core::kinds::Sized` is not implemented for the type `str` -//~^^ ERROR the trait `core::kinds::Sized` is not implemented for the type `str` } diff --git a/src/test/compile-fail/issue-15965.rs b/src/test/compile-fail/issue-15965.rs index 935e6770658..f3636edeaa5 100644 --- a/src/test/compile-fail/issue-15965.rs +++ b/src/test/compile-fail/issue-15965.rs @@ -10,7 +10,10 @@ fn main() { return - { return () } //~ ERROR the type of this value must be known in this context + { return () } +//~^ ERROR the type of this value must be known in this context +//~| ERROR this function takes 1 parameter +//~| ERROR mismatched types () ; } diff --git a/src/test/compile-fail/issue-18345.rs b/src/test/compile-fail/issue-18345.rs index 298f155faff..c8b3463b091 100644 --- a/src/test/compile-fail/issue-18345.rs +++ b/src/test/compile-fail/issue-18345.rs @@ -13,7 +13,9 @@ type Transducer<'t, R, T, U> = |Step<'t, R, U>|: 't -> Step<'t, R, T>; fn mapping<'f, R, T, U>(f: |T|: 'f -> U) -> &'f Transducer<'f, R, T, U> { |step| |r, x| - step(r, f(x)) //~ ERROR the type of this value must be known in this context + step(r, f(x)) + //~^ ERROR the type of this value must be known in this context + //~| ERROR this function takes 1 parameter but 2 parameters were supplied } fn main() {} diff --git a/src/test/compile-fail/issue-18532.rs b/src/test/compile-fail/issue-18532.rs index 9cf922ae990..ec44ab7b277 100644 --- a/src/test/compile-fail/issue-18532.rs +++ b/src/test/compile-fail/issue-18532.rs @@ -17,4 +17,5 @@ fn main() { (return)((),()); //~^ ERROR the type of this value must be known + //~| ERROR this function takes 1 parameter } diff --git a/src/test/compile-fail/kindck-inherited-copy-bound.rs b/src/test/compile-fail/kindck-inherited-copy-bound.rs index 51ee38d5cfe..f5740992af4 100644 --- a/src/test/compile-fail/kindck-inherited-copy-bound.rs +++ b/src/test/compile-fail/kindck-inherited-copy-bound.rs @@ -21,10 +21,15 @@ impl<T:Copy> Foo for T { fn take_param<T:Foo>(foo: &T) { } -fn main() { +fn a() { let x = box 3i; take_param(&x); //~ ERROR `core::kinds::Copy` is not implemented +} +fn b() { + let x = box 3i; let y = &x; let z = &x as &Foo; //~ ERROR `core::kinds::Copy` is not implemented } + +fn main() { } diff --git a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs index a82689b1649..b0b37d077c1 100644 --- a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs +++ b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs @@ -20,9 +20,16 @@ fn call_it<F:Fn(&int)->int>(_: &F, _: int) -> int { 0 } fn call_it_mut<F:FnMut(&int)->int>(_: &mut F, _: int) -> int { 0 } fn call_it_once<F:FnOnce(&int)->int>(_: F, _: int) -> int { 0 } -fn main() { +fn a() { let x = call_it(&square, 22); //~ ERROR not implemented +} + +fn b() { let y = call_it_mut(&mut square, 22); //~ ERROR not implemented +} + +fn c() { let z = call_it_once(square, 22); //~ ERROR not implemented } +fn main() { } diff --git a/src/test/compile-fail/unboxed-closures-wrong-abi.rs b/src/test/compile-fail/unboxed-closures-wrong-abi.rs index 920e91958ee..20a4ab85d7b 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-abi.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-abi.rs @@ -20,9 +20,17 @@ fn call_it<F:Fn(&int)->int>(_: &F, _: int) -> int { 0 } fn call_it_mut<F:FnMut(&int)->int>(_: &mut F, _: int) -> int { 0 } fn call_it_once<F:FnOnce(&int)->int>(_: F, _: int) -> int { 0 } -fn main() { +fn a() { let x = call_it(&square, 22); //~ ERROR not implemented +} + +fn b() { let y = call_it_mut(&mut square, 22); //~ ERROR not implemented +} + +fn c() { let z = call_it_once(square, 22); //~ ERROR not implemented } +fn main() { } + diff --git a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs index a7a7b1c6762..f08cff3cd68 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs @@ -21,9 +21,16 @@ fn call_it<F:Fn(&int)->int>(_: &F, _: int) -> int { 0 } fn call_it_mut<F:FnMut(&int)->int>(_: &mut F, _: int) -> int { 0 } fn call_it_once<F:FnOnce(&int)->int>(_: F, _: int) -> int { 0 } -fn main() { +fn a() { let x = call_it(&square, 22); //~ ERROR not implemented +} + +fn b() { let y = call_it_mut(&mut square, 22); //~ ERROR not implemented +} + +fn c() { let z = call_it_once(square, 22); //~ ERROR not implemented } +fn main() { } diff --git a/src/test/run-pass/hrtb-opt-in-copy.rs b/src/test/run-pass/hrtb-opt-in-copy.rs new file mode 100644 index 00000000000..b6bba363e72 --- /dev/null +++ b/src/test/run-pass/hrtb-opt-in-copy.rs @@ -0,0 +1,38 @@ +// 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. + +// Test that we handle binder levels correctly when checking whether a +// type can implement `Copy`. In particular, we had a bug where we failed to +// liberate the late-bound regions from the impl, and thus wound up +// searching for an impl of `for<'tcx> Foo<&'tcx T>`. The impl that +// exists however is `impl<T> Copy for Foo<T>` and the current rules +// did not consider that a match (something I would like to revise in +// a later PR). + +#![allow(dead_code)] + +use std::kinds::marker; + +#[deriving(Copy)] +struct Foo<T> { x: T } + +type Ty<'tcx> = &'tcx TyS<'tcx>; + +enum TyS<'tcx> { + Boop(marker::InvariantLifetime<'tcx>) +} + +enum Bar<'tcx> { + Baz(Foo<Ty<'tcx>>) +} + +impl<'tcx> Copy for Bar<'tcx> { } + +fn main() { } diff --git a/src/test/run-pass/issue-10501.rs b/src/test/run-pass/issue-10501.rs deleted file mode 100644 index 78f125398ed..00000000000 --- a/src/test/run-pass/issue-10501.rs +++ /dev/null @@ -1,14 +0,0 @@ -// 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. - -pub type Foo = fn(&int) -> (); -#[deriving(Clone)] -enum Baz { Bar(Foo) } -fn main() {} diff --git a/src/test/run-pass/issue-12741.rs b/src/test/run-pass/issue-12741.rs deleted file mode 100644 index e41613b4ae3..00000000000 --- a/src/test/run-pass/issue-12741.rs +++ /dev/null @@ -1,35 +0,0 @@ -// 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. - -#[deriving(Clone)] -pub struct Foo { - f: fn(char, |char| -> char) -> char -} - -impl Foo { - fn bar(&self) -> char { - ((*self).f)('a', |c: char| c) - } -} - -fn bla(c: char, cb: |char| -> char) -> char { - cb(c) -} - -pub fn make_foo() -> Foo { - Foo { - f: bla - } -} - -fn main() { - let a = make_foo(); - assert_eq!(a.bar(), 'a'); -} |
