#![feature(std_misc)]
#![feature(test)]
#![feature(path_ext)]
-#![feature(convert)]
#![feature(str_char)]
#![deny(warnings)]
```
# #![feature(core)]
-use std::iter::range_step;
use std::option::Option::{Some, None};
use std::collections::hash_map::{self, HashMap};
fn bar(map1: HashMap<String, usize>, map2: hash_map::HashMap<String, usize>){}
fn main() {
- // Equivalent to 'std::iter::range_step(0, 10, 2);'
- range_step(0, 10, 2);
-
// Equivalent to 'foo(vec![std::option::Option::Some(1.0f64),
// std::option::Option::None]);'
foo(vec![Some(1.0f64), None]);
* [Intrinsics](intrinsics.md)
* [Lang items](lang-items.md)
* [Link args](link-args.md)
+ * [Benchmark Tests](benchmark-tests.md)
* [Conclusion](conclusion.md)
* [Glossary](glossary.md)
--- /dev/null
+% Benchmark tests
+
+Rust supports benchmark tests, which can test the performance of your
+code. Let's make our `src/lib.rs` look like this (comments elided):
+
+```{rust,ignore}
+#![feature(test)]
+
+extern crate test;
+
+pub fn add_two(a: i32) -> i32 {
+ a + 2
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use test::Bencher;
+
+ #[test]
+ fn it_works() {
+ assert_eq!(4, add_two(2));
+ }
+
+ #[bench]
+ fn bench_add_two(b: &mut Bencher) {
+ b.iter(|| add_two(2));
+ }
+}
+```
+
+Note the `test` feature gate, which enables this unstable feature.
+
+We've imported the `test` crate, which contains our benchmarking support.
+We have a new function as well, with the `bench` attribute. Unlike regular
+tests, which take no arguments, benchmark tests take a `&mut Bencher`. This
+`Bencher` provides an `iter` method, which takes a closure. This closure
+contains the code we'd like to benchmark.
+
+We can run benchmark tests with `cargo bench`:
+
+```bash
+$ cargo bench
+ Compiling adder v0.0.1 (file:///home/steve/tmp/adder)
+ Running target/release/adder-91b3e234d4ed382a
+
+running 2 tests
+test tests::it_works ... ignored
+test tests::bench_add_two ... bench: 1 ns/iter (+/- 0)
+
+test result: ok. 0 passed; 0 failed; 1 ignored; 1 measured
+```
+
+Our non-benchmark test was ignored. You may have noticed that `cargo bench`
+takes a bit longer than `cargo test`. This is because Rust runs our benchmark
+a number of times, and then takes the average. Because we're doing so little
+work in this example, we have a `1 ns/iter (+/- 0)`, but this would show
+the variance if there was one.
+
+Advice on writing benchmarks:
+
+
+* Move setup code outside the `iter` loop; only put the part you want to measure inside
+* Make the code do "the same thing" on each iteration; do not accumulate or change state
+* Make the outer function idempotent too; the benchmark runner is likely to run
+ it many times
+* Make the inner `iter` loop short and fast so benchmark runs are fast and the
+ calibrator can adjust the run-length at fine resolution
+* Make the code in the `iter` loop do something simple, to assist in pinpointing
+ performance improvements (or regressions)
+
+## Gotcha: optimizations
+
+There's another tricky part to writing benchmarks: benchmarks compiled with
+optimizations activated can be dramatically changed by the optimizer so that
+the benchmark is no longer benchmarking what one expects. For example, the
+compiler might recognize that some calculation has no external effects and
+remove it entirely.
+
+```{rust,ignore}
+#![feature(test)]
+
+extern crate test;
+use test::Bencher;
+
+#[bench]
+fn bench_xor_1000_ints(b: &mut Bencher) {
+ b.iter(|| {
+ (0..1000).fold(0, |old, new| old ^ new);
+ });
+}
+```
+
+gives the following results
+
+```text
+running 1 test
+test bench_xor_1000_ints ... bench: 0 ns/iter (+/- 0)
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
+```
+
+The benchmarking runner offers two ways to avoid this. Either, the closure that
+the `iter` method receives can return an arbitrary value which forces the
+optimizer to consider the result used and ensures it cannot remove the
+computation entirely. This could be done for the example above by adjusting the
+`b.iter` call to
+
+```rust
+# struct X;
+# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
+b.iter(|| {
+ // note lack of `;` (could also use an explicit `return`).
+ (0..1000).fold(0, |old, new| old ^ new)
+});
+```
+
+Or, the other option is to call the generic `test::black_box` function, which
+is an opaque "black box" to the optimizer and so forces it to consider any
+argument as used.
+
+```rust
+#![feature(test)]
+
+extern crate test;
+
+# fn main() {
+# struct X;
+# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
+b.iter(|| {
+ let n = test::black_box(1000);
+
+ (0..n).fold(0, |a, b| a ^ b)
+})
+# }
+```
+
+Neither of these read or modify the value, and are very cheap for small values.
+Larger values can be passed indirectly to reduce overhead (e.g.
+`black_box(&huge_struct)`).
+
+Performing either of the above changes gives the following benchmarking results
+
+```text
+running 1 test
+test bench_xor_1000_ints ... bench: 131 ns/iter (+/- 3)
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
+```
+
+However, the optimizer can still modify a testcase in an undesirable manner
+even when using either of the above.
it to get a reference to the data. Real code would have more robust error handling
here. We're then free to mutate it, since we have the lock.
-This timer bit is a bit awkward, however. We have picked a reasonable amount of
-time to wait, but it's entirely possible that we've picked too high, and that
-we could be taking less time. It's also possible that we've picked too low,
-and that we aren't actually finishing this computation.
-
-Rust's standard library provides a few more mechanisms for two threads to
-synchronize with each other. Let's talk about one: channels.
+Lastly, while the threads are running, we wait on a short timer. But
+this is not ideal: we may have picked a reasonable amount of time to
+wait but it's more likely we'll either be waiting longer than
+necessary or not long enough, depending on just how much time the
+threads actually take to finish computing when the program runs.
+
+A more precise alternative to the timer would be to use one of the
+mechanisms provided by the Rust standard library for synchronizing
+threads with each other. Let's talk about one of them: channels.
## Channels
```
These two basic iterators should serve you well. There are some more
-advanced iterators, including ones that are infinite. Like `count`:
+advanced iterators, including ones that are infinite. Like using range syntax
+and `step_by`:
```rust
-# #![feature(core)]
-std::iter::count(1, 5);
+# #![feature(step_by)]
+(1..).step_by(5);
```
This iterator counts up from one, adding five each time. It will give
There are tons of interesting iterator adapters. `take(n)` will return an
iterator over the next `n` elements of the original iterator, note that this
has no side effect on the original iterator. Let's try it out with our infinite
-iterator from before, `count()`:
+iterator from before:
```rust
-# #![feature(core)]
-for i in std::iter::count(1, 5).take(5) {
+# #![feature(step_by)]
+for i in (1..).step_by(5).take(5) {
println!("{}", i);
}
```
```rust
let x: Vec<u32> = vec![1, 2, 3];
-# assert_eq!(&[1,2,3], &x);
+# assert_eq!(x, [1, 2, 3]);
```
This can't be an ordinary function, because it takes any number of arguments.
temp_vec.push(3);
temp_vec
};
-# assert_eq!(&[1,2,3], &x);
+# assert_eq!(x, [1, 2, 3]);
```
We can implement this shorthand, using a macro: [^actual]
};
}
# fn main() {
-# assert_eq!([1,2,3], vec![1,2,3]);
+# assert_eq!(vec![1,2,3], [1, 2, 3]);
# }
```
the item signature alone. However, for ergonomic reasons a very restricted
secondary inference algorithm called “lifetime elision” applies in function
signatures. It infers only based on the signature components themselves and not
-based on the body of the function, only infers lifetime paramters, and does
+based on the body of the function, only infers lifetime parameters, and does
this with only three easily memorizable and unambiguous rules. This makes
lifetime elision a shorthand for writing an item signature, while not hiding
away the actual types involved as full local inference would if applied to it.
for the function test. These will auto increment with names like `add_two_1` as
you add more examples.
-# Benchmark tests
-
-Rust also supports benchmark tests, which can test the performance of your
-code. Let's make our `src/lib.rs` look like this (comments elided):
-
-```{rust,ignore}
-extern crate test;
-
-pub fn add_two(a: i32) -> i32 {
- a + 2
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use test::Bencher;
-
- #[test]
- fn it_works() {
- assert_eq!(4, add_two(2));
- }
-
- #[bench]
- fn bench_add_two(b: &mut Bencher) {
- b.iter(|| add_two(2));
- }
-}
-```
-
-We've imported the `test` crate, which contains our benchmarking support.
-We have a new function as well, with the `bench` attribute. Unlike regular
-tests, which take no arguments, benchmark tests take a `&mut Bencher`. This
-`Bencher` provides an `iter` method, which takes a closure. This closure
-contains the code we'd like to benchmark.
-
-We can run benchmark tests with `cargo bench`:
-
-```bash
-$ cargo bench
- Compiling adder v0.0.1 (file:///home/steve/tmp/adder)
- Running target/release/adder-91b3e234d4ed382a
-
-running 2 tests
-test tests::it_works ... ignored
-test tests::bench_add_two ... bench: 1 ns/iter (+/- 0)
-
-test result: ok. 0 passed; 0 failed; 1 ignored; 1 measured
-```
-
-Our non-benchmark test was ignored. You may have noticed that `cargo bench`
-takes a bit longer than `cargo test`. This is because Rust runs our benchmark
-a number of times, and then takes the average. Because we're doing so little
-work in this example, we have a `1 ns/iter (+/- 0)`, but this would show
-the variance if there was one.
-
-Advice on writing benchmarks:
-
-
-* Move setup code outside the `iter` loop; only put the part you want to measure inside
-* Make the code do "the same thing" on each iteration; do not accumulate or change state
-* Make the outer function idempotent too; the benchmark runner is likely to run
- it many times
-* Make the inner `iter` loop short and fast so benchmark runs are fast and the
- calibrator can adjust the run-length at fine resolution
-* Make the code in the `iter` loop do something simple, to assist in pinpointing
- performance improvements (or regressions)
-
-## Gotcha: optimizations
-
-There's another tricky part to writing benchmarks: benchmarks compiled with
-optimizations activated can be dramatically changed by the optimizer so that
-the benchmark is no longer benchmarking what one expects. For example, the
-compiler might recognize that some calculation has no external effects and
-remove it entirely.
-
-```{rust,ignore}
-extern crate test;
-use test::Bencher;
-
-#[bench]
-fn bench_xor_1000_ints(b: &mut Bencher) {
- b.iter(|| {
- (0..1000).fold(0, |old, new| old ^ new);
- });
-}
-```
-
-gives the following results
-
-```text
-running 1 test
-test bench_xor_1000_ints ... bench: 0 ns/iter (+/- 0)
-
-test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
-```
-
-The benchmarking runner offers two ways to avoid this. Either, the closure that
-the `iter` method receives can return an arbitrary value which forces the
-optimizer to consider the result used and ensures it cannot remove the
-computation entirely. This could be done for the example above by adjusting the
-`b.iter` call to
-
-```rust
-# struct X;
-# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
-b.iter(|| {
- // note lack of `;` (could also use an explicit `return`).
- (0..1000).fold(0, |old, new| old ^ new)
-});
-```
-
-Or, the other option is to call the generic `test::black_box` function, which
-is an opaque "black box" to the optimizer and so forces it to consider any
-argument as used.
-
-```rust
-# #![feature(test)]
-
-extern crate test;
-
-# fn main() {
-# struct X;
-# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
-b.iter(|| {
- let n = test::black_box(1000);
-
- (0..n).fold(0, |a, b| a ^ b)
-})
-# }
-```
-
-Neither of these read or modify the value, and are very cheap for small values.
-Larger values can be passed indirectly to reduce overhead (e.g.
-`black_box(&huge_struct)`).
-
-Performing either of the above changes gives the following benchmarking results
-
-```text
-running 1 test
-test bench_xor_1000_ints ... bench: 131 ns/iter (+/- 3)
-
-test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
-```
-
-However, the optimizer can still modify a testcase in an undesirable manner
-even when using either of the above.
dispatched. What's that mean? Check out the chapter on [static and dynamic
dispatch](static-and-dynamic-dispatch.html) for more.
+## Multiple trait bounds
+
+You’ve seen that you can bound a generic type parameter with a trait:
+
+```rust
+fn foo<T: Clone>(x: T) {
+ x.clone();
+}
+```
+
+If you need more than one bound, you can use `+`:
+
+```rust
+use std::fmt::Debug;
+
+fn foo<T: Clone + Debug>(x: T) {
+ x.clone();
+ println!("{:?}", x);
+}
+```
+
+`T` now needs to be both `Clone` as well as `Debug`.
+
## Where clause
Writing functions with only a few generic types and a small number of trait
/// let child_numbers = shared_numbers.clone();
///
/// thread::spawn(move || {
-/// let local_numbers = child_numbers.as_slice();
+/// let local_numbers = &child_numbers[..];
///
/// // Work with the local numbers
/// });
#[unstable(feature = "alloc")]
pub fn strong_count<T>(this: &Arc<T>) -> usize { this.inner().strong.load(SeqCst) }
+
+/// Try accessing a mutable reference to the contents behind an unique `Arc<T>`.
+///
+/// The access is granted only if this is the only reference to the object.
+/// Otherwise, `None` is returned.
+///
+/// # Examples
+///
+/// ```
+/// # #![feature(alloc)]
+/// use std::alloc::arc;
+///
+/// let mut four = arc::Arc::new(4);
+///
+/// arc::unique(&mut four).map(|num| *num = 5);
+/// ```
+#[inline]
+#[unstable(feature = "alloc")]
+pub fn unique<T>(this: &mut Arc<T>) -> Option<&mut T> {
+ if strong_count(this) == 1 && weak_count(this) == 0 {
+ // This unsafety is ok because we're guaranteed that the pointer
+ // returned is the *only* pointer that will ever be returned to T. Our
+ // reference count is guaranteed to be 1 at this point, and we required
+ // the Arc itself to be `mut`, so we're returning the only possible
+ // reference to the inner data.
+ let inner = unsafe { &mut **this._ptr };
+ Some(&mut inner.data)
+ }else {
+ None
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Clone for Arc<T> {
/// Makes a clone of the `Arc<T>`.
self.inner().weak.load(SeqCst) != 1 {
*self = Arc::new((**self).clone())
}
- // This unsafety is ok because we're guaranteed that the pointer
- // returned is the *only* pointer that will ever be returned to T. Our
- // reference count is guaranteed to be 1 at this point, and we required
- // the Arc itself to be `mut`, so we're returning the only possible
- // reference to the inner data.
+ // As with `unique()`, the unsafety is ok because our reference was
+ // either unique to begin with, or became one upon cloning the contents.
let inner = unsafe { &mut **self._ptr };
&mut inner.data
}
use std::sync::atomic::Ordering::{Acquire, SeqCst};
use std::thread;
use std::vec::Vec;
- use super::{Arc, Weak, weak_count, strong_count};
+ use super::{Arc, Weak, weak_count, strong_count, unique};
use std::sync::Mutex;
struct Canary(*mut atomic::AtomicUsize);
assert_eq!((*arc_v)[4], 5);
}
+ #[test]
+ fn test_arc_unique() {
+ let mut x = Arc::new(10);
+ assert!(unique(&mut x).is_some());
+ {
+ let y = x.clone();
+ assert!(unique(&mut x).is_none());
+ }
+ {
+ let z = x.downgrade();
+ assert!(unique(&mut x).is_none());
+ }
+ assert!(unique(&mut x).is_some());
+ }
+
#[test]
fn test_cowarc_clone_make_unique() {
let mut cow0 = Arc::new(75);
use core::any::Any;
use core::cmp::Ordering;
use core::default::Default;
-use core::error::{Error, FromError};
+use core::error::Error;
use core::fmt;
use core::hash::{self, Hash};
use core::mem;
use core::ops::{Deref, DerefMut};
-use core::ptr::Unique;
-use core::raw::TraitObject;
+use core::ptr::{self, Unique};
+use core::raw::{TraitObject, Slice};
+
+use heap;
/// A value that represents the heap. This is the default place that the `box`
/// keyword allocates into when no place is supplied.
/// See the [module-level documentation](../../std/boxed/index.html) for more.
#[lang = "owned_box"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[fundamental]
pub struct Box<T>(Unique<T>);
impl<T> Box<T> {
}
}
-/// Extension methods for an owning `Any` trait object.
-#[unstable(feature = "alloc",
- reason = "this trait will likely disappear once compiler bugs blocking \
- a direct impl on `Box<Any>` have been fixed ")]
-// FIXME(#18737): this should be a direct impl on `Box<Any>`. If you're
-// removing this please make sure that you can downcase on
-// `Box<Any + Send>` as well as `Box<Any>`
-pub trait BoxAny {
- /// Returns the boxed value if it is of type `T`, or
- /// `Err(Self)` if it isn't.
- #[stable(feature = "rust1", since = "1.0.0")]
- fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>>;
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl BoxAny for Box<Any> {
+impl Box<Any> {
#[inline]
- fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
if self.is::<T>() {
unsafe {
// Get the raw representation of the trait object
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl BoxAny for Box<Any+Send> {
+impl Box<Any+Send> {
#[inline]
- fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
<Box<Any>>::downcast(self)
}
}
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for Box<Any> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.pad("Box<Any>")
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Deref for Box<T> {
type Target = T;
impl<I: ExactSizeIterator + ?Sized> ExactSizeIterator for Box<I> {}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, E: Error + 'a> FromError<E> for Box<Error + 'a> {
- fn from_error(err: E) -> Box<Error + 'a> {
+impl<'a, E: Error + 'a> From<E> for Box<Error + 'a> {
+ fn from(err: E) -> Box<Error + 'a> {
Box::new(err)
}
}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, E: Error + Send + 'a> From<E> for Box<Error + Send + 'a> {
+ fn from(err: E) -> Box<Error + Send + 'a> {
+ Box::new(err)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, 'b> From<&'b str> for Box<Error + Send + 'a> {
+ fn from(err: &'b str) -> Box<Error + Send + 'a> {
+ #[derive(Debug)]
+ struct StringError(Box<str>);
+ impl Error for StringError {
+ fn description(&self) -> &str { &self.0 }
+ }
+ impl fmt::Display for StringError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.0.fmt(f)
+ }
+ }
+
+ // Unfortunately `String` is located in libcollections, so we construct
+ // a `Box<str>` manually here.
+ unsafe {
+ let alloc = if err.len() == 0 {
+ 0 as *mut u8
+ } else {
+ let ptr = heap::allocate(err.len(), 1);
+ if ptr.is_null() { ::oom(); }
+ ptr as *mut u8
+ };
+ ptr::copy(err.as_bytes().as_ptr(), alloc, err.len());
+ Box::new(StringError(mem::transmute(Slice {
+ data: alloc,
+ len: err.len(),
+ })))
+ }
+ }
+}
use std::boxed;
use std::boxed::Box;
-use std::boxed::BoxAny;
#[test]
fn test_owned_clone() {
let b = Box::new(Test) as Box<Any>;
let a_str = format!("{:?}", a);
let b_str = format!("{:?}", b);
- assert_eq!(a_str, "Box<Any>");
- assert_eq!(b_str, "Box<Any>");
+ assert_eq!(a_str, "Any");
+ assert_eq!(b_str, "Any");
static EIGHT: usize = 8;
static TEST: Test = Test;
let a = &EIGHT as &Any;
let b = &TEST as &Any;
let s = format!("{:?}", a);
- assert_eq!(s, "&Any");
+ assert_eq!(s, "Any");
let s = format!("{:?}", b);
- assert_eq!(s, "&Any");
+ assert_eq!(s, "Any");
}
#[test]
#![feature(no_std)]
#![no_std]
#![feature(allocator)]
+#![feature(custom_attribute)]
+#![feature(fundamental)]
#![feature(lang_items, unsafe_destructor)]
#![feature(box_syntax)]
#![feature(optin_builtin_traits)]
//! [sieve]: http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
//!
//! ```
-//! # #![feature(collections, core)]
+//! # #![feature(collections, core, step_by)]
//! use std::collections::{BitSet, BitVec};
//! use std::num::Float;
//! use std::iter;
//! if bv[i] {
//! // Mark all multiples of i as non-prime (any multiples below i * i
//! // will have been marked as non-prime previously)
-//! for j in iter::range_step(i * i, max_prime, i) { bv.set(j, false) }
+//! for j in (i * i..max_prime).step_by(i) { bv.set(j, false) }
//! }
//! }
//! BitSet::from_bit_vec(bv)
BitSet { bit_vec: bit_vec }
}
- /// Deprecated: use `from_bit_vec`.
- #[inline]
- #[deprecated(since = "1.0.0", reason = "renamed to from_bit_vec")]
- #[unstable(feature = "collections")]
- pub fn from_bitv(bit_vec: BitVec) -> BitSet {
- BitSet { bit_vec: bit_vec }
- }
-
/// Returns the capacity in bits for this bit vector. Inserting any
/// element less than this amount will not trigger a resizing.
///
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Borrow<Borrowed: ?Sized> {
/// Immutably borrow from an owned value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::borrow::Borrow;
+ ///
+ /// fn check<T: Borrow<str>>(s: T) {
+ /// assert_eq!("Hello", s.borrow());
+ /// }
+ ///
+ /// let s = "Hello".to_string();
+ ///
+ /// check(s);
+ ///
+ /// let s = "Hello";
+ ///
+ /// check(s);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn borrow(&self) -> &Borrowed;
}
#[stable(feature = "rust1", since = "1.0.0")]
pub trait BorrowMut<Borrowed: ?Sized> : Borrow<Borrowed> {
/// Mutably borrow from an owned value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::borrow::BorrowMut;
+ ///
+ /// fn check<T: BorrowMut<[i32]>>(mut v: T) {
+ /// assert_eq!(&mut [1, 2, 3], v.borrow_mut());
+ /// }
+ ///
+ /// let v = vec![1, 2, 3];
+ ///
+ /// check(v);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn borrow_mut(&mut self) -> &mut Borrowed;
}
/// Acquire a mutable reference to the owned form of the data.
///
/// Copies the data if it is not already owned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::borrow::Cow;
+ ///
+ /// let mut cow: Cow<[_]> = Cow::Owned(vec![1, 2, 3]);
+ ///
+ /// let hello = cow.to_mut();
+ ///
+ /// assert_eq!(hello, &[1, 2, 3]);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_mut(&mut self) -> &mut <B as ToOwned>::Owned {
match *self {
/// Extract the owned data.
///
/// Copies the data if it is not already owned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::borrow::Cow;
+ ///
+ /// let cow: Cow<[_]> = Cow::Owned(vec![1, 2, 3]);
+ ///
+ /// let hello = cow.into_owned();
+ ///
+ /// assert_eq!(vec![1, 2, 3], hello);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_owned(self) -> <B as ToOwned>::Owned {
match self {
Owned(owned) => owned
}
}
-
- /// Returns true if this `Cow` wraps a borrowed value
- #[deprecated(since = "1.0.0", reason = "match on the enum instead")]
- #[unstable(feature = "std_misc")]
- pub fn is_borrowed(&self) -> bool {
- match *self {
- Borrowed(_) => true,
- _ => false,
- }
- }
-
- /// Returns true if this `Cow` wraps an owned value
- #[deprecated(since = "1.0.0", reason = "match on the enum instead")]
- #[unstable(feature = "std_misc")]
- pub fn is_owned(&self) -> bool {
- match *self {
- Owned(_) => true,
- _ => false,
- }
- }
}
#[stable(feature = "rust1", since = "1.0.0")]
}
}
- #[unstable(feature = "collections",
- reason = "matches entry v3 specification, waiting for dust to settle")]
+ #[stable(feature = "rust1", since = "1.0.0")]
/// Ensures a value is in the entry by inserting the default if empty, and returns
/// a mutable reference to the value in the entry.
pub fn or_insert(self, default: V) -> &'a mut V {
}
}
- #[unstable(feature = "collections",
- reason = "matches entry v3 specification, waiting for dust to settle")]
+ #[stable(feature = "rust1", since = "1.0.0")]
/// Ensures a value is in the entry by inserting the result of the default function if empty,
/// and returns a mutable reference to the value in the entry.
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
#![feature(unsafe_no_drop_flag, filling_drop)]
#![feature(step_by)]
#![feature(str_char)]
-#![feature(convert)]
#![feature(slice_patterns)]
#![feature(debug_builders)]
#![cfg_attr(test, feature(rand, rustc_private, test, hash, collections))]
pub use vec::Vec;
pub use vec_map::VecMap;
-#[deprecated(since = "1.0.0", reason = "renamed to vec_deque")]
-#[unstable(feature = "collections")]
-pub use vec_deque as ring_buf;
-
-#[deprecated(since = "1.0.0", reason = "renamed to linked_list")]
-#[unstable(feature = "collections")]
-pub use linked_list as dlist;
-
-#[deprecated(since = "1.0.0", reason = "renamed to bit_vec")]
-#[unstable(feature = "collections")]
-pub use bit_vec as bitv;
-
-#[deprecated(since = "1.0.0", reason = "renamed to bit_set")]
-#[unstable(feature = "collections")]
-pub use bit_set as bitv_set;
-
// Needed for the vec! macro
pub use alloc::boxed;
reason = "RFC 509")]
pub mod bit_vec {
pub use bit::{BitVec, Iter};
-
- #[deprecated(since = "1.0.0", reason = "renamed to BitVec")]
- #[unstable(feature = "collections")]
- pub use bit::BitVec as Bitv;
}
#[unstable(feature = "collections",
pub mod bit_set {
pub use bit::{BitSet, Union, Intersection, Difference, SymmetricDifference};
pub use bit::SetIter as Iter;
-
- #[deprecated(since = "1.0.0", reason = "renamed to BitSet")]
- #[unstable(feature = "collections")]
- pub use bit::BitSet as BitvSet;
}
#[stable(feature = "rust1", since = "1.0.0")]
use core::mem;
use core::ptr;
-#[deprecated(since = "1.0.0", reason = "renamed to LinkedList")]
-#[unstable(feature = "collections")]
-pub use LinkedList as DList;
-
/// A doubly-linked list.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct LinkedList<T> {
/// }
/// println!("{}", b.len()); // prints 0
/// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn append(&mut self, other: &mut LinkedList<T>) {
match self.list_tail.resolve() {
None => {
#[stable(feature = "rust1", since = "1.0.0")]
impl<A> FromIterator<A> for LinkedList<A> {
fn from_iter<T: IntoIterator<Item=A>>(iter: T) -> LinkedList<A> {
- let mut ret = DList::new();
+ let mut ret = LinkedList::new();
ret.extend(iter);
ret
}
thread::spawn(move || {
check_links(&n);
let a: &[_] = &[&1,&2,&3];
- assert_eq!(a, n.iter().collect::<Vec<_>>());
+ assert_eq!(a, &n.iter().collect::<Vec<_>>()[..]);
}).join().ok().unwrap();
}
use core::marker::Sized;
use core::mem::size_of;
use core::mem;
-#[cfg(stage0)]
-use core::num::wrapping::WrappingOps;
use core::ops::FnMut;
use core::option::Option::{self, Some, None};
use core::ptr;
pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut};
pub use core::slice::{bytes, mut_ref_slice, ref_slice};
pub use core::slice::{from_raw_parts, from_raw_parts_mut};
-pub use core::slice::{from_raw_buf, from_raw_mut_buf};
////////////////////////////////////////////////////////////////////////////////
// Basic slice extension methods
cmp::min(self.len(), end-start)
}
- /// Deprecated: use `&s[start .. end]` notation instead.
- #[unstable(feature = "collections",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &s[start .. end] instead")]
- #[inline]
- pub fn slice(&self, start: usize, end: usize) -> &[T] {
- &self[start .. end]
- }
-
- /// Deprecated: use `&s[start..]` notation instead.
- #[unstable(feature = "collections",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &s[start..] instead")]
- #[inline]
- pub fn slice_from(&self, start: usize) -> &[T] {
- &self[start ..]
- }
-
- /// Deprecated: use `&s[..end]` notation instead.
- #[unstable(feature = "collections",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &s[..end] instead")]
- #[inline]
- pub fn slice_to(&self, end: usize) -> &[T] {
- &self[.. end]
- }
-
/// Divides one slice into two at an index.
///
/// The first will contain all indices from `[0, mid)` (excluding
/// ```rust
/// # #![feature(core)]
/// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
- /// let s = s.as_slice();
///
/// let seek = 13;
/// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9));
core_slice::SliceExt::get_mut(self, index)
}
- /// Deprecated: use `&mut s[..]` instead.
- #[unstable(feature = "collections",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")]
- #[allow(deprecated)]
- pub fn as_mut_slice(&mut self) -> &mut [T] {
- core_slice::SliceExt::as_mut_slice(self)
- }
-
- /// Deprecated: use `&mut s[start .. end]` instead.
- #[unstable(feature = "collections",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &mut s[start .. end] instead")]
- #[inline]
- pub fn slice_mut(&mut self, start: usize, end: usize) -> &mut [T] {
- &mut self[start .. end]
- }
-
- /// Deprecated: use `&mut s[start ..]` instead.
- #[unstable(feature = "collections",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &mut s[start ..] instead")]
- #[inline]
- pub fn slice_from_mut(&mut self, start: usize) -> &mut [T] {
- &mut self[start ..]
- }
-
- /// Deprecated: use `&mut s[.. end]` instead.
- #[unstable(feature = "collections",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &mut s[.. end] instead")]
- #[inline]
- pub fn slice_to_mut(&mut self, end: usize) -> &mut [T] {
- &mut self[.. end]
- }
-
/// Returns an iterator that allows modifying each value
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
/// ```rust
/// # #![feature(core)]
/// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
- /// let s = s.as_slice();
///
/// assert_eq!(s.binary_search(&13), Ok(9));
/// assert_eq!(s.binary_search(&4), Err(7));
core_slice::SliceExt::binary_search(self, x)
}
- /// Deprecated: use `binary_search` instead.
- #[unstable(feature = "collections")]
- #[deprecated(since = "1.0.0", reason = "use binary_search instead")]
- pub fn binary_search_elem(&self, x: &T) -> Result<usize, usize> where T: Ord {
- self.binary_search(x)
- }
-
/// Mutates the slice to the next lexicographic permutation.
///
/// Returns `true` if successful and `false` if the slice is at the
//
// ignore-lexer-test FIXME #15679
-//! Unicode string manipulation (the [`str`](../primitive.str.html) type).
+//! Unicode string manipulation (the `str` type).
//!
-//! Rust's [`str`](../primitive.str.html) type is one of the core primitive
-//! types of the language. `&str` is the borrowed string type. This type of
-//! string can only be created from other strings, unless it is a `&'static str`
-//! (see below). It is not possible to move out of borrowed strings because they
-//! are owned elsewhere.
+//! Rust's `str` type is one of the core primitive types of the language. `&str`
+//! is the borrowed string type. This type of string can only be created from
+//! other strings, unless it is a `&'static str` (see below). It is not possible
+//! to move out of borrowed strings because they are owned elsewhere.
//!
//! # Examples
//!
use slice::SliceConcatExt;
pub use core::str::{FromStr, Utf8Error, Str};
-pub use core::str::{Lines, LinesAny, MatchIndices, SplitStr, CharRange};
+pub use core::str::{Lines, LinesAny, MatchIndices, CharRange};
pub use core::str::{Split, SplitTerminator, SplitN};
pub use core::str::{RSplit, RSplitN};
-pub use core::str::{from_utf8, CharEq, Chars, CharIndices, Bytes};
-pub use core::str::{from_utf8_unchecked, from_c_str, ParseBoolError};
+pub use core::str::{from_utf8, Chars, CharIndices, Bytes};
+pub use core::str::{from_utf8_unchecked, ParseBoolError};
pub use unicode::str::{Words, Graphemes, GraphemeIndices};
pub use core::str::Pattern;
pub use core::str::{Searcher, ReverseSearcher, DoubleEndedSearcher, SearchStep};
core_str::StrExt::contains(&self[..], pat)
}
- /// Returns `true` if `self` contains a `char`.
- ///
- /// # Examples
- ///
- /// ```
- /// # #![feature(collections)]
- /// assert!("hello".contains_char('e'));
- ///
- /// assert!(!"hello".contains_char('z'));
- /// ```
- #[unstable(feature = "collections")]
- #[deprecated(since = "1.0.0", reason = "use `contains()` with a char")]
- pub fn contains_char<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
- core_str::StrExt::contains_char(&self[..], pat)
- }
-
/// An iterator over the codepoints of `self`.
///
/// # Examples
core_str::StrExt::match_indices(&self[..], pat)
}
- /// An iterator over the substrings of `self` separated by a `&str`.
- ///
- /// # Examples
- ///
- /// ```
- /// # #![feature(collections)]
- /// let v: Vec<&str> = "abcXXXabcYYYabc".split_str("abc").collect();
- /// assert_eq!(v, ["", "XXX", "YYY", ""]);
- ///
- /// let v: Vec<&str> = "1abcabc2".split_str("abc").collect();
- /// assert_eq!(v, ["1", "", "2"]);
- /// ```
- #[unstable(feature = "collections")]
- #[deprecated(since = "1.0.0", reason = "use `split()` with a `&str`")]
- #[allow(deprecated) /* for SplitStr */]
- pub fn split_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitStr<'a, P> {
- core_str::StrExt::split_str(&self[..], pat)
- }
-
/// An iterator over the lines of a string, separated by `\n`.
///
/// This does not include the empty string after a trailing `\n`.
pub fn lines_any(&self) -> LinesAny {
core_str::StrExt::lines_any(&self[..])
}
-
- /// Deprecated: use `s[a .. b]` instead.
- #[unstable(feature = "collections",
- reason = "use slice notation [a..b] instead")]
- #[deprecated(since = "1.0.0", reason = "use slice notation [a..b] instead")]
- pub fn slice(&self, begin: usize, end: usize) -> &str {
- &self[begin..end]
- }
-
- /// Deprecated: use `s[a..]` instead.
- #[unstable(feature = "collections",
- reason = "use slice notation [a..b] instead")]
- #[deprecated(since = "1.0.0", reason = "use slice notation [a..] instead")]
- pub fn slice_from(&self, begin: usize) -> &str {
- &self[begin..]
- }
-
- /// Deprecated: use `s[..a]` instead.
- #[unstable(feature = "collections",
- reason = "use slice notation [a..b] instead")]
- #[deprecated(since = "1.0.0", reason = "use slice notation [..a] instead")]
- pub fn slice_to(&self, end: usize) -> &str {
- &self[..end]
- }
-
/// Returns a slice of the string from the character range [`begin`..`end`).
///
/// That is, start at the `begin`-th code point of the string and continue
core_str::StrExt::rfind(&self[..], pat)
}
- /// Returns the byte index of the first matching substring if it exists.
- ///
- /// Returns `None` if it doesn't exist.
- ///
- /// The pattern can be a simple `&str`, or a closure that determines the split.
- ///
- /// # Examples
- ///
- /// ```
- /// # #![feature(collections)]
- /// let s = "Löwe 老虎 Léopard";
- ///
- /// assert_eq!(s.find_str("老虎 L"), Some(6));
- /// assert_eq!(s.find_str("muffin man"), None);
- /// ```
- #[unstable(feature = "collections")]
- #[deprecated(since = "1.0.0", reason = "use `find()` with a `&str`")]
- pub fn find_str<'a, P: Pattern<'a>>(&'a self, needle: P) -> Option<usize> {
- core_str::StrExt::find_str(&self[..], needle)
- }
-
/// Retrieves the first character from a `&str` and returns it.
///
/// This does not allocate a new string; instead, it returns a slice that points one character
/// let gr1 = "a\u{310}e\u{301}o\u{308}\u{332}".graphemes(true).collect::<Vec<&str>>();
/// let b: &[_] = &["a\u{310}", "e\u{301}", "o\u{308}\u{332}"];
///
- /// assert_eq!(gr1.as_slice(), b);
+ /// assert_eq!(&gr1[..], b);
///
/// let gr2 = "a\r\nb🇷🇺🇸🇹".graphemes(true).collect::<Vec<&str>>();
/// let b: &[_] = &["a", "\r\n", "b", "🇷🇺🇸🇹"];
///
- /// assert_eq!(gr2.as_slice(), b);
+ /// assert_eq!(&gr2[..], b);
/// ```
#[unstable(feature = "unicode",
reason = "this functionality may only be provided by libunicode")]
/// let gr_inds = "a̐éö̲\r\n".grapheme_indices(true).collect::<Vec<(usize, &str)>>();
/// let b: &[_] = &[(0, "a̐"), (3, "é"), (6, "ö̲"), (11, "\r\n")];
///
- /// assert_eq!(gr_inds.as_slice(), b);
+ /// assert_eq!(&gr_inds[..], b);
/// ```
#[unstable(feature = "unicode",
reason = "this functionality may only be provided by libunicode")]
/// ```
/// # #![feature(collections, core)]
/// let s = String::from_str("hello");
- /// assert_eq!(s.as_slice(), "hello");
+ /// assert_eq!(&s[..], "hello");
/// ```
#[inline]
#[unstable(feature = "collections",
self.vec
}
+ /// Extract a string slice containing the entire string.
+ #[inline]
+ #[unstable(feature = "convert",
+ reason = "waiting on RFC revision")]
+ pub fn as_str(&self) -> &str {
+ self
+ }
+
/// Pushes the given string onto this string buffer.
///
/// # Examples
#[allow(deprecated)]
impl Str for String {
#[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
fn as_slice(&self) -> &str {
unsafe { mem::transmute(&*self.vec) }
}
}
}
-/// A clone-on-write string
-#[deprecated(since = "1.0.0", reason = "use Cow<'a, str> instead")]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub type CowString<'a> = Cow<'a, str>;
-
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Write for String {
#[inline]
/// Note that this will drop any excess capacity. Calling this and
/// converting back to a vector with `into_vec()` is equivalent to calling
/// `shrink_to_fit()`.
- #[unstable(feature = "collections")]
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn into_boxed_slice(mut self) -> Box<[T]> {
self.shrink_to_fit();
unsafe {
}
}
+ /// Extract a slice containing the entire vector.
+ #[inline]
+ #[unstable(feature = "convert",
+ reason = "waiting on RFC revision")]
+ pub fn as_slice(&self) -> &[T] {
+ self
+ }
+
/// Deprecated: use `&mut s[..]` instead.
#[inline]
- #[unstable(feature = "collections",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")]
+ #[unstable(feature = "convert",
+ reason = "waiting on RFC revision")]
pub fn as_mut_slice(&mut self) -> &mut [T] {
&mut self[..]
}
/// # #![feature(collections, core)]
/// let v = vec![0, 1, 2];
/// let w = v.map_in_place(|i| i + 3);
- /// assert_eq!(w.as_slice(), [3, 4, 5].as_slice());
+ /// assert_eq!(&w[..], &[3, 4, 5]);
///
/// #[derive(PartialEq, Debug)]
/// struct Newtype(u8);
/// let bytes = vec![0x11, 0x22];
/// let newtyped_bytes = bytes.map_in_place(|x| Newtype(x));
- /// assert_eq!(newtyped_bytes.as_slice(), [Newtype(0x11), Newtype(0x22)].as_slice());
+ /// assert_eq!(&newtyped_bytes[..], &[Newtype(0x11), Newtype(0x22)]);
/// ```
#[unstable(feature = "collections",
reason = "API may change to provide stronger guarantees")]
}
__impl_slice_eq1! { Vec<A>, Vec<B> }
-__impl_slice_eq2! { Vec<A>, &'b [B] }
-__impl_slice_eq2! { Vec<A>, &'b mut [B] }
-__impl_slice_eq2! { Cow<'a, [A]>, &'b [B], Clone }
-__impl_slice_eq2! { Cow<'a, [A]>, &'b mut [B], Clone }
-__impl_slice_eq2! { Cow<'a, [A]>, Vec<B>, Clone }
+__impl_slice_eq1! { Vec<A>, &'b [B] }
+__impl_slice_eq1! { Vec<A>, &'b mut [B] }
+__impl_slice_eq1! { Cow<'a, [A]>, &'b [B], Clone }
+__impl_slice_eq1! { Cow<'a, [A]>, &'b mut [B], Clone }
+__impl_slice_eq1! { Cow<'a, [A]>, Vec<B>, Clone }
macro_rules! array_impls {
($($N: expr)+) => {
$(
// NOTE: some less important impls are omitted to reduce code bloat
- __impl_slice_eq2! { Vec<A>, [B; $N] }
- __impl_slice_eq2! { Vec<A>, &'b [B; $N] }
- // __impl_slice_eq2! { Vec<A>, &'b mut [B; $N] }
- // __impl_slice_eq2! { Cow<'a, [A]>, [B; $N], Clone }
- // __impl_slice_eq2! { Cow<'a, [A]>, &'b [B; $N], Clone }
- // __impl_slice_eq2! { Cow<'a, [A]>, &'b mut [B; $N], Clone }
+ __impl_slice_eq1! { Vec<A>, [B; $N] }
+ __impl_slice_eq1! { Vec<A>, &'b [B; $N] }
+ // __impl_slice_eq1! { Vec<A>, &'b mut [B; $N] }
+ // __impl_slice_eq1! { Cow<'a, [A]>, [B; $N], Clone }
+ // __impl_slice_eq1! { Cow<'a, [A]>, &'b [B; $N], Clone }
+ // __impl_slice_eq1! { Cow<'a, [A]>, &'b mut [B; $N], Clone }
)+
}
}
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Into<Vec<T>> for Vec<T> {
- fn into(self) -> Vec<T> {
- self
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsRef<[T]> for Vec<T> {
fn as_ref(&self) -> &[T] {
// Clone-on-write
////////////////////////////////////////////////////////////////////////////////
-/// A clone-on-write vector
-#[deprecated(since = "1.0.0", reason = "use Cow<'a, [T]> instead")]
-#[unstable(feature = "collections")]
-pub type CowVec<'a, T> = Cow<'a, [T]>;
-
#[unstable(feature = "collections")]
impl<'a, T> FromIterator<T> for Cow<'a, [T]> where T: Clone {
fn from_iter<I: IntoIterator<Item=T>>(it: I) -> Cow<'a, [T]> {
use core::fmt;
use core::iter::{self, repeat, FromIterator, IntoIterator, RandomAccessIterator};
use core::mem;
-#[cfg(stage0)]
-use core::num::wrapping::WrappingOps;
use core::ops::{Index, IndexMut};
use core::ptr::{self, Unique};
use core::slice;
use alloc::heap;
-#[deprecated(since = "1.0.0", reason = "renamed to VecDeque")]
-#[unstable(feature = "collections")]
-pub use VecDeque as RingBuf;
-
const INITIAL_CAPACITY: usize = 7; // 2^3 - 1
const MINIMUM_CAPACITY: usize = 1; // 2 - 1
/// buf.push_back(3);
/// buf.push_back(4);
/// let b: &[_] = &[&5, &3, &4];
- /// assert_eq!(buf.iter().collect::<Vec<&i32>>().as_slice(), b);
+ /// let c: Vec<&i32> = buf.iter().collect();
+ /// assert_eq!(&c[..], b);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter(&self) -> Iter<T> {
// len is the length *after* insertion
for len in 1..cap {
// 0, 1, 2, .., len - 1
- let expected = iter::count(0, 1).take(len).collect();
+ let expected = (0..).take(len).collect();
for tail_pos in 0..cap {
for to_insert in 0..len {
tester.tail = tail_pos;
// len is the length *after* removal
for len in 0..cap - 1 {
// 0, 1, 2, .., len - 1
- let expected = iter::count(0, 1).take(len).collect();
+ let expected = (0..).take(len).collect();
for tail_pos in 0..cap {
for to_remove in 0..len + 1 {
tester.tail = tail_pos;
for len in 0..cap + 1 {
// 0, 1, 2, .., len - 1
- let expected = iter::count(0, 1).take(len).collect();
+ let expected = (0..).take(len).collect();
for tail_pos in 0..max_cap + 1 {
tester.tail = tail_pos;
tester.head = tail_pos;
// index to split at
for at in 0..len + 1 {
// 0, 1, 2, .., at - 1 (may be empty)
- let expected_self = iter::count(0, 1).take(at).collect();
+ let expected_self = (0..).take(at).collect();
// at, at + 1, .., len - 1 (may be empty)
- let expected_other = iter::count(at, 1).take(len - at).collect();
+ let expected_other = (at..).take(len - at).collect();
for tail_pos in 0..cap {
tester.tail = tail_pos;
use std::cmp::Ordering::{Equal, Greater, Less};
use std::collections::{BitSet, BitVec};
-use std::iter::range_step;
#[test]
fn test_bit_set_show() {
assert_eq!(idxs, [0, 2, 3]);
let long: BitSet = (0..10000).filter(|&n| n % 2 == 0).collect();
- let real: Vec<_> = range_step(0, 10000, 2).collect();
+ let real: Vec<_> = (0..10000).step_by(2).collect();
let idxs: Vec<_> = long.iter().collect();
assert_eq!(idxs, real);
e1.insert(A);
let elems: Vec<_> = e1.iter().collect();
- assert_eq!([A], elems);
+ assert_eq!(elems, [A]);
e1.insert(C);
let elems: Vec<_> = e1.iter().collect();
- assert_eq!([A,C], elems);
+ assert_eq!(elems, [A,C]);
e1.insert(C);
let elems: Vec<_> = e1.iter().collect();
- assert_eq!([A,C], elems);
+ assert_eq!(elems, [A,C]);
e1.insert(B);
let elems: Vec<_> = e1.iter().collect();
- assert_eq!([A,B,C], elems);
+ assert_eq!(elems, [A,B,C]);
}
///////////////////////////////////////////////////////////////////////////
let e_union = e1 | e2;
let elems: Vec<_> = e_union.iter().collect();
- assert_eq!([A,B,C], elems);
+ assert_eq!(elems, [A,B,C]);
let e_intersection = e1 & e2;
let elems: Vec<_> = e_intersection.iter().collect();
- assert_eq!([C], elems);
+ assert_eq!(elems, [C]);
// Another way to express intersection
let e_intersection = e1 - (e1 - e2);
let elems: Vec<_> = e_intersection.iter().collect();
- assert_eq!([C], elems);
+ assert_eq!(elems, [C]);
let e_subtract = e1 - e2;
let elems: Vec<_> = e_subtract.iter().collect();
- assert_eq!([A], elems);
+ assert_eq!(elems, [A]);
// Bitwise XOR of two sets, aka symmetric difference
let e_symmetric_diff = e1 ^ e2;
let elems: Vec<_> = e_symmetric_diff.iter().collect();
- assert_eq!([A,B], elems);
+ assert_eq!(elems, [A,B]);
// Another way to express symmetric difference
let e_symmetric_diff = (e1 - e2) | (e2 - e1);
let elems: Vec<_> = e_symmetric_diff.iter().collect();
- assert_eq!([A,B], elems);
+ assert_eq!(elems, [A,B]);
// Yet another way to express symmetric difference
let e_symmetric_diff = (e1 | e2) - (e1 & e2);
let elems: Vec<_> = e_symmetric_diff.iter().collect();
- assert_eq!([A,B], elems);
+ assert_eq!(elems, [A,B]);
}
#[test]
#[test]
fn test_format() {
let s = fmt::format(format_args!("Hello, {}!", "world"));
- assert_eq!(s.as_slice(), "Hello, world!");
+ assert_eq!(s, "Hello, world!");
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(deprecated)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(core)]
#![feature(unicode)]
#![feature(unsafe_destructor)]
#![feature(into_cow)]
+#![feature(step_by)]
#![cfg_attr(test, feature(str_char))]
#[macro_use] extern crate log;
// Test on-heap from_elem.
v = vec![20; 6];
{
- let v = v.as_slice();
+ let v = &v[..];
assert_eq!(v[0], 20);
assert_eq!(v[1], 20);
assert_eq!(v[2], 20);
#[test]
fn test_slice_2() {
let v = vec![1, 2, 3, 4, 5];
- let v = v.slice(1, 3);
+ let v = &v[1..3];
assert_eq!(v.len(), 2);
assert_eq!(v[0], 2);
assert_eq!(v[1], 3);
fn test_into_bytes() {
let data = String::from_str("asdf");
let buf = data.into_bytes();
- assert_eq!(b"asdf", buf);
+ assert_eq!(buf, b"asdf");
}
#[test]
fn test_find_str() {
// byte positions
- assert_eq!("".find_str(""), Some(0));
- assert!("banana".find_str("apple pie").is_none());
+ assert_eq!("".find(""), Some(0));
+ assert!("banana".find("apple pie").is_none());
let data = "abcabc";
- assert_eq!(data[0..6].find_str("ab"), Some(0));
- assert_eq!(data[2..6].find_str("ab"), Some(3 - 2));
- assert!(data[2..4].find_str("ab").is_none());
+ assert_eq!(data[0..6].find("ab"), Some(0));
+ assert_eq!(data[2..6].find("ab"), Some(3 - 2));
+ assert!(data[2..4].find("ab").is_none());
let string = "ประเทศไทย中华Việt Nam";
let mut data = String::from_str(string);
data.push_str(string);
- assert!(data.find_str("ไท华").is_none());
- assert_eq!(data[0..43].find_str(""), Some(0));
- assert_eq!(data[6..43].find_str(""), Some(6 - 6));
+ assert!(data.find("ไท华").is_none());
+ assert_eq!(data[0..43].find(""), Some(0));
+ assert_eq!(data[6..43].find(""), Some(6 - 6));
- assert_eq!(data[0..43].find_str("ประ"), Some( 0));
- assert_eq!(data[0..43].find_str("ทศไ"), Some(12));
- assert_eq!(data[0..43].find_str("ย中"), Some(24));
- assert_eq!(data[0..43].find_str("iệt"), Some(34));
- assert_eq!(data[0..43].find_str("Nam"), Some(40));
+ assert_eq!(data[0..43].find("ประ"), Some( 0));
+ assert_eq!(data[0..43].find("ทศไ"), Some(12));
+ assert_eq!(data[0..43].find("ย中"), Some(24));
+ assert_eq!(data[0..43].find("iệt"), Some(34));
+ assert_eq!(data[0..43].find("Nam"), Some(40));
- assert_eq!(data[43..86].find_str("ประ"), Some(43 - 43));
- assert_eq!(data[43..86].find_str("ทศไ"), Some(55 - 43));
- assert_eq!(data[43..86].find_str("ย中"), Some(67 - 43));
- assert_eq!(data[43..86].find_str("iệt"), Some(77 - 43));
- assert_eq!(data[43..86].find_str("Nam"), Some(83 - 43));
+ assert_eq!(data[43..86].find("ประ"), Some(43 - 43));
+ assert_eq!(data[43..86].find("ทศไ"), Some(55 - 43));
+ assert_eq!(data[43..86].find("ย中"), Some(67 - 43));
+ assert_eq!(data[43..86].find("iệt"), Some(77 - 43));
+ assert_eq!(data[43..86].find("Nam"), Some(83 - 43));
}
#[test]
#[test]
fn test_slice() {
- assert_eq!("ab", "abc".slice(0, 2));
- assert_eq!("bc", "abc".slice(1, 3));
- assert_eq!("", "abc".slice(1, 1));
- assert_eq!("\u{65e5}", "\u{65e5}\u{672c}".slice(0, 3));
+ assert_eq!("ab", &"abc"[0..2]);
+ assert_eq!("bc", &"abc"[1..3]);
+ assert_eq!("", &"abc"[1..1]);
+ assert_eq!("\u{65e5}", &"\u{65e5}\u{672c}"[0..3]);
let data = "ประเทศไทย中华";
- assert_eq!("ป", data.slice(0, 3));
- assert_eq!("ร", data.slice(3, 6));
- assert_eq!("", data.slice(3, 3));
- assert_eq!("华", data.slice(30, 33));
+ assert_eq!("ป", &data[0..3]);
+ assert_eq!("ร", &data[3..6]);
+ assert_eq!("", &data[3..3]);
+ assert_eq!("华", &data[30..33]);
fn a_million_letter_x() -> String {
let mut i = 0;
}
let letters = a_million_letter_x();
assert!(half_a_million_letter_x() ==
- String::from_str(letters.slice(0, 3 * 500000)));
+ String::from_str(&letters[0..3 * 500000]));
}
#[test]
fn test_slice_2() {
let ss = "中华Việt Nam";
- assert_eq!("华", ss.slice(3, 6));
- assert_eq!("Việt Nam", ss.slice(6, 16));
+ assert_eq!("华", &ss[3..6]);
+ assert_eq!("Việt Nam", &ss[6..16]);
- assert_eq!("ab", "abc".slice(0, 2));
- assert_eq!("bc", "abc".slice(1, 3));
- assert_eq!("", "abc".slice(1, 1));
+ assert_eq!("ab", &"abc"[0..2]);
+ assert_eq!("bc", &"abc"[1..3]);
+ assert_eq!("", &"abc"[1..1]);
- assert_eq!("中", ss.slice(0, 3));
- assert_eq!("华V", ss.slice(3, 7));
- assert_eq!("", ss.slice(3, 3));
+ assert_eq!("中", &ss[0..3]);
+ assert_eq!("华V", &ss[3..7]);
+ assert_eq!("", &ss[3..3]);
/*0: 中
3: 华
6: V
#[test]
#[should_panic]
fn test_slice_fail() {
- "中华Việt Nam".slice(0, 2);
+ &"中华Việt Nam"[0..2];
}
#[test]
fn test_slice_from() {
- assert_eq!("abcd".slice_from(0), "abcd");
- assert_eq!("abcd".slice_from(2), "cd");
- assert_eq!("abcd".slice_from(4), "");
+ assert_eq!(&"abcd"[0..], "abcd");
+ assert_eq!(&"abcd"[2..], "cd");
+ assert_eq!(&"abcd"[4..], "");
}
#[test]
fn test_slice_to() {
- assert_eq!("abcd".slice_to(0), "");
- assert_eq!("abcd".slice_to(2), "ab");
- assert_eq!("abcd".slice_to(4), "abcd");
+ assert_eq!(&"abcd"[..0], "");
+ assert_eq!(&"abcd"[..2], "ab");
+ assert_eq!(&"abcd"[..4], "abcd");
}
#[test]
#[test]
fn test_contains_char() {
- assert!("abc".contains_char('b'));
- assert!("a".contains_char('a'));
- assert!(!"abc".contains_char('d'));
- assert!(!"".contains_char('a'));
+ assert!("abc".contains('b'));
+ assert!("a".contains('a'));
+ assert!(!"abc".contains('d'));
+ assert!(!"".contains('a'));
}
#[test]
}
#[test]
-fn test_split_strator() {
+fn test_splitator() {
fn t(s: &str, sep: &str, u: &[&str]) {
- let v: Vec<&str> = s.split_str(sep).collect();
+ let v: Vec<&str> = s.split(sep).collect();
assert_eq!(v, u);
}
t("--1233345--", "12345", &["--1233345--"]);
fn test_str_default() {
use std::default::Default;
- fn t<S: Default + Str>() {
+ fn t<S: Default + AsRef<str>>() {
let s: S = Default::default();
- assert_eq!(s.as_slice(), "");
+ assert_eq!(s.as_ref(), "");
}
t::<&str>();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::borrow::IntoCow;
+use std::borrow::{IntoCow, Cow};
use std::iter::repeat;
use std::str::Utf8Error;
-use std::string::{CowString, as_string};
+use std::string::as_string;
use test::Bencher;
#[test]
fn test_from_utf8_lossy() {
let xs = b"hello";
- let ys: CowString = "hello".into_cow();
+ let ys: Cow<str> = "hello".into_cow();
assert_eq!(String::from_utf8_lossy(xs), ys);
let xs = "ศไทย中华Việt Nam".as_bytes();
- let ys: CowString = "ศไทย中华Việt Nam".into_cow();
+ let ys: Cow<str> = "ศไทย中华Việt Nam".into_cow();
assert_eq!(String::from_utf8_lossy(xs), ys);
let xs = b"Hello\xC2 There\xFF Goodbye";
use self::Taggypar::*;
#[test]
-#[allow(deprecated)]
fn test_simple() {
let mut d = VecDeque::new();
assert_eq!(d.len(), 0);
let u: Vec<_> = deq.iter().cloned().collect();
assert_eq!(u, v);
- let seq = iter::count(0, 2).take(256);
+ let seq = (0..).step_by(2).take(256);
let deq: VecDeque<_> = seq.collect();
for (i, &x) in deq.iter().enumerate() {
assert_eq!(2*i, x);
let (left, right) = ring.as_slices();
let expected: Vec<_> = (0..i+1).collect();
- assert_eq!(left, expected);
+ assert_eq!(left, &expected[..]);
assert_eq!(right, []);
}
let (left, right) = ring.as_slices();
let expected_left: Vec<_> = (-last..j+1).rev().collect();
let expected_right: Vec<_> = (0..first).collect();
- assert_eq!(left, expected_left);
- assert_eq!(right, expected_right);
+ assert_eq!(left, &expected_left[..]);
+ assert_eq!(right, &expected_right[..]);
}
assert_eq!(ring.len() as i32, cap);
let (left, right) = ring.as_mut_slices();
let expected: Vec<_> = (0..i+1).collect();
- assert_eq!(left, expected);
+ assert_eq!(left, &expected[..]);
assert_eq!(right, []);
}
let (left, right) = ring.as_mut_slices();
let expected_left: Vec<_> = (-last..j+1).rev().collect();
let expected_right: Vec<_> = (0..first).collect();
- assert_eq!(left, expected_left);
- assert_eq!(right, expected_right);
+ assert_eq!(left, &expected_left[..]);
+ assert_eq!(right, &expected_right[..]);
}
assert_eq!(ring.len() as i32, cap);
#![stable(feature = "rust1", since = "1.0.0")]
+use fmt;
use marker::Send;
use mem::transmute;
use option::Option::{self, Some, None};
// Extension methods for Any trait objects.
///////////////////////////////////////////////////////////////////////////////
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Any {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.pad("Any")
+ }
+}
+
impl Any {
/// Returns true if the boxed type is the same as `T`
#[stable(feature = "rust1", since = "1.0.0")]
impl TypeId {
/// Returns the `TypeId` of the type this generic function has been
/// instantiated with
- #[unstable(feature = "core",
- reason = "may grow a `Reflect` bound soon via marker traits")]
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn of<T: ?Sized + Any>() -> TypeId {
TypeId {
t: unsafe { intrinsics::type_id::<T>() },
}
}
}
-
-#[unstable(feature = "core")]
-#[deprecated(since = "1.0.0",
- reason = "renamed to AtomicIsize")]
-#[allow(missing_docs)]
-pub struct AtomicInt {
- v: UnsafeCell<isize>,
-}
-
-#[allow(deprecated)]
-unsafe impl Sync for AtomicInt {}
-
-#[unstable(feature = "core")]
-#[deprecated(since = "1.0.0",
- reason = "renamed to AtomicUsize")]
-#[allow(missing_docs)]
-pub struct AtomicUint {
- v: UnsafeCell<usize>,
-}
-
-#[allow(deprecated)]
-unsafe impl Sync for AtomicUint {}
-
-#[unstable(feature = "core")]
-#[deprecated(since = "1.0.0",
- reason = "use ATOMIC_ISIZE_INIT instead")]
-#[allow(missing_docs, deprecated)]
-pub const ATOMIC_INT_INIT: AtomicInt =
- AtomicInt { v: UnsafeCell { value: 0 } };
-#[unstable(feature = "core")]
-#[deprecated(since = "1.0.0",
- reason = "use ATOMIC_USIZE_INIT instead")]
-#[allow(missing_docs, deprecated)]
-pub const ATOMIC_UINT_INIT: AtomicUint =
- AtomicUint { v: UnsafeCell { value: 0, } };
-
-#[allow(missing_docs, deprecated)]
-impl AtomicInt {
- #[inline]
- pub fn new(v: isize) -> AtomicInt {
- AtomicInt {v: UnsafeCell::new(v)}
- }
-
- #[inline]
- pub fn load(&self, order: Ordering) -> isize {
- unsafe { atomic_load(self.v.get(), order) }
- }
-
- #[inline]
- pub fn store(&self, val: isize, order: Ordering) {
- unsafe { atomic_store(self.v.get(), val, order); }
- }
-
- #[inline]
- pub fn swap(&self, val: isize, order: Ordering) -> isize {
- unsafe { atomic_swap(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn compare_and_swap(&self, old: isize, new: isize, order: Ordering) -> isize {
- unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) }
- }
-
- #[inline]
- pub fn fetch_add(&self, val: isize, order: Ordering) -> isize {
- unsafe { atomic_add(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn fetch_sub(&self, val: isize, order: Ordering) -> isize {
- unsafe { atomic_sub(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn fetch_and(&self, val: isize, order: Ordering) -> isize {
- unsafe { atomic_and(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn fetch_or(&self, val: isize, order: Ordering) -> isize {
- unsafe { atomic_or(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn fetch_xor(&self, val: isize, order: Ordering) -> isize {
- unsafe { atomic_xor(self.v.get(), val, order) }
- }
-}
-
-#[allow(missing_docs, deprecated)]
-impl AtomicUint {
- #[inline]
- pub fn new(v: usize) -> AtomicUint {
- AtomicUint { v: UnsafeCell::new(v) }
- }
-
- #[inline]
- pub fn load(&self, order: Ordering) -> usize {
- unsafe { atomic_load(self.v.get(), order) }
- }
-
- #[inline]
- pub fn store(&self, val: usize, order: Ordering) {
- unsafe { atomic_store(self.v.get(), val, order); }
- }
-
- #[inline]
- pub fn swap(&self, val: usize, order: Ordering) -> usize {
- unsafe { atomic_swap(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn compare_and_swap(&self, old: usize, new: usize, order: Ordering) -> usize {
- unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) }
- }
-
- #[inline]
- pub fn fetch_add(&self, val: usize, order: Ordering) -> usize {
- unsafe { atomic_add(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn fetch_sub(&self, val: usize, order: Ordering) -> usize {
- unsafe { atomic_sub(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn fetch_and(&self, val: usize, order: Ordering) -> usize {
- unsafe { atomic_and(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn fetch_or(&self, val: usize, order: Ordering) -> usize {
- unsafe { atomic_or(self.v.get(), val, order) }
- }
-
- #[inline]
- pub fn fetch_xor(&self, val: usize, order: Ordering) -> usize {
- unsafe { atomic_xor(self.v.get(), val, order) }
- }
-}
}
}
- /// Attempts to immutably borrow the wrapped value.
- ///
- /// The borrow lasts until the returned `Ref` exits scope. Multiple
- /// immutable borrows can be taken out at the same time.
- ///
- /// Returns `None` if the value is currently mutably borrowed.
- #[unstable(feature = "core", reason = "may be renamed or removed")]
- #[deprecated(since = "1.0.0",
- reason = "dispatch on `cell.borrow_state()` instead")]
- #[inline]
- pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
- match BorrowRef::new(&self.borrow) {
- Some(b) => Some(Ref { _value: unsafe { &*self.value.get() }, _borrow: b }),
- None => None,
- }
- }
-
/// Immutably borrows the wrapped value.
///
/// The borrow lasts until the returned `Ref` exits scope. Multiple
}
}
- /// Mutably borrows the wrapped value.
- ///
- /// The borrow lasts until the returned `RefMut` exits scope. The value
- /// cannot be borrowed while this borrow is active.
- ///
- /// Returns `None` if the value is currently borrowed.
- #[unstable(feature = "core", reason = "may be renamed or removed")]
- #[deprecated(since = "1.0.0",
- reason = "dispatch on `cell.borrow_state()` instead")]
- #[inline]
- pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
- match BorrowRefMut::new(&self.borrow) {
- Some(b) => Some(RefMut { _value: unsafe { &mut *self.value.get() }, _borrow: b }),
- None => None,
- }
- }
-
/// Mutably borrows the wrapped value.
///
/// The borrow lasts until the returned `RefMut` exits scope. The value
/// inverse of `ne`; that is, `!(a == b)` if and only if `a != b`.
#[lang="eq"]
#[stable(feature = "rust1", since = "1.0.0")]
-#[old_orphan_check]
pub trait PartialEq<Rhs: ?Sized = Self> {
/// This method tests for `self` and `other` values to be equal, and is used by `==`.
#[stable(feature = "rust1", since = "1.0.0")]
/// Compare and return the minimum of two values.
///
+/// Returns the first argument if the comparison determines them to be equal.
+///
/// # Examples
///
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn min<T: Ord>(v1: T, v2: T) -> T {
- if v1 < v2 { v1 } else { v2 }
+ if v1 <= v2 { v1 } else { v2 }
}
/// Compare and return the maximum of two values.
///
+/// Returns the second argument if the comparison determines them to be equal.
+///
/// # Examples
///
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn max<T: Ord>(v1: T, v2: T) -> T {
- if v1 > v2 { v1 } else { v2 }
+ if v2 >= v1 { v2 } else { v1 }
}
/// Compare and return the minimum of two values if there is one.
/// Compare and return the maximum of two values if there is one.
///
-/// Returns the first argument if the comparison determines them to be equal.
+/// Returns the second argument if the comparison determines them to be equal.
///
/// # Examples
///
#[unstable(feature = "core")]
pub fn partial_max<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
match v1.partial_cmp(&v2) {
- Some(Less) => Some(v2),
- Some(Equal) | Some(Greater) => Some(v1),
+ Some(Equal) | Some(Less) => Some(v2),
+ Some(Greater) => Some(v1),
None => None
}
}
#[macro_export]
macro_rules! __impl_slice_eq1 {
($Lhs: ty, $Rhs: ty) => {
+ __impl_slice_eq1! { $Lhs, $Rhs, Sized }
+ };
+ ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
#[stable(feature = "rust1", since = "1.0.0")]
- impl<'a, 'b, A, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
+ impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
#[inline]
fn eq(&self, other: &$Rhs) -> bool { &self[..] == &other[..] }
#[inline]
__impl_slice_eq2! { $Lhs, $Rhs, Sized }
};
($Lhs: ty, $Rhs: ty, $Bound: ident) => {
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
- #[inline]
- fn eq(&self, other: &$Rhs) -> bool { &self[..] == &other[..] }
- #[inline]
- fn ne(&self, other: &$Rhs) -> bool { &self[..] != &other[..] }
- }
+ __impl_slice_eq1!($Lhs, $Rhs, $Bound);
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b, A: $Bound, B> PartialEq<$Lhs> for $Rhs where B: PartialEq<A> {
//! conversions from one type to another. They follow the standard
//! Rust conventions of `as`/`to`/`into`/`from`.
-#![unstable(feature = "convert",
- reason = "recently added, experimental traits")]
+#![stable(feature = "rust1", since = "1.0.0")]
use marker::Sized;
/// A cheap, reference-to-reference conversion.
+#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRef<T: ?Sized> {
/// Perform the conversion.
+ #[stable(feature = "rust1", since = "1.0.0")]
fn as_ref(&self) -> &T;
}
/// A cheap, mutable reference-to-mutable reference conversion.
+#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsMut<T: ?Sized> {
/// Perform the conversion.
+ #[stable(feature = "rust1", since = "1.0.0")]
fn as_mut(&mut self) -> &mut T;
}
/// A conversion that consumes `self`, which may or may not be
/// expensive.
+#[stable(feature = "rust1", since = "1.0.0")]
pub trait Into<T>: Sized {
/// Perform the conversion.
+ #[stable(feature = "rust1", since = "1.0.0")]
fn into(self) -> T;
}
/// Construct `Self` via a conversion.
+#[stable(feature = "rust1", since = "1.0.0")]
pub trait From<T> {
/// Perform the conversion.
+ #[stable(feature = "rust1", since = "1.0.0")]
fn from(T) -> Self;
}
// GENERIC IMPLS
////////////////////////////////////////////////////////////////////////////////
-// As implies Into
-impl<'a, T: ?Sized, U: ?Sized> Into<&'a U> for &'a T where T: AsRef<U> {
- fn into(self) -> &'a U {
- self.as_ref()
- }
-}
-
// As lifts over &
+#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
fn as_ref(&self) -> &U {
<T as AsRef<U>>::as_ref(*self)
}
// As lifts over &mut
+#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
fn as_ref(&self) -> &U {
<T as AsRef<U>>::as_ref(*self)
// }
// }
-// AsMut implies Into
-impl<'a, T: ?Sized, U: ?Sized> Into<&'a mut U> for &'a mut T where T: AsMut<U> {
- fn into(self) -> &'a mut U {
- (*self).as_mut()
- }
-}
-
// AsMut lifts over &mut
+#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
fn as_mut(&mut self) -> &mut U {
(*self).as_mut()
// }
// From implies Into
+#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U> Into<U> for T where U: From<T> {
fn into(self) -> U {
U::from(self)
}
}
+// From (and thus Into) is reflexive
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> From<T> for T {
+ fn from(t: T) -> T { t }
+}
+
////////////////////////////////////////////////////////////////////////////////
// CONCRETE IMPLS
////////////////////////////////////////////////////////////////////////////////
+#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsRef<[T]> for [T] {
fn as_ref(&self) -> &[T] {
self
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsMut<[T]> for [T] {
fn as_mut(&mut self) -> &mut [T] {
self
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<str> for str {
fn as_ref(&self) -> &str {
self
//! high-level module to provide its own errors that do not commit to any
//! particular implementation, but also reveal some of its implementation for
//! debugging via `cause` chains.
-//!
-//! # The `FromError` trait
-//!
-//! `FromError` is a simple trait that expresses conversions between different
-//! error types. To provide maximum flexibility, it does not require either of
-//! the types to actually implement the `Error` trait, although this will be the
-//! common case.
-//!
-//! The main use of this trait is in the `try!` macro, which uses it to
-//! automatically convert a given error to the error specified in a function's
-//! return type.
-//!
-//! For example,
-//!
-//! ```
-//! #![feature(core)]
-//! use std::error::FromError;
-//! use std::{io, str};
-//! use std::fs::File;
-//!
-//! enum MyError {
-//! Io(io::Error),
-//! Utf8(str::Utf8Error),
-//! }
-//!
-//! impl FromError<io::Error> for MyError {
-//! fn from_error(err: io::Error) -> MyError { MyError::Io(err) }
-//! }
-//!
-//! impl FromError<str::Utf8Error> for MyError {
-//! fn from_error(err: str::Utf8Error) -> MyError { MyError::Utf8(err) }
-//! }
-//!
-//! #[allow(unused_variables)]
-//! fn open_and_map() -> Result<(), MyError> {
-//! let b = b"foo.txt";
-//! let s = try!(str::from_utf8(b));
-//! let f = try!(File::open(s));
-//!
-//! // do something interesting here...
-//! Ok(())
-//! }
-//! ```
#![stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
fn cause(&self) -> Option<&Error> { None }
}
-
-/// A trait for types that can be converted from a given error type `E`.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub trait FromError<E> {
- /// Perform the conversion.
- #[stable(feature = "rust1", since = "1.0.0")]
- fn from_error(err: E) -> Self;
-}
-
-// Any type is convertable from itself
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<E> FromError<E> for E {
- fn from_error(err: E) -> E {
- err
- }
-}
+++ /dev/null
-// Copyright 2013 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.
-
-//! The Finally trait provides a method, `finally` on
-//! stack closures that emulates Java-style try/finally blocks.
-//!
-//! Using the `finally` method is sometimes convenient, but the type rules
-//! prohibit any shared, mutable state between the "try" case and the
-//! "finally" case. For advanced cases, the `try_finally` function can
-//! also be used. See that function for more details.
-//!
-//! # Examples
-//!
-//! ```
-//! # #![feature(core)]
-//! # #![feature(unboxed_closures)]
-//!
-//! use std::finally::Finally;
-//!
-//! (|| {
-//! // ...
-//! }).finally(|| {
-//! // this code is always run
-//! })
-//! ```
-
-#![unstable(feature = "core")]
-#![deprecated(since = "1.0.0",
- reason = "It is unclear if this module is more robust than implementing \
- Drop on a custom type, and this module is being removed with no \
- replacement. Use a custom Drop implementation to regain existing \
- functionality.")]
-#![allow(deprecated)]
-
-use ops::{Drop, FnMut, FnOnce};
-
-/// A trait for executing a destructor unconditionally after a block of code,
-/// regardless of whether the blocked fails.
-pub trait Finally<T> {
- /// Executes this object, unconditionally running `dtor` after this block of
- /// code has run.
- fn finally<F>(&mut self, dtor: F) -> T where F: FnMut();
-}
-
-impl<T, F> Finally<T> for F where F: FnMut() -> T {
- fn finally<G>(&mut self, mut dtor: G) -> T where G: FnMut() {
- try_finally(&mut (), self, |_, f| (*f)(), |_| dtor())
- }
-}
-
-/// The most general form of the `finally` functions. The function
-/// `try_fn` will be invoked first; whether or not it panics, the
-/// function `finally_fn` will be invoked next. The two parameters
-/// `mutate` and `drop` are used to thread state through the two
-/// closures. `mutate` is used for any shared, mutable state that both
-/// closures require access to; `drop` is used for any state that the
-/// `try_fn` requires ownership of.
-///
-/// **WARNING:** While shared, mutable state between the try and finally
-/// function is often necessary, one must be very careful; the `try`
-/// function could have panicked at any point, so the values of the shared
-/// state may be inconsistent.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(core)]
-/// use std::finally::try_finally;
-///
-/// struct State<'a> { buffer: &'a mut [u8], len: usize }
-/// # let mut buf = [];
-/// let mut state = State { buffer: &mut buf, len: 0 };
-/// try_finally(
-/// &mut state, (),
-/// |state, ()| {
-/// // use state.buffer, state.len
-/// },
-/// |state| {
-/// // use state.buffer, state.len to cleanup
-/// })
-/// ```
-pub fn try_finally<T, U, R, F, G>(mutate: &mut T, drop: U, try_fn: F, finally_fn: G) -> R where
- F: FnOnce(&mut T, U) -> R,
- G: FnMut(&mut T),
-{
- let f = Finallyalizer {
- mutate: mutate,
- dtor: finally_fn,
- };
- try_fn(&mut *f.mutate, drop)
-}
-
-struct Finallyalizer<'a, A:'a, F> where F: FnMut(&mut A) {
- mutate: &'a mut A,
- dtor: F,
-}
-
-#[unsafe_destructor]
-impl<'a, A, F> Drop for Finallyalizer<'a, A, F> where F: FnMut(&mut A) {
- #[inline]
- fn drop(&mut self) {
- (self.dtor)(self.mutate);
- }
-}
#![stable(feature = "rust1", since = "1.0.0")]
-use any;
use cell::{Cell, RefCell, Ref, RefMut, BorrowState};
use char::CharExt;
use iter::Iterator;
tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> Debug for &'a (any::Any+'a) {
- fn fmt(&self, f: &mut Formatter) -> Result { f.pad("&Any") }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Debug> Debug for [T] {
fn fmt(&self, f: &mut Formatter) -> Result {
state
}
- /// Returns the computed hash.
- #[unstable(feature = "hash")]
- #[deprecated(since = "1.0.0", reason = "renamed to finish")]
- pub fn result(&self) -> u64 { self.finish() }
-
fn reset(&mut self) {
self.length = 0;
self.v0 = self.k0 ^ 0x736f6d6570736575;
/// Rust moves to non-zeroing dynamic drop (and thus removes the
/// embedded drop flags that are being established by this
/// intrinsic).
- #[cfg(not(stage0))]
pub fn init_dropped<T>() -> T;
/// Create a value initialized to zero.
//!
//! # The `Iterator` trait
//!
-//! This module defines Rust's core iteration trait. The `Iterator` trait has one
-//! unimplemented method, `next`. All other methods are derived through default
-//! methods to perform operations such as `zip`, `chain`, `enumerate`, and `fold`.
+//! This module defines Rust's core iteration trait. The `Iterator` trait has
+//! one unimplemented method, `next`. All other methods are derived through
+//! default methods to perform operations such as `zip`, `chain`, `enumerate`,
+//! and `fold`.
//!
//! The goal of this module is to unify iteration across all containers in Rust.
-//! An iterator can be considered as a state machine which is used to track which
-//! element will be yielded next.
+//! An iterator can be considered as a state machine which is used to track
+//! which element will be yielded next.
//!
-//! There are various extensions also defined in this module to assist with various
-//! types of iteration, such as the `DoubleEndedIterator` for iterating in reverse,
-//! the `FromIterator` trait for creating a container from an iterator, and much
-//! more.
+//! There are various extensions also defined in this module to assist with
+//! various types of iteration, such as the `DoubleEndedIterator` for iterating
+//! in reverse, the `FromIterator` trait for creating a container from an
+//! iterator, and much more.
//!
-//! ## Rust's `for` loop
+//! # Rust's `for` loop
//!
-//! The special syntax used by rust's `for` loop is based around the `Iterator`
-//! trait defined in this module. For loops can be viewed as a syntactical expansion
-//! into a `loop`, for example, the `for` loop in this example is essentially
-//! translated to the `loop` below.
+//! The special syntax used by rust's `for` loop is based around the
+//! `IntoIterator` trait defined in this module. `for` loops can be viewed as a
+//! syntactical expansion into a `loop`, for example, the `for` loop in this
+//! example is essentially translated to the `loop` below.
//!
//! ```
//! let values = vec![1, 2, 3];
//!
-//! // "Syntactical sugar" taking advantage of an iterator
-//! for &x in values.iter() {
+//! for x in values {
//! println!("{}", x);
//! }
//!
//! // Rough translation of the iteration without a `for` iterator.
-//! let mut it = values.iter();
+//! # let values = vec![1, 2, 3];
+//! let mut it = values.into_iter();
//! loop {
//! match it.next() {
-//! Some(&x) => {
-//! println!("{}", x);
-//! }
-//! None => { break }
+//! Some(x) => println!("{}", x),
+//! None => break,
//! }
//! }
//! ```
//!
-//! This `for` loop syntax can be applied to any iterator over any type.
+//! Because `Iterator`s implement `IntoIterator`, this `for` loop syntax can be applied to any
+//! iterator over any type.
#![stable(feature = "rust1", since = "1.0.0")]
use default::Default;
use marker;
use mem;
-use num::{Int, Zero, One, ToPrimitive};
-use ops::{Add, Sub, FnMut, RangeFrom};
-use option::Option;
-use option::Option::{Some, None};
+use num::{Int, Zero, One};
+use ops::{self, Add, Sub, FnMut, RangeFrom};
+use option::Option::{self, Some, None};
use marker::Sized;
use usize;
/// else.
#[lang="iterator"]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "`{Self}` is not an iterator; maybe try calling `.iter()` or a similar \
- method"]
+#[rustc_on_unimplemented = "`{Self}` is not an iterator; maybe try calling \
+ `.iter()` or a similar method"]
pub trait Iterator {
/// The type of the elements being iterated
#[stable(feature = "rust1", since = "1.0.0")]
type Item;
- /// Advance the iterator and return the next value. Return `None` when the end is reached.
+ /// Advance the iterator and return the next value. Return `None` when the
+ /// end is reached.
#[stable(feature = "rust1", since = "1.0.0")]
fn next(&mut self) -> Option<Self::Item>;
/// Returns a lower and upper bound on the remaining length of the iterator.
///
- /// An upper bound of `None` means either there is no known upper bound, or the upper bound
- /// does not fit within a `usize`.
+ /// An upper bound of `None` means either there is no known upper bound, or
+ /// the upper bound does not fit within a `usize`.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn size_hint(&self) -> (usize, Option<usize>) { (0, None) }
/// iterator plus the current index of iteration.
///
/// `enumerate` keeps its count as a `usize`. If you want to count by a
- /// different sized integer, the `zip` function provides similar functionality.
+ /// different sized integer, the `zip` function provides similar
+ /// functionality.
///
/// # Examples
///
/// # #![feature(core)]
/// let xs = [2, 3];
/// let ys = [0, 1, 0, 1, 2];
- /// let it = xs.iter().flat_map(|&x| std::iter::count(0, 1).take(x));
+ /// let it = xs.iter().flat_map(|&x| (0..).take(x));
/// // Check that `it` has the same elements as `ys`
/// for (i, x) in it.enumerate() {
/// assert_eq!(x, ys[i]);
/// # Examples
///
/// ```
- /// # #![feature(core)]
- /// let a = [1, 2, 3, 4, 5];
- /// let b: Vec<_> = a.iter().cloned().collect();
- /// assert_eq!(a, b);
+ /// let expected = [1, 2, 3, 4, 5];
+ /// let actual: Vec<_> = expected.iter().cloned().collect();
+ /// assert_eq!(actual, expected);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// assert_eq!(even, [2, 4]);
/// assert_eq!(odd, [1, 3]);
/// ```
- #[unstable(feature = "core",
- reason = "recently added as part of collections reform")]
+ #[stable(feature = "rust1", since = "1.0.0")]
fn partition<B, F>(self, mut f: F) -> (B, B) where
Self: Sized,
B: Default + Extend<Self::Item>,
true
}
- /// Tests whether any element of an iterator satisfies the specified predicate.
+ /// Tests whether any element of an iterator satisfies the specified
+ /// predicate.
///
/// Does not consume the iterator past the first found element.
///
/// let a = [1, 2, 3, 4, 5];
/// let mut it = a.iter();
/// assert!(it.any(|x| *x == 3));
- /// assert_eq!(it.as_slice(), [4, 5]);
+ /// assert_eq!(&it[..], [4, 5]);
///
/// ```
#[inline]
/// let a = [1, 2, 3, 4, 5];
/// let mut it = a.iter();
/// assert_eq!(it.find(|&x| *x == 3).unwrap(), &3);
- /// assert_eq!(it.as_slice(), [4, 5]);
+ /// assert_eq!(&it[..], [4, 5]);
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item> where
/// let a = [1, 2, 3, 4, 5];
/// let mut it = a.iter();
/// assert_eq!(it.position(|x| *x == 3).unwrap(), 2);
- /// assert_eq!(it.as_slice(), [4, 5]);
+ /// assert_eq!(&it[..], [4, 5]);
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn position<P>(&mut self, mut predicate: P) -> Option<usize> where
/// let a = [1, 2, 2, 4, 5];
/// let mut it = a.iter();
/// assert_eq!(it.rposition(|x| *x == 2).unwrap(), 2);
- /// assert_eq!(it.as_slice(), [1, 2]);
+ /// assert_eq!(&it[..], [1, 2]);
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
/// Consumes the entire iterator to return the maximum element.
///
+ /// Returns the rightmost element if the comparison determines two elements
+ /// to be equally maximum.
+ ///
/// # Examples
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn max(self) -> Option<Self::Item> where Self: Sized, Self::Item: Ord
{
- self.fold(None, |max, x| {
+ self.fold(None, |max, y| {
match max {
- None => Some(x),
- Some(y) => Some(cmp::max(x, y))
+ None => Some(y),
+ Some(x) => Some(cmp::max(x, y))
}
})
}
/// Consumes the entire iterator to return the minimum element.
///
+ /// Returns the leftmost element if the comparison determines two elements
+ /// to be equally minimum.
+ ///
/// # Examples
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn min(self) -> Option<Self::Item> where Self: Sized, Self::Item: Ord
{
- self.fold(None, |min, x| {
+ self.fold(None, |min, y| {
match min {
- None => Some(x),
- Some(y) => Some(cmp::min(x, y))
+ None => Some(y),
+ Some(x) => Some(cmp::min(x, y))
}
})
}
/// element in the iterator and all elements are equal.
///
/// On an iterator of length `n`, `min_max` does `1.5 * n` comparisons,
- /// and so is faster than calling `min` and `max` separately which does `2 * n` comparisons.
+ /// and so is faster than calling `min` and `max` separately which does `2 *
+ /// n` comparisons.
///
/// # Examples
///
Some(x) => {
match self.next() {
None => return OneElement(x),
- Some(y) => if x < y {(x, y)} else {(y,x)}
+ Some(y) => if x <= y {(x, y)} else {(y, x)}
}
}
};
loop {
- // `first` and `second` are the two next elements we want to look at.
- // We first compare `first` and `second` (#1). The smaller one is then compared to
- // current minimum (#2). The larger one is compared to current maximum (#3). This
- // way we do 3 comparisons for 2 elements.
+ // `first` and `second` are the two next elements we want to look
+ // at. We first compare `first` and `second` (#1). The smaller one
+ // is then compared to current minimum (#2). The larger one is
+ // compared to current maximum (#3). This way we do 3 comparisons
+ // for 2 elements.
let first = match self.next() {
None => break,
Some(x) => x
None => {
if first < min {
min = first;
- } else if first > max {
+ } else if first >= max {
max = first;
}
break;
}
Some(x) => x
};
- if first < second {
- if first < min {min = first;}
- if max < second {max = second;}
+ if first <= second {
+ if first < min { min = first }
+ if second >= max { max = second }
} else {
- if second < min {min = second;}
- if max < first {max = first;}
+ if second < min { min = second }
+ if first >= max { max = first }
}
}
/// Return the element that gives the maximum value from the
/// specified function.
///
+ /// Returns the rightmost element if the comparison determines two elements
+ /// to be equally maximum.
+ ///
/// # Examples
///
/// ```
Self: Sized,
F: FnMut(&Self::Item) -> B,
{
- self.fold(None, |max: Option<(Self::Item, B)>, x| {
- let x_val = f(&x);
+ self.fold(None, |max: Option<(Self::Item, B)>, y| {
+ let y_val = f(&y);
match max {
- None => Some((x, x_val)),
- Some((y, y_val)) => if x_val > y_val {
- Some((x, x_val))
- } else {
+ None => Some((y, y_val)),
+ Some((x, x_val)) => if y_val >= x_val {
Some((y, y_val))
+ } else {
+ Some((x, x_val))
}
}
}).map(|(x, _)| x)
/// Return the element that gives the minimum value from the
/// specified function.
///
+ /// Returns the leftmost element if the comparison determines two elements
+ /// to be equally minimum.
+ ///
/// # Examples
///
/// ```
Self: Sized,
F: FnMut(&Self::Item) -> B,
{
- self.fold(None, |min: Option<(Self::Item, B)>, x| {
- let x_val = f(&x);
+ self.fold(None, |min: Option<(Self::Item, B)>, y| {
+ let y_val = f(&y);
match min {
- None => Some((x, x_val)),
- Some((y, y_val)) => if x_val < y_val {
+ None => Some((y, y_val)),
+ Some((x, x_val)) => if x_val <= y_val {
Some((x, x_val))
} else {
Some((y, y_val))
/// # #![feature(core)]
/// let a = [(1, 2), (3, 4)];
/// let (left, right): (Vec<_>, Vec<_>) = a.iter().cloned().unzip();
- /// assert_eq!([1, 3], left);
- /// assert_eq!([2, 4], right);
+ /// assert_eq!(left, [1, 3]);
+ /// assert_eq!(right, [2, 4]);
/// ```
- #[unstable(feature = "core", reason = "recent addition")]
+ #[stable(feature = "rust1", since = "1.0.0")]
fn unzip<A, B, FromA, FromB>(self) -> (FromA, FromB) where
FromA: Default + Extend<A>,
FromB: Default + Extend<B>,
/// assert_eq!(colors_set.len(), 3);
/// ```
///
- /// `FromIterator` is more commonly used implicitly via the `Iterator::collect` method:
+ /// `FromIterator` is more commonly used implicitly via the
+ /// `Iterator::collect` method:
///
/// ```
/// use std::collections::HashSet;
}
/// Conversion into an `Iterator`
+///
+/// Implementing this trait allows you to use your type with Rust's `for` loop. See
+/// the [module level documentation](../index.html) for more details.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait IntoIterator {
/// The type of the elements being iterated
/// An object implementing random access indexing by `usize`
///
-/// A `RandomAccessIterator` should be either infinite or a `DoubleEndedIterator`.
-/// Calling `next()` or `next_back()` on a `RandomAccessIterator`
-/// reduces the indexable range accordingly. That is, `it.idx(1)` will become `it.idx(0)`
-/// after `it.next()` is called.
+/// A `RandomAccessIterator` should be either infinite or a
+/// `DoubleEndedIterator`. Calling `next()` or `next_back()` on a
+/// `RandomAccessIterator` reduces the indexable range accordingly. That is,
+/// `it.idx(1)` will become `it.idx(0)` after `it.next()` is called.
#[unstable(feature = "core",
- reason = "not widely used, may be better decomposed into Index and ExactSizeIterator")]
+ reason = "not widely used, may be better decomposed into Index \
+ and ExactSizeIterator")]
pub trait RandomAccessIterator: Iterator {
/// Return the number of indexable elements. At most `std::usize::MAX`
/// elements are indexable, even if the iterator represents a longer range.
F: FnMut(&I::Item),
{}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<I> ExactSizeIterator for Rev<I> where I: ExactSizeIterator + DoubleEndedIterator {}
+impl<I> ExactSizeIterator for Rev<I>
+ where I: ExactSizeIterator + DoubleEndedIterator {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<B, I: ExactSizeIterator, F> ExactSizeIterator for Map<I, F> where
F: FnMut(I::Item) -> B,
{}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<A, B> ExactSizeIterator for Zip<A, B> where A: ExactSizeIterator, B: ExactSizeIterator {}
+impl<A, B> ExactSizeIterator for Zip<A, B>
+ where A: ExactSizeIterator, B: ExactSizeIterator {}
/// An double-ended iterator with the direction inverted
#[derive(Clone)]
}
#[unstable(feature = "core", reason = "trait is experimental")]
-impl<I> RandomAccessIterator for Rev<I> where I: DoubleEndedIterator + RandomAccessIterator {
+impl<I> RandomAccessIterator for Rev<I>
+ where I: DoubleEndedIterator + RandomAccessIterator
+{
#[inline]
fn indexable(&self) -> usize { self.iter.indexable() }
#[inline]
///
/// ```
/// # #![feature(core)]
- /// use std::iter::{count, MultiplicativeIterator};
+ /// use std::iter::MultiplicativeIterator;
///
/// fn factorial(n: usize) -> usize {
- /// count(1, 1).take_while(|&i| i <= n).product()
+ /// (1..).take_while(|&i| i <= n).product()
/// }
/// assert!(factorial(0) == 1);
/// assert!(factorial(1) == 1);
impl_multiplicative! { f32, 1.0 }
impl_multiplicative! { f64, 1.0 }
-/// `MinMaxResult` is an enum returned by `min_max`. See `Iterator::min_max` for more detail.
+/// `MinMaxResult` is an enum returned by `min_max`. See `Iterator::min_max` for
+/// more detail.
#[derive(Clone, PartialEq, Debug)]
#[unstable(feature = "core",
reason = "unclear whether such a fine-grained result is widely useful")]
/// Iterator with one element, so the minimum and maximum are the same
OneElement(T),
- /// More than one element in the iterator, the first element is not larger than the second
+ /// More than one element in the iterator, the first element is not larger
+ /// than the second
MinMax(T, T)
}
impl<T: Clone> MinMaxResult<T> {
- /// `into_option` creates an `Option` of type `(T,T)`. The returned `Option` has variant
- /// `None` if and only if the `MinMaxResult` has variant `NoElements`. Otherwise variant
- /// `Some(x,y)` is returned where `x <= y`. If `MinMaxResult` has variant `OneElement(x)`,
- /// performing this operation will make one clone of `x`.
+ /// `into_option` creates an `Option` of type `(T,T)`. The returned `Option`
+ /// has variant `None` if and only if the `MinMaxResult` has variant
+ /// `NoElements`. Otherwise variant `Some(x,y)` is returned where `x <= y`.
+ /// If `MinMaxResult` has variant `OneElement(x)`, performing this operation
+ /// will make one clone of `x`.
///
/// # Examples
///
}
#[allow(deprecated)]
-impl<A: Step> ::ops::Range<A> {
+impl<A: Step> ops::Range<A> {
/// Creates an iterator with the same range, but stepping by the
/// given amount at each iteration.
///
}
}
-/// An infinite iterator starting at `start` and advancing by `step` with each
-/// iteration
-#[unstable(feature = "core",
- reason = "may be renamed or replaced by range notation adapters")]
-#[deprecated(since = "1.0.0-beta", reason = "use range notation and step_by")]
-pub type Counter<A> = StepBy<A, RangeFrom<A>>;
-
-/// Deprecated: use `(start..).step_by(step)` instead.
-#[inline]
-#[unstable(feature = "core",
- reason = "may be renamed or replaced by range notation adapters")]
-#[deprecated(since = "1.0.0-beta", reason = "use (start..).step_by(step) instead")]
-#[allow(deprecated)]
-pub fn count<A>(start: A, step: A) -> Counter<A> {
- StepBy {
- range: RangeFrom { start: start },
- step_by: step,
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<A> Iterator for StepBy<A, RangeFrom<A>> where
A: Clone,
}
}
-/// An iterator over the range [start, stop)
-#[allow(deprecated)]
-#[derive(Clone)]
-#[unstable(feature = "core",
- reason = "will be replaced by range notation")]
-#[deprecated(since = "1.0.0-beta", reason = "use range notation")]
-pub struct Range<A> {
- state: A,
- stop: A,
- one: A,
-}
-
-/// Deprecated: use `(start..stop)` instead.
-#[inline]
-#[unstable(feature = "core", reason = "will be replaced by range notation")]
-#[deprecated(since = "1.0.0-beta", reason = "use (start..stop) instead")]
-#[allow(deprecated)]
-pub fn range<A: Int>(start: A, stop: A) -> Range<A> {
- Range {
- state: start,
- stop: stop,
- one: Int::one(),
- }
-}
-
-// FIXME: #10414: Unfortunate type bound
-#[unstable(feature = "core",
- reason = "will be replaced by range notation")]
-#[deprecated(since = "1.0.0-beta", reason = "use range notation")]
-#[allow(deprecated)]
-impl<A: Int + ToPrimitive> Iterator for Range<A> {
- type Item = A;
-
- #[inline]
- fn next(&mut self) -> Option<A> {
- if self.state < self.stop {
- let result = self.state.clone();
- self.state = self.state + self.one;
- Some(result)
- } else {
- None
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- // This first checks if the elements are representable as i64. If they aren't, try u64 (to
- // handle cases like range(huge, huger)). We don't use usize/isize because the difference of
- // the i64/u64 might lie within their range.
- let bound = match self.state.to_i64() {
- Some(a) => {
- let sz = self.stop.to_i64().map(|b| b.checked_sub(a));
- match sz {
- Some(Some(bound)) => bound.to_usize(),
- _ => None,
- }
- },
- None => match self.state.to_u64() {
- Some(a) => {
- let sz = self.stop.to_u64().map(|b| b.checked_sub(a));
- match sz {
- Some(Some(bound)) => bound.to_usize(),
- _ => None
- }
- },
- None => None
- }
- };
-
- match bound {
- Some(b) => (b, Some(b)),
- // Standard fallback for unbounded/unrepresentable bounds
- None => (0, None)
- }
- }
-}
-
-/// `Int` is required to ensure the range will be the same regardless of
-/// the direction it is consumed.
-#[unstable(feature = "core",
- reason = "will be replaced by range notation")]
-#[deprecated(since = "1.0.0-beta", reason = "use range notation")]
-#[allow(deprecated)]
-impl<A: Int + ToPrimitive> DoubleEndedIterator for Range<A> {
- #[inline]
- fn next_back(&mut self) -> Option<A> {
- if self.stop > self.state {
- self.stop = self.stop - self.one;
- Some(self.stop.clone())
- } else {
- None
- }
- }
-}
-
/// An iterator over the range [start, stop]
#[derive(Clone)]
#[unstable(feature = "core",
reason = "likely to be replaced by range notation and adapters")]
-#[allow(deprecated)]
pub struct RangeInclusive<A> {
- range: Range<A>,
+ range: ops::Range<A>,
done: bool,
}
#[inline]
#[unstable(feature = "core",
reason = "likely to be replaced by range notation and adapters")]
-#[allow(deprecated)]
-pub fn range_inclusive<A: Int>(start: A, stop: A) -> RangeInclusive<A> {
+pub fn range_inclusive<A>(start: A, stop: A) -> RangeInclusive<A>
+ where A: Step + One + Clone
+{
RangeInclusive {
- range: range(start, stop),
+ range: start..stop,
done: false,
}
}
#[unstable(feature = "core",
reason = "likely to be replaced by range notation and adapters")]
-#[allow(deprecated)]
-impl<A: Int + ToPrimitive> Iterator for RangeInclusive<A> {
+impl<A: Step + One + Clone> Iterator for RangeInclusive<A> {
type Item = A;
#[inline]
match self.range.next() {
Some(x) => Some(x),
None => {
- if !self.done && self.range.state == self.range.stop {
+ if !self.done && self.range.start == self.range.end {
self.done = true;
- Some(self.range.stop.clone())
+ Some(self.range.end.clone())
} else {
None
}
#[unstable(feature = "core",
reason = "likely to be replaced by range notation and adapters")]
-#[allow(deprecated)]
-impl<A: Int + ToPrimitive> DoubleEndedIterator for RangeInclusive<A> {
+impl<A> DoubleEndedIterator for RangeInclusive<A>
+ where A: Step + One + Clone,
+ for<'a> &'a A: Sub<Output=A>
+{
#[inline]
fn next_back(&mut self) -> Option<A> {
- if self.range.stop > self.range.state {
- let result = self.range.stop.clone();
- self.range.stop = self.range.stop - self.range.one;
+ if self.range.end > self.range.start {
+ let result = self.range.end.clone();
+ self.range.end = &self.range.end - &A::one();
Some(result)
- } else if !self.done && self.range.state == self.range.stop {
+ } else if !self.done && self.range.start == self.range.end {
self.done = true;
- Some(self.range.stop.clone())
+ Some(self.range.end.clone())
} else {
None
}
}
}
-/// An iterator over the range [start, stop) by `step`. It handles overflow by stopping.
-#[unstable(feature = "core",
- reason = "likely to be replaced by range notation and adapters")]
-#[deprecated(since = "1.0.0-beta", reason = "use range notation and step_by")]
-pub type RangeStep<A> = StepBy<A, ::ops::Range<A>>;
-
-/// Deprecated: use `(start..stop).step_by(step)` instead.
-#[inline]
-#[unstable(feature = "core",
- reason = "likely to be replaced by range notation and adapters")]
-#[deprecated(since = "1.0.0-beta",
- reason = "use `(start..stop).step_by(step)` instead")]
-#[allow(deprecated)]
-pub fn range_step<A: Int>(start: A, stop: A, step: A) -> RangeStep<A> {
- StepBy {
- step_by: step,
- range: ::ops::Range { start: start, end: stop },
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
-impl<A: Step + Zero + Clone> Iterator for StepBy<A, ::ops::Range<A>> {
+impl<A: Step + Zero + Clone> Iterator for StepBy<A, ops::Range<A>> {
type Item = A;
#[inline]
macro_rules! range_exact_iter_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl ExactSizeIterator for ::ops::Range<$t> { }
+ impl ExactSizeIterator for ops::Range<$t> { }
)*)
}
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
-impl<A: Step + One + Clone> Iterator for ::ops::Range<A> {
+impl<A: Step + One + Clone> Iterator for ops::Range<A> {
type Item = A;
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
-impl<A: Step + One + Clone> DoubleEndedIterator for ::ops::Range<A> where
+impl<A: Step + One + Clone> DoubleEndedIterator for ops::Range<A> where
for<'a> &'a A: Sub<&'a A, Output = A>
{
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
-impl<A: Step + One> Iterator for ::ops::RangeFrom<A> {
+impl<A: Step + One> Iterator for ops::RangeFrom<A> {
type Item = A;
#[inline]
#![feature(unboxed_closures)]
#![feature(rustc_attrs)]
#![feature(optin_builtin_traits)]
+#![feature(fundamental)]
#![feature(concat_idents)]
#![feature(reflect)]
+#![feature(custom_attribute)]
#[macro_use]
mod macros;
pub mod cell;
pub mod char;
pub mod panicking;
-pub mod finally;
pub mod iter;
pub mod option;
pub mod raw;
);
}
-/// Asserts that two expressions are equal to each other, testing equality in
-/// both directions.
+/// Asserts that two expressions are equal to each other.
///
-/// On panic, this macro will print the values of the expressions.
+/// On panic, this macro will print the values of the expressions with their
+/// debug representations.
///
/// # Examples
///
($left:expr , $right:expr) => ({
match (&($left), &($right)) {
(left_val, right_val) => {
- // check both directions of equality....
- if !((*left_val == *right_val) &&
- (*right_val == *left_val)) {
- panic!("assertion failed: `(left == right) && (right == left)` \
+ if !(*left_val == *right_val) {
+ panic!("assertion failed: `(left == right)` \
(left: `{:?}`, right: `{:?}`)", *left_val, *right_val)
}
}
/// Short circuiting evaluation on Err
///
-/// `libstd` contains a more general `try!` macro that uses `FromError`.
+/// `libstd` contains a more general `try!` macro that uses `From<E>`.
#[macro_export]
macro_rules! try {
($e:expr) => ({
/// ```
/// # #![feature(core)]
/// fn divide_by_three(x: u32) -> u32 { // one of the poorest implementations of x/3
-/// for i in std::iter::count(0, 1) {
+/// for i in 0.. {
/// if 3*i < i { panic!("u32 overflow"); }
/// if x < 3*i { return i-1; }
/// }
#[stable(feature = "rust1", since = "1.0.0")]
#[lang="sized"]
#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"]
+#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
pub trait Sized : MarkerTrait {
// Empty.
}
#[stable(feature = "rust1", since = "1.0.0")]
pub trait PhantomFn<A:?Sized,R:?Sized=()> { }
-/// `PhantomData` is a way to tell the compiler about fake fields.
-/// Phantom data is required whenever type parameters are not used.
-/// The idea is that if the compiler encounters a `PhantomData<T>`
-/// instance, it will behave *as if* an instance of the type `T` were
-/// present for the purpose of various automatic analyses.
+/// `PhantomData<T>` allows you to describe that a type acts as if it stores a value of type `T`,
+/// even though it does not. This allows you to inform the compiler about certain safety properties
+/// of your code.
+///
+/// Though they both have scary names, `PhantomData<T>` and "phantom types" are unrelated. 👻👻👻
///
/// # Examples
///
/// When handling external resources over a foreign function interface, `PhantomData<T>` can
-/// prevent mismatches by enforcing types in the method implementations, although the struct
-/// doesn't actually contain values of the resource type.
+/// prevent mismatches by enforcing types in the method implementations:
///
/// ```
/// # trait ResType { fn foo(&self); };
/// commonly necessary if the structure is using an unsafe pointer
/// like `*mut T` whose referent may be dropped when the type is
/// dropped, as a `*mut T` is otherwise not treated as owned.
-///
-/// FIXME. Better documentation and examples of common patterns needed
-/// here! For now, please see [RFC 738][738] for more information.
-///
-/// [738]: https://github.com/rust-lang/rfcs/blob/master/text/0738-variance.md
#[lang="phantom_data"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct PhantomData<T:?Sized>;
unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {}
}
-/// Old-style marker trait. Deprecated.
-#[unstable(feature = "core", reason = "deprecated")]
-#[deprecated(since = "1.0.0", reason = "Replace with `PhantomData<&'a ()>`")]
-#[lang="contravariant_lifetime"]
-pub struct ContravariantLifetime<'a>;
-
-/// Old-style marker trait. Deprecated.
-#[unstable(feature = "core", reason = "deprecated")]
-#[deprecated(since = "1.0.0", reason = "Replace with `PhantomData<fn(&'a ())>`")]
-#[lang="covariant_lifetime"]
-pub struct CovariantLifetime<'a>;
-
-/// Old-style marker trait. Deprecated.
-#[unstable(feature = "core", reason = "deprecated")]
-#[deprecated(since = "1.0.0", reason = "Replace with `PhantomData<Cell<&'a ()>>`")]
-#[lang="invariant_lifetime"]
-pub struct InvariantLifetime<'a>;
-
-/// Old-style marker trait. Deprecated.
-#[unstable(feature = "core", reason = "deprecated")]
-#[deprecated(since = "1.0.0", reason = "Replace with `PhantomData<fn(T)>`")]
-#[lang="contravariant_type"]
-pub struct ContravariantType<T>;
-
-/// Old-style marker trait. Deprecated.
-#[unstable(feature = "core", reason = "deprecated")]
-#[deprecated(since = "1.0.0", reason = "Replace with `PhantomData<T>`")]
-#[lang="covariant_type"]
-pub struct CovariantType<T>;
-
-/// Old-style marker trait. Deprecated.
-#[unstable(feature = "core", reason = "deprecated")]
-#[deprecated(since = "1.0.0", reason = "Replace with `PhantomData<Cell<T>>`")]
-#[lang="invariant_type"]
-pub struct InvariantType<T>;
-
/// A marker trait indicates a type that can be reflected over. This
/// trait is implemented for all types. Its purpose is to ensure that
/// when you write a generic function that will employ reflection,
pub trait Reflect : MarkerTrait {
}
-#[cfg(stage0)]
-impl<T> Reflect for T { }
-
-#[cfg(not(stage0))]
impl Reflect for .. { }
#[inline]
#[unstable(feature = "filling_drop")]
pub unsafe fn dropped<T>() -> T {
- #[cfg(stage0)]
- #[inline(always)]
- unsafe fn dropped_impl<T>() -> T { zeroed() }
-
- #[cfg(not(stage0))]
#[inline(always)]
unsafe fn dropped_impl<T>() -> T { intrinsics::init_dropped() }
// But having the sign bit set is a pain, so 0x1d is probably better.
//
// And of course, 0x00 brings back the old world of zero'ing on drop.
-#[cfg(not(stage0))] #[unstable(feature = "filling_drop")]
+#[unstable(feature = "filling_drop")]
pub const POST_DROP_U8: u8 = 0x1d;
-#[cfg(not(stage0))] #[unstable(feature = "filling_drop")]
+#[unstable(feature = "filling_drop")]
pub const POST_DROP_U32: u32 = repeat_u8_as_u32!(POST_DROP_U8);
-#[cfg(not(stage0))] #[unstable(feature = "filling_drop")]
+#[unstable(feature = "filling_drop")]
pub const POST_DROP_U64: u64 = repeat_u8_as_u64!(POST_DROP_U8);
#[cfg(target_pointer_width = "32")]
-#[cfg(not(stage0))] #[unstable(feature = "filling_drop")]
+#[unstable(feature = "filling_drop")]
pub const POST_DROP_USIZE: usize = POST_DROP_U32 as usize;
#[cfg(target_pointer_width = "64")]
-#[cfg(not(stage0))] #[unstable(feature = "filling_drop")]
+#[unstable(feature = "filling_drop")]
pub const POST_DROP_USIZE: usize = POST_DROP_U64 as usize;
-#[cfg(stage0)] #[unstable(feature = "filling_drop")]
-pub const POST_DROP_U8: u8 = 0;
-#[cfg(stage0)] #[unstable(feature = "filling_drop")]
-pub const POST_DROP_U32: u32 = 0;
-#[cfg(stage0)] #[unstable(feature = "filling_drop")]
-pub const POST_DROP_U64: u64 = 0;
-#[cfg(stage0)] #[unstable(feature = "filling_drop")]
-pub const POST_DROP_USIZE: usize = 0;
-
-/// Interprets `src` as `&U`, and then reads `src` without moving the contained value.
-///
-/// This function will unsafely assume the pointer `src` is valid for `sizeof(U)` bytes by
-/// transmuting `&T` to `&U` and then reading the `&U`. It will also unsafely create a copy of the
-/// contained value instead of moving out of `src`.
-///
-/// It is not a compile-time error if `T` and `U` have different sizes, but it is highly encouraged
-/// to only invoke this function where `T` and `U` have the same size. This function triggers
-/// undefined behavior if `U` is larger than `T`.
+/// Interprets `src` as `&U`, and then reads `src` without moving the contained
+/// value.
+///
+/// This function will unsafely assume the pointer `src` is valid for
+/// `sizeof(U)` bytes by transmuting `&T` to `&U` and then reading the `&U`. It
+/// will also unsafely create a copy of the contained value instead of moving
+/// out of `src`.
+///
+/// It is not a compile-time error if `T` and `U` have different sizes, but it
+/// is highly encouraged to only invoke this function where `T` and `U` have the
+/// same size. This function triggers undefined behavior if `U` is larger than
+/// `T`.
///
/// # Examples
///
/// intended to have wrapping semantics.
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
-pub struct Wrapping<T>(pub T);
+pub struct Wrapping<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
#[unstable(feature = "core", reason = "may be removed or relocated")]
pub mod wrapping;
use intrinsics::{i32_mul_with_overflow, u32_mul_with_overflow};
use intrinsics::{i64_mul_with_overflow, u64_mul_with_overflow};
+use ::{i8,i16,i32,i64,u8,u16,u32,u64};
+
#[unstable(feature = "core", reason = "may be removed, renamed, or relocated")]
#[deprecated(since = "1.0.0", reason = "moved to inherent methods")]
pub trait WrappingOps {
fn overflowing_add(self, rhs: Self) -> (Self, bool);
fn overflowing_sub(self, rhs: Self) -> (Self, bool);
fn overflowing_mul(self, rhs: Self) -> (Self, bool);
+
+ fn overflowing_div(self, rhs: Self) -> (Self, bool);
+ fn overflowing_rem(self, rhs: Self) -> (Self, bool);
+
+ fn overflowing_shl(self, rhs: u32) -> (Self, bool);
+ fn overflowing_shr(self, rhs: u32) -> (Self, bool);
}
macro_rules! sh_impl {
wrapping_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
+mod shift_max {
+ #![allow(non_upper_case_globals)]
+
+ pub const i8: u32 = (1 << 3) - 1;
+ pub const i16: u32 = (1 << 4) - 1;
+ pub const i32: u32 = (1 << 5) - 1;
+ pub const i64: u32 = (1 << 6) - 1;
+
+ pub const u8: u32 = i8;
+ pub const u16: u32 = i16;
+ pub const u32: u32 = i32;
+ pub const u64: u32 = i64;
+}
+
macro_rules! overflowing_impl {
($($t:ident)*) => ($(
impl OverflowingOps for $t {
concat_idents!($t, _mul_with_overflow)(self, rhs)
}
}
+
+ #[inline(always)]
+ fn overflowing_div(self, rhs: $t) -> ($t, bool) {
+ if self == $t::MIN && rhs == -1 {
+ (1, true)
+ } else {
+ (self/rhs, false)
+ }
+ }
+ #[inline(always)]
+ fn overflowing_rem(self, rhs: $t) -> ($t, bool) {
+ if self == $t::MIN && rhs == -1 {
+ (0, true)
+ } else {
+ (self % rhs, false)
+ }
+ }
+
+ #[inline(always)]
+ fn overflowing_shl(self, rhs: u32) -> ($t, bool) {
+ (self << (rhs & self::shift_max::$t),
+ (rhs > self::shift_max::$t))
+ }
+ #[inline(always)]
+ fn overflowing_shr(self, rhs: u32) -> ($t, bool) {
+ (self >> (rhs & self::shift_max::$t),
+ (rhs > self::shift_max::$t))
+ }
}
)*)
}
(res.0 as usize, res.1)
}
}
+ #[inline(always)]
+ fn overflowing_div(self, rhs: usize) -> (usize, bool) {
+ let (r, f) = (self as u64).overflowing_div(rhs as u64);
+ (r as usize, f)
+ }
+ #[inline(always)]
+ fn overflowing_rem(self, rhs: usize) -> (usize, bool) {
+ let (r, f) = (self as u64).overflowing_rem(rhs as u64);
+ (r as usize, f)
+ }
+ #[inline(always)]
+ fn overflowing_shl(self, rhs: u32) -> (usize, bool) {
+ let (r, f) = (self as u64).overflowing_shl(rhs);
+ (r as usize, f)
+ }
+ #[inline(always)]
+ fn overflowing_shr(self, rhs: u32) -> (usize, bool) {
+ let (r, f) = (self as u64).overflowing_shr(rhs);
+ (r as usize, f)
+ }
}
#[cfg(target_pointer_width = "32")]
(res.0 as usize, res.1)
}
}
+ #[inline(always)]
+ fn overflowing_div(self, rhs: usize) -> (usize, bool) {
+ let (r, f) = (self as u32).overflowing_div(rhs as u32);
+ (r as usize, f)
+ }
+ #[inline(always)]
+ fn overflowing_rem(self, rhs: usize) -> (usize, bool) {
+ let (r, f) = (self as u32).overflowing_rem(rhs as u32);
+ (r as usize, f)
+ }
+ #[inline(always)]
+ fn overflowing_shl(self, rhs: u32) -> (usize, bool) {
+ let (r, f) = (self as u32).overflowing_shl(rhs);
+ (r as usize, f)
+ }
+ #[inline(always)]
+ fn overflowing_shr(self, rhs: u32) -> (usize, bool) {
+ let (r, f) = (self as u32).overflowing_shr(rhs);
+ (r as usize, f)
+ }
}
#[cfg(target_pointer_width = "64")]
(res.0 as isize, res.1)
}
}
+ #[inline(always)]
+ fn overflowing_div(self, rhs: isize) -> (isize, bool) {
+ let (r, f) = (self as i64).overflowing_div(rhs as i64);
+ (r as isize, f)
+ }
+ #[inline(always)]
+ fn overflowing_rem(self, rhs: isize) -> (isize, bool) {
+ let (r, f) = (self as i64).overflowing_rem(rhs as i64);
+ (r as isize, f)
+ }
+ #[inline(always)]
+ fn overflowing_shl(self, rhs: u32) -> (isize, bool) {
+ let (r, f) = (self as i64).overflowing_shl(rhs);
+ (r as isize, f)
+ }
+ #[inline(always)]
+ fn overflowing_shr(self, rhs: u32) -> (isize, bool) {
+ let (r, f) = (self as i64).overflowing_shr(rhs);
+ (r as isize, f)
+ }
}
#[cfg(target_pointer_width = "32")]
(res.0 as isize, res.1)
}
}
+ #[inline(always)]
+ fn overflowing_div(self, rhs: isize) -> (isize, bool) {
+ let (r, f) = (self as i32).overflowing_div(rhs as i32);
+ (r as isize, f)
+ }
+ #[inline(always)]
+ fn overflowing_rem(self, rhs: isize) -> (isize, bool) {
+ let (r, f) = (self as i32).overflowing_rem(rhs as i32);
+ (r as isize, f)
+ }
+ #[inline(always)]
+ fn overflowing_shl(self, rhs: u32) -> (isize, bool) {
+ let (r, f) = (self as i32).overflowing_shl(rhs);
+ (r as isize, f)
+ }
+ #[inline(always)]
+ fn overflowing_shr(self, rhs: u32) -> (isize, bool) {
+ let (r, f) = (self as i32).overflowing_shr(rhs);
+ (r as isize, f)
+ }
}
#[lang="fn"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_paren_sugar]
+#[fundamental] // so that regex can rely that `&str: !FnMut`
pub trait Fn<Args> : FnMut<Args> {
/// This is called when the call operator is used.
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
#[lang="fn_mut"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_paren_sugar]
+#[fundamental] // so that regex can rely that `&str: !FnMut`
pub trait FnMut<Args> : FnOnce<Args> {
/// This is called when the call operator is used.
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
#[lang="fn_once"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_paren_sugar]
+#[fundamental] // so that regex can rely that `&str: !FnMut`
pub trait FnOnce<Args> {
/// The returned type after the call operator is used.
type Output;
/// This is called when the call operator is used.
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
+
+#[cfg(not(stage0))]
+mod impls {
+ use marker::Sized;
+ use super::{Fn, FnMut, FnOnce};
+
+ impl<'a,A,F:?Sized> Fn<A> for &'a F
+ where F : Fn<A>
+ {
+ extern "rust-call" fn call(&self, args: A) -> F::Output {
+ (**self).call(args)
+ }
+ }
+
+ impl<'a,A,F:?Sized> FnMut<A> for &'a F
+ where F : Fn<A>
+ {
+ extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
+ (**self).call(args)
+ }
+ }
+
+ impl<'a,A,F:?Sized> FnOnce<A> for &'a F
+ where F : Fn<A>
+ {
+ type Output = F::Output;
+
+ extern "rust-call" fn call_once(self, args: A) -> F::Output {
+ (*self).call(args)
+ }
+ }
+
+ impl<'a,A,F:?Sized> FnMut<A> for &'a mut F
+ where F : FnMut<A>
+ {
+ extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
+ (*self).call_mut(args)
+ }
+ }
+
+ impl<'a,A,F:?Sized> FnOnce<A> for &'a mut F
+ where F : FnMut<A>
+ {
+ type Output = F::Output;
+ extern "rust-call" fn call_once(mut self, args: A) -> F::Output {
+ (*self).call_mut(args)
+ }
+ }
+}
use ops::FnOnce;
use result::Result::{Ok, Err};
use result::Result;
-#[allow(deprecated)]
-use slice::AsSlice;
use slice;
// Note that this is not a lang item per se, but it has a hidden dependency on
// Trait implementations
/////////////////////////////////////////////////////////////////////////////
-#[unstable(feature = "core",
- reason = "waiting on the stability of the trait itself")]
-#[deprecated(since = "1.0.0",
- reason = "use the inherent method instead")]
-#[allow(deprecated)]
-impl<T> AsSlice<T> for Option<T> {
- /// Convert from `Option<T>` to `&[T]` (without copying)
- #[inline]
- fn as_slice<'a>(&'a self) -> &'a [T] {
- match *self {
- Some(ref x) => slice::ref_slice(x),
- None => {
- let result: &[_] = &[];
- result
- }
- }
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Default for Option<T> {
#[inline]
pub use clone::Clone;
pub use cmp::{PartialEq, PartialOrd, Eq, Ord};
pub use convert::{AsRef, AsMut, Into, From};
-pub use iter::Extend;
-pub use iter::{Iterator, DoubleEndedIterator};
-pub use iter::{ExactSizeIterator};
+pub use iter::{Iterator, DoubleEndedIterator, Extend, ExactSizeIterator};
pub use option::Option::{self, Some, None};
pub use result::Result::{self, Ok, Err};
-pub use slice::{AsSlice, SliceExt};
-pub use str::{Str, StrExt};
+pub use slice::SliceExt;
+pub use str::StrExt;
+
+#[allow(deprecated)] pub use slice::AsSlice;
+#[allow(deprecated)] pub use str::Str;
#[stable(feature = "rust1", since = "1.0.0")]
pub fn null_mut<T>() -> *mut T { 0 as *mut T }
-/// Zeroes out `count * size_of::<T>` bytes of memory at `dst`. `count` may be
-/// `0`.
-///
-/// # Safety
-///
-/// Beyond accepting a raw pointer, this is unsafe because it will not drop the
-/// contents of `dst`, and may be used to create invalid instances of `T`.
-#[inline]
-#[unstable(feature = "core",
- reason = "may play a larger role in std::ptr future extensions")]
-#[deprecated(since = "1.0.0", reason = "use `write_bytes` instead")]
-pub unsafe fn zero_memory<T>(dst: *mut T, count: usize) {
- write_bytes(dst, 0, count);
-}
-
/// Swaps the values at two mutable locations of the same type, without
/// deinitialising either. They may overlap, unlike `mem::swap` which is
/// otherwise equivalent.
impl<T> Copy for Slice<T> {}
-/// The representation of an old closure.
-#[repr(C)]
-#[derive(Copy)]
-#[unstable(feature = "core")]
-#[deprecated(reason = "unboxed new closures do not have a universal representation; \
- `&Fn` (etc) trait objects should use `TraitObject` instead",
- since= "1.0.0")]
-#[allow(deprecated) /* for deriving Copy impl */]
-pub struct Closure {
- pub code: *mut (),
- pub env: *mut (),
-}
-
/// The representation of a trait object like `&SomeTrait`.
///
/// This struct has the same layout as types like `&SomeTrait` and
fn len(&self) -> usize;
fn is_empty(&self) -> bool { self.len() == 0 }
fn get_mut<'a>(&'a mut self, index: usize) -> Option<&'a mut Self::Item>;
- #[unstable(feature = "core",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")]
- fn as_mut_slice<'a>(&'a mut self) -> &'a mut [Self::Item];
fn iter_mut<'a>(&'a mut self) -> IterMut<'a, Self::Item>;
fn first_mut<'a>(&'a mut self) -> Option<&'a mut Self::Item>;
fn tail_mut<'a>(&'a mut self) -> &'a mut [Self::Item];
if index < self.len() { Some(&mut self[index]) } else { None }
}
- #[inline]
- #[unstable(feature = "core",
- reason = "will be replaced by slice syntax")]
- #[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")]
- fn as_mut_slice(&mut self) -> &mut [T] { self }
-
#[inline]
fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
unsafe {
transmute(RawSlice { data: p, len: len })
}
-/// Forms a slice from a pointer and a length.
-///
-/// The pointer given is actually a reference to the base of the slice. This
-/// reference is used to give a concrete lifetime to tie the returned slice to.
-/// Typically this should indicate that the slice is valid for as long as the
-/// pointer itself is valid.
-///
-/// The `len` argument is the number of **elements**, not the number of bytes.
-///
-/// This function is unsafe as there is no guarantee that the given pointer is
-/// valid for `len` elements, nor whether the lifetime provided is a suitable
-/// lifetime for the returned slice.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core)]
-/// use std::slice;
-///
-/// // manifest a slice out of thin air!
-/// let ptr = 0x1234 as *const usize;
-/// let amt = 10;
-/// unsafe {
-/// let slice = slice::from_raw_buf(&ptr, amt);
-/// }
-/// ```
-#[inline]
-#[unstable(feature = "core")]
-#[deprecated(since = "1.0.0",
- reason = "use from_raw_parts")]
-pub unsafe fn from_raw_buf<'a, T>(p: &'a *const T, len: usize) -> &'a [T] {
- transmute(RawSlice { data: *p, len: len })
-}
-
-/// Performs the same functionality as `from_raw_buf`, except that a mutable
-/// slice is returned.
-///
-/// This function is unsafe for the same reasons as `from_raw_buf`, as well as
-/// not being able to provide a non-aliasing guarantee of the returned mutable
-/// slice.
-#[inline]
-#[unstable(feature = "core")]
-#[deprecated(since = "1.0.0",
- reason = "use from_raw_parts_mut")]
-pub unsafe fn from_raw_mut_buf<'a, T>(p: &'a *mut T, len: usize) -> &'a mut [T] {
- transmute(RawSlice { data: *p, len: len })
-}
-
//
// Submodules
//
use iter::{Map, Iterator, DoubleEndedIterator};
use marker::Sized;
use mem;
-#[allow(deprecated)]
-use num::Int;
use ops::{Fn, FnMut, FnOnce};
use option::Option::{self, None, Some};
use raw::{Repr, Slice};
mem::transmute(v)
}
-/// Constructs a static string slice from a given raw pointer.
-///
-/// This function will read memory starting at `s` until it finds a 0, and then
-/// transmute the memory up to that point as a string slice, returning the
-/// corresponding `&'static str` value.
-///
-/// This function is unsafe because the caller must ensure the C string itself
-/// has the static lifetime and that the memory `s` is valid up to and including
-/// the first null byte.
-///
-/// # Panics
-///
-/// This function will panic if the string pointed to by `s` is not valid UTF-8.
-#[unstable(feature = "core")]
-#[deprecated(since = "1.0.0",
- reason = "use std::ffi::c_str_to_bytes + str::from_utf8")]
-pub unsafe fn from_c_str(s: *const i8) -> &'static str {
- let s = s as *const u8;
- let mut len: usize = 0;
- while *s.offset(len as isize) != 0 {
- len += 1;
- }
- let v: &'static [u8] = ::mem::transmute(Slice { data: s, len: len });
- from_utf8(v).ok().expect("from_c_str passed invalid utf-8 data")
-}
-
-/// Something that can be used to compare against a character
-#[unstable(feature = "core")]
-#[deprecated(since = "1.0.0",
- reason = "use `Pattern` instead")]
-// NB: Rather than removing it, make it private and move it into self::pattern
-pub trait CharEq {
- /// Determine if the splitter should split at the given character
- fn matches(&mut self, char) -> bool;
- /// Indicate if this is only concerned about ASCII characters,
- /// which can allow for a faster implementation.
- fn only_ascii(&self) -> bool;
-}
-
-#[allow(deprecated) /* for CharEq */ ]
-impl CharEq for char {
- #[inline]
- fn matches(&mut self, c: char) -> bool { *self == c }
-
- #[inline]
- fn only_ascii(&self) -> bool { (*self as u32) < 128 }
-}
-
-#[allow(deprecated) /* for CharEq */ ]
-impl<F> CharEq for F where F: FnMut(char) -> bool {
- #[inline]
- fn matches(&mut self, c: char) -> bool { (*self)(c) }
-
- #[inline]
- fn only_ascii(&self) -> bool { false }
-}
-
-#[allow(deprecated) /* for CharEq */ ]
-impl<'a> CharEq for &'a [char] {
- #[inline]
- #[allow(deprecated) /* for CharEq */ ]
- fn matches(&mut self, c: char) -> bool {
- self.iter().any(|&m| { let mut m = m; m.matches(c) })
- }
-
- #[inline]
- #[allow(deprecated) /* for CharEq */ ]
- fn only_ascii(&self) -> bool {
- self.iter().all(|m| m.only_ascii())
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl Error for Utf8Error {
fn description(&self) -> &str {
}
}
-/// An iterator over the substrings of a string separated by a given
-/// search string
-#[unstable(feature = "core")]
-#[deprecated(since = "1.0.0", reason = "use `Split` with a `&str`")]
-pub struct SplitStr<'a, P: Pattern<'a>>(Split<'a, P>);
-#[allow(deprecated)]
-impl<'a, P: Pattern<'a>> Iterator for SplitStr<'a, P> {
- type Item = &'a str;
-
- #[inline]
- #[allow(deprecated)]
- fn next(&mut self) -> Option<&'a str> {
- Iterator::next(&mut self.0)
- }
-}
-
impl<'a, 'b> OldMatchIndices<'a, 'b> {
#[inline]
#[allow(dead_code)]
fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
where P::Searcher: ReverseSearcher<'a>;
fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P>;
- #[allow(deprecated) /* for SplitStr */]
- fn split_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitStr<'a, P>;
fn lines<'a>(&'a self) -> Lines<'a>;
fn lines_any<'a>(&'a self) -> LinesAny<'a>;
fn char_len(&self) -> usize;
MatchIndices(pat.into_searcher(self))
}
- #[inline]
- #[allow(deprecated) /* for SplitStr */ ]
- fn split_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitStr<'a, P> {
- SplitStr(self.split(pat))
- }
-
#[inline]
fn lines(&self) -> Lines {
Lines { inner: self.split_terminator('\n').0 }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(deprecated) /* for CharEq */ ]
-
use prelude::*;
-use super::CharEq;
// Pattern
// Impl for a CharEq wrapper
+#[doc(hidden)]
+trait CharEq {
+ fn matches(&mut self, char) -> bool;
+ fn only_ascii(&self) -> bool;
+}
+
+impl CharEq for char {
+ #[inline]
+ fn matches(&mut self, c: char) -> bool { *self == c }
+
+ #[inline]
+ fn only_ascii(&self) -> bool { (*self as u32) < 128 }
+}
+
+impl<F> CharEq for F where F: FnMut(char) -> bool {
+ #[inline]
+ fn matches(&mut self, c: char) -> bool { (*self)(c) }
+
+ #[inline]
+ fn only_ascii(&self) -> bool { false }
+}
+
+impl<'a> CharEq for &'a [char] {
+ #[inline]
+ fn matches(&mut self, c: char) -> bool {
+ self.iter().any(|&m| { let mut m = m; m.matches(c) })
+ }
+
+ #[inline]
+ fn only_ascii(&self) -> bool {
+ self.iter().all(|m| m.only_ascii())
+ }
+}
+
struct CharEqPattern<C: CharEq>(C);
struct CharEqSearcher<'a, C: CharEq> {
}
}
-macro_rules! associated_items {
- ($t:ty, $s:ident, $e:expr) => {
- // FIXME: #22463
- //type Searcher = $t;
-
- fn into_searcher(self, haystack: &'a str) -> $t {
- let $s = self;
- $e.into_searcher(haystack)
+macro_rules! char_eq_pattern_impl {
+ ($wrapper:ty, $wrapper_ident:ident) => {
+ fn into_searcher(self, haystack: &'a str) -> $wrapper {
+ $wrapper_ident(CharEqPattern(self).into_searcher(haystack))
}
-
#[inline]
fn is_contained_in(self, haystack: &'a str) -> bool {
- let $s = self;
- $e.is_contained_in(haystack)
+ CharEqPattern(self).is_contained_in(haystack)
}
-
#[inline]
fn is_prefix_of(self, haystack: &'a str) -> bool {
- let $s = self;
- $e.is_prefix_of(haystack)
+ CharEqPattern(self).is_prefix_of(haystack)
}
-
- // FIXME: #21750
- /*#[inline]
+ #[inline]
fn is_suffix_of(self, haystack: &'a str) -> bool
- where $t: ReverseSearcher<'a>
+ where $wrapper: ReverseSearcher<'a>
{
- let $s = self;
- $e.is_suffix_of(haystack)
- }*/
+ CharEqPattern(self).is_suffix_of(haystack)
+ }
}
}
-// CharEq delegation impls
+// Pattern for char
-/// Searches for chars that are equal to a given char
impl<'a> Pattern<'a> for char {
- type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
- associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
- s, CharEqPattern(s));
+ type Searcher = CharSearcher<'a>;
+ char_eq_pattern_impl!(CharSearcher<'a>, CharSearcher);
+}
+
+pub struct CharSearcher<'a>(CharEqSearcher<'a, char>);
+
+unsafe impl<'a> Searcher<'a> for CharSearcher<'a> {
+ #[inline]
+ fn haystack(&self) -> &'a str { self.0.haystack() }
+ #[inline]
+ fn next(&mut self) -> SearchStep { self.0.next() }
+}
+unsafe impl<'a> ReverseSearcher<'a> for CharSearcher<'a> {
+ #[inline]
+ fn next_back(&mut self) -> SearchStep { self.0.next_back() }
}
+impl<'a> DoubleEndedSearcher<'a> for CharSearcher<'a> {}
+
+// Pattern for &[char]
-/// Searches for chars that are equal to any of the chars in the array
impl<'a, 'b> Pattern<'a> for &'b [char] {
- type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
- associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
- s, CharEqPattern(s));
+ type Searcher = CharSliceSearcher<'a, 'b>;
+ char_eq_pattern_impl!(CharSliceSearcher<'a, 'b>, CharSliceSearcher);
}
-/// A convenience impl that delegates to the impl for `&str`
-impl<'a, 'b> Pattern<'a> for &'b &'b str {
- type Searcher = <&'b str as Pattern<'a>>::Searcher;
- associated_items!(<&'b str as Pattern<'a>>::Searcher,
- s, (*s));
+pub struct CharSliceSearcher<'a, 'b>(CharEqSearcher<'a, &'b [char]>);
+
+unsafe impl<'a, 'b> Searcher<'a> for CharSliceSearcher<'a, 'b> {
+ #[inline]
+ fn haystack(&self) -> &'a str { self.0.haystack() }
+ #[inline]
+ fn next(&mut self) -> SearchStep { self.0.next() }
+}
+unsafe impl<'a, 'b> ReverseSearcher<'a> for CharSliceSearcher<'a, 'b> {
+ #[inline]
+ fn next_back(&mut self) -> SearchStep { self.0.next_back() }
+}
+impl<'a, 'b> DoubleEndedSearcher<'a> for CharSliceSearcher<'a, 'b> {}
+
+// Pattern for predicates
+
+impl<'a, F: FnMut(char) -> bool> Pattern<'a> for F {
+ type Searcher = CharPredSearcher<'a, F>;
+ char_eq_pattern_impl!(CharPredSearcher<'a, F>, CharPredSearcher);
+}
+
+pub struct CharPredSearcher<'a, F: FnMut(char) -> bool>(CharEqSearcher<'a, F>);
+
+unsafe impl<'a, F> Searcher<'a> for CharPredSearcher<'a, F>
+ where F: FnMut(char) -> bool
+{
+ #[inline]
+ fn haystack(&self) -> &'a str { self.0.haystack() }
+ #[inline]
+ fn next(&mut self) -> SearchStep { self.0.next() }
+}
+unsafe impl<'a, F> ReverseSearcher<'a> for CharPredSearcher<'a, F>
+ where F: FnMut(char) -> bool
+{
+ #[inline]
+ fn next_back(&mut self) -> SearchStep { self.0.next_back() }
}
+impl<'a, F> DoubleEndedSearcher<'a> for CharPredSearcher<'a, F>
+ where F: FnMut(char) -> bool
+{}
-/// Searches for chars that match the given predicate
-impl<'a, F> Pattern<'a> for F where F: FnMut(char) -> bool {
- type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
- associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
- s, CharEqPattern(s));
+// Pattern for &&str
+
+impl<'a, 'b> Pattern<'a> for &'b &'b str {
+ type Searcher = <&'b str as Pattern<'a>>::Searcher;
+ #[inline]
+ fn into_searcher(self, haystack: &'a str)
+ -> <&'b str as Pattern<'a>>::Searcher {
+ (*self).into_searcher(haystack)
+ }
+ #[inline]
+ fn is_contained_in(self, haystack: &'a str) -> bool {
+ (*self).is_contained_in(haystack)
+ }
+ #[inline]
+ fn is_prefix_of(self, haystack: &'a str) -> bool {
+ (*self).is_prefix_of(haystack)
+ }
+ #[inline]
+ fn is_suffix_of(self, haystack: &'a str) -> bool {
+ (*self).is_suffix_of(haystack)
+ }
}
fn no_mut_then_imm_borrow() {
let x = RefCell::new(0);
let _b1 = x.borrow_mut();
- assert!(x.try_borrow().is_none());
assert_eq!(x.borrow_state(), BorrowState::Writing);
}
fn no_imm_then_borrow_mut() {
let x = RefCell::new(0);
let _b1 = x.borrow();
- assert!(x.try_borrow_mut().is_none());
assert_eq!(x.borrow_state(), BorrowState::Reading);
}
let x = RefCell::new(0);
assert_eq!(x.borrow_state(), BorrowState::Unused);
let _b1 = x.borrow_mut();
- assert!(x.try_borrow_mut().is_none());
assert_eq!(x.borrow_state(), BorrowState::Writing);
}
{
let _b2 = x.borrow();
}
- assert!(x.try_borrow_mut().is_none());
+ assert_eq!(x.borrow_state(), BorrowState::Reading);
}
#[test]
let x = RefCell::new(0);
{
let b1 = x.borrow();
- assert!(x.try_borrow_mut().is_none());
+ assert_eq!(x.borrow_state(), BorrowState::Reading);
{
let _b2 = clone_ref(&b1);
- assert!(x.try_borrow_mut().is_none());
+ assert_eq!(x.borrow_state(), BorrowState::Reading);
}
- assert!(x.try_borrow_mut().is_none());
+ assert_eq!(x.borrow_state(), BorrowState::Reading);
}
- assert!(x.try_borrow_mut().is_some());
+ assert_eq!(x.borrow_state(), BorrowState::Unused);
}
#[test]
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(deprecated)]
-
-use core::finally::{try_finally, Finally};
-use std::thread;
-
-#[test]
-fn test_success() {
- let mut i = 0;
- try_finally(
- &mut i, (),
- |i, ()| {
- *i = 10;
- },
- |i| {
- assert!(!thread::panicking());
- assert_eq!(*i, 10);
- *i = 20;
- });
- assert_eq!(i, 20);
-}
-
-#[test]
-#[should_panic]
-fn test_fail() {
- let mut i = 0;
- try_finally(
- &mut i, (),
- |i, ()| {
- *i = 10;
- panic!();
- },
- |i| {
- assert!(thread::panicking());
- assert_eq!(*i, 10);
- })
-}
-
-#[test]
-fn test_retval() {
- let mut closure = || 10;
- // FIXME(#16640) `: i32` annotation shouldn't be necessary
- let i: i32 = closure.finally(|| { });
- assert_eq!(i, 10);
-}
-
-#[test]
-fn test_compact() {
- fn do_some_fallible_work() {}
- fn but_always_run_this_function() { }
- let mut f = do_some_fallible_work;
- f.finally(but_always_run_this_function);
-}
#[test]
fn test_counter_from_iter() {
- let it = count(0, 5).take(10);
+ let it = (0..).step_by(5).take(10);
let xs: Vec<isize> = FromIterator::from_iter(it);
assert_eq!(xs, [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]);
}
}
assert_eq!(i, expected.len());
- let ys = count(30, 10).take(4);
+ let ys = (30..).step_by(10).take(4);
let it = xs.iter().cloned().chain(ys);
let mut i = 0;
for x in it {
#[test]
fn test_filter_map() {
- let it = count(0, 1).take(10)
+ let it = (0..).step_by(1).take(10)
.filter_map(|x| if x % 2 == 0 { Some(x*x) } else { None });
assert_eq!(it.collect::<Vec<usize>>(), [0*0, 2*2, 4*4, 6*6, 8*8]);
}
fn test_iterator_flat_map() {
let xs = [0, 3, 6];
let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8];
- let it = xs.iter().flat_map(|&x| count(x, 1).take(3));
+ let it = xs.iter().flat_map(|&x| (x..).step_by(1).take(3));
let mut i = 0;
for x in it {
assert_eq!(x, ys[i]);
#[test]
fn test_cycle() {
let cycle_len = 3;
- let it = count(0, 1).take(cycle_len).cycle();
+ let it = (0..).step_by(1).take(cycle_len).cycle();
assert_eq!(it.size_hint(), (usize::MAX, None));
for (i, x) in it.take(100).enumerate() {
assert_eq!(i % cycle_len, x);
}
- let mut it = count(0, 1).take(0).cycle();
+ let mut it = (0..).step_by(1).take(0).cycle();
assert_eq!(it.size_hint(), (0, Some(0)));
assert_eq!(it.next(), None);
}
#[test]
fn test_iterator_size_hint() {
- let c = count(0, 1);
+ let c = (0..).step_by(1);
let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let v2 = &[10, 11, 12];
let vi = v.iter();
mod cell;
mod char;
mod cmp;
-mod finally;
mod fmt;
mod hash;
mod iter;
}
unsafe {
- assert_eq!([76], transmute::<_, Vec<u8>>("L".to_string()));
+ assert_eq!(transmute::<_, Vec<u8>>("L".to_string()), [76]);
}
}
fn test_overflows() {
assert!(MAX > 0);
assert!(MIN <= 0);
- assert!(MIN + MAX + 1 == 0);
+ assert!((MIN + MAX).wrapping_add(1) == 0);
}
#[test]
#[test]
fn contains_weird_cases() {
- assert!("* \t".contains_char(' '));
- assert!(!"* \t".contains_char('?'));
- assert!(!"* \t".contains_char('\u{1F4A9}'));
+ assert!("* \t".contains(' '));
+ assert!(!"* \t".contains('?'));
+ assert!(!"* \t".contains('\u{1F4A9}'));
}
#[test]
make_test!(chars_count, s, s.chars().count());
make_test!(contains_bang_str, s, s.contains("!"));
- make_test!(contains_bang_char, s, s.contains_char('!'));
+ make_test!(contains_bang_char, s, s.contains('!'));
make_test!(match_indices_a_str, s, s.match_indices("a").count());
- make_test!(split_str_a_str, s, s.split_str("a").count());
+ make_test!(split_a_str, s, s.split("a").count());
make_test!(trim_ascii_char, s, {
use std::ascii::AsciiExt;
make_test!(find_underscore_char, s, s.find('_'));
make_test!(rfind_underscore_char, s, s.rfind('_'));
- make_test!(find_underscore_str, s, s.find_str("_"));
+ make_test!(find_underscore_str, s, s.find("_"));
make_test!(find_zzz_char, s, s.find('\u{1F4A4}'));
make_test!(rfind_zzz_char, s, s.rfind('\u{1F4A4}'));
- make_test!(find_zzz_str, s, s.find_str("\u{1F4A4}"));
+ make_test!(find_zzz_str, s, s.find("\u{1F4A4}"));
make_test!(split_space_char, s, s.split(' ').count());
make_test!(split_terminator_space_char, s, s.split_terminator(' ').count());
make_test!(splitn_space_char, s, s.splitn(10, ' ').count());
make_test!(rsplitn_space_char, s, s.rsplitn(10, ' ').count());
- make_test!(split_str_space_str, s, s.split_str(" ").count());
- make_test!(split_str_ad_str, s, s.split_str("ad").count());
+ make_test!(split_space_str, s, s.split(" ").count());
+ make_test!(split_ad_str, s, s.split("ad").count());
}
fn same(fmt: &'static str, p: &[Piece<'static>]) {
let parser = Parser::new(fmt);
- assert!(p == parser.collect::<Vec<Piece<'static>>>());
+ assert!(parser.collect::<Vec<Piece<'static>>>() == p);
}
fn fmtdflt() -> FormatSpec<'static> {
//!
//! fn edges(&'a self) -> dot::Edges<'a,Ed> {
//! let &Edges(ref edges) = self;
-//! edges.as_slice().into_cow()
+//! (&edges[..]).into_cow()
//! }
//!
//! fn source(&self, e: &Ed) -> Nd { let &(s,_) = e; s }
for word in &mut key {
*word = other.gen();
}
- SeedableRng::from_seed(key.as_slice())
+ SeedableRng::from_seed(&key[..])
}
}
///
/// let mut v = [0; 13579];
/// thread_rng().fill_bytes(&mut v);
- /// println!("{:?}", v.as_slice());
+ /// println!("{:?}", &v[..]);
/// ```
fn fill_bytes(&mut self, dest: &mut [u8]) {
// this could, in theory, be done by transmuting dest to a
/// let mut rng = thread_rng();
/// let mut y = [1, 2, 3];
/// rng.shuffle(&mut y);
- /// println!("{:?}", y.as_slice());
+ /// println!("{:?}", y);
/// rng.shuffle(&mut y);
- /// println!("{:?}", y.as_slice());
+ /// println!("{:?}", y);
/// ```
fn shuffle<T>(&mut self, values: &mut [T]) {
let mut i = values.len();
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
-#![feature(io)]
#![feature(core)]
#![feature(rustc_private)]
#![feature(staged_api)]
} else if 0x100 <= n && n < NUM_TAGS {
w.write_all(&[0xf0 | (n >> 8) as u8, n as u8])
} else {
- Err(io::Error::new(io::ErrorKind::Other, "invalid tag",
- Some(n.to_string())))
+ Err(io::Error::new(io::ErrorKind::Other,
+ &format!("invalid tag: {}", n)[..]))
}
}
4 => w.write_all(&[0x10 | ((n >> 24) as u8), (n >> 16) as u8,
(n >> 8) as u8, n as u8]),
_ => Err(io::Error::new(io::ErrorKind::Other,
- "isize too big", Some(n.to_string())))
+ &format!("isize too big: {}", n)[..]))
}
}
if n < 0x4000 { return write_sized_vuint(w, n, 2); }
if n < 0x200000 { return write_sized_vuint(w, n, 3); }
if n < 0x10000000 { return write_sized_vuint(w, n, 4); }
- Err(io::Error::new(io::ErrorKind::Other, "isize too big",
- Some(n.to_string())))
+ Err(io::Error::new(io::ErrorKind::Other,
+ &format!("isize too big: {}", n)[..]))
}
impl<'a> Encoder<'a> {
self.wr_tagged_raw_u32(EsSub32 as usize, v)
} else {
Err(io::Error::new(io::ErrorKind::Other,
- "length or variant id too big",
- Some(v.to_string())))
+ &format!("length or variant id too big: {}",
+ v)[..]))
}
}
E0019,
E0020,
E0022,
+ E0079, // enum variant: expected signed integer constant
+ E0080, // enum variant: constant evaluation error
E0109,
E0110,
E0133,
E0313, // lifetime of borrowed pointer outlives lifetime of captured variable
E0314, // closure outlives stack frame
E0315, // cannot invoke closure outside of its lifetime
- E0316 // nested quantification of lifetimes
+ E0316, // nested quantification of lifetimes
+ E0370 // discriminant overflow
}
__build_diagnostic_array! { DIAGNOSTICS }
#![feature(unsafe_destructor)]
#![feature(staged_api)]
#![feature(std_misc)]
-#![feature(io)]
#![feature(path_ext)]
#![feature(str_words)]
#![feature(str_char)]
-#![feature(convert)]
#![feature(into_cow)]
#![feature(slice_patterns)]
#![cfg_attr(test, feature(test))]
pub mod traits;
pub mod ty;
pub mod ty_fold;
+ pub mod ty_match;
+ pub mod ty_relate;
pub mod ty_walk;
pub mod weak_lang_items;
}
use std::io::{Cursor, SeekFrom};
use syntax::abi;
use syntax::ast::{self, DefId, NodeId};
-use syntax::ast_map::{PathElem, PathElems};
-use syntax::ast_map;
+use syntax::ast_map::{self, LinkedPath, PathElem, PathElems};
use syntax::ast_util::*;
use syntax::ast_util;
use syntax::attr;
&krate.module,
&[],
ast::CRATE_NODE_ID,
- [].iter().cloned().chain(None),
+ [].iter().cloned().chain(LinkedPath::empty()),
syntax::parse::token::special_idents::invalid,
ast::Public);
}
// Encode reexports for the root module.
- encode_reexports(ecx, rbml_w, 0, [].iter().cloned().chain(None));
+ encode_reexports(ecx, rbml_w, 0, [].iter().cloned().chain(LinkedPath::empty()));
rbml_w.end_tag();
rbml_w.end_tag();
})
}
- if let Some(ty) = tcx.node_types.borrow().get(&id) {
+ if let Some(ty) = tcx.node_types().get(&id) {
rbml_w.tag(c::tag_table_node_type, |rbml_w| {
rbml_w.id(id);
rbml_w.emit_ty(ecx, *ty);
let ty = val_dsr.read_ty(dcx);
debug!("inserting ty for node {}: {}",
id, ty_to_string(dcx.tcx, ty));
- dcx.tcx.node_types.borrow_mut().insert(id, ty);
+ dcx.tcx.node_type_insert(id, ty);
}
c::tag_table_item_subst => {
let item_substs = ty::ItemSubsts {
pub use self::const_val::*;
+use self::ErrKind::*;
+
use metadata::csearch;
use middle::{astencode, def};
use middle::pat_util::def_to_path;
use std::borrow::{Cow, IntoCow};
use std::num::wrapping::OverflowingOps;
+use std::num::ToPrimitive;
use std::cmp::Ordering;
use std::collections::hash_map::Entry::Vacant;
use std::{i8, i16, i32, i64};
NotOnStruct,
NotOnTuple,
+ NegateWithOverflow(i64),
AddiWithOverflow(i64, i64),
SubiWithOverflow(i64, i64),
MuliWithOverflow(i64, i64),
DivideWithOverflow,
ModuloByZero,
ModuloWithOverflow,
+ ShiftLeftWithOverflow,
+ ShiftRightWithOverflow,
MissingStructField,
NonConstPath,
ExpectedConstTuple,
impl ConstEvalErr {
pub fn description(&self) -> Cow<str> {
use self::ErrKind::*;
+
match self.kind {
CannotCast => "can't cast this type".into_cow(),
CannotCastTo(s) => format!("can't cast this type to {}", s).into_cow(),
NotOnStruct => "not on struct".into_cow(),
NotOnTuple => "not on tuple".into_cow(),
+ NegateWithOverflow(..) => "attempted to negate with overflow".into_cow(),
AddiWithOverflow(..) => "attempted to add with overflow".into_cow(),
SubiWithOverflow(..) => "attempted to sub with overflow".into_cow(),
MuliWithOverflow(..) => "attempted to mul with overflow".into_cow(),
DivideWithOverflow => "attempted to divide with overflow".into_cow(),
ModuloByZero => "attempted remainder with a divisor of zero".into_cow(),
ModuloWithOverflow => "attempted remainder with overflow".into_cow(),
+ ShiftLeftWithOverflow => "attempted left shift with overflow".into_cow(),
+ ShiftRightWithOverflow => "attempted right shift with overflow".into_cow(),
MissingStructField => "nonexistent struct field".into_cow(),
NonConstPath => "non-constant path in constant expr".into_cow(),
ExpectedConstTuple => "expected constant tuple".into_cow(),
}
}
+pub type EvalResult = Result<const_val, ConstEvalErr>;
+pub type CastResult = Result<const_val, ErrKind>;
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum IntTy { I8, I16, I32, I64 }
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum UintTy { U8, U16, U32, U64 }
+
+impl IntTy {
+ pub fn from(tcx: &ty::ctxt, t: ast::IntTy) -> IntTy {
+ let t = if let ast::TyIs = t {
+ tcx.sess.target.int_type
+ } else {
+ t
+ };
+ match t {
+ ast::TyIs => unreachable!(),
+ ast::TyI8 => IntTy::I8,
+ ast::TyI16 => IntTy::I16,
+ ast::TyI32 => IntTy::I32,
+ ast::TyI64 => IntTy::I64,
+ }
+ }
+}
+
+impl UintTy {
+ pub fn from(tcx: &ty::ctxt, t: ast::UintTy) -> UintTy {
+ let t = if let ast::TyUs = t {
+ tcx.sess.target.uint_type
+ } else {
+ t
+ };
+ match t {
+ ast::TyUs => unreachable!(),
+ ast::TyU8 => UintTy::U8,
+ ast::TyU16 => UintTy::U16,
+ ast::TyU32 => UintTy::U32,
+ ast::TyU64 => UintTy::U64,
+ }
+ }
+}
+
macro_rules! signal {
- ($e:expr, $ctor:ident) => {
- return Err(ConstEvalErr { span: $e.span, kind: ErrKind::$ctor })
+ ($e:expr, $exn:expr) => {
+ return Err(ConstEvalErr { span: $e.span, kind: $exn })
+ }
+}
+
+// The const_{int,uint}_checked_{neg,add,sub,mul,div,shl,shr} family
+// of functions catch and signal overflow errors during constant
+// evaluation.
+//
+// They all take the operator's arguments (`a` and `b` if binary), the
+// overall expression (`e`) and, if available, whole expression's
+// concrete type (`opt_ety`).
+//
+// If the whole expression's concrete type is None, then this is a
+// constant evaluation happening before type check (e.g. in the check
+// to confirm that a pattern range's left-side is not greater than its
+// right-side). We do not do arithmetic modulo the type's bitwidth in
+// such a case; we just do 64-bit arithmetic and assume that later
+// passes will do it again with the type information, and thus do the
+// overflow checks then.
+
+pub fn const_int_checked_neg<'a>(
+ a: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
+
+ let (min,max) = match opt_ety {
+ // (-i8::MIN is itself not an i8, etc, but this is an easy way
+ // to allow literals to pass the check. Of course that does
+ // not work for i64::MIN.)
+ Some(IntTy::I8) => (-(i8::MAX as i64), -(i8::MIN as i64)),
+ Some(IntTy::I16) => (-(i16::MAX as i64), -(i16::MIN as i64)),
+ Some(IntTy::I32) => (-(i32::MAX as i64), -(i32::MIN as i64)),
+ None | Some(IntTy::I64) => (-i64::MAX, -(i64::MIN+1)),
};
- ($e:expr, $ctor:ident($($arg:expr),*)) => {
- return Err(ConstEvalErr { span: $e.span, kind: ErrKind::$ctor($($arg),*) })
+ let oflo = a < min || a > max;
+ if oflo {
+ signal!(e, NegateWithOverflow(a));
+ } else {
+ Ok(const_int(-a))
+ }
+}
+
+pub fn const_uint_checked_neg<'a>(
+ a: u64, _e: &'a Expr, _opt_ety: Option<UintTy>) -> EvalResult {
+ // This always succeeds, and by definition, returns `(!a)+1`.
+ Ok(const_uint(-a))
+}
+
+macro_rules! overflow_checking_body {
+ ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident,
+ lhs: $to_8_lhs:ident $to_16_lhs:ident $to_32_lhs:ident,
+ rhs: $to_8_rhs:ident $to_16_rhs:ident $to_32_rhs:ident $to_64_rhs:ident,
+ $EnumTy:ident $T8: ident $T16: ident $T32: ident $T64: ident,
+ $result_type: ident) => { {
+ let (a,b,opt_ety) = ($a,$b,$ety);
+ match opt_ety {
+ Some($EnumTy::$T8) => match (a.$to_8_lhs(), b.$to_8_rhs()) {
+ (Some(a), Some(b)) => {
+ let (a, oflo) = a.$overflowing_op(b);
+ (a as $result_type, oflo)
+ }
+ (None, _) | (_, None) => (0, true)
+ },
+ Some($EnumTy::$T16) => match (a.$to_16_lhs(), b.$to_16_rhs()) {
+ (Some(a), Some(b)) => {
+ let (a, oflo) = a.$overflowing_op(b);
+ (a as $result_type, oflo)
+ }
+ (None, _) | (_, None) => (0, true)
+ },
+ Some($EnumTy::$T32) => match (a.$to_32_lhs(), b.$to_32_rhs()) {
+ (Some(a), Some(b)) => {
+ let (a, oflo) = a.$overflowing_op(b);
+ (a as $result_type, oflo)
+ }
+ (None, _) | (_, None) => (0, true)
+ },
+ None | Some($EnumTy::$T64) => match b.$to_64_rhs() {
+ Some(b) => a.$overflowing_op(b),
+ None => (0, true),
+ }
+ }
+ } }
+}
+
+macro_rules! int_arith_body {
+ ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
+ overflow_checking_body!(
+ $a, $b, $ety, $overflowing_op,
+ lhs: to_i8 to_i16 to_i32,
+ rhs: to_i8 to_i16 to_i32 to_i64, IntTy I8 I16 I32 I64, i64)
+ }
+}
+
+macro_rules! uint_arith_body {
+ ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
+ overflow_checking_body!(
+ $a, $b, $ety, $overflowing_op,
+ lhs: to_u8 to_u16 to_u32,
+ rhs: to_u8 to_u16 to_u32 to_u64, UintTy U8 U16 U32 U64, u64)
+ }
+}
+
+macro_rules! int_shift_body {
+ ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
+ overflow_checking_body!(
+ $a, $b, $ety, $overflowing_op,
+ lhs: to_i8 to_i16 to_i32,
+ rhs: to_u32 to_u32 to_u32 to_u32, IntTy I8 I16 I32 I64, i64)
}
}
-fn checked_add_int(e: &Expr, a: i64, b: i64) -> Result<const_val, ConstEvalErr> {
- let (ret, oflo) = a.overflowing_add(b);
- if !oflo { Ok(const_int(ret)) } else { signal!(e, AddiWithOverflow(a, b)) }
+macro_rules! uint_shift_body {
+ ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
+ overflow_checking_body!(
+ $a, $b, $ety, $overflowing_op,
+ lhs: to_u8 to_u16 to_u32,
+ rhs: to_u32 to_u32 to_u32 to_u32, UintTy U8 U16 U32 U64, u64)
+ }
}
-fn checked_sub_int(e: &Expr, a: i64, b: i64) -> Result<const_val, ConstEvalErr> {
- let (ret, oflo) = a.overflowing_sub(b);
- if !oflo { Ok(const_int(ret)) } else { signal!(e, SubiWithOverflow(a, b)) }
+
+macro_rules! pub_fn_checked_op {
+ {$fn_name:ident ($a:ident : $a_ty:ty, $b:ident : $b_ty:ty,.. $WhichTy:ident) {
+ $ret_oflo_body:ident $overflowing_op:ident
+ $const_ty:ident $signal_exn:expr
+ }} => {
+ pub fn $fn_name<'a>($a: $a_ty,
+ $b: $b_ty,
+ e: &'a Expr,
+ opt_ety: Option<$WhichTy>) -> EvalResult {
+ let (ret, oflo) = $ret_oflo_body!($a, $b, opt_ety, $overflowing_op);
+ if !oflo { Ok($const_ty(ret)) } else { signal!(e, $signal_exn) }
+ }
+ }
}
-fn checked_mul_int(e: &Expr, a: i64, b: i64) -> Result<const_val, ConstEvalErr> {
- let (ret, oflo) = a.overflowing_mul(b);
- if !oflo { Ok(const_int(ret)) } else { signal!(e, MuliWithOverflow(a, b)) }
+
+pub_fn_checked_op!{ const_int_checked_add(a: i64, b: i64,.. IntTy) {
+ int_arith_body overflowing_add const_int AddiWithOverflow(a, b)
+}}
+
+pub_fn_checked_op!{ const_int_checked_sub(a: i64, b: i64,.. IntTy) {
+ int_arith_body overflowing_sub const_int SubiWithOverflow(a, b)
+}}
+
+pub_fn_checked_op!{ const_int_checked_mul(a: i64, b: i64,.. IntTy) {
+ int_arith_body overflowing_mul const_int MuliWithOverflow(a, b)
+}}
+
+pub fn const_int_checked_div<'a>(
+ a: i64, b: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
+ if b == 0 { signal!(e, DivideByZero); }
+ let (ret, oflo) = int_arith_body!(a, b, opt_ety, overflowing_div);
+ if !oflo { Ok(const_int(ret)) } else { signal!(e, DivideWithOverflow) }
}
-fn checked_add_uint(e: &Expr, a: u64, b: u64) -> Result<const_val, ConstEvalErr> {
- let (ret, oflo) = a.overflowing_add(b);
- if !oflo { Ok(const_uint(ret)) } else { signal!(e, AdduWithOverflow(a, b)) }
+pub fn const_int_checked_rem<'a>(
+ a: i64, b: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
+ if b == 0 { signal!(e, ModuloByZero); }
+ let (ret, oflo) = int_arith_body!(a, b, opt_ety, overflowing_rem);
+ if !oflo { Ok(const_int(ret)) } else { signal!(e, ModuloWithOverflow) }
}
-fn checked_sub_uint(e: &Expr, a: u64, b: u64) -> Result<const_val, ConstEvalErr> {
- let (ret, oflo) = a.overflowing_sub(b);
- if !oflo { Ok(const_uint(ret)) } else { signal!(e, SubuWithOverflow(a, b)) }
+
+pub_fn_checked_op!{ const_int_checked_shl(a: i64, b: i64,.. IntTy) {
+ int_shift_body overflowing_shl const_int ShiftLeftWithOverflow
+}}
+
+pub_fn_checked_op!{ const_int_checked_shl_via_uint(a: i64, b: u64,.. IntTy) {
+ int_shift_body overflowing_shl const_int ShiftLeftWithOverflow
+}}
+
+pub_fn_checked_op!{ const_int_checked_shr(a: i64, b: i64,.. IntTy) {
+ int_shift_body overflowing_shr const_int ShiftRightWithOverflow
+}}
+
+pub_fn_checked_op!{ const_int_checked_shr_via_uint(a: i64, b: u64,.. IntTy) {
+ int_shift_body overflowing_shr const_int ShiftRightWithOverflow
+}}
+
+pub_fn_checked_op!{ const_uint_checked_add(a: u64, b: u64,.. UintTy) {
+ uint_arith_body overflowing_add const_uint AdduWithOverflow(a, b)
+}}
+
+pub_fn_checked_op!{ const_uint_checked_sub(a: u64, b: u64,.. UintTy) {
+ uint_arith_body overflowing_sub const_uint SubuWithOverflow(a, b)
+}}
+
+pub_fn_checked_op!{ const_uint_checked_mul(a: u64, b: u64,.. UintTy) {
+ uint_arith_body overflowing_mul const_uint MuluWithOverflow(a, b)
+}}
+
+pub fn const_uint_checked_div<'a>(
+ a: u64, b: u64, e: &'a Expr, opt_ety: Option<UintTy>) -> EvalResult {
+ if b == 0 { signal!(e, DivideByZero); }
+ let (ret, oflo) = uint_arith_body!(a, b, opt_ety, overflowing_div);
+ if !oflo { Ok(const_uint(ret)) } else { signal!(e, DivideWithOverflow) }
}
-fn checked_mul_uint(e: &Expr, a: u64, b: u64) -> Result<const_val, ConstEvalErr> {
- let (ret, oflo) = a.overflowing_mul(b);
- if !oflo { Ok(const_uint(ret)) } else { signal!(e, MuluWithOverflow(a, b)) }
+
+pub fn const_uint_checked_rem<'a>(
+ a: u64, b: u64, e: &'a Expr, opt_ety: Option<UintTy>) -> EvalResult {
+ if b == 0 { signal!(e, ModuloByZero); }
+ let (ret, oflo) = uint_arith_body!(a, b, opt_ety, overflowing_rem);
+ if !oflo { Ok(const_uint(ret)) } else { signal!(e, ModuloWithOverflow) }
}
+pub_fn_checked_op!{ const_uint_checked_shl(a: u64, b: u64,.. UintTy) {
+ uint_shift_body overflowing_shl const_uint ShiftLeftWithOverflow
+}}
+
+pub_fn_checked_op!{ const_uint_checked_shl_via_int(a: u64, b: i64,.. UintTy) {
+ uint_shift_body overflowing_shl const_uint ShiftLeftWithOverflow
+}}
+
+pub_fn_checked_op!{ const_uint_checked_shr(a: u64, b: u64,.. UintTy) {
+ uint_shift_body overflowing_shr const_uint ShiftRightWithOverflow
+}}
+
+pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) {
+ uint_shift_body overflowing_shr const_uint ShiftRightWithOverflow
+}}
pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
e: &Expr,
- ty_hint: Option<Ty<'tcx>>)
- -> Result<const_val, ConstEvalErr> {
+ ty_hint: Option<Ty<'tcx>>) -> EvalResult {
fn fromb(b: bool) -> const_val { const_int(b as i64) }
let ety = ty_hint.or_else(|| ty::expr_ty_opt(tcx, e));
+ // If type of expression itself is int or uint, normalize in these
+ // bindings so that isize/usize is mapped to a type with an
+ // inherently known bitwidth.
+ let expr_int_type = ety.and_then(|ty| {
+ if let ty::ty_int(t) = ty.sty {
+ Some(IntTy::from(tcx, t)) } else { None }
+ });
+ let expr_uint_type = ety.and_then(|ty| {
+ if let ty::ty_uint(t) = ty.sty {
+ Some(UintTy::from(tcx, t)) } else { None }
+ });
+
let result = match e.node {
ast::ExprUnary(ast::UnNeg, ref inner) => {
match try!(eval_const_expr_partial(tcx, &**inner, ety)) {
const_float(f) => const_float(-f),
- const_int(i) => const_int(-i),
- const_uint(i) => const_uint(-i),
+ const_int(n) => try!(const_int_checked_neg(n, e, expr_int_type)),
+ const_uint(n) => try!(const_uint_checked_neg(n, e, expr_uint_type)),
const_str(_) => signal!(e, NegateOnString),
const_bool(_) => signal!(e, NegateOnBoolean),
const_binary(_) => signal!(e, NegateOnBinary),
}
}
(const_int(a), const_int(b)) => {
- let is_a_min_value = || {
- let int_ty = match ty::expr_ty_opt(tcx, e).map(|ty| &ty.sty) {
- Some(&ty::ty_int(int_ty)) => int_ty,
- _ => return false
- };
- let int_ty = if let ast::TyIs = int_ty {
- tcx.sess.target.int_type
- } else {
- int_ty
- };
- match int_ty {
- ast::TyI8 => (a as i8) == i8::MIN,
- ast::TyI16 => (a as i16) == i16::MIN,
- ast::TyI32 => (a as i32) == i32::MIN,
- ast::TyI64 => (a as i64) == i64::MIN,
- ast::TyIs => unreachable!()
- }
- };
match op.node {
- ast::BiAdd => try!(checked_add_int(e, a, b)),
- ast::BiSub => try!(checked_sub_int(e, a, b)),
- ast::BiMul => try!(checked_mul_int(e, a, b)),
- ast::BiDiv => {
- if b == 0 {
- signal!(e, DivideByZero);
- } else if b == -1 && is_a_min_value() {
- signal!(e, DivideWithOverflow);
- } else {
- const_int(a / b)
- }
- }
- ast::BiRem => {
- if b == 0 {
- signal!(e, ModuloByZero)
- } else if b == -1 && is_a_min_value() {
- signal!(e, ModuloWithOverflow)
- } else {
- const_int(a % b)
- }
- }
+ ast::BiAdd => try!(const_int_checked_add(a,b,e,expr_int_type)),
+ ast::BiSub => try!(const_int_checked_sub(a,b,e,expr_int_type)),
+ ast::BiMul => try!(const_int_checked_mul(a,b,e,expr_int_type)),
+ ast::BiDiv => try!(const_int_checked_div(a,b,e,expr_int_type)),
+ ast::BiRem => try!(const_int_checked_rem(a,b,e,expr_int_type)),
ast::BiAnd | ast::BiBitAnd => const_int(a & b),
ast::BiOr | ast::BiBitOr => const_int(a | b),
ast::BiBitXor => const_int(a ^ b),
- ast::BiShl => const_int(a << b as usize),
- ast::BiShr => const_int(a >> b as usize),
+ ast::BiShl => try!(const_int_checked_shl(a,b,e,expr_int_type)),
+ ast::BiShr => try!(const_int_checked_shr(a,b,e,expr_int_type)),
ast::BiEq => fromb(a == b),
ast::BiLt => fromb(a < b),
ast::BiLe => fromb(a <= b),
}
(const_uint(a), const_uint(b)) => {
match op.node {
- ast::BiAdd => try!(checked_add_uint(e, a, b)),
- ast::BiSub => try!(checked_sub_uint(e, a, b)),
- ast::BiMul => try!(checked_mul_uint(e, a, b)),
- ast::BiDiv if b == 0 => signal!(e, DivideByZero),
- ast::BiDiv => const_uint(a / b),
- ast::BiRem if b == 0 => signal!(e, ModuloByZero),
- ast::BiRem => const_uint(a % b),
+ ast::BiAdd => try!(const_uint_checked_add(a,b,e,expr_uint_type)),
+ ast::BiSub => try!(const_uint_checked_sub(a,b,e,expr_uint_type)),
+ ast::BiMul => try!(const_uint_checked_mul(a,b,e,expr_uint_type)),
+ ast::BiDiv => try!(const_uint_checked_div(a,b,e,expr_uint_type)),
+ ast::BiRem => try!(const_uint_checked_rem(a,b,e,expr_uint_type)),
ast::BiAnd | ast::BiBitAnd => const_uint(a & b),
ast::BiOr | ast::BiBitOr => const_uint(a | b),
ast::BiBitXor => const_uint(a ^ b),
- ast::BiShl => const_uint(a << b as usize),
- ast::BiShr => const_uint(a >> b as usize),
+ ast::BiShl => try!(const_uint_checked_shl(a,b,e,expr_uint_type)),
+ ast::BiShr => try!(const_uint_checked_shr(a,b,e,expr_uint_type)),
ast::BiEq => fromb(a == b),
ast::BiLt => fromb(a < b),
ast::BiLe => fromb(a <= b),
// shifts can have any integral type as their rhs
(const_int(a), const_uint(b)) => {
match op.node {
- ast::BiShl => const_int(a << b as usize),
- ast::BiShr => const_int(a >> b as usize),
+ ast::BiShl => try!(const_int_checked_shl_via_uint(a,b,e,expr_int_type)),
+ ast::BiShr => try!(const_int_checked_shr_via_uint(a,b,e,expr_int_type)),
_ => signal!(e, InvalidOpForIntUint(op.node)),
}
}
(const_uint(a), const_int(b)) => {
match op.node {
- ast::BiShl => const_uint(a << b as usize),
- ast::BiShr => const_uint(a >> b as usize),
+ ast::BiShl => try!(const_uint_checked_shl_via_int(a,b,e,expr_uint_type)),
+ ast::BiShr => try!(const_uint_checked_shr_via_int(a,b,e,expr_uint_type)),
_ => signal!(e, InvalidOpForUintInt(op.node)),
}
}
tcx.sess.span_fatal(target_ty.span,
"target type not found for const cast")
});
+
// Prefer known type to noop, but always have a type hint.
+ //
+ // FIXME (#23833): the type-hint can cause problems,
+ // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result
+ // type to the sum, and thus no overflow is signaled.
let base_hint = ty::expr_ty_opt(tcx, &**base).unwrap_or(ety);
let val = try!(eval_const_expr_partial(tcx, &**base, Some(base_hint)));
- match cast_const(val, ety) {
+ match cast_const(tcx, val, ety) {
Ok(val) => val,
Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
}
Ok(result)
}
-fn cast_const(val: const_val, ty: Ty) -> Result<const_val, ErrKind> {
- macro_rules! define_casts {
- ($($ty_pat:pat => (
- $intermediate_ty:ty,
- $const_type:ident,
- $target_ty:ty
- )),*) => (match ty.sty {
- $($ty_pat => {
- match val {
- const_bool(b) => Ok($const_type(b as $intermediate_ty as $target_ty)),
- const_uint(u) => Ok($const_type(u as $intermediate_ty as $target_ty)),
- const_int(i) => Ok($const_type(i as $intermediate_ty as $target_ty)),
- const_float(f) => Ok($const_type(f as $intermediate_ty as $target_ty)),
- _ => Err(ErrKind::CannotCastTo(stringify!($const_type))),
- }
- },)*
- _ => Err(ErrKind::CannotCast),
- })
+fn cast_const<'tcx>(tcx: &ty::ctxt<'tcx>, val: const_val, ty: Ty) -> CastResult {
+ macro_rules! convert_val {
+ ($intermediate_ty:ty, $const_type:ident, $target_ty:ty) => {
+ match val {
+ const_bool(b) => Ok($const_type(b as $intermediate_ty as $target_ty)),
+ const_uint(u) => Ok($const_type(u as $intermediate_ty as $target_ty)),
+ const_int(i) => Ok($const_type(i as $intermediate_ty as $target_ty)),
+ const_float(f) => Ok($const_type(f as $intermediate_ty as $target_ty)),
+ _ => Err(ErrKind::CannotCastTo(stringify!($const_type))),
+ }
+ }
+ }
+
+ // Issue #23890: If isize/usize, then dispatch to appropriate target representation type
+ match (&ty.sty, tcx.sess.target.int_type, tcx.sess.target.uint_type) {
+ (&ty::ty_int(ast::TyIs), ast::TyI32, _) => return convert_val!(i32, const_int, i64),
+ (&ty::ty_int(ast::TyIs), ast::TyI64, _) => return convert_val!(i64, const_int, i64),
+ (&ty::ty_int(ast::TyIs), _, _) => panic!("unexpected target.int_type"),
+
+ (&ty::ty_uint(ast::TyUs), _, ast::TyU32) => return convert_val!(u32, const_uint, u64),
+ (&ty::ty_uint(ast::TyUs), _, ast::TyU64) => return convert_val!(u64, const_uint, u64),
+ (&ty::ty_uint(ast::TyUs), _, _) => panic!("unexpected target.uint_type"),
+
+ _ => {}
}
- define_casts!{
- ty::ty_int(ast::TyIs) => (isize, const_int, i64),
- ty::ty_int(ast::TyI8) => (i8, const_int, i64),
- ty::ty_int(ast::TyI16) => (i16, const_int, i64),
- ty::ty_int(ast::TyI32) => (i32, const_int, i64),
- ty::ty_int(ast::TyI64) => (i64, const_int, i64),
- ty::ty_uint(ast::TyUs) => (usize, const_uint, u64),
- ty::ty_uint(ast::TyU8) => (u8, const_uint, u64),
- ty::ty_uint(ast::TyU16) => (u16, const_uint, u64),
- ty::ty_uint(ast::TyU32) => (u32, const_uint, u64),
- ty::ty_uint(ast::TyU64) => (u64, const_uint, u64),
- ty::ty_float(ast::TyF32) => (f32, const_float, f64),
- ty::ty_float(ast::TyF64) => (f64, const_float, f64)
+ match ty.sty {
+ ty::ty_int(ast::TyIs) => unreachable!(),
+ ty::ty_uint(ast::TyUs) => unreachable!(),
+
+ ty::ty_int(ast::TyI8) => convert_val!(i8, const_int, i64),
+ ty::ty_int(ast::TyI16) => convert_val!(i16, const_int, i64),
+ ty::ty_int(ast::TyI32) => convert_val!(i32, const_int, i64),
+ ty::ty_int(ast::TyI64) => convert_val!(i64, const_int, i64),
+
+ ty::ty_uint(ast::TyU8) => convert_val!(u8, const_uint, u64),
+ ty::ty_uint(ast::TyU16) => convert_val!(u16, const_uint, u64),
+ ty::ty_uint(ast::TyU32) => convert_val!(u32, const_uint, u64),
+ ty::ty_uint(ast::TyU64) => convert_val!(u64, const_uint, u64),
+
+ ty::ty_float(ast::TyF32) => convert_val!(f32, const_float, f64),
+ ty::ty_float(ast::TyF64) => convert_val!(f64, const_float, f64),
+ _ => Err(ErrKind::CannotCast),
}
}
pprust::NodeIdent(_) | pprust::NodeName(_) => 0,
pprust::NodeExpr(expr) => expr.id,
pprust::NodeBlock(blk) => blk.id,
- pprust::NodeItem(_) => 0,
+ pprust::NodeItem(_) | pprust::NodeSubItem(_) => 0,
pprust::NodePat(pat) => pat.id
};
/// <T as Trait>::AssocX::AssocY::MethodOrAssocType
/// ^~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~
/// base_def depth = 2
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub struct PathResolution {
pub base_def: Def,
pub last_private: LastPrivate,
pub fn def_id(&self) -> ast::DefId {
self.full_def().def_id()
}
+
+ pub fn new(base_def: Def,
+ last_private: LastPrivate,
+ depth: usize)
+ -> PathResolution {
+ PathResolution {
+ base_def: base_def,
+ last_private: last_private,
+ depth: depth,
+ }
+ }
}
// Definition mapping
//! In particular, it might be enough to say (A,B) are bivariant for
//! all (A,B).
-use middle::ty::BuiltinBounds;
+use super::combine::{self, CombineFields};
+use super::type_variable::{BiTo};
+
use middle::ty::{self, Ty};
use middle::ty::TyVar;
-use middle::infer::combine::*;
-use middle::infer::cres;
-use middle::infer::type_variable::BiTo;
-use util::ppaux::Repr;
+use middle::ty_relate::{Relate, RelateResult, TypeRelation};
+use util::ppaux::{Repr};
-pub struct Bivariate<'f, 'tcx: 'f> {
- fields: CombineFields<'f, 'tcx>
+pub struct Bivariate<'a, 'tcx: 'a> {
+ fields: CombineFields<'a, 'tcx>
}
-#[allow(non_snake_case)]
-pub fn Bivariate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Bivariate<'f, 'tcx> {
- Bivariate { fields: cf }
+impl<'a, 'tcx> Bivariate<'a, 'tcx> {
+ pub fn new(fields: CombineFields<'a, 'tcx>) -> Bivariate<'a, 'tcx> {
+ Bivariate { fields: fields }
+ }
}
-impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> {
- fn tag(&self) -> String { "Bivariate".to_string() }
- fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
+impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Bivariate<'a, 'tcx> {
+ fn tag(&self) -> &'static str { "Bivariate" }
- fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>
- {
- match v {
- ty::Invariant => self.equate().tys(a, b),
- ty::Covariant => self.tys(a, b),
- ty::Contravariant => self.tys(a, b),
- ty::Bivariant => self.tys(a, b),
- }
- }
+ fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() }
- fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
- -> cres<'tcx, ty::Region>
- {
- match v {
- ty::Invariant => self.equate().regions(a, b),
- ty::Covariant => self.regions(a, b),
- ty::Contravariant => self.regions(a, b),
- ty::Bivariant => self.regions(a, b),
- }
- }
+ fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
- fn regions(&self, a: ty::Region, _: ty::Region) -> cres<'tcx, ty::Region> {
- Ok(a)
- }
-
- fn builtin_bounds(&self,
- a: BuiltinBounds,
- b: BuiltinBounds)
- -> cres<'tcx, BuiltinBounds>
+ fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
+ variance: ty::Variance,
+ a: &T,
+ b: &T)
+ -> RelateResult<'tcx, T>
{
- if a != b {
- Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
- } else {
- Ok(a)
+ match variance {
+ // If we have Foo<A> and Foo is invariant w/r/t A,
+ // and we want to assert that
+ //
+ // Foo<A> <: Foo<B> ||
+ // Foo<B> <: Foo<A>
+ //
+ // then still A must equal B.
+ ty::Invariant => self.relate(a, b),
+
+ ty::Covariant => self.relate(a, b),
+ ty::Bivariant => self.relate(a, b),
+ ty::Contravariant => self.relate(a, b),
}
}
- fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
+ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug!("{}.tys({}, {})", self.tag(),
a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
if a == b { return Ok(a); }
}
_ => {
- super_tys(self, a, b)
+ combine::super_combine_tys(self.fields.infcx, self, a, b)
}
}
}
- fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
- where T : Combineable<'tcx>
+ fn regions(&mut self, a: ty::Region, _: ty::Region) -> RelateResult<'tcx, ty::Region> {
+ Ok(a)
+ }
+
+ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
+ -> RelateResult<'tcx, ty::Binder<T>>
+ where T: Relate<'a,'tcx>
{
let a1 = ty::erase_late_bound_regions(self.tcx(), a);
let b1 = ty::erase_late_bound_regions(self.tcx(), b);
- let c = try!(Combineable::combine(self, &a1, &b1));
+ let c = try!(self.relate(&a1, &b1));
Ok(ty::Binder(c))
}
}
use super::glb::Glb;
use super::lub::Lub;
use super::sub::Sub;
-use super::unify::InferCtxtMethodsForSimplyUnifiableTypes;
-use super::{InferCtxt, cres};
+use super::{InferCtxt};
use super::{MiscVariable, TypeTrace};
use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf};
-use middle::subst;
-use middle::subst::{ErasedRegions, NonerasedRegions, Substs};
-use middle::ty::{FloatVar, FnSig, IntVar, TyVar};
+use middle::ty::{TyVar};
use middle::ty::{IntType, UintType};
-use middle::ty::BuiltinBounds;
use middle::ty::{self, Ty};
use middle::ty_fold;
use middle::ty_fold::{TypeFolder, TypeFoldable};
+use middle::ty_relate::{self, Relate, RelateResult, TypeRelation};
use util::ppaux::Repr;
-use std::rc::Rc;
-use syntax::ast::Unsafety;
use syntax::ast;
-use syntax::abi;
use syntax::codemap::Span;
-pub trait Combine<'tcx> : Sized {
- fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.infcx().tcx }
- fn tag(&self) -> String;
-
- fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx>;
-
- fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields().infcx }
- fn a_is_expected(&self) -> bool { self.fields().a_is_expected }
- fn trace(&self) -> TypeTrace<'tcx> { self.fields().trace.clone() }
- fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { self.fields().equate() }
- fn bivariate<'a>(&'a self) -> Bivariate<'a, 'tcx> { self.fields().bivariate() }
-
- fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { self.fields().sub() }
- fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields().clone()) }
- fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields().clone()) }
-
- fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> {
- debug!("{}.mts({}, {})",
- self.tag(),
- a.repr(self.tcx()),
- b.repr(self.tcx()));
-
- if a.mutbl != b.mutbl {
- Err(ty::terr_mutability)
- } else {
- let mutbl = a.mutbl;
- let variance = match mutbl {
- ast::MutImmutable => ty::Covariant,
- ast::MutMutable => ty::Invariant,
- };
- let ty = try!(self.tys_with_variance(variance, a.ty, b.ty));
- Ok(ty::mt {ty: ty, mutbl: mutbl})
- }
- }
-
- fn tys_with_variance(&self, variance: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>;
-
- fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>>;
-
- fn regions_with_variance(&self, variance: ty::Variance, a: ty::Region, b: ty::Region)
- -> cres<'tcx, ty::Region>;
-
- fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region>;
-
- fn substs(&self,
- item_def_id: ast::DefId,
- a_subst: &subst::Substs<'tcx>,
- b_subst: &subst::Substs<'tcx>)
- -> cres<'tcx, subst::Substs<'tcx>>
- {
- debug!("substs: item_def_id={} a_subst={} b_subst={}",
- item_def_id.repr(self.infcx().tcx),
- a_subst.repr(self.infcx().tcx),
- b_subst.repr(self.infcx().tcx));
-
- let variances = if self.infcx().tcx.variance_computed.get() {
- Some(ty::item_variances(self.infcx().tcx, item_def_id))
- } else {
- None
- };
- self.substs_variances(variances.as_ref().map(|v| &**v), a_subst, b_subst)
- }
-
- fn substs_variances(&self,
- variances: Option<&ty::ItemVariances>,
- a_subst: &subst::Substs<'tcx>,
- b_subst: &subst::Substs<'tcx>)
- -> cres<'tcx, subst::Substs<'tcx>>
- {
- let mut substs = subst::Substs::empty();
-
- for &space in &subst::ParamSpace::all() {
- let a_tps = a_subst.types.get_slice(space);
- let b_tps = b_subst.types.get_slice(space);
- let t_variances = variances.map(|v| v.types.get_slice(space));
- let tps = try!(relate_type_params(self, t_variances, a_tps, b_tps));
- substs.types.replace(space, tps);
- }
-
- match (&a_subst.regions, &b_subst.regions) {
- (&ErasedRegions, _) | (_, &ErasedRegions) => {
- substs.regions = ErasedRegions;
- }
-
- (&NonerasedRegions(ref a), &NonerasedRegions(ref b)) => {
- for &space in &subst::ParamSpace::all() {
- let a_regions = a.get_slice(space);
- let b_regions = b.get_slice(space);
- let r_variances = variances.map(|v| v.regions.get_slice(space));
- let regions = try!(relate_region_params(self,
- r_variances,
- a_regions,
- b_regions));
- substs.mut_regions().replace(space, regions);
- }
- }
- }
-
- return Ok(substs);
-
- fn relate_type_params<'tcx, C: Combine<'tcx>>(this: &C,
- variances: Option<&[ty::Variance]>,
- a_tys: &[Ty<'tcx>],
- b_tys: &[Ty<'tcx>])
- -> cres<'tcx, Vec<Ty<'tcx>>>
- {
- if a_tys.len() != b_tys.len() {
- return Err(ty::terr_ty_param_size(expected_found(this,
- a_tys.len(),
- b_tys.len())));
- }
-
- (0.. a_tys.len()).map(|i| {
- let a_ty = a_tys[i];
- let b_ty = b_tys[i];
- let v = variances.map_or(ty::Invariant, |v| v[i]);
- this.tys_with_variance(v, a_ty, b_ty)
- }).collect()
- }
-
- fn relate_region_params<'tcx, C: Combine<'tcx>>(this: &C,
- variances: Option<&[ty::Variance]>,
- a_rs: &[ty::Region],
- b_rs: &[ty::Region])
- -> cres<'tcx, Vec<ty::Region>>
- {
- let tcx = this.infcx().tcx;
- let num_region_params = a_rs.len();
-
- debug!("relate_region_params(\
- a_rs={}, \
- b_rs={},
- variances={})",
- a_rs.repr(tcx),
- b_rs.repr(tcx),
- variances.repr(tcx));
-
- assert_eq!(num_region_params,
- variances.map_or(num_region_params,
- |v| v.len()));
-
- assert_eq!(num_region_params, b_rs.len());
-
- (0..a_rs.len()).map(|i| {
- let a_r = a_rs[i];
- let b_r = b_rs[i];
- let variance = variances.map_or(ty::Invariant, |v| v[i]);
- this.regions_with_variance(variance, a_r, b_r)
- }).collect()
- }
- }
-
- fn bare_fn_tys(&self, a: &ty::BareFnTy<'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.binders(&a.sig, &b.sig));
- Ok(ty::BareFnTy {unsafety: unsafety,
- abi: abi,
- sig: sig})
- }
-
- 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,
- &b.inputs));
-
- 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>(combiner: &C,
- a_args: &[Ty<'tcx>],
- b_args: &[Ty<'tcx>])
- -> cres<'tcx, Vec<Ty<'tcx>>>
- where C: Combine<'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.tys_with_variance(ty::Contravariant, a, b).and_then(|t| Ok(t))
- }
-
- fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> {
- if a != b {
- Err(ty::terr_unsafety_mismatch(expected_found(self, a, b)))
- } else {
- Ok(a)
- }
- }
-
- fn abi(&self, a: abi::Abi, b: abi::Abi) -> cres<'tcx, abi::Abi> {
- if a == b {
- Ok(a)
- } else {
- Err(ty::terr_abi_mismatch(expected_found(self, a, b)))
- }
- }
-
- fn projection_tys(&self,
- a: &ty::ProjectionTy<'tcx>,
- b: &ty::ProjectionTy<'tcx>)
- -> cres<'tcx, ty::ProjectionTy<'tcx>>
- {
- if a.item_name != b.item_name {
- Err(ty::terr_projection_name_mismatched(
- expected_found(self, a.item_name, b.item_name)))
- } else {
- let trait_ref = try!(self.trait_refs(&*a.trait_ref, &*b.trait_ref));
- Ok(ty::ProjectionTy { trait_ref: Rc::new(trait_ref), item_name: a.item_name })
- }
- }
-
- fn projection_predicates(&self,
- a: &ty::ProjectionPredicate<'tcx>,
- b: &ty::ProjectionPredicate<'tcx>)
- -> cres<'tcx, ty::ProjectionPredicate<'tcx>>
- {
- let projection_ty = try!(self.projection_tys(&a.projection_ty, &b.projection_ty));
- let ty = try!(self.tys(a.ty, b.ty));
- Ok(ty::ProjectionPredicate { projection_ty: projection_ty, ty: ty })
- }
-
- fn projection_bounds(&self,
- a: &Vec<ty::PolyProjectionPredicate<'tcx>>,
- b: &Vec<ty::PolyProjectionPredicate<'tcx>>)
- -> cres<'tcx, Vec<ty::PolyProjectionPredicate<'tcx>>>
- {
- // To be compatible, `a` and `b` must be for precisely the
- // same set of traits and item names. We always require that
- // projection bounds lists are sorted by trait-def-id and item-name,
- // so we can just iterate through the lists pairwise, so long as they are the
- // same length.
- if a.len() != b.len() {
- Err(ty::terr_projection_bounds_length(expected_found(self, a.len(), b.len())))
- } else {
- a.iter()
- .zip(b.iter())
- .map(|(a, b)| self.binders(a, b))
- .collect()
- }
- }
-
- fn existential_bounds(&self,
- a: &ty::ExistentialBounds<'tcx>,
- b: &ty::ExistentialBounds<'tcx>)
- -> cres<'tcx, ty::ExistentialBounds<'tcx>>
- {
- let r = try!(self.regions_with_variance(ty::Contravariant, a.region_bound, b.region_bound));
- let nb = try!(self.builtin_bounds(a.builtin_bounds, b.builtin_bounds));
- let pb = try!(self.projection_bounds(&a.projection_bounds, &b.projection_bounds));
- Ok(ty::ExistentialBounds { region_bound: r,
- builtin_bounds: nb,
- projection_bounds: pb })
- }
-
- fn builtin_bounds(&self,
- a: BuiltinBounds,
- b: BuiltinBounds)
- -> cres<'tcx, BuiltinBounds>
- {
- // Two sets of builtin bounds are only relatable if they are
- // precisely the same (but see the coercion code).
- if a != b {
- Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
- } else {
- Ok(a)
- }
- }
-
- fn trait_refs(&self,
- 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(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: self.tcx().mk_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,T> Combineable<'tcx> for Rc<T>
- where T : Combineable<'tcx>
-{
- fn combine<C>(combiner: &C,
- a: &Rc<T>,
- b: &Rc<T>)
- -> cres<'tcx, Rc<T>>
- where C: Combine<'tcx> {
- Ok(Rc::new(try!(Combineable::combine(combiner, &**a, &**b))))
- }
-}
-
-impl<'tcx> Combineable<'tcx> for ty::TraitRef<'tcx> {
- fn combine<C>(combiner: &C,
- a: &ty::TraitRef<'tcx>,
- b: &ty::TraitRef<'tcx>)
- -> cres<'tcx, ty::TraitRef<'tcx>>
- where C: Combine<'tcx> {
- combiner.trait_refs(a, b)
- }
-}
-
-impl<'tcx> Combineable<'tcx> for Ty<'tcx> {
- fn combine<C>(combiner: &C,
- a: &Ty<'tcx>,
- b: &Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>
- where C: Combine<'tcx> {
- combiner.tys(*a, *b)
- }
-}
-
-impl<'tcx> Combineable<'tcx> for ty::ProjectionPredicate<'tcx> {
- fn combine<C>(combiner: &C,
- a: &ty::ProjectionPredicate<'tcx>,
- b: &ty::ProjectionPredicate<'tcx>)
- -> cres<'tcx, ty::ProjectionPredicate<'tcx>>
- where C: Combine<'tcx> {
- combiner.projection_predicates(a, b)
- }
-}
-
-impl<'tcx> Combineable<'tcx> for ty::FnSig<'tcx> {
- fn combine<C>(combiner: &C,
- a: &ty::FnSig<'tcx>,
- b: &ty::FnSig<'tcx>)
- -> cres<'tcx, ty::FnSig<'tcx>>
- where C: Combine<'tcx> {
- combiner.fn_sigs(a, b)
- }
-}
-
#[derive(Clone)]
pub struct CombineFields<'a, 'tcx: 'a> {
pub infcx: &'a InferCtxt<'a, 'tcx>,
pub trace: TypeTrace<'tcx>,
}
-pub fn expected_found<'tcx, C, T>(this: &C,
- a: T,
- b: T)
- -> ty::expected_found<T>
- where C: Combine<'tcx> {
- if this.a_is_expected() {
- ty::expected_found {expected: a, found: b}
- } else {
- ty::expected_found {expected: b, found: a}
- }
-}
-
-pub fn super_tys<'tcx, C>(this: &C,
- a: Ty<'tcx>,
- b: Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>
- where C: Combine<'tcx> {
- let tcx = this.infcx().tcx;
- let a_sty = &a.sty;
- let b_sty = &b.sty;
- debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty);
- return match (a_sty, b_sty) {
- // The "subtype" ought to be handling cases involving var:
- (&ty::ty_infer(TyVar(_)), _)
- | (_, &ty::ty_infer(TyVar(_))) =>
- tcx.sess.bug(
- &format!("{}: bot and var types should have been handled ({},{})",
- this.tag(),
- a.repr(this.infcx().tcx),
- b.repr(this.infcx().tcx))),
-
- (&ty::ty_err, _) | (_, &ty::ty_err) => Ok(tcx.types.err),
+pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>,
+ relation: &mut R,
+ a: Ty<'tcx>,
+ b: Ty<'tcx>)
+ -> RelateResult<'tcx, Ty<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+{
+ let a_is_expected = relation.a_is_expected();
+ match (&a.sty, &b.sty) {
// Relate integral variables to other types
- (&ty::ty_infer(IntVar(a_id)), &ty::ty_infer(IntVar(b_id))) => {
- try!(this.infcx().simple_vars(this.a_is_expected(),
- a_id, b_id));
+ (&ty::ty_infer(ty::IntVar(a_id)), &ty::ty_infer(ty::IntVar(b_id))) => {
+ try!(infcx.int_unification_table
+ .borrow_mut()
+ .unify_var_var(a_id, b_id)
+ .map_err(|e| int_unification_error(a_is_expected, e)));
Ok(a)
}
- (&ty::ty_infer(IntVar(v_id)), &ty::ty_int(v)) => {
- unify_integral_variable(this, this.a_is_expected(),
- v_id, IntType(v))
+ (&ty::ty_infer(ty::IntVar(v_id)), &ty::ty_int(v)) => {
+ unify_integral_variable(infcx, a_is_expected, v_id, IntType(v))
}
- (&ty::ty_int(v), &ty::ty_infer(IntVar(v_id))) => {
- unify_integral_variable(this, !this.a_is_expected(),
- v_id, IntType(v))
+ (&ty::ty_int(v), &ty::ty_infer(ty::IntVar(v_id))) => {
+ unify_integral_variable(infcx, !a_is_expected, v_id, IntType(v))
}
- (&ty::ty_infer(IntVar(v_id)), &ty::ty_uint(v)) => {
- unify_integral_variable(this, this.a_is_expected(),
- v_id, UintType(v))
+ (&ty::ty_infer(ty::IntVar(v_id)), &ty::ty_uint(v)) => {
+ unify_integral_variable(infcx, a_is_expected, v_id, UintType(v))
}
- (&ty::ty_uint(v), &ty::ty_infer(IntVar(v_id))) => {
- unify_integral_variable(this, !this.a_is_expected(),
- v_id, UintType(v))
+ (&ty::ty_uint(v), &ty::ty_infer(ty::IntVar(v_id))) => {
+ unify_integral_variable(infcx, !a_is_expected, v_id, UintType(v))
}
// Relate floating-point variables to other types
- (&ty::ty_infer(FloatVar(a_id)), &ty::ty_infer(FloatVar(b_id))) => {
- try!(this.infcx().simple_vars(this.a_is_expected(), a_id, b_id));
+ (&ty::ty_infer(ty::FloatVar(a_id)), &ty::ty_infer(ty::FloatVar(b_id))) => {
+ try!(infcx.float_unification_table
+ .borrow_mut()
+ .unify_var_var(a_id, b_id)
+ .map_err(|e| float_unification_error(relation.a_is_expected(), e)));
Ok(a)
}
- (&ty::ty_infer(FloatVar(v_id)), &ty::ty_float(v)) => {
- unify_float_variable(this, this.a_is_expected(), v_id, v)
- }
- (&ty::ty_float(v), &ty::ty_infer(FloatVar(v_id))) => {
- unify_float_variable(this, !this.a_is_expected(), v_id, v)
+ (&ty::ty_infer(ty::FloatVar(v_id)), &ty::ty_float(v)) => {
+ unify_float_variable(infcx, a_is_expected, v_id, v)
}
-
- (&ty::ty_char, _)
- | (&ty::ty_bool, _)
- | (&ty::ty_int(_), _)
- | (&ty::ty_uint(_), _)
- | (&ty::ty_float(_), _) => {
- if a == b {
- Ok(a)
- } else {
- Err(ty::terr_sorts(expected_found(this, a, b)))
- }
+ (&ty::ty_float(v), &ty::ty_infer(ty::FloatVar(v_id))) => {
+ unify_float_variable(infcx, !a_is_expected, v_id, v)
}
- (&ty::ty_param(ref a_p), &ty::ty_param(ref b_p)) if
- a_p.idx == b_p.idx && a_p.space == b_p.space => Ok(a),
-
- (&ty::ty_enum(a_id, a_substs), &ty::ty_enum(b_id, b_substs))
- if a_id == b_id => {
- let substs = try!(this.substs(a_id, a_substs, b_substs));
- Ok(ty::mk_enum(tcx, a_id, tcx.mk_substs(substs)))
+ // All other cases of inference are errors
+ (&ty::ty_infer(_), _) |
+ (_, &ty::ty_infer(_)) => {
+ Err(ty::terr_sorts(ty_relate::expected_found(relation, &a, &b)))
}
- (&ty::ty_trait(ref a_), &ty::ty_trait(ref b_)) => {
- debug!("Trying to match traits {:?} and {:?}", a, b);
- 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))
- }
-
- (&ty::ty_struct(a_id, a_substs), &ty::ty_struct(b_id, b_substs))
- if a_id == b_id => {
- let substs = try!(this.substs(a_id, a_substs, b_substs));
- Ok(ty::mk_struct(tcx, a_id, tcx.mk_substs(substs)))
- }
-
- (&ty::ty_closure(a_id, a_substs),
- &ty::ty_closure(b_id, b_substs))
- if a_id == b_id => {
- // All ty_closure types with the same id represent
- // the (anonymous) type of the same closure expression. So
- // all of their regions should be equated.
- let substs = try!(this.substs_variances(None, a_substs, b_substs));
- Ok(ty::mk_closure(tcx, a_id, tcx.mk_substs(substs)))
- }
- (&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => {
- let typ = try!(this.tys(a_inner, b_inner));
- Ok(ty::mk_uniq(tcx, typ))
- }
-
- (&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) => {
- let mt = try!(this.mts(a_mt, b_mt));
- Ok(ty::mk_ptr(tcx, mt))
- }
-
- (&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => {
- let r = try!(this.regions_with_variance(ty::Contravariant, *a_r, *b_r));
- let mt = try!(this.mts(a_mt, b_mt));
- Ok(ty::mk_rptr(tcx, tcx.mk_region(r), mt))
- }
-
- (&ty::ty_vec(a_t, Some(sz_a)), &ty::ty_vec(b_t, Some(sz_b))) => {
- this.tys(a_t, b_t).and_then(|t| {
- if sz_a == sz_b {
- Ok(ty::mk_vec(tcx, t, Some(sz_a)))
- } else {
- Err(ty::terr_fixed_array_size(expected_found(this, sz_a, sz_b)))
- }
- })
- }
-
- (&ty::ty_vec(a_t, sz_a), &ty::ty_vec(b_t, sz_b)) => {
- this.tys(a_t, b_t).and_then(|t| {
- if sz_a == sz_b {
- Ok(ty::mk_vec(tcx, t, sz_a))
- } else {
- Err(ty::terr_sorts(expected_found(this, a, b)))
- }
- })
- }
-
- (&ty::ty_str, &ty::ty_str) => Ok(ty::mk_str(tcx)),
-
- (&ty::ty_tup(ref as_), &ty::ty_tup(ref bs)) => {
- if as_.len() == bs.len() {
- as_.iter().zip(bs.iter())
- .map(|(a, b)| this.tys(*a, *b))
- .collect::<Result<_, _>>()
- .map(|ts| ty::mk_tup(tcx, ts))
- } else if as_.len() != 0 && bs.len() != 0 {
- Err(ty::terr_tuple_size(
- expected_found(this, as_.len(), bs.len())))
- } else {
- Err(ty::terr_sorts(expected_found(this, a, b)))
- }
- }
-
- (&ty::ty_bare_fn(a_opt_def_id, a_fty), &ty::ty_bare_fn(b_opt_def_id, b_fty))
- if a_opt_def_id == b_opt_def_id =>
- {
- let fty = try!(this.bare_fn_tys(a_fty, b_fty));
- Ok(ty::mk_bare_fn(tcx, a_opt_def_id, tcx.mk_bare_fn(fty)))
- }
-
- (&ty::ty_projection(ref a_data), &ty::ty_projection(ref b_data)) => {
- let projection_ty = try!(this.projection_tys(a_data, b_data));
- Ok(ty::mk_projection(tcx, projection_ty.trait_ref, projection_ty.item_name))
- }
-
- _ => Err(ty::terr_sorts(expected_found(this, a, b))),
- };
-
- fn unify_integral_variable<'tcx, C>(this: &C,
- vid_is_expected: bool,
- vid: ty::IntVid,
- val: ty::IntVarValue)
- -> cres<'tcx, Ty<'tcx>>
- where C: Combine<'tcx> {
- try!(this.infcx().simple_var_t(vid_is_expected, vid, val));
- match val {
- IntType(v) => Ok(ty::mk_mach_int(this.tcx(), v)),
- UintType(v) => Ok(ty::mk_mach_uint(this.tcx(), v)),
+ _ => {
+ ty_relate::super_relate_tys(relation, a, b)
}
}
+}
- fn unify_float_variable<'tcx, C>(this: &C,
- vid_is_expected: bool,
- vid: ty::FloatVid,
- val: ast::FloatTy)
- -> cres<'tcx, Ty<'tcx>>
- where C: Combine<'tcx> {
- try!(this.infcx().simple_var_t(vid_is_expected, vid, val));
- Ok(ty::mk_mach_float(this.tcx(), val))
+fn unify_integral_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
+ vid_is_expected: bool,
+ vid: ty::IntVid,
+ val: ty::IntVarValue)
+ -> RelateResult<'tcx, Ty<'tcx>>
+{
+ try!(infcx
+ .int_unification_table
+ .borrow_mut()
+ .unify_var_value(vid, val)
+ .map_err(|e| int_unification_error(vid_is_expected, e)));
+ match val {
+ IntType(v) => Ok(ty::mk_mach_int(infcx.tcx, v)),
+ UintType(v) => Ok(ty::mk_mach_uint(infcx.tcx, v)),
}
}
-impl<'f, 'tcx> CombineFields<'f, 'tcx> {
- pub fn switch_expected(&self) -> CombineFields<'f, 'tcx> {
+fn unify_float_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
+ vid_is_expected: bool,
+ vid: ty::FloatVid,
+ val: ast::FloatTy)
+ -> RelateResult<'tcx, Ty<'tcx>>
+{
+ try!(infcx
+ .float_unification_table
+ .borrow_mut()
+ .unify_var_value(vid, val)
+ .map_err(|e| float_unification_error(vid_is_expected, e)));
+ Ok(ty::mk_mach_float(infcx.tcx, val))
+}
+
+impl<'a, 'tcx> CombineFields<'a, 'tcx> {
+ pub fn tcx(&self) -> &'a ty::ctxt<'tcx> {
+ self.infcx.tcx
+ }
+
+ pub fn switch_expected(&self) -> CombineFields<'a, 'tcx> {
CombineFields {
a_is_expected: !self.a_is_expected,
..(*self).clone()
}
}
- fn equate(&self) -> Equate<'f, 'tcx> {
- Equate((*self).clone())
+ pub fn equate(&self) -> Equate<'a, 'tcx> {
+ Equate::new(self.clone())
+ }
+
+ pub fn bivariate(&self) -> Bivariate<'a, 'tcx> {
+ Bivariate::new(self.clone())
+ }
+
+ pub fn sub(&self) -> Sub<'a, 'tcx> {
+ Sub::new(self.clone())
}
- fn bivariate(&self) -> Bivariate<'f, 'tcx> {
- Bivariate((*self).clone())
+ pub fn lub(&self) -> Lub<'a, 'tcx> {
+ Lub::new(self.clone())
}
- fn sub(&self) -> Sub<'f, 'tcx> {
- Sub((*self).clone())
+ pub fn glb(&self) -> Glb<'a, 'tcx> {
+ Glb::new(self.clone())
}
pub fn instantiate(&self,
a_ty: Ty<'tcx>,
dir: RelationDir,
b_vid: ty::TyVid)
- -> cres<'tcx, ()>
+ -> RelateResult<'tcx, ()>
{
let tcx = self.infcx.tcx;
let mut stack = Vec::new();
// relations wind up attributed to the same spans. We need
// to associate causes/spans with each of the relations in
// the stack to get this right.
- match dir {
- BiTo => try!(self.bivariate().tys(a_ty, b_ty)),
-
- EqTo => try!(self.equate().tys(a_ty, b_ty)),
-
- SubtypeOf => try!(self.sub().tys(a_ty, b_ty)),
-
- SupertypeOf => try!(self.sub().tys_with_variance(ty::Contravariant, a_ty, b_ty)),
- };
+ try!(match dir {
+ BiTo => self.bivariate().relate(&a_ty, &b_ty),
+ EqTo => self.equate().relate(&a_ty, &b_ty),
+ SubtypeOf => self.sub().relate(&a_ty, &b_ty),
+ SupertypeOf => self.sub().relate_with_variance(ty::Contravariant, &a_ty, &b_ty),
+ });
}
Ok(())
ty: Ty<'tcx>,
for_vid: ty::TyVid,
make_region_vars: bool)
- -> cres<'tcx, Ty<'tcx>>
+ -> RelateResult<'tcx, Ty<'tcx>>
{
let mut generalize = Generalizer {
infcx: self.infcx,
self.infcx.next_region_var(MiscVariable(self.span))
}
}
+
+pub trait RelateResultCompare<'tcx, T> {
+ fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T> where
+ F: FnOnce() -> ty::type_err<'tcx>;
+}
+
+impl<'tcx, T:Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<'tcx, T> {
+ fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T> where
+ F: FnOnce() -> ty::type_err<'tcx>,
+ {
+ self.clone().and_then(|s| {
+ if s == t {
+ self.clone()
+ } else {
+ Err(f())
+ }
+ })
+ }
+}
+
+fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::IntVarValue))
+ -> ty::type_err<'tcx>
+{
+ let (a, b) = v;
+ ty::terr_int_mismatch(ty_relate::expected_found_bool(a_is_expected, &a, &b))
+}
+
+fn float_unification_error<'tcx>(a_is_expected: bool,
+ v: (ast::FloatTy, ast::FloatTy))
+ -> ty::type_err<'tcx>
+{
+ let (a, b) = v;
+ ty::terr_float_mismatch(ty_relate::expected_found_bool(a_is_expected, &a, &b))
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use super::combine::{self, CombineFields};
+use super::higher_ranked::HigherRankedRelations;
+use super::{Subtype};
+use super::type_variable::{EqTo};
+
use middle::ty::{self, Ty};
use middle::ty::TyVar;
-use middle::infer::combine::*;
-use middle::infer::cres;
-use middle::infer::Subtype;
-use middle::infer::type_variable::EqTo;
-use util::ppaux::Repr;
+use middle::ty_relate::{Relate, RelateResult, TypeRelation};
+use util::ppaux::{Repr};
-pub struct Equate<'f, 'tcx: 'f> {
- fields: CombineFields<'f, 'tcx>
+pub struct Equate<'a, 'tcx: 'a> {
+ fields: CombineFields<'a, 'tcx>
}
-#[allow(non_snake_case)]
-pub fn Equate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Equate<'f, 'tcx> {
- Equate { fields: cf }
+impl<'a, 'tcx> Equate<'a, 'tcx> {
+ pub fn new(fields: CombineFields<'a, 'tcx>) -> Equate<'a, 'tcx> {
+ Equate { fields: fields }
+ }
}
-impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> {
- fn tag(&self) -> String { "Equate".to_string() }
- fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
+impl<'a, 'tcx> TypeRelation<'a,'tcx> for Equate<'a, 'tcx> {
+ fn tag(&self) -> &'static str { "Equate" }
- fn tys_with_variance(&self, _: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>
- {
- // Once we're equating, it doesn't matter what the variance is.
- self.tys(a, b)
- }
+ fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() }
- fn regions_with_variance(&self, _: ty::Variance, a: ty::Region, b: ty::Region)
- -> cres<'tcx, ty::Region>
- {
- // Once we're equating, it doesn't matter what the variance is.
- self.regions(a, b)
- }
+ fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
- fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
- debug!("{}.regions({}, {})",
- self.tag(),
- a.repr(self.fields.infcx.tcx),
- b.repr(self.fields.infcx.tcx));
- self.infcx().region_vars.make_eqregion(Subtype(self.trace()), a, b);
- Ok(a)
+ fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
+ _: ty::Variance,
+ a: &T,
+ b: &T)
+ -> RelateResult<'tcx, T>
+ {
+ self.relate(a, b)
}
- fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
+ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug!("{}.tys({}, {})", self.tag(),
a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
if a == b { return Ok(a); }
}
_ => {
- super_tys(self, a, b)
+ combine::super_combine_tys(self.fields.infcx, self, a, b)
}
}
}
- fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
- where T : Combineable<'tcx>
+ fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
+ debug!("{}.regions({}, {})",
+ self.tag(),
+ a.repr(self.fields.infcx.tcx),
+ b.repr(self.fields.infcx.tcx));
+ let origin = Subtype(self.fields.trace.clone());
+ self.fields.infcx.region_vars.make_eqregion(origin, a, b);
+ Ok(a)
+ }
+
+ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
+ -> RelateResult<'tcx, ty::Binder<T>>
+ where T: Relate<'a, 'tcx>
{
- try!(self.sub().binders(a, b));
- self.sub().binders(b, a)
+ try!(self.fields.higher_ranked_sub(a, b));
+ self.fields.higher_ranked_sub(b, a)
}
}
use std::collections::hash_map::{self, Entry};
use super::InferCtxt;
-use super::unify::InferCtxtMethodsForSimplyUnifiableTypes;
+use super::unify::ToType;
pub struct TypeFreshener<'a, 'tcx:'a> {
infcx: &'a InferCtxt<'a, 'tcx>,
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ let tcx = self.infcx.tcx;
+
match t.sty {
ty::ty_infer(ty::TyVar(v)) => {
- self.freshen(self.infcx.type_variables.borrow().probe(v),
- ty::TyVar(v),
- ty::FreshTy)
+ self.freshen(
+ self.infcx.type_variables.borrow().probe(v),
+ ty::TyVar(v),
+ ty::FreshTy)
}
ty::ty_infer(ty::IntVar(v)) => {
- self.freshen(self.infcx.probe_var(v),
- ty::IntVar(v),
- ty::FreshIntTy)
+ self.freshen(
+ self.infcx.int_unification_table.borrow_mut()
+ .probe(v)
+ .map(|v| v.to_type(tcx)),
+ ty::IntVar(v),
+ ty::FreshIntTy)
}
ty::ty_infer(ty::FloatVar(v)) => {
- self.freshen(self.infcx.probe_var(v),
- ty::FloatVar(v),
- ty::FreshIntTy)
+ self.freshen(
+ self.infcx.float_unification_table.borrow_mut()
+ .probe(v)
+ .map(|v| v.to_type(tcx)),
+ ty::FloatVar(v),
+ ty::FreshIntTy)
}
ty::ty_infer(ty::FreshTy(c)) |
ty::ty_infer(ty::FreshIntTy(c)) => {
if c >= self.freshen_count {
- self.tcx().sess.bug(
+ tcx.sess.bug(
&format!("Encountered a freshend type with id {} \
but our counter is only at {}",
c,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use super::combine::*;
-use super::lattice::*;
+use super::combine::CombineFields;
use super::higher_ranked::HigherRankedRelations;
-use super::cres;
+use super::InferCtxt;
+use super::lattice::{self, LatticeDir};
use super::Subtype;
use middle::ty::{self, Ty};
+use middle::ty_relate::{Relate, RelateResult, TypeRelation};
use util::ppaux::Repr;
/// "Greatest lower bound" (common subtype)
-pub struct Glb<'f, 'tcx: 'f> {
- fields: CombineFields<'f, 'tcx>
+pub struct Glb<'a, 'tcx: 'a> {
+ fields: CombineFields<'a, 'tcx>
}
-#[allow(non_snake_case)]
-pub fn Glb<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Glb<'f, 'tcx> {
- Glb { fields: cf }
+impl<'a, 'tcx> Glb<'a, 'tcx> {
+ pub fn new(fields: CombineFields<'a, 'tcx>) -> Glb<'a, 'tcx> {
+ Glb { fields: fields }
+ }
}
-impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> {
- fn tag(&self) -> String { "Glb".to_string() }
- fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
+impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Glb<'a, 'tcx> {
+ fn tag(&self) -> &'static str { "Glb" }
+
+ fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() }
+
+ fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
- fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>
+ fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
+ variance: ty::Variance,
+ a: &T,
+ b: &T)
+ -> RelateResult<'tcx, T>
{
- match v {
- ty::Invariant => self.equate().tys(a, b),
- ty::Covariant => self.tys(a, b),
- ty::Bivariant => self.bivariate().tys(a, b),
- ty::Contravariant => self.lub().tys(a, b),
+ match variance {
+ ty::Invariant => self.fields.equate().relate(a, b),
+ ty::Covariant => self.relate(a, b),
+ ty::Bivariant => self.fields.bivariate().relate(a, b),
+ ty::Contravariant => self.fields.lub().relate(a, b),
}
}
- fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
- -> cres<'tcx, ty::Region>
- {
- match v {
- ty::Invariant => self.equate().regions(a, b),
- ty::Covariant => self.regions(a, b),
- ty::Bivariant => self.bivariate().regions(a, b),
- ty::Contravariant => self.lub().regions(a, b),
- }
+ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+ lattice::super_lattice_tys(self, a, b)
}
- fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
+ fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
debug!("{}.regions({}, {})",
self.tag(),
a.repr(self.fields.infcx.tcx),
b.repr(self.fields.infcx.tcx));
- Ok(self.fields.infcx.region_vars.glb_regions(Subtype(self.trace()), a, b))
+ let origin = Subtype(self.fields.trace.clone());
+ Ok(self.fields.infcx.region_vars.glb_regions(origin, a, b))
}
- fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
- super_lattice_tys(self, a, b)
+ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
+ -> RelateResult<'tcx, ty::Binder<T>>
+ where T: Relate<'a, 'tcx>
+ {
+ self.fields.higher_ranked_glb(a, b)
}
+}
- 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)
+impl<'a, 'tcx> LatticeDir<'a,'tcx> for Glb<'a, 'tcx> {
+ fn infcx(&self) -> &'a InferCtxt<'a,'tcx> {
+ self.fields.infcx
+ }
+
+ fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
+ let mut sub = self.fields.sub();
+ try!(sub.relate(&v, &a));
+ try!(sub.relate(&v, &b));
+ Ok(())
}
}
//! Helper routines for higher-ranked things. See the `doc` module at
//! the end of the file for details.
-use super::{CombinedSnapshot, cres, InferCtxt, HigherRankedType, SkolemizationMap};
-use super::combine::{Combine, Combineable};
+use super::{CombinedSnapshot, InferCtxt, HigherRankedType, SkolemizationMap};
+use super::combine::CombineFields;
use middle::subst;
use middle::ty::{self, Binder};
use middle::ty_fold::{self, TypeFoldable};
+use middle::ty_relate::{Relate, RelateResult, TypeRelation};
use syntax::codemap::Span;
use util::nodemap::{FnvHashMap, FnvHashSet};
use util::ppaux::Repr;
-pub trait HigherRankedRelations<'tcx> {
- fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>>
- where T : Combineable<'tcx>;
+pub trait HigherRankedRelations<'a,'tcx> {
+ fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
+ where T: Relate<'a,'tcx>;
- fn higher_ranked_lub<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>) -> RelateResult<'tcx, Binder<T>>
+ where T: Relate<'a,'tcx>;
- fn higher_ranked_glb<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>) -> RelateResult<'tcx, Binder<T>>
+ where T: Relate<'a,'tcx>;
}
trait InferCtxtExt {
-> Vec<ty::RegionVid>;
}
-impl<'tcx,C> HigherRankedRelations<'tcx> for C
- where C : Combine<'tcx>
-{
+impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> {
fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>)
- -> cres<'tcx, Binder<T>>
- where T : Combineable<'tcx>
+ -> RelateResult<'tcx, Binder<T>>
+ where T: Relate<'a,'tcx>
{
+ let tcx = self.infcx.tcx;
+
debug!("higher_ranked_sub(a={}, b={})",
- a.repr(self.tcx()), b.repr(self.tcx()));
+ a.repr(tcx), b.repr(tcx));
// Rather than checking the subtype relationship between `a` and `b`
// as-is, we need to do some extra work here in order to make sure
// Start a snapshot so we can examine "all bindings that were
// created as part of this type comparison".
- return self.infcx().try(|snapshot| {
+ return self.infcx.commit_if_ok(|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(),
+ 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);
+ self.infcx.skolemize_late_bound_regions(b, snapshot);
- debug!("a_prime={}", a_prime.repr(self.tcx()));
- debug!("b_prime={}", b_prime.repr(self.tcx()));
+ debug!("a_prime={}", a_prime.repr(tcx));
+ debug!("b_prime={}", b_prime.repr(tcx));
// Compare types now that bound regions have been replaced.
- let result = try!(Combineable::combine(self, &a_prime, &b_prime));
+ let result = try!(self.sub().relate(&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) {
+ match leak_check(self.infcx, &skol_map, snapshot) {
Ok(()) => { }
Err((skol_br, tainted_region)) => {
- if self.a_is_expected() {
+ if self.a_is_expected {
debug!("Not as polymorphic!");
return Err(ty::terr_regions_insufficiently_polymorphic(skol_br,
tainted_region));
}
debug!("higher_ranked_sub: OK result={}",
- result.repr(self.tcx()));
+ result.repr(tcx));
Ok(ty::Binder(result))
});
}
- fn higher_ranked_lub<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>) -> RelateResult<'tcx, Binder<T>>
+ where T: Relate<'a,'tcx>
{
// Start a snapshot so we can examine "all bindings that were
// created as part of this type comparison".
- return self.infcx().try(|snapshot| {
+ return self.infcx.commit_if_ok(|snapshot| {
// Instantiate each bound region with a fresh region variable.
- let span = self.trace().origin.span();
+ let span = self.trace.origin.span();
let (a_with_fresh, a_map) =
- self.infcx().replace_late_bound_regions_with_fresh_var(
+ 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(
+ 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));
+ try!(self.lub().relate(&a_with_fresh, &b_with_fresh));
let result0 =
- self.infcx().resolve_type_vars_if_possible(&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 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,
+ |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
&new_vars, &a_map, r));
debug!("lub({},{}) = {}",
}
}
- fn higher_ranked_glb<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>) -> RelateResult<'tcx, Binder<T>>
+ where T: Relate<'a,'tcx>
{
- debug!("{}.higher_ranked_glb({}, {})",
- self.tag(), a.repr(self.tcx()), b.repr(self.tcx()));
+ debug!("higher_ranked_glb({}, {})",
+ a.repr(self.tcx()), b.repr(self.tcx()));
// Make a snapshot so we can examine "all bindings that were
// created as part of this type comparison".
- return self.infcx().try(|snapshot| {
+ return self.infcx.commit_if_ok(|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);
+ 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);
+ 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));
+ try!(self.glb().relate(&a_with_fresh, &b_with_fresh));
let result0 =
- self.infcx().resolve_type_vars_if_possible(&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 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,
+ |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
&new_vars,
&a_map, &a_vars, &b_vars,
r));
}
}
-fn var_ids<'tcx, T: Combine<'tcx>>(combiner: &T,
- map: &FnvHashMap<ty::BoundRegion, ty::Region>)
- -> Vec<ty::RegionVid> {
- map.iter().map(|(_, r)| match *r {
- ty::ReInfer(ty::ReVar(r)) => { r }
- r => {
- combiner.infcx().tcx.sess.span_bug(
- combiner.trace().origin.span(),
- &format!("found non-region-vid: {:?}", r));
- }
- }).collect()
+fn var_ids<'a, 'tcx>(fields: &CombineFields<'a, 'tcx>,
+ map: &FnvHashMap<ty::BoundRegion, ty::Region>)
+ -> Vec<ty::RegionVid> {
+ map.iter()
+ .map(|(_, r)| match *r {
+ ty::ReInfer(ty::ReVar(r)) => { r }
+ r => {
+ fields.tcx().sess.span_bug(
+ fields.trace.origin.span(),
+ &format!("found non-region-vid: {:?}", r));
+ }
+ })
+ .collect()
}
fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool {
unbound_value: &T,
mut fldr: F)
-> T
- where T : Combineable<'tcx>,
- F : FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region,
+ where T: TypeFoldable<'tcx>,
+ F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region,
{
unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, &mut |region, current_depth| {
// we should only be encountering "escaping" late-bound regions here,
//! over a `LatticeValue`, which is a value defined with respect to
//! a lattice.
-use super::*;
-use super::combine::*;
-use super::glb::Glb;
-use super::lub::Lub;
+use super::combine;
+use super::InferCtxt;
use middle::ty::TyVar;
use middle::ty::{self, Ty};
+use middle::ty_relate::{RelateResult, TypeRelation};
use util::ppaux::Repr;
-pub trait LatticeDir<'tcx> {
+pub trait LatticeDir<'f,'tcx> : TypeRelation<'f,'tcx> {
+ fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>;
+
// Relates the type `v` to `a` and `b` such that `v` represents
// the LUB/GLB of `a` and `b` as appropriate.
- fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, ()>;
-}
-
-impl<'a, 'tcx> LatticeDir<'tcx> for Lub<'a, 'tcx> {
- fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, ()> {
- let sub = self.sub();
- try!(sub.tys(a, v));
- try!(sub.tys(b, v));
- Ok(())
- }
-}
-
-impl<'a, 'tcx> LatticeDir<'tcx> for Glb<'a, 'tcx> {
- fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, ()> {
- let sub = self.sub();
- try!(sub.tys(v, a));
- try!(sub.tys(v, b));
- Ok(())
- }
+ fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
}
-pub fn super_lattice_tys<'tcx, L:LatticeDir<'tcx>+Combine<'tcx>>(this: &L,
- a: Ty<'tcx>,
- b: Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>
+pub fn super_lattice_tys<'a,'tcx,L:LatticeDir<'a,'tcx>>(this: &mut L,
+ a: Ty<'tcx>,
+ b: Ty<'tcx>)
+ -> RelateResult<'tcx, Ty<'tcx>>
+ where 'tcx: 'a
{
debug!("{}.lattice_tys({}, {})",
this.tag(),
- a.repr(this.infcx().tcx),
- b.repr(this.infcx().tcx));
+ a.repr(this.tcx()),
+ b.repr(this.tcx()));
if a == b {
return Ok(a);
}
_ => {
- super_tys(this, a, b)
+ combine::super_combine_tys(this.infcx(), this, a, b)
}
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use super::combine::*;
+use super::combine::CombineFields;
use super::higher_ranked::HigherRankedRelations;
-use super::lattice::*;
-use super::cres;
+use super::InferCtxt;
+use super::lattice::{self, LatticeDir};
use super::Subtype;
use middle::ty::{self, Ty};
+use middle::ty_relate::{Relate, RelateResult, TypeRelation};
use util::ppaux::Repr;
/// "Least upper bound" (common supertype)
-pub struct Lub<'f, 'tcx: 'f> {
- fields: CombineFields<'f, 'tcx>
+pub struct Lub<'a, 'tcx: 'a> {
+ fields: CombineFields<'a, 'tcx>
}
-#[allow(non_snake_case)]
-pub fn Lub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Lub<'f, 'tcx> {
- Lub { fields: cf }
+impl<'a, 'tcx> Lub<'a, 'tcx> {
+ pub fn new(fields: CombineFields<'a, 'tcx>) -> Lub<'a, 'tcx> {
+ Lub { fields: fields }
+ }
}
-impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> {
- fn tag(&self) -> String { "Lub".to_string() }
- fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
+impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Lub<'a, 'tcx> {
+ fn tag(&self) -> &'static str { "Lub" }
+
+ fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() }
+
+ fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
- fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>
+ fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
+ variance: ty::Variance,
+ a: &T,
+ b: &T)
+ -> RelateResult<'tcx, T>
{
- match v {
- ty::Invariant => self.equate().tys(a, b),
- ty::Covariant => self.tys(a, b),
- ty::Bivariant => self.bivariate().tys(a, b),
- ty::Contravariant => self.glb().tys(a, b),
+ match variance {
+ ty::Invariant => self.fields.equate().relate(a, b),
+ ty::Covariant => self.relate(a, b),
+ ty::Bivariant => self.fields.bivariate().relate(a, b),
+ ty::Contravariant => self.fields.glb().relate(a, b),
}
}
- fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
- -> cres<'tcx, ty::Region>
- {
- match v {
- ty::Invariant => self.equate().regions(a, b),
- ty::Covariant => self.regions(a, b),
- ty::Bivariant => self.bivariate().regions(a, b),
- ty::Contravariant => self.glb().regions(a, b),
- }
+ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+ lattice::super_lattice_tys(self, a, b)
}
- fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
+ fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
debug!("{}.regions({}, {})",
self.tag(),
a.repr(self.tcx()),
b.repr(self.tcx()));
- Ok(self.infcx().region_vars.lub_regions(Subtype(self.trace()), a, b))
+ let origin = Subtype(self.fields.trace.clone());
+ Ok(self.fields.infcx.region_vars.lub_regions(origin, a, b))
}
- fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
- super_lattice_tys(self, a, b)
+ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
+ -> RelateResult<'tcx, ty::Binder<T>>
+ where T: Relate<'a, 'tcx>
+ {
+ self.fields.higher_ranked_lub(a, b)
}
+}
- 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)
+impl<'a, 'tcx> LatticeDir<'a,'tcx> for Lub<'a, 'tcx> {
+ fn infcx(&self) -> &'a InferCtxt<'a,'tcx> {
+ self.fields.infcx
+ }
+
+ fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
+ let mut sub = self.fields.sub();
+ try!(sub.relate(&a, &v));
+ try!(sub.relate(&b, &v));
+ Ok(())
}
}
+
use middle::ty::replace_late_bound_regions;
use middle::ty::{self, Ty};
use middle::ty_fold::{TypeFolder, TypeFoldable};
-use std::cell::RefCell;
+use middle::ty_relate::{Relate, RelateResult, TypeRelation};
+use std::cell::{RefCell};
use std::fmt;
use std::rc::Rc;
use syntax::ast;
use util::ppaux::ty_to_string;
use util::ppaux::{Repr, UserString};
-use self::combine::{Combine, Combineable, CombineFields};
+use self::combine::CombineFields;
use self::region_inference::{RegionVarBindings, RegionSnapshot};
-use self::equate::Equate;
-use self::sub::Sub;
-use self::lub::Lub;
-use self::unify::{UnificationTable, InferCtxtMethodsForSimplyUnifiableTypes};
+use self::unify::{ToType, UnificationTable};
use self::error_reporting::ErrorReporting;
pub mod bivariate;
pub mod unify;
pub type Bound<T> = Option<T>;
-
-pub type cres<'tcx, T> = Result<T,ty::type_err<'tcx>>; // "combine result"
-pub type ures<'tcx> = cres<'tcx, ()>; // "unify result"
+pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
pub type fres<T> = Result<T, fixup_err>; // "fixup result"
pub struct InferCtxt<'a, 'tcx: 'a> {
///
/// See `error_reporting.rs` for more details
#[derive(Clone, Debug)]
-pub enum RegionVariableOrigin<'tcx> {
+pub enum RegionVariableOrigin {
// Region variables created for ill-categorized reasons,
// mostly indicates places in need of refactoring
MiscVariable(Span),
Autoref(Span),
// Regions created as part of an automatic coercion
- Coercion(TypeTrace<'tcx>),
+ Coercion(Span),
// Region variables created as the values for early-bound regions
EarlyBoundRegion(Span, ast::Name),
values: Types(expected_found(a_is_expected, a, b))
};
- let result =
- cx.commit_if_ok(|| cx.lub(a_is_expected, trace.clone()).tys(a, b));
+ let result = cx.commit_if_ok(|_| cx.lub(a_is_expected, trace.clone()).relate(&a, &b));
match result {
Ok(t) => t,
Err(ref err) => {
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
- -> ures<'tcx>
+ -> UnitResult<'tcx>
{
debug!("mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
- cx.commit_if_ok(|| {
- cx.sub_types(a_is_expected, origin, a, b)
- })
+ cx.sub_types(a_is_expected, origin, a, b)
}
pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
a: Ty<'tcx>,
b: Ty<'tcx>)
- -> ures<'tcx> {
+ -> UnitResult<'tcx> {
debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
cx.probe(|_| {
let trace = TypeTrace {
origin: Misc(codemap::DUMMY_SP),
values: Types(expected_found(true, a, b))
};
- cx.sub(true, trace).tys(a, b).to_ures()
+ cx.sub(true, trace).relate(&a, &b).map(|_| ())
})
}
-pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> ures<'tcx>
+pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>)
+ -> UnitResult<'tcx>
{
cx.can_equate(&a, &b)
}
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
- -> ures<'tcx>
+ -> UnitResult<'tcx>
{
debug!("mk_eqty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
- cx.commit_if_ok(
- || cx.eq_types(a_is_expected, origin, a, b))
+ cx.commit_if_ok(|_| cx.eq_types(a_is_expected, origin, a, b))
}
pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
origin: TypeOrigin,
a: ty::PolyTraitRef<'tcx>,
b: ty::PolyTraitRef<'tcx>)
- -> ures<'tcx>
+ -> UnitResult<'tcx>
{
debug!("mk_sub_trait_refs({} <: {})",
a.repr(cx.tcx), b.repr(cx.tcx));
- cx.commit_if_ok(
- || cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone()))
+ cx.commit_if_ok(|_| cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone()))
}
fn expected_found<T>(a_is_expected: bool,
}
}
-trait then<'tcx> {
- fn then<T, F>(&self, f: F) -> Result<T, ty::type_err<'tcx>> where
- T: Clone,
- F: FnOnce() -> Result<T, ty::type_err<'tcx>>;
-}
-
-impl<'tcx> then<'tcx> for ures<'tcx> {
- fn then<T, F>(&self, f: F) -> Result<T, ty::type_err<'tcx>> where
- T: Clone,
- F: FnOnce() -> Result<T, ty::type_err<'tcx>>,
- {
- self.and_then(move |_| f())
- }
-}
-
-trait ToUres<'tcx> {
- fn to_ures(&self) -> ures<'tcx>;
-}
-
-impl<'tcx, T> ToUres<'tcx> for cres<'tcx, T> {
- fn to_ures(&self) -> ures<'tcx> {
- match *self {
- Ok(ref _v) => Ok(()),
- Err(ref e) => Err((*e))
- }
- }
-}
-
-trait CresCompare<'tcx, T> {
- fn compare<F>(&self, t: T, f: F) -> cres<'tcx, T> where
- F: FnOnce() -> ty::type_err<'tcx>;
-}
-
-impl<'tcx, T:Clone + PartialEq> CresCompare<'tcx, T> for cres<'tcx, T> {
- fn compare<F>(&self, t: T, f: F) -> cres<'tcx, T> where
- F: FnOnce() -> ty::type_err<'tcx>,
- {
- (*self).clone().and_then(move |s| {
- if s == t {
- (*self).clone()
- } else {
- Err(f())
- }
- })
- }
-}
-
-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,
use middle::ty::UnconstrainedNumeric::{Neither, UnconstrainedInt, UnconstrainedFloat};
match ty.sty {
ty::ty_infer(ty::IntVar(vid)) => {
- match self.int_unification_table.borrow_mut().get(self.tcx, vid).value {
- None => UnconstrainedInt,
- _ => Neither,
+ if self.int_unification_table.borrow_mut().has_value(vid) {
+ Neither
+ } else {
+ UnconstrainedInt
}
},
ty::ty_infer(ty::FloatVar(vid)) => {
- match self.float_unification_table.borrow_mut().get(self.tcx, vid).value {
- None => return UnconstrainedFloat,
- _ => Neither,
+ if self.float_unification_table.borrow_mut().has_value(vid) {
+ Neither
+ } else {
+ UnconstrainedFloat
}
},
_ => Neither,
}
}
- pub fn combine_fields<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>)
- -> CombineFields<'b, 'tcx> {
+ fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
+ -> CombineFields<'a, 'tcx> {
CombineFields {infcx: self,
a_is_expected: a_is_expected,
trace: trace}
}
- pub fn equate<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>)
- -> Equate<'b, 'tcx> {
- Equate(self.combine_fields(a_is_expected, trace))
+ // public so that it can be used from the rustc_driver unit tests
+ pub fn equate(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
+ -> equate::Equate<'a, 'tcx>
+ {
+ self.combine_fields(a_is_expected, trace).equate()
}
- pub fn sub<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>)
- -> Sub<'b, 'tcx> {
- Sub(self.combine_fields(a_is_expected, trace))
+ // public so that it can be used from the rustc_driver unit tests
+ pub fn sub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
+ -> sub::Sub<'a, 'tcx>
+ {
+ self.combine_fields(a_is_expected, trace).sub()
}
- pub fn lub<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>)
- -> Lub<'b, 'tcx> {
- Lub(self.combine_fields(a_is_expected, trace))
+ // public so that it can be used from the rustc_driver unit tests
+ pub fn lub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
+ -> lub::Lub<'a, 'tcx>
+ {
+ self.combine_fields(a_is_expected, trace).lub()
+ }
+
+ // public so that it can be used from the rustc_driver unit tests
+ pub fn glb(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
+ -> glb::Glb<'a, 'tcx>
+ {
+ self.combine_fields(a_is_expected, trace).glb()
}
fn start_snapshot(&self) -> CombinedSnapshot {
r
}
- /// Execute `f` and commit the bindings if successful
+ /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`
pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E> where
- F: FnOnce() -> Result<T, E>
+ F: FnOnce(&CombinedSnapshot) -> Result<T, E>
{
- self.commit_unconditionally(move || self.try(move |_| f()))
+ debug!("commit_if_ok()");
+ let snapshot = self.start_snapshot();
+ let r = f(&snapshot);
+ debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok());
+ match r {
+ Ok(_) => { self.commit_from(snapshot); }
+ Err(_) => { self.rollback_to(snapshot); }
+ }
+ r
}
/// Execute `f` and commit only the region bindings if successful.
float_snapshot,
region_vars_snapshot } = self.start_snapshot();
- let r = self.try(move |_| f());
+ let r = self.commit_if_ok(|_| f());
// Roll back any non-region bindings - they should be resolved
// inside `f`, with, e.g. `resolve_type_vars_if_possible`.
r
}
- /// Execute `f`, unroll bindings on panic
- pub fn try<T, E, F>(&self, f: F) -> Result<T, E> where
- F: FnOnce(&CombinedSnapshot) -> Result<T, E>
- {
- debug!("try()");
- let snapshot = self.start_snapshot();
- let r = f(&snapshot);
- debug!("try() -- r.is_ok() = {}", r.is_ok());
- match r {
- Ok(_) => {
- self.commit_from(snapshot);
- }
- Err(_) => {
- self.rollback_to(snapshot);
- }
- }
- r
- }
-
/// Execute `f` then unroll any bindings it creates
pub fn probe<R, F>(&self, f: F) -> R where
F: FnOnce(&CombinedSnapshot) -> R,
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
- -> ures<'tcx>
+ -> UnitResult<'tcx>
{
debug!("sub_types({} <: {})", a.repr(self.tcx), b.repr(self.tcx));
- self.commit_if_ok(|| {
+ self.commit_if_ok(|_| {
let trace = TypeTrace::types(origin, a_is_expected, a, b);
- self.sub(a_is_expected, trace).tys(a, b).to_ures()
+ self.sub(a_is_expected, trace).relate(&a, &b).map(|_| ())
})
}
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
- -> ures<'tcx>
+ -> UnitResult<'tcx>
{
- self.commit_if_ok(|| {
+ self.commit_if_ok(|_| {
let trace = TypeTrace::types(origin, a_is_expected, a, b);
- self.equate(a_is_expected, trace).tys(a, b).to_ures()
+ self.equate(a_is_expected, trace).relate(&a, &b).map(|_| ())
})
}
origin: TypeOrigin,
a: Rc<ty::TraitRef<'tcx>>,
b: Rc<ty::TraitRef<'tcx>>)
- -> ures<'tcx>
+ -> UnitResult<'tcx>
{
debug!("sub_trait_refs({} <: {})",
a.repr(self.tcx),
b.repr(self.tcx));
- self.commit_if_ok(|| {
+ self.commit_if_ok(|_| {
let trace = TypeTrace {
origin: origin,
values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
};
- self.sub(a_is_expected, trace).trait_refs(&*a, &*b).to_ures()
+ self.sub(a_is_expected, trace).relate(&*a, &*b).map(|_| ())
})
}
origin: TypeOrigin,
a: ty::PolyTraitRef<'tcx>,
b: ty::PolyTraitRef<'tcx>)
- -> ures<'tcx>
+ -> UnitResult<'tcx>
{
debug!("sub_poly_trait_refs({} <: {})",
a.repr(self.tcx),
b.repr(self.tcx));
- self.commit_if_ok(|| {
+ 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()
+ self.sub(a_is_expected, trace).relate(&a, &b).map(|_| ())
})
}
pub fn leak_check(&self,
skol_map: &SkolemizationMap,
snapshot: &CombinedSnapshot)
- -> ures<'tcx>
+ -> UnitResult<'tcx>
{
/*! See `higher_ranked::leak_check` */
pub fn equality_predicate(&self,
span: Span,
predicate: &ty::PolyEquatePredicate<'tcx>)
- -> ures<'tcx> {
- self.try(|snapshot| {
+ -> UnitResult<'tcx> {
+ self.commit_if_ok(|snapshot| {
let (ty::EquatePredicate(a, b), skol_map) =
self.skolemize_late_bound_regions(predicate, snapshot);
let origin = EquatePredicate(span);
pub fn region_outlives_predicate(&self,
span: Span,
predicate: &ty::PolyRegionOutlivesPredicate)
- -> ures<'tcx> {
- self.try(|snapshot| {
+ -> UnitResult<'tcx> {
+ self.commit_if_ok(|snapshot| {
let (ty::OutlivesPredicate(r_a, r_b), skol_map) =
self.skolemize_late_bound_regions(predicate, snapshot);
let origin = RelateRegionParamBound(span);
.new_key(None)
}
- pub fn next_region_var(&self, origin: RegionVariableOrigin<'tcx>) -> ty::Region {
+ pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region {
ty::ReInfer(ty::ReVar(self.region_vars.new_region_var(origin)))
}
}
ty::ty_infer(ty::IntVar(v)) => {
- self.probe_var(v)
+ self.int_unification_table
+ .borrow_mut()
+ .probe(v)
+ .map(|v| v.to_type(self.tcx))
.unwrap_or(typ)
}
ty::ty_infer(ty::FloatVar(v)) => {
- self.probe_var(v)
+ self.float_unification_table
+ .borrow_mut()
+ .probe(v)
+ .map(|v| v.to_type(self.tcx))
.unwrap_or(typ)
}
self.region_vars.verify_generic_bound(origin, kind, a, bs);
}
- pub fn can_equate<T>(&self, a: &T, b: &T) -> ures<'tcx>
- where T : Combineable<'tcx> + Repr<'tcx>
+ pub fn can_equate<'b,T>(&'b self, a: &T, b: &T) -> UnitResult<'tcx>
+ where T: Relate<'b,'tcx> + Repr<'tcx>
{
debug!("can_equate({}, {})", a.repr(self.tcx), b.repr(self.tcx));
self.probe(|_| {
let e = self.tcx.types.err;
let trace = TypeTrace { origin: Misc(codemap::DUMMY_SP),
values: Types(expected_found(true, e, e)) };
- let eq = self.equate(true, trace);
- Combineable::combine(&eq, a, b)
- }).to_ures()
+ self.equate(true, trace).relate(a, b)
+ }).map(|_| ())
}
}
}
}
-impl<'tcx> RegionVariableOrigin<'tcx> {
+impl RegionVariableOrigin {
pub fn span(&self) -> Span {
match *self {
MiscVariable(a) => a,
PatternRegion(a) => a,
AddrOfRegion(a) => a,
Autoref(a) => a,
- Coercion(ref a) => a.span(),
+ Coercion(a) => a,
EarlyBoundRegion(a, _) => a,
LateBoundRegion(a, _, _) => a,
BoundRegionInCoherence(_) => codemap::DUMMY_SP,
}
}
-impl<'tcx> Repr<'tcx> for RegionVariableOrigin<'tcx> {
+impl<'tcx> Repr<'tcx> for RegionVariableOrigin {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self {
MiscVariable(a) => {
format!("AddrOfRegion({})", a.repr(tcx))
}
Autoref(a) => format!("Autoref({})", a.repr(tcx)),
- Coercion(ref a) => format!("Coercion({})", a.repr(tcx)),
+ Coercion(a) => format!("Coercion({})", a.repr(tcx)),
EarlyBoundRegion(a, b) => {
format!("EarlyBoundRegion({},{})", a.repr(tcx), b.repr(tcx))
}
the borrow expression, we must issue sufficient restrictions to ensure
that the pointee remains valid.
-## Adding closures
-
-The other significant complication to the region hierarchy is
-closures. I will describe here how closures should work, though some
-of the work to implement this model is ongoing at the time of this
-writing.
-
-The body of closures are type-checked along with the function that
-creates them. However, unlike other expressions that appear within the
-function body, it is not entirely obvious when a closure body executes
-with respect to the other expressions. This is because the closure
-body will execute whenever the closure is called; however, we can
-never know precisely when the closure will be called, especially
-without some sort of alias analysis.
-
-However, we can place some sort of limits on when the closure
-executes. In particular, the type of every closure `fn:'r K` includes
-a region bound `'r`. This bound indicates the maximum lifetime of that
-closure; once we exit that region, the closure cannot be called
-anymore. Therefore, we say that the lifetime of the closure body is a
-sublifetime of the closure bound, but the closure body itself is unordered
-with respect to other parts of the code.
-
-For example, consider the following fragment of code:
-
- 'a: {
- let closure: fn:'a() = || 'b: {
- 'c: ...
- };
- 'd: ...
- }
-
-Here we have four lifetimes, `'a`, `'b`, `'c`, and `'d`. The closure
-`closure` is bounded by the lifetime `'a`. The lifetime `'b` is the
-lifetime of the closure body, and `'c` is some statement within the
-closure body. Finally, `'d` is a statement within the outer block that
-created the closure.
-
-We can say that the closure body `'b` is a sublifetime of `'a` due to
-the closure bound. By the usual lexical scoping conventions, the
-statement `'c` is clearly a sublifetime of `'b`, and `'d` is a
-sublifetime of `'d`. However, there is no ordering between `'c` and
-`'d` per se (this kind of ordering between statements is actually only
-an issue for dataflow; passes like the borrow checker must assume that
-closures could execute at any time from the moment they are created
-until they go out of scope).
-
-### Complications due to closure bound inference
-
-There is only one problem with the above model: in general, we do not
-actually *know* the closure bounds during region inference! In fact,
-closure bounds are almost always region variables! This is very tricky
-because the inference system implicitly assumes that we can do things
-like compute the LUB of two scoped lifetimes without needing to know
-the values of any variables.
-
-Here is an example to illustrate the problem:
-
- fn identify<T>(x: T) -> T { x }
-
- fn foo() { // 'foo is the function body
- 'a: {
- let closure = identity(|| 'b: {
- 'c: ...
- });
- 'd: closure();
- }
- 'e: ...;
- }
-
-In this example, the closure bound is not explicit. At compile time,
-we will create a region variable (let's call it `V0`) to represent the
-closure bound.
-
-The primary difficulty arises during the constraint propagation phase.
-Imagine there is some variable with incoming edges from `'c` and `'d`.
-This means that the value of the variable must be `LUB('c,
-'d)`. However, without knowing what the closure bound `V0` is, we
-can't compute the LUB of `'c` and `'d`! Any we don't know the closure
-bound until inference is done.
-
-The solution is to rely on the fixed point nature of inference.
-Basically, when we must compute `LUB('c, 'd)`, we just use the current
-value for `V0` as the closure's bound. If `V0`'s binding should
-change, then we will do another round of inference, and the result of
-`LUB('c, 'd)` will change.
-
-One minor implication of this is that the graph does not in fact track
-the full set of dependencies between edges. We cannot easily know
-whether the result of a LUB computation will change, since there may
-be indirect dependencies on other variables that are not reflected on
-the graph. Therefore, we must *always* iterate over all edges when
-doing the fixed point calculation, not just those adjacent to nodes
-whose values have changed.
-
-Were it not for this requirement, we could in fact avoid fixed-point
-iteration altogether. In that universe, we could instead first
-identify and remove strongly connected components (SCC) in the graph.
-Note that such components must consist solely of region variables; all
-of these variables can effectively be unified into a single variable.
-Once SCCs are removed, we are left with a DAG. At this point, we
-could walk the DAG in topological order once to compute the expanding
-nodes, and again in reverse topological order to compute the
-contracting nodes. However, as I said, this does not work given the
-current treatment of closure bounds, but perhaps in the future we can
-address this problem somehow and make region inference somewhat more
-efficient. Note that this is solely a matter of performance, not
-expressiveness.
+## Modeling closures
+
+Integrating closures properly into the model is a bit of
+work-in-progress. In an ideal world, we would model closures as
+closely as possible after their desugared equivalents. That is, a
+closure type would be modeled as a struct, and the region hierarchy of
+different closure bodies would be completely distinct from all other
+fns. We are generally moving in that direction but there are
+complications in terms of the implementation.
+
+In practice what we currently do is somewhat different. The basis for
+the current approach is the observation that the only time that
+regions from distinct fn bodies interact with one another is through
+an upvar or the type of a fn parameter (since closures live in the fn
+body namespace, they can in fact have fn parameters whose types
+include regions from the surrounding fn body). For these cases, there
+are separate mechanisms which ensure that the regions that appear in
+upvars/parameters outlive the dynamic extent of each call to the
+closure:
+
+1. Types must outlive the region of any expression where they are used.
+ For a closure type `C` to outlive a region `'r`, that implies that the
+ types of all its upvars must outlive `'r`.
+2. Parameters must outlive the region of any fn that they are passed to.
+
+Therefore, we can -- sort of -- assume that any region from an
+enclosing fns is larger than any region from one of its enclosed
+fn. And that is precisely what we do: when building the region
+hierarchy, each region lives in its own distinct subtree, but if we
+are asked to compute the `LUB(r1, r2)` of two regions, and those
+regions are in disjoint subtrees, we compare the lexical nesting of
+the two regions.
+
+*Ideas for improving the situation:* (FIXME #3696) The correctness
+argument here is subtle and a bit hand-wavy. The ideal, as stated
+earlier, would be to model things in such a way that it corresponds
+more closely to the desugared code. The best approach for doing this
+is a bit unclear: it may in fact be possible to *actually* desugar
+before we start, but I don't think so. The main option that I've been
+thinking through is imposing a "view shift" as we enter the fn body,
+so that regions appearing in the types of fn parameters and upvars are
+translated from being regions in the outer fn into free region
+parameters, just as they would be if we applied the desugaring. The
+challenge here is that type inference may not have fully run, so the
+types may not be fully known: we could probably do this translation
+lazilly, as type variables are instantiated. We would also have to
+apply a kind of inverse translation to the return value. This would be
+a good idea anyway, as right now it is possible for free regions
+instantiated within the closure to leak into the parent: this
+currently leads to type errors, since those regions cannot outlive any
+expressions within the parent hierarchy. Much like the current
+handling of closures, there are no known cases where this leads to a
+type-checking accepting incorrect code (though it sometimes rejects
+what might be considered correct code; see rust-lang/rust#22557), but
+it still doesn't feel like the right approach.
### Skolemization
pub use self::VarValue::*;
use self::Classification::*;
-use super::cres;
use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable};
use middle::region;
use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound};
use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
+use middle::ty_relate::RelateResult;
use middle::graph;
use middle::graph::{Direction, NodeIndex};
use util::common::indenter;
/// Could not infer a value for `v` because `sub_r <= v` (due to
/// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
/// `sub_r <= sup_r` does not hold.
- SubSupConflict(RegionVariableOrigin<'tcx>,
+ SubSupConflict(RegionVariableOrigin,
SubregionOrigin<'tcx>, Region,
SubregionOrigin<'tcx>, Region),
/// Could not infer a value for `v` because `v <= r1` (due to
/// `origin1`) and `v <= r2` (due to `origin2`) and
/// `r1` and `r2` have no intersection.
- SupSupConflict(RegionVariableOrigin<'tcx>,
+ SupSupConflict(RegionVariableOrigin,
SubregionOrigin<'tcx>, Region,
SubregionOrigin<'tcx>, Region),
/// more specific errors message by suggesting to the user where they
/// should put a lifetime. In those cases we process and put those errors
/// into `ProcessedErrors` before we do any reporting.
- ProcessedErrors(Vec<RegionVariableOrigin<'tcx>>,
+ ProcessedErrors(Vec<RegionVariableOrigin>,
Vec<(TypeTrace<'tcx>, ty::type_err<'tcx>)>,
Vec<SameRegions>),
}
pub struct RegionVarBindings<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
- var_origins: RefCell<Vec<RegionVariableOrigin<'tcx>>>,
+ var_origins: RefCell<Vec<RegionVariableOrigin>>,
// Constraints of the form `A <= B` introduced by the region
// checker. Here at least one of `A` and `B` must be a region
len as u32
}
- pub fn new_region_var(&self, origin: RegionVariableOrigin<'tcx>) -> RegionVid {
+ pub fn new_region_var(&self, origin: RegionVariableOrigin) -> RegionVid {
let id = self.num_vars();
self.var_origins.borrow_mut().push(origin.clone());
let vid = RegionVid { index: id };
// at least as big as the block fr.scope_id". So, we can
// reasonably compare free regions and scopes:
let fr_scope = fr.scope.to_code_extent();
- match self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) {
+ let r_id = self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id);
+
+ if r_id == fr_scope {
// if the free region's scope `fr.scope_id` is bigger than
// the scope region `s_id`, then the LUB is the free
// region itself:
- Some(r_id) if r_id == fr_scope => f,
-
+ f
+ } else {
// otherwise, we don't know what the free region is,
// so we must conservatively say the LUB is static:
- _ => ReStatic
+ ReStatic
}
}
// The region corresponding to an outer block is a
// subtype of the region corresponding to an inner
// block.
- match self.tcx.region_maps.nearest_common_ancestor(a_id, b_id) {
- Some(r_id) => ReScope(r_id),
- _ => ReStatic
- }
+ ReScope(self.tcx.region_maps.nearest_common_ancestor(a_id, b_id))
}
(ReFree(ref a_fr), ReFree(ref b_fr)) => {
/// regions are given as argument, in any order, a consistent result is returned.
fn lub_free_regions(&self,
a: &FreeRegion,
- b: &FreeRegion) -> ty::Region
+ b: &FreeRegion)
+ -> ty::Region
{
return match a.cmp(b) {
Less => helper(self, a, b),
fn glb_concrete_regions(&self,
a: Region,
b: Region)
- -> cres<'tcx, Region> {
+ -> RelateResult<'tcx, Region>
+ {
debug!("glb_concrete_regions({:?}, {:?})", a, b);
match (a, b) {
(ReLateBound(..), _) |
// is the scope `s_id`. Otherwise, as we do not know
// big the free region is precisely, the GLB is undefined.
let fr_scope = fr.scope.to_code_extent();
- match self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) {
- Some(r_id) if r_id == fr_scope => Ok(s),
- _ => Err(ty::terr_regions_no_overlap(b, a))
+ if self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) == fr_scope {
+ Ok(s)
+ } else {
+ Err(ty::terr_regions_no_overlap(b, a))
}
}
/// returned.
fn glb_free_regions(&self,
a: &FreeRegion,
- b: &FreeRegion) -> cres<'tcx, ty::Region>
+ b: &FreeRegion)
+ -> RelateResult<'tcx, ty::Region>
{
return match a.cmp(b) {
Less => helper(self, a, b),
fn helper<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>,
a: &FreeRegion,
- b: &FreeRegion) -> cres<'tcx, ty::Region>
+ b: &FreeRegion) -> RelateResult<'tcx, ty::Region>
{
if this.tcx.region_maps.sub_free_region(*a, *b) {
Ok(ty::ReFree(*a))
region_a: ty::Region,
region_b: ty::Region,
scope_a: region::CodeExtent,
- scope_b: region::CodeExtent) -> cres<'tcx, Region>
+ scope_b: region::CodeExtent)
+ -> RelateResult<'tcx, Region>
{
// We want to generate the intersection of two
// scopes or two free regions. So, if one of
// it. Otherwise fail.
debug!("intersect_scopes(scope_a={:?}, scope_b={:?}, region_a={:?}, region_b={:?})",
scope_a, scope_b, region_a, region_b);
- match self.tcx.region_maps.nearest_common_ancestor(scope_a, scope_b) {
- Some(r_id) if scope_a == r_id => Ok(ReScope(scope_b)),
- Some(r_id) if scope_b == r_id => Ok(ReScope(scope_a)),
- _ => Err(ty::terr_regions_no_overlap(region_a, region_b))
+ let r_id = self.tcx.region_maps.nearest_common_ancestor(scope_a, scope_b);
+ if r_id == scope_a {
+ Ok(ReScope(scope_b))
+ } else if r_id == scope_b {
+ Ok(ReScope(scope_a))
+ } else {
+ Err(ty::terr_regions_no_overlap(region_a, region_b))
}
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use super::combine::*;
-use super::cres;
+use super::combine::{self, CombineFields};
use super::higher_ranked::HigherRankedRelations;
use super::Subtype;
use super::type_variable::{SubtypeOf, SupertypeOf};
use middle::ty::{self, Ty};
use middle::ty::TyVar;
-use util::ppaux::Repr;
+use middle::ty_relate::{Relate, RelateResult, TypeRelation};
+use util::ppaux::{Repr};
/// "Greatest lower bound" (common subtype)
-pub struct Sub<'f, 'tcx: 'f> {
- fields: CombineFields<'f, 'tcx>
+pub struct Sub<'a, 'tcx: 'a> {
+ fields: CombineFields<'a, 'tcx>
}
-#[allow(non_snake_case)]
-pub fn Sub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Sub<'f, 'tcx> {
- Sub { fields: cf }
+impl<'a, 'tcx> Sub<'a, 'tcx> {
+ pub fn new(f: CombineFields<'a, 'tcx>) -> Sub<'a, 'tcx> {
+ Sub { fields: f }
+ }
}
-impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
- fn tag(&self) -> String { "Sub".to_string() }
- fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
-
- fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>
- {
- match v {
- ty::Invariant => self.equate().tys(a, b),
- ty::Covariant => self.tys(a, b),
- ty::Bivariant => self.bivariate().tys(a, b),
- ty::Contravariant => Sub(self.fields.switch_expected()).tys(b, a),
- }
- }
+impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> {
+ fn tag(&self) -> &'static str { "Sub" }
+ fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.infcx.tcx }
+ fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
- fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
- -> cres<'tcx, ty::Region>
+ fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
+ variance: ty::Variance,
+ a: &T,
+ b: &T)
+ -> RelateResult<'tcx, T>
{
- match v {
- ty::Invariant => self.equate().regions(a, b),
- ty::Covariant => self.regions(a, b),
- ty::Bivariant => self.bivariate().regions(a, b),
- ty::Contravariant => Sub(self.fields.switch_expected()).regions(b, a),
+ match variance {
+ ty::Invariant => self.fields.equate().relate(a, b),
+ ty::Covariant => self.relate(a, b),
+ ty::Bivariant => self.fields.bivariate().relate(a, b),
+ ty::Contravariant => self.fields.switch_expected().sub().relate(b, a),
}
}
- fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
- debug!("{}.regions({}, {})",
- self.tag(),
- a.repr(self.tcx()),
- b.repr(self.tcx()));
- self.infcx().region_vars.make_subregion(Subtype(self.trace()), a, b);
- Ok(a)
- }
+ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+ debug!("{}.tys({}, {})", self.tag(), a.repr(self.tcx()), b.repr(self.tcx()));
- fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
- debug!("{}.tys({}, {})", self.tag(),
- a.repr(self.tcx()), b.repr(self.tcx()));
if a == b { return Ok(a); }
let infcx = self.fields.infcx;
}
(&ty::ty_infer(TyVar(a_id)), _) => {
try!(self.fields
- .switch_expected()
- .instantiate(b, SupertypeOf, a_id));
+ .switch_expected()
+ .instantiate(b, SupertypeOf, a_id));
Ok(a)
}
(_, &ty::ty_infer(TyVar(b_id))) => {
}
_ => {
- super_tys(self, a, b)
+ combine::super_combine_tys(self.fields.infcx, self, a, b)
}
}
}
- fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
- where T : Combineable<'tcx>
+ fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
+ debug!("{}.regions({}, {})",
+ self.tag(),
+ a.repr(self.tcx()),
+ b.repr(self.tcx()));
+ let origin = Subtype(self.fields.trace.clone());
+ self.fields.infcx.region_vars.make_subregion(origin, a, b);
+ Ok(a)
+ }
+
+ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
+ -> RelateResult<'tcx, ty::Binder<T>>
+ where T: Relate<'a,'tcx>
{
- self.higher_ranked_sub(a, b)
+ self.fields.higher_ranked_sub(a, b)
}
}
use std::marker;
-use middle::ty::{expected_found, IntVarValue};
+use middle::ty::{IntVarValue};
use middle::ty::{self, Ty};
-use middle::infer::{uok, ures};
-use middle::infer::InferCtxt;
-use std::cell::RefCell;
use std::fmt::Debug;
use std::marker::PhantomData;
use syntax::ast;
pub trait UnifyKey : Clone + Debug + PartialEq {
type Value : UnifyValue;
- fn index(&self) -> usize;
+ fn index(&self) -> u32;
- fn from_index(u: usize) -> Self;
-
- // Given an inference context, returns the unification table
- // appropriate to this key type.
- fn unification_table<'v>(infcx: &'v InferCtxt)
- -> &'v RefCell<UnificationTable<Self>>;
+ fn from_index(u: u32) -> Self;
fn tag(k: Option<Self>) -> &'static str;
}
pub fn new_key(&mut self, value: K::Value) -> K {
let index = self.values.push(Root(value, 0));
- let k = UnifyKey::from_index(index);
+ let k = UnifyKey::from_index(index as u32);
debug!("{}: created new key: {:?}",
UnifyKey::tag(None::<K>),
k);
k
}
- /// Find the root node for `vid`. This uses the standard union-find algorithm with path
- /// compression: http://en.wikipedia.org/wiki/Disjoint-set_data_structure
- pub fn get(&mut self, tcx: &ty::ctxt, vid: K) -> Node<K> {
- let index = vid.index();
+ /// Find the root node for `vid`. This uses the standard
+ /// union-find algorithm with path compression:
+ /// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>.
+ ///
+ /// NB. This is a building-block operation and you would probably
+ /// prefer to call `probe` below.
+ fn get(&mut self, vid: K) -> Node<K> {
+ let index = vid.index() as usize;
let value = (*self.values.get(index)).clone();
match value {
Redirect(redirect) => {
- let node: Node<K> = self.get(tcx, redirect.clone());
+ let node: Node<K> = self.get(redirect.clone());
if node.key != redirect {
// Path compression
self.values.set(index, Redirect(node.key.clone()));
}
fn is_root(&self, key: &K) -> bool {
- match *self.values.get(key.index()) {
+ let index = key.index() as usize;
+ match *self.values.get(index) {
Redirect(..) => false,
Root(..) => true,
}
}
- /// Sets the value for `vid` to `new_value`. `vid` MUST be a root node! Also, we must be in the
- /// middle of a snapshot.
- pub fn set<'tcx>(&mut self,
- _tcx: &ty::ctxt<'tcx>,
- key: K,
- new_value: VarValue<K>)
- {
+ /// Sets the value for `vid` to `new_value`. `vid` MUST be a root
+ /// node! This is an internal operation used to impl other things.
+ fn set(&mut self, key: K, new_value: VarValue<K>) {
assert!(self.is_root(&key));
debug!("Updating variable {:?} to {:?}",
key, new_value);
- self.values.set(key.index(), new_value);
+ let index = key.index() as usize;
+ self.values.set(index, new_value);
}
- /// Either redirects node_a to node_b or vice versa, depending on the relative rank. Returns
- /// the new root and rank. You should then update the value of the new root to something
- /// suitable.
- pub fn unify<'tcx>(&mut self,
- tcx: &ty::ctxt<'tcx>,
- node_a: &Node<K>,
- node_b: &Node<K>)
- -> (K, usize)
- {
+ /// Either redirects `node_a` to `node_b` or vice versa, depending
+ /// on the relative rank. The value associated with the new root
+ /// will be `new_value`.
+ ///
+ /// NB: This is the "union" operation of "union-find". It is
+ /// really more of a building block. If the values associated with
+ /// your key are non-trivial, you would probably prefer to call
+ /// `unify_var_var` below.
+ fn unify(&mut self, node_a: &Node<K>, node_b: &Node<K>, new_value: K::Value) {
debug!("unify(node_a(id={:?}, rank={:?}), node_b(id={:?}, rank={:?}))",
node_a.key,
node_a.rank,
node_b.key,
node_b.rank);
- if node_a.rank > node_b.rank {
+ let (new_root, new_rank) = if node_a.rank > node_b.rank {
// a has greater rank, so a should become b's parent,
// i.e., b should redirect to a.
- self.set(tcx, node_b.key.clone(), Redirect(node_a.key.clone()));
+ self.set(node_b.key.clone(), Redirect(node_a.key.clone()));
(node_a.key.clone(), node_a.rank)
} else if node_a.rank < node_b.rank {
// b has greater rank, so a should redirect to b.
- self.set(tcx, node_a.key.clone(), Redirect(node_b.key.clone()));
+ self.set(node_a.key.clone(), Redirect(node_b.key.clone()));
(node_b.key.clone(), node_b.rank)
} else {
// If equal, redirect one to the other and increment the
// other's rank.
assert_eq!(node_a.rank, node_b.rank);
- self.set(tcx, node_b.key.clone(), Redirect(node_a.key.clone()));
+ self.set(node_b.key.clone(), Redirect(node_a.key.clone()));
(node_a.key.clone(), node_a.rank + 1)
- }
+ };
+
+ self.set(new_root, Root(new_value, new_rank));
}
}
}
///////////////////////////////////////////////////////////////////////////
-// Code to handle simple keys like ints, floats---anything that
-// doesn't have a subtyping relationship we need to worry about.
-
-/// Indicates a type that does not have any kind of subtyping
-/// relationship.
-pub trait SimplyUnifiable<'tcx> : Clone + PartialEq + Debug {
- fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>;
- fn to_type_err(expected_found<Self>) -> ty::type_err<'tcx>;
-}
-
-pub fn err<'tcx, V:SimplyUnifiable<'tcx>>(a_is_expected: bool,
- a_t: V,
- b_t: V)
- -> ures<'tcx> {
- if a_is_expected {
- Err(SimplyUnifiable::to_type_err(
- ty::expected_found {expected: a_t, found: b_t}))
- } else {
- Err(SimplyUnifiable::to_type_err(
- ty::expected_found {expected: b_t, found: a_t}))
- }
-}
-
-pub trait InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V>
- where K : UnifyKey<Value=Option<V>>,
- V : SimplyUnifiable<'tcx>,
- Option<V> : UnifyValue,
-{
- fn simple_vars(&self,
- a_is_expected: bool,
- a_id: K,
- b_id: K)
- -> ures<'tcx>;
- fn simple_var_t(&self,
- a_is_expected: bool,
- a_id: K,
- b: V)
- -> ures<'tcx>;
- fn probe_var(&self, a_id: K) -> Option<Ty<'tcx>>;
-}
-
-impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtxt<'a,'tcx>
- where K : UnifyKey<Value=Option<V>>,
- V : SimplyUnifiable<'tcx>,
- Option<V> : UnifyValue,
+// Code to handle keys which carry a value, like ints,
+// floats---anything that doesn't have a subtyping relationship we
+// need to worry about.
+
+impl<'tcx,K,V> UnificationTable<K>
+ where K: UnifyKey<Value=Option<V>>,
+ V: Clone+PartialEq,
+ Option<V>: UnifyValue,
{
- /// Unifies two simple keys. Because simple keys do not have any subtyping relationships, if
- /// both keys have already been associated with a value, then those two values must be the
- /// same.
- fn simple_vars(&self,
- a_is_expected: bool,
- a_id: K,
- b_id: K)
- -> ures<'tcx>
+ pub fn unify_var_var(&mut self,
+ a_id: K,
+ b_id: K)
+ -> Result<(),(V,V)>
{
- let tcx = self.tcx;
- let table = UnifyKey::unification_table(self);
- let node_a: Node<K> = table.borrow_mut().get(tcx, a_id);
- let node_b: Node<K> = table.borrow_mut().get(tcx, b_id);
+ let node_a = self.get(a_id);
+ let node_b = self.get(b_id);
let a_id = node_a.key.clone();
let b_id = node_b.key.clone();
- if a_id == b_id { return uok(); }
+ if a_id == b_id { return Ok(()); }
let combined = {
match (&node_a.value, &node_b.value) {
None
}
(&Some(ref v), &None) | (&None, &Some(ref v)) => {
- Some((*v).clone())
+ Some(v.clone())
}
(&Some(ref v1), &Some(ref v2)) => {
if *v1 != *v2 {
- return err(a_is_expected, (*v1).clone(), (*v2).clone())
+ return Err((v1.clone(), v2.clone()));
}
- Some((*v1).clone())
+ Some(v1.clone())
}
}
};
- let (new_root, new_rank) = table.borrow_mut().unify(tcx,
- &node_a,
- &node_b);
- table.borrow_mut().set(tcx, new_root, Root(combined, new_rank));
- return Ok(())
+ Ok(self.unify(&node_a, &node_b, combined))
}
/// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping
/// relationships, if `a_id` already has a value, it must be the same as `b`.
- fn simple_var_t(&self,
- a_is_expected: bool,
- a_id: K,
- b: V)
- -> ures<'tcx>
+ pub fn unify_var_value(&mut self,
+ a_id: K,
+ b: V)
+ -> Result<(),(V,V)>
{
- let tcx = self.tcx;
- let table = UnifyKey::unification_table(self);
- let node_a = table.borrow_mut().get(tcx, a_id);
+ let node_a = self.get(a_id);
let a_id = node_a.key.clone();
match node_a.value {
None => {
- table.borrow_mut().set(tcx, a_id, Root(Some(b), node_a.rank));
- return Ok(());
+ self.set(a_id, Root(Some(b), node_a.rank));
+ Ok(())
}
Some(ref a_t) => {
if *a_t == b {
- return Ok(());
+ Ok(())
} else {
- return err(a_is_expected, (*a_t).clone(), b);
+ Err((a_t.clone(), b))
}
}
}
}
- fn probe_var(&self, a_id: K) -> Option<Ty<'tcx>> {
- let tcx = self.tcx;
- let table = UnifyKey::unification_table(self);
- let node_a = table.borrow_mut().get(tcx, a_id);
- match node_a.value {
- None => None,
- Some(ref a_t) => Some(a_t.to_type(tcx))
- }
+ pub fn has_value(&mut self, id: K) -> bool {
+ self.get(id).value.is_some()
+ }
+
+ pub fn probe(&mut self, a_id: K) -> Option<V> {
+ self.get(a_id).value.clone()
}
}
// Integral type keys
+pub trait ToType<'tcx> {
+ fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>;
+}
+
impl UnifyKey for ty::IntVid {
type Value = Option<IntVarValue>;
-
- fn index(&self) -> usize { self.index as usize }
-
- fn from_index(i: usize) -> ty::IntVid { ty::IntVid { index: i as u32 } }
-
- fn unification_table<'v>(infcx: &'v InferCtxt) -> &'v RefCell<UnificationTable<ty::IntVid>> {
- return &infcx.int_unification_table;
- }
-
- fn tag(_: Option<ty::IntVid>) -> &'static str {
- "IntVid"
- }
+ fn index(&self) -> u32 { self.index }
+ fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } }
+ fn tag(_: Option<ty::IntVid>) -> &'static str { "IntVid" }
}
-impl<'tcx> SimplyUnifiable<'tcx> for IntVarValue {
+impl<'tcx> ToType<'tcx> for IntVarValue {
fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
match *self {
ty::IntType(i) => ty::mk_mach_int(tcx, i),
ty::UintType(i) => ty::mk_mach_uint(tcx, i),
}
}
-
- fn to_type_err(err: expected_found<IntVarValue>) -> ty::type_err<'tcx> {
- return ty::terr_int_mismatch(err);
- }
}
impl UnifyValue for Option<IntVarValue> { }
impl UnifyKey for ty::FloatVid {
type Value = Option<ast::FloatTy>;
-
- fn index(&self) -> usize { self.index as usize }
-
- fn from_index(i: usize) -> ty::FloatVid { ty::FloatVid { index: i as u32 } }
-
- fn unification_table<'v>(infcx: &'v InferCtxt) -> &'v RefCell<UnificationTable<ty::FloatVid>> {
- return &infcx.float_unification_table;
- }
-
- fn tag(_: Option<ty::FloatVid>) -> &'static str {
- "FloatVid"
- }
+ fn index(&self) -> u32 { self.index }
+ fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } }
+ fn tag(_: Option<ty::FloatVid>) -> &'static str { "FloatVid" }
}
impl UnifyValue for Option<ast::FloatTy> {
}
-impl<'tcx> SimplyUnifiable<'tcx> for ast::FloatTy {
+impl<'tcx> ToType<'tcx> for ast::FloatTy {
fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
ty::mk_mach_float(tcx, *self)
}
-
- fn to_type_err(err: expected_found<ast::FloatTy>) -> ty::type_err<'tcx> {
- ty::terr_float_mismatch(err)
- }
}
/// reexporting a public struct doesn't inline the doc).
pub type PublicItems = NodeSet;
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum LastPrivate {
LastMod(PrivateDep),
// `use` directives (imports) can refer to two separate definitions in the
type_used: ImportUse},
}
-#[derive(Copy, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum PrivateDep {
AllPublic,
DependsOn(ast::DefId),
}
// How an import is used.
-#[derive(Copy, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
pub enum ImportUse {
Unused, // The import is not used.
Used, // The import is used.
}
/// The region maps encode information about region relationships.
-///
-/// - `scope_map` maps from a scope id to the enclosing scope id; this is
-/// usually corresponding to the lexical nesting, though in the case of
-/// closures the parent scope is the innermost conditional expression or repeating
-/// block. (Note that the enclosing scope id for the block
-/// associated with a closure is the closure itself.)
-///
-/// - `var_map` maps from a variable or binding id to the block in which
-/// that variable is declared.
-///
-/// - `free_region_map` maps from a free region `a` to a list of free
-/// regions `bs` such that `a <= b for all b in bs`
-/// - the free region map is populated during type check as we check
-/// each function. See the function `relate_free_regions` for
-/// more information.
-///
-/// - `rvalue_scopes` includes entries for those expressions whose cleanup
-/// scope is larger than the default. The map goes from the expression
-/// id to the cleanup scope id. For rvalues not present in this table,
-/// the appropriate cleanup scope is the innermost enclosing statement,
-/// conditional expression, or repeating block (see `terminating_scopes`).
-///
-/// - `terminating_scopes` is a set containing the ids of each statement,
-/// or conditional/repeating expression. These scopes are calling "terminating
-/// scopes" because, when attempting to find the scope of a temporary, by
-/// default we search up the enclosing scopes until we encounter the
-/// terminating scope. A conditional/repeating
-/// expression is one which is not guaranteed to execute exactly once
-/// upon entering the parent scope. This could be because the expression
-/// only executes conditionally, such as the expression `b` in `a && b`,
-/// or because the expression may execute many times, such as a loop
-/// body. The reason that we distinguish such expressions is that, upon
-/// exiting the parent scope, we cannot statically know how many times
-/// the expression executed, and thus if the expression creates
-/// temporaries we cannot know statically how many such temporaries we
-/// would have to cleanup. Therefore we ensure that the temporaries never
-/// outlast the conditional/repeating expression, preventing the need
-/// for dynamic checks and/or arbitrary amounts of stack space.
pub struct RegionMaps {
+ /// `scope_map` maps from a scope id to the enclosing scope id;
+ /// this is usually corresponding to the lexical nesting, though
+ /// in the case of closures the parent scope is the innermost
+ /// conditional expression or repeating block. (Note that the
+ /// enclosing scope id for the block associated with a closure is
+ /// the closure itself.)
scope_map: RefCell<FnvHashMap<CodeExtent, CodeExtent>>,
+
+ /// `var_map` maps from a variable or binding id to the block in
+ /// which that variable is declared.
var_map: RefCell<NodeMap<CodeExtent>>,
+
+ /// `free_region_map` maps from a free region `a` to a list of
+ /// free regions `bs` such that `a <= b for all b in bs`
+ ///
+ /// NB. the free region map is populated during type check as we
+ /// check each function. See the function `relate_free_regions`
+ /// for more information.
free_region_map: RefCell<FnvHashMap<FreeRegion, Vec<FreeRegion>>>,
+
+ /// `rvalue_scopes` includes entries for those expressions whose cleanup scope is
+ /// larger than the default. The map goes from the expression id
+ /// to the cleanup scope id. For rvalues not present in this
+ /// table, the appropriate cleanup scope is the innermost
+ /// enclosing statement, conditional expression, or repeating
+ /// block (see `terminating_scopes`).
rvalue_scopes: RefCell<NodeMap<CodeExtent>>,
+
+ /// `terminating_scopes` is a set containing the ids of each
+ /// statement, or conditional/repeating expression. These scopes
+ /// are calling "terminating scopes" because, when attempting to
+ /// find the scope of a temporary, by default we search up the
+ /// enclosing scopes until we encounter the terminating scope. A
+ /// conditional/repeating expression is one which is not
+ /// guaranteed to execute exactly once upon entering the parent
+ /// scope. This could be because the expression only executes
+ /// conditionally, such as the expression `b` in `a && b`, or
+ /// because the expression may execute many times, such as a loop
+ /// body. The reason that we distinguish such expressions is that,
+ /// upon exiting the parent scope, we cannot statically know how
+ /// many times the expression executed, and thus if the expression
+ /// creates temporaries we cannot know statically how many such
+ /// temporaries we would have to cleanup. Therefore we ensure that
+ /// the temporaries never outlast the conditional/repeating
+ /// expression, preventing the need for dynamic checks and/or
+ /// arbitrary amounts of stack space.
terminating_scopes: RefCell<FnvHashSet<CodeExtent>>,
+
+ /// Encodes the hierarchy of fn bodies. Every fn body (including
+ /// closures) forms its own distinct region hierarchy, rooted in
+ /// the block that is the fn body. This map points from the id of
+ /// that root block to the id of the root block for the enclosing
+ /// fn, if any. Thus the map structures the fn bodies into a
+ /// hierarchy based on their lexical mapping. This is used to
+ /// handle the relationships between regions in a fn and in a
+ /// closure defined by that fn. See the "Modeling closures"
+ /// section of the README in middle::infer::region_inference for
+ /// more details.
+ fn_tree: RefCell<NodeMap<ast::NodeId>>,
}
/// Carries the node id for the innermost block or match expression,
#[derive(Debug, Copy)]
pub struct Context {
+ /// the root of the current region tree. This is typically the id
+ /// of the innermost fn body. Each fn forms its own disjoint tree
+ /// in the region hierarchy. These fn bodies are themselves
+ /// arranged into a tree. See the "Modeling closures" section of
+ /// the README in middle::infer::region_inference for more
+ /// details.
+ root_id: Option<ast::NodeId>,
+
/// the scope that contains any new variables declared
var_parent: InnermostDeclaringBlock,
self.free_region_map.borrow_mut().insert(sub, vec!(sup));
}
+ /// Records that `sub_fn` is defined within `sup_fn`. These ids
+ /// should be the id of the block that is the fn body, which is
+ /// also the root of the region hierarchy for that fn.
+ fn record_fn_parent(&self, sub_fn: ast::NodeId, sup_fn: ast::NodeId) {
+ debug!("record_fn_parent(sub_fn={:?}, sup_fn={:?})", sub_fn, sup_fn);
+ assert!(sub_fn != sup_fn);
+ let previous = self.fn_tree.borrow_mut().insert(sub_fn, sup_fn);
+ assert!(previous.is_none());
+ }
+
+ fn fn_is_enclosed_by(&self, mut sub_fn: ast::NodeId, sup_fn: ast::NodeId) -> bool {
+ let fn_tree = self.fn_tree.borrow();
+ loop {
+ if sub_fn == sup_fn { return true; }
+ match fn_tree.get(&sub_fn) {
+ Some(&s) => { sub_fn = s; }
+ None => { return false; }
+ }
+ }
+ }
+
pub fn record_encl_scope(&self, sub: CodeExtent, sup: CodeExtent) {
debug!("record_encl_scope(sub={:?}, sup={:?})", sub, sup);
assert!(sub != sup);
self.scope_map.borrow_mut().insert(sub, sup);
}
- pub fn record_var_scope(&self, var: ast::NodeId, lifetime: CodeExtent) {
+ fn record_var_scope(&self, var: ast::NodeId, lifetime: CodeExtent) {
debug!("record_var_scope(sub={:?}, sup={:?})", var, lifetime);
assert!(var != lifetime.node_id());
self.var_map.borrow_mut().insert(var, lifetime);
}
- pub fn record_rvalue_scope(&self, var: ast::NodeId, lifetime: CodeExtent) {
+ fn record_rvalue_scope(&self, var: ast::NodeId, lifetime: CodeExtent) {
debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime);
assert!(var != lifetime.node_id());
self.rvalue_scopes.borrow_mut().insert(var, lifetime);
/// Records that a scope is a TERMINATING SCOPE. Whenever we create automatic temporaries --
/// e.g. by an expression like `a().f` -- they will be freed within the innermost terminating
/// scope.
- pub fn mark_as_terminating_scope(&self, scope_id: CodeExtent) {
+ fn mark_as_terminating_scope(&self, scope_id: CodeExtent) {
debug!("record_terminating_scope(scope_id={:?})", scope_id);
self.terminating_scopes.borrow_mut().insert(scope_id);
}
pub fn nearest_common_ancestor(&self,
scope_a: CodeExtent,
scope_b: CodeExtent)
- -> Option<CodeExtent> {
- if scope_a == scope_b { return Some(scope_a); }
+ -> CodeExtent {
+ if scope_a == scope_b { return scope_a; }
let a_ancestors = ancestors_of(self, scope_a);
let b_ancestors = ancestors_of(self, scope_b);
let mut a_index = a_ancestors.len() - 1;
let mut b_index = b_ancestors.len() - 1;
- // Here, ~[ab]_ancestors is a vector going from narrow to broad.
+ // Here, [ab]_ancestors is a vector going from narrow to broad.
// The end of each vector will be the item where the scope is
// defined; if there are any common ancestors, then the tails of
// the vector will be the same. So basically we want to walk
// then the corresponding scope is a superscope of the other.
if a_ancestors[a_index] != b_ancestors[b_index] {
- return None;
+ // In this case, the two regions belong to completely
+ // different functions. Compare those fn for lexical
+ // nesting. The reasoning behind this is subtle. See the
+ // "Modeling closures" section of the README in
+ // middle::infer::region_inference for more details.
+ let a_root_scope = a_ancestors[a_index];
+ let b_root_scope = a_ancestors[a_index];
+ return match (a_root_scope, b_root_scope) {
+ (CodeExtent::DestructionScope(a_root_id),
+ CodeExtent::DestructionScope(b_root_id)) => {
+ if self.fn_is_enclosed_by(a_root_id, b_root_id) {
+ // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a`
+ scope_b
+ } else if self.fn_is_enclosed_by(b_root_id, a_root_id) {
+ // `b` is enclosed by `a`, hence `a` is the ancestor of everything in `b`
+ scope_a
+ } else {
+ // neither fn encloses the other
+ unreachable!()
+ }
+ }
+ _ => {
+ // root ids are always Misc right now
+ unreachable!()
+ }
+ };
}
loop {
// Loop invariant: a_ancestors[a_index] == b_ancestors[b_index]
// for all indices between a_index and the end of the array
- if a_index == 0 { return Some(scope_a); }
- if b_index == 0 { return Some(scope_b); }
+ if a_index == 0 { return scope_a; }
+ if b_index == 0 { return scope_b; }
a_index -= 1;
b_index -= 1;
if a_ancestors[a_index] != b_ancestors[b_index] {
- return Some(a_ancestors[a_index + 1]);
+ return a_ancestors[a_index + 1];
}
}
- fn ancestors_of(this: &RegionMaps, scope: CodeExtent)
- -> Vec<CodeExtent> {
+ fn ancestors_of(this: &RegionMaps, scope: CodeExtent) -> Vec<CodeExtent> {
// debug!("ancestors_of(scope={:?})", scope);
let mut result = vec!(scope);
let mut scope = scope;
let prev_cx = visitor.cx;
let blk_scope = CodeExtent::Misc(blk.id);
+
// If block was previously marked as a terminating scope during
// the recursive visit of its parent node in the AST, then we need
// to account for the destruction scope representing the extent of
// itself has returned.
visitor.cx = Context {
+ root_id: prev_cx.root_id,
var_parent: InnermostDeclaringBlock::Block(blk.id),
parent: InnermostEnclosingExpr::Some(blk.id),
};
record_superlifetime(
visitor, declaring.to_code_extent(), statement.span);
visitor.cx = Context {
+ root_id: prev_cx.root_id,
var_parent: InnermostDeclaringBlock::Statement(declaring),
parent: InnermostEnclosingExpr::Statement(declaring),
};
// Items create a new outer block scope as far as we're concerned.
let prev_cx = visitor.cx;
visitor.cx = Context {
+ root_id: None,
var_parent: InnermostDeclaringBlock::None,
parent: InnermostEnclosingExpr::None
};
}
fn resolve_fn(visitor: &mut RegionResolutionVisitor,
- fk: FnKind,
+ _: FnKind,
decl: &ast::FnDecl,
body: &ast::Block,
sp: Span,
let body_scope = CodeExtent::from_node_id(body.id);
visitor.region_maps.mark_as_terminating_scope(body_scope);
+
let dtor_scope = CodeExtent::DestructionScope(body.id);
visitor.region_maps.record_encl_scope(body_scope, dtor_scope);
+
record_superlifetime(visitor, dtor_scope, body.span);
+ if let Some(root_id) = visitor.cx.root_id {
+ visitor.region_maps.record_fn_parent(body.id, root_id);
+ }
+
let outer_cx = visitor.cx;
// The arguments and `self` are parented to the body of the fn.
visitor.cx = Context {
+ root_id: Some(body.id),
parent: InnermostEnclosingExpr::Some(body.id),
var_parent: InnermostDeclaringBlock::Block(body.id)
};
visit::walk_fn_decl(visitor, decl);
- // The body of the fn itself is either a root scope (top-level fn)
- // or it continues with the inherited scope (closures).
- match fk {
- visit::FkItemFn(..) | visit::FkMethod(..) => {
- visitor.cx = Context {
- parent: InnermostEnclosingExpr::None,
- var_parent: InnermostDeclaringBlock::None
- };
- visitor.visit_block(body);
- visitor.cx = outer_cx;
- }
- visit::FkFnBlock(..) => {
- // FIXME(#3696) -- at present we are place the closure body
- // within the region hierarchy exactly where it appears lexically.
- // This is wrong because the closure may live longer
- // than the enclosing expression. We should probably fix this,
- // but the correct fix is a bit subtle, and I am also not sure
- // that the present approach is unsound -- it may not permit
- // any illegal programs. See issue for more details.
- visitor.cx = outer_cx;
- visitor.visit_block(body);
- }
- }
+ // The body of the every fn is a root scope.
+ visitor.cx = Context {
+ root_id: Some(body.id),
+ parent: InnermostEnclosingExpr::None,
+ var_parent: InnermostDeclaringBlock::None
+ };
+ visitor.visit_block(body);
+
+ // Restore context we had at the start.
+ visitor.cx = outer_cx;
}
impl<'a, 'v> Visitor<'v> for RegionResolutionVisitor<'a> {
free_region_map: RefCell::new(FnvHashMap()),
rvalue_scopes: RefCell::new(NodeMap()),
terminating_scopes: RefCell::new(FnvHashSet()),
+ fn_tree: RefCell::new(NodeMap()),
};
{
let mut visitor = RegionResolutionVisitor {
sess: sess,
region_maps: &maps,
cx: Context {
+ root_id: None,
parent: InnermostEnclosingExpr::None,
var_parent: InnermostDeclaringBlock::None,
}
sess: sess,
region_maps: region_maps,
cx: Context {
+ root_id: None,
parent: InnermostEnclosingExpr::None,
var_parent: InnermostDeclaringBlock::None
}
use super::project;
use super::util;
-use middle::subst::{Subst, TypeSpace};
+use middle::subst::{Subst, Substs, TypeSpace};
use middle::ty::{self, ToPolyTraitRef, Ty};
use middle::infer::{self, InferCtxt};
-use std::collections::HashSet;
use std::rc::Rc;
use syntax::ast;
-use syntax::codemap::DUMMY_SP;
+use syntax::codemap::{DUMMY_SP, Span};
use util::ppaux::Repr;
+#[derive(Copy)]
+struct ParamIsLocal(bool);
+
/// True if there exist types that satisfy both of the two given impls.
pub fn overlapping_impls(infcx: &InferCtxt,
impl1_def_id: ast::DefId,
a_def_id.repr(selcx.tcx()),
b_def_id.repr(selcx.tcx()));
- let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx, a_def_id);
- let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx, b_def_id);
+ let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx,
+ a_def_id,
+ util::free_substs_for_impl);
+
+ let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx,
+ b_def_id,
+ util::fresh_type_vars_for_impl);
debug!("overlap: a_trait_ref={}", a_trait_ref.repr(selcx.tcx()));
+
debug!("overlap: b_trait_ref={}", b_trait_ref.repr(selcx.tcx()));
// Does `a <: b` hold? If not, no overlap.
debug!("overlap: subtraitref check succeeded");
// Are any of the obligations unsatisfiable? If so, no overlap.
+ let tcx = selcx.tcx();
+ let infcx = selcx.infcx();
let opt_failing_obligation =
a_obligations.iter()
.chain(b_obligations.iter())
+ .map(|o| infcx.resolve_type_vars_if_possible(o))
.find(|o| !selcx.evaluate_obligation(o));
if let Some(failing_obligation) = opt_failing_obligation {
- debug!("overlap: obligation unsatisfiable {}", failing_obligation.repr(selcx.tcx()));
- return false;
+ debug!("overlap: obligation unsatisfiable {}", failing_obligation.repr(tcx));
+ return false
}
true
}
+pub fn trait_ref_is_knowable<'tcx>(tcx: &ty::ctxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> bool
+{
+ debug!("trait_ref_is_knowable(trait_ref={})", trait_ref.repr(tcx));
+
+ // if the orphan rules pass, that means that no ancestor crate can
+ // impl this, so it's up to us.
+ if orphan_check_trait_ref(tcx, trait_ref, ParamIsLocal(false)).is_ok() {
+ debug!("trait_ref_is_knowable: orphan check passed");
+ return true;
+ }
+
+ // if the trait is not marked fundamental, then it's always possible that
+ // an ancestor crate will impl this in the future, if they haven't
+ // already
+ if
+ trait_ref.def_id.krate != ast::LOCAL_CRATE &&
+ !ty::has_attr(tcx, trait_ref.def_id, "fundamental")
+ {
+ debug!("trait_ref_is_knowable: trait is neither local nor fundamental");
+ return false;
+ }
+
+ // find out when some downstream (or cousin) crate could impl this
+ // trait-ref, presuming that all the parameters were instantiated
+ // with downstream types. If not, then it could only be
+ // implemented by an upstream crate, which means that the impl
+ // must be visible to us, and -- since the trait is fundamental
+ // -- we can test.
+ orphan_check_trait_ref(tcx, trait_ref, ParamIsLocal(true)).is_err()
+}
+
+type SubstsFn = for<'a,'tcx> fn(infcx: &InferCtxt<'a, 'tcx>,
+ span: Span,
+ impl_def_id: ast::DefId)
+ -> Substs<'tcx>;
+
/// Instantiate fresh variables for all bound parameters of the impl
/// and return the impl trait ref with those variables substituted.
fn impl_trait_ref_and_oblig<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
- impl_def_id: ast::DefId)
+ impl_def_id: ast::DefId,
+ substs_fn: SubstsFn)
-> (Rc<ty::TraitRef<'tcx>>,
Vec<PredicateObligation<'tcx>>)
{
let impl_substs =
- &util::fresh_substs_for_impl(selcx.infcx(), DUMMY_SP, impl_def_id);
+ &substs_fn(selcx.infcx(), DUMMY_SP, impl_def_id);
let impl_trait_ref =
ty::impl_trait_ref(selcx.tcx(), impl_def_id).unwrap();
let impl_trait_ref =
impl_def_id: ast::DefId)
-> Result<(), OrphanCheckErr<'tcx>>
{
- debug!("impl_is_local({})", impl_def_id.repr(tcx));
+ debug!("orphan_check({})", impl_def_id.repr(tcx));
// We only except this routine to be invoked on implementations
// of a trait, not inherent implementations.
let trait_ref = ty::impl_trait_ref(tcx, impl_def_id).unwrap();
- debug!("trait_ref={}", trait_ref.repr(tcx));
+ debug!("orphan_check: trait_ref={}", trait_ref.repr(tcx));
// If the *trait* is local to the crate, ok.
if trait_ref.def_id.krate == ast::LOCAL_CRATE {
return Ok(());
}
+ orphan_check_trait_ref(tcx, &trait_ref, ParamIsLocal(false))
+}
+
+fn orphan_check_trait_ref<'tcx>(tcx: &ty::ctxt<'tcx>,
+ trait_ref: &ty::TraitRef<'tcx>,
+ param_is_local: ParamIsLocal)
+ -> Result<(), OrphanCheckErr<'tcx>>
+{
+ debug!("orphan_check_trait_ref(trait_ref={}, param_is_local={})",
+ trait_ref.repr(tcx), param_is_local.0);
+
// First, create an ordered iterator over all the type parameters to the trait, with the self
// type appearing first.
let input_tys = Some(trait_ref.self_ty());
let input_tys = input_tys.iter().chain(trait_ref.substs.types.get_slice(TypeSpace).iter());
- let mut input_tys = input_tys;
// Find the first input type that either references a type parameter OR
// some local type.
- match input_tys.find(|&&input_ty| references_local_or_type_parameter(tcx, input_ty)) {
- Some(&input_ty) => {
- // Within this first type, check that all type parameters are covered by a local
- // type constructor. Note that if there is no local type constructor, then any
- // type parameter at all will be an error.
- let covered_params = type_parameters_covered_by_ty(tcx, input_ty);
- let all_params = type_parameters_reachable_from_ty(input_ty);
- for ¶m in all_params.difference(&covered_params) {
- return Err(OrphanCheckErr::UncoveredTy(param));
+ for input_ty in input_tys {
+ if ty_is_local(tcx, input_ty, param_is_local) {
+ debug!("orphan_check_trait_ref: ty_is_local `{}`", input_ty.repr(tcx));
+
+ // First local input type. Check that there are no
+ // uncovered type parameters.
+ let uncovered_tys = uncovered_tys(tcx, input_ty, param_is_local);
+ for uncovered_ty in uncovered_tys {
+ if let Some(param) = uncovered_ty.walk().find(|t| is_type_parameter(t)) {
+ debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx));
+ return Err(OrphanCheckErr::UncoveredTy(param));
+ }
}
+
+ // OK, found local type, all prior types upheld invariant.
+ return Ok(());
}
- None => {
- return Err(OrphanCheckErr::NoLocalInputType);
+
+ // Otherwise, enforce invariant that there are no type
+ // parameters reachable.
+ if !param_is_local.0 {
+ if let Some(param) = input_ty.walk().find(|t| is_type_parameter(t)) {
+ debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx));
+ return Err(OrphanCheckErr::UncoveredTy(param));
+ }
}
}
- return Ok(());
+ // If we exit above loop, never found a local type.
+ debug!("orphan_check_trait_ref: no local type");
+ return Err(OrphanCheckErr::NoLocalInputType);
+}
+
+fn uncovered_tys<'tcx>(tcx: &ty::ctxt<'tcx>,
+ ty: Ty<'tcx>,
+ param_is_local: ParamIsLocal)
+ -> Vec<Ty<'tcx>>
+{
+ if ty_is_local_constructor(tcx, ty, param_is_local) {
+ vec![]
+ } else if fundamental_ty(tcx, ty) {
+ ty.walk_shallow()
+ .flat_map(|t| uncovered_tys(tcx, t, param_is_local).into_iter())
+ .collect()
+ } else {
+ vec![ty]
+ }
}
-fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
+fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool {
+ match ty.sty {
+ // FIXME(#20590) straighten story about projection types
+ ty::ty_projection(..) | ty::ty_param(..) => true,
+ _ => false,
+ }
+}
+
+fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>, param_is_local: ParamIsLocal) -> bool
+{
+ ty_is_local_constructor(tcx, ty, param_is_local) ||
+ fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, param_is_local))
+}
+
+fn fundamental_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool
+{
+ match ty.sty {
+ ty::ty_uniq(..) | ty::ty_rptr(..) =>
+ true,
+ ty::ty_enum(def_id, _) | ty::ty_struct(def_id, _) =>
+ ty::has_attr(tcx, def_id, "fundamental"),
+ ty::ty_trait(ref data) =>
+ ty::has_attr(tcx, data.principal_def_id(), "fundamental"),
+ _ =>
+ false
+ }
+}
+
+fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>,
+ ty: Ty<'tcx>,
+ param_is_local: ParamIsLocal)
+ -> bool
+{
debug!("ty_is_local_constructor({})", ty.repr(tcx));
match ty.sty {
ty::ty_ptr(..) |
ty::ty_rptr(..) |
ty::ty_tup(..) |
- ty::ty_param(..) |
+ ty::ty_infer(..) |
ty::ty_projection(..) => {
false
}
+ ty::ty_param(..) => {
+ param_is_local.0
+ }
+
ty::ty_enum(def_id, _) |
ty::ty_struct(def_id, _) => {
def_id.krate == ast::LOCAL_CRATE
}
ty::ty_closure(..) |
- ty::ty_infer(..) |
ty::ty_err => {
tcx.sess.bug(
&format!("ty_is_local invoked on unexpected type: {}",
}
}
-fn type_parameters_covered_by_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
- ty: Ty<'tcx>)
- -> HashSet<Ty<'tcx>>
-{
- if ty_is_local_constructor(tcx, ty) {
- type_parameters_reachable_from_ty(ty)
- } else {
- ty.walk_children().flat_map(|t| type_parameters_covered_by_ty(tcx, t).into_iter()).collect()
- }
-}
-
-/// All type parameters reachable from `ty`
-fn type_parameters_reachable_from_ty<'tcx>(ty: Ty<'tcx>) -> HashSet<Ty<'tcx>> {
- ty.walk().filter(|&t| is_type_parameter(t)).collect()
-}
-
-fn references_local_or_type_parameter<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
- ty.walk().any(|ty| is_type_parameter(ty) || ty_is_local_constructor(tcx, ty))
-}
-fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool {
- match ty.sty {
- // FIXME(#20590) straighten story about projection types
- ty::ty_projection(..) | ty::ty_param(..) => true,
- _ => false,
- }
-}
obligation.repr(selcx.tcx()));
let infcx = selcx.infcx();
- infcx.try(|snapshot| {
+ infcx.commit_if_ok(|snapshot| {
let (skol_predicate, skol_map) =
infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot);
}
}
+#[derive(Clone)]
pub struct Normalized<'tcx,T> {
pub value: T,
pub obligations: Vec<PredicateObligation<'tcx>>,
use self::BuiltinBoundConditions::*;
use self::EvaluationResult::*;
+use super::coherence;
use super::DerivedObligationCause;
use super::project;
use super::project::{normalize_with_depth, Normalized};
use middle::infer;
use middle::infer::{InferCtxt, TypeFreshener};
use middle::ty_fold::TypeFoldable;
+use middle::ty_match;
+use middle::ty_relate::TypeRelation;
use std::cell::RefCell;
-use std::collections::hash_map::HashMap;
use std::rc::Rc;
use syntax::{abi, ast};
use util::common::ErrorReported;
+use util::nodemap::FnvHashMap;
use util::ppaux::Repr;
pub struct SelectionContext<'cx, 'tcx:'cx> {
/// selection-context's freshener. Used to check for recursion.
fresh_trait_ref: ty::PolyTraitRef<'tcx>,
- previous: Option<&'prev TraitObligationStack<'prev, 'tcx>>
+ previous: TraitObligationStackList<'prev, 'tcx>,
}
#[derive(Clone)]
pub struct SelectionCache<'tcx> {
- hashmap: RefCell<HashMap<Rc<ty::TraitRef<'tcx>>,
- SelectionResult<'tcx, SelectionCandidate<'tcx>>>>,
+ hashmap: RefCell<FnvHashMap<Rc<ty::TraitRef<'tcx>>,
+ SelectionResult<'tcx, SelectionCandidate<'tcx>>>>,
}
pub enum MethodMatchResult {
debug!("select({})", obligation.repr(self.tcx()));
assert!(!obligation.predicate.has_escaping_regions());
- let stack = self.push_stack(None, obligation);
+ let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
match try!(self.candidate_from_obligation(&stack)) {
None => {
self.consider_unification_despite_ambiguity(obligation);
debug!("evaluate_obligation({})",
obligation.repr(self.tcx()));
- self.evaluate_predicate_recursively(None, obligation).may_apply()
+ self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
+ .may_apply()
}
fn evaluate_builtin_bound_recursively<'o>(&mut self,
match obligation {
Ok(obligation) => {
- self.evaluate_predicate_recursively(Some(previous_stack), &obligation)
+ self.evaluate_predicate_recursively(previous_stack.list(), &obligation)
}
Err(ErrorReported) => {
EvaluatedToOk
}
fn evaluate_predicates_recursively<'a,'o,I>(&mut self,
- stack: Option<&TraitObligationStack<'o, 'tcx>>,
+ stack: TraitObligationStackList<'o, 'tcx>,
predicates: I)
-> EvaluationResult<'tcx>
where I : Iterator<Item=&'a PredicateObligation<'tcx>>, 'tcx:'a
}
fn evaluate_predicate_recursively<'o>(&mut self,
- previous_stack: Option<&TraitObligationStack<'o, 'tcx>>,
+ previous_stack: TraitObligationStackList<'o, 'tcx>,
obligation: &PredicateObligation<'tcx>)
-> EvaluationResult<'tcx>
{
}
fn evaluate_obligation_recursively<'o>(&mut self,
- previous_stack: Option<&TraitObligationStack<'o, 'tcx>>,
+ previous_stack: TraitObligationStackList<'o, 'tcx>,
obligation: &TraitObligation<'tcx>)
-> EvaluationResult<'tcx>
{
debug!("evaluate_obligation_recursively({})",
obligation.repr(self.tcx()));
- let stack = self.push_stack(previous_stack.map(|x| x), obligation);
+ let stack = self.push_stack(previous_stack, obligation);
let result = self.evaluate_stack(&stack);
unbound_input_types &&
(self.intercrate ||
stack.iter().skip(1).any(
- |prev| stack.fresh_trait_ref.def_id() == prev.fresh_trait_ref.def_id()))
+ |prev| self.match_fresh_trait_refs(&stack.fresh_trait_ref,
+ &prev.fresh_trait_ref)))
{
debug!("evaluate_stack({}) --> unbound argument, recursion --> ambiguous",
stack.fresh_trait_ref.repr(self.tcx()));
obligation.recursion_depth + 1,
skol_map,
snapshot);
- self.winnow_selection(None, VtableImpl(vtable_impl)).may_apply()
+ self.winnow_selection(TraitObligationStackList::empty(),
+ VtableImpl(vtable_impl)).may_apply()
}
Err(()) => {
false
return Ok(Some(ErrorCandidate));
}
+ if !self.is_knowable(stack) {
+ debug!("intercrate not knowable");
+ return Ok(None);
+ }
+
let candidate_set = try!(self.assemble_candidates(stack));
if candidate_set.ambiguous {
Ok(Some(candidate))
}
+ fn is_knowable<'o>(&mut self,
+ stack: &TraitObligationStack<'o, 'tcx>)
+ -> bool
+ {
+ debug!("is_knowable(intercrate={})", self.intercrate);
+
+ if !self.intercrate {
+ return true;
+ }
+
+ let obligation = &stack.obligation;
+ let predicate = self.infcx().resolve_type_vars_if_possible(&obligation.predicate);
+
+ // ok to skip binder because of the nature of the
+ // trait-ref-is-knowable check, which does not care about
+ // bound regions
+ let trait_ref = &predicate.skip_binder().trait_ref;
+
+ coherence::trait_ref_is_knowable(self.tcx(), trait_ref)
+ }
+
fn pick_candidate_cache(&self) -> &SelectionCache<'tcx> {
// If there are any where-clauses in scope, then we always use
// a cache local to this particular scope. Otherwise, we
self.infcx().probe(move |_| {
match self.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
Ok(obligations) => {
- self.evaluate_predicates_recursively(Some(stack), obligations.iter())
+ self.evaluate_predicates_recursively(stack.list(), obligations.iter())
}
Err(()) => {
EvaluatedToErr(Unimplemented)
return;
}
- self.infcx.try(|snapshot| {
+ self.infcx.commit_if_ok(|snapshot| {
let bound_self_ty =
self.infcx.resolve_type_vars_if_possible(&obligation.self_ty());
let (self_ty, _) =
let result = self.infcx.probe(|_| {
let candidate = (*candidate).clone();
match self.confirm_candidate(stack.obligation, candidate) {
- Ok(selection) => self.winnow_selection(Some(stack), selection),
+ Ok(selection) => self.winnow_selection(stack.list(),
+ selection),
Err(error) => EvaluatedToErr(error),
}
});
}
fn winnow_selection<'o>(&mut self,
- stack: Option<&TraitObligationStack<'o, 'tcx>>,
+ stack: TraitObligationStackList<'o,'tcx>,
selection: Selection<'tcx>)
-> EvaluationResult<'tcx>
{
// For each type, produce a vector of resulting obligations
let obligations: Result<Vec<Vec<_>>, _> = bound_types.iter().map(|nested_ty| {
- self.infcx.try(|snapshot| {
+ self.infcx.commit_if_ok(|snapshot| {
let (skol_ty, skol_map) =
self.infcx().skolemize_late_bound_regions(nested_ty, snapshot);
let Normalized { value: normalized_ty, mut obligations } =
obligation: &TraitObligation<'tcx>)
{
let _: Result<(),()> =
- self.infcx.try(|snapshot| {
+ self.infcx.commit_if_ok(|snapshot| {
let result =
self.match_projection_obligation_against_bounds_from_trait(obligation,
snapshot);
trait_def_id,
nested);
- let trait_obligations: Result<VecPerParamSpace<_>,()> = self.infcx.try(|snapshot| {
+ let trait_obligations: Result<VecPerParamSpace<_>,()> = self.infcx.commit_if_ok(|snapshot| {
let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
let (trait_ref, skol_map) =
self.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot);
// First, create the substitutions by matching the impl again,
// this time not in a probe.
- self.infcx.try(|snapshot| {
+ self.infcx.commit_if_ok(|snapshot| {
let (skol_obligation_trait_ref, skol_map) =
self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot);
let substs =
return Err(());
}
- let impl_substs = util::fresh_substs_for_impl(self.infcx,
- obligation.cause.span,
- impl_def_id);
+ let impl_substs = util::fresh_type_vars_for_impl(self.infcx,
+ obligation.cause.span,
+ impl_def_id);
let impl_trait_ref = impl_trait_ref.subst(self.tcx(),
&impl_substs);
{
// Create fresh type variables for each type parameter declared
// on the impl etc.
- let impl_substs = util::fresh_substs_for_impl(self.infcx,
- obligation_cause.span,
- impl_def_id);
+ let impl_substs = util::fresh_type_vars_for_impl(self.infcx,
+ obligation_cause.span,
+ impl_def_id);
// Find the self type for the impl.
let impl_self_ty = ty::lookup_item_type(self.tcx(), impl_def_id).ty;
///////////////////////////////////////////////////////////////////////////
// Miscellany
+ fn match_fresh_trait_refs(&self,
+ previous: &ty::PolyTraitRef<'tcx>,
+ current: &ty::PolyTraitRef<'tcx>)
+ -> bool
+ {
+ let mut matcher = ty_match::Match::new(self.tcx());
+ matcher.relate(previous, current).is_ok()
+ }
+
fn push_stack<'o,'s:'o>(&mut self,
- previous_stack: Option<&'s TraitObligationStack<'s, 'tcx>>,
+ previous_stack: TraitObligationStackList<'s, 'tcx>,
obligation: &'o TraitObligation<'tcx>)
-> TraitObligationStack<'o, 'tcx>
{
TraitObligationStack {
obligation: obligation,
fresh_trait_ref: fresh_trait_ref,
- previous: previous_stack.map(|p| p), // FIXME variance
+ previous: previous_stack,
}
}
impl<'tcx> SelectionCache<'tcx> {
pub fn new() -> SelectionCache<'tcx> {
SelectionCache {
- hashmap: RefCell::new(HashMap::new())
+ hashmap: RefCell::new(FnvHashMap())
}
}
}
-impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
- fn iter(&self) -> Option<&TraitObligationStack<'o, 'tcx>> {
- Some(self)
+impl<'o,'tcx> TraitObligationStack<'o,'tcx> {
+ fn list(&'o self) -> TraitObligationStackList<'o,'tcx> {
+ TraitObligationStackList::with(self)
}
+
+ fn iter(&'o self) -> TraitObligationStackList<'o,'tcx> {
+ self.list()
+ }
+}
+
+#[derive(Copy, Clone)]
+struct TraitObligationStackList<'o,'tcx:'o> {
+ head: Option<&'o TraitObligationStack<'o,'tcx>>
}
-impl<'o, 'tcx> Iterator for Option<&'o TraitObligationStack<'o, 'tcx>> {
+impl<'o,'tcx> TraitObligationStackList<'o,'tcx> {
+ fn empty() -> TraitObligationStackList<'o,'tcx> {
+ TraitObligationStackList { head: None }
+ }
+
+ fn with(r: &'o TraitObligationStack<'o,'tcx>) -> TraitObligationStackList<'o,'tcx> {
+ TraitObligationStackList { head: Some(r) }
+ }
+}
+
+impl<'o,'tcx> Iterator for TraitObligationStackList<'o,'tcx>{
type Item = &'o TraitObligationStack<'o,'tcx>;
- fn next(&mut self) -> Option<&'o TraitObligationStack<'o, 'tcx>> {
- match *self {
+ fn next(&mut self) -> Option<&'o TraitObligationStack<'o,'tcx>> {
+ match self.head {
Some(o) => {
*self = o.previous;
Some(o)
}
}
-impl<'o, 'tcx> Repr<'tcx> for TraitObligationStack<'o, 'tcx> {
+impl<'o,'tcx> Repr<'tcx> for TraitObligationStack<'o,'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
format!("TraitObligationStack({})",
self.obligation.repr(tcx))
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use middle::region;
use middle::subst::{Substs, VecPerParamSpace};
use middle::infer::InferCtxt;
use middle::ty::{self, Ty, AsPredicate, ToPolyTraitRef};
}
}
-
///////////////////////////////////////////////////////////////////////////
// Other
///////////////////////////////////////////////////////////////////////////
// declared on the impl declaration e.g., `impl<A,B> for Box<[(A,B)]>`
// would return ($0, $1) where $0 and $1 are freshly instantiated type
// variables.
-pub fn fresh_substs_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
- span: Span,
- impl_def_id: ast::DefId)
- -> Substs<'tcx>
+pub fn fresh_type_vars_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
+ span: Span,
+ impl_def_id: ast::DefId)
+ -> Substs<'tcx>
{
let tcx = infcx.tcx;
let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics;
infcx.fresh_substs_for_generics(span, &impl_generics)
}
+// determine the `self` type, using fresh variables for all variables
+// declared on the impl declaration e.g., `impl<A,B> for Box<[(A,B)]>`
+// would return ($0, $1) where $0 and $1 are freshly instantiated type
+// variables.
+pub fn free_substs_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
+ _span: Span,
+ impl_def_id: ast::DefId)
+ -> Substs<'tcx>
+{
+ let tcx = infcx.tcx;
+ let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics;
+
+ let some_types = impl_generics.types.map(|def| {
+ ty::mk_param_from_def(tcx, def)
+ });
+
+ let some_regions = impl_generics.regions.map(|def| {
+ // FIXME. This destruction scope information is pretty darn
+ // bogus; after all, the impl might not even be in this crate!
+ // But given what we do in coherence, it is harmless enough
+ // for now I think. -nmatsakis
+ let extent = region::DestructionScopeData::new(ast::DUMMY_NODE_ID);
+ ty::free_region_from_def(extent, def)
+ });
+
+ Substs::new(some_types, some_regions)
+}
+
impl<'tcx, N> fmt::Debug for VtableImplData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "VtableImpl({:?})", self.impl_def_id)
use middle::traits;
use middle::ty;
use middle::ty_fold::{self, TypeFoldable, TypeFolder};
-use middle::ty_walk::TypeWalker;
+use middle::ty_walk::{self, TypeWalker};
use util::ppaux::{note_and_explain_region, bound_region_ptr_to_string};
use util::ppaux::ty_to_string;
use util::ppaux::{Repr, UserString};
use arena::TypedArena;
use std::borrow::{Borrow, Cow};
-use std::cell::{Cell, RefCell};
+use std::cell::{Cell, RefCell, Ref};
use std::cmp;
use std::fmt;
use std::hash::{Hash, SipHasher, Hasher};
use std::mem;
+use std::num::ToPrimitive;
use std::ops;
use std::rc::Rc;
use std::vec::IntoIter;
use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
use syntax::ast::{StmtExpr, StmtSemi, StructField, UnnamedField, Visibility};
use syntax::ast_util::{self, is_local, lit_is_str, local_def};
-use syntax::attr::{self, AttrMetaMethods};
+use syntax::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt};
use syntax::codemap::Span;
use syntax::parse::token::{self, InternedString, special_idents};
-use syntax::{ast, ast_map};
+use syntax::print::pprust;
+use syntax::ptr::P;
+use syntax::ast;
+use syntax::ast_map::{self, LinkedPath};
pub type Disr = u64;
/// Stores the types for various nodes in the AST. Note that this table
/// is not guaranteed to be populated until after typeck. See
/// typeck::check::fn_ctxt for details.
- pub node_types: RefCell<NodeMap<Ty<'tcx>>>,
+ node_types: RefCell<NodeMap<Ty<'tcx>>>,
/// Stores the type parameters which were substituted to obtain the type
/// of this node. This only applies to nodes that refer to entities
pub const_qualif_map: RefCell<NodeMap<check_const::ConstQualif>>,
}
+impl<'tcx> ctxt<'tcx> {
+ pub fn node_types(&self) -> Ref<NodeMap<Ty<'tcx>>> { self.node_types.borrow() }
+ pub fn node_type_insert(&self, id: NodeId, ty: Ty<'tcx>) {
+ self.node_types.borrow_mut().insert(id, ty);
+ }
+}
+
// Flags that we track on types. These flags are propagated upwards
// through the type during type construction, so that we can quickly
// check whether the type has various kinds of types in it without
TypeWalker::new(self)
}
- /// Iterator that walks types reachable from `self`, in
- /// depth-first order. Note that this is a shallow walk. For
- /// example:
- ///
- /// ```notrust
- /// isize => { }
- /// Foo<Bar<isize>> => { Bar<isize>, isize }
- /// [isize] => { isize }
- /// ```
- pub fn walk_children(&'tcx self) -> TypeWalker<'tcx> {
- // Walks type reachable from `self` but not `self
- let mut walker = self.walk();
- let r = walker.next();
- assert_eq!(r, Some(self));
- walker
+ /// Iterator that walks the immediate children of `self`. Hence
+ /// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]`
+ /// (but not `i32`, like `walk`).
+ pub fn walk_shallow(&'tcx self) -> IntoIter<Ty<'tcx>> {
+ ty_walk::walk_shallow(self)
}
pub fn as_opt_param_ty(&self) -> Option<ty::ParamTy> {
if id.krate == ast::LOCAL_CRATE {
cx.map.with_path(id.node, f)
} else {
- f(csearch::get_item_path(cx, id).iter().cloned().chain(None))
+ f(csearch::get_item_path(cx, id).iter().cloned().chain(LinkedPath::empty()))
}
}
}
}
+trait IntTypeExt {
+ fn to_ty<'tcx>(&self, cx: &ctxt<'tcx>) -> Ty<'tcx>;
+ fn i64_to_disr(&self, val: i64) -> Option<Disr>;
+ fn u64_to_disr(&self, val: u64) -> Option<Disr>;
+ fn disr_incr(&self, val: Disr) -> Option<Disr>;
+ fn disr_string(&self, val: Disr) -> String;
+ fn disr_wrap_incr(&self, val: Option<Disr>) -> Disr;
+}
+
+impl IntTypeExt for attr::IntType {
+ fn to_ty<'tcx>(&self, cx: &ctxt<'tcx>) -> Ty<'tcx> {
+ match *self {
+ SignedInt(ast::TyI8) => cx.types.i8,
+ SignedInt(ast::TyI16) => cx.types.i16,
+ SignedInt(ast::TyI32) => cx.types.i32,
+ SignedInt(ast::TyI64) => cx.types.i64,
+ SignedInt(ast::TyIs) => cx.types.isize,
+ UnsignedInt(ast::TyU8) => cx.types.u8,
+ UnsignedInt(ast::TyU16) => cx.types.u16,
+ UnsignedInt(ast::TyU32) => cx.types.u32,
+ UnsignedInt(ast::TyU64) => cx.types.u64,
+ UnsignedInt(ast::TyUs) => cx.types.usize,
+ }
+ }
+
+ fn i64_to_disr(&self, val: i64) -> Option<Disr> {
+ match *self {
+ SignedInt(ast::TyI8) => val.to_i8() .map(|v| v as Disr),
+ SignedInt(ast::TyI16) => val.to_i16() .map(|v| v as Disr),
+ SignedInt(ast::TyI32) => val.to_i32() .map(|v| v as Disr),
+ SignedInt(ast::TyI64) => val.to_i64() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU8) => val.to_u8() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU16) => val.to_u16() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU32) => val.to_u32() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU64) => val.to_u64() .map(|v| v as Disr),
+
+ UnsignedInt(ast::TyUs) |
+ SignedInt(ast::TyIs) => unreachable!(),
+ }
+ }
+
+ fn u64_to_disr(&self, val: u64) -> Option<Disr> {
+ match *self {
+ SignedInt(ast::TyI8) => val.to_i8() .map(|v| v as Disr),
+ SignedInt(ast::TyI16) => val.to_i16() .map(|v| v as Disr),
+ SignedInt(ast::TyI32) => val.to_i32() .map(|v| v as Disr),
+ SignedInt(ast::TyI64) => val.to_i64() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU8) => val.to_u8() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU16) => val.to_u16() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU32) => val.to_u32() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU64) => val.to_u64() .map(|v| v as Disr),
+
+ UnsignedInt(ast::TyUs) |
+ SignedInt(ast::TyIs) => unreachable!(),
+ }
+ }
+
+ fn disr_incr(&self, val: Disr) -> Option<Disr> {
+ macro_rules! add1 {
+ ($e:expr) => { $e.and_then(|v|v.checked_add(1)).map(|v| v as Disr) }
+ }
+ match *self {
+ // SignedInt repr means we *want* to reinterpret the bits
+ // treating the highest bit of Disr as a sign-bit, so
+ // cast to i64 before range-checking.
+ SignedInt(ast::TyI8) => add1!((val as i64).to_i8()),
+ SignedInt(ast::TyI16) => add1!((val as i64).to_i16()),
+ SignedInt(ast::TyI32) => add1!((val as i64).to_i32()),
+ SignedInt(ast::TyI64) => add1!(Some(val as i64)),
+
+ UnsignedInt(ast::TyU8) => add1!(val.to_u8()),
+ UnsignedInt(ast::TyU16) => add1!(val.to_u16()),
+ UnsignedInt(ast::TyU32) => add1!(val.to_u32()),
+ UnsignedInt(ast::TyU64) => add1!(Some(val)),
+
+ UnsignedInt(ast::TyUs) |
+ SignedInt(ast::TyIs) => unreachable!(),
+ }
+ }
+
+ // This returns a String because (1.) it is only used for
+ // rendering an error message and (2.) a string can represent the
+ // full range from `i64::MIN` through `u64::MAX`.
+ fn disr_string(&self, val: Disr) -> String {
+ match *self {
+ SignedInt(ast::TyI8) => format!("{}", val as i8 ),
+ SignedInt(ast::TyI16) => format!("{}", val as i16),
+ SignedInt(ast::TyI32) => format!("{}", val as i32),
+ SignedInt(ast::TyI64) => format!("{}", val as i64),
+ UnsignedInt(ast::TyU8) => format!("{}", val as u8 ),
+ UnsignedInt(ast::TyU16) => format!("{}", val as u16),
+ UnsignedInt(ast::TyU32) => format!("{}", val as u32),
+ UnsignedInt(ast::TyU64) => format!("{}", val as u64),
+
+ UnsignedInt(ast::TyUs) |
+ SignedInt(ast::TyIs) => unreachable!(),
+ }
+ }
+
+ fn disr_wrap_incr(&self, val: Option<Disr>) -> Disr {
+ macro_rules! add1 {
+ ($e:expr) => { ($e).wrapping_add(1) as Disr }
+ }
+ let val = val.unwrap_or(ty::INITIAL_DISCRIMINANT_VALUE);
+ match *self {
+ SignedInt(ast::TyI8) => add1!(val as i8 ),
+ SignedInt(ast::TyI16) => add1!(val as i16),
+ SignedInt(ast::TyI32) => add1!(val as i32),
+ SignedInt(ast::TyI64) => add1!(val as i64),
+ UnsignedInt(ast::TyU8) => add1!(val as u8 ),
+ UnsignedInt(ast::TyU16) => add1!(val as u16),
+ UnsignedInt(ast::TyU32) => add1!(val as u32),
+ UnsignedInt(ast::TyU64) => add1!(val as u64),
+
+ UnsignedInt(ast::TyUs) |
+ SignedInt(ast::TyIs) => unreachable!(),
+ }
+ }
+}
+
+/// Returns `(normalized_type, ty)`, where `normalized_type` is the
+/// IntType representation of one of {i64,i32,i16,i8,u64,u32,u16,u8},
+/// and `ty` is the original type (i.e. may include `isize` or
+/// `usize`).
+pub fn enum_repr_type<'tcx>(cx: &ctxt<'tcx>,
+ opt_hint: Option<&attr::ReprAttr>)
+ -> (attr::IntType, Ty<'tcx>)
+{
+ let repr_type = match opt_hint {
+ // Feed in the given type
+ Some(&attr::ReprInt(_, int_t)) => int_t,
+ // ... but provide sensible default if none provided
+ //
+ // NB. Historically `fn enum_variants` generate i64 here, while
+ // rustc_typeck::check would generate isize.
+ _ => SignedInt(ast::TyIs),
+ };
+
+ let repr_type_ty = repr_type.to_ty(cx);
+ let repr_type = match repr_type {
+ SignedInt(ast::TyIs) =>
+ SignedInt(cx.sess.target.int_type),
+ UnsignedInt(ast::TyUs) =>
+ UnsignedInt(cx.sess.target.uint_type),
+ other => other
+ };
+
+ (repr_type, repr_type_ty)
+}
+
+fn report_discrim_overflow(cx: &ctxt,
+ variant_span: Span,
+ variant_name: &str,
+ repr_type: attr::IntType,
+ prev_val: Disr) {
+ let computed_value = repr_type.disr_wrap_incr(Some(prev_val));
+ let computed_value = repr_type.disr_string(computed_value);
+ let prev_val = repr_type.disr_string(prev_val);
+ let repr_type = repr_type.to_ty(cx).user_string(cx);
+ span_err!(cx.sess, variant_span, E0370,
+ "enum discriminant overflowed on value after {}: {}; \
+ set explicitly via {} = {} if that is desired outcome",
+ prev_val, repr_type, variant_name, computed_value);
+}
+
+// This computes the discriminant values for the sequence of Variants
+// attached to a particular enum, taking into account the #[repr] (if
+// any) provided via the `opt_hint`.
+fn compute_enum_variants<'tcx>(cx: &ctxt<'tcx>,
+ vs: &'tcx [P<ast::Variant>],
+ opt_hint: Option<&attr::ReprAttr>)
+ -> Vec<Rc<ty::VariantInfo<'tcx>>> {
+ let mut variants: Vec<Rc<ty::VariantInfo>> = Vec::new();
+ let mut prev_disr_val: Option<ty::Disr> = None;
+
+ let (repr_type, repr_type_ty) = ty::enum_repr_type(cx, opt_hint);
+
+ for v in vs {
+ // If the discriminant value is specified explicitly in the
+ // enum, check whether the initialization expression is valid,
+ // otherwise use the last value plus one.
+ let current_disr_val;
+
+ // This closure marks cases where, when an error occurs during
+ // the computation, attempt to assign a (hopefully) fresh
+ // value to avoid spurious error reports downstream.
+ let attempt_fresh_value = move || -> Disr {
+ repr_type.disr_wrap_incr(prev_disr_val)
+ };
+
+ match v.node.disr_expr {
+ Some(ref e) => {
+ debug!("disr expr, checking {}", pprust::expr_to_string(&**e));
+
+ // check_expr (from check_const pass) doesn't guarantee
+ // that the expression is in a form that eval_const_expr can
+ // handle, so we may still get an internal compiler error
+ //
+ // pnkfelix: The above comment was transcribed from
+ // the version of this code taken from rustc_typeck.
+ // Presumably the implication is that we need to deal
+ // with such ICE's as they arise.
+ //
+ // Since this can be called from `ty::enum_variants`
+ // anyway, best thing is to make `eval_const_expr`
+ // more robust (on case-by-case basis).
+
+ match const_eval::eval_const_expr_partial(cx, &**e, Some(repr_type_ty)) {
+ Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
+ Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
+ Ok(_) => {
+ span_err!(cx.sess, e.span, E0079,
+ "expected signed integer constant");
+ current_disr_val = attempt_fresh_value();
+ }
+ Err(ref err) => {
+ span_err!(cx.sess, err.span, E0080,
+ "constant evaluation error: {}",
+ err.description());
+ current_disr_val = attempt_fresh_value();
+ }
+ }
+ },
+ None => {
+ current_disr_val = match prev_disr_val {
+ Some(prev_disr_val) => {
+ if let Some(v) = repr_type.disr_incr(prev_disr_val) {
+ v
+ } else {
+ report_discrim_overflow(cx, v.span, v.node.name.as_str(),
+ repr_type, prev_disr_val);
+ attempt_fresh_value()
+ }
+ }
+ None => ty::INITIAL_DISCRIMINANT_VALUE
+ }
+ }
+ }
+
+ let variant_info = Rc::new(VariantInfo::from_ast_variant(cx, &**v, current_disr_val));
+ prev_disr_val = Some(current_disr_val);
+
+ variants.push(variant_info);
+ }
+
+ return variants;
+}
+
pub fn enum_variants<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
-> Rc<Vec<Rc<VariantInfo<'tcx>>>> {
memoized(&cx.enum_var_cache, id, |id: ast::DefId| {
if ast::LOCAL_CRATE != id.krate {
Rc::new(csearch::get_enum_variants(cx, id))
} else {
- /*
- Although both this code and check_enum_variants in typeck/check
- call eval_const_expr, it should never get called twice for the same
- expr, since check_enum_variants also updates the enum_var_cache
- */
match cx.map.get(id.node) {
ast_map::NodeItem(ref item) => {
match item.node {
ast::ItemEnum(ref enum_definition, _) => {
- let mut last_discriminant: Option<Disr> = None;
- Rc::new(enum_definition.variants.iter().map(|variant| {
-
- let mut discriminant = INITIAL_DISCRIMINANT_VALUE;
- if let Some(ref e) = variant.node.disr_expr {
- // Preserve all values, and prefer signed.
- let ty = Some(cx.types.i64);
- match const_eval::eval_const_expr_partial(cx, &**e, ty) {
- Ok(const_eval::const_int(val)) => {
- discriminant = val as Disr;
- }
- Ok(const_eval::const_uint(val)) => {
- discriminant = val as Disr;
- }
- Ok(_) => {
- span_err!(cx.sess, e.span, E0304,
- "expected signed integer constant");
- }
- Err(err) => {
- span_err!(cx.sess, err.span, E0305,
- "constant evaluation error: {}",
- err.description());
- }
- }
- } else {
- if let Some(val) = last_discriminant {
- if let Some(v) = val.checked_add(1) {
- discriminant = v
- } else {
- cx.sess.span_err(
- variant.span,
- &format!("Discriminant overflowed!"));
- }
- } else {
- discriminant = INITIAL_DISCRIMINANT_VALUE;
- }
- }
-
- last_discriminant = Some(discriminant);
- Rc::new(VariantInfo::from_ast_variant(cx, &**variant,
- discriminant))
- }).collect())
+ Rc::new(compute_enum_variants(
+ cx,
+ &enum_definition.variants,
+ lookup_repr_hints(cx, id).get(0)))
}
_ => {
cx.sess.bug("enum_variants: id not bound to an enum")
"expected positive integer for repeat count, found {}",
found);
}
- Err(_) => {
+ Err(err) => {
+ let err_description = err.description();
let found = match count_expr.node {
ast::ExprPath(None, ast::Path {
global: false,
ref segments,
..
}) if segments.len() == 1 =>
- "variable",
+ format!("{}", "found variable"),
_ =>
- "non-constant expression"
+ format!("but {}", err_description),
};
span_err!(tcx.sess, count_expr.span, E0307,
- "expected constant integer for repeat count, found {}",
+ "expected constant integer for repeat count, {}",
found);
}
}
use middle::ty::{self, Ty};
use middle::traits;
use std::rc::Rc;
+use syntax::abi;
+use syntax::ast;
use syntax::owned_slice::OwnedSlice;
use util::ppaux::Repr;
/// The TypeFoldable trait is implemented for every type that can be folded.
/// Basically, every type that has a corresponding method in TypeFolder.
-pub trait TypeFoldable<'tcx> {
+pub trait TypeFoldable<'tcx>: Repr<'tcx> + Clone {
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self;
}
// can easily refactor the folding into the TypeFolder trait as
// needed.
-impl<'tcx> TypeFoldable<'tcx> for () {
- fn fold_with<F:TypeFolder<'tcx>>(&self, _: &mut F) -> () {
- ()
+macro_rules! CopyImpls {
+ ($($ty:ty),+) => {
+ $(
+ impl<'tcx> TypeFoldable<'tcx> for $ty {
+ fn fold_with<F:TypeFolder<'tcx>>(&self, _: &mut F) -> $ty {
+ *self
+ }
+ }
+ )+
}
}
+CopyImpls! { (), ast::Unsafety, abi::Abi }
+
impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> (T, U) {
(self.0.fold_with(folder), self.1.fold_with(folder))
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use middle::ty::{self, Ty};
+use middle::ty_relate::{self, Relate, TypeRelation, RelateResult};
+use util::ppaux::Repr;
+
+/// A type "A" *matches* "B" if the fresh types in B could be
+/// substituted with values so as to make it equal to A. Matching is
+/// intended to be used only on freshened types, and it basically
+/// indicates if the non-freshened versions of A and B could have been
+/// unified.
+///
+/// It is only an approximation. If it yields false, unification would
+/// definitely fail, but a true result doesn't mean unification would
+/// succeed. This is because we don't track the "side-constraints" on
+/// type variables, nor do we track if the same freshened type appears
+/// more than once. To some extent these approximations could be
+/// fixed, given effort.
+///
+/// Like subtyping, matching is really a binary relation, so the only
+/// important thing about the result is Ok/Err. Also, matching never
+/// affects any type variables or unification state.
+pub struct Match<'a, 'tcx: 'a> {
+ tcx: &'a ty::ctxt<'tcx>
+}
+
+impl<'a, 'tcx> Match<'a, 'tcx> {
+ pub fn new(tcx: &'a ty::ctxt<'tcx>) -> Match<'a, 'tcx> {
+ Match { tcx: tcx }
+ }
+}
+
+impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Match<'a, 'tcx> {
+ fn tag(&self) -> &'static str { "Match" }
+ fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.tcx }
+ fn a_is_expected(&self) -> bool { true } // irrelevant
+
+ fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
+ _: ty::Variance,
+ a: &T,
+ b: &T)
+ -> RelateResult<'tcx, T>
+ {
+ self.relate(a, b)
+ }
+
+ fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
+ debug!("{}.regions({}, {})",
+ self.tag(),
+ a.repr(self.tcx()),
+ b.repr(self.tcx()));
+ Ok(a)
+ }
+
+ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+ debug!("{}.tys({}, {})", self.tag(),
+ a.repr(self.tcx()), b.repr(self.tcx()));
+ if a == b { return Ok(a); }
+
+ match (&a.sty, &b.sty) {
+ (_, &ty::ty_infer(ty::FreshTy(_))) |
+ (_, &ty::ty_infer(ty::FreshIntTy(_))) => {
+ Ok(a)
+ }
+
+ (&ty::ty_infer(_), _) |
+ (_, &ty::ty_infer(_)) => {
+ Err(ty::terr_sorts(ty_relate::expected_found(self, &a, &b)))
+ }
+
+ (&ty::ty_err, _) | (_, &ty::ty_err) => {
+ Ok(self.tcx().types.err)
+ }
+
+ _ => {
+ ty_relate::super_relate_tys(self, a, b)
+ }
+ }
+ }
+
+ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
+ -> RelateResult<'tcx, ty::Binder<T>>
+ where T: Relate<'a,'tcx>
+ {
+ Ok(ty::Binder(try!(self.relate(a.skip_binder(), b.skip_binder()))))
+ }
+}
--- /dev/null
+// Copyright 2012-2013 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.
+
+//! Generalized type relating mechanism. A type relation R relates a
+//! pair of values (A, B). A and B are usually types or regions but
+//! can be other things. Examples of type relations are subtyping,
+//! type equality, etc.
+
+use middle::subst::{ErasedRegions, NonerasedRegions, ParamSpace, Substs};
+use middle::ty::{self, Ty};
+use middle::ty_fold::TypeFoldable;
+use std::rc::Rc;
+use syntax::abi;
+use syntax::ast;
+use util::ppaux::Repr;
+
+pub type RelateResult<'tcx, T> = Result<T, ty::type_err<'tcx>>;
+
+pub trait TypeRelation<'a,'tcx> : Sized {
+ fn tcx(&self) -> &'a ty::ctxt<'tcx>;
+
+ /// Returns a static string we can use for printouts.
+ fn tag(&self) -> &'static str;
+
+ /// Returns true if the value `a` is the "expected" type in the
+ /// relation. Just affects error messages.
+ fn a_is_expected(&self) -> bool;
+
+ /// Generic relation routine suitable for most anything.
+ fn relate<T:Relate<'a,'tcx>>(&mut self, a: &T, b: &T) -> RelateResult<'tcx, T> {
+ Relate::relate(self, a, b)
+ }
+
+ /// Switch variance for the purpose of relating `a` and `b`.
+ fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
+ variance: ty::Variance,
+ a: &T,
+ b: &T)
+ -> RelateResult<'tcx, T>;
+
+ // Overrideable relations. You shouldn't typically call these
+ // directly, instead call `relate()`, which in turn calls
+ // these. This is both more uniform but also allows us to add
+ // additional hooks for other types in the future if needed
+ // without making older code, which called `relate`, obsolete.
+
+ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>)
+ -> RelateResult<'tcx, Ty<'tcx>>;
+
+ fn regions(&mut self, a: ty::Region, b: ty::Region)
+ -> RelateResult<'tcx, ty::Region>;
+
+ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
+ -> RelateResult<'tcx, ty::Binder<T>>
+ where T: Relate<'a,'tcx>;
+}
+
+pub trait Relate<'a,'tcx>: TypeFoldable<'tcx> {
+ fn relate<R:TypeRelation<'a,'tcx>>(relation: &mut R,
+ a: &Self,
+ b: &Self)
+ -> RelateResult<'tcx, Self>;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Relate impls
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::mt<'tcx> {
+ fn relate<R>(relation: &mut R,
+ a: &ty::mt<'tcx>,
+ b: &ty::mt<'tcx>)
+ -> RelateResult<'tcx, ty::mt<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ debug!("{}.mts({}, {})",
+ relation.tag(),
+ a.repr(relation.tcx()),
+ b.repr(relation.tcx()));
+ if a.mutbl != b.mutbl {
+ Err(ty::terr_mutability)
+ } else {
+ let mutbl = a.mutbl;
+ let variance = match mutbl {
+ ast::MutImmutable => ty::Covariant,
+ ast::MutMutable => ty::Invariant,
+ };
+ let ty = try!(relation.relate_with_variance(variance, &a.ty, &b.ty));
+ Ok(ty::mt {ty: ty, mutbl: mutbl})
+ }
+ }
+}
+
+// substitutions are not themselves relatable without more context,
+// but they is an important subroutine for things that ARE relatable,
+// like traits etc.
+fn relate_item_substs<'a,'tcx:'a,R>(relation: &mut R,
+ item_def_id: ast::DefId,
+ a_subst: &Substs<'tcx>,
+ b_subst: &Substs<'tcx>)
+ -> RelateResult<'tcx, Substs<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+{
+ debug!("substs: item_def_id={} a_subst={} b_subst={}",
+ item_def_id.repr(relation.tcx()),
+ a_subst.repr(relation.tcx()),
+ b_subst.repr(relation.tcx()));
+
+ let variances;
+ let opt_variances = if relation.tcx().variance_computed.get() {
+ variances = ty::item_variances(relation.tcx(), item_def_id);
+ Some(&*variances)
+ } else {
+ None
+ };
+ relate_substs(relation, opt_variances, a_subst, b_subst)
+}
+
+fn relate_substs<'a,'tcx,R>(relation: &mut R,
+ variances: Option<&ty::ItemVariances>,
+ a_subst: &Substs<'tcx>,
+ b_subst: &Substs<'tcx>)
+ -> RelateResult<'tcx, Substs<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+{
+ let mut substs = Substs::empty();
+
+ for &space in &ParamSpace::all() {
+ let a_tps = a_subst.types.get_slice(space);
+ let b_tps = b_subst.types.get_slice(space);
+ let t_variances = variances.map(|v| v.types.get_slice(space));
+ let tps = try!(relate_type_params(relation, t_variances, a_tps, b_tps));
+ substs.types.replace(space, tps);
+ }
+
+ match (&a_subst.regions, &b_subst.regions) {
+ (&ErasedRegions, _) | (_, &ErasedRegions) => {
+ substs.regions = ErasedRegions;
+ }
+
+ (&NonerasedRegions(ref a), &NonerasedRegions(ref b)) => {
+ for &space in &ParamSpace::all() {
+ let a_regions = a.get_slice(space);
+ let b_regions = b.get_slice(space);
+ let r_variances = variances.map(|v| v.regions.get_slice(space));
+ let regions = try!(relate_region_params(relation,
+ r_variances,
+ a_regions,
+ b_regions));
+ substs.mut_regions().replace(space, regions);
+ }
+ }
+ }
+
+ Ok(substs)
+}
+
+fn relate_type_params<'a,'tcx,R>(relation: &mut R,
+ variances: Option<&[ty::Variance]>,
+ a_tys: &[Ty<'tcx>],
+ b_tys: &[Ty<'tcx>])
+ -> RelateResult<'tcx, Vec<Ty<'tcx>>>
+ where R: TypeRelation<'a,'tcx>
+{
+ if a_tys.len() != b_tys.len() {
+ return Err(ty::terr_ty_param_size(expected_found(relation,
+ &a_tys.len(),
+ &b_tys.len())));
+ }
+
+ (0 .. a_tys.len())
+ .map(|i| {
+ let a_ty = a_tys[i];
+ let b_ty = b_tys[i];
+ let v = variances.map_or(ty::Invariant, |v| v[i]);
+ relation.relate_with_variance(v, &a_ty, &b_ty)
+ })
+ .collect()
+}
+
+fn relate_region_params<'a,'tcx:'a,R>(relation: &mut R,
+ variances: Option<&[ty::Variance]>,
+ a_rs: &[ty::Region],
+ b_rs: &[ty::Region])
+ -> RelateResult<'tcx, Vec<ty::Region>>
+ where R: TypeRelation<'a,'tcx>
+{
+ let tcx = relation.tcx();
+ let num_region_params = a_rs.len();
+
+ debug!("relate_region_params(a_rs={}, \
+ b_rs={}, variances={})",
+ a_rs.repr(tcx),
+ b_rs.repr(tcx),
+ variances.repr(tcx));
+
+ assert_eq!(num_region_params,
+ variances.map_or(num_region_params,
+ |v| v.len()));
+
+ assert_eq!(num_region_params, b_rs.len());
+
+ (0..a_rs.len())
+ .map(|i| {
+ let a_r = a_rs[i];
+ let b_r = b_rs[i];
+ let variance = variances.map_or(ty::Invariant, |v| v[i]);
+ relation.relate_with_variance(variance, &a_r, &b_r)
+ })
+ .collect()
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::BareFnTy<'tcx> {
+ fn relate<R>(relation: &mut R,
+ a: &ty::BareFnTy<'tcx>,
+ b: &ty::BareFnTy<'tcx>)
+ -> RelateResult<'tcx, ty::BareFnTy<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ let unsafety = try!(relation.relate(&a.unsafety, &b.unsafety));
+ let abi = try!(relation.relate(&a.abi, &b.abi));
+ let sig = try!(relation.relate(&a.sig, &b.sig));
+ Ok(ty::BareFnTy {unsafety: unsafety,
+ abi: abi,
+ sig: sig})
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::FnSig<'tcx> {
+ fn relate<R>(relation: &mut R,
+ a: &ty::FnSig<'tcx>,
+ b: &ty::FnSig<'tcx>)
+ -> RelateResult<'tcx, ty::FnSig<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ if a.variadic != b.variadic {
+ return Err(ty::terr_variadic_mismatch(
+ expected_found(relation, &a.variadic, &b.variadic)));
+ }
+
+ let inputs = try!(relate_arg_vecs(relation,
+ &a.inputs,
+ &b.inputs));
+
+ let output = try!(match (a.output, b.output) {
+ (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) =>
+ Ok(ty::FnConverging(try!(relation.relate(&a_ty, &b_ty)))),
+ (ty::FnDiverging, ty::FnDiverging) =>
+ Ok(ty::FnDiverging),
+ (a, b) =>
+ Err(ty::terr_convergence_mismatch(
+ expected_found(relation, &(a != ty::FnDiverging), &(b != ty::FnDiverging)))),
+ });
+
+ return Ok(ty::FnSig {inputs: inputs,
+ output: output,
+ variadic: a.variadic});
+ }
+}
+
+fn relate_arg_vecs<'a,'tcx,R>(relation: &mut R,
+ a_args: &[Ty<'tcx>],
+ b_args: &[Ty<'tcx>])
+ -> RelateResult<'tcx, Vec<Ty<'tcx>>>
+ where R: TypeRelation<'a,'tcx>
+{
+ if a_args.len() != b_args.len() {
+ return Err(ty::terr_arg_count);
+ }
+
+ a_args.iter()
+ .zip(b_args.iter())
+ .map(|(a, b)| relation.relate_with_variance(ty::Contravariant, a, b))
+ .collect()
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ast::Unsafety {
+ fn relate<R>(relation: &mut R,
+ a: &ast::Unsafety,
+ b: &ast::Unsafety)
+ -> RelateResult<'tcx, ast::Unsafety>
+ where R: TypeRelation<'a,'tcx>
+ {
+ if a != b {
+ Err(ty::terr_unsafety_mismatch(expected_found(relation, a, b)))
+ } else {
+ Ok(*a)
+ }
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for abi::Abi {
+ fn relate<R>(relation: &mut R,
+ a: &abi::Abi,
+ b: &abi::Abi)
+ -> RelateResult<'tcx, abi::Abi>
+ where R: TypeRelation<'a,'tcx>
+ {
+ if a == b {
+ Ok(*a)
+ } else {
+ Err(ty::terr_abi_mismatch(expected_found(relation, a, b)))
+ }
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ProjectionTy<'tcx> {
+ fn relate<R>(relation: &mut R,
+ a: &ty::ProjectionTy<'tcx>,
+ b: &ty::ProjectionTy<'tcx>)
+ -> RelateResult<'tcx, ty::ProjectionTy<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ if a.item_name != b.item_name {
+ Err(ty::terr_projection_name_mismatched(
+ expected_found(relation, &a.item_name, &b.item_name)))
+ } else {
+ let trait_ref = try!(relation.relate(&*a.trait_ref, &*b.trait_ref));
+ Ok(ty::ProjectionTy { trait_ref: Rc::new(trait_ref), item_name: a.item_name })
+ }
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ProjectionPredicate<'tcx> {
+ fn relate<R>(relation: &mut R,
+ a: &ty::ProjectionPredicate<'tcx>,
+ b: &ty::ProjectionPredicate<'tcx>)
+ -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ let projection_ty = try!(relation.relate(&a.projection_ty, &b.projection_ty));
+ let ty = try!(relation.relate(&a.ty, &b.ty));
+ Ok(ty::ProjectionPredicate { projection_ty: projection_ty, ty: ty })
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for Vec<ty::PolyProjectionPredicate<'tcx>> {
+ fn relate<R>(relation: &mut R,
+ a: &Vec<ty::PolyProjectionPredicate<'tcx>>,
+ b: &Vec<ty::PolyProjectionPredicate<'tcx>>)
+ -> RelateResult<'tcx, Vec<ty::PolyProjectionPredicate<'tcx>>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ // To be compatible, `a` and `b` must be for precisely the
+ // same set of traits and item names. We always require that
+ // projection bounds lists are sorted by trait-def-id and item-name,
+ // so we can just iterate through the lists pairwise, so long as they are the
+ // same length.
+ if a.len() != b.len() {
+ Err(ty::terr_projection_bounds_length(expected_found(relation, &a.len(), &b.len())))
+ } else {
+ a.iter()
+ .zip(b.iter())
+ .map(|(a, b)| relation.relate(a, b))
+ .collect()
+ }
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ExistentialBounds<'tcx> {
+ fn relate<R>(relation: &mut R,
+ a: &ty::ExistentialBounds<'tcx>,
+ b: &ty::ExistentialBounds<'tcx>)
+ -> RelateResult<'tcx, ty::ExistentialBounds<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ let r = try!(relation.relate_with_variance(ty::Contravariant,
+ &a.region_bound,
+ &b.region_bound));
+ let nb = try!(relation.relate(&a.builtin_bounds, &b.builtin_bounds));
+ let pb = try!(relation.relate(&a.projection_bounds, &b.projection_bounds));
+ Ok(ty::ExistentialBounds { region_bound: r,
+ builtin_bounds: nb,
+ projection_bounds: pb })
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::BuiltinBounds {
+ fn relate<R>(relation: &mut R,
+ a: &ty::BuiltinBounds,
+ b: &ty::BuiltinBounds)
+ -> RelateResult<'tcx, ty::BuiltinBounds>
+ where R: TypeRelation<'a,'tcx>
+ {
+ // Two sets of builtin bounds are only relatable if they are
+ // precisely the same (but see the coercion code).
+ if a != b {
+ Err(ty::terr_builtin_bounds(expected_found(relation, a, b)))
+ } else {
+ Ok(*a)
+ }
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::TraitRef<'tcx> {
+ fn relate<R>(relation: &mut R,
+ a: &ty::TraitRef<'tcx>,
+ b: &ty::TraitRef<'tcx>)
+ -> RelateResult<'tcx, ty::TraitRef<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ // Different traits cannot be related
+ if a.def_id != b.def_id {
+ Err(ty::terr_traits(expected_found(relation, &a.def_id, &b.def_id)))
+ } else {
+ let substs = try!(relate_item_substs(relation, a.def_id, a.substs, b.substs));
+ Ok(ty::TraitRef { def_id: a.def_id, substs: relation.tcx().mk_substs(substs) })
+ }
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for Ty<'tcx> {
+ fn relate<R>(relation: &mut R,
+ a: &Ty<'tcx>,
+ b: &Ty<'tcx>)
+ -> RelateResult<'tcx, Ty<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ relation.tys(a, b)
+ }
+}
+
+/// The main "type relation" routine. Note that this does not handle
+/// inference artifacts, so you should filter those out before calling
+/// it.
+pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R,
+ a: Ty<'tcx>,
+ b: Ty<'tcx>)
+ -> RelateResult<'tcx, Ty<'tcx>>
+ where R: TypeRelation<'a,'tcx>
+{
+ let tcx = relation.tcx();
+ let a_sty = &a.sty;
+ let b_sty = &b.sty;
+ debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty);
+ match (a_sty, b_sty) {
+ (&ty::ty_infer(_), _) |
+ (_, &ty::ty_infer(_)) =>
+ {
+ // The caller should handle these cases!
+ tcx.sess.bug("var types encountered in super_relate_tys")
+ }
+
+ (&ty::ty_err, _) | (_, &ty::ty_err) =>
+ {
+ Ok(tcx.types.err)
+ }
+
+ (&ty::ty_char, _) |
+ (&ty::ty_bool, _) |
+ (&ty::ty_int(_), _) |
+ (&ty::ty_uint(_), _) |
+ (&ty::ty_float(_), _) |
+ (&ty::ty_str, _)
+ if a == b =>
+ {
+ Ok(a)
+ }
+
+ (&ty::ty_param(ref a_p), &ty::ty_param(ref b_p))
+ if a_p.idx == b_p.idx && a_p.space == b_p.space =>
+ {
+ Ok(a)
+ }
+
+ (&ty::ty_enum(a_id, a_substs), &ty::ty_enum(b_id, b_substs))
+ if a_id == b_id =>
+ {
+ let substs = try!(relate_item_substs(relation, a_id, a_substs, b_substs));
+ Ok(ty::mk_enum(tcx, a_id, tcx.mk_substs(substs)))
+ }
+
+ (&ty::ty_trait(ref a_), &ty::ty_trait(ref b_)) =>
+ {
+ let principal = try!(relation.relate(&a_.principal, &b_.principal));
+ let bounds = try!(relation.relate(&a_.bounds, &b_.bounds));
+ Ok(ty::mk_trait(tcx, principal, bounds))
+ }
+
+ (&ty::ty_struct(a_id, a_substs), &ty::ty_struct(b_id, b_substs))
+ if a_id == b_id =>
+ {
+ let substs = try!(relate_item_substs(relation, a_id, a_substs, b_substs));
+ Ok(ty::mk_struct(tcx, a_id, tcx.mk_substs(substs)))
+ }
+
+ (&ty::ty_closure(a_id, a_substs),
+ &ty::ty_closure(b_id, b_substs))
+ if a_id == b_id =>
+ {
+ // All ty_closure types with the same id represent
+ // the (anonymous) type of the same closure expression. So
+ // all of their regions should be equated.
+ let substs = try!(relate_substs(relation, None, a_substs, b_substs));
+ Ok(ty::mk_closure(tcx, a_id, tcx.mk_substs(substs)))
+ }
+
+ (&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) =>
+ {
+ let typ = try!(relation.relate(&a_inner, &b_inner));
+ Ok(ty::mk_uniq(tcx, typ))
+ }
+
+ (&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) =>
+ {
+ let mt = try!(relation.relate(a_mt, b_mt));
+ Ok(ty::mk_ptr(tcx, mt))
+ }
+
+ (&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) =>
+ {
+ let r = try!(relation.relate_with_variance(ty::Contravariant, a_r, b_r));
+ let mt = try!(relation.relate(a_mt, b_mt));
+ Ok(ty::mk_rptr(tcx, tcx.mk_region(r), mt))
+ }
+
+ (&ty::ty_vec(a_t, Some(sz_a)), &ty::ty_vec(b_t, Some(sz_b))) =>
+ {
+ let t = try!(relation.relate(&a_t, &b_t));
+ if sz_a == sz_b {
+ Ok(ty::mk_vec(tcx, t, Some(sz_a)))
+ } else {
+ Err(ty::terr_fixed_array_size(expected_found(relation, &sz_a, &sz_b)))
+ }
+ }
+
+ (&ty::ty_vec(a_t, None), &ty::ty_vec(b_t, None)) =>
+ {
+ let t = try!(relation.relate(&a_t, &b_t));
+ Ok(ty::mk_vec(tcx, t, None))
+ }
+
+ (&ty::ty_tup(ref as_), &ty::ty_tup(ref bs)) =>
+ {
+ if as_.len() == bs.len() {
+ let ts = try!(as_.iter()
+ .zip(bs.iter())
+ .map(|(a, b)| relation.relate(a, b))
+ .collect::<Result<_, _>>());
+ Ok(ty::mk_tup(tcx, ts))
+ } else if as_.len() != 0 && bs.len() != 0 {
+ Err(ty::terr_tuple_size(
+ expected_found(relation, &as_.len(), &bs.len())))
+ } else {
+ Err(ty::terr_sorts(expected_found(relation, &a, &b)))
+ }
+ }
+
+ (&ty::ty_bare_fn(a_opt_def_id, a_fty), &ty::ty_bare_fn(b_opt_def_id, b_fty))
+ if a_opt_def_id == b_opt_def_id =>
+ {
+ let fty = try!(relation.relate(a_fty, b_fty));
+ Ok(ty::mk_bare_fn(tcx, a_opt_def_id, tcx.mk_bare_fn(fty)))
+ }
+
+ (&ty::ty_projection(ref a_data), &ty::ty_projection(ref b_data)) =>
+ {
+ let projection_ty = try!(relation.relate(a_data, b_data));
+ Ok(ty::mk_projection(tcx, projection_ty.trait_ref, projection_ty.item_name))
+ }
+
+ _ =>
+ {
+ Err(ty::terr_sorts(expected_found(relation, &a, &b)))
+ }
+ }
+}
+
+impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::Region {
+ fn relate<R>(relation: &mut R,
+ a: &ty::Region,
+ b: &ty::Region)
+ -> RelateResult<'tcx, ty::Region>
+ where R: TypeRelation<'a,'tcx>
+ {
+ relation.regions(*a, *b)
+ }
+}
+
+impl<'a,'tcx:'a,T> Relate<'a,'tcx> for ty::Binder<T>
+ where T: Relate<'a,'tcx>
+{
+ fn relate<R>(relation: &mut R,
+ a: &ty::Binder<T>,
+ b: &ty::Binder<T>)
+ -> RelateResult<'tcx, ty::Binder<T>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ relation.binders(a, b)
+ }
+}
+
+impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Rc<T>
+ where T: Relate<'a,'tcx>
+{
+ fn relate<R>(relation: &mut R,
+ a: &Rc<T>,
+ b: &Rc<T>)
+ -> RelateResult<'tcx, Rc<T>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ let a: &T = a;
+ let b: &T = b;
+ Ok(Rc::new(try!(relation.relate(a, b))))
+ }
+}
+
+impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Box<T>
+ where T: Relate<'a,'tcx>
+{
+ fn relate<R>(relation: &mut R,
+ a: &Box<T>,
+ b: &Box<T>)
+ -> RelateResult<'tcx, Box<T>>
+ where R: TypeRelation<'a,'tcx>
+ {
+ let a: &T = a;
+ let b: &T = b;
+ Ok(Box::new(try!(relation.relate(a, b))))
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Error handling
+
+pub fn expected_found<'a,'tcx,R,T>(relation: &mut R,
+ a: &T,
+ b: &T)
+ -> ty::expected_found<T>
+ where R: TypeRelation<'a,'tcx>, T: Clone
+{
+ expected_found_bool(relation.a_is_expected(), a, b)
+}
+
+pub fn expected_found_bool<T>(a_is_expected: bool,
+ a: &T,
+ b: &T)
+ -> ty::expected_found<T>
+ where T: Clone
+{
+ let a = a.clone();
+ let b = b.clone();
+ if a_is_expected {
+ ty::expected_found {expected: a, found: b}
+ } else {
+ ty::expected_found {expected: b, found: a}
+ }
+}
+
use middle::ty::{self, Ty};
use std::iter::Iterator;
+use std::vec::IntoIter;
pub struct TypeWalker<'tcx> {
stack: Vec<Ty<'tcx>>,
TypeWalker { stack: vec!(ty), last_subtree: 1, }
}
- fn push_subtypes(&mut self, parent_ty: Ty<'tcx>) {
- match parent_ty.sty {
- ty::ty_bool | ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) |
- ty::ty_str | ty::ty_infer(_) | ty::ty_param(_) | ty::ty_err => {
- }
- ty::ty_uniq(ty) | ty::ty_vec(ty, _) => {
- self.stack.push(ty);
- }
- ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => {
- self.stack.push(mt.ty);
- }
- ty::ty_projection(ref data) => {
- self.push_reversed(data.trait_ref.substs.types.as_slice());
- }
- ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => {
- self.push_reversed(principal.substs().types.as_slice());
- self.push_reversed(&bounds.projection_bounds.iter().map(|pred| {
- pred.0.ty
- }).collect::<Vec<_>>());
- }
- ty::ty_enum(_, ref substs) |
- ty::ty_struct(_, ref substs) |
- ty::ty_closure(_, ref substs) => {
- self.push_reversed(substs.types.as_slice());
- }
- ty::ty_tup(ref ts) => {
- self.push_reversed(ts);
- }
- ty::ty_bare_fn(_, ref ft) => {
- self.push_sig_subtypes(&ft.sig);
- }
- }
- }
-
- fn push_sig_subtypes(&mut self, sig: &ty::PolyFnSig<'tcx>) {
- match sig.0.output {
- ty::FnConverging(output) => { self.stack.push(output); }
- ty::FnDiverging => { }
- }
- self.push_reversed(&sig.0.inputs);
- }
-
- fn push_reversed(&mut self, tys: &[Ty<'tcx>]) {
- // We push slices on the stack in reverse order so as to
- // maintain a pre-order traversal. As of the time of this
- // writing, the fact that the traversal is pre-order is not
- // known to be significant to any code, but it seems like the
- // natural order one would expect (basically, the order of the
- // types as they are written).
- for &ty in tys.iter().rev() {
- self.stack.push(ty);
- }
- }
-
/// Skips the subtree of types corresponding to the last type
/// returned by `next()`.
///
}
Some(ty) => {
self.last_subtree = self.stack.len();
- self.push_subtypes(ty);
+ push_subtypes(&mut self.stack, ty);
debug!("next: stack={:?}", self.stack);
Some(ty)
}
}
}
}
+
+pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter<Ty<'tcx>> {
+ let mut stack = vec![];
+ push_subtypes(&mut stack, ty);
+ stack.into_iter()
+}
+
+fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, parent_ty: Ty<'tcx>) {
+ match parent_ty.sty {
+ ty::ty_bool | ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) |
+ ty::ty_str | ty::ty_infer(_) | ty::ty_param(_) | ty::ty_err => {
+ }
+ ty::ty_uniq(ty) | ty::ty_vec(ty, _) => {
+ stack.push(ty);
+ }
+ ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => {
+ stack.push(mt.ty);
+ }
+ ty::ty_projection(ref data) => {
+ push_reversed(stack, data.trait_ref.substs.types.as_slice());
+ }
+ ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => {
+ push_reversed(stack, principal.substs().types.as_slice());
+ push_reversed(stack, &bounds.projection_bounds.iter().map(|pred| {
+ pred.0.ty
+ }).collect::<Vec<_>>());
+ }
+ ty::ty_enum(_, ref substs) |
+ ty::ty_struct(_, ref substs) |
+ ty::ty_closure(_, ref substs) => {
+ push_reversed(stack, substs.types.as_slice());
+ }
+ ty::ty_tup(ref ts) => {
+ push_reversed(stack, ts);
+ }
+ ty::ty_bare_fn(_, ref ft) => {
+ push_sig_subtypes(stack, &ft.sig);
+ }
+ }
+}
+
+fn push_sig_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, sig: &ty::PolyFnSig<'tcx>) {
+ match sig.0.output {
+ ty::FnConverging(output) => { stack.push(output); }
+ ty::FnDiverging => { }
+ }
+ push_reversed(stack, &sig.0.inputs);
+}
+
+fn push_reversed<'tcx>(stack: &mut Vec<Ty<'tcx>>, tys: &[Ty<'tcx>]) {
+ // We push slices on the stack in reverse order so as to
+ // maintain a pre-order traversal. As of the time of this
+ // writing, the fact that the traversal is pre-order is not
+ // known to be significant to any code, but it seems like the
+ // natural order one would expect (basically, the order of the
+ // types as they are written).
+ for &ty in tys.iter().rev() {
+ stack.push(ty);
+ }
+}
#[cfg(unix)]
pub fn path2cstr(p: &Path) -> CString {
use std::os::unix::prelude::*;
- use std::ffi::AsOsStr;
- CString::new(p.as_os_str().as_bytes()).unwrap()
+ use std::ffi::OsStr;
+ let p: &OsStr = p.as_ref();
+ CString::new(p.as_bytes()).unwrap()
}
#[cfg(windows)]
pub fn path2cstr(p: &Path) -> CString {
}
ty_infer(infer_ty) => infer_ty_to_string(cx, infer_ty),
ty_err => "[type error]".to_string(),
- ty_param(ref param_ty) => {
- if cx.sess.verbose() {
- param_ty.repr(cx)
- } else {
- param_ty.user_string(cx)
- }
- }
+ ty_param(ref param_ty) => param_ty.user_string(cx),
ty_enum(did, substs) | ty_struct(did, substs) => {
let base = ty::item_path_str(cx, did);
parameterized(cx, &base, substs, did, &[],
}
}
}
+
+impl<'tcx> Repr<'tcx> for ast::Unsafety {
+ fn repr(&self, _: &ctxt<'tcx>) -> String {
+ format!("{:?}", *self)
+ }
+}
// except according to those terms.
use std::io;
+use std::env;
#[allow(deprecated)] use std::old_path::{self, GenericPath};
#[allow(deprecated)] use std::old_io;
use std::path::{Path, PathBuf};
let old = old_path::Path::new(original.to_str().unwrap());
match old_realpath(&old) {
Ok(p) => Ok(PathBuf::from(p.as_str().unwrap())),
- Err(e) => Err(io::Error::new(io::ErrorKind::Other,
- "realpath error",
- Some(e.to_string())))
+ Err(e) => Err(io::Error::new(io::ErrorKind::Other, e))
}
}
#[allow(deprecated)]
fn old_realpath(original: &old_path::Path) -> old_io::IoResult<old_path::Path> {
use std::old_io::fs;
- use std::os;
const MAX_LINKS_FOLLOWED: usize = 256;
- let original = try!(os::getcwd()).join(original);
+ let original = old_path::Path::new(env::current_dir().unwrap()
+ .to_str().unwrap()).join(original);
// Right now lstat on windows doesn't work quite well
if cfg!(windows) {
#![feature(collections)]
#![feature(core)]
#![feature(old_fs)]
-#![feature(io)]
#![feature(old_io)]
#![feature(old_path)]
-#![feature(os)]
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(rand)]
#![feature(path_ext)]
-#![feature(std_misc)]
#![feature(step_by)]
-#![feature(convert)]
#![cfg_attr(test, feature(test, rand))]
extern crate syntax;
#![allow(deprecated)] // to_be32
-use std::iter::{range_step, repeat};
+use std::iter::repeat;
use std::num::Int;
use std::slice::bytes::{MutableByteVector, copy_memory};
use serialize::hex::ToHex;
// Putting the message schedule inside the same loop as the round calculations allows for
// the compiler to generate better code.
- for t in range_step(0, 48, 8) {
+ for t in (0..48).step_by(8) {
schedule_round!(t + 16);
schedule_round!(t + 17);
schedule_round!(t + 18);
sha2_round!(b, c, d, e, f, g, h, a, K32, t + 7);
}
- for t in range_step(48, 64, 8) {
+ for t in (48..64).step_by(8) {
sha2_round!(a, b, c, d, e, f, g, h, K32, t);
sha2_round!(h, a, b, c, d, e, f, g, K32, t + 1);
sha2_round!(g, h, a, b, c, d, e, f, K32, t + 2);
Ok(String::from_utf8(output.stdout).unwrap())
} else {
let error = String::from_utf8(output.stderr);
+ let error = format!("process exit with error: {}",
+ error.unwrap());
Err(io::Error::new(io::ErrorKind::Other,
- "process exit with error",
- error.ok()))
+ &error[..]))
}
});
use std::env;
use std::io::{self, Error, ErrorKind};
use std::fs;
-use std::path::{self, PathBuf, AsPath};
+use std::path::{self, PathBuf, Path};
use std::rand::{thread_rng, Rng};
/// A wrapper for a path to temporary directory implementing automatic
///
/// If no directory can be created, `Err` is returned.
#[allow(deprecated)] // rand usage
- pub fn new_in<P: AsPath + ?Sized>(tmpdir: &P, prefix: &str)
- -> io::Result<TempDir> {
+ pub fn new_in<P: AsRef<Path>>(tmpdir: P, prefix: &str)
+ -> io::Result<TempDir> {
let storage;
- let mut tmpdir = tmpdir.as_path();
+ let mut tmpdir = tmpdir.as_ref();
if !tmpdir.is_absolute() {
let cur_dir = try!(env::current_dir());
storage = cur_dir.join(tmpdir);
}
Err(Error::new(ErrorKind::AlreadyExists,
- "too many temporary directories already exist",
- None))
+ "too many temporary directories already exist"))
}
/// Attempts to make a temporary directory inside of `env::temp_dir()` whose
#![feature(box_syntax)]
#![feature(collections)]
-#![feature(core)]
#![feature(libc)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(unsafe_destructor)]
#![feature(staged_api)]
#![feature(exit_status)]
-#![feature(io)]
#![feature(set_stdio)]
#![feature(unicode)]
-#![feature(convert)]
extern crate arena;
extern crate flate;
try!(pp::space(&mut s.s));
s.synth_comment(item.id.to_string())
}
+ pprust::NodeSubItem(id) => {
+ try!(pp::space(&mut s.s));
+ s.synth_comment(id.to_string())
+ }
pprust::NodeBlock(blk) => {
try!(pp::space(&mut s.s));
s.synth_comment(format!("block {}", blk.id))
fn expand_err_details(r: io::Result<()>) -> io::Result<()> {
r.map_err(|ioerr| {
- io::Error::new(io::ErrorKind::Other, "graphviz::render failed",
- Some(ioerr.to_string()))
+ io::Error::new(io::ErrorKind::Other,
+ &format!("graphviz::render failed: {}", ioerr)[..])
})
}
}
use rustc_typeck::middle::subst;
use rustc_typeck::middle::subst::Subst;
use rustc_typeck::middle::ty::{self, Ty};
-use rustc_typeck::middle::infer::combine::Combine;
+use rustc_typeck::middle::ty_relate::TypeRelation;
use rustc_typeck::middle::infer;
use rustc_typeck::middle::infer::lub::Lub;
use rustc_typeck::middle::infer::glb::Glb;
pub fn sub(&self) -> Sub<'a, 'tcx> {
let trace = self.dummy_type_trace();
- Sub(self.infcx.combine_fields(true, trace))
+ self.infcx.sub(true, trace)
}
pub fn lub(&self) -> Lub<'a, 'tcx> {
let trace = self.dummy_type_trace();
- Lub(self.infcx.combine_fields(true, trace))
+ self.infcx.lub(true, trace)
}
pub fn glb(&self) -> Glb<'a, 'tcx> {
let trace = self.dummy_type_trace();
- Glb(self.infcx.combine_fields(true, trace))
+ self.infcx.glb(true, trace)
}
pub fn make_lub_ty(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> Ty<'tcx> {
- match self.lub().tys(t1, t2) {
+ match self.lub().relate(&t1, &t2) {
Ok(t) => t,
Err(ref e) => panic!("unexpected error computing LUB: {}",
ty::type_err_to_str(self.infcx.tcx, e))
/// 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) {
+ match self.sub().relate(&t1, &t2) {
Ok(_) => { }
Err(ref e) => {
panic!("unexpected error computing sub({},{}): {}",
/// 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) {
+ match self.sub().relate(&t1, &t2) {
Err(_) => { }
Ok(_) => {
panic!("unexpected success computing sub({},{})",
/// 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) {
+ match self.lub().relate(&t1, &t2) {
Ok(t) => {
self.assert_eq(t, t_lub);
}
self.ty_to_string(t1),
self.ty_to_string(t2),
self.ty_to_string(t_glb));
- match self.glb().tys(t1, t2) {
+ match self.glb().relate(&t1, &t2) {
Err(e) => {
panic!("unexpected error computing LUB: {:?}", e)
}
fn lub_returning_scope() {
test_env(EMPTY_SOURCE_STR,
errors(&["cannot infer an appropriate lifetime"]), |env| {
+ env.create_simple_region_hierarchy();
let t_rptr_scope10 = env.t_rptr_scope(10);
let t_rptr_scope11 = env.t_rptr_scope(11);
let tup2_ty = ty::mk_tup(tcx, vec!(tup1_ty, tup1_ty, uint_ty));
let uniq_ty = ty::mk_uniq(tcx, tup2_ty);
let walked: Vec<_> = uniq_ty.walk().collect();
- assert_eq!([uniq_ty,
- tup2_ty,
- tup1_ty, int_ty, uint_ty, int_ty, uint_ty,
- tup1_ty, int_ty, uint_ty, int_ty, uint_ty,
- uint_ty],
- walked);
+ assert_eq!(walked, [uniq_ty,
+ tup2_ty,
+ tup1_ty, int_ty, uint_ty, int_ty, uint_ty,
+ tup1_ty, int_ty, uint_ty, int_ty, uint_ty,
+ uint_ty]);
})
}
#[cfg(unix)]
fn path2cstr(p: &Path) -> CString {
use std::os::unix::prelude::*;
- use std::ffi::AsOsStr;
- CString::new(p.as_os_str().as_bytes()).unwrap()
+ use std::ffi::OsStr;
+ let p: &OsStr = p.as_ref();
+ CString::new(p.as_bytes()).unwrap()
}
#[cfg(windows)]
fn path2cstr(p: &Path) -> CString {
#![feature(libc)]
#![feature(link_args)]
#![feature(staged_api)]
-#![cfg_attr(unix, feature(std_misc))]
extern crate libc;
#[macro_use] #[no_link] extern crate rustc_bitflags;
pub fn LLVMIsAArgument(value_ref: ValueRef) -> ValueRef;
pub fn LLVMIsAAllocaInst(value_ref: ValueRef) -> ValueRef;
+ pub fn LLVMIsAConstantInt(value_ref: ValueRef) -> ValueRef;
pub fn LLVMInitializeX86TargetInfo();
pub fn LLVMInitializeX86Target();
}
enum NameDefinition {
- NoNameDefinition, //< The name was unbound.
- ChildNameDefinition(Def, LastPrivate), //< The name identifies an immediate child.
- ImportNameDefinition(Def, LastPrivate) //< The name identifies an import.
+ // The name was unbound.
+ NoNameDefinition,
+ // The name identifies an immediate child.
+ ChildNameDefinition(Def, LastPrivate),
+ // The name identifies an import.
+ ImportNameDefinition(Def, LastPrivate),
}
impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> {
// The current self type if inside an impl (used for better errors).
current_self_type: Option<Ty>,
- // The ident for the keyword "self".
- self_name: Name,
- // The ident for the non-keyword "Self".
- type_self_name: Name,
-
// The idents for the primitive types.
primitive_type_table: PrimitiveTypeTable,
current_trait_ref: None,
current_self_type: None,
- self_name: special_names::self_,
- type_self_name: special_names::type_self,
-
primitive_type_table: PrimitiveTypeTable::new(),
def_map: RefCell::new(NodeMap()),
let mut self_type_rib = Rib::new(ItemRibKind);
// plain insert (no renaming, types are not currently hygienic....)
- let name = self.type_self_name;
+ let name = special_names::type_self;
self_type_rib.bindings.insert(name, DlDef(DefSelfTy(item.id)));
self.type_ribs.push(self_type_rib);
fn with_optional_trait_ref<T, F>(&mut self,
opt_trait_ref: Option<&TraitRef>,
- f: F) -> T where
- F: FnOnce(&mut Resolver) -> T,
+ f: F)
+ -> T
+ where F: FnOnce(&mut Resolver) -> T,
{
let mut new_val = None;
if let Some(trait_ref) = opt_trait_ref {
let span = path.span;
let segments = &path.segments[..path.segments.len()-path_depth];
- let mk_res = |(def, lp)| PathResolution {
- base_def: def,
- last_private: lp,
- depth: path_depth
- };
+ let mk_res = |(def, lp)| PathResolution::new(def, lp, path_depth);
if path.global {
let def = self.resolve_crate_relative_path(span, segments, namespace);
check_ribs,
span);
- if segments.len() > 1 {
- let def = self.resolve_module_relative_path(span, segments, namespace);
- match (def, unqualified_def) {
- (Some((ref d, _)), Some((ref ud, _))) if *d == *ud => {
- self.session
- .add_lint(lint::builtin::UNUSED_QUALIFICATIONS,
- id, span,
- "unnecessary qualification".to_string());
- }
- _ => ()
- }
+ if segments.len() <= 1 {
+ return unqualified_def.map(mk_res);
+ }
- def.map(mk_res)
- } else {
- unqualified_def.map(mk_res)
+ let def = self.resolve_module_relative_path(span, segments, namespace);
+ match (def, unqualified_def) {
+ (Some((ref d, _)), Some((ref ud, _))) if *d == *ud => {
+ self.session
+ .add_lint(lint::builtin::UNUSED_QUALIFICATIONS,
+ id, span,
+ "unnecessary qualification".to_string());
+ }
+ _ => {}
}
+
+ def.map(mk_res)
}
- // resolve a single identifier (used as a varref)
+ // Resolve a single identifier.
fn resolve_identifier(&mut self,
identifier: Ident,
namespace: Namespace,
match child_name_bindings.def_for_namespace(namespace) {
Some(def) => {
// Found it. Stop the search here.
- let p = child_name_bindings.defined_in_public_namespace(
- namespace);
+ let p = child_name_bindings.defined_in_public_namespace(namespace);
let lp = if p {LastMod(AllPublic)} else {
LastMod(DependsOn(def.def_id()))
};
let containing_module;
let last_private;
- let module = self.current_module.clone();
- match self.resolve_module_path(module,
+ let current_module = self.current_module.clone();
+ match self.resolve_module_path(current_module,
&module_path[..],
UseLexicalScope,
span,
match search_result {
Some(DlDef(def)) => {
- debug!("(resolving path in local ribs) resolved `{}` to \
- local: {:?}",
+ debug!("(resolving path in local ribs) resolved `{}` to local: {:?}",
token::get_ident(ident),
def);
Some(def)
panic!("unexpected indeterminate result");
}
Failed(err) => {
- match err {
- Some((span, msg)) =>
- self.resolve_error(span, &format!("failed to resolve. {}",
- msg)),
- None => ()
- }
-
debug!("(resolving item path by identifier in lexical scope) \
failed to resolve {}", token::get_name(name));
+
+ if let Some((span, msg)) = err {
+ self.resolve_error(span, &format!("failed to resolve. {}", msg))
+ }
+
return None;
}
}
}
} else {
match this.resolve_module_path(root,
- &name_path[..],
- UseLexicalScope,
- span,
- PathSearch) {
+ &name_path[..],
+ UseLexicalScope,
+ span,
+ PathSearch) {
Success((module, _)) => Some(module),
_ => None
}
false // Stop advancing
});
- if method_scope && &token::get_name(self.self_name)[..]
- == path_name {
+ if method_scope &&
+ &token::get_name(special_names::self_)[..] == path_name {
self.resolve_error(
expr.span,
"`self` is not available \
#![feature(unicode)]
#![feature(path_ext)]
#![feature(fs)]
-#![feature(convert)]
#![feature(path_relative_from)]
#![allow(trivial_casts)]
let typ =
ppaux::ty_to_string(
&self.analysis.ty_cx,
- *self.analysis.ty_cx.node_types.borrow().get(&id).unwrap());
+ *self.analysis.ty_cx.node_types().get(&id).unwrap());
// get the span only for the name of the variable (I hope the path is only ever a
// variable name, but who knows?)
self.fmt.formal_str(p.span,
let typ =
ppaux::ty_to_string(
&self.analysis.ty_cx,
- *self.analysis.ty_cx.node_types.borrow().get(&field.node.id).unwrap());
+ *self.analysis.ty_cx.node_types().get(&field.node.id).unwrap());
match self.span.sub_span_before_token(field.span, token::Colon) {
Some(sub_span) => self.fmt.field_str(field.span,
Some(sub_span),
for &(id, ref p, ref immut, _) in &self.collected_paths {
let value = if *immut { value.to_string() } else { "<mutable>".to_string() };
- let types = self.analysis.ty_cx.node_types.borrow();
+ let types = self.analysis.ty_cx.node_types();
let typ = ppaux::ty_to_string(&self.analysis.ty_cx, *types.get(&id).unwrap());
// Get the span only for the name of the variable (I hope the path
// is only ever a variable name, but who knows?).
use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
use middle::weak_lang_items;
use middle::subst::{Subst, Substs};
-use middle::ty::{self, Ty, ClosureTyper};
+use middle::ty::{self, Ty, ClosureTyper, type_is_simd, simd_size};
use session::config::{self, NoDebugInfo};
use session::Session;
use trans::_match;
use trans::cleanup::CleanupMethods;
use trans::cleanup;
use trans::closure;
-use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_integral};
+use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_integral};
use trans::common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef};
use trans::common::{CrateContext, ExternMap, FunctionContext};
use trans::common::{Result, NodeIdAndSpan};
let zero = C_integral(Type::uint_from_ty(cx.ccx(), t), 0, false);
(ICmp(cx, llvm::IntEQ, rhs, zero, debug_loc), false)
}
+ ty::ty_struct(_, _) if type_is_simd(cx.tcx(), rhs_t) => {
+ let mut res = C_bool(cx.ccx(), false);
+ for i in 0 .. simd_size(cx.tcx(), rhs_t) {
+ res = Or(cx, res,
+ IsNull(cx,
+ ExtractElement(cx, rhs, C_int(cx.ccx(), i as i64))), debug_loc);
+ }
+ (res, false)
+ }
_ => {
cx.sess().bug(&format!("fail-if-zero on unexpected type: {}",
ty_to_string(cx.tcx(), rhs_t)));
}
}
+fn is_const_integral(v: ValueRef) -> bool {
+ unsafe {
+ !llvm::LLVMIsAConstantInt(v).is_null()
+ }
+}
+
+pub fn const_to_opt_int(v: ValueRef) -> Option<i64> {
+ unsafe {
+ if is_const_integral(v) {
+ Some(llvm::LLVMConstIntGetSExtValue(v))
+ } else {
+ None
+ }
+ }
+}
+
+pub fn const_to_opt_uint(v: ValueRef) -> Option<u64> {
+ unsafe {
+ if is_const_integral(v) {
+ Some(llvm::LLVMConstIntGetZExtValue(v))
+ } else {
+ None
+ }
+ }
+}
+
pub fn is_undef(val: ValueRef) -> bool {
unsafe {
llvm::LLVMIsUndef(val) != False
use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr};
use llvm::{InternalLinkage, ValueRef, Bool, True};
use middle::{check_const, const_eval, def};
+use middle::const_eval::{const_int_checked_neg, const_uint_checked_neg};
+use middle::const_eval::{const_int_checked_add, const_uint_checked_add};
+use middle::const_eval::{const_int_checked_sub, const_uint_checked_sub};
+use middle::const_eval::{const_int_checked_mul, const_uint_checked_mul};
+use middle::const_eval::{const_int_checked_div, const_uint_checked_div};
+use middle::const_eval::{const_int_checked_rem, const_uint_checked_rem};
+use middle::const_eval::{const_int_checked_shl, const_uint_checked_shl};
+use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr};
use trans::{adt, closure, debuginfo, expr, inline, machine};
use trans::base::{self, push_ctxt};
use trans::common::*;
let csize = machine::llsize_of_alloc(cx, val_ty(llconst));
let tsize = machine::llsize_of_alloc(cx, llty);
if csize != tsize {
+ cx.sess().abort_if_errors();
unsafe {
// FIXME these values could use some context
llvm::LLVMDumpValue(llconst);
(llconst, ety_adjusted)
}
+fn check_unary_expr_validity(cx: &CrateContext, e: &ast::Expr, t: Ty,
+ te: ValueRef) {
+ // The only kind of unary expression that we check for validity
+ // here is `-expr`, to check if it "overflows" (e.g. `-i32::MIN`).
+ if let ast::ExprUnary(ast::UnNeg, ref inner_e) = e.node {
+
+ // An unfortunate special case: we parse e.g. -128 as a
+ // negation of the literal 128, which means if we're expecting
+ // a i8 (or if it was already suffixed, e.g. `-128_i8`), then
+ // 128 will have already overflowed to -128, and so then the
+ // constant evaluator thinks we're trying to negate -128.
+ //
+ // Catch this up front by looking for ExprLit directly,
+ // and just accepting it.
+ if let ast::ExprLit(_) = inner_e.node { return; }
+
+ let result = match t.sty {
+ ty::ty_int(int_type) => {
+ let input = match const_to_opt_int(te) {
+ Some(v) => v,
+ None => return,
+ };
+ const_int_checked_neg(
+ input, e, Some(const_eval::IntTy::from(cx.tcx(), int_type)))
+ }
+ ty::ty_uint(uint_type) => {
+ let input = match const_to_opt_uint(te) {
+ Some(v) => v,
+ None => return,
+ };
+ const_uint_checked_neg(
+ input, e, Some(const_eval::UintTy::from(cx.tcx(), uint_type)))
+ }
+ _ => return,
+ };
+
+ // We do not actually care about a successful result.
+ if let Err(err) = result {
+ cx.tcx().sess.span_err(e.span, &err.description());
+ }
+ }
+}
+
+fn check_binary_expr_validity(cx: &CrateContext, e: &ast::Expr, t: Ty,
+ te1: ValueRef, te2: ValueRef) {
+ let b = if let ast::ExprBinary(b, _, _) = e.node { b } else { return };
+
+ let result = match t.sty {
+ ty::ty_int(int_type) => {
+ let (lhs, rhs) = match (const_to_opt_int(te1),
+ const_to_opt_int(te2)) {
+ (Some(v1), Some(v2)) => (v1, v2),
+ _ => return,
+ };
+
+ let opt_ety = Some(const_eval::IntTy::from(cx.tcx(), int_type));
+ match b.node {
+ ast::BiAdd => const_int_checked_add(lhs, rhs, e, opt_ety),
+ ast::BiSub => const_int_checked_sub(lhs, rhs, e, opt_ety),
+ ast::BiMul => const_int_checked_mul(lhs, rhs, e, opt_ety),
+ ast::BiDiv => const_int_checked_div(lhs, rhs, e, opt_ety),
+ ast::BiRem => const_int_checked_rem(lhs, rhs, e, opt_ety),
+ ast::BiShl => const_int_checked_shl(lhs, rhs, e, opt_ety),
+ ast::BiShr => const_int_checked_shr(lhs, rhs, e, opt_ety),
+ _ => return,
+ }
+ }
+ ty::ty_uint(uint_type) => {
+ let (lhs, rhs) = match (const_to_opt_uint(te1),
+ const_to_opt_uint(te2)) {
+ (Some(v1), Some(v2)) => (v1, v2),
+ _ => return,
+ };
+
+ let opt_ety = Some(const_eval::UintTy::from(cx.tcx(), uint_type));
+ match b.node {
+ ast::BiAdd => const_uint_checked_add(lhs, rhs, e, opt_ety),
+ ast::BiSub => const_uint_checked_sub(lhs, rhs, e, opt_ety),
+ ast::BiMul => const_uint_checked_mul(lhs, rhs, e, opt_ety),
+ ast::BiDiv => const_uint_checked_div(lhs, rhs, e, opt_ety),
+ ast::BiRem => const_uint_checked_rem(lhs, rhs, e, opt_ety),
+ ast::BiShl => const_uint_checked_shl(lhs, rhs, e, opt_ety),
+ ast::BiShr => const_uint_checked_shr(lhs, rhs, e, opt_ety),
+ _ => return,
+ }
+ }
+ _ => return,
+ };
+ // We do not actually care about a successful result.
+ if let Err(err) = result {
+ cx.tcx().sess.span_err(e.span, &err.description());
+ }
+}
+
fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
e: &ast::Expr,
ety: Ty<'tcx>,
let signed = ty::type_is_signed(intype);
let (te2, _) = const_expr(cx, &**e2, param_substs);
- let te2 = base::cast_shift_const_rhs(b.node, te1, te2);
+
+ check_binary_expr_validity(cx, e, ty, te1, te2);
match b.node {
ast::BiAdd => {
ast::BiBitXor => llvm::LLVMConstXor(te1, te2),
ast::BiBitAnd => llvm::LLVMConstAnd(te1, te2),
ast::BiBitOr => llvm::LLVMConstOr(te1, te2),
- ast::BiShl => llvm::LLVMConstShl(te1, te2),
+ ast::BiShl => {
+ let te2 = base::cast_shift_const_rhs(b.node, te1, te2);
+ llvm::LLVMConstShl(te1, te2)
+ }
ast::BiShr => {
+ let te2 = base::cast_shift_const_rhs(b.node, te1, te2);
if signed { llvm::LLVMConstAShr(te1, te2) }
else { llvm::LLVMConstLShr(te1, te2) }
}
}
}
},
- ast::ExprUnary(u, ref e) => {
- let (te, ty) = const_expr(cx, &**e, param_substs);
+ ast::ExprUnary(u, ref inner_e) => {
+ let (te, ty) = const_expr(cx, &**inner_e, param_substs);
+
+ check_unary_expr_validity(cx, e, ty, te);
+
let is_float = ty::type_is_fp(ty);
match u {
ast::UnUniq | ast::UnDeref => {
ast::ExprRepeat(ref elem, ref count) => {
let unit_ty = ty::sequence_element_type(cx.tcx(), ety);
let llunitty = type_of::type_of(cx, unit_ty);
- let n = match const_eval::eval_const_expr_partial(cx.tcx(), &**count, None) {
- Ok(const_eval::const_int(i)) => i as usize,
- Ok(const_eval::const_uint(i)) => i as usize,
- _ => cx.sess().span_bug(count.span, "count must be integral const expression.")
- };
+ let n = ty::eval_repeat_count(cx.tcx(), count);
let unit_val = const_expr(cx, &**elem, param_substs).0;
let vs: Vec<_> = repeat(unit_val).take(n).collect();
if val_ty(unit_val) != llunitty {
let fcx = cx.fcx;
debug!("trans_stmt({})", s.repr(cx.tcx()));
+ if cx.unreachable.get() {
+ return cx;
+ }
+
if cx.sess().asm_comments() {
add_span_comment(cx, s.span, &s.repr(cx.tcx()));
}
pub fn trans_stmt_semi<'blk, 'tcx>(cx: Block<'blk, 'tcx>, e: &ast::Expr)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_stmt_semi");
+
+ if cx.unreachable.get() {
+ return cx;
+ }
+
let ty = expr_ty(cx, e);
if cx.fcx.type_needs_drop(ty) {
expr::trans_to_lvalue(cx, e, "stmt").bcx
mut dest: expr::Dest)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_block");
+
+ if bcx.unreachable.get() {
+ return bcx;
+ }
+
let fcx = bcx.fcx;
let mut bcx = bcx;
bcx.to_str(), if_id, bcx.expr_to_string(cond), thn.id,
dest.to_string(bcx.ccx()));
let _icx = push_ctxt("trans_if");
+
+ if bcx.unreachable.get() {
+ return bcx;
+ }
+
let mut bcx = bcx;
let cond_val = unpack_result!(bcx, expr::trans(bcx, cond).to_llbool());
body: &ast::Block)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_while");
+
+ if bcx.unreachable.get() {
+ return bcx;
+ }
+
let fcx = bcx.fcx;
// bcx
body: &ast::Block)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_loop");
+
+ if bcx.unreachable.get() {
+ return bcx;
+ }
+
let fcx = bcx.fcx;
// bcx
exit: usize)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_break_cont");
- let fcx = bcx.fcx;
if bcx.unreachable.get() {
return bcx;
}
+ let fcx = bcx.fcx;
+
// Locate loop that we will break to
let loop_id = match opt_label {
None => fcx.top_loop_scope(),
retval_expr: Option<&ast::Expr>)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_ret");
+
+ if bcx.unreachable.get() {
+ return bcx;
+ }
+
let fcx = bcx.fcx;
let mut bcx = bcx;
let dest = match (fcx.llretslotptr.get(), retval_expr) {
let ccx = bcx.ccx();
let _icx = push_ctxt("trans_fail_value");
+ if bcx.unreachable.get() {
+ return bcx;
+ }
+
let v_str = C_str_slice(ccx, fail_str);
let loc = bcx.sess().codemap().lookup_char_pos(call_info.span.lo);
let filename = token::intern_and_get_ident(&loc.file.name);
let ccx = bcx.ccx();
let _icx = push_ctxt("trans_fail_bounds_check");
+ if bcx.unreachable.get() {
+ return bcx;
+ }
+
// Extract the file/line from the span
let loc = bcx.sess().codemap().lookup_char_pos(call_info.span.lo);
let filename = token::intern_and_get_ident(&loc.file.name);
fn assert_type_for_node_id(cx: &CrateContext,
node_id: ast::NodeId,
error_reporting_span: Span) {
- if !cx.tcx().node_types.borrow().contains_key(&node_id) {
+ if !cx.tcx().node_types().contains_key(&node_id) {
cx.sess().span_bug(error_reporting_span,
"debuginfo: Could not find type for node id!");
}
span: Span,
_trait_ref: Rc<ty::TraitRef<'tcx>>,
_item_name: ast::Name)
- -> Ty<'tcx>
- {
- span_err!(self.tcx().sess, span, E0213,
- "associated types are not accepted in this context");
-
- self.tcx().types.err
- }
+ -> Ty<'tcx>;
}
pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime)
}
};
- let substs = ast_path_substs_for_ty(this, rscope,
- span, param_mode,
- &generics, item_segment);
+ let substs = ast_path_substs_for_ty(this,
+ rscope,
+ span,
+ param_mode,
+ &generics,
+ item_segment);
// FIXME(#12938): This is a hack until we have full support for DST.
if Some(did) == this.tcx().lang_items.owned_box() {
type_str, trait_str, name);
}
+// Create a type from a a path to an associated type.
+// For a path A::B::C::D, ty and ty_path_def are the type and def for A::B::C
+// and item_segment is the path segment for D. We return a type and a def for
+// the whole path.
+// Will fail except for T::A and Self::A; i.e., if ty/ty_path_def are not a type
+// parameter or Self.
fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
span: Span,
ty: Ty<'tcx>,
-> (Ty<'tcx>, def::Def)
{
let tcx = this.tcx();
- check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS);
let assoc_name = item_segment.identifier.name;
- let is_param = match (&ty.sty, ty_path_def) {
- (&ty::ty_param(_), def::DefTyParam(..)) |
- (&ty::ty_param(_), def::DefSelfTy(_)) => true,
- _ => false
- };
+ debug!("associated_path_def_to_ty: {}::{}", ty.repr(tcx), token::get_name(assoc_name));
- let ty_param_node_id = if is_param {
- ty_path_def.local_node_id()
- } else {
- report_ambiguous_associated_type(
- tcx, span, &ty.user_string(tcx), "Trait", &token::get_name(assoc_name));
- return (tcx.types.err, ty_path_def);
- };
+ check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS);
+
+ // Check that the path prefix given by ty/ty_path_def is a type parameter/Self.
+ match (&ty.sty, ty_path_def) {
+ (&ty::ty_param(_), def::DefTyParam(..)) |
+ (&ty::ty_param(_), def::DefSelfTy(_)) => {}
+ _ => {
+ report_ambiguous_associated_type(tcx,
+ span,
+ &ty.user_string(tcx),
+ "Trait",
+ &token::get_name(assoc_name));
+ return (tcx.types.err, ty_path_def);
+ }
+ }
+ let ty_param_node_id = ty_path_def.local_node_id();
let ty_param_name = tcx.ty_param_defs.borrow().get(&ty_param_node_id).unwrap().name;
let bounds = match this.get_type_parameter_bounds(span, ty_param_node_id) {
Ok(v) => v,
- Err(ErrorReported) => { return (tcx.types.err, ty_path_def); }
+ Err(ErrorReported) => {
+ return (tcx.types.err, ty_path_def);
+ }
};
- // ensure the super predicates and stop if we encountered an error
+ // Ensure the super predicates and stop if we encountered an error.
if bounds.iter().any(|b| this.ensure_super_predicates(span, b.def_id()).is_err()) {
return (this.tcx().types.err, ty_path_def);
}
+ // Check that there is exactly one way to find an associated type with the
+ // correct name.
let mut suitable_bounds: Vec<_> =
traits::transitive_bounds(tcx, &bounds)
.filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name))
// by type collection, which may be in progress at this point.
match this.tcx().map.expect_item(trait_did.node).node {
ast::ItemTrait(_, _, _, ref trait_items) => {
- let item = trait_items.iter().find(|i| i.ident.name == assoc_name)
+ let item = trait_items.iter()
+ .find(|i| i.ident.name == assoc_name)
.expect("missing associated type");
ast_util::local_def(item.id)
}
let item = trait_items.iter().find(|i| i.name() == assoc_name);
item.expect("missing associated type").def_id()
};
+
(ty, def::DefAssociatedTy(trait_did, item_did))
}
ty
} else {
let path_str = ty::item_path_str(tcx, trait_def_id);
- report_ambiguous_associated_type(
- tcx, span, "Type", &path_str, &token::get_ident(item_segment.identifier));
+ report_ambiguous_associated_type(tcx,
+ span,
+ "Type",
+ &path_str,
+ &token::get_ident(item_segment.identifier));
return tcx.types.err;
};
}
}
+// Note that both base_segments and assoc_segments may be empty, although not at
+// the same time.
pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
param_mode: PathParamMode,
- def: &mut def::Def,
+ def: &def::Def,
opt_self_ty: Option<Ty<'tcx>>,
- segments: &[ast::PathSegment],
+ base_segments: &[ast::PathSegment],
assoc_segments: &[ast::PathSegment])
-> Ty<'tcx> {
let tcx = this.tcx();
span,
param_mode,
trait_def_id,
- segments.last().unwrap(),
+ base_segments.last().unwrap(),
&mut projection_bounds);
- check_path_args(tcx, segments.init(), NO_TPS | NO_REGIONS);
- trait_ref_to_object_type(this, rscope, span, trait_ref,
- projection_bounds, &[])
+ check_path_args(tcx, base_segments.init(), NO_TPS | NO_REGIONS);
+ trait_ref_to_object_type(this,
+ rscope,
+ span,
+ trait_ref,
+ projection_bounds,
+ &[])
}
def::DefTy(did, _) | def::DefStruct(did) => {
- check_path_args(tcx, segments.init(), NO_TPS | NO_REGIONS);
+ check_path_args(tcx, base_segments.init(), NO_TPS | NO_REGIONS);
ast_path_to_ty(this, rscope, span,
param_mode, did,
- segments.last().unwrap())
+ base_segments.last().unwrap())
}
def::DefTyParam(space, index, _, name) => {
- check_path_args(tcx, segments, NO_TPS | NO_REGIONS);
+ check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS);
ty::mk_param(tcx, space, index, name)
}
def::DefSelfTy(_) => {
- // n.b.: resolve guarantees that the this type only appears in a
+ // N.b.: resolve guarantees that the this type only appears in a
// trait, which we rely upon in various places when creating
- // substs
- check_path_args(tcx, segments, NO_TPS | NO_REGIONS);
+ // substs.
+ check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS);
ty::mk_self_type(tcx)
}
def::DefAssociatedTy(trait_did, _) => {
- check_path_args(tcx, &segments[..segments.len()-2], NO_TPS | NO_REGIONS);
- qpath_to_ty(this, rscope, span, param_mode,
- opt_self_ty, trait_did,
- &segments[segments.len()-2],
- segments.last().unwrap())
+ check_path_args(tcx, &base_segments[..base_segments.len()-2], NO_TPS | NO_REGIONS);
+ qpath_to_ty(this,
+ rscope,
+ span,
+ param_mode,
+ opt_self_ty,
+ trait_did,
+ &base_segments[base_segments.len()-2],
+ base_segments.last().unwrap())
}
def::DefMod(id) => {
// Used as sentinel by callers to indicate the `<T>::A::B::C` form.
// FIXME(#22519) This part of the resolution logic should be
// avoided entirely for that form, once we stop needed a Def
// for `associated_path_def_to_ty`.
- if segments.is_empty() {
- opt_self_ty.expect("missing T in <T>::a::b::c")
- } else {
- span_err!(tcx.sess, span, E0247, "found module name used as a type: {}",
+
+ if !base_segments.is_empty() {
+ span_err!(tcx.sess,
+ span,
+ E0247,
+ "found module name used as a type: {}",
tcx.map.node_to_string(id.node));
return this.tcx().types.err;
}
+
+ opt_self_ty.expect("missing T in <T>::a::b::c")
}
def::DefPrimTy(prim_ty) => {
- prim_ty_to_ty(tcx, segments, prim_ty)
+ prim_ty_to_ty(tcx, base_segments, prim_ty)
}
_ => {
span_err!(tcx.sess, span, E0248,
// If any associated type segments remain, attempt to resolve them.
let mut ty = base_ty;
+ let mut def = *def;
for segment in assoc_segments {
if ty.sty == ty::ty_err {
break;
}
// This is pretty bad (it will fail except for T::A and Self::A).
- let (a_ty, a_def) = associated_path_def_to_ty(this, span,
- ty, *def, segment);
+ let (a_ty, a_def) = associated_path_def_to_ty(this,
+ span,
+ ty,
+ def,
+ segment);
ty = a_ty;
- *def = a_def;
+ def = a_def;
}
ty
}
tcx.sess.span_bug(ast_ty.span,
&format!("unbound path {}", ast_ty.repr(tcx)))
};
- let mut def = path_res.base_def;
+ let def = path_res.base_def;
let base_ty_end = path.segments.len() - path_res.depth;
let opt_self_ty = maybe_qself.as_ref().map(|qself| {
ast_ty_to_ty(this, rscope, &qself.ty)
});
- let ty = finish_resolving_def_to_ty(this, rscope, ast_ty.span,
- PathParamMode::Explicit, &mut def,
+ let ty = finish_resolving_def_to_ty(this,
+ rscope,
+ ast_ty.span,
+ PathParamMode::Explicit,
+ &def,
opt_self_ty,
&path.segments[..base_ty_end],
&path.segments[base_ty_end..]);
UnresolvedTypeAction::Error,
LvaluePreference::NoPreference,
|adj_ty, idx| {
- let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
- try_overloaded_call_step(fcx, call_expr, callee_expr,
- adj_ty, autoderefref)
+ try_overloaded_call_step(fcx, call_expr, callee_expr, adj_ty, idx)
});
match result {
call_expr: &'tcx ast::Expr,
callee_expr: &'tcx ast::Expr,
adjusted_ty: Ty<'tcx>,
- autoderefref: ty::AutoDerefRef<'tcx>)
+ autoderefs: usize)
-> Option<CallStep<'tcx>>
{
- debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefref={})",
+ debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefs={})",
call_expr.repr(fcx.tcx()),
adjusted_ty.repr(fcx.tcx()),
- autoderefref.repr(fcx.tcx()));
+ autoderefs);
+
+ let autoderefref = ty::AutoDerefRef { autoderefs: autoderefs, autoref: None };
// If the callee is a bare function or a closure, then we're all set.
match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty {
}
}
+ // Hack: we know that there are traits implementing Fn for &F
+ // where F:Fn and so forth. In the particular case of types
+ // like `x: &mut FnMut()`, if there is a call `x()`, we would
+ // normally translate to `FnMut::call_mut(&mut x, ())`, but
+ // that winds up requiring `mut x: &mut FnMut()`. A little
+ // over the top. The simplest fix by far is to just ignore
+ // this case and deref again, so we wind up with
+ // `FnMut::call_mut(&mut *x, ())`.
+ ty::ty_rptr(..) if autoderefs == 0 => {
+ return None;
+ }
+
_ => {}
}
use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction};
-use middle::infer::{self, cres, Coercion, TypeTrace};
-use middle::infer::combine::Combine;
-use middle::infer::sub::Sub;
+use middle::infer::{self, Coercion};
use middle::subst;
use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe};
use middle::ty::{self, mt, Ty};
+use middle::ty_relate::RelateResult;
use util::common::indent;
use util::ppaux;
use util::ppaux::Repr;
struct Coerce<'a, 'tcx: 'a> {
fcx: &'a FnCtxt<'a, 'tcx>,
- trace: TypeTrace<'tcx>
+ origin: infer::TypeOrigin,
}
-type CoerceResult<'tcx> = cres<'tcx, Option<ty::AutoAdjustment<'tcx>>>;
+type CoerceResult<'tcx> = RelateResult<'tcx, Option<ty::AutoAdjustment<'tcx>>>;
impl<'f, 'tcx> Coerce<'f, 'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> {
}
fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
- let sub = Sub(self.fcx.infcx().combine_fields(false, self.trace.clone()));
- try!(sub.tys(a, b));
+ try!(self.fcx.infcx().sub_types(false, self.origin.clone(), a, b));
Ok(None) // No coercion required.
}
- fn outlives(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ()> {
- let sub = Sub(self.fcx.infcx().combine_fields(false, self.trace.clone()));
- try!(sub.regions(b, a));
+ fn outlives(&self,
+ origin: infer::SubregionOrigin<'tcx>,
+ a: ty::Region,
+ b: ty::Region)
+ -> RelateResult<'tcx, ()> {
+ infer::mk_subr(self.fcx.infcx(), origin, b, a);
Ok(())
}
_ => return self.subtype(a, b)
}
- let coercion = Coercion(self.trace.clone());
+ let coercion = Coercion(self.origin.span());
let r_borrow = self.fcx.infcx().next_region_var(coercion);
let autoref = Some(AutoPtr(r_borrow, mutbl_b, None));
}
let ty = ty::mk_rptr(self.tcx(), r_borrow,
mt {ty: inner_ty, mutbl: mutbl_b});
- if let Err(err) = self.fcx.infcx().try(|_| self.subtype(ty, b)) {
+ if let Err(err) = self.subtype(ty, b) {
if first_error.is_none() {
first_error = Some(err);
}
return Err(ty::terr_mutability);
}
- let coercion = Coercion(self.trace.clone());
+ let coercion = Coercion(self.origin.span());
let r_borrow = self.fcx.infcx().next_region_var(coercion);
let ty = ty::mk_rptr(self.tcx(),
self.tcx().mk_region(r_borrow),
ty::mt{ty: ty, mutbl: mt_b.mutbl});
- try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
+ try!(self.subtype(ty, b));
debug!("Success, coerced with AutoDerefRef(1, \
AutoPtr(AutoUnsize({:?})))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef {
let ty = ty::mk_ptr(self.tcx(),
ty::mt{ty: ty, mutbl: mt_b.mutbl});
- try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
+ try!(self.subtype(ty, b));
debug!("Success, coerced with AutoDerefRef(1, \
AutoPtr(AutoUnsize({:?})))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef {
match self.unsize_ty(t_a, t_b) {
Some((ty, kind)) => {
let ty = ty::mk_uniq(self.tcx(), ty);
- try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
+ try!(self.subtype(ty, b));
debug!("Success, coerced with AutoDerefRef(1, \
AutoUnsizeUniq({:?}))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef {
let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1);
// relate `a1` to `b`
- let result = self.fcx.infcx().try(|_| {
+ let result = self.fcx.infcx().commit_if_ok(|_| {
// it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b
- try!(self.outlives(data_a.bounds.region_bound,
+ try!(self.outlives(infer::RelateObjectBound(self.origin.span()),
+ data_a.bounds.region_bound,
data_b.bounds.region_bound));
self.subtype(ty_a1, ty_b)
});
let mut result = None;
let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
for (i, (tp_a, tp_b)) in tps {
- if self.fcx.infcx().try(|_| self.subtype(*tp_a, *tp_b)).is_ok() {
+ if self.subtype(*tp_a, *tp_b).is_ok() {
continue;
}
match self.unsize_ty(*tp_a, *tp_b) {
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, tcx.mk_substs(new_substs));
- if self.fcx.infcx().try(|_| self.subtype(ty, ty_b)).is_err() {
+ if self.subtype(ty, ty_b).is_err() {
debug!("Unsized type parameter '{}', but still \
could not match types {} and {}",
ppaux::ty_to_string(tcx, *tp_a),
expr: &ast::Expr,
a: Ty<'tcx>,
b: Ty<'tcx>)
- -> cres<'tcx, ()> {
+ -> RelateResult<'tcx, ()> {
debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx()));
let adjustment = try!(indent(|| {
- fcx.infcx().commit_if_ok(|| {
- let origin = infer::ExprAssignable(expr.span);
+ fcx.infcx().commit_if_ok(|_| {
Coerce {
fcx: fcx,
- trace: infer::TypeTrace::types(origin, false, a, b)
+ origin: infer::ExprAssignable(expr.span),
}.coerce(expr, a, b)
})
}));
let trait_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(trait_m.fty.clone()));
let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
- let err = infcx.try(|snapshot| {
+ let err = infcx.commit_if_ok(|snapshot| {
let origin = infer::MethodCompatCheck(impl_m_span);
let (impl_sig, _) =
ty::lookup_item_type(tcx, self_type_did);
let infcx = infer::new_infer_ctxt(tcx);
- infcx.try(|snapshot| {
+ infcx.commit_if_ok(|snapshot| {
let (named_type_to_skolem, skol_map) =
infcx.construct_skolemized_subst(named_type_generics, snapshot);
let named_type_skolem = named_type.subst(tcx, &named_type_to_skolem);
///////////////////////////////////////////////////////////////////////////
// MISCELLANY
- fn make_sub_ty(&self, sub: Ty<'tcx>, sup: Ty<'tcx>) -> infer::ures<'tcx> {
+ fn make_sub_ty(&self, sub: Ty<'tcx>, sup: Ty<'tcx>) -> infer::UnitResult<'tcx> {
self.infcx().sub_types(false, infer::Misc(DUMMY_SP), sub, sup)
}
use check::_match::pat_ctxt;
use fmt_macros::{Parser, Piece, Position};
use middle::astconv_util::{check_path_args, NO_TPS, NO_REGIONS};
-use middle::{const_eval, def};
+use middle::def;
use middle::infer;
use middle::mem_categorization as mc;
use middle::mem_categorization::McResult;
use middle::region::{self, CodeExtent};
use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace};
use middle::traits;
-use middle::ty::{FnSig, GenericPredicates, VariantInfo, TypeScheme};
+use middle::ty::{FnSig, GenericPredicates, TypeScheme};
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
use middle::ty::{self, HasProjectionTypes, RegionEscape, ToPolyTraitRef, Ty};
use middle::ty::liberate_late_bound_regions;
&format!("unbound path {}", expr.repr(tcx)))
};
- let mut def = path_res.base_def;
+ let def = path_res.base_def;
if path_res.depth == 0 {
let (scheme, predicates) =
type_scheme_and_predicates_for_def(fcx, expr.span, def);
} else {
let ty_segments = path.segments.init();
let base_ty_end = path.segments.len() - path_res.depth;
- let ty = astconv::finish_resolving_def_to_ty(fcx, fcx, expr.span,
+ let ty = astconv::finish_resolving_def_to_ty(fcx,
+ fcx,
+ expr.span,
PathParamMode::Optional,
- &mut def,
+ &def,
opt_self_ty,
&ty_segments[..base_ty_end],
&ty_segments[base_ty_end..]);
fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
vs: &'tcx [P<ast::Variant>],
id: ast::NodeId,
- hint: attr::ReprAttr)
- -> Vec<Rc<ty::VariantInfo<'tcx>>> {
+ hint: attr::ReprAttr) {
#![allow(trivial_numeric_casts)]
let rty = ty::node_id_to_type(ccx.tcx, id);
- let mut variants: Vec<Rc<ty::VariantInfo>> = Vec::new();
let mut disr_vals: Vec<ty::Disr> = Vec::new();
- let mut prev_disr_val: Option<ty::Disr> = None;
- for v in vs {
+ let inh = static_inherited_fields(ccx);
+ let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), id);
- // If the discriminant value is specified explicitly in the enum check whether the
- // initialization expression is valid, otherwise use the last value plus one.
- let mut current_disr_val = match prev_disr_val {
- Some(prev_disr_val) => {
- if let Some(v) = prev_disr_val.checked_add(1) {
- v
- } else {
- ty::INITIAL_DISCRIMINANT_VALUE
- }
- }
- None => ty::INITIAL_DISCRIMINANT_VALUE
- };
+ let (_, repr_type_ty) = ty::enum_repr_type(ccx.tcx, Some(&hint));
+ for v in vs {
+ if let Some(ref e) = v.node.disr_expr {
+ check_const_with_ty(&fcx, e.span, e, repr_type_ty);
+ }
+ }
- match v.node.disr_expr {
- Some(ref e) => {
- debug!("disr expr, checking {}", pprust::expr_to_string(&**e));
+ let def_id = local_def(id);
- let inh = static_inherited_fields(ccx);
- let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), e.id);
- let declty = match hint {
- attr::ReprAny | attr::ReprPacked |
- attr::ReprExtern => fcx.tcx().types.isize,
+ // ty::enum_variants guards against discriminant overflows, so
+ // we need not check for that.
+ let variants = ty::enum_variants(ccx.tcx, def_id);
- attr::ReprInt(_, attr::SignedInt(ity)) => {
- ty::mk_mach_int(fcx.tcx(), ity)
- }
- attr::ReprInt(_, attr::UnsignedInt(ity)) => {
- ty::mk_mach_uint(fcx.tcx(), ity)
- },
- };
- check_const_with_ty(&fcx, e.span, &**e, declty);
- // check_expr (from check_const pass) doesn't guarantee
- // that the expression is in a form that eval_const_expr can
- // handle, so we may still get an internal compiler error
-
- match const_eval::eval_const_expr_partial(ccx.tcx, &**e, Some(declty)) {
- Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
- Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
- Ok(_) => {
- span_err!(ccx.tcx.sess, e.span, E0079,
- "expected signed integer constant");
- }
- Err(ref err) => {
- span_err!(ccx.tcx.sess, err.span, E0080,
- "constant evaluation error: {}",
- err.description());
- }
- }
- },
- None => ()
- };
+ for (v, variant) in vs.iter().zip(variants.iter()) {
+ let current_disr_val = variant.disr_val;
// Check for duplicate discriminant values
match disr_vals.iter().position(|&x| x == current_disr_val) {
}
}
disr_vals.push(current_disr_val);
-
- let variant_info = Rc::new(VariantInfo::from_ast_variant(ccx.tcx, &**v,
- current_disr_val));
- prev_disr_val = Some(current_disr_val);
-
- variants.push(variant_info);
}
-
- return variants;
}
let hint = *ty::lookup_repr_hints(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id })
};
}
- let variants = do_check(ccx, vs, id, hint);
-
- // cache so that ty::enum_variants won't repeat this work
- ccx.tcx.enum_var_cache.borrow_mut().insert(local_def(id), Rc::new(variants));
+ do_check(ccx, vs, id, hint);
check_representable(ccx.tcx, sp, id, "enum");
debug!("projection_bounds: outlives={} (2)",
outlives.repr(tcx));
- let region_result = infcx.try(|_| {
+ let region_result = infcx.commit_if_ok(|_| {
let (outlives, _) =
infcx.replace_late_bound_regions_with_fresh_var(
span,
use middle::ty::ty_projection;
use middle::ty;
use CrateCtxt;
-use middle::infer::combine::Combine;
use middle::infer::InferCtxt;
use middle::infer::new_infer_ctxt;
use std::collections::HashSet;
match traits::orphan_check(self.tcx, def_id) {
Ok(()) => { }
Err(traits::OrphanCheckErr::NoLocalInputType) => {
- if !ty::has_attr(self.tcx, trait_def_id, "old_orphan_check") {
- span_err!(
- self.tcx.sess, item.span, E0117,
- "the impl does not reference any \
- types defined in this crate; \
- only traits defined in the current crate can be \
- implemented for arbitrary types");
- return;
- }
+ span_err!(
+ self.tcx.sess, item.span, E0117,
+ "the impl does not reference any \
+ types defined in this crate; \
+ only traits defined in the current crate can be \
+ implemented for arbitrary types");
+ return;
}
Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => {
- if !ty::has_attr(self.tcx, trait_def_id, "old_orphan_check") {
- span_err!(self.tcx.sess, item.span, E0210,
- "type parameter `{}` must be used as the type parameter for \
- some local type (e.g. `MyStruct<T>`); only traits defined in \
- the current crate can be implemented for a type parameter",
- param_ty.user_string(self.tcx));
- return;
- }
+ span_err!(self.tcx.sess, item.span, E0210,
+ "type parameter `{}` must be used as the type parameter for \
+ some local type (e.g. `MyStruct<T>`); only traits defined in \
+ the current crate can be implemented for a type parameter",
+ param_ty.user_string(self.tcx));
+ return;
}
}
E0075,
E0076,
E0077,
- E0079,
- E0080,
E0081,
E0082,
E0083,
fn write_ty_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) {
debug!("write_ty_to_tcx({}, {})", node_id, ppaux::ty_to_string(tcx, ty));
assert!(!ty::type_needs_infer(ty));
- tcx.node_types.borrow_mut().insert(node_id, ty);
+ tcx.node_type_insert(node_id, ty);
}
fn write_substs_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>,
#[cfg(unix)]
mod imp {
- use std::ffi::{AsOsStr, CString};
+ use std::ffi::{CString, OsStr};
use std::os::unix::prelude::*;
use std::path::Path;
use std::io;
impl Lock {
pub fn new(p: &Path) -> Lock {
- let buf = CString::new(p.as_os_str().as_bytes()).unwrap();
+ let os: &OsStr = p.as_ref();
+ let buf = CString::new(os.as_bytes()).unwrap();
let fd = unsafe {
libc::open(buf.as_ptr(), libc::O_RDWR | libc::O_CREAT,
libc::S_IRWXU)
#[cfg(windows)]
mod imp {
use libc;
- use std::ffi::AsOsStr;
use std::io;
use std::mem;
+ use std::ffi::OsStr;
use std::os::windows::prelude::*;
use std::path::Path;
use std::ptr;
impl Lock {
pub fn new(p: &Path) -> Lock {
- let mut p_16: Vec<_> = p.as_os_str().encode_wide().collect();
+ let os: &OsStr = p.as_ref();
+ let mut p_16: Vec<_> = os.encode_wide().collect();
p_16.push(0);
let handle = unsafe {
libc::CreateFileW(p_16.as_ptr(),
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(collections)]
-#![feature(core)]
#![feature(exit_status)]
#![feature(set_stdio)]
#![feature(libc)]
#![feature(file_path)]
#![feature(path_ext)]
#![feature(path_relative_from)]
-#![feature(convert)]
#![feature(slice_patterns)]
extern crate arena;
//! let encoded = json::encode(&object).unwrap();
//!
//! // Deserialize using `json::decode`
-//! let decoded: TestStruct = json::decode(encoded.as_slice()).unwrap();
+//! let decoded: TestStruct = json::decode(&encoded[..]).unwrap();
//! }
//! ```
//!
fn description(&self) -> &str { "encoder error" }
}
-impl std::error::FromError<fmt::Error> for EncoderError {
- fn from_error(err: fmt::Error) -> EncoderError { EncoderError::FmtError(err) }
+impl From<fmt::Error> for EncoderError {
+ fn from(err: fmt::Error) -> EncoderError { EncoderError::FmtError(err) }
}
pub type EncodeResult = Result<(), EncoderError>;
#![feature(std_misc)]
#![feature(unicode)]
#![feature(str_char)]
-#![feature(convert)]
#![cfg_attr(test, feature(test, old_io))]
// test harness access
}
}
- #[unstable(feature = "collections",
- reason = "matches entry v3 specification, waiting for dust to settle")]
+ #[stable(feature = "rust1", since = "1.0.0")]
/// Ensures a value is in the entry by inserting the default if empty, and returns
/// a mutable reference to the value in the entry.
pub fn or_insert(self, default: V) -> &'a mut V {
}
}
- #[unstable(feature = "collections",
- reason = "matches entry v3 specification, waiting for dust to settle")]
+ #[stable(feature = "rust1", since = "1.0.0")]
/// Ensures a value is in the entry by inserting the result of the default function if empty,
/// and returns a mutable reference to the value in the entry.
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
};
let v = hs.into_iter().collect::<Vec<char>>();
- assert!(['a', 'b'] == v || ['b', 'a'] == v);
+ assert!(v == ['a', 'b'] || v == ['b', 'a']);
}
#[test]
use clone::Clone;
use cmp;
use hash::{Hash, Hasher};
-use iter::{Iterator, ExactSizeIterator, count};
+use iter::{Iterator, ExactSizeIterator};
use marker::{Copy, Send, Sync, Sized, self};
use mem::{min_align_of, size_of};
use mem;
use prelude::v1::*;
use env;
-use ffi::{AsOsStr, CString, OsString};
+use ffi::{CString, OsString};
use mem;
use path::{Path, PathBuf};
use ffi::{CStr, OsStr};
use str;
use libc;
- use os::unix::prelude::*;
use ptr;
pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
use iter::IntoIterator;
use error::Error;
-use ffi::{OsString, AsOsStr};
+use ffi::{OsStr, OsString};
use fmt;
use io;
use path::{Path, PathBuf};
/// }
/// ```
#[stable(feature = "env", since = "1.0.0")]
-pub fn var<K: ?Sized>(key: &K) -> Result<String, VarError> where K: AsOsStr {
+pub fn var<K: ?Sized>(key: &K) -> Result<String, VarError> where K: AsRef<OsStr> {
match var_os(key) {
Some(s) => s.into_string().map_err(VarError::NotUnicode),
None => Err(VarError::NotPresent)
/// }
/// ```
#[stable(feature = "env", since = "1.0.0")]
-pub fn var_os<K: ?Sized>(key: &K) -> Option<OsString> where K: AsOsStr {
+pub fn var_os<K: ?Sized>(key: &K) -> Option<OsString> where K: AsRef<OsStr> {
let _g = ENV_LOCK.lock();
- os_imp::getenv(key.as_os_str())
+ os_imp::getenv(key.as_ref())
}
/// Possible errors from the `env::var` method.
/// ```
#[stable(feature = "env", since = "1.0.0")]
pub fn set_var<K: ?Sized, V: ?Sized>(k: &K, v: &V)
- where K: AsOsStr, V: AsOsStr
+ where K: AsRef<OsStr>, V: AsRef<OsStr>
{
let _g = ENV_LOCK.lock();
- os_imp::setenv(k.as_os_str(), v.as_os_str())
+ os_imp::setenv(k.as_ref(), v.as_ref())
}
-/// Remove a variable from the environment entirely.
+/// Remove an environment variable from the environment of the currently running process.
+///
+/// # Examples
+///
+/// ```
+/// use std::env;
+///
+/// let key = "KEY";
+/// env::set_var(key, "VALUE");
+/// assert_eq!(env::var(key), Ok("VALUE".to_string()));
+///
+/// env::remove_var(key);
+/// assert!(env::var(key).is_err());
+/// ```
#[stable(feature = "env", since = "1.0.0")]
-pub fn remove_var<K: ?Sized>(k: &K) where K: AsOsStr {
+pub fn remove_var<K: ?Sized>(k: &K) where K: AsRef<OsStr> {
let _g = ENV_LOCK.lock();
- os_imp::unsetenv(k.as_os_str())
+ os_imp::unsetenv(k.as_ref())
}
/// An iterator over `Path` instances for parsing an environment variable
/// }
/// ```
#[stable(feature = "env", since = "1.0.0")]
-pub fn split_paths<T: AsOsStr + ?Sized>(unparsed: &T) -> SplitPaths {
- SplitPaths { inner: os_imp::split_paths(unparsed.as_os_str()) }
+pub fn split_paths<T: AsRef<OsStr> + ?Sized>(unparsed: &T) -> SplitPaths {
+ SplitPaths { inner: os_imp::split_paths(unparsed.as_ref()) }
}
#[stable(feature = "env", since = "1.0.0")]
/// # Examples
///
/// ```
-/// # #![feature(convert)]
/// use std::env;
/// use std::path::PathBuf;
///
/// ```
#[stable(feature = "env", since = "1.0.0")]
pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
- where I: IntoIterator<Item=T>, T: AsOsStr
+ where I: IntoIterator<Item=T>, T: AsRef<OsStr>
{
os_imp::join_paths(paths.into_iter()).map_err(|e| {
JoinPathsError { inner: e }
/// On Windows, returns the value of, in order, the 'TMP', 'TEMP',
/// 'USERPROFILE' environment variable if any are set and not the empty
/// string. Otherwise, tmpdir returns the path to the Windows directory.
+///
+/// ```
+/// use std::env;
+/// use std::fs::File;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// let mut dir = env::temp_dir();
+/// dir.push("foo.txt");
+///
+/// let f = try!(File::create(dir));
+/// # Ok(())
+/// # }
+/// ```
#[stable(feature = "env", since = "1.0.0")]
pub fn temp_dir() -> PathBuf {
os_imp::temp_dir()
#[stable(feature = "env", since = "1.0.0")]
pub const ARCH: &'static str = super::arch::ARCH;
+ /// The family of the operating system. In this case, `unix`.
#[stable(feature = "env", since = "1.0.0")]
pub const FAMILY: &'static str = super::os::FAMILY;
let mut rng = rand::thread_rng();
let n = format!("TEST{}", rng.gen_ascii_chars().take(10)
.collect::<String>());
- let n = OsString::from_string(n);
+ let n = OsString::from(n);
assert!(var_os(&n).is_none());
n
}
#![unstable(feature = "std_misc")]
-use convert::Into;
+use convert::{Into, From};
use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
-use error::{Error, FromError};
+use error::Error;
use fmt;
use io;
use iter::Iterator;
#[stable(feature = "rust1", since = "1.0.0")]
pub struct NulError(usize, Vec<u8>);
-/// A conversion trait used by the constructor of `CString` for types that can
-/// be converted to a vector of bytes.
-#[deprecated(since = "1.0.0", reason = "use std::convert::Into<Vec<u8>> instead")]
-#[unstable(feature = "std_misc")]
-pub trait IntoBytes {
- /// Consumes this container, returning a vector of bytes.
- fn into_bytes(self) -> Vec<u8>;
-}
-
impl CString {
/// Create a new C-compatible string from a container of bytes.
///
}
}
- /// Create a new C-compatible string from a byte slice.
- ///
- /// This method will copy the data of the slice provided into a new
- /// allocation, ensuring that there is a trailing 0 byte.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// # #![feature(libc)]
- /// extern crate libc;
- /// use std::ffi::CString;
- ///
- /// extern { fn puts(s: *const libc::c_char); }
- ///
- /// fn main() {
- /// let to_print = CString::new("Hello!").unwrap();
- /// unsafe {
- /// puts(to_print.as_ptr());
- /// }
- /// }
- /// ```
- ///
- /// # Panics
- ///
- /// This function will panic if the provided slice contains any
- /// interior nul bytes.
- #[unstable(feature = "std_misc")]
- #[deprecated(since = "1.0.0", reason = "use CString::new instead")]
- #[allow(deprecated)]
- pub fn from_slice(v: &[u8]) -> CString {
- CString::from_vec(v.to_vec())
- }
-
- /// Create a C-compatible string from a byte vector.
- ///
- /// This method will consume ownership of the provided vector, appending a 0
- /// byte to the end after verifying that there are no interior 0 bytes.
- ///
- /// # Panics
- ///
- /// This function will panic if the provided slice contains any
- /// interior nul bytes.
- #[unstable(feature = "std_misc")]
- #[deprecated(since = "1.0.0", reason = "use CString::new instead")]
- pub fn from_vec(v: Vec<u8>) -> CString {
- match v.iter().position(|x| *x == 0) {
- Some(i) => panic!("null byte found in slice at: {}", i),
- None => unsafe { CString::from_vec_unchecked(v) },
- }
- }
-
/// Create a C-compatible string from a byte vector without checking for
/// interior 0 bytes.
///
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl FromError<NulError> for io::Error {
- fn from_error(_: NulError) -> io::Error {
+impl From<NulError> for io::Error {
+ fn from(_: NulError) -> io::Error {
io::Error::new(io::ErrorKind::InvalidInput,
- "data provided contains a nul byte", None)
+ "data provided contains a nul byte")
}
}
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
-impl FromError<NulError> for old_io::IoError {
- fn from_error(_: NulError) -> old_io::IoError {
+impl From<NulError> for old_io::IoError {
+ fn from(_: NulError) -> old_io::IoError {
old_io::IoError {
kind: old_io::IoErrorKind::InvalidInput,
desc: "data provided contains a nul byte",
}
}
-/// Deprecated in favor of `CStr`
-#[unstable(feature = "std_misc")]
-#[deprecated(since = "1.0.0", reason = "use CStr::from_ptr(p).to_bytes() instead")]
-pub unsafe fn c_str_to_bytes<'a>(raw: &'a *const libc::c_char) -> &'a [u8] {
- let len = libc::strlen(*raw);
- slice::from_raw_parts(*(raw as *const _ as *const *const u8), len as usize)
-}
-
-/// Deprecated in favor of `CStr`
-#[unstable(feature = "std_misc")]
-#[deprecated(since = "1.0.0",
- reason = "use CStr::from_ptr(p).to_bytes_with_nul() instead")]
-pub unsafe fn c_str_to_bytes_with_nul<'a>(raw: &'a *const libc::c_char)
- -> &'a [u8] {
- let len = libc::strlen(*raw) + 1;
- slice::from_raw_parts(*(raw as *const _ as *const *const u8), len as usize)
-}
-
-#[allow(deprecated)]
-impl<'a> IntoBytes for &'a str {
- fn into_bytes(self) -> Vec<u8> { self.as_bytes().to_vec() }
-}
-#[allow(deprecated)]
-impl<'a> IntoBytes for &'a [u8] {
- fn into_bytes(self) -> Vec<u8> { self.to_vec() }
-}
-#[allow(deprecated)]
-impl IntoBytes for String {
- fn into_bytes(self) -> Vec<u8> { self.into_bytes() }
-}
-#[allow(deprecated)]
-impl IntoBytes for Vec<u8> {
- fn into_bytes(self) -> Vec<u8> { self }
-}
-
#[cfg(test)]
mod tests {
use prelude::v1::*;
#![stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::c_str::{CString, CStr};
-pub use self::c_str::{NulError, IntoBytes};
-#[allow(deprecated)]
-pub use self::c_str::c_str_to_bytes;
-#[allow(deprecated)]
-pub use self::c_str::c_str_to_bytes_with_nul;
+pub use self::c_str::{CString, CStr, NulError};
#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::os_str::OsString;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::os_str::OsStr;
+pub use self::os_str::{OsString, OsStr};
mod c_str;
mod os_str;
//! for conversion to/from various other string types. Eventually these types
//! will offer a full-fledged string API.
-#![unstable(feature = "os",
+#![unstable(feature = "os_str",
reason = "recently added as part of path/io reform")]
use core::prelude::*;
use borrow::{Borrow, Cow, ToOwned};
+use ffi::CString;
use fmt::{self, Debug};
use mem;
use string::String;
use cmp;
use hash::{Hash, Hasher};
use old_path::{Path, GenericPath};
+use vec::Vec;
use sys::os_str::{Buf, Slice};
use sys_common::{AsInner, IntoInner, FromInner};
}
impl OsString {
- /// Constructs an `OsString` at no cost by consuming a `String`.
+ /// Constructs a new empty `OsString`.
#[stable(feature = "rust1", since = "1.0.0")]
- #[deprecated(since = "1.0.0", reason = "use `from` instead")]
- pub fn from_string(s: String) -> OsString {
- OsString::from(s)
+ pub fn new() -> OsString {
+ OsString { inner: Buf::from_string(String::new()) }
}
- /// Constructs an `OsString` by copying from a `&str` slice.
+ /// Construct an `OsString` from a byte sequence.
///
- /// Equivalent to: `OsString::from_string(String::from_str(s))`.
- #[stable(feature = "rust1", since = "1.0.0")]
- #[deprecated(since = "1.0.0", reason = "use `from` instead")]
- pub fn from_str(s: &str) -> OsString {
- OsString::from(s)
+ /// # Platform behavior
+ ///
+ /// On Unix systems, any byte sequence can be successfully
+ /// converted into an `OsString`.
+ ///
+ /// On Windows system, only UTF-8 byte sequences will successfully
+ /// convert; non UTF-8 data will produce `None`.
+ #[unstable(feature = "convert", reason = "recently added")]
+ pub fn from_bytes<B>(bytes: B) -> Option<OsString> where B: Into<Vec<u8>> {
+ #[cfg(unix)]
+ fn from_bytes_inner(vec: Vec<u8>) -> Option<OsString> {
+ use os::unix::ffi::OsStringExt;
+ Some(OsString::from_vec(vec))
+ }
+
+ #[cfg(windows)]
+ fn from_bytes_inner(vec: Vec<u8>) -> Option<OsString> {
+ String::from_utf8(vec).ok().map(OsString::from)
+ }
+
+ from_bytes_inner(bytes.into())
}
- /// Constructs a new empty `OsString`.
+ /// Convert to an `OsStr` slice.
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn new() -> OsString {
- OsString { inner: Buf::from_string(String::new()) }
+ pub fn as_os_str(&self) -> &OsStr {
+ self
}
/// Convert the `OsString` into a `String` if it contains valid Unicode data.
self.inner.into_string().map_err(|buf| OsString { inner: buf} )
}
- /// Extend the string with the given `&OsStr` slice.
- #[deprecated(since = "1.0.0", reason = "renamed to `push`")]
- #[unstable(feature = "os")]
- pub fn push_os_str(&mut self, s: &OsStr) {
- self.inner.push_slice(&s.inner)
- }
-
/// Extend the string with the given `&OsStr` slice.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn push<T: AsRef<OsStr>>(&mut self, s: T) {
}
impl OsStr {
+ /// Coerce into an `OsStr` slice.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &OsStr {
+ s.as_ref()
+ }
+
/// Coerce directly from a `&str` slice to a `&OsStr` slice.
#[stable(feature = "rust1", since = "1.0.0")]
+ #[deprecated(since = "1.0.0",
+ reason = "use `OsStr::new` instead")]
pub fn from_str(s: &str) -> &OsStr {
unsafe { mem::transmute(Slice::from_str(s)) }
}
OsString { inner: self.inner.to_owned() }
}
+ /// Yield this `OsStr` as a byte slice.
+ ///
+ /// # Platform behavior
+ ///
+ /// On Unix systems, this is a no-op.
+ ///
+ /// On Windows systems, this returns `None` unless the `OsStr` is
+ /// valid unicode, in which case it produces UTF-8-encoded
+ /// data. This may entail checking validity.
+ #[unstable(feature = "convert", reason = "recently added")]
+ pub fn to_bytes(&self) -> Option<&[u8]> {
+ if cfg!(windows) {
+ self.to_str().map(|s| s.as_bytes())
+ } else {
+ Some(self.bytes())
+ }
+ }
+
+ /// Create a `CString` containing this `OsStr` data.
+ ///
+ /// Fails if the `OsStr` contains interior nulls.
+ ///
+ /// This is a convenience for creating a `CString` from
+ /// `self.to_bytes()`, and inherits the platform behavior of the
+ /// `to_bytes` method.
+ #[unstable(feature = "convert", reason = "recently added")]
+ pub fn to_cstring(&self) -> Option<CString> {
+ self.to_bytes().and_then(|b| CString::new(b).ok())
+ }
+
/// Get the underlying byte representation.
///
/// Note: it is *crucial* that this API is private, to avoid
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialEq<str> for OsStr {
fn eq(&self, other: &str) -> bool {
- *self == *OsStr::from_str(other)
+ *self == *OsStr::new(other)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialEq<OsStr> for str {
fn eq(&self, other: &OsStr) -> bool {
- *other == *OsStr::from_str(self)
+ *other == *OsStr::new(self)
}
}
impl PartialOrd<str> for OsStr {
#[inline]
fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
- self.partial_cmp(OsStr::from_str(other))
+ self.partial_cmp(OsStr::new(other))
}
}
#[deprecated(since = "1.0.0", reason = "trait is deprecated")]
impl AsOsStr for str {
fn as_os_str(&self) -> &OsStr {
- OsStr::from_str(self)
+ unsafe { mem::transmute(Slice::from_str(self)) }
}
}
#[deprecated(since = "1.0.0", reason = "trait is deprecated")]
impl AsOsStr for String {
fn as_os_str(&self) -> &OsStr {
- OsStr::from_str(&self[..])
+ unsafe { mem::transmute(Slice::from_str(self)) }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<OsStr> for str {
fn as_ref(&self) -> &OsStr {
- OsStr::from_str(self)
+ unsafe { mem::transmute(Slice::from_str(self)) }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<OsStr> for String {
fn as_ref(&self) -> &OsStr {
- OsStr::from_str(&self[..])
+ unsafe { mem::transmute(Slice::from_str(self)) }
}
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Filesystem manipulation operations
+//!
+//! This module contains basic methods to manipulate the contents of the local
+//! filesystem. All methods in this module represent cross-platform filesystem
+//! operations. Extra platform-specific functionality can be found in the
+//! extension traits of `std::os::$platform`.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use core::prelude::*;
+
+use io::{self, Error, ErrorKind, SeekFrom, Seek, Read, Write};
+use path::{Path, PathBuf};
+use sys::fs2 as fs_imp;
+use sys_common::{AsInnerMut, FromInner, AsInner};
+use vec::Vec;
+
+/// A reference to an open file on the filesystem.
+///
+/// An instance of a `File` can be read and/or written depending on what options
+/// it was opened with. Files also implement `Seek` to alter the logical cursor
+/// that the file contains internally.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::fs::File;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// let mut f = try!(File::create("foo.txt"));
+/// try!(f.write_all(b"Hello, world!"));
+///
+/// let mut f = try!(File::open("foo.txt"));
+/// let mut s = String::new();
+/// try!(f.read_to_string(&mut s));
+/// assert_eq!(s, "Hello, world!");
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct File {
+ inner: fs_imp::File,
+ path: Option<PathBuf>,
+}
+
+/// Metadata information about a file.
+///
+/// This structure is returned from the `metadata` function or method and
+/// represents known metadata about a file such as its permissions, size,
+/// modification times, etc.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Metadata(fs_imp::FileAttr);
+
+/// Iterator over the entries in a directory.
+///
+/// This iterator is returned from the `read_dir` function of this module and
+/// will yield instances of `io::Result<DirEntry>`. Through a `DirEntry`
+/// information like the entry's path and possibly other metadata can be
+/// learned.
+///
+/// # Failure
+///
+/// This `io::Result` will be an `Err` if there's some sort of intermittent
+/// IO error during iteration.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct ReadDir(fs_imp::ReadDir);
+
+/// Entries returned by the `ReadDir` iterator.
+///
+/// An instance of `DirEntry` represents an entry inside of a directory on the
+/// filesystem. Each entry can be inspected via methods to learn about the full
+/// path or possibly other metadata through per-platform extension traits.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct DirEntry(fs_imp::DirEntry);
+
+/// An iterator that recursively walks over the contents of a directory.
+#[unstable(feature = "fs_walk",
+ reason = "the precise semantics and defaults for a recursive walk \
+ may change and this may end up accounting for files such \
+ as symlinks differently")]
+pub struct WalkDir {
+ cur: Option<ReadDir>,
+ stack: Vec<io::Result<ReadDir>>,
+}
+
+/// Options and flags which can be used to configure how a file is opened.
+///
+/// This builder exposes the ability to configure how a `File` is opened and
+/// what operations are permitted on the open file. The `File::open` and
+/// `File::create` methods are aliases for commonly used options using this
+/// builder.
+#[derive(Clone)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct OpenOptions(fs_imp::OpenOptions);
+
+/// Representation of the various permissions on a file.
+///
+/// This module only currently provides one bit of information, `readonly`,
+/// which is exposed on all currently supported platforms. Unix-specific
+/// functionality, such as mode bits, is available through the
+/// `os::unix::PermissionsExt` trait.
+#[derive(Clone, PartialEq, Eq, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Permissions(fs_imp::FilePermissions);
+
+impl File {
+ /// Attempts to open a file in read-only mode.
+ ///
+ /// See the `OpenOptions::open` method for more details.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if `path` does not already exist.
+ /// Other errors may also be returned according to `OpenOptions::open`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let mut f = try!(File::open("foo.txt"));
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
+ OpenOptions::new().read(true).open(path)
+ }
+
+ /// Open a file in write-only mode.
+ ///
+ /// This function will create a file if it does not exist,
+ /// and will truncate it if it does.
+ ///
+ /// See the `OpenOptions::open` function for more details.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let mut f = try!(File::create("foo.txt"));
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
+ OpenOptions::new().write(true).create(true).truncate(true).open(path)
+ }
+
+ /// Returns the original path that was used to open this file.
+ #[unstable(feature = "file_path",
+ reason = "this abstraction is imposed by this library instead \
+ of the underlying OS and may be removed")]
+ pub fn path(&self) -> Option<&Path> {
+ self.path.as_ref().map(|p| &**p)
+ }
+
+ /// Attempt to sync all OS-internal metadata to disk.
+ ///
+ /// This function will attempt to ensure that all in-core data reaches the
+ /// filesystem before returning.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::io::prelude::*;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let mut f = try!(File::create("foo.txt"));
+ /// try!(f.write_all(b"Hello, world!"));
+ ///
+ /// try!(f.sync_all());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn sync_all(&self) -> io::Result<()> {
+ self.inner.fsync()
+ }
+
+ /// This function is similar to `sync_all`, except that it may not
+ /// synchronize file metadata to the filesystem.
+ ///
+ /// This is intended for use cases that must synchronize content, but don't
+ /// need the metadata on disk. The goal of this method is to reduce disk
+ /// operations.
+ ///
+ /// Note that some platforms may simply implement this in terms of
+ /// `sync_all`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::io::prelude::*;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let mut f = try!(File::create("foo.txt"));
+ /// try!(f.write_all(b"Hello, world!"));
+ ///
+ /// try!(f.sync_data());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn sync_data(&self) -> io::Result<()> {
+ self.inner.datasync()
+ }
+
+ /// Truncates or extends the underlying file, updating the size of
+ /// this file to become `size`.
+ ///
+ /// If the `size` is less than the current file's size, then the file will
+ /// be shrunk. If it is greater than the current file's size, then the file
+ /// will be extended to `size` and have all of the intermediate data filled
+ /// in with 0s.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let mut f = try!(File::open("foo.txt"));
+ /// try!(f.set_len(0));
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn set_len(&self, size: u64) -> io::Result<()> {
+ self.inner.truncate(size)
+ }
+
+ /// Queries metadata about the underlying file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let mut f = try!(File::open("foo.txt"));
+ /// let metadata = try!(f.metadata());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn metadata(&self) -> io::Result<Metadata> {
+ self.inner.file_attr().map(Metadata)
+ }
+}
+
+impl AsInner<fs_imp::File> for File {
+ fn as_inner(&self) -> &fs_imp::File { &self.inner }
+}
+impl FromInner<fs_imp::File> for File {
+ fn from_inner(f: fs_imp::File) -> File {
+ File { inner: f, path: None }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Read for File {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(buf)
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Write for File {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.inner.write(buf)
+ }
+ fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Seek for File {
+ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+ self.inner.seek(pos)
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Read for &'a File {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(buf)
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Write for &'a File {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.inner.write(buf)
+ }
+ fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Seek for &'a File {
+ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+ self.inner.seek(pos)
+ }
+}
+
+impl OpenOptions {
+ /// Creates a blank net set of options ready for configuration.
+ ///
+ /// All options are initially set to `false`.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new() -> OpenOptions {
+ OpenOptions(fs_imp::OpenOptions::new())
+ }
+
+ /// Set the option for read access.
+ ///
+ /// This option, when true, will indicate that the file should be
+ /// `read`-able if opened.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn read(&mut self, read: bool) -> &mut OpenOptions {
+ self.0.read(read); self
+ }
+
+ /// Set the option for write access.
+ ///
+ /// This option, when true, will indicate that the file should be
+ /// `write`-able if opened.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn write(&mut self, write: bool) -> &mut OpenOptions {
+ self.0.write(write); self
+ }
+
+ /// Set the option for the append mode.
+ ///
+ /// This option, when true, means that writes will append to a file instead
+ /// of overwriting previous contents.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn append(&mut self, append: bool) -> &mut OpenOptions {
+ self.0.append(append); self
+ }
+
+ /// Set the option for truncating a previous file.
+ ///
+ /// If a file is successfully opened with this option set it will truncate
+ /// the file to 0 length if it already exists.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
+ self.0.truncate(truncate); self
+ }
+
+ /// Set the option for creating a new file.
+ ///
+ /// This option indicates whether a new file will be created if the file
+ /// does not yet already exist.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn create(&mut self, create: bool) -> &mut OpenOptions {
+ self.0.create(create); self
+ }
+
+ /// Open a file at `path` with the options specified by `self`.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error under a number of different
+ /// circumstances, to include but not limited to:
+ ///
+ /// * Opening a file that does not exist with read access.
+ /// * Attempting to open a file with access that the user lacks
+ /// permissions for
+ /// * Filesystem-level errors (full disk, etc)
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
+ let path = path.as_ref();
+ let inner = try!(fs_imp::File::open(path, &self.0));
+ Ok(File { path: Some(path.to_path_buf()), inner: inner })
+ }
+}
+
+impl AsInnerMut<fs_imp::OpenOptions> for OpenOptions {
+ fn as_inner_mut(&mut self) -> &mut fs_imp::OpenOptions { &mut self.0 }
+}
+
+impl Metadata {
+ /// Returns whether this metadata is for a directory.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_dir(&self) -> bool { self.0.is_dir() }
+
+ /// Returns whether this metadata is for a regular file.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_file(&self) -> bool { self.0.is_file() }
+
+ /// Returns the size of the file, in bytes, this metadata is for.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn len(&self) -> u64 { self.0.size() }
+
+ /// Returns the permissions of the file this metadata is for.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn permissions(&self) -> Permissions {
+ Permissions(self.0.perm())
+ }
+
+ /// Returns the most recent access time for a file.
+ ///
+ /// The return value is in milliseconds since the epoch.
+ #[unstable(feature = "fs_time",
+ reason = "the return type of u64 is not quite appropriate for \
+ this method and may change if the standard library \
+ gains a type to represent a moment in time")]
+ pub fn accessed(&self) -> u64 { self.0.accessed() }
+
+ /// Returns the most recent modification time for a file.
+ ///
+ /// The return value is in milliseconds since the epoch.
+ #[unstable(feature = "fs_time",
+ reason = "the return type of u64 is not quite appropriate for \
+ this method and may change if the standard library \
+ gains a type to represent a moment in time")]
+ pub fn modified(&self) -> u64 { self.0.modified() }
+}
+
+impl Permissions {
+ /// Returns whether these permissions describe a readonly file.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn readonly(&self) -> bool { self.0.readonly() }
+
+ /// Modify the readonly flag for this set of permissions.
+ ///
+ /// This operation does **not** modify the filesystem. To modify the
+ /// filesystem use the `fs::set_permissions` function.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn set_readonly(&mut self, readonly: bool) {
+ self.0.set_readonly(readonly)
+ }
+}
+
+impl FromInner<fs_imp::FilePermissions> for Permissions {
+ fn from_inner(f: fs_imp::FilePermissions) -> Permissions {
+ Permissions(f)
+ }
+}
+
+impl AsInner<fs_imp::FilePermissions> for Permissions {
+ fn as_inner(&self) -> &fs_imp::FilePermissions { &self.0 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Iterator for ReadDir {
+ type Item = io::Result<DirEntry>;
+
+ fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ self.0.next().map(|entry| entry.map(DirEntry))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl DirEntry {
+ /// Returns the full path to the file that this entry represents.
+ ///
+ /// The full path is created by joining the original path to `read_dir` or
+ /// `walk_dir` with the filename of this entry.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn path(&self) -> PathBuf { self.0.path() }
+}
+
+/// Remove a file from the underlying filesystem.
+///
+/// # Examples
+///
+/// ```rust,no_run
+/// use std::fs;
+///
+/// fs::remove_file("/some/file/path.txt");
+/// ```
+///
+/// Note that, just because an unlink call was successful, it is not
+/// guaranteed that a file is immediately deleted (e.g. depending on
+/// platform, other open file descriptors may prevent immediate removal).
+///
+/// # Errors
+///
+/// This function will return an error if `path` points to a directory, if the
+/// user lacks permissions to remove the file, or if some other filesystem-level
+/// error occurs.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ fs_imp::unlink(path.as_ref())
+}
+
+/// Given a path, query the file system to get information about a file,
+/// directory, etc.
+///
+/// This function will traverse soft links to query information about the
+/// destination file.
+///
+/// # Examples
+///
+/// ```rust,no_run
+/// # fn foo() -> std::io::Result<()> {
+/// use std::fs;
+///
+/// let attr = try!(fs::metadata("/some/file/path.txt"));
+/// // inspect attr ...
+/// # Ok(())
+/// # }
+/// ```
+///
+/// # Errors
+///
+/// This function will return an error if the user lacks the requisite
+/// permissions to perform a `metadata` call on the given `path` or if there
+/// is no entry in the filesystem at the provided path.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
+ fs_imp::stat(path.as_ref()).map(Metadata)
+}
+
+/// Rename a file or directory to a new name.
+///
+/// # Examples
+///
+/// ```rust,no_run
+/// use std::fs;
+///
+/// fs::rename("foo", "bar");
+/// ```
+///
+/// # Errors
+///
+/// This function will return an error if the provided `from` doesn't exist, if
+/// the process lacks permissions to view the contents, if `from` and `to`
+/// reside on separate filesystems, or if some other intermittent I/O error
+/// occurs.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
+ fs_imp::rename(from.as_ref(), to.as_ref())
+}
+
+/// Copies the contents of one file to another. This function will also
+/// copy the permission bits of the original file to the destination file.
+///
+/// This function will **overwrite** the contents of `to`.
+///
+/// Note that if `from` and `to` both point to the same file, then the file
+/// will likely get truncated by this operation.
+///
+/// # Examples
+///
+/// ```
+/// use std::fs;
+///
+/// fs::copy("foo.txt", "bar.txt");
+/// ```
+///
+/// # Errors
+///
+/// This function will return an error in the following situations, but is not
+/// limited to just these cases:
+///
+/// * The `from` path is not a file
+/// * The `from` file does not exist
+/// * The current process does not have the permission rights to access
+/// `from` or write `to`
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
+ let from = from.as_ref();
+ let to = to.as_ref();
+ if !from.is_file() {
+ return Err(Error::new(ErrorKind::InvalidInput,
+ "the source path is not an existing file"))
+ }
+
+ let mut reader = try!(File::open(from));
+ let mut writer = try!(File::create(to));
+ let perm = try!(reader.metadata()).permissions();
+
+ let ret = try!(io::copy(&mut reader, &mut writer));
+ try!(set_permissions(to, perm));
+ Ok(ret)
+}
+
+/// Creates a new hard link on the filesystem.
+///
+/// The `dst` path will be a link pointing to the `src` path. Note that systems
+/// often require these two paths to both be located on the same filesystem.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
+ fs_imp::link(src.as_ref(), dst.as_ref())
+}
+
+/// Creates a new soft link on the filesystem.
+///
+/// The `dst` path will be a soft link pointing to the `src` path.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
+ fs_imp::symlink(src.as_ref(), dst.as_ref())
+}
+
+/// Reads a soft link, returning the file that the link points to.
+///
+/// # Errors
+///
+/// This function will return an error on failure. Failure conditions include
+/// reading a file that does not exist or reading a file that is not a soft
+/// link.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
+ fs_imp::readlink(path.as_ref())
+}
+
+/// Create a new, empty directory at the provided path
+///
+/// # Examples
+///
+/// ```
+/// use std::fs;
+///
+/// fs::create_dir("/some/dir");
+/// ```
+///
+/// # Errors
+///
+/// This function will return an error if the user lacks permissions to make a
+/// new directory at the provided `path`, or if the directory already exists.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ fs_imp::mkdir(path.as_ref())
+}
+
+/// Recursively create a directory and all of its parent components if they
+/// are missing.
+///
+/// # Errors
+///
+/// This function will fail if any directory in the path specified by `path`
+/// does not already exist and it could not be created otherwise. The specific
+/// error conditions for when a directory is being created (after it is
+/// determined to not exist) are outlined by `fs::create_dir`.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ let path = path.as_ref();
+ if path == Path::new("") || path.is_dir() { return Ok(()) }
+ if let Some(p) = path.parent() { try!(create_dir_all(p)) }
+ create_dir(path)
+}
+
+/// Remove an existing, empty directory
+///
+/// # Examples
+///
+/// ```
+/// use std::fs;
+///
+/// fs::remove_dir("/some/dir");
+/// ```
+///
+/// # Errors
+///
+/// This function will return an error if the user lacks permissions to remove
+/// the directory at the provided `path`, or if the directory isn't empty.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ fs_imp::rmdir(path.as_ref())
+}
+
+/// Removes a directory at this path, after removing all its contents. Use
+/// carefully!
+///
+/// This function does **not** follow soft links and it will simply remove the
+/// soft link itself.
+///
+/// # Errors
+///
+/// See `file::remove_file` and `fs::remove_dir`
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ let path = path.as_ref();
+ for child in try!(read_dir(path)) {
+ let child = try!(child).path();
+ let stat = try!(lstat(&*child));
+ if stat.is_dir() {
+ try!(remove_dir_all(&*child));
+ } else {
+ try!(remove_file(&*child));
+ }
+ }
+ return remove_dir(path);
+
+ #[cfg(unix)]
+ fn lstat(path: &Path) -> io::Result<fs_imp::FileAttr> { fs_imp::lstat(path) }
+ #[cfg(windows)]
+ fn lstat(path: &Path) -> io::Result<fs_imp::FileAttr> { fs_imp::stat(path) }
+}
+
+/// Returns an iterator over the entries within a directory.
+///
+/// The iterator will yield instances of `io::Result<DirEntry>`. New errors may
+/// be encountered after an iterator is initially constructed.
+///
+/// # Examples
+///
+/// ```
+/// # #![feature(path_ext)]
+/// use std::io;
+/// use std::fs::{self, PathExt, DirEntry};
+/// use std::path::Path;
+///
+/// // one possible implementation of fs::walk_dir only visiting files
+/// fn visit_dirs(dir: &Path, cb: &mut FnMut(DirEntry)) -> io::Result<()> {
+/// if dir.is_dir() {
+/// for entry in try!(fs::read_dir(dir)) {
+/// let entry = try!(entry);
+/// if entry.path().is_dir() {
+/// try!(visit_dirs(&entry.path(), cb));
+/// } else {
+/// cb(entry);
+/// }
+/// }
+/// }
+/// Ok(())
+/// }
+/// ```
+///
+/// # Errors
+///
+/// This function will return an error if the provided `path` doesn't exist, if
+/// the process lacks permissions to view the contents or if the `path` points
+/// at a non-directory file
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
+ fs_imp::readdir(path.as_ref()).map(ReadDir)
+}
+
+/// Returns an iterator that will recursively walk the directory structure
+/// rooted at `path`.
+///
+/// The path given will not be iterated over, and this will perform iteration in
+/// some top-down order. The contents of unreadable subdirectories are ignored.
+///
+/// The iterator will yield instances of `io::Result<DirEntry>`. New errors may
+/// be encountered after an iterator is initially constructed.
+#[unstable(feature = "fs_walk",
+ reason = "the precise semantics and defaults for a recursive walk \
+ may change and this may end up accounting for files such \
+ as symlinks differently")]
+pub fn walk_dir<P: AsRef<Path>>(path: P) -> io::Result<WalkDir> {
+ let start = try!(read_dir(path));
+ Ok(WalkDir { cur: Some(start), stack: Vec::new() })
+}
+
+#[unstable(feature = "fs_walk")]
+impl Iterator for WalkDir {
+ type Item = io::Result<DirEntry>;
+
+ fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ loop {
+ if let Some(ref mut cur) = self.cur {
+ match cur.next() {
+ Some(Err(e)) => return Some(Err(e)),
+ Some(Ok(next)) => {
+ let path = next.path();
+ if path.is_dir() {
+ self.stack.push(read_dir(&*path));
+ }
+ return Some(Ok(next))
+ }
+ None => {}
+ }
+ }
+ self.cur = None;
+ match self.stack.pop() {
+ Some(Err(e)) => return Some(Err(e)),
+ Some(Ok(next)) => self.cur = Some(next),
+ None => return None,
+ }
+ }
+ }
+}
+
+/// Utility methods for paths.
+#[unstable(feature = "path_ext",
+ reason = "the precise set of methods exposed on this trait may \
+ change and some methods may be removed")]
+pub trait PathExt {
+ /// Get information on the file, directory, etc at this path.
+ ///
+ /// Consult the `fs::stat` documentation for more info.
+ ///
+ /// This call preserves identical runtime/error semantics with `file::stat`.
+ fn metadata(&self) -> io::Result<Metadata>;
+
+ /// Boolean value indicator whether the underlying file exists on the local
+ /// filesystem. Returns false in exactly the cases where `fs::stat` fails.
+ fn exists(&self) -> bool;
+
+ /// Whether the underlying implementation (be it a file path, or something
+ /// else) points at a "regular file" on the FS. Will return false for paths
+ /// to non-existent locations or directories or other non-regular files
+ /// (named pipes, etc). Follows links when making this determination.
+ fn is_file(&self) -> bool;
+
+ /// Whether the underlying implementation (be it a file path, or something
+ /// else) is pointing at a directory in the underlying FS. Will return
+ /// false for paths to non-existent locations or if the item is not a
+ /// directory (eg files, named pipes, etc). Follows links when making this
+ /// determination.
+ fn is_dir(&self) -> bool;
+}
+
+impl PathExt for Path {
+ fn metadata(&self) -> io::Result<Metadata> { metadata(self) }
+
+ fn exists(&self) -> bool { metadata(self).is_ok() }
+
+ fn is_file(&self) -> bool {
+ metadata(self).map(|s| s.is_file()).unwrap_or(false)
+ }
+ fn is_dir(&self) -> bool {
+ metadata(self).map(|s| s.is_dir()).unwrap_or(false)
+ }
+}
+
+/// Changes the timestamps for a file's last modification and access time.
+///
+/// The file at the path specified will have its last access time set to
+/// `atime` and its modification time set to `mtime`. The times specified should
+/// be in milliseconds.
+#[unstable(feature = "fs_time",
+ reason = "the argument type of u64 is not quite appropriate for \
+ this function and may change if the standard library \
+ gains a type to represent a moment in time")]
+pub fn set_file_times<P: AsRef<Path>>(path: P, accessed: u64,
+ modified: u64) -> io::Result<()> {
+ fs_imp::utimes(path.as_ref(), accessed, modified)
+}
+
+/// Changes the permissions found on a file or a directory.
+///
+/// # Examples
+///
+/// ```
+/// # #![feature(fs)]
+/// # fn foo() -> std::io::Result<()> {
+/// use std::fs;
+///
+/// let mut perms = try!(fs::metadata("foo.txt")).permissions();
+/// perms.set_readonly(true);
+/// try!(fs::set_permissions("foo.txt", perms));
+/// # Ok(())
+/// # }
+/// ```
+///
+/// # Errors
+///
+/// This function will return an error if the provided `path` doesn't exist, if
+/// the process lacks permissions to change the attributes of the file, or if
+/// some other I/O error is encountered.
+#[unstable(feature = "fs",
+ reason = "a more granual ability to set specific permissions may \
+ be exposed on the Permissions structure itself and this \
+ method may not always exist")]
+pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
+ fs_imp::set_perm(path.as_ref(), perm.0)
+}
+
+#[cfg(test)]
+mod tests {
+ #![allow(deprecated)] //rand
+
+ use prelude::v1::*;
+ use io::prelude::*;
+
+ use env;
+ use fs::{self, File, OpenOptions};
+ use io::{ErrorKind, SeekFrom};
+ use path::PathBuf;
+ use path::Path as Path2;
+ use os;
+ use rand::{self, StdRng, Rng};
+ use str;
+
+ macro_rules! check { ($e:expr) => (
+ match $e {
+ Ok(t) => t,
+ Err(e) => panic!("{} failed with: {}", stringify!($e), e),
+ }
+ ) }
+
+ macro_rules! error { ($e:expr, $s:expr) => (
+ match $e {
+ Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
+ Err(ref err) => assert!(err.to_string().contains($s),
+ format!("`{}` did not contain `{}`", err, $s))
+ }
+ ) }
+
+ pub struct TempDir(PathBuf);
+
+ impl TempDir {
+ fn join(&self, path: &str) -> PathBuf {
+ let TempDir(ref p) = *self;
+ p.join(path)
+ }
+
+ fn path<'a>(&'a self) -> &'a Path2 {
+ let TempDir(ref p) = *self;
+ p
+ }
+ }
+
+ impl Drop for TempDir {
+ fn drop(&mut self) {
+ // Gee, seeing how we're testing the fs module I sure hope that we
+ // at least implement this correctly!
+ let TempDir(ref p) = *self;
+ check!(fs::remove_dir_all(p));
+ }
+ }
+
+ pub fn tmpdir() -> TempDir {
+ let p = env::temp_dir();
+ let ret = p.join(&format!("rust-{}", rand::random::<u32>()));
+ check!(fs::create_dir(&ret));
+ TempDir(ret)
+ }
+
+ #[test]
+ fn file_test_io_smoke_test() {
+ let message = "it's alright. have a good time";
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test.txt");
+ {
+ let mut write_stream = check!(File::create(filename));
+ check!(write_stream.write(message.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+ let mut read_buf = [0; 1028];
+ let read_str = match check!(read_stream.read(&mut read_buf)) {
+ -1|0 => panic!("shouldn't happen"),
+ n => str::from_utf8(&read_buf[..n]).unwrap().to_string()
+ };
+ assert_eq!(read_str, message);
+ }
+ check!(fs::remove_file(filename));
+ }
+
+ #[test]
+ fn invalid_path_raises() {
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_that_does_not_exist.txt");
+ let result = File::open(filename);
+
+ if cfg!(unix) {
+ error!(result, "o such file or directory");
+ }
+ // error!(result, "couldn't open path as file");
+ // error!(result, format!("path={}; mode=open; access=read", filename.display()));
+ }
+
+ #[test]
+ fn file_test_iounlinking_invalid_path_should_raise_condition() {
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt");
+
+ let result = fs::remove_file(filename);
+
+ if cfg!(unix) {
+ error!(result, "o such file or directory");
+ }
+ // error!(result, "couldn't unlink path");
+ // error!(result, format!("path={}", filename.display()));
+ }
+
+ #[test]
+ fn file_test_io_non_positional_read() {
+ let message: &str = "ten-four";
+ let mut read_mem = [0; 8];
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test_positional.txt");
+ {
+ let mut rw_stream = check!(File::create(filename));
+ check!(rw_stream.write(message.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+ {
+ let read_buf = &mut read_mem[0..4];
+ check!(read_stream.read(read_buf));
+ }
+ {
+ let read_buf = &mut read_mem[4..8];
+ check!(read_stream.read(read_buf));
+ }
+ }
+ check!(fs::remove_file(filename));
+ let read_str = str::from_utf8(&read_mem).unwrap();
+ assert_eq!(read_str, message);
+ }
+
+ #[test]
+ fn file_test_io_seek_and_tell_smoke_test() {
+ let message = "ten-four";
+ let mut read_mem = [0; 4];
+ let set_cursor = 4 as u64;
+ let mut tell_pos_pre_read;
+ let mut tell_pos_post_read;
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt");
+ {
+ let mut rw_stream = check!(File::create(filename));
+ check!(rw_stream.write(message.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+ check!(read_stream.seek(SeekFrom::Start(set_cursor)));
+ tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0)));
+ check!(read_stream.read(&mut read_mem));
+ tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0)));
+ }
+ check!(fs::remove_file(filename));
+ let read_str = str::from_utf8(&read_mem).unwrap();
+ assert_eq!(read_str, &message[4..8]);
+ assert_eq!(tell_pos_pre_read, set_cursor);
+ assert_eq!(tell_pos_post_read, message.len() as u64);
+ }
+
+ #[test]
+ fn file_test_io_seek_and_write() {
+ let initial_msg = "food-is-yummy";
+ let overwrite_msg = "-the-bar!!";
+ let final_msg = "foo-the-bar!!";
+ let seek_idx = 3;
+ let mut read_mem = [0; 13];
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt");
+ {
+ let mut rw_stream = check!(File::create(filename));
+ check!(rw_stream.write(initial_msg.as_bytes()));
+ check!(rw_stream.seek(SeekFrom::Start(seek_idx)));
+ check!(rw_stream.write(overwrite_msg.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+ check!(read_stream.read(&mut read_mem));
+ }
+ check!(fs::remove_file(filename));
+ let read_str = str::from_utf8(&read_mem).unwrap();
+ assert!(read_str == final_msg);
+ }
+
+ #[test]
+ fn file_test_io_seek_shakedown() {
+ // 01234567890123
+ let initial_msg = "qwer-asdf-zxcv";
+ let chunk_one: &str = "qwer";
+ let chunk_two: &str = "asdf";
+ let chunk_three: &str = "zxcv";
+ let mut read_mem = [0; 4];
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt");
+ {
+ let mut rw_stream = check!(File::create(filename));
+ check!(rw_stream.write(initial_msg.as_bytes()));
+ }
+ {
+ let mut read_stream = check!(File::open(filename));
+
+ check!(read_stream.seek(SeekFrom::End(-4)));
+ check!(read_stream.read(&mut read_mem));
+ assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three);
+
+ check!(read_stream.seek(SeekFrom::Current(-9)));
+ check!(read_stream.read(&mut read_mem));
+ assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two);
+
+ check!(read_stream.seek(SeekFrom::Start(0)));
+ check!(read_stream.read(&mut read_mem));
+ assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one);
+ }
+ check!(fs::remove_file(filename));
+ }
+
+ #[test]
+ fn file_test_stat_is_correct_on_is_file() {
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_stat_correct_on_is_file.txt");
+ {
+ let mut opts = OpenOptions::new();
+ let mut fs = check!(opts.read(true).write(true)
+ .create(true).open(filename));
+ let msg = "hw";
+ fs.write(msg.as_bytes()).unwrap();
+
+ let fstat_res = check!(fs.metadata());
+ assert!(fstat_res.is_file());
+ }
+ let stat_res_fn = check!(fs::metadata(filename));
+ assert!(stat_res_fn.is_file());
+ let stat_res_meth = check!(filename.metadata());
+ assert!(stat_res_meth.is_file());
+ check!(fs::remove_file(filename));
+ }
+
+ #[test]
+ fn file_test_stat_is_correct_on_is_dir() {
+ let tmpdir = tmpdir();
+ let filename = &tmpdir.join("file_stat_correct_on_is_dir");
+ check!(fs::create_dir(filename));
+ let stat_res_fn = check!(fs::metadata(filename));
+ assert!(stat_res_fn.is_dir());
+ let stat_res_meth = check!(filename.metadata());
+ assert!(stat_res_meth.is_dir());
+ check!(fs::remove_dir(filename));
+ }
+
+ #[test]
+ fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
+ let tmpdir = tmpdir();
+ let dir = &tmpdir.join("fileinfo_false_on_dir");
+ check!(fs::create_dir(dir));
+ assert!(dir.is_file() == false);
+ check!(fs::remove_dir(dir));
+ }
+
+ #[test]
+ fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
+ let tmpdir = tmpdir();
+ let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt");
+ check!(check!(File::create(file)).write(b"foo"));
+ assert!(file.exists());
+ check!(fs::remove_file(file));
+ assert!(!file.exists());
+ }
+
+ #[test]
+ fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
+ let tmpdir = tmpdir();
+ let dir = &tmpdir.join("before_and_after_dir");
+ assert!(!dir.exists());
+ check!(fs::create_dir(dir));
+ assert!(dir.exists());
+ assert!(dir.is_dir());
+ check!(fs::remove_dir(dir));
+ assert!(!dir.exists());
+ }
+
+ #[test]
+ fn file_test_directoryinfo_readdir() {
+ let tmpdir = tmpdir();
+ let dir = &tmpdir.join("di_readdir");
+ check!(fs::create_dir(dir));
+ let prefix = "foo";
+ for n in 0..3 {
+ let f = dir.join(&format!("{}.txt", n));
+ let mut w = check!(File::create(&f));
+ let msg_str = format!("{}{}", prefix, n.to_string());
+ let msg = msg_str.as_bytes();
+ check!(w.write(msg));
+ }
+ let files = check!(fs::read_dir(dir));
+ let mut mem = [0; 4];
+ for f in files {
+ let f = f.unwrap().path();
+ {
+ let n = f.file_stem().unwrap();
+ check!(check!(File::open(&f)).read(&mut mem));
+ let read_str = str::from_utf8(&mem).unwrap();
+ let expected = format!("{}{}", prefix, n.to_str().unwrap());
+ assert_eq!(expected, read_str);
+ }
+ check!(fs::remove_file(&f));
+ }
+ check!(fs::remove_dir(dir));
+ }
+
+ #[test]
+ fn file_test_walk_dir() {
+ let tmpdir = tmpdir();
+ let dir = &tmpdir.join("walk_dir");
+ check!(fs::create_dir(dir));
+
+ let dir1 = &dir.join("01/02/03");
+ check!(fs::create_dir_all(dir1));
+ check!(File::create(&dir1.join("04")));
+
+ let dir2 = &dir.join("11/12/13");
+ check!(fs::create_dir_all(dir2));
+ check!(File::create(&dir2.join("14")));
+
+ let files = check!(fs::walk_dir(dir));
+ let mut cur = [0; 2];
+ for f in files {
+ let f = f.unwrap().path();
+ let stem = f.file_stem().unwrap().to_str().unwrap();
+ let root = stem.as_bytes()[0] - b'0';
+ let name = stem.as_bytes()[1] - b'0';
+ assert!(cur[root as usize] < name);
+ cur[root as usize] = name;
+ }
+
+ check!(fs::remove_dir_all(dir));
+ }
+
+ #[test]
+ fn mkdir_path_already_exists_error() {
+ let tmpdir = tmpdir();
+ let dir = &tmpdir.join("mkdir_error_twice");
+ check!(fs::create_dir(dir));
+ let e = fs::create_dir(dir).err().unwrap();
+ assert_eq!(e.kind(), ErrorKind::AlreadyExists);
+ }
+
+ #[test]
+ fn recursive_mkdir() {
+ let tmpdir = tmpdir();
+ let dir = tmpdir.join("d1/d2");
+ check!(fs::create_dir_all(&dir));
+ assert!(dir.is_dir())
+ }
+
+ #[test]
+ fn recursive_mkdir_failure() {
+ let tmpdir = tmpdir();
+ let dir = tmpdir.join("d1");
+ let file = dir.join("f1");
+
+ check!(fs::create_dir_all(&dir));
+ check!(File::create(&file));
+
+ let result = fs::create_dir_all(&file);
+
+ assert!(result.is_err());
+ // error!(result, "couldn't recursively mkdir");
+ // error!(result, "couldn't create directory");
+ // error!(result, "mode=0700");
+ // error!(result, format!("path={}", file.display()));
+ }
+
+ #[test]
+ fn recursive_mkdir_slash() {
+ check!(fs::create_dir_all(&Path2::new("/")));
+ }
+
+ // FIXME(#12795) depends on lstat to work on windows
+ #[cfg(not(windows))]
+ #[test]
+ fn recursive_rmdir() {
+ let tmpdir = tmpdir();
+ let d1 = tmpdir.join("d1");
+ let dt = d1.join("t");
+ let dtt = dt.join("t");
+ let d2 = tmpdir.join("d2");
+ let canary = d2.join("do_not_delete");
+ check!(fs::create_dir_all(&dtt));
+ check!(fs::create_dir_all(&d2));
+ check!(check!(File::create(&canary)).write(b"foo"));
+ check!(fs::soft_link(&d2, &dt.join("d2")));
+ check!(fs::remove_dir_all(&d1));
+
+ assert!(!d1.is_dir());
+ assert!(canary.exists());
+ }
+
+ #[test]
+ fn unicode_path_is_dir() {
+ assert!(Path2::new(".").is_dir());
+ assert!(!Path2::new("test/stdtest/fs.rs").is_dir());
+
+ let tmpdir = tmpdir();
+
+ let mut dirpath = tmpdir.path().to_path_buf();
+ dirpath.push(&format!("test-가一ー你好"));
+ check!(fs::create_dir(&dirpath));
+ assert!(dirpath.is_dir());
+
+ let mut filepath = dirpath;
+ filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs");
+ check!(File::create(&filepath)); // ignore return; touch only
+ assert!(!filepath.is_dir());
+ assert!(filepath.exists());
+ }
+
+ #[test]
+ fn unicode_path_exists() {
+ assert!(Path2::new(".").exists());
+ assert!(!Path2::new("test/nonexistent-bogus-path").exists());
+
+ let tmpdir = tmpdir();
+ let unicode = tmpdir.path();
+ let unicode = unicode.join(&format!("test-각丁ー再见"));
+ check!(fs::create_dir(&unicode));
+ assert!(unicode.exists());
+ assert!(!Path2::new("test/unicode-bogus-path-각丁ー再见").exists());
+ }
+
+ #[test]
+ fn copy_file_does_not_exist() {
+ let from = Path2::new("test/nonexistent-bogus-path");
+ let to = Path2::new("test/other-bogus-path");
+
+ match fs::copy(&from, &to) {
+ Ok(..) => panic!(),
+ Err(..) => {
+ assert!(!from.exists());
+ assert!(!to.exists());
+ }
+ }
+ }
+
+ #[test]
+ fn copy_file_ok() {
+ let tmpdir = tmpdir();
+ let input = tmpdir.join("in.txt");
+ let out = tmpdir.join("out.txt");
+
+ check!(check!(File::create(&input)).write(b"hello"));
+ check!(fs::copy(&input, &out));
+ let mut v = Vec::new();
+ check!(check!(File::open(&out)).read_to_end(&mut v));
+ assert_eq!(v, b"hello");
+
+ assert_eq!(check!(input.metadata()).permissions(),
+ check!(out.metadata()).permissions());
+ }
+
+ #[test]
+ fn copy_file_dst_dir() {
+ let tmpdir = tmpdir();
+ let out = tmpdir.join("out");
+
+ check!(File::create(&out));
+ match fs::copy(&*out, tmpdir.path()) {
+ Ok(..) => panic!(), Err(..) => {}
+ }
+ }
+
+ #[test]
+ fn copy_file_dst_exists() {
+ let tmpdir = tmpdir();
+ let input = tmpdir.join("in");
+ let output = tmpdir.join("out");
+
+ check!(check!(File::create(&input)).write("foo".as_bytes()));
+ check!(check!(File::create(&output)).write("bar".as_bytes()));
+ check!(fs::copy(&input, &output));
+
+ let mut v = Vec::new();
+ check!(check!(File::open(&output)).read_to_end(&mut v));
+ assert_eq!(v, b"foo".to_vec());
+ }
+
+ #[test]
+ fn copy_file_src_dir() {
+ let tmpdir = tmpdir();
+ let out = tmpdir.join("out");
+
+ match fs::copy(tmpdir.path(), &out) {
+ Ok(..) => panic!(), Err(..) => {}
+ }
+ assert!(!out.exists());
+ }
+
+ #[test]
+ fn copy_file_preserves_perm_bits() {
+ let tmpdir = tmpdir();
+ let input = tmpdir.join("in.txt");
+ let out = tmpdir.join("out.txt");
+
+ let attr = check!(check!(File::create(&input)).metadata());
+ let mut p = attr.permissions();
+ p.set_readonly(true);
+ check!(fs::set_permissions(&input, p));
+ check!(fs::copy(&input, &out));
+ assert!(check!(out.metadata()).permissions().readonly());
+ check!(fs::set_permissions(&input, attr.permissions()));
+ check!(fs::set_permissions(&out, attr.permissions()));
+ }
+
+ #[cfg(not(windows))] // FIXME(#10264) operation not permitted?
+ #[test]
+ fn symlinks_work() {
+ let tmpdir = tmpdir();
+ let input = tmpdir.join("in.txt");
+ let out = tmpdir.join("out.txt");
+
+ check!(check!(File::create(&input)).write("foobar".as_bytes()));
+ check!(fs::soft_link(&input, &out));
+ // if cfg!(not(windows)) {
+ // assert_eq!(check!(lstat(&out)).kind, FileType::Symlink);
+ // assert_eq!(check!(out.lstat()).kind, FileType::Symlink);
+ // }
+ assert_eq!(check!(fs::metadata(&out)).len(),
+ check!(fs::metadata(&input)).len());
+ let mut v = Vec::new();
+ check!(check!(File::open(&out)).read_to_end(&mut v));
+ assert_eq!(v, b"foobar".to_vec());
+ }
+
+ #[cfg(not(windows))] // apparently windows doesn't like symlinks
+ #[test]
+ fn symlink_noexist() {
+ let tmpdir = tmpdir();
+ // symlinks can point to things that don't exist
+ check!(fs::soft_link(&tmpdir.join("foo"), &tmpdir.join("bar")));
+ assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))),
+ tmpdir.join("foo"));
+ }
+
+ #[test]
+ fn readlink_not_symlink() {
+ let tmpdir = tmpdir();
+ match fs::read_link(tmpdir.path()) {
+ Ok(..) => panic!("wanted a failure"),
+ Err(..) => {}
+ }
+ }
+
+ #[test]
+ fn links_work() {
+ let tmpdir = tmpdir();
+ let input = tmpdir.join("in.txt");
+ let out = tmpdir.join("out.txt");
+
+ check!(check!(File::create(&input)).write("foobar".as_bytes()));
+ check!(fs::hard_link(&input, &out));
+ assert_eq!(check!(fs::metadata(&out)).len(),
+ check!(fs::metadata(&input)).len());
+ assert_eq!(check!(fs::metadata(&out)).len(),
+ check!(input.metadata()).len());
+ let mut v = Vec::new();
+ check!(check!(File::open(&out)).read_to_end(&mut v));
+ assert_eq!(v, b"foobar".to_vec());
+
+ // can't link to yourself
+ match fs::hard_link(&input, &input) {
+ Ok(..) => panic!("wanted a failure"),
+ Err(..) => {}
+ }
+ // can't link to something that doesn't exist
+ match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) {
+ Ok(..) => panic!("wanted a failure"),
+ Err(..) => {}
+ }
+ }
+
+ #[test]
+ fn chmod_works() {
+ let tmpdir = tmpdir();
+ let file = tmpdir.join("in.txt");
+
+ check!(File::create(&file));
+ let attr = check!(fs::metadata(&file));
+ assert!(!attr.permissions().readonly());
+ let mut p = attr.permissions();
+ p.set_readonly(true);
+ check!(fs::set_permissions(&file, p.clone()));
+ let attr = check!(fs::metadata(&file));
+ assert!(attr.permissions().readonly());
+
+ match fs::set_permissions(&tmpdir.join("foo"), p.clone()) {
+ Ok(..) => panic!("wanted an error"),
+ Err(..) => {}
+ }
+
+ p.set_readonly(false);
+ check!(fs::set_permissions(&file, p));
+ }
+
+ #[test]
+ fn sync_doesnt_kill_anything() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("in.txt");
+
+ let mut file = check!(File::create(&path));
+ check!(file.sync_all());
+ check!(file.sync_data());
+ check!(file.write(b"foo"));
+ check!(file.sync_all());
+ check!(file.sync_data());
+ }
+
+ #[test]
+ fn truncate_works() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("in.txt");
+
+ let mut file = check!(File::create(&path));
+ check!(file.write(b"foo"));
+ check!(file.sync_all());
+
+ // Do some simple things with truncation
+ assert_eq!(check!(file.metadata()).len(), 3);
+ check!(file.set_len(10));
+ assert_eq!(check!(file.metadata()).len(), 10);
+ check!(file.write(b"bar"));
+ check!(file.sync_all());
+ assert_eq!(check!(file.metadata()).len(), 10);
+
+ let mut v = Vec::new();
+ check!(check!(File::open(&path)).read_to_end(&mut v));
+ assert_eq!(v, b"foobar\0\0\0\0".to_vec());
+
+ // Truncate to a smaller length, don't seek, and then write something.
+ // Ensure that the intermediate zeroes are all filled in (we have `seek`ed
+ // past the end of the file).
+ check!(file.set_len(2));
+ assert_eq!(check!(file.metadata()).len(), 2);
+ check!(file.write(b"wut"));
+ check!(file.sync_all());
+ assert_eq!(check!(file.metadata()).len(), 9);
+ let mut v = Vec::new();
+ check!(check!(File::open(&path)).read_to_end(&mut v));
+ assert_eq!(v, b"fo\0\0\0\0wut".to_vec());
+ }
+
+ #[test]
+ fn open_flavors() {
+ use fs::OpenOptions as OO;
+ fn c<T: Clone>(t: &T) -> T { t.clone() }
+
+ let tmpdir = tmpdir();
+
+ let mut r = OO::new(); r.read(true);
+ let mut w = OO::new(); w.write(true);
+ let mut rw = OO::new(); rw.write(true).read(true);
+
+ match r.open(&tmpdir.join("a")) {
+ Ok(..) => panic!(), Err(..) => {}
+ }
+
+ // Perform each one twice to make sure that it succeeds the second time
+ // (where the file exists)
+ check!(c(&w).create(true).open(&tmpdir.join("b")));
+ assert!(tmpdir.join("b").exists());
+ check!(c(&w).create(true).open(&tmpdir.join("b")));
+ check!(w.open(&tmpdir.join("b")));
+
+ check!(c(&rw).create(true).open(&tmpdir.join("c")));
+ assert!(tmpdir.join("c").exists());
+ check!(c(&rw).create(true).open(&tmpdir.join("c")));
+ check!(rw.open(&tmpdir.join("c")));
+
+ check!(c(&w).append(true).create(true).open(&tmpdir.join("d")));
+ assert!(tmpdir.join("d").exists());
+ check!(c(&w).append(true).create(true).open(&tmpdir.join("d")));
+ check!(c(&w).append(true).open(&tmpdir.join("d")));
+
+ check!(c(&rw).append(true).create(true).open(&tmpdir.join("e")));
+ assert!(tmpdir.join("e").exists());
+ check!(c(&rw).append(true).create(true).open(&tmpdir.join("e")));
+ check!(c(&rw).append(true).open(&tmpdir.join("e")));
+
+ check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f")));
+ assert!(tmpdir.join("f").exists());
+ check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f")));
+ check!(c(&w).truncate(true).open(&tmpdir.join("f")));
+
+ check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g")));
+ assert!(tmpdir.join("g").exists());
+ check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g")));
+ check!(c(&rw).truncate(true).open(&tmpdir.join("g")));
+
+ check!(check!(File::create(&tmpdir.join("h"))).write("foo".as_bytes()));
+ check!(r.open(&tmpdir.join("h")));
+ {
+ let mut f = check!(r.open(&tmpdir.join("h")));
+ assert!(f.write("wut".as_bytes()).is_err());
+ }
+ assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
+ {
+ let mut f = check!(c(&w).append(true).open(&tmpdir.join("h")));
+ check!(f.write("bar".as_bytes()));
+ }
+ assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6);
+ {
+ let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h")));
+ check!(f.write("bar".as_bytes()));
+ }
+ assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
+ }
+
+ #[test]
+ fn utime() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("a");
+ check!(File::create(&path));
+ // These numbers have to be bigger than the time in the day to account
+ // for timezones Windows in particular will fail in certain timezones
+ // with small enough values
+ check!(fs::set_file_times(&path, 100000, 200000));
+ assert_eq!(check!(path.metadata()).accessed(), 100000);
+ assert_eq!(check!(path.metadata()).modified(), 200000);
+ }
+
+ #[test]
+ fn utime_noexist() {
+ let tmpdir = tmpdir();
+
+ match fs::set_file_times(&tmpdir.join("a"), 100, 200) {
+ Ok(..) => panic!(),
+ Err(..) => {}
+ }
+ }
+
+ #[test]
+ fn binary_file() {
+ let mut bytes = [0; 1024];
+ StdRng::new().unwrap().fill_bytes(&mut bytes);
+
+ let tmpdir = tmpdir();
+
+ check!(check!(File::create(&tmpdir.join("test"))).write(&bytes));
+ let mut v = Vec::new();
+ check!(check!(File::open(&tmpdir.join("test"))).read_to_end(&mut v));
+ assert!(v == &bytes[..]);
+ }
+
+ #[test]
+ #[cfg(not(windows))]
+ fn unlink_readonly() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("file");
+ check!(File::create(&path));
+ let mut perm = check!(fs::metadata(&path)).permissions();
+ perm.set_readonly(true);
+ check!(fs::set_permissions(&path, perm));
+ check!(fs::remove_file(&path));
+ }
+
+ #[test]
+ fn mkdir_trailing_slash() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("file");
+ check!(fs::create_dir_all(&path.join("a/")));
+ }
+}
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Filesystem manipulation operations
-//!
-//! This module contains basic methods to manipulate the contents of the local
-//! filesystem. All methods in this module represent cross-platform filesystem
-//! operations. Extra platform-specific functionality can be found in the
-//! extension traits of `std::os::$platform`.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use core::prelude::*;
-
-use io::{self, Error, ErrorKind, SeekFrom, Seek, Read, Write};
-use path::{Path, PathBuf};
-use sys::fs2 as fs_imp;
-use sys_common::{AsInnerMut, FromInner, AsInner};
-use vec::Vec;
-
-#[allow(deprecated)]
-pub use self::tempdir::TempDir;
-
-mod tempdir;
-
-/// A reference to an open file on the filesystem.
-///
-/// An instance of a `File` can be read and/or written depending on what options
-/// it was opened with. Files also implement `Seek` to alter the logical cursor
-/// that the file contains internally.
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::io::prelude::*;
-/// use std::fs::File;
-///
-/// # fn foo() -> std::io::Result<()> {
-/// let mut f = try!(File::create("foo.txt"));
-/// try!(f.write_all(b"Hello, world!"));
-///
-/// let mut f = try!(File::open("foo.txt"));
-/// let mut s = String::new();
-/// try!(f.read_to_string(&mut s));
-/// assert_eq!(s, "Hello, world!");
-/// # Ok(())
-/// # }
-/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct File {
- inner: fs_imp::File,
- path: PathBuf,
-}
-
-/// Metadata information about a file.
-///
-/// This structure is returned from the `metadata` function or method and
-/// represents known metadata about a file such as its permissions, size,
-/// modification times, etc.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Metadata(fs_imp::FileAttr);
-
-/// Iterator over the entries in a directory.
-///
-/// This iterator is returned from the `read_dir` function of this module and
-/// will yield instances of `io::Result<DirEntry>`. Through a `DirEntry`
-/// information like the entry's path and possibly other metadata can be
-/// learned.
-///
-/// # Failure
-///
-/// This `io::Result` will be an `Err` if there's some sort of intermittent
-/// IO error during iteration.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct ReadDir(fs_imp::ReadDir);
-
-/// Entries returned by the `ReadDir` iterator.
-///
-/// An instance of `DirEntry` represents an entry inside of a directory on the
-/// filesystem. Each entry can be inspected via methods to learn about the full
-/// path or possibly other metadata through per-platform extension traits.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct DirEntry(fs_imp::DirEntry);
-
-/// An iterator that recursively walks over the contents of a directory.
-#[unstable(feature = "fs_walk",
- reason = "the precise semantics and defaults for a recursive walk \
- may change and this may end up accounting for files such \
- as symlinks differently")]
-pub struct WalkDir {
- cur: Option<ReadDir>,
- stack: Vec<io::Result<ReadDir>>,
-}
-
-/// Options and flags which can be used to configure how a file is opened.
-///
-/// This builder exposes the ability to configure how a `File` is opened and
-/// what operations are permitted on the open file. The `File::open` and
-/// `File::create` methods are aliases for commonly used options using this
-/// builder.
-#[derive(Clone)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct OpenOptions(fs_imp::OpenOptions);
-
-/// Representation of the various permissions on a file.
-///
-/// This module only currently provides one bit of information, `readonly`,
-/// which is exposed on all currently supported platforms. Unix-specific
-/// functionality, such as mode bits, is available through the
-/// `os::unix::PermissionsExt` trait.
-#[derive(Clone, PartialEq, Eq, Debug)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Permissions(fs_imp::FilePermissions);
-
-impl File {
- /// Attempts to open a file in read-only mode.
- ///
- /// See the `OpenOptions::open` method for more details.
- ///
- /// # Errors
- ///
- /// This function will return an error if `path` does not already exist.
- /// Other errors may also be returned according to `OpenOptions::open`.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::fs::File;
- ///
- /// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::open("foo.txt"));
- /// # Ok(())
- /// # }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
- OpenOptions::new().read(true).open(path)
- }
-
- /// Open a file in write-only mode.
- ///
- /// This function will create a file if it does not exist,
- /// and will truncate it if it does.
- ///
- /// See the `OpenOptions::open` function for more details.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::fs::File;
- ///
- /// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::create("foo.txt"));
- /// # Ok(())
- /// # }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
- OpenOptions::new().write(true).create(true).truncate(true).open(path)
- }
-
- /// Returns the original path that was used to open this file.
- #[unstable(feature = "file_path",
- reason = "this abstraction is imposed by this library instead \
- of the underlying OS and may be removed")]
- pub fn path(&self) -> Option<&Path> {
- Some(&self.path)
- }
-
- /// Attempt to sync all OS-internal metadata to disk.
- ///
- /// This function will attempt to ensure that all in-core data reaches the
- /// filesystem before returning.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::fs::File;
- /// use std::io::prelude::*;
- ///
- /// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::create("foo.txt"));
- /// try!(f.write_all(b"Hello, world!"));
- ///
- /// try!(f.sync_all());
- /// # Ok(())
- /// # }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn sync_all(&self) -> io::Result<()> {
- self.inner.fsync()
- }
-
- /// This function is similar to `sync_all`, except that it may not
- /// synchronize file metadata to the filesystem.
- ///
- /// This is intended for use cases that must synchronize content, but don't
- /// need the metadata on disk. The goal of this method is to reduce disk
- /// operations.
- ///
- /// Note that some platforms may simply implement this in terms of
- /// `sync_all`.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::fs::File;
- /// use std::io::prelude::*;
- ///
- /// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::create("foo.txt"));
- /// try!(f.write_all(b"Hello, world!"));
- ///
- /// try!(f.sync_data());
- /// # Ok(())
- /// # }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn sync_data(&self) -> io::Result<()> {
- self.inner.datasync()
- }
-
- /// Truncates or extends the underlying file, updating the size of
- /// this file to become `size`.
- ///
- /// If the `size` is less than the current file's size, then the file will
- /// be shrunk. If it is greater than the current file's size, then the file
- /// will be extended to `size` and have all of the intermediate data filled
- /// in with 0s.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::fs::File;
- ///
- /// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::open("foo.txt"));
- /// try!(f.set_len(0));
- /// # Ok(())
- /// # }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn set_len(&self, size: u64) -> io::Result<()> {
- self.inner.truncate(size)
- }
-
- /// Queries metadata about the underlying file.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::fs::File;
- ///
- /// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::open("foo.txt"));
- /// let metadata = try!(f.metadata());
- /// # Ok(())
- /// # }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn metadata(&self) -> io::Result<Metadata> {
- self.inner.file_attr().map(Metadata)
- }
-}
-
-impl AsInner<fs_imp::File> for File {
- fn as_inner(&self) -> &fs_imp::File { &self.inner }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Read for File {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- self.inner.read(buf)
- }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Write for File {
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- self.inner.write(buf)
- }
- fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Seek for File {
- fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
- self.inner.seek(pos)
- }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> Read for &'a File {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- self.inner.read(buf)
- }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> Write for &'a File {
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- self.inner.write(buf)
- }
- fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> Seek for &'a File {
- fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
- self.inner.seek(pos)
- }
-}
-
-impl OpenOptions {
- /// Creates a blank net set of options ready for configuration.
- ///
- /// All options are initially set to `false`.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn new() -> OpenOptions {
- OpenOptions(fs_imp::OpenOptions::new())
- }
-
- /// Set the option for read access.
- ///
- /// This option, when true, will indicate that the file should be
- /// `read`-able if opened.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn read(&mut self, read: bool) -> &mut OpenOptions {
- self.0.read(read); self
- }
-
- /// Set the option for write access.
- ///
- /// This option, when true, will indicate that the file should be
- /// `write`-able if opened.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn write(&mut self, write: bool) -> &mut OpenOptions {
- self.0.write(write); self
- }
-
- /// Set the option for the append mode.
- ///
- /// This option, when true, means that writes will append to a file instead
- /// of overwriting previous contents.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn append(&mut self, append: bool) -> &mut OpenOptions {
- self.0.append(append); self
- }
-
- /// Set the option for truncating a previous file.
- ///
- /// If a file is successfully opened with this option set it will truncate
- /// the file to 0 length if it already exists.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
- self.0.truncate(truncate); self
- }
-
- /// Set the option for creating a new file.
- ///
- /// This option indicates whether a new file will be created if the file
- /// does not yet already exist.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn create(&mut self, create: bool) -> &mut OpenOptions {
- self.0.create(create); self
- }
-
- /// Open a file at `path` with the options specified by `self`.
- ///
- /// # Errors
- ///
- /// This function will return an error under a number of different
- /// circumstances, to include but not limited to:
- ///
- /// * Opening a file that does not exist with read access.
- /// * Attempting to open a file with access that the user lacks
- /// permissions for
- /// * Filesystem-level errors (full disk, etc)
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
- let path = path.as_ref();
- let inner = try!(fs_imp::File::open(path, &self.0));
- Ok(File { path: path.to_path_buf(), inner: inner })
- }
-}
-
-impl AsInnerMut<fs_imp::OpenOptions> for OpenOptions {
- fn as_inner_mut(&mut self) -> &mut fs_imp::OpenOptions { &mut self.0 }
-}
-
-impl Metadata {
- /// Returns whether this metadata is for a directory.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn is_dir(&self) -> bool { self.0.is_dir() }
-
- /// Returns whether this metadata is for a regular file.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn is_file(&self) -> bool { self.0.is_file() }
-
- /// Returns the size of the file, in bytes, this metadata is for.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn len(&self) -> u64 { self.0.size() }
-
- /// Returns the permissions of the file this metadata is for.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn permissions(&self) -> Permissions {
- Permissions(self.0.perm())
- }
-
- /// Returns the most recent access time for a file.
- ///
- /// The return value is in milliseconds since the epoch.
- #[unstable(feature = "fs_time",
- reason = "the return type of u64 is not quite appropriate for \
- this method and may change if the standard library \
- gains a type to represent a moment in time")]
- pub fn accessed(&self) -> u64 { self.0.accessed() }
-
- /// Returns the most recent modification time for a file.
- ///
- /// The return value is in milliseconds since the epoch.
- #[unstable(feature = "fs_time",
- reason = "the return type of u64 is not quite appropriate for \
- this method and may change if the standard library \
- gains a type to represent a moment in time")]
- pub fn modified(&self) -> u64 { self.0.modified() }
-}
-
-impl Permissions {
- /// Returns whether these permissions describe a readonly file.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn readonly(&self) -> bool { self.0.readonly() }
-
- /// Modify the readonly flag for this set of permissions.
- ///
- /// This operation does **not** modify the filesystem. To modify the
- /// filesystem use the `fs::set_permissions` function.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn set_readonly(&mut self, readonly: bool) {
- self.0.set_readonly(readonly)
- }
-}
-
-impl FromInner<fs_imp::FilePermissions> for Permissions {
- fn from_inner(f: fs_imp::FilePermissions) -> Permissions {
- Permissions(f)
- }
-}
-
-impl AsInner<fs_imp::FilePermissions> for Permissions {
- fn as_inner(&self) -> &fs_imp::FilePermissions { &self.0 }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Iterator for ReadDir {
- type Item = io::Result<DirEntry>;
-
- fn next(&mut self) -> Option<io::Result<DirEntry>> {
- self.0.next().map(|entry| entry.map(DirEntry))
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl DirEntry {
- /// Returns the full path to the file that this entry represents.
- ///
- /// The full path is created by joining the original path to `read_dir` or
- /// `walk_dir` with the filename of this entry.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn path(&self) -> PathBuf { self.0.path() }
-}
-
-/// Remove a file from the underlying filesystem.
-///
-/// # Examples
-///
-/// ```rust,no_run
-/// use std::fs;
-///
-/// fs::remove_file("/some/file/path.txt");
-/// ```
-///
-/// Note that, just because an unlink call was successful, it is not
-/// guaranteed that a file is immediately deleted (e.g. depending on
-/// platform, other open file descriptors may prevent immediate removal).
-///
-/// # Errors
-///
-/// This function will return an error if `path` points to a directory, if the
-/// user lacks permissions to remove the file, or if some other filesystem-level
-/// error occurs.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
- fs_imp::unlink(path.as_ref())
-}
-
-/// Given a path, query the file system to get information about a file,
-/// directory, etc.
-///
-/// This function will traverse soft links to query information about the
-/// destination file.
-///
-/// # Examples
-///
-/// ```rust,no_run
-/// # fn foo() -> std::io::Result<()> {
-/// use std::fs;
-///
-/// let attr = try!(fs::metadata("/some/file/path.txt"));
-/// // inspect attr ...
-/// # Ok(())
-/// # }
-/// ```
-///
-/// # Errors
-///
-/// This function will return an error if the user lacks the requisite
-/// permissions to perform a `metadata` call on the given `path` or if there
-/// is no entry in the filesystem at the provided path.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
- fs_imp::stat(path.as_ref()).map(Metadata)
-}
-
-/// Rename a file or directory to a new name.
-///
-/// # Examples
-///
-/// ```rust,no_run
-/// use std::fs;
-///
-/// fs::rename("foo", "bar");
-/// ```
-///
-/// # Errors
-///
-/// This function will return an error if the provided `from` doesn't exist, if
-/// the process lacks permissions to view the contents, if `from` and `to`
-/// reside on separate filesystems, or if some other intermittent I/O error
-/// occurs.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
- fs_imp::rename(from.as_ref(), to.as_ref())
-}
-
-/// Copies the contents of one file to another. This function will also
-/// copy the permission bits of the original file to the destination file.
-///
-/// This function will **overwrite** the contents of `to`.
-///
-/// Note that if `from` and `to` both point to the same file, then the file
-/// will likely get truncated by this operation.
-///
-/// # Examples
-///
-/// ```
-/// use std::fs;
-///
-/// fs::copy("foo.txt", "bar.txt");
-/// ```
-///
-/// # Errors
-///
-/// This function will return an error in the following situations, but is not
-/// limited to just these cases:
-///
-/// * The `from` path is not a file
-/// * The `from` file does not exist
-/// * The current process does not have the permission rights to access
-/// `from` or write `to`
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
- let from = from.as_ref();
- let to = to.as_ref();
- if !from.is_file() {
- return Err(Error::new(ErrorKind::InvalidInput,
- "the source path is not an existing file",
- None))
- }
-
- let mut reader = try!(File::open(from));
- let mut writer = try!(File::create(to));
- let perm = try!(reader.metadata()).permissions();
-
- let ret = try!(io::copy(&mut reader, &mut writer));
- try!(set_permissions(to, perm));
- Ok(ret)
-}
-
-/// Creates a new hard link on the filesystem.
-///
-/// The `dst` path will be a link pointing to the `src` path. Note that systems
-/// often require these two paths to both be located on the same filesystem.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
- fs_imp::link(src.as_ref(), dst.as_ref())
-}
-
-/// Creates a new soft link on the filesystem.
-///
-/// The `dst` path will be a soft link pointing to the `src` path.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
- fs_imp::symlink(src.as_ref(), dst.as_ref())
-}
-
-/// Reads a soft link, returning the file that the link points to.
-///
-/// # Errors
-///
-/// This function will return an error on failure. Failure conditions include
-/// reading a file that does not exist or reading a file that is not a soft
-/// link.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
- fs_imp::readlink(path.as_ref())
-}
-
-/// Create a new, empty directory at the provided path
-///
-/// # Examples
-///
-/// ```
-/// use std::fs;
-///
-/// fs::create_dir("/some/dir");
-/// ```
-///
-/// # Errors
-///
-/// This function will return an error if the user lacks permissions to make a
-/// new directory at the provided `path`, or if the directory already exists.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
- fs_imp::mkdir(path.as_ref())
-}
-
-/// Recursively create a directory and all of its parent components if they
-/// are missing.
-///
-/// # Errors
-///
-/// This function will fail if any directory in the path specified by `path`
-/// does not already exist and it could not be created otherwise. The specific
-/// error conditions for when a directory is being created (after it is
-/// determined to not exist) are outlined by `fs::create_dir`.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
- let path = path.as_ref();
- if path == Path::new("") || path.is_dir() { return Ok(()) }
- if let Some(p) = path.parent() { try!(create_dir_all(p)) }
- create_dir(path)
-}
-
-/// Remove an existing, empty directory
-///
-/// # Examples
-///
-/// ```
-/// use std::fs;
-///
-/// fs::remove_dir("/some/dir");
-/// ```
-///
-/// # Errors
-///
-/// This function will return an error if the user lacks permissions to remove
-/// the directory at the provided `path`, or if the directory isn't empty.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
- fs_imp::rmdir(path.as_ref())
-}
-
-/// Removes a directory at this path, after removing all its contents. Use
-/// carefully!
-///
-/// This function does **not** follow soft links and it will simply remove the
-/// soft link itself.
-///
-/// # Errors
-///
-/// See `file::remove_file` and `fs::remove_dir`
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
- let path = path.as_ref();
- for child in try!(read_dir(path)) {
- let child = try!(child).path();
- let stat = try!(lstat(&*child));
- if stat.is_dir() {
- try!(remove_dir_all(&*child));
- } else {
- try!(remove_file(&*child));
- }
- }
- return remove_dir(path);
-
- #[cfg(unix)]
- fn lstat(path: &Path) -> io::Result<fs_imp::FileAttr> { fs_imp::lstat(path) }
- #[cfg(windows)]
- fn lstat(path: &Path) -> io::Result<fs_imp::FileAttr> { fs_imp::stat(path) }
-}
-
-/// Returns an iterator over the entries within a directory.
-///
-/// The iterator will yield instances of `io::Result<DirEntry>`. New errors may
-/// be encountered after an iterator is initially constructed.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(path_ext)]
-/// use std::io;
-/// use std::fs::{self, PathExt, DirEntry};
-/// use std::path::Path;
-///
-/// // one possible implementation of fs::walk_dir only visiting files
-/// fn visit_dirs(dir: &Path, cb: &mut FnMut(DirEntry)) -> io::Result<()> {
-/// if dir.is_dir() {
-/// for entry in try!(fs::read_dir(dir)) {
-/// let entry = try!(entry);
-/// if entry.path().is_dir() {
-/// try!(visit_dirs(&entry.path(), cb));
-/// } else {
-/// cb(entry);
-/// }
-/// }
-/// }
-/// Ok(())
-/// }
-/// ```
-///
-/// # Errors
-///
-/// This function will return an error if the provided `path` doesn't exist, if
-/// the process lacks permissions to view the contents or if the `path` points
-/// at a non-directory file
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
- fs_imp::readdir(path.as_ref()).map(ReadDir)
-}
-
-/// Returns an iterator that will recursively walk the directory structure
-/// rooted at `path`.
-///
-/// The path given will not be iterated over, and this will perform iteration in
-/// some top-down order. The contents of unreadable subdirectories are ignored.
-///
-/// The iterator will yield instances of `io::Result<DirEntry>`. New errors may
-/// be encountered after an iterator is initially constructed.
-#[unstable(feature = "fs_walk",
- reason = "the precise semantics and defaults for a recursive walk \
- may change and this may end up accounting for files such \
- as symlinks differently")]
-pub fn walk_dir<P: AsRef<Path>>(path: P) -> io::Result<WalkDir> {
- let start = try!(read_dir(path));
- Ok(WalkDir { cur: Some(start), stack: Vec::new() })
-}
-
-#[unstable(feature = "fs_walk")]
-impl Iterator for WalkDir {
- type Item = io::Result<DirEntry>;
-
- fn next(&mut self) -> Option<io::Result<DirEntry>> {
- loop {
- if let Some(ref mut cur) = self.cur {
- match cur.next() {
- Some(Err(e)) => return Some(Err(e)),
- Some(Ok(next)) => {
- let path = next.path();
- if path.is_dir() {
- self.stack.push(read_dir(&*path));
- }
- return Some(Ok(next))
- }
- None => {}
- }
- }
- self.cur = None;
- match self.stack.pop() {
- Some(Err(e)) => return Some(Err(e)),
- Some(Ok(next)) => self.cur = Some(next),
- None => return None,
- }
- }
- }
-}
-
-/// Utility methods for paths.
-#[unstable(feature = "path_ext",
- reason = "the precise set of methods exposed on this trait may \
- change and some methods may be removed")]
-pub trait PathExt {
- /// Get information on the file, directory, etc at this path.
- ///
- /// Consult the `fs::stat` documentation for more info.
- ///
- /// This call preserves identical runtime/error semantics with `file::stat`.
- fn metadata(&self) -> io::Result<Metadata>;
-
- /// Boolean value indicator whether the underlying file exists on the local
- /// filesystem. Returns false in exactly the cases where `fs::stat` fails.
- fn exists(&self) -> bool;
-
- /// Whether the underlying implementation (be it a file path, or something
- /// else) points at a "regular file" on the FS. Will return false for paths
- /// to non-existent locations or directories or other non-regular files
- /// (named pipes, etc). Follows links when making this determination.
- fn is_file(&self) -> bool;
-
- /// Whether the underlying implementation (be it a file path, or something
- /// else) is pointing at a directory in the underlying FS. Will return
- /// false for paths to non-existent locations or if the item is not a
- /// directory (eg files, named pipes, etc). Follows links when making this
- /// determination.
- fn is_dir(&self) -> bool;
-}
-
-impl PathExt for Path {
- fn metadata(&self) -> io::Result<Metadata> { metadata(self) }
-
- fn exists(&self) -> bool { metadata(self).is_ok() }
-
- fn is_file(&self) -> bool {
- metadata(self).map(|s| s.is_file()).unwrap_or(false)
- }
- fn is_dir(&self) -> bool {
- metadata(self).map(|s| s.is_dir()).unwrap_or(false)
- }
-}
-
-/// Changes the timestamps for a file's last modification and access time.
-///
-/// The file at the path specified will have its last access time set to
-/// `atime` and its modification time set to `mtime`. The times specified should
-/// be in milliseconds.
-#[unstable(feature = "fs_time",
- reason = "the argument type of u64 is not quite appropriate for \
- this function and may change if the standard library \
- gains a type to represent a moment in time")]
-pub fn set_file_times<P: AsRef<Path>>(path: P, accessed: u64,
- modified: u64) -> io::Result<()> {
- fs_imp::utimes(path.as_ref(), accessed, modified)
-}
-
-/// Changes the permissions found on a file or a directory.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(fs)]
-/// # fn foo() -> std::io::Result<()> {
-/// use std::fs;
-///
-/// let mut perms = try!(fs::metadata("foo.txt")).permissions();
-/// perms.set_readonly(true);
-/// try!(fs::set_permissions("foo.txt", perms));
-/// # Ok(())
-/// # }
-/// ```
-///
-/// # Errors
-///
-/// This function will return an error if the provided `path` doesn't exist, if
-/// the process lacks permissions to change the attributes of the file, or if
-/// some other I/O error is encountered.
-#[unstable(feature = "fs",
- reason = "a more granual ability to set specific permissions may \
- be exposed on the Permissions structure itself and this \
- method may not always exist")]
-pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
- fs_imp::set_perm(path.as_ref(), perm.0)
-}
-
-#[cfg(test)]
-mod tests {
- #![allow(deprecated)] //rand
-
- use prelude::v1::*;
- use io::prelude::*;
-
- use env;
- use fs::{self, File, OpenOptions};
- use io::{ErrorKind, SeekFrom};
- use path::PathBuf;
- use path::Path as Path2;
- use os;
- use rand::{self, StdRng, Rng};
- use str;
-
- macro_rules! check { ($e:expr) => (
- match $e {
- Ok(t) => t,
- Err(e) => panic!("{} failed with: {}", stringify!($e), e),
- }
- ) }
-
- macro_rules! error { ($e:expr, $s:expr) => (
- match $e {
- Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
- Err(ref err) => assert!(err.to_string().contains($s),
- format!("`{}` did not contain `{}`", err, $s))
- }
- ) }
-
- pub struct TempDir(PathBuf);
-
- impl TempDir {
- fn join(&self, path: &str) -> PathBuf {
- let TempDir(ref p) = *self;
- p.join(path)
- }
-
- fn path<'a>(&'a self) -> &'a Path2 {
- let TempDir(ref p) = *self;
- p
- }
- }
-
- impl Drop for TempDir {
- fn drop(&mut self) {
- // Gee, seeing how we're testing the fs module I sure hope that we
- // at least implement this correctly!
- let TempDir(ref p) = *self;
- check!(fs::remove_dir_all(p));
- }
- }
-
- pub fn tmpdir() -> TempDir {
- let p = env::temp_dir();
- let ret = p.join(&format!("rust-{}", rand::random::<u32>()));
- check!(fs::create_dir(&ret));
- TempDir(ret)
- }
-
- #[test]
- fn file_test_io_smoke_test() {
- let message = "it's alright. have a good time";
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_rt_io_file_test.txt");
- {
- let mut write_stream = check!(File::create(filename));
- check!(write_stream.write(message.as_bytes()));
- }
- {
- let mut read_stream = check!(File::open(filename));
- let mut read_buf = [0; 1028];
- let read_str = match check!(read_stream.read(&mut read_buf)) {
- -1|0 => panic!("shouldn't happen"),
- n => str::from_utf8(&read_buf[..n]).unwrap().to_string()
- };
- assert_eq!(read_str, message);
- }
- check!(fs::remove_file(filename));
- }
-
- #[test]
- fn invalid_path_raises() {
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_that_does_not_exist.txt");
- let result = File::open(filename);
-
- if cfg!(unix) {
- error!(result, "o such file or directory");
- }
- // error!(result, "couldn't open path as file");
- // error!(result, format!("path={}; mode=open; access=read", filename.display()));
- }
-
- #[test]
- fn file_test_iounlinking_invalid_path_should_raise_condition() {
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt");
-
- let result = fs::remove_file(filename);
-
- if cfg!(unix) {
- error!(result, "o such file or directory");
- }
- // error!(result, "couldn't unlink path");
- // error!(result, format!("path={}", filename.display()));
- }
-
- #[test]
- fn file_test_io_non_positional_read() {
- let message: &str = "ten-four";
- let mut read_mem = [0; 8];
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_rt_io_file_test_positional.txt");
- {
- let mut rw_stream = check!(File::create(filename));
- check!(rw_stream.write(message.as_bytes()));
- }
- {
- let mut read_stream = check!(File::open(filename));
- {
- let read_buf = &mut read_mem[0..4];
- check!(read_stream.read(read_buf));
- }
- {
- let read_buf = &mut read_mem[4..8];
- check!(read_stream.read(read_buf));
- }
- }
- check!(fs::remove_file(filename));
- let read_str = str::from_utf8(&read_mem).unwrap();
- assert_eq!(read_str, message);
- }
-
- #[test]
- fn file_test_io_seek_and_tell_smoke_test() {
- let message = "ten-four";
- let mut read_mem = [0; 4];
- let set_cursor = 4 as u64;
- let mut tell_pos_pre_read;
- let mut tell_pos_post_read;
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt");
- {
- let mut rw_stream = check!(File::create(filename));
- check!(rw_stream.write(message.as_bytes()));
- }
- {
- let mut read_stream = check!(File::open(filename));
- check!(read_stream.seek(SeekFrom::Start(set_cursor)));
- tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0)));
- check!(read_stream.read(&mut read_mem));
- tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0)));
- }
- check!(fs::remove_file(filename));
- let read_str = str::from_utf8(&read_mem).unwrap();
- assert_eq!(read_str, &message[4..8]);
- assert_eq!(tell_pos_pre_read, set_cursor);
- assert_eq!(tell_pos_post_read, message.len() as u64);
- }
-
- #[test]
- fn file_test_io_seek_and_write() {
- let initial_msg = "food-is-yummy";
- let overwrite_msg = "-the-bar!!";
- let final_msg = "foo-the-bar!!";
- let seek_idx = 3;
- let mut read_mem = [0; 13];
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt");
- {
- let mut rw_stream = check!(File::create(filename));
- check!(rw_stream.write(initial_msg.as_bytes()));
- check!(rw_stream.seek(SeekFrom::Start(seek_idx)));
- check!(rw_stream.write(overwrite_msg.as_bytes()));
- }
- {
- let mut read_stream = check!(File::open(filename));
- check!(read_stream.read(&mut read_mem));
- }
- check!(fs::remove_file(filename));
- let read_str = str::from_utf8(&read_mem).unwrap();
- assert!(read_str == final_msg);
- }
-
- #[test]
- fn file_test_io_seek_shakedown() {
- // 01234567890123
- let initial_msg = "qwer-asdf-zxcv";
- let chunk_one: &str = "qwer";
- let chunk_two: &str = "asdf";
- let chunk_three: &str = "zxcv";
- let mut read_mem = [0; 4];
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt");
- {
- let mut rw_stream = check!(File::create(filename));
- check!(rw_stream.write(initial_msg.as_bytes()));
- }
- {
- let mut read_stream = check!(File::open(filename));
-
- check!(read_stream.seek(SeekFrom::End(-4)));
- check!(read_stream.read(&mut read_mem));
- assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three);
-
- check!(read_stream.seek(SeekFrom::Current(-9)));
- check!(read_stream.read(&mut read_mem));
- assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two);
-
- check!(read_stream.seek(SeekFrom::Start(0)));
- check!(read_stream.read(&mut read_mem));
- assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one);
- }
- check!(fs::remove_file(filename));
- }
-
- #[test]
- fn file_test_stat_is_correct_on_is_file() {
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_stat_correct_on_is_file.txt");
- {
- let mut opts = OpenOptions::new();
- let mut fs = check!(opts.read(true).write(true)
- .create(true).open(filename));
- let msg = "hw";
- fs.write(msg.as_bytes()).unwrap();
-
- let fstat_res = check!(fs.metadata());
- assert!(fstat_res.is_file());
- }
- let stat_res_fn = check!(fs::metadata(filename));
- assert!(stat_res_fn.is_file());
- let stat_res_meth = check!(filename.metadata());
- assert!(stat_res_meth.is_file());
- check!(fs::remove_file(filename));
- }
-
- #[test]
- fn file_test_stat_is_correct_on_is_dir() {
- let tmpdir = tmpdir();
- let filename = &tmpdir.join("file_stat_correct_on_is_dir");
- check!(fs::create_dir(filename));
- let stat_res_fn = check!(fs::metadata(filename));
- assert!(stat_res_fn.is_dir());
- let stat_res_meth = check!(filename.metadata());
- assert!(stat_res_meth.is_dir());
- check!(fs::remove_dir(filename));
- }
-
- #[test]
- fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
- let tmpdir = tmpdir();
- let dir = &tmpdir.join("fileinfo_false_on_dir");
- check!(fs::create_dir(dir));
- assert!(dir.is_file() == false);
- check!(fs::remove_dir(dir));
- }
-
- #[test]
- fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
- let tmpdir = tmpdir();
- let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt");
- check!(check!(File::create(file)).write(b"foo"));
- assert!(file.exists());
- check!(fs::remove_file(file));
- assert!(!file.exists());
- }
-
- #[test]
- fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
- let tmpdir = tmpdir();
- let dir = &tmpdir.join("before_and_after_dir");
- assert!(!dir.exists());
- check!(fs::create_dir(dir));
- assert!(dir.exists());
- assert!(dir.is_dir());
- check!(fs::remove_dir(dir));
- assert!(!dir.exists());
- }
-
- #[test]
- fn file_test_directoryinfo_readdir() {
- let tmpdir = tmpdir();
- let dir = &tmpdir.join("di_readdir");
- check!(fs::create_dir(dir));
- let prefix = "foo";
- for n in 0..3 {
- let f = dir.join(&format!("{}.txt", n));
- let mut w = check!(File::create(&f));
- let msg_str = format!("{}{}", prefix, n.to_string());
- let msg = msg_str.as_bytes();
- check!(w.write(msg));
- }
- let files = check!(fs::read_dir(dir));
- let mut mem = [0; 4];
- for f in files {
- let f = f.unwrap().path();
- {
- let n = f.file_stem().unwrap();
- check!(check!(File::open(&f)).read(&mut mem));
- let read_str = str::from_utf8(&mem).unwrap();
- let expected = format!("{}{}", prefix, n.to_str().unwrap());
- assert_eq!(expected, read_str);
- }
- check!(fs::remove_file(&f));
- }
- check!(fs::remove_dir(dir));
- }
-
- #[test]
- fn file_test_walk_dir() {
- let tmpdir = tmpdir();
- let dir = &tmpdir.join("walk_dir");
- check!(fs::create_dir(dir));
-
- let dir1 = &dir.join("01/02/03");
- check!(fs::create_dir_all(dir1));
- check!(File::create(&dir1.join("04")));
-
- let dir2 = &dir.join("11/12/13");
- check!(fs::create_dir_all(dir2));
- check!(File::create(&dir2.join("14")));
-
- let files = check!(fs::walk_dir(dir));
- let mut cur = [0; 2];
- for f in files {
- let f = f.unwrap().path();
- let stem = f.file_stem().unwrap().to_str().unwrap();
- let root = stem.as_bytes()[0] - b'0';
- let name = stem.as_bytes()[1] - b'0';
- assert!(cur[root as usize] < name);
- cur[root as usize] = name;
- }
-
- check!(fs::remove_dir_all(dir));
- }
-
- #[test]
- fn mkdir_path_already_exists_error() {
- let tmpdir = tmpdir();
- let dir = &tmpdir.join("mkdir_error_twice");
- check!(fs::create_dir(dir));
- let e = fs::create_dir(dir).err().unwrap();
- assert_eq!(e.kind(), ErrorKind::AlreadyExists);
- }
-
- #[test]
- fn recursive_mkdir() {
- let tmpdir = tmpdir();
- let dir = tmpdir.join("d1/d2");
- check!(fs::create_dir_all(&dir));
- assert!(dir.is_dir())
- }
-
- #[test]
- fn recursive_mkdir_failure() {
- let tmpdir = tmpdir();
- let dir = tmpdir.join("d1");
- let file = dir.join("f1");
-
- check!(fs::create_dir_all(&dir));
- check!(File::create(&file));
-
- let result = fs::create_dir_all(&file);
-
- assert!(result.is_err());
- // error!(result, "couldn't recursively mkdir");
- // error!(result, "couldn't create directory");
- // error!(result, "mode=0700");
- // error!(result, format!("path={}", file.display()));
- }
-
- #[test]
- fn recursive_mkdir_slash() {
- check!(fs::create_dir_all(&Path2::new("/")));
- }
-
- // FIXME(#12795) depends on lstat to work on windows
- #[cfg(not(windows))]
- #[test]
- fn recursive_rmdir() {
- let tmpdir = tmpdir();
- let d1 = tmpdir.join("d1");
- let dt = d1.join("t");
- let dtt = dt.join("t");
- let d2 = tmpdir.join("d2");
- let canary = d2.join("do_not_delete");
- check!(fs::create_dir_all(&dtt));
- check!(fs::create_dir_all(&d2));
- check!(check!(File::create(&canary)).write(b"foo"));
- check!(fs::soft_link(&d2, &dt.join("d2")));
- check!(fs::remove_dir_all(&d1));
-
- assert!(!d1.is_dir());
- assert!(canary.exists());
- }
-
- #[test]
- fn unicode_path_is_dir() {
- assert!(Path2::new(".").is_dir());
- assert!(!Path2::new("test/stdtest/fs.rs").is_dir());
-
- let tmpdir = tmpdir();
-
- let mut dirpath = tmpdir.path().to_path_buf();
- dirpath.push(&format!("test-가一ー你好"));
- check!(fs::create_dir(&dirpath));
- assert!(dirpath.is_dir());
-
- let mut filepath = dirpath;
- filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs");
- check!(File::create(&filepath)); // ignore return; touch only
- assert!(!filepath.is_dir());
- assert!(filepath.exists());
- }
-
- #[test]
- fn unicode_path_exists() {
- assert!(Path2::new(".").exists());
- assert!(!Path2::new("test/nonexistent-bogus-path").exists());
-
- let tmpdir = tmpdir();
- let unicode = tmpdir.path();
- let unicode = unicode.join(&format!("test-각丁ー再见"));
- check!(fs::create_dir(&unicode));
- assert!(unicode.exists());
- assert!(!Path2::new("test/unicode-bogus-path-각丁ー再见").exists());
- }
-
- #[test]
- fn copy_file_does_not_exist() {
- let from = Path2::new("test/nonexistent-bogus-path");
- let to = Path2::new("test/other-bogus-path");
-
- match fs::copy(&from, &to) {
- Ok(..) => panic!(),
- Err(..) => {
- assert!(!from.exists());
- assert!(!to.exists());
- }
- }
- }
-
- #[test]
- fn copy_file_ok() {
- let tmpdir = tmpdir();
- let input = tmpdir.join("in.txt");
- let out = tmpdir.join("out.txt");
-
- check!(check!(File::create(&input)).write(b"hello"));
- check!(fs::copy(&input, &out));
- let mut v = Vec::new();
- check!(check!(File::open(&out)).read_to_end(&mut v));
- assert_eq!(v.as_slice(), b"hello");
-
- assert_eq!(check!(input.metadata()).permissions(),
- check!(out.metadata()).permissions());
- }
-
- #[test]
- fn copy_file_dst_dir() {
- let tmpdir = tmpdir();
- let out = tmpdir.join("out");
-
- check!(File::create(&out));
- match fs::copy(&*out, tmpdir.path()) {
- Ok(..) => panic!(), Err(..) => {}
- }
- }
-
- #[test]
- fn copy_file_dst_exists() {
- let tmpdir = tmpdir();
- let input = tmpdir.join("in");
- let output = tmpdir.join("out");
-
- check!(check!(File::create(&input)).write("foo".as_bytes()));
- check!(check!(File::create(&output)).write("bar".as_bytes()));
- check!(fs::copy(&input, &output));
-
- let mut v = Vec::new();
- check!(check!(File::open(&output)).read_to_end(&mut v));
- assert_eq!(v, b"foo".to_vec());
- }
-
- #[test]
- fn copy_file_src_dir() {
- let tmpdir = tmpdir();
- let out = tmpdir.join("out");
-
- match fs::copy(tmpdir.path(), &out) {
- Ok(..) => panic!(), Err(..) => {}
- }
- assert!(!out.exists());
- }
-
- #[test]
- fn copy_file_preserves_perm_bits() {
- let tmpdir = tmpdir();
- let input = tmpdir.join("in.txt");
- let out = tmpdir.join("out.txt");
-
- let attr = check!(check!(File::create(&input)).metadata());
- let mut p = attr.permissions();
- p.set_readonly(true);
- check!(fs::set_permissions(&input, p));
- check!(fs::copy(&input, &out));
- assert!(check!(out.metadata()).permissions().readonly());
- check!(fs::set_permissions(&input, attr.permissions()));
- check!(fs::set_permissions(&out, attr.permissions()));
- }
-
- #[cfg(not(windows))] // FIXME(#10264) operation not permitted?
- #[test]
- fn symlinks_work() {
- let tmpdir = tmpdir();
- let input = tmpdir.join("in.txt");
- let out = tmpdir.join("out.txt");
-
- check!(check!(File::create(&input)).write("foobar".as_bytes()));
- check!(fs::soft_link(&input, &out));
- // if cfg!(not(windows)) {
- // assert_eq!(check!(lstat(&out)).kind, FileType::Symlink);
- // assert_eq!(check!(out.lstat()).kind, FileType::Symlink);
- // }
- assert_eq!(check!(fs::metadata(&out)).len(),
- check!(fs::metadata(&input)).len());
- let mut v = Vec::new();
- check!(check!(File::open(&out)).read_to_end(&mut v));
- assert_eq!(v, b"foobar".to_vec());
- }
-
- #[cfg(not(windows))] // apparently windows doesn't like symlinks
- #[test]
- fn symlink_noexist() {
- let tmpdir = tmpdir();
- // symlinks can point to things that don't exist
- check!(fs::soft_link(&tmpdir.join("foo"), &tmpdir.join("bar")));
- assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))),
- tmpdir.join("foo"));
- }
-
- #[test]
- fn readlink_not_symlink() {
- let tmpdir = tmpdir();
- match fs::read_link(tmpdir.path()) {
- Ok(..) => panic!("wanted a failure"),
- Err(..) => {}
- }
- }
-
- #[test]
- fn links_work() {
- let tmpdir = tmpdir();
- let input = tmpdir.join("in.txt");
- let out = tmpdir.join("out.txt");
-
- check!(check!(File::create(&input)).write("foobar".as_bytes()));
- check!(fs::hard_link(&input, &out));
- assert_eq!(check!(fs::metadata(&out)).len(),
- check!(fs::metadata(&input)).len());
- assert_eq!(check!(fs::metadata(&out)).len(),
- check!(input.metadata()).len());
- let mut v = Vec::new();
- check!(check!(File::open(&out)).read_to_end(&mut v));
- assert_eq!(v, b"foobar".to_vec());
-
- // can't link to yourself
- match fs::hard_link(&input, &input) {
- Ok(..) => panic!("wanted a failure"),
- Err(..) => {}
- }
- // can't link to something that doesn't exist
- match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) {
- Ok(..) => panic!("wanted a failure"),
- Err(..) => {}
- }
- }
-
- #[test]
- fn chmod_works() {
- let tmpdir = tmpdir();
- let file = tmpdir.join("in.txt");
-
- check!(File::create(&file));
- let attr = check!(fs::metadata(&file));
- assert!(!attr.permissions().readonly());
- let mut p = attr.permissions();
- p.set_readonly(true);
- check!(fs::set_permissions(&file, p.clone()));
- let attr = check!(fs::metadata(&file));
- assert!(attr.permissions().readonly());
-
- match fs::set_permissions(&tmpdir.join("foo"), p.clone()) {
- Ok(..) => panic!("wanted an error"),
- Err(..) => {}
- }
-
- p.set_readonly(false);
- check!(fs::set_permissions(&file, p));
- }
-
- #[test]
- fn sync_doesnt_kill_anything() {
- let tmpdir = tmpdir();
- let path = tmpdir.join("in.txt");
-
- let mut file = check!(File::create(&path));
- check!(file.sync_all());
- check!(file.sync_data());
- check!(file.write(b"foo"));
- check!(file.sync_all());
- check!(file.sync_data());
- }
-
- #[test]
- fn truncate_works() {
- let tmpdir = tmpdir();
- let path = tmpdir.join("in.txt");
-
- let mut file = check!(File::create(&path));
- check!(file.write(b"foo"));
- check!(file.sync_all());
-
- // Do some simple things with truncation
- assert_eq!(check!(file.metadata()).len(), 3);
- check!(file.set_len(10));
- assert_eq!(check!(file.metadata()).len(), 10);
- check!(file.write(b"bar"));
- check!(file.sync_all());
- assert_eq!(check!(file.metadata()).len(), 10);
-
- let mut v = Vec::new();
- check!(check!(File::open(&path)).read_to_end(&mut v));
- assert_eq!(v, b"foobar\0\0\0\0".to_vec());
-
- // Truncate to a smaller length, don't seek, and then write something.
- // Ensure that the intermediate zeroes are all filled in (we have `seek`ed
- // past the end of the file).
- check!(file.set_len(2));
- assert_eq!(check!(file.metadata()).len(), 2);
- check!(file.write(b"wut"));
- check!(file.sync_all());
- assert_eq!(check!(file.metadata()).len(), 9);
- let mut v = Vec::new();
- check!(check!(File::open(&path)).read_to_end(&mut v));
- assert_eq!(v, b"fo\0\0\0\0wut".to_vec());
- }
-
- #[test]
- fn open_flavors() {
- use fs::OpenOptions as OO;
- fn c<T: Clone>(t: &T) -> T { t.clone() }
-
- let tmpdir = tmpdir();
-
- let mut r = OO::new(); r.read(true);
- let mut w = OO::new(); w.write(true);
- let mut rw = OO::new(); rw.write(true).read(true);
-
- match r.open(&tmpdir.join("a")) {
- Ok(..) => panic!(), Err(..) => {}
- }
-
- // Perform each one twice to make sure that it succeeds the second time
- // (where the file exists)
- check!(c(&w).create(true).open(&tmpdir.join("b")));
- assert!(tmpdir.join("b").exists());
- check!(c(&w).create(true).open(&tmpdir.join("b")));
- check!(w.open(&tmpdir.join("b")));
-
- check!(c(&rw).create(true).open(&tmpdir.join("c")));
- assert!(tmpdir.join("c").exists());
- check!(c(&rw).create(true).open(&tmpdir.join("c")));
- check!(rw.open(&tmpdir.join("c")));
-
- check!(c(&w).append(true).create(true).open(&tmpdir.join("d")));
- assert!(tmpdir.join("d").exists());
- check!(c(&w).append(true).create(true).open(&tmpdir.join("d")));
- check!(c(&w).append(true).open(&tmpdir.join("d")));
-
- check!(c(&rw).append(true).create(true).open(&tmpdir.join("e")));
- assert!(tmpdir.join("e").exists());
- check!(c(&rw).append(true).create(true).open(&tmpdir.join("e")));
- check!(c(&rw).append(true).open(&tmpdir.join("e")));
-
- check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f")));
- assert!(tmpdir.join("f").exists());
- check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f")));
- check!(c(&w).truncate(true).open(&tmpdir.join("f")));
-
- check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g")));
- assert!(tmpdir.join("g").exists());
- check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g")));
- check!(c(&rw).truncate(true).open(&tmpdir.join("g")));
-
- check!(check!(File::create(&tmpdir.join("h"))).write("foo".as_bytes()));
- check!(r.open(&tmpdir.join("h")));
- {
- let mut f = check!(r.open(&tmpdir.join("h")));
- assert!(f.write("wut".as_bytes()).is_err());
- }
- assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
- {
- let mut f = check!(c(&w).append(true).open(&tmpdir.join("h")));
- check!(f.write("bar".as_bytes()));
- }
- assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6);
- {
- let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h")));
- check!(f.write("bar".as_bytes()));
- }
- assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
- }
-
- #[test]
- fn utime() {
- let tmpdir = tmpdir();
- let path = tmpdir.join("a");
- check!(File::create(&path));
- // These numbers have to be bigger than the time in the day to account
- // for timezones Windows in particular will fail in certain timezones
- // with small enough values
- check!(fs::set_file_times(&path, 100000, 200000));
- assert_eq!(check!(path.metadata()).accessed(), 100000);
- assert_eq!(check!(path.metadata()).modified(), 200000);
- }
-
- #[test]
- fn utime_noexist() {
- let tmpdir = tmpdir();
-
- match fs::set_file_times(&tmpdir.join("a"), 100, 200) {
- Ok(..) => panic!(),
- Err(..) => {}
- }
- }
-
- #[test]
- fn binary_file() {
- let mut bytes = [0; 1024];
- StdRng::new().unwrap().fill_bytes(&mut bytes);
-
- let tmpdir = tmpdir();
-
- check!(check!(File::create(&tmpdir.join("test"))).write(&bytes));
- let mut v = Vec::new();
- check!(check!(File::open(&tmpdir.join("test"))).read_to_end(&mut v));
- assert!(v == bytes.as_slice());
- }
-
- #[test]
- #[cfg(not(windows))]
- fn unlink_readonly() {
- let tmpdir = tmpdir();
- let path = tmpdir.join("file");
- check!(File::create(&path));
- let mut perm = check!(fs::metadata(&path)).permissions();
- perm.set_readonly(true);
- check!(fs::set_permissions(&path, perm));
- check!(fs::remove_file(&path));
- }
-
- #[test]
- fn mkdir_trailing_slash() {
- let tmpdir = tmpdir();
- let path = tmpdir.join("file");
- check!(fs::create_dir_all(&path.join("a/")));
- }
-}
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![unstable(feature = "tempdir", reason = "needs an RFC before stabilization")]
-#![deprecated(since = "1.0.0",
- reason = "use the `tempdir` crate from crates.io instead")]
-#![allow(deprecated)]
-
-use prelude::v1::*;
-
-use env;
-use io::{self, Error, ErrorKind};
-use fs;
-use path::{self, PathBuf};
-use rand::{thread_rng, Rng};
-
-/// A wrapper for a path to temporary directory implementing automatic
-/// scope-based deletion.
-pub struct TempDir {
- path: Option<PathBuf>,
-}
-
-// How many times should we (re)try finding an unused random name? It should be
-// enough that an attacker will run out of luck before we run out of patience.
-const NUM_RETRIES: u32 = 1 << 31;
-// How many characters should we include in a random file name? It needs to
-// be enough to dissuade an attacker from trying to preemptively create names
-// of that length, but not so huge that we unnecessarily drain the random number
-// generator of entropy.
-const NUM_RAND_CHARS: usize = 12;
-
-impl TempDir {
- /// Attempts to make a temporary directory inside of `tmpdir` whose name
- /// will have the prefix `prefix`. The directory will be automatically
- /// deleted once the returned wrapper is destroyed.
- ///
- /// If no directory can be created, `Err` is returned.
- #[allow(deprecated)] // rand usage
- pub fn new_in<P: AsRef<path::Path>>(tmpdir: P, prefix: &str) -> io::Result<TempDir> {
- let storage;
- let mut tmpdir = tmpdir.as_ref();
- if !tmpdir.is_absolute() {
- let cur_dir = try!(env::current_dir());
- storage = cur_dir.join(tmpdir);
- tmpdir = &storage;
- // return TempDir::new_in(&cur_dir.join(tmpdir), prefix);
- }
-
- let mut rng = thread_rng();
- for _ in 0..NUM_RETRIES {
- let suffix: String = rng.gen_ascii_chars().take(NUM_RAND_CHARS).collect();
- let leaf = if prefix.len() > 0 {
- format!("{}.{}", prefix, suffix)
- } else {
- // If we're given an empty string for a prefix, then creating a
- // directory starting with "." would lead to it being
- // semi-invisible on some systems.
- suffix
- };
- let path = tmpdir.join(&leaf);
- match fs::create_dir(&path) {
- Ok(_) => return Ok(TempDir { path: Some(path) }),
- Err(ref e) if e.kind() == ErrorKind::AlreadyExists => {}
- Err(e) => return Err(e)
- }
- }
-
- Err(Error::new(ErrorKind::AlreadyExists,
- "too many temporary directories already exist",
- None))
- }
-
- /// Attempts to make a temporary directory inside of `env::temp_dir()` whose
- /// name will have the prefix `prefix`. The directory will be automatically
- /// deleted once the returned wrapper is destroyed.
- ///
- /// If no directory can be created, `Err` is returned.
- #[allow(deprecated)]
- pub fn new(prefix: &str) -> io::Result<TempDir> {
- TempDir::new_in(&env::temp_dir(), prefix)
- }
-
- /// Unwrap the wrapped `std::path::Path` from the `TempDir` wrapper.
- /// This discards the wrapper so that the automatic deletion of the
- /// temporary directory is prevented.
- pub fn into_path(mut self) -> PathBuf {
- self.path.take().unwrap()
- }
-
- /// Access the wrapped `std::path::Path` to the temporary directory.
- pub fn path(&self) -> &path::Path {
- self.path.as_ref().unwrap()
- }
-
- /// Close and remove the temporary directory
- ///
- /// Although `TempDir` removes the directory on drop, in the destructor
- /// any errors are ignored. To detect errors cleaning up the temporary
- /// directory, call `close` instead.
- pub fn close(mut self) -> io::Result<()> {
- self.cleanup_dir()
- }
-
- fn cleanup_dir(&mut self) -> io::Result<()> {
- match self.path {
- Some(ref p) => fs::remove_dir_all(p),
- None => Ok(())
- }
- }
-}
-
-impl Drop for TempDir {
- fn drop(&mut self) {
- let _ = self.cleanup_dir();
- }
-}
-
-// the tests for this module need to change the path using change_dir,
-// and this doesn't play nicely with other tests so these unit tests are located
-// in src/test/run-pass/tempfile.rs
use io::prelude::*;
use cmp;
-use error::{self, FromError};
+use error;
use fmt;
use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind};
use ptr;
match self.inner.as_mut().unwrap().write(&self.buf[written..]) {
Ok(0) => {
ret = Err(Error::new(ErrorKind::WriteZero,
- "failed to write the buffered data", None));
+ "failed to write the buffered data"));
break;
}
Ok(n) => written += n,
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<W> FromError<IntoInnerError<W>> for Error {
- fn from_error(iie: IntoInnerError<W>) -> Error { iie.1 }
+impl<W> From<IntoInnerError<W>> for Error {
+ fn from(iie: IntoInnerError<W>) -> Error { iie.1 }
}
#[stable(feature = "rust1", since = "1.0.0")]
let mut buf = [0, 0, 0];
let nread = reader.read(&mut buf);
- assert_eq!(Ok(3), nread);
+ assert_eq!(nread.unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(buf, b);
let mut buf = [0, 0];
let nread = reader.read(&mut buf);
- assert_eq!(Ok(2), nread);
+ assert_eq!(nread.unwrap(), 2);
let b: &[_] = &[0, 1];
assert_eq!(buf, b);
let mut buf = [0];
let nread = reader.read(&mut buf);
- assert_eq!(Ok(1), nread);
+ assert_eq!(nread.unwrap(), 1);
let b: &[_] = &[2];
assert_eq!(buf, b);
let mut buf = [0, 0, 0];
let nread = reader.read(&mut buf);
- assert_eq!(Ok(1), nread);
+ assert_eq!(nread.unwrap(), 1);
let b: &[_] = &[3, 0, 0];
assert_eq!(buf, b);
let nread = reader.read(&mut buf);
- assert_eq!(Ok(1), nread);
+ assert_eq!(nread.unwrap(), 1);
let b: &[_] = &[4, 0, 0];
assert_eq!(buf, b);
- assert_eq!(reader.read(&mut buf), Ok(0));
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
}
let mut stream = BufStream::new(S);
- assert_eq!(stream.read(&mut [0; 10]), Ok(0));
+ assert_eq!(stream.read(&mut [0; 10]).unwrap(), 0);
stream.write(&[0; 10]).unwrap();
stream.flush().unwrap();
}
let in_buf: &[u8] = b"a\nb\nc";
let reader = BufReader::with_capacity(2, in_buf);
let mut it = reader.lines();
- assert_eq!(it.next(), Some(Ok("a".to_string())));
- assert_eq!(it.next(), Some(Ok("b".to_string())));
- assert_eq!(it.next(), Some(Ok("c".to_string())));
- assert_eq!(it.next(), None);
+ assert_eq!(it.next().unwrap().unwrap(), "a".to_string());
+ assert_eq!(it.next().unwrap().unwrap(), "b".to_string());
+ assert_eq!(it.next().unwrap().unwrap(), "c".to_string());
+ assert!(it.next().is_none());
}
#[test]
let inner = ShortReader{lengths: vec![0, 1, 2, 0, 1, 0]};
let mut reader = BufReader::new(inner);
let mut buf = [0, 0];
- assert_eq!(reader.read(&mut buf), Ok(0));
- assert_eq!(reader.read(&mut buf), Ok(1));
- assert_eq!(reader.read(&mut buf), Ok(2));
- assert_eq!(reader.read(&mut buf), Ok(0));
- assert_eq!(reader.read(&mut buf), Ok(1));
- assert_eq!(reader.read(&mut buf), Ok(0));
- assert_eq!(reader.read(&mut buf), Ok(0));
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ assert_eq!(reader.read(&mut buf).unwrap(), 1);
+ assert_eq!(reader.read(&mut buf).unwrap(), 2);
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ assert_eq!(reader.read(&mut buf).unwrap(), 1);
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn read_char_buffered() {
let buf = [195, 159];
let reader = BufReader::with_capacity(1, &buf[..]);
- assert_eq!(reader.chars().next(), Some(Ok('ß')));
+ assert_eq!(reader.chars().next().unwrap().unwrap(), 'ß');
}
#[test]
let buf = [195, 159, b'a'];
let reader = BufReader::with_capacity(1, &buf[..]);
let mut it = reader.chars();
- assert_eq!(it.next(), Some(Ok('ß')));
- assert_eq!(it.next(), Some(Ok('a')));
- assert_eq!(it.next(), None);
+ assert_eq!(it.next().unwrap().unwrap(), 'ß');
+ assert_eq!(it.next().unwrap().unwrap(), 'a');
+ assert!(it.next().is_none());
}
#[test]
if pos < 0 {
Err(Error::new(ErrorKind::InvalidInput,
- "invalid seek to a negative position",
- None))
+ "invalid seek to a negative position"))
} else {
self.pos = pos as u64;
Ok(self.pos)
#[test]
fn test_vec_writer() {
let mut writer = Vec::new();
- assert_eq!(writer.write(&[0]), Ok(1));
- assert_eq!(writer.write(&[1, 2, 3]), Ok(3));
- assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4));
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
+ assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+ assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(writer, b);
}
#[test]
fn test_mem_writer() {
let mut writer = Cursor::new(Vec::new());
- assert_eq!(writer.write(&[0]), Ok(1));
- assert_eq!(writer.write(&[1, 2, 3]), Ok(3));
- assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4));
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
+ assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+ assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
}
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
- assert_eq!(writer.write(&[0]), Ok(1));
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
- assert_eq!(writer.write(&[1, 2, 3]), Ok(3));
- assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4));
+ assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+ assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(writer.position(), 8);
- assert_eq!(writer.write(&[]), Ok(0));
+ assert_eq!(writer.write(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);
- assert_eq!(writer.write(&[8, 9]), Ok(1));
- assert_eq!(writer.write(&[10]), Ok(0));
+ assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
+ assert_eq!(writer.write(&[10]).unwrap(), 0);
}
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(buf, b);
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
- assert_eq!(writer.write(&[1]), Ok(1));
+ assert_eq!(writer.write(&[1]).unwrap(), 1);
assert_eq!(writer.position(), 1);
- assert_eq!(writer.seek(SeekFrom::Start(2)), Ok(2));
+ assert_eq!(writer.seek(SeekFrom::Start(2)).unwrap(), 2);
assert_eq!(writer.position(), 2);
- assert_eq!(writer.write(&[2]), Ok(1));
+ assert_eq!(writer.write(&[2]).unwrap(), 1);
assert_eq!(writer.position(), 3);
- assert_eq!(writer.seek(SeekFrom::Current(-2)), Ok(1));
+ assert_eq!(writer.seek(SeekFrom::Current(-2)).unwrap(), 1);
assert_eq!(writer.position(), 1);
- assert_eq!(writer.write(&[3]), Ok(1));
+ assert_eq!(writer.write(&[3]).unwrap(), 1);
assert_eq!(writer.position(), 2);
- assert_eq!(writer.seek(SeekFrom::End(-1)), Ok(7));
+ assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
assert_eq!(writer.position(), 7);
- assert_eq!(writer.write(&[4]), Ok(1));
+ assert_eq!(writer.write(&[4]).unwrap(), 1);
assert_eq!(writer.position(), 8);
}
fn test_buf_writer_error() {
let mut buf = [0 as u8; 2];
let mut writer = Cursor::new(&mut buf[..]);
- assert_eq!(writer.write(&[0]), Ok(1));
- assert_eq!(writer.write(&[0, 0]), Ok(1));
- assert_eq!(writer.write(&[0, 0]), Ok(0));
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
+ assert_eq!(writer.write(&[0, 0]).unwrap(), 1);
+ assert_eq!(writer.write(&[0, 0]).unwrap(), 0);
}
#[test]
fn test_mem_reader() {
let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7));
let mut buf = [];
- assert_eq!(reader.read(&mut buf), Ok(0));
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
- assert_eq!(reader.read(&mut buf), Ok(1));
+ assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
- assert_eq!(reader.read(&mut buf), Ok(4));
+ assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.position(), 5);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
- assert_eq!(reader.read(&mut buf), Ok(3));
+ assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
- assert_eq!(reader.read(&mut buf), Ok(0));
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
#[test]
fn test_slice_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
- let mut reader = &mut in_buf.as_slice();
+ let mut reader = &mut &in_buf[..];
let mut buf = [];
- assert_eq!(reader.read(&mut buf), Ok(0));
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
let mut buf = [0];
- assert_eq!(reader.read(&mut buf), Ok(1));
+ assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.len(), 7);
let b: &[_] = &[0];
- assert_eq!(buf.as_slice(), b);
+ assert_eq!(&buf[..], b);
let mut buf = [0; 4];
- assert_eq!(reader.read(&mut buf), Ok(4));
+ assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.len(), 3);
let b: &[_] = &[1, 2, 3, 4];
- assert_eq!(buf.as_slice(), b);
- assert_eq!(reader.read(&mut buf), Ok(3));
+ assert_eq!(&buf[..], b);
+ assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
- assert_eq!(reader.read(&mut buf), Ok(0));
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_buf_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
- let mut reader = Cursor::new(in_buf.as_slice());
+ let mut reader = Cursor::new(&in_buf[..]);
let mut buf = [];
- assert_eq!(reader.read(&mut buf), Ok(0));
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
- assert_eq!(reader.read(&mut buf), Ok(1));
+ assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
- assert_eq!(reader.read(&mut buf), Ok(4));
+ assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.position(), 5);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
- assert_eq!(reader.read(&mut buf), Ok(3));
+ assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
- assert_eq!(reader.read(&mut buf), Ok(0));
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_read_char() {
let b = &b"Vi\xE1\xBB\x87t"[..];
let mut c = Cursor::new(b).chars();
- assert_eq!(c.next(), Some(Ok('V')));
- assert_eq!(c.next(), Some(Ok('i')));
- assert_eq!(c.next(), Some(Ok('ệ')));
- assert_eq!(c.next(), Some(Ok('t')));
- assert_eq!(c.next(), None);
+ assert_eq!(c.next().unwrap().unwrap(), 'V');
+ assert_eq!(c.next().unwrap().unwrap(), 'i');
+ assert_eq!(c.next().unwrap().unwrap(), 'ệ');
+ assert_eq!(c.next().unwrap().unwrap(), 't');
+ assert!(c.next().is_none());
}
#[test]
fn seek_past_end() {
let buf = [0xff];
let mut r = Cursor::new(&buf[..]);
- assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10));
- assert_eq!(r.read(&mut [0]), Ok(0));
+ assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+ assert_eq!(r.read(&mut [0]).unwrap(), 0);
let mut r = Cursor::new(vec!(10));
- assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10));
- assert_eq!(r.read(&mut [0]), Ok(0));
+ assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+ assert_eq!(r.read(&mut [0]).unwrap(), 0);
let mut buf = [0];
let mut r = Cursor::new(&mut buf[..]);
- assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10));
- assert_eq!(r.write(&[3]), Ok(0));
+ assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+ assert_eq!(r.write(&[3]).unwrap(), 0);
}
#[test]
fn test_seekable_mem_writer() {
let mut writer = Cursor::new(Vec::<u8>::new());
assert_eq!(writer.position(), 0);
- assert_eq!(writer.write(&[0]), Ok(1));
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
- assert_eq!(writer.write(&[1, 2, 3]), Ok(3));
- assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4));
+ assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+ assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(writer.position(), 8);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
- assert_eq!(writer.seek(SeekFrom::Start(0)), Ok(0));
+ assert_eq!(writer.seek(SeekFrom::Start(0)).unwrap(), 0);
assert_eq!(writer.position(), 0);
- assert_eq!(writer.write(&[3, 4]), Ok(2));
+ assert_eq!(writer.write(&[3, 4]).unwrap(), 2);
let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
- assert_eq!(writer.seek(SeekFrom::Current(1)), Ok(3));
- assert_eq!(writer.write(&[0, 1]), Ok(2));
+ assert_eq!(writer.seek(SeekFrom::Current(1)).unwrap(), 3);
+ assert_eq!(writer.write(&[0, 1]).unwrap(), 2);
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
- assert_eq!(writer.seek(SeekFrom::End(-1)), Ok(7));
- assert_eq!(writer.write(&[1, 2]), Ok(2));
+ assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
+ assert_eq!(writer.write(&[1, 2]).unwrap(), 2);
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2];
assert_eq!(&writer.get_ref()[..], b);
- assert_eq!(writer.seek(SeekFrom::End(1)), Ok(10));
- assert_eq!(writer.write(&[1]), Ok(1));
+ assert_eq!(writer.seek(SeekFrom::End(1)).unwrap(), 10);
+ assert_eq!(writer.write(&[1]).unwrap(), 1);
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1];
assert_eq!(&writer.get_ref()[..], b);
}
#[test]
fn vec_seek_past_end() {
let mut r = Cursor::new(Vec::new());
- assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10));
- assert_eq!(r.write(&[3]), Ok(1));
+ assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+ assert_eq!(r.write(&[3]).unwrap(), 1);
}
#[test]
// except according to those terms.
use boxed::Box;
-use clone::Clone;
+use convert::Into;
use error;
use fmt;
+use marker::Send;
use option::Option::{self, Some, None};
use result;
-use string::String;
use sys;
/// A type for results generated by I/O related functions where the `Err` type
/// Errors mostly originate from the underlying OS, but custom instances of
/// `Error` can be created with crafted error messages and a particular value of
/// `ErrorKind`.
-#[derive(PartialEq, Eq, Clone, Debug)]
+#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Error {
repr: Repr,
}
-#[derive(PartialEq, Eq, Clone, Debug)]
+#[derive(Debug)]
enum Repr {
Os(i32),
Custom(Box<Custom>),
}
-#[derive(PartialEq, Eq, Clone, Debug)]
+#[derive(Debug)]
struct Custom {
kind: ErrorKind,
- desc: &'static str,
- detail: Option<String>
+ error: Box<error::Error+Send>,
}
/// A list specifying general categories of I/O error.
}
impl Error {
- /// Creates a new custom error from a specified kind/description/detail.
- #[unstable(feature = "io", reason = "the exact makeup of an Error may
- change to include `Box<Error>` for \
- example")]
- pub fn new(kind: ErrorKind,
- description: &'static str,
- detail: Option<String>) -> Error {
+ /// Creates a new I/O error from a known kind of error as well as an
+ /// arbitrary error payload.
+ ///
+ /// This function is used to generically create I/O errors which do not
+ /// originate from the OS itself. The `error` argument is an arbitrary
+ /// payload which will be contained in this `Error`. Accessors as well as
+ /// downcasting will soon be added to this type as well to access the custom
+ /// information.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::{Error, ErrorKind};
+ ///
+ /// // errors can be created from strings
+ /// let custom_error = Error::new(ErrorKind::Other, "oh no!");
+ ///
+ /// // errors can also be created from other errors
+ /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn new<E>(kind: ErrorKind, error: E) -> Error
+ where E: Into<Box<error::Error+Send>>
+ {
Error {
repr: Repr::Custom(Box::new(Custom {
kind: kind,
- desc: description,
- detail: detail,
+ error: error.into(),
}))
}
}
///
/// If this `Error` was constructed via `last_os_error` then this function
/// will return `Some`, otherwise it will return `None`.
- #[unstable(feature = "io", reason = "function was just added and the return \
- type may become an abstract OS error")]
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn raw_os_error(&self) -> Option<i32> {
match self.repr {
Repr::Os(i) => Some(i),
Repr::Custom(ref c) => c.kind,
}
}
-
- /// Returns a short description for this error message
- #[unstable(feature = "io")]
- #[deprecated(since = "1.0.0", reason = "use the Error trait's description \
- method instead")]
- pub fn description(&self) -> &str {
- match self.repr {
- Repr::Os(..) => "os error",
- Repr::Custom(ref c) => c.desc,
- }
- }
-
- /// Returns a detailed error message for this error (if one is available)
- #[unstable(feature = "io")]
- #[deprecated(since = "1.0.0", reason = "use the to_string() method instead")]
- pub fn detail(&self) -> Option<String> {
- match self.repr {
- Repr::Os(code) => Some(sys::os::error_string(code)),
- Repr::Custom(ref s) => s.detail.clone(),
- }
- }
}
#[stable(feature = "rust1", since = "1.0.0")]
let detail = sys::os::error_string(code);
write!(fmt, "{} (os error {})", detail, code)
}
- Repr::Custom(ref c) => {
- match **c {
- Custom {
- kind: ErrorKind::Other,
- desc: "unknown error",
- detail: Some(ref detail)
- } => {
- write!(fmt, "{}", detail)
- }
- Custom { detail: None, desc, .. } =>
- write!(fmt, "{}", desc),
- Custom { detail: Some(ref detail), desc, .. } =>
- write!(fmt, "{} ({})", desc, detail)
- }
- }
+ Repr::Custom(ref c) => c.error.fmt(fmt),
}
}
}
fn description(&self) -> &str {
match self.repr {
Repr::Os(..) => "os error",
- Repr::Custom(ref c) => c.desc,
+ Repr::Custom(ref c) => c.error.description(),
}
}
}
if try!(self.write(data)) == data.len() {
Ok(())
} else {
- Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer", None))
+ Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer"))
}
}
if str::from_utf8(&g.s[g.len..]).is_err() {
ret.and_then(|_| {
Err(Error::new(ErrorKind::InvalidInput,
- "stream did not contain valid UTF-8", None))
+ "stream did not contain valid UTF-8"))
})
} else {
g.len = g.s.len();
fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
let start_len = buf.len();
let mut len = start_len;
- let mut cap_bump = 16;
+ let mut new_write_size = 16;
let ret;
loop {
if len == buf.len() {
- if buf.capacity() == buf.len() {
- if cap_bump < DEFAULT_BUF_SIZE {
- cap_bump *= 2;
- }
- buf.reserve(cap_bump);
+ if new_write_size < DEFAULT_BUF_SIZE {
+ new_write_size *= 2;
}
- let new_area = buf.capacity() - buf.len();
- buf.extend(iter::repeat(0).take(new_area));
+ buf.extend(iter::repeat(0).take(new_write_size));
}
match r.read(&mut buf[len..]) {
while buf.len() > 0 {
match self.write(buf) {
Ok(0) => return Err(Error::new(ErrorKind::WriteZero,
- "failed to write whole buffer",
- None)),
+ "failed to write whole buffer")),
Ok(n) => buf = &buf[n..],
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => return Err(e),
///
/// The stream typically has a fixed size, allowing seeking relative to either
/// end or the current offset.
-#[unstable(feature = "io", reason = "the central `seek` method may be split \
- into multiple methods instead of taking \
- an enum as an argument")]
+#[stable(feature = "rust1", since = "1.0.0")]
pub trait Seek {
/// Seek to an offset, in bytes, in a stream
///
/// # Errors
///
/// Seeking to a negative offset is considered an error
+ #[stable(feature = "rust1", since = "1.0.0")]
fn seek(&mut self, pos: SeekFrom) -> Result<u64>;
}
/// Enumeration of possible methods to seek within an I/O object.
#[derive(Copy, PartialEq, Eq, Clone, Debug)]
-#[unstable(feature = "io", reason = "awaiting the stability of Seek")]
+#[stable(feature = "rust1", since = "1.0.0")]
pub enum SeekFrom {
/// Set the offset to the provided number of bytes.
+ #[stable(feature = "rust1", since = "1.0.0")]
Start(u64),
/// Set the offset to the size of this object plus the specified number of
///
/// It is possible to seek beyond the end of an object, but is an error to
/// seek before byte 0.
+ #[stable(feature = "rust1", since = "1.0.0")]
End(i64),
/// Set the offset to the current position plus the specified number of
///
/// It is possible to seek beyond the end of an object, but is an error to
/// seek before byte 0.
+ #[stable(feature = "rust1", since = "1.0.0")]
Current(i64),
}
/// An enumeration of possible errors that can be generated from the `Chars`
/// adapter.
-#[derive(PartialEq, Clone, Debug)]
+#[derive(Debug)]
#[unstable(feature = "io", reason = "awaiting stability of Read::chars")]
pub enum CharsError {
/// Variant representing that the underlying stream was read successfully
fn read_until() {
let mut buf = Cursor::new(&b"12"[..]);
let mut v = Vec::new();
- assert_eq!(buf.read_until(b'3', &mut v), Ok(2));
+ assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 2);
assert_eq!(v, b"12");
let mut buf = Cursor::new(&b"1233"[..]);
let mut v = Vec::new();
- assert_eq!(buf.read_until(b'3', &mut v), Ok(3));
+ assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 3);
assert_eq!(v, b"123");
v.truncate(0);
- assert_eq!(buf.read_until(b'3', &mut v), Ok(1));
+ assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 1);
assert_eq!(v, b"3");
v.truncate(0);
- assert_eq!(buf.read_until(b'3', &mut v), Ok(0));
+ assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 0);
assert_eq!(v, []);
}
fn split() {
let buf = Cursor::new(&b"12"[..]);
let mut s = buf.split(b'3');
- assert_eq!(s.next(), Some(Ok(vec![b'1', b'2'])));
- assert_eq!(s.next(), None);
+ assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']);
+ assert!(s.next().is_none());
let buf = Cursor::new(&b"1233"[..]);
let mut s = buf.split(b'3');
- assert_eq!(s.next(), Some(Ok(vec![b'1', b'2'])));
- assert_eq!(s.next(), Some(Ok(vec![])));
- assert_eq!(s.next(), None);
+ assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']);
+ assert_eq!(s.next().unwrap().unwrap(), vec![]);
+ assert!(s.next().is_none());
}
#[test]
fn read_line() {
let mut buf = Cursor::new(&b"12"[..]);
let mut v = String::new();
- assert_eq!(buf.read_line(&mut v), Ok(2));
+ assert_eq!(buf.read_line(&mut v).unwrap(), 2);
assert_eq!(v, "12");
let mut buf = Cursor::new(&b"12\n\n"[..]);
let mut v = String::new();
- assert_eq!(buf.read_line(&mut v), Ok(3));
+ assert_eq!(buf.read_line(&mut v).unwrap(), 3);
assert_eq!(v, "12\n");
v.truncate(0);
- assert_eq!(buf.read_line(&mut v), Ok(1));
+ assert_eq!(buf.read_line(&mut v).unwrap(), 1);
assert_eq!(v, "\n");
v.truncate(0);
- assert_eq!(buf.read_line(&mut v), Ok(0));
+ assert_eq!(buf.read_line(&mut v).unwrap(), 0);
assert_eq!(v, "");
}
fn lines() {
let buf = Cursor::new(&b"12"[..]);
let mut s = buf.lines();
- assert_eq!(s.next(), Some(Ok("12".to_string())));
- assert_eq!(s.next(), None);
+ assert_eq!(s.next().unwrap().unwrap(), "12".to_string());
+ assert!(s.next().is_none());
let buf = Cursor::new(&b"12\n\n"[..]);
let mut s = buf.lines();
- assert_eq!(s.next(), Some(Ok("12".to_string())));
- assert_eq!(s.next(), Some(Ok(String::new())));
- assert_eq!(s.next(), None);
+ assert_eq!(s.next().unwrap().unwrap(), "12".to_string());
+ assert_eq!(s.next().unwrap().unwrap(), "".to_string());
+ assert!(s.next().is_none());
}
#[test]
fn read_to_end() {
let mut c = Cursor::new(&b""[..]);
let mut v = Vec::new();
- assert_eq!(c.read_to_end(&mut v), Ok(0));
+ assert_eq!(c.read_to_end(&mut v).unwrap(), 0);
assert_eq!(v, []);
let mut c = Cursor::new(&b"1"[..]);
let mut v = Vec::new();
- assert_eq!(c.read_to_end(&mut v), Ok(1));
+ assert_eq!(c.read_to_end(&mut v).unwrap(), 1);
assert_eq!(v, b"1");
}
fn read_to_string() {
let mut c = Cursor::new(&b""[..]);
let mut v = String::new();
- assert_eq!(c.read_to_string(&mut v), Ok(0));
+ assert_eq!(c.read_to_string(&mut v).unwrap(), 0);
assert_eq!(v, "");
let mut c = Cursor::new(&b"1"[..]);
let mut v = String::new();
- assert_eq!(c.read_to_string(&mut v), Ok(1));
+ assert_eq!(c.read_to_string(&mut v).unwrap(), 1);
assert_eq!(v, "1");
let mut c = Cursor::new(&b"\xff"[..]);
impl Read for R {
fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
- Err(io::Error::new(io::ErrorKind::Other, "", None))
+ Err(io::Error::new(io::ErrorKind::Other, ""))
}
}
let mut buf = [0; 1];
- assert_eq!(Ok(0), R.take(0).read(&mut buf));
+ assert_eq!(0, R.take(0).read(&mut buf).unwrap());
}
}
#[test]
fn sink_sinks() {
let mut s = sink();
- assert_eq!(s.write(&[]), Ok(0));
- assert_eq!(s.write(&[0]), Ok(1));
- assert_eq!(s.write(&[0; 1024]), Ok(1024));
- assert_eq!(s.by_ref().write(&[0; 1024]), Ok(1024));
+ assert_eq!(s.write(&[]).unwrap(), 0);
+ assert_eq!(s.write(&[0]).unwrap(), 1);
+ assert_eq!(s.write(&[0; 1024]).unwrap(), 1024);
+ assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024);
}
#[test]
fn empty_reads() {
let mut e = empty();
- assert_eq!(e.read(&mut []), Ok(0));
- assert_eq!(e.read(&mut [0]), Ok(0));
- assert_eq!(e.read(&mut [0; 1024]), Ok(0));
- assert_eq!(e.by_ref().read(&mut [0; 1024]), Ok(0));
+ assert_eq!(e.read(&mut []).unwrap(), 0);
+ assert_eq!(e.read(&mut [0]).unwrap(), 0);
+ assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
+ assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
}
#[test]
fn repeat_repeats() {
let mut r = repeat(4);
let mut b = [0; 1024];
- assert_eq!(r.read(&mut b), Ok(1024));
+ assert_eq!(r.read(&mut b).unwrap(), 1024);
assert!(b.iter().all(|b| *b == 4));
}
#[test]
fn take_some_bytes() {
assert_eq!(repeat(4).take(100).bytes().count(), 100);
- assert_eq!(repeat(4).take(100).bytes().next(), Some(Ok(4)));
+ assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4);
assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20);
}
let mut buf = [0; 10];
{
let mut ptr: &mut [u8] = &mut buf;
- assert_eq!(repeat(4).tee(&mut ptr).take(5).read(&mut [0; 10]), Ok(5));
+ assert_eq!(repeat(4).tee(&mut ptr).take(5).read(&mut [0; 10]).unwrap(), 5);
}
assert_eq!(buf, [4, 4, 4, 4, 4, 0, 0, 0, 0, 0]);
}
let mut ptr2: &mut [u8] = &mut buf2;
assert_eq!((&mut ptr1).broadcast(&mut ptr2)
- .write(&[1, 2, 3]), Ok(3));
+ .write(&[1, 2, 3]).unwrap(), 3);
}
assert_eq!(buf1, buf2);
assert_eq!(buf1, [1, 2, 3, 0, 0, 0, 0, 0, 0, 0]);
//! lives in the [`vec`](vec/index.html) module. Contiguous, unsized regions
//! of memory, `[T]`, commonly called "slices", and their borrowed versions,
//! `&[T]`, commonly called "borrowed slices", are built-in types for which the
-//! for which the [`slice`](slice/index.html) module defines many methods.
+//! [`slice`](slice/index.html) module defines many methods.
//!
//! `&str`, a UTF-8 string, is a built-in type, and the standard library
//! defines methods for it on a variety of traits in the
#![feature(unsafe_no_drop_flag, filling_drop)]
#![feature(macro_reexport)]
#![feature(unique)]
-#![feature(convert)]
#![feature(allow_internal_unstable)]
#![feature(str_char)]
#![feature(into_cow)]
-#![feature(slice_patterns)]
#![feature(std_misc)]
+#![feature(slice_patterns)]
#![feature(debug_builders)]
#![cfg_attr(test, feature(test, rustc_private, std_misc))]
#[cfg(not(test))] pub use core::cmp;
pub use core::convert;
pub use core::default;
-#[allow(deprecated)]
-pub use core::finally;
pub use core::hash;
pub use core::intrinsics;
pub use core::iter;
($expr:expr) => (match $expr {
$crate::result::Result::Ok(val) => val,
$crate::result::Result::Err(err) => {
- return $crate::result::Result::Err($crate::error::FromError::from_error(err))
+ return $crate::result::Result::Err($crate::convert::From::from(err))
}
})
}
match $e {
Some(r) => r,
None => return Err(io::Error::new(io::ErrorKind::InvalidInput,
- $msg, None)),
+ $msg)),
}
)
}
false, false, false, true, false, false, false, Some(Global));
}
- fn tsa<A: ToSocketAddrs>(a: A) -> io::Result<Vec<SocketAddr>> {
- Ok(try!(a.to_socket_addrs()).collect())
+ fn tsa<A: ToSocketAddrs>(a: A) -> Result<Vec<SocketAddr>, String> {
+ match a.to_socket_addrs() {
+ Ok(a) => Ok(a.collect()),
+ Err(e) => Err(e.to_string()),
+ }
}
#[test]
}
Err(last_err.unwrap_or_else(|| {
Error::new(ErrorKind::InvalidInput,
- "could not resolve to any addresses", None)
+ "could not resolve to any addresses")
}))
}
use io;
use net::{ToSocketAddrs, SocketAddr, Shutdown};
use sys_common::net2 as net_imp;
-use sys_common::AsInner;
+use sys_common::{AsInner, FromInner};
/// A structure which represents a TCP stream between a local socket and a
/// remote socket.
self.0.peer_addr()
}
- /// Returns the socket address of the local half of this TCP connection.
- #[unstable(feature = "net")]
- #[deprecated(since = "1.0.0", reason = "renamed to local_addr")]
- pub fn socket_addr(&self) -> io::Result<SocketAddr> {
- self.0.socket_addr()
- }
-
/// Returns the socket address of the local half of this TCP connection.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn local_addr(&self) -> io::Result<SocketAddr> {
fn as_inner(&self) -> &net_imp::TcpStream { &self.0 }
}
+impl FromInner<net_imp::TcpStream> for TcpStream {
+ fn from_inner(inner: net_imp::TcpStream) -> TcpStream { TcpStream(inner) }
+}
+
impl TcpListener {
/// Creates a new `TcpListener` which will be bound to the specified
/// address.
self.0.socket_addr()
}
- /// Deprecated, renamed to local_addr
- #[unstable(feature = "net")]
- #[deprecated(since = "1.0.0", reason = "renamed to local_addr")]
- pub fn socket_addr(&self) -> io::Result<SocketAddr> {
- self.0.socket_addr()
- }
-
/// Create a new independently owned handle to the underlying socket.
///
/// The returned `TcpListener` is a reference to the same socket that this
fn as_inner(&self) -> &net_imp::TcpListener { &self.0 }
}
+impl FromInner<net_imp::TcpListener> for TcpListener {
+ fn from_inner(inner: net_imp::TcpListener) -> TcpListener {
+ TcpListener(inner)
+ }
+}
+
#[cfg(test)]
mod tests {
use prelude::v1::*;
let _t = thread::spawn(move|| {
let mut stream = t!(TcpStream::connect(&addr));
t!(stream.write(&[99]));
- tx.send(t!(stream.socket_addr())).unwrap();
+ tx.send(t!(stream.local_addr())).unwrap();
});
let (mut stream, addr) = t!(acceptor.accept());
fn socket_and_peer_name_ip4() {
each_ip(&mut |addr| {
let listener = t!(TcpListener::bind(&addr));
- let so_name = t!(listener.socket_addr());
+ let so_name = t!(listener.local_addr());
assert_eq!(addr, so_name);
let _t = thread::spawn(move|| {
t!(listener.accept());
let mut c = t!(TcpStream::connect(&addr));
let mut b = [0; 10];
- assert_eq!(c.read(&mut b), Ok(1));
+ assert_eq!(c.read(&mut b).unwrap(), 1);
t!(c.write(&[1]));
rx.recv().unwrap();
})
let _t = thread::spawn(move|| {
let mut s = t!(TcpStream::connect(&addr));
let mut buf = [0, 0];
- assert_eq!(s.read(&mut buf), Ok(1));
+ assert_eq!(s.read(&mut buf).unwrap(), 1);
assert_eq!(buf[0], 1);
t!(s.write(&[2]));
});
});
tx1.send(()).unwrap();
let mut buf = [0, 0];
- assert_eq!(s1.read(&mut buf), Ok(1));
+ assert_eq!(s1.read(&mut buf).unwrap(), 1);
rx2.recv().unwrap();
})
}
let _t = thread::spawn(move|| {
let mut c = t!(a.accept()).0;
let mut b = [0];
- assert_eq!(c.read(&mut b), Ok(0));
+ assert_eq!(c.read(&mut b).unwrap(), 0);
t!(c.write(&[1]));
});
t!(s.shutdown(Shutdown::Write));
assert!(s.write(&[0]).is_err());
t!(s.shutdown(Shutdown::Read));
- assert_eq!(s.read(&mut b), Ok(0));
+ assert_eq!(s.read(&mut b).unwrap(), 0);
// closing should affect previous handles
assert!(s2.write(&[0]).is_err());
- assert_eq!(s2.read(&mut b), Ok(0));
+ assert_eq!(s2.read(&mut b).unwrap(), 0);
// closing should affect new handles
let mut s3 = t!(s.try_clone());
assert!(s3.write(&[0]).is_err());
- assert_eq!(s3.read(&mut b), Ok(0));
+ assert_eq!(s3.read(&mut b).unwrap(), 0);
// make sure these don't die
let _ = s2.shutdown(Shutdown::Read);
use io::{self, Error, ErrorKind};
use net::{ToSocketAddrs, SocketAddr, IpAddr};
use sys_common::net2 as net_imp;
-use sys_common::AsInner;
+use sys_common::{AsInner, FromInner};
/// A User Datagram Protocol socket.
///
match try!(addr.to_socket_addrs()).next() {
Some(addr) => self.0.send_to(buf, &addr),
None => Err(Error::new(ErrorKind::InvalidInput,
- "no addresses to send data to", None)),
+ "no addresses to send data to")),
}
}
- /// Returns the socket address that this socket was created from.
- #[unstable(feature = "net")]
- #[deprecated(since = "1.0.0", reason = "renamed to local_addr")]
- pub fn socket_addr(&self) -> io::Result<SocketAddr> {
- self.0.socket_addr()
- }
-
/// Returns the socket address that this socket was created from.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn local_addr(&self) -> io::Result<SocketAddr> {
fn as_inner(&self) -> &net_imp::UdpSocket { &self.0 }
}
+impl FromInner<net_imp::UdpSocket> for UdpSocket {
+ fn from_inner(inner: net_imp::UdpSocket) -> UdpSocket { UdpSocket(inner) }
+}
+
#[cfg(test)]
mod tests {
use prelude::v1::*;
fn socket_name_ip4() {
each_ip(&mut |addr, _| {
let server = t!(UdpSocket::bind(&addr));
- assert_eq!(addr, t!(server.socket_addr()));
+ assert_eq!(addr, t!(server.local_addr()));
})
}
let _t = thread::spawn(move|| {
let mut buf = [0, 0];
- assert_eq!(sock2.recv_from(&mut buf), Ok((1, addr1)));
+ assert_eq!(sock2.recv_from(&mut buf).unwrap(), (1, addr1));
assert_eq!(buf[0], 1);
t!(sock2.send_to(&[2], &addr1));
});
});
tx1.send(()).unwrap();
let mut buf = [0, 0];
- assert_eq!(sock1.recv_from(&mut buf), Ok((1, addr2)));
+ assert_eq!(sock1.recv_from(&mut buf).unwrap(), (1, addr2));
rx2.recv().unwrap();
})
}
let mut w = BufferedWriter::with_capacity(3, Vec::new());
w.write_all(&[0, 1]).unwrap();
let a: &[_] = &[];
- assert_eq!(a, &w.get_ref()[..]);
+ assert_eq!(&w.get_ref()[..], a);
let w = w.into_inner();
let a: &[_] = &[0, 1];
assert_eq!(a, &w[..]);
({
use super::u64_from_be_bytes;
- let data = (0..$stride*100+$start_index).collect::<Vec<_>>();
+ let len = ($stride as u8).wrapping_mul(100).wrapping_add($start_index);
+ let data = (0..len).collect::<Vec<_>>();
let mut sum = 0;
$b.iter(|| {
let mut i = $start_index;
pub fn tmpdir() -> TempDir {
use os;
use rand;
- let ret = os::tmpdir().join(format!("rust-{}", rand::random::<u32>()));
+ let temp = Path::new(::env::temp_dir().to_str().unwrap());
+ let ret = temp.join(format!("rust-{}", rand::random::<u32>()));
check!(old_io::fs::mkdir(&ret, old_io::USER_RWX));
TempDir(ret)
}
check!(File::create(&tmpdir.join("test")).write(&bytes));
let actual = check!(File::open(&tmpdir.join("test")).read_to_end());
- assert!(actual == bytes.as_slice());
+ assert!(actual == &bytes[..]);
}
#[test]
mod test {
extern crate test as test_crate;
use old_io::{SeekSet, SeekCur, SeekEnd, Reader, Writer, Seek, Buffer};
- use prelude::v1::{Ok, Err, Vec, AsSlice};
+ use prelude::v1::{Ok, Err, Vec};
use prelude::v1::Iterator;
use old_io;
use iter::repeat;
wr.write(&[5; 10]).unwrap();
}
}
- assert_eq!(buf.as_slice(), [5; 100].as_slice());
+ assert_eq!(&buf[..], &[5; 100][..]);
});
}
use ops::FnOnce;
use option::Option;
use option::Option::{Some, None};
-use os;
+use sys::os;
use boxed::Box;
use result::Result;
use result::Result::{Ok, Err};
/// Some examples:
///
/// ```rust,no_run
-/// # #![feature(old_io, core)]
+/// # #![feature(old_io, core, convert)]
/// # #![allow(unused_must_use)]
///
/// use std::old_io::{TcpStream, TcpListener};
/// let tcp_l = TcpListener::bind("localhost:12345");
///
/// let mut udp_s = UdpSocket::bind(("127.0.0.1", 23451)).unwrap();
-/// udp_s.send_to([7, 7, 7].as_slice(), (Ipv4Addr(127, 0, 0, 1), 23451));
+/// udp_s.send_to([7, 7, 7].as_ref(), (Ipv4Addr(127, 0, 0, 1), 23451));
/// }
/// ```
pub trait ToSocketAddr {
use os;
use old_io::pipe::PipeStream;
- let os::Pipe { reader, writer } = unsafe { os::pipe().unwrap() };
- let out = PipeStream::open(writer);
- let mut input = PipeStream::open(reader);
+ let (reader, writer) = unsafe { ::sys::os::pipe().unwrap() };
+ let out = PipeStream::open(writer.unwrap());
+ let mut input = PipeStream::open(reader.unwrap());
let (tx, rx) = channel();
let _t = thread::spawn(move|| {
let mut out = out;
None => {
// if the env is currently just inheriting from the parent's,
// materialize the parent's env into a hashtable.
- self.env = Some(os::env_as_bytes().into_iter().map(|(k, v)| {
+ self.env = Some(::env::vars().map(|(k, v)| {
(EnvKey(CString::new(k).unwrap()),
CString::new(v).unwrap())
}).collect());
/// # Examples
///
/// ```
- /// # #![feature(old_io, core)]
+ /// # #![feature(old_io, core, convert)]
/// use std::old_io::Command;
///
/// let output = match Command::new("cat").arg("foot.txt").output() {
/// };
///
/// println!("status: {}", output.status);
- /// println!("stdout: {}", String::from_utf8_lossy(output.output.as_slice()));
- /// println!("stderr: {}", String::from_utf8_lossy(output.error.as_slice()));
+ /// println!("stdout: {}", String::from_utf8_lossy(output.output.as_ref()));
+ /// println!("stderr: {}", String::from_utf8_lossy(output.error.as_ref()));
/// ```
pub fn output(&self) -> IoResult<ProcessOutput> {
self.spawn().and_then(|p| p.wait_with_output())
#[cfg(test)]
mod tests {
+ use prelude::v1::*;
use old_io::{Truncate, Write, TimedOut, timer, process, FileNotFound};
use old_io::{Reader, Writer};
- use prelude::v1::{Ok, Err, drop, Some, None, Vec};
- use prelude::v1::{String, Clone};
- use prelude::v1::{Str, AsSlice, ToString};
use old_path::{GenericPath, Path};
use old_io::fs::PathExtensions;
use old_io::timer::*;
let prog = pwd_cmd().spawn().unwrap();
let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
- let parent_dir = os::getcwd().unwrap();
+ let parent_dir = Path::new(::env::current_dir().unwrap().to_str().unwrap());
let child_dir = Path::new(output.trim());
let parent_stat = parent_dir.stat().unwrap();
use os;
// test changing to the parent of os::getcwd() because we know
// the path exists (and os::getcwd() is not expected to be root)
- let parent_dir = os::getcwd().unwrap().dir_path();
+ let parent_dir = Path::new(::env::current_dir().unwrap().to_str().unwrap());
let prog = pwd_cmd().cwd(&parent_dir).spawn().unwrap();
let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
let prog = env_cmd().spawn().unwrap();
let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
- let r = os::env();
- for &(ref k, ref v) in &r {
+ let r = ::env::vars();
+ for (k, v) in r {
// don't check windows magical empty-named variables
assert!(k.is_empty() ||
- output.contains(&format!("{}={}", *k, *v)),
+ output.contains(&format!("{}={}", k, v)),
"output doesn't contain `{}={}`\n{}",
k, v, output);
}
let mut prog = env_cmd().spawn().unwrap();
let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
- let r = os::env();
- for &(ref k, ref v) in &r {
+ let r = ::env::vars();
+ for (k, v) in r {
// don't check android RANDOM variables
- if *k != "RANDOM".to_string() {
- assert!(output.contains(&format!("{}={}",
- *k,
- *v)) ||
- output.contains(&format!("{}=\'{}\'",
- *k,
- *v)));
+ if k != "RANDOM".to_string() {
+ assert!(output.contains(&format!("{}={}", k, v)) ||
+ output.contains(&format!("{}=\'{}\'", k, v)));
}
}
}
// PATH to our sub-process.
let path_val: String;
let mut new_env = vec![("RUN_TEST_NEW_ENV", "123")];
- match os::getenv("PATH") {
- None => {}
- Some(val) => {
+ match ::env::var("PATH") {
+ Err(..) => {}
+ Ok(val) => {
path_val = val;
new_env.push(("PATH", &path_val))
}
#[allow(deprecated)]
pub fn new_in(tmpdir: &Path, prefix: &str) -> IoResult<TempDir> {
if !tmpdir.is_absolute() {
- let cur_dir = try!(::os::getcwd());
+ let cur_dir = ::env::current_dir().unwrap();
+ let cur_dir = Path::new(cur_dir.to_str().unwrap());
return TempDir::new_in(&cur_dir.join(tmpdir), prefix);
}
/// If no directory can be created, `Err` is returned.
#[allow(deprecated)]
pub fn new(prefix: &str) -> IoResult<TempDir> {
- TempDir::new_in(&::os::tmpdir(), prefix)
+ let tmp = Path::new(::env::temp_dir().to_str().unwrap());
+ TempDir::new_in(&tmp, prefix)
}
/// Unwrap the wrapped `std::path::Path` from the `TempDir` wrapper.
pub fn next_test_unix() -> Path {
let string = next_test_unix_socket();
if cfg!(unix) {
- ::os::tmpdir().join(string)
+ Path::new(::env::temp_dir().to_str().unwrap()).join(string)
} else {
Path::new(format!("{}{}", r"\\.\pipe\", string))
}
// sysctl value, and bump the soft resource limit for maxfiles up to the sysctl value.
use ptr::null_mut;
use mem::size_of_val;
- use os::last_os_error;
+ use io;
// Fetch the kern.maxfilesperproc value
let mut mib: [libc::c_int; 2] = [CTL_KERN, KERN_MAXFILESPERPROC];
let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t;
if sysctl(&mut mib[0], 2, &mut maxfiles as *mut libc::c_int as *mut libc::c_void, &mut size,
null_mut(), 0) != 0 {
- let err = last_os_error();
+ let err = io::Error::last_os_error();
panic!("raise_fd_limit: error calling sysctl: {}", err);
}
// Fetch the current resource limits
let mut rlim = rlimit{rlim_cur: 0, rlim_max: 0};
if getrlimit(RLIMIT_NOFILE, &mut rlim) != 0 {
- let err = last_os_error();
+ let err = io::Error::last_os_error();
panic!("raise_fd_limit: error calling getrlimit: {}", err);
}
// Set our newly-increased resource limit
if setrlimit(RLIMIT_NOFILE, &rlim) != 0 {
- let err = last_os_error();
+ let err = io::Error::last_os_error();
panic!("raise_fd_limit: error calling setrlimit: {}", err);
}
}
let mut r = MemReader::new(vec!(0, 1, 2));
{
let mut r = LimitReader::new(r.by_ref(), 4);
- assert_eq!([0, 1, 2], r.read_to_end().unwrap());
+ assert_eq!(r.read_to_end().unwrap(), [0, 1, 2]);
}
}
let mut r = MemReader::new(vec!(0, 1, 2));
{
let mut r = LimitReader::new(r.by_ref(), 2);
- assert_eq!([0, 1], r.read_to_end().unwrap());
+ assert_eq!(r.read_to_end().unwrap(), [0, 1]);
}
- assert_eq!([2], r.read_to_end().unwrap());
+ assert_eq!(r.read_to_end().unwrap(), [2]);
}
#[test]
assert_eq!(3, r.limit());
assert_eq!(0, r.read_byte().unwrap());
assert_eq!(2, r.limit());
- assert_eq!([1, 2], r.read_to_end().unwrap());
+ assert_eq!(r.read_to_end().unwrap(), [1, 2]);
assert_eq!(0, r.limit());
}
let mut r = MemReader::new(vec![0, 1, 2, 3, 4, 5]);
let mut r = LimitReader::new(r.by_ref(), 1);
r.consume(2);
- assert_eq!([], r.read_to_end().unwrap());
+ assert_eq!(r.read_to_end().unwrap(), []);
}
#[test]
let mut s = ZeroReader;
let mut buf = vec![1, 2, 3];
assert_eq!(s.read(&mut buf), Ok(3));
- assert_eq!([0, 0, 0], buf);
+ assert_eq!(buf, [0, 0, 0]);
}
#[test]
let rs = vec!(MemReader::new(vec!(0, 1)), MemReader::new(vec!()),
MemReader::new(vec!(2, 3)));
let mut r = ChainedReader::new(rs.into_iter());
- assert_eq!([0, 1, 2, 3], r.read_to_end().unwrap());
+ assert_eq!(r.read_to_end().unwrap(), [0, 1, 2, 3]);
}
#[test]
fn test_tee_reader() {
let mut r = TeeReader::new(MemReader::new(vec!(0, 1, 2)),
Vec::new());
- assert_eq!([0, 1, 2], r.read_to_end().unwrap());
+ assert_eq!(r.read_to_end().unwrap(), [0, 1, 2]);
let (_, w) = r.into_inner();
- assert_eq!([0, 1, 2], w);
+ assert_eq!(w, [0, 1, 2]);
}
#[test]
let mut r = MemReader::new(vec!(0, 1, 2, 3, 4));
let mut w = Vec::new();
copy(&mut r, &mut w).unwrap();
- assert_eq!([0, 1, 2, 3, 4], w);
+ assert_eq!(w, [0, 1, 2, 3, 4]);
}
#[test]
use core::marker::Sized;
use ffi::CString;
use clone::Clone;
+use borrow::Cow;
use fmt;
use iter::Iterator;
use option::Option;
use option::Option::{None, Some};
use str;
-use string::{String, CowString};
+use string::String;
use vec::Vec;
/// Typedef for POSIX file paths.
/// If the path is not UTF-8, invalid sequences will be replaced with the
/// Unicode replacement char. This involves allocation.
#[inline]
- pub fn as_cow(&self) -> CowString<'a> {
+ pub fn as_cow(&self) -> Cow<'a, str> {
String::from_utf8_lossy(if self.filename {
match self.path.filename() {
None => {
use marker::Sized;
use option::Option::{self, Some, None};
use result::Result::{self, Ok, Err};
-use slice::{AsSlice, Split, SliceConcatExt};
+use slice::{Split, SliceConcatExt};
use str::{self, FromStr};
use vec::Vec;
unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T) {
let filename = filename.container_as_bytes();
match self.sepidx {
- None if b".." == self.repr => {
+ None if self.repr == b".." => {
let mut v = Vec::with_capacity(3 + filename.len());
v.push_all(dot_dot_static);
v.push(SEP_BYTE);
fn dirname<'a>(&'a self) -> &'a [u8] {
match self.sepidx {
- None if b".." == self.repr => &self.repr,
+ None if self.repr == b".." => &self.repr,
None => dot_static,
Some(0) => &self.repr[..1],
Some(idx) if &self.repr[idx+1..] == b".." => &self.repr,
fn filename<'a>(&'a self) -> Option<&'a [u8]> {
match self.sepidx {
- None if b"." == self.repr ||
- b".." == self.repr => None,
+ None if self.repr == b"." || self.repr == b".." => None,
None => Some(&self.repr),
Some(idx) if &self.repr[idx+1..] == b".." => None,
Some(0) if self.repr[1..].is_empty() => None,
fn pop(&mut self) -> bool {
match self.sepidx {
- None if b"." == self.repr => false,
+ None if self.repr == b"." => false,
None => {
self.repr = vec![b'.'];
self.sepidx = None;
true
}
- Some(0) if b"/" == self.repr => false,
+ Some(0) if self.repr == b"/" => false,
Some(idx) => {
if idx == 0 {
self.repr.truncate(idx+1);
} else {
let mut ita = self.components();
let mut itb = other.components();
- if b"." == self.repr {
+ if self.repr == b"." {
return match itb.next() {
None => true,
Some(b) => b != b".."
/// Returns a normalized byte vector representation of a path, by removing all empty
/// components, and unnecessary . and .. components.
- fn normalize<V: ?Sized + AsSlice<u8>>(v: &V) -> Vec<u8> {
+ fn normalize(v: &[u8]) -> Vec<u8> {
// borrowck is being very picky
let val = {
- let is_abs = !v.as_slice().is_empty() && v.as_slice()[0] == SEP_BYTE;
- let v_ = if is_abs { &v.as_slice()[1..] } else { v.as_slice() };
+ let is_abs = !v.is_empty() && v[0] == SEP_BYTE;
+ let v_ = if is_abs { &v[1..] } else { v };
let comps = normalize_helper(v_, is_abs);
match comps {
None => None,
}
};
match val {
- None => v.as_slice().to_vec(),
+ None => v.to_vec(),
Some(val) => val
}
}
use clone::Clone;
use option::Option::{self, Some, None};
use old_path::GenericPath;
- use slice::AsSlice;
- use str::{self, Str};
+ use str;
use string::ToString;
use vec::Vec;
use iter::Iterator;
use iter::Iterator;
use option::Option::{self, Some, None};
use old_path::GenericPath;
- use slice::AsSlice;
- use str::Str;
use string::ToString;
use vec::Vec;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Higher-level interfaces to libc::* functions and operating system services.
-//!
-//! In general these take and return rust types, use rust idioms (enums,
-//! closures, vectors) rather than C idioms, and do more extensive safety
-//! checks.
-//!
-//! This module is not meant to only contain 1:1 mappings to libc entries; any
-//! os-interface code that is reasonably useful and broadly applicable can go
-//! here. Including utility routines that merely build on other os code.
-//!
-//! We assume the general case is that users do not care, and do not want to be
-//! made to care, which operating system they are on. While they may want to
-//! special case various special cases -- and so we will not _hide_ the facts of
-//! which OS the user is on -- they should be given the opportunity to write
-//! OS-ignorant code by default.
+//! OS-specific functionality
-#![unstable(feature = "os")]
-#![deprecated(since = "1.0.0", reason = "replaced with std::env APIs")]
-
-#![allow(missing_docs)]
-#![allow(non_snake_case)]
-#![allow(unused_imports)]
-#![allow(deprecated)]
-
-use self::MemoryMapKind::*;
-use self::MapOption::*;
-use self::MapError::*;
-
-use boxed::Box;
-use clone::Clone;
-use convert::From;
-use env;
-use error::{FromError, Error};
-use ffi::{OsString, OsStr};
-use fmt;
-use iter::Iterator;
-use libc::{c_void, c_int, c_char};
-use libc;
-use marker::{Copy, Send};
-use old_io::{IoResult, IoError};
-use ops::{Drop, FnOnce};
-use option::Option::{Some, None};
-use option::Option;
-use old_path::{Path, GenericPath, BytesContainer};
-use path::{self, PathBuf};
-use ptr;
-use result::Result::{Err, Ok};
-use result::Result;
-use slice::AsSlice;
-use str::Str;
-use str;
-use string::{String, ToString};
-use sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT, Ordering};
-use sys::os as os_imp;
-use sys;
-use vec::Vec;
-
-#[cfg(unix)] use ffi::{self, CString};
+#![stable(feature = "os", since = "1.0.0")]
#[cfg(unix)] pub use sys::ext as unix;
#[cfg(windows)] pub use sys::ext as windows;
-
-fn err2old(new: ::io::Error) -> IoError {
- IoError {
- kind: ::old_io::OtherIoError,
- desc: "os error",
- detail: Some(new.to_string()),
- }
-}
-
-#[cfg(windows)]
-fn path2new(path: &Path) -> PathBuf {
- PathBuf::from(path.as_str().unwrap())
-}
-#[cfg(unix)]
-fn path2new(path: &Path) -> PathBuf {
- use os::unix::prelude::*;
- PathBuf::from(<OsStr as OsStrExt>::from_bytes(path.as_vec()))
-}
-
-#[cfg(unix)]
-fn path2old(path: &path::Path) -> Path {
- use os::unix::prelude::*;
- use ffi::AsOsStr;
- Path::new(path.as_os_str().as_bytes())
-}
-#[cfg(windows)]
-fn path2old(path: &path::Path) -> Path {
- Path::new(path.to_str().unwrap())
-}
-
-/// Get the number of cores available
-pub fn num_cpus() -> usize {
- unsafe {
- return rust_get_num_cpus() as usize;
- }
-
- extern {
- fn rust_get_num_cpus() -> libc::uintptr_t;
- }
-}
-
-pub const TMPBUF_SZ : usize = 1000;
-
-/// Returns the current working directory as a `Path`.
-///
-/// # Errors
-///
-/// Returns an `Err` if the current working directory value is invalid.
-/// Possible cases:
-///
-/// * Current directory does not exist.
-/// * There are insufficient permissions to access the current directory.
-/// * The internal buffer is not large enough to hold the path.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os, old_path)]
-/// use std::os;
-/// use std::old_path::{Path, GenericPath};
-///
-/// // We assume that we are in a valid directory.
-/// let current_working_directory = os::getcwd().unwrap();
-/// println!("The current directory is {:?}", current_working_directory.display());
-/// ```
-#[unstable(feature = "os")]
-pub fn getcwd() -> IoResult<Path> {
- env::current_dir().map_err(err2old).map(|s| path2old(&s))
-}
-
-/// Returns a vector of (variable, value) pairs, for all the environment
-/// variables of the current process.
-///
-/// Invalid UTF-8 bytes are replaced with \uFFFD. See `String::from_utf8_lossy()`
-/// for details.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os)]
-/// use std::os;
-///
-/// // We will iterate through the references to the element returned by os::env();
-/// for &(ref key, ref value) in os::env().iter() {
-/// println!("'{}': '{}'", key, value );
-/// }
-/// ```
-#[deprecated(since = "1.0.0", reason = "use env::vars instead")]
-#[unstable(feature = "os")]
-pub fn env() -> Vec<(String,String)> {
- env::vars_os().map(|(k, v)| {
- (k.to_string_lossy().into_owned(), v.to_string_lossy().into_owned())
- }).collect()
-}
-
-/// Returns a vector of (variable, value) byte-vector pairs for all the
-/// environment variables of the current process.
-#[deprecated(since = "1.0.0", reason = "use env::vars_os instead")]
-#[unstable(feature = "os")]
-pub fn env_as_bytes() -> Vec<(Vec<u8>, Vec<u8>)> {
- env::vars_os().map(|(k, v)| (byteify(k), byteify(v))).collect()
-}
-
-/// Fetches the environment variable `n` from the current process, returning
-/// None if the variable isn't set.
-///
-/// Any invalid UTF-8 bytes in the value are replaced by \uFFFD. See
-/// `String::from_utf8_lossy()` for details.
-///
-/// # Panics
-///
-/// Panics if `n` has any interior NULs.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os)]
-/// use std::os;
-///
-/// let key = "HOME";
-/// match os::getenv(key) {
-/// Some(val) => println!("{}: {}", key, val),
-/// None => println!("{} is not defined in the environment.", key)
-/// }
-/// ```
-#[deprecated(since = "1.0.0", reason = "use env::var instead")]
-#[unstable(feature = "os")]
-pub fn getenv(n: &str) -> Option<String> {
- env::var(n).ok()
-}
-
-/// Fetches the environment variable `n` byte vector from the current process,
-/// returning None if the variable isn't set.
-///
-/// # Panics
-///
-/// Panics if `n` has any interior NULs.
-#[deprecated(since = "1.0.0", reason = "use env::var_os instead")]
-#[unstable(feature = "os")]
-pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
- env::var_os(n).map(byteify)
-}
-
-#[cfg(unix)]
-fn byteify(s: OsString) -> Vec<u8> {
- use os::unix::prelude::*;
- s.into_vec()
-}
-#[cfg(windows)]
-fn byteify(s: OsString) -> Vec<u8> {
- s.to_string_lossy().as_bytes().to_vec()
-}
-
-/// Sets the environment variable `n` to the value `v` for the currently running
-/// process.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os)]
-/// use std::os;
-///
-/// let key = "KEY";
-/// os::setenv(key, "VALUE");
-/// match os::getenv(key) {
-/// Some(ref val) => println!("{}: {}", key, val),
-/// None => println!("{} is not defined in the environment.", key)
-/// }
-/// ```
-#[deprecated(since = "1.0.0", reason = "renamed to env::set_var")]
-#[unstable(feature = "os")]
-pub fn setenv<T: BytesContainer>(n: &str, v: T) {
- #[cfg(unix)]
- fn _setenv(n: &str, v: &[u8]) {
- use os::unix::prelude::*;
- let v: OsString = OsStringExt::from_vec(v.to_vec());
- env::set_var(n, &v)
- }
-
- #[cfg(windows)]
- fn _setenv(n: &str, v: &[u8]) {
- let v = str::from_utf8(v).unwrap();
- env::set_var(n, v)
- }
-
- _setenv(n, v.container_as_bytes())
-}
-
-/// Remove a variable from the environment entirely.
-#[deprecated(since = "1.0.0", reason = "renamed to env::remove_var")]
-#[unstable(feature = "os")]
-pub fn unsetenv(n: &str) {
- env::remove_var(n)
-}
-
-/// Parses input according to platform conventions for the `PATH`
-/// environment variable.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(old_path, os)]
-/// use std::os;
-/// use std::old_path::{Path, GenericPath};
-///
-/// let key = "PATH";
-/// match os::getenv_as_bytes(key) {
-/// Some(paths) => {
-/// for path in os::split_paths(paths).iter() {
-/// println!("'{}'", path.display());
-/// }
-/// }
-/// None => println!("{} is not defined in the environment.", key)
-/// }
-/// ```
-#[unstable(feature = "os")]
-pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
- let b = unparsed.container_as_bytes();
- let s = str::from_utf8(b).unwrap();
- env::split_paths(s).map(|s| path2old(&s)).collect()
-}
-
-/// Joins a collection of `Path`s appropriately for the `PATH`
-/// environment variable.
-///
-/// Returns a `Vec<u8>` on success, since `Path`s are not utf-8
-/// encoded on all platforms.
-///
-/// Returns an `Err` (containing an error message) if one of the input
-/// `Path`s contains an invalid character for constructing the `PATH`
-/// variable (a double quote on Windows or a colon on Unix).
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os, old_path, core)]
-/// use std::os;
-/// use std::old_path::Path;
-///
-/// let key = "PATH";
-/// let mut paths = os::getenv_as_bytes(key).map_or(Vec::new(), os::split_paths);
-/// paths.push(Path::new("/home/xyz/bin"));
-/// os::setenv(key, os::join_paths(paths.as_slice()).unwrap());
-/// ```
-#[unstable(feature = "os")]
-pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
- env::join_paths(paths.iter().map(|s| {
- str::from_utf8(s.container_as_bytes()).unwrap()
- })).map(|s| {
- s.to_string_lossy().into_owned().into_bytes()
- }).map_err(|_| "failed to join paths")
-}
-
-/// A low-level OS in-memory pipe.
-#[derive(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.
- pub reader: c_int,
- /// A file descriptor representing the write end of the pipe. Data written
- /// to this file descriptor can be read from the `input` file descriptor.
- pub writer: c_int,
-}
-
-/// Creates a new low-level OS in-memory pipe.
-///
-/// This function can fail to succeed if there are no more resources available
-/// to allocate a pipe.
-///
-/// This function is also unsafe as there is no destructor associated with the
-/// `Pipe` structure will return. If it is not arranged for the returned file
-/// descriptors to be closed, the file descriptors will leak. For safe handling
-/// of this scenario, use `std::old_io::PipeStream` instead.
-pub unsafe fn pipe() -> IoResult<Pipe> {
- let (reader, writer) = try!(sys::os::pipe());
- Ok(Pipe {
- reader: reader.unwrap(),
- writer: writer.unwrap(),
- })
-}
-
-/// Returns the proper dll filename for the given basename of a file
-/// as a String.
-#[cfg(not(target_os="ios"))]
-#[deprecated(since = "1.0.0", reason = "this function will be removed, use the constants directly")]
-#[unstable(feature = "os")]
-#[allow(deprecated)]
-pub fn dll_filename(base: &str) -> String {
- format!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX)
-}
-
-/// Optionally returns the filesystem path to the current executable which is
-/// running but with the executable name.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os, old_path)]
-/// use std::os;
-/// use std::old_path::{Path, GenericPath};
-///
-/// match os::self_exe_name() {
-/// Some(exe_path) => println!("Path of this executable is: {}", exe_path.display()),
-/// None => println!("Unable to get the path of this executable!")
-/// };
-/// ```
-#[unstable(feature = "os")]
-pub fn self_exe_name() -> Option<Path> {
- env::current_exe().ok().map(|p| path2old(&p))
-}
-
-/// Optionally returns the filesystem path to the current executable which is
-/// running.
-///
-/// Like self_exe_name() but without the binary's name.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os, old_path)]
-/// use std::os;
-/// use std::old_path::{Path, GenericPath};
-///
-/// match os::self_exe_path() {
-/// Some(exe_path) => println!("Executable's Path is: {}", exe_path.display()),
-/// None => println!("Impossible to fetch the path of this executable.")
-/// };
-/// ```
-#[unstable(feature = "os")]
-pub fn self_exe_path() -> Option<Path> {
- env::current_exe().ok().map(|p| { let mut p = path2old(&p); p.pop(); p })
-}
-
-/// Optionally returns the path to the current user's home directory if known.
-///
-/// # Unix
-///
-/// Returns the value of the 'HOME' environment variable if it is set
-/// and not equal to the empty string.
-///
-/// # Windows
-///
-/// Returns the value of the 'HOME' environment variable if it is
-/// set and not equal to the empty string. Otherwise, returns the value of the
-/// 'USERPROFILE' environment variable if it is set and not equal to the empty
-/// string.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os, old_path)]
-/// use std::os;
-/// use std::old_path::{Path, GenericPath};
-///
-/// match os::homedir() {
-/// Some(ref p) => println!("{}", p.display()),
-/// None => println!("Impossible to get your home dir!")
-/// }
-/// ```
-#[unstable(feature = "os")]
-#[allow(deprecated)]
-pub fn homedir() -> Option<Path> {
- #[inline]
- #[cfg(unix)]
- fn _homedir() -> Option<Path> {
- aux_homedir("HOME")
- }
-
- #[inline]
- #[cfg(windows)]
- fn _homedir() -> Option<Path> {
- aux_homedir("HOME").or(aux_homedir("USERPROFILE"))
- }
-
- #[inline]
- fn aux_homedir(home_name: &str) -> Option<Path> {
- match getenv_as_bytes(home_name) {
- Some(p) => {
- if p.is_empty() { None } else { Path::new_opt(p) }
- },
- _ => None
- }
- }
- _homedir()
-}
-
-/// Returns the path to a temporary directory.
-///
-/// On Unix, returns the value of the 'TMPDIR' environment variable if it is
-/// set, otherwise for non-Android it returns '/tmp'. If Android, since there
-/// is no global temporary folder (it is usually allocated per-app), we return
-/// '/data/local/tmp'.
-///
-/// On Windows, returns the value of, in order, the 'TMP', 'TEMP',
-/// 'USERPROFILE' environment variable if any are set and not the empty
-/// string. Otherwise, tmpdir returns the path to the Windows directory.
-#[unstable(feature = "os")]
-#[allow(deprecated)]
-pub fn tmpdir() -> Path {
- return lookup();
-
- fn getenv_nonempty(v: &str) -> Option<Path> {
- match getenv(v) {
- Some(x) =>
- if x.is_empty() {
- None
- } else {
- Path::new_opt(x)
- },
- _ => None
- }
- }
-
- #[cfg(unix)]
- fn lookup() -> Path {
- let default = if cfg!(target_os = "android") {
- Path::new("/data/local/tmp")
- } else {
- Path::new("/tmp")
- };
-
- getenv_nonempty("TMPDIR").unwrap_or(default)
- }
-
- #[cfg(windows)]
- fn lookup() -> Path {
- getenv_nonempty("TMP").or(
- getenv_nonempty("TEMP").or(
- getenv_nonempty("USERPROFILE").or(
- getenv_nonempty("WINDIR")))).unwrap_or(Path::new("C:\\Windows"))
- }
-}
-
-/// Convert a relative path to an absolute path
-///
-/// If the given path is relative, return it prepended with the current working
-/// directory. If the given path is already an absolute path, return it
-/// as is.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os, old_path)]
-/// use std::os;
-/// use std::old_path::{Path, GenericPath};
-///
-/// // Assume we're in a path like /home/someuser
-/// let rel_path = Path::new("..");
-/// let abs_path = os::make_absolute(&rel_path).unwrap();
-/// println!("The absolute path is {}", abs_path.display());
-/// // Prints "The absolute path is /home"
-/// ```
-// NB: this is here rather than in path because it is a form of environment
-// querying; what it does depends on the process working directory, not just
-// the input paths.
-#[deprecated(since = "1.0.0", reason = "use env::current_dir + .join directly")]
-#[unstable(feature = "os")]
-pub fn make_absolute(p: &Path) -> IoResult<Path> {
- if p.is_absolute() {
- Ok(p.clone())
- } else {
- env::current_dir().map_err(err2old).map(|cwd| {
- let mut cwd = path2old(&cwd);
- cwd.push(p);
- cwd
- })
- }
-}
-
-/// Changes the current working directory to the specified path, returning
-/// whether the change was completed successfully or not.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os, old_path)]
-/// use std::os;
-/// use std::old_path::{Path, GenericPath};
-///
-/// let root = Path::new("/");
-/// assert!(os::change_dir(&root).is_ok());
-/// println!("Successfully changed working directory to {}!", root.display());
-/// ```
-#[unstable(feature = "os")]
-pub fn change_dir(p: &Path) -> IoResult<()> {
- sys::os::chdir(&path2new(p)).map_err(err2old)
-}
-
-/// Returns the platform-specific value of errno
-pub fn errno() -> i32 {
- sys::os::errno() as i32
-}
-
-/// Return the string corresponding to an `errno()` value of `errnum`.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(os)]
-/// use std::os;
-///
-/// // Same as println!("{}", last_os_error());
-/// println!("{}", os::error_string(os::errno() as i32));
-/// ```
-pub fn error_string(errnum: i32) -> String {
- return sys::os::error_string(errnum);
-}
-
-/// Get a string representing the platform-dependent last error
-pub fn last_os_error() -> String {
- error_string(errno())
-}
-
-/// Sets the process exit code
-///
-/// Sets the exit code returned by the process if all supervised tasks
-/// terminate successfully (without panicking). If the current root task panics
-/// and is supervised by the scheduler then any user-specified exit status is
-/// ignored and the process exits with the default panic status.
-///
-/// Note that this is not synchronized against modifications of other threads.
-#[deprecated(since = "1.0.0", reason = "renamed to env::set_exit_status")]
-#[unstable(feature = "os")]
-pub fn set_exit_status(code: isize) {
- env::set_exit_status(code as i32)
-}
-
-/// Fetches the process's current exit code. This defaults to 0 and can change
-/// by calling `set_exit_status`.
-#[deprecated(since = "1.0.0", reason = "renamed to env::get_exit_status")]
-#[unstable(feature = "os")]
-pub fn get_exit_status() -> isize {
- env::get_exit_status() as isize
-}
-
-#[cfg(target_os = "macos")]
-unsafe fn load_argc_and_argv(argc: isize,
- argv: *const *const c_char) -> Vec<Vec<u8>> {
- use ffi::CStr;
-
- (0..argc).map(|i| {
- CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec()
- }).collect()
-}
-
-/// Returns the command line arguments
-///
-/// Returns a list of the command line arguments.
-#[cfg(target_os = "macos")]
-fn real_args_as_bytes() -> Vec<Vec<u8>> {
- unsafe {
- let (argc, argv) = (*_NSGetArgc() as isize,
- *_NSGetArgv() as *const *const c_char);
- load_argc_and_argv(argc, argv)
- }
-}
-
-// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
-// and use underscores in their names - they're most probably
-// are considered private and therefore should be avoided
-// Here is another way to get arguments using Objective C
-// runtime
-//
-// In general it looks like:
-// res = Vec::new()
-// let args = [[NSProcessInfo processInfo] arguments]
-// for i in 0..[args count]
-// res.push([args objectAtIndex:i])
-// res
-#[cfg(target_os = "ios")]
-fn real_args_as_bytes() -> Vec<Vec<u8>> {
- use ffi::CStr;
- use iter::range;
- use mem;
-
- #[link(name = "objc")]
- extern {
- fn sel_registerName(name: *const libc::c_uchar) -> Sel;
- fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
- fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
- }
-
- #[link(name = "Foundation", kind = "framework")]
- extern {}
-
- type Sel = *const libc::c_void;
- type NsId = *const libc::c_void;
-
- let mut res = Vec::new();
-
- unsafe {
- let processInfoSel = sel_registerName("processInfo\0".as_ptr());
- let argumentsSel = sel_registerName("arguments\0".as_ptr());
- let utf8Sel = sel_registerName("UTF8String\0".as_ptr());
- let countSel = sel_registerName("count\0".as_ptr());
- let objectAtSel = sel_registerName("objectAtIndex:\0".as_ptr());
-
- let klass = objc_getClass("NSProcessInfo\0".as_ptr());
- let info = objc_msgSend(klass, processInfoSel);
- let args = objc_msgSend(info, argumentsSel);
-
- let cnt: isize = mem::transmute(objc_msgSend(args, countSel));
- for i in 0..cnt {
- let tmp = objc_msgSend(args, objectAtSel, i);
- let utf_c_str: *const libc::c_char =
- mem::transmute(objc_msgSend(tmp, utf8Sel));
- res.push(CStr::from_ptr(utf_c_str).to_bytes().to_vec());
- }
- }
-
- res
-}
-
-#[cfg(any(target_os = "linux",
- target_os = "android",
- target_os = "freebsd",
- target_os = "dragonfly",
- target_os = "bitrig",
- target_os = "openbsd"))]
-fn real_args_as_bytes() -> Vec<Vec<u8>> {
- use rt;
- rt::args::clone().unwrap_or_else(|| vec![])
-}
-
-#[cfg(not(windows))]
-fn real_args() -> Vec<String> {
- real_args_as_bytes().into_iter()
- .map(|v| {
- String::from_utf8_lossy(&v).into_owned()
- }).collect()
-}
-
-#[cfg(windows)]
-fn real_args() -> Vec<String> {
- use slice;
- use iter::range;
-
- let mut nArgs: c_int = 0;
- let lpArgCount: *mut c_int = &mut nArgs;
- let lpCmdLine = unsafe { GetCommandLineW() };
- let szArgList = unsafe { CommandLineToArgvW(lpCmdLine, lpArgCount) };
-
- let args: Vec<_> = (0..nArgs as usize).map(|i| unsafe {
- // Determine the length of this argument.
- let ptr = *szArgList.offset(i as isize);
- let mut len = 0;
- while *ptr.offset(len as isize) != 0 { len += 1; }
-
- // Push it onto the list.
- let ptr = ptr as *const u16;
- let buf = slice::from_raw_parts(ptr, len);
- let opt_s = String::from_utf16(sys::truncate_utf16_at_nul(buf));
- opt_s.ok().expect("CommandLineToArgvW returned invalid UTF-16")
- }).collect();
-
- unsafe {
- LocalFree(szArgList as *mut c_void);
- }
-
- return args
-}
-
-#[cfg(windows)]
-fn real_args_as_bytes() -> Vec<Vec<u8>> {
- real_args().into_iter().map(|s| s.into_bytes()).collect()
-}
-
-type LPCWSTR = *const u16;
-
-#[cfg(windows)]
-#[link_name="kernel32"]
-extern "system" {
- fn GetCommandLineW() -> LPCWSTR;
- fn LocalFree(ptr: *mut c_void);
-}
-
-#[cfg(windows)]
-#[link_name="shell32"]
-extern "system" {
- fn CommandLineToArgvW(lpCmdLine: LPCWSTR,
- pNumArgs: *mut c_int) -> *mut *mut u16;
-}
-
-/// Returns the arguments which this program was started with (normally passed
-/// via the command line).
-///
-/// The first element is traditionally the path to the executable, but it can be
-/// set to arbitrary text, and it may not even exist, so this property should not
-/// be relied upon for security purposes.
-///
-/// The arguments are interpreted as utf-8, with invalid bytes replaced with \uFFFD.
-/// See `String::from_utf8_lossy` for details.
-/// # Examples
-///
-/// ```
-/// # #![feature(os)]
-/// use std::os;
-///
-/// // Prints each argument on a separate line
-/// for argument in os::args().iter() {
-/// println!("{}", argument);
-/// }
-/// ```
-#[deprecated(since = "1.0.0", reason = "use std::env::args() instead")]
-#[unstable(feature = "os")]
-pub fn args() -> Vec<String> {
- real_args()
-}
-
-/// Returns the arguments which this program was started with (normally passed
-/// via the command line) as byte vectors.
-#[deprecated(since = "1.0.0", reason = "use env::args_os instead")]
-#[unstable(feature = "os")]
-pub fn args_as_bytes() -> Vec<Vec<u8>> {
- real_args_as_bytes()
-}
-
-#[cfg(target_os = "macos")]
-extern {
- // These functions are in crt_externs.h.
- fn _NSGetArgc() -> *mut c_int;
- fn _NSGetArgv() -> *mut *mut *mut c_char;
-}
-
-/// Returns the page size of the current architecture in bytes.
-#[deprecated(since = "1.0.0", reason = "renamed to env::page_size")]
-#[unstable(feature = "os")]
-pub fn page_size() -> usize {
- sys::os::page_size()
-}
-
-/// A memory mapped file or chunk of memory. This is a very system-specific
-/// interface to the OS's memory mapping facilities (`mmap` on POSIX,
-/// `VirtualAlloc`/`CreateFileMapping` on Windows). It makes no attempt at
-/// abstracting platform differences, besides in error values returned. Consider
-/// yourself warned.
-///
-/// The memory map is released (unmapped) when the destructor is run, so don't
-/// let it leave scope by accident if you want it to stick around.
-pub struct MemoryMap {
- data: *mut u8,
- len: usize,
- kind: MemoryMapKind,
-}
-
-/// Type of memory map
-#[allow(raw_pointer_derive)]
-#[derive(Copy)]
-pub enum MemoryMapKind {
- /// Virtual memory map. Usually used to change the permissions of a given
- /// chunk of memory. Corresponds to `VirtualAlloc` on Windows.
- MapFile(*const u8),
- /// Virtual memory map. Usually used to change the permissions of a given
- /// chunk of memory, or for allocation. Corresponds to `VirtualAlloc` on
- /// Windows.
- MapVirtual
-}
-
-/// Options the memory map is created with
-#[allow(raw_pointer_derive)]
-#[derive(Copy)]
-pub enum MapOption {
- /// The memory should be readable
- MapReadable,
- /// The memory should be writable
- MapWritable,
- /// The memory should be executable
- MapExecutable,
- /// Create a map for a specific address range. Corresponds to `MAP_FIXED` on
- /// POSIX.
- MapAddr(*const u8),
- /// Create a memory mapping for a file with a given HANDLE.
- #[cfg(windows)]
- MapFd(libc::HANDLE),
- /// Create a memory mapping for a file with a given fd.
- #[cfg(not(windows))]
- MapFd(c_int),
- /// When using `MapFd`, the start of the map is `usize` bytes from the start
- /// of the file.
- MapOffset(usize),
- /// On POSIX, this can be used to specify the default flags passed to
- /// `mmap`. By default it uses `MAP_PRIVATE` and, if not using `MapFd`,
- /// `MAP_ANON`. This will override both of those. This is platform-specific
- /// (the exact values used) and ignored on Windows.
- MapNonStandardFlags(c_int),
-}
-
-/// Possible errors when creating a map.
-#[derive(Copy, Debug)]
-pub enum MapError {
- /// # The following are POSIX-specific
- ///
- /// fd was not open for reading or, if using `MapWritable`, was not open for
- /// writing.
- ErrFdNotAvail,
- /// fd was not valid
- ErrInvalidFd,
- /// Either the address given by `MapAddr` or offset given by `MapOffset` was
- /// not a multiple of `MemoryMap::granularity` (unaligned to page size).
- ErrUnaligned,
- /// With `MapFd`, the fd does not support mapping.
- ErrNoMapSupport,
- /// If using `MapAddr`, the address + `min_len` was outside of the process's
- /// address space. If using `MapFd`, the target of the fd didn't have enough
- /// resources to fulfill the request.
- ErrNoMem,
- /// A zero-length map was requested. This is invalid according to
- /// [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html).
- /// Not all platforms obey this, but this wrapper does.
- ErrZeroLength,
- /// Unrecognized error. The inner value is the unrecognized errno.
- ErrUnknown(isize),
- /// # The following are Windows-specific
- ///
- /// Unsupported combination of protection flags
- /// (`MapReadable`/`MapWritable`/`MapExecutable`).
- ErrUnsupProt,
- /// When using `MapFd`, `MapOffset` was given (Windows does not support this
- /// at all)
- ErrUnsupOffset,
- /// When using `MapFd`, there was already a mapping to the file.
- ErrAlreadyExists,
- /// Unrecognized error from `VirtualAlloc`. The inner value is the return
- /// value of GetLastError.
- ErrVirtualAlloc(i32),
- /// Unrecognized error from `CreateFileMapping`. The inner value is the
- /// return value of `GetLastError`.
- ErrCreateFileMappingW(i32),
- /// Unrecognized error from `MapViewOfFile`. The inner value is the return
- /// value of `GetLastError`.
- ErrMapViewOfFile(i32)
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for MapError {
- fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
- let str = match *self {
- ErrFdNotAvail => "fd not available for reading or writing",
- ErrInvalidFd => "Invalid fd",
- ErrUnaligned => {
- "Unaligned address, invalid flags, negative length or \
- unaligned offset"
- }
- ErrNoMapSupport=> "File doesn't support mapping",
- ErrNoMem => "Invalid address, or not enough available memory",
- ErrUnsupProt => "Protection mode unsupported",
- ErrUnsupOffset => "Offset in virtual memory mode is unsupported",
- ErrAlreadyExists => "File mapping for specified file already exists",
- ErrZeroLength => "Zero-length mapping not allowed",
- ErrUnknown(code) => {
- return write!(out, "Unknown error = {}", code)
- },
- ErrVirtualAlloc(code) => {
- return write!(out, "VirtualAlloc failure = {}", code)
- },
- ErrCreateFileMappingW(code) => {
- return write!(out, "CreateFileMappingW failure = {}", code)
- },
- ErrMapViewOfFile(code) => {
- return write!(out, "MapViewOfFile failure = {}", code)
- }
- };
- write!(out, "{}", str)
- }
-}
-
-impl Error for MapError {
- fn description(&self) -> &str { "memory map error" }
-}
-
-// Round up `from` to be divisible by `to`
-fn round_up(from: usize, to: usize) -> usize {
- let r = if from % to == 0 {
- from
- } else {
- from + to - (from % to)
- };
- if r == 0 {
- to
- } else {
- r
- }
-}
-
-#[cfg(unix)]
-impl MemoryMap {
- /// Create a new mapping with the given `options`, at least `min_len` bytes
- /// long. `min_len` must be greater than zero; see the note on
- /// `ErrZeroLength`.
- pub fn new(min_len: usize, options: &[MapOption]) -> Result<MemoryMap, MapError> {
- use libc::off_t;
-
- if min_len == 0 {
- return Err(ErrZeroLength)
- }
- let mut addr: *const u8 = ptr::null();
- let mut prot = 0;
- let mut flags = libc::MAP_PRIVATE;
- let mut fd = -1;
- let mut offset = 0;
- let mut custom_flags = false;
- let len = round_up(min_len, env::page_size());
-
- for &o in options {
- match o {
- MapReadable => { prot |= libc::PROT_READ; },
- MapWritable => { prot |= libc::PROT_WRITE; },
- MapExecutable => { prot |= libc::PROT_EXEC; },
- MapAddr(addr_) => {
- flags |= libc::MAP_FIXED;
- addr = addr_;
- },
- MapFd(fd_) => {
- flags |= libc::MAP_FILE;
- fd = fd_;
- },
- MapOffset(offset_) => { offset = offset_ as off_t; },
- MapNonStandardFlags(f) => { custom_flags = true; flags = f },
- }
- }
- if fd == -1 && !custom_flags { flags |= libc::MAP_ANON; }
-
- let r = unsafe {
- libc::mmap(addr as *mut c_void, len as libc::size_t, prot, flags,
- fd, offset)
- };
- if r == libc::MAP_FAILED {
- Err(match errno() as c_int {
- libc::EACCES => ErrFdNotAvail,
- libc::EBADF => ErrInvalidFd,
- libc::EINVAL => ErrUnaligned,
- libc::ENODEV => ErrNoMapSupport,
- libc::ENOMEM => ErrNoMem,
- code => ErrUnknown(code as isize)
- })
- } else {
- Ok(MemoryMap {
- data: r as *mut u8,
- len: len,
- kind: if fd == -1 {
- MapVirtual
- } else {
- MapFile(ptr::null())
- }
- })
- }
- }
-
- /// Granularity that the offset or address must be for `MapOffset` and
- /// `MapAddr` respectively.
- pub fn granularity() -> usize {
- env::page_size()
- }
-}
-
-#[cfg(unix)]
-impl Drop for MemoryMap {
- /// Unmap the mapping. Panics the task if `munmap` panics.
- fn drop(&mut self) {
- if self.len == 0 { /* workaround for dummy_stack */ return; }
-
- unsafe {
- // `munmap` only panics due to logic errors
- libc::munmap(self.data as *mut c_void, self.len as libc::size_t);
- }
- }
-}
-
-#[cfg(windows)]
-impl MemoryMap {
- /// Create a new mapping with the given `options`, at least `min_len` bytes long.
- pub fn new(min_len: usize, options: &[MapOption]) -> Result<MemoryMap, MapError> {
- use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, HANDLE};
-
- let mut lpAddress: LPVOID = ptr::null_mut();
- let mut readable = false;
- let mut writable = false;
- let mut executable = false;
- let mut handle: HANDLE = libc::INVALID_HANDLE_VALUE;
- let mut offset: usize = 0;
- let len = round_up(min_len, env::page_size());
-
- for &o in options {
- match o {
- MapReadable => { readable = true; },
- MapWritable => { writable = true; },
- MapExecutable => { executable = true; }
- MapAddr(addr_) => { lpAddress = addr_ as LPVOID; },
- MapFd(handle_) => { handle = handle_; },
- MapOffset(offset_) => { offset = offset_; },
- MapNonStandardFlags(..) => {}
- }
- }
-
- let flProtect = match (executable, readable, writable) {
- (false, false, false) if handle == libc::INVALID_HANDLE_VALUE => libc::PAGE_NOACCESS,
- (false, true, false) => libc::PAGE_READONLY,
- (false, true, true) => libc::PAGE_READWRITE,
- (true, false, false) if handle == libc::INVALID_HANDLE_VALUE => libc::PAGE_EXECUTE,
- (true, true, false) => libc::PAGE_EXECUTE_READ,
- (true, true, true) => libc::PAGE_EXECUTE_READWRITE,
- _ => return Err(ErrUnsupProt)
- };
-
- if handle == libc::INVALID_HANDLE_VALUE {
- if offset != 0 {
- return Err(ErrUnsupOffset);
- }
- let r = unsafe {
- libc::VirtualAlloc(lpAddress,
- len as SIZE_T,
- libc::MEM_COMMIT | libc::MEM_RESERVE,
- flProtect)
- };
- match r as usize {
- 0 => Err(ErrVirtualAlloc(errno())),
- _ => Ok(MemoryMap {
- data: r as *mut u8,
- len: len,
- kind: MapVirtual
- })
- }
- } else {
- let dwDesiredAccess = match (executable, readable, writable) {
- (false, true, false) => libc::FILE_MAP_READ,
- (false, true, true) => libc::FILE_MAP_WRITE,
- (true, true, false) => libc::FILE_MAP_READ | libc::FILE_MAP_EXECUTE,
- (true, true, true) => libc::FILE_MAP_WRITE | libc::FILE_MAP_EXECUTE,
- _ => return Err(ErrUnsupProt) // Actually, because of the check above,
- // we should never get here.
- };
- unsafe {
- let hFile = handle;
- let mapping = libc::CreateFileMappingW(hFile,
- ptr::null_mut(),
- flProtect,
- 0,
- 0,
- ptr::null());
- if mapping == ptr::null_mut() {
- return Err(ErrCreateFileMappingW(errno()));
- }
- if errno() as c_int == libc::ERROR_ALREADY_EXISTS {
- return Err(ErrAlreadyExists);
- }
- let r = libc::MapViewOfFile(mapping,
- dwDesiredAccess,
- ((len as u64) >> 32) as DWORD,
- (offset & 0xffff_ffff) as DWORD,
- 0);
- match r as usize {
- 0 => Err(ErrMapViewOfFile(errno())),
- _ => Ok(MemoryMap {
- data: r as *mut u8,
- len: len,
- kind: MapFile(mapping as *const u8)
- })
- }
- }
- }
- }
-
- /// Granularity of MapAddr() and MapOffset() parameter values.
- /// This may be greater than the value returned by page_size().
- pub fn granularity() -> usize {
- use mem;
- unsafe {
- let mut info = mem::zeroed();
- libc::GetSystemInfo(&mut info);
-
- return info.dwAllocationGranularity as usize;
- }
- }
-}
-
-#[cfg(windows)]
-impl Drop for MemoryMap {
- /// Unmap the mapping. Panics the task if any of `VirtualFree`,
- /// `UnmapViewOfFile`, or `CloseHandle` fail.
- fn drop(&mut self) {
- use libc::types::os::arch::extra::{LPCVOID, HANDLE};
- use libc::consts::os::extra::FALSE;
- if self.len == 0 { return }
-
- unsafe {
- match self.kind {
- MapVirtual => {
- if libc::VirtualFree(self.data as *mut c_void, 0,
- libc::MEM_RELEASE) == 0 {
- println!("VirtualFree failed: {}", errno());
- }
- },
- MapFile(mapping) => {
- if libc::UnmapViewOfFile(self.data as LPCVOID) == FALSE {
- println!("UnmapViewOfFile failed: {}", errno());
- }
- if libc::CloseHandle(mapping as HANDLE) == FALSE {
- println!("CloseHandle failed: {}", errno());
- }
- }
- }
- }
- }
-}
-
-impl MemoryMap {
- /// Returns the pointer to the memory created or modified by this map.
- pub fn data(&self) -> *mut u8 { self.data }
- /// Returns the number of bytes this map applies to.
- pub fn len(&self) -> usize { self.len }
- /// Returns the type of mapping this represents.
- pub fn kind(&self) -> MemoryMapKind { self.kind }
-}
-
-#[cfg(target_os = "linux")]
-#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
-#[unstable(feature = "os")]
-pub mod consts {
- pub use os::arch_consts::ARCH;
-
- pub const FAMILY: &'static str = "unix";
-
- /// A string describing the specific operating system in use: in this
- /// case, `linux`.
- pub const SYSNAME: &'static str = "linux";
-
- /// Specifies the filename prefix used for shared libraries on this
- /// platform: in this case, `lib`.
- pub const DLL_PREFIX: &'static str = "lib";
-
- /// Specifies the filename suffix used for shared libraries on this
- /// platform: in this case, `.so`.
- pub const DLL_SUFFIX: &'static str = ".so";
-
- /// Specifies the file extension used for shared libraries on this
- /// platform that goes after the dot: in this case, `so`.
- pub const DLL_EXTENSION: &'static str = "so";
-
- /// Specifies the filename suffix used for executable binaries on this
- /// platform: in this case, the empty string.
- pub const EXE_SUFFIX: &'static str = "";
-
- /// Specifies the file extension, if any, used for executable binaries
- /// on this platform: in this case, the empty string.
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "macos")]
-#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
-#[unstable(feature = "os")]
-pub mod consts {
- pub use os::arch_consts::ARCH;
-
- pub const FAMILY: &'static str = "unix";
-
- /// A string describing the specific operating system in use: in this
- /// case, `macos`.
- pub const SYSNAME: &'static str = "macos";
-
- /// Specifies the filename prefix used for shared libraries on this
- /// platform: in this case, `lib`.
- pub const DLL_PREFIX: &'static str = "lib";
-
- /// Specifies the filename suffix used for shared libraries on this
- /// platform: in this case, `.dylib`.
- pub const DLL_SUFFIX: &'static str = ".dylib";
-
- /// Specifies the file extension used for shared libraries on this
- /// platform that goes after the dot: in this case, `dylib`.
- pub const DLL_EXTENSION: &'static str = "dylib";
-
- /// Specifies the filename suffix used for executable binaries on this
- /// platform: in this case, the empty string.
- pub const EXE_SUFFIX: &'static str = "";
-
- /// Specifies the file extension, if any, used for executable binaries
- /// on this platform: in this case, the empty string.
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "ios")]
-#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
-#[unstable(feature = "os")]
-pub mod consts {
- pub use os::arch_consts::ARCH;
-
- pub const FAMILY: &'static str = "unix";
-
- /// A string describing the specific operating system in use: in this
- /// case, `ios`.
- pub const SYSNAME: &'static str = "ios";
-
- /// Specifies the filename suffix used for executable binaries on this
- /// platform: in this case, the empty string.
- pub const EXE_SUFFIX: &'static str = "";
-
- /// Specifies the file extension, if any, used for executable binaries
- /// on this platform: in this case, the empty string.
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "freebsd")]
-#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
-#[unstable(feature = "os")]
-pub mod consts {
- pub use os::arch_consts::ARCH;
-
- pub const FAMILY: &'static str = "unix";
-
- /// A string describing the specific operating system in use: in this
- /// case, `freebsd`.
- pub const SYSNAME: &'static str = "freebsd";
-
- /// Specifies the filename prefix used for shared libraries on this
- /// platform: in this case, `lib`.
- pub const DLL_PREFIX: &'static str = "lib";
-
- /// Specifies the filename suffix used for shared libraries on this
- /// platform: in this case, `.so`.
- pub const DLL_SUFFIX: &'static str = ".so";
-
- /// Specifies the file extension used for shared libraries on this
- /// platform that goes after the dot: in this case, `so`.
- pub const DLL_EXTENSION: &'static str = "so";
-
- /// Specifies the filename suffix used for executable binaries on this
- /// platform: in this case, the empty string.
- pub const EXE_SUFFIX: &'static str = "";
-
- /// Specifies the file extension, if any, used for executable binaries
- /// on this platform: in this case, the empty string.
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "dragonfly")]
-#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
-#[unstable(feature = "os")]
-pub mod consts {
- pub use os::arch_consts::ARCH;
-
- pub const FAMILY: &'static str = "unix";
-
- /// A string describing the specific operating system in use: in this
- /// case, `dragonfly`.
- pub const SYSNAME: &'static str = "dragonfly";
-
- /// Specifies the filename prefix used for shared libraries on this
- /// platform: in this case, `lib`.
- pub const DLL_PREFIX: &'static str = "lib";
-
- /// Specifies the filename suffix used for shared libraries on this
- /// platform: in this case, `.so`.
- pub const DLL_SUFFIX: &'static str = ".so";
-
- /// Specifies the file extension used for shared libraries on this
- /// platform that goes after the dot: in this case, `so`.
- pub const DLL_EXTENSION: &'static str = "so";
-
- /// Specifies the filename suffix used for executable binaries on this
- /// platform: in this case, the empty string.
- pub const EXE_SUFFIX: &'static str = "";
-
- /// Specifies the file extension, if any, used for executable binaries
- /// on this platform: in this case, the empty string.
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "bitrig")]
-#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
-#[unstable(feature = "os")]
-pub mod consts {
- pub use os::arch_consts::ARCH;
-
- pub const FAMILY: &'static str = "unix";
-
- /// A string describing the specific operating system in use: in this
- /// case, `bitrig`.
- pub const SYSNAME: &'static str = "bitrig";
-
- /// Specifies the filename prefix used for shared libraries on this
- /// platform: in this case, `lib`.
- pub const DLL_PREFIX: &'static str = "lib";
-
- /// Specifies the filename suffix used for shared libraries on this
- /// platform: in this case, `.so`.
- pub const DLL_SUFFIX: &'static str = ".so";
-
- /// Specifies the file extension used for shared libraries on this
- /// platform that goes after the dot: in this case, `so`.
- pub const DLL_EXTENSION: &'static str = "so";
-
- /// Specifies the filename suffix used for executable binaries on this
- /// platform: in this case, the empty string.
- pub const EXE_SUFFIX: &'static str = "";
-
- /// Specifies the file extension, if any, used for executable binaries
- /// on this platform: in this case, the empty string.
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "openbsd")]
-#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
-#[unstable(feature = "os")]
-pub mod consts {
- pub use os::arch_consts::ARCH;
-
- pub const FAMILY: &'static str = "unix";
-
- /// A string describing the specific operating system in use: in this
- /// case, `openbsd`.
- pub const SYSNAME: &'static str = "openbsd";
-
- /// Specifies the filename prefix used for shared libraries on this
- /// platform: in this case, `lib`.
- pub const DLL_PREFIX: &'static str = "lib";
-
- /// Specifies the filename suffix used for shared libraries on this
- /// platform: in this case, `.so`.
- pub const DLL_SUFFIX: &'static str = ".so";
-
- /// Specifies the file extension used for shared libraries on this
- /// platform that goes after the dot: in this case, `so`.
- pub const DLL_EXTENSION: &'static str = "so";
-
- /// Specifies the filename suffix used for executable binaries on this
- /// platform: in this case, the empty string.
- pub const EXE_SUFFIX: &'static str = "";
-
- /// Specifies the file extension, if any, used for executable binaries
- /// on this platform: in this case, the empty string.
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "android")]
-#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
-#[unstable(feature = "os")]
-pub mod consts {
- pub use os::arch_consts::ARCH;
-
- pub const FAMILY: &'static str = "unix";
-
- /// A string describing the specific operating system in use: in this
- /// case, `android`.
- pub const SYSNAME: &'static str = "android";
-
- /// Specifies the filename prefix used for shared libraries on this
- /// platform: in this case, `lib`.
- pub const DLL_PREFIX: &'static str = "lib";
-
- /// Specifies the filename suffix used for shared libraries on this
- /// platform: in this case, `.so`.
- pub const DLL_SUFFIX: &'static str = ".so";
-
- /// Specifies the file extension used for shared libraries on this
- /// platform that goes after the dot: in this case, `so`.
- pub const DLL_EXTENSION: &'static str = "so";
-
- /// Specifies the filename suffix used for executable binaries on this
- /// platform: in this case, the empty string.
- pub const EXE_SUFFIX: &'static str = "";
-
- /// Specifies the file extension, if any, used for executable binaries
- /// on this platform: in this case, the empty string.
- pub const EXE_EXTENSION: &'static str = "";
-}
-
-#[cfg(target_os = "windows")]
-#[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
-#[unstable(feature = "os")]
-pub mod consts {
- pub use os::arch_consts::ARCH;
-
- pub const FAMILY: &'static str = "windows";
-
- /// A string describing the specific operating system in use: in this
- /// case, `windows`.
- pub const SYSNAME: &'static str = "windows";
-
- /// Specifies the filename prefix used for shared libraries on this
- /// platform: in this case, the empty string.
- pub const DLL_PREFIX: &'static str = "";
-
- /// Specifies the filename suffix used for shared libraries on this
- /// platform: in this case, `.dll`.
- pub const DLL_SUFFIX: &'static str = ".dll";
-
- /// Specifies the file extension used for shared libraries on this
- /// platform that goes after the dot: in this case, `dll`.
- pub const DLL_EXTENSION: &'static str = "dll";
-
- /// Specifies the filename suffix used for executable binaries on this
- /// platform: in this case, `.exe`.
- pub const EXE_SUFFIX: &'static str = ".exe";
-
- /// Specifies the file extension, if any, used for executable binaries
- /// on this platform: in this case, `exe`.
- pub const EXE_EXTENSION: &'static str = "exe";
-}
-
-#[cfg(target_arch = "x86")]
-mod arch_consts {
- pub const ARCH: &'static str = "x86";
-}
-
-#[cfg(target_arch = "x86_64")]
-mod arch_consts {
- pub const ARCH: &'static str = "x86_64";
-}
-
-#[cfg(target_arch = "arm")]
-mod arch_consts {
- pub const ARCH: &'static str = "arm";
-}
-
-#[cfg(target_arch = "aarch64")]
-mod arch_consts {
- pub const ARCH: &'static str = "aarch64";
-}
-
-#[cfg(target_arch = "mips")]
-mod arch_consts {
- pub const ARCH: &'static str = "mips";
-}
-
-#[cfg(target_arch = "mipsel")]
-mod arch_consts {
- pub const ARCH: &'static str = "mipsel";
-}
-
-#[cfg(target_arch = "powerpc")]
-mod arch_consts {
- pub const ARCH: &'static str = "powerpc";
-}
-
-#[cfg(test)]
-mod tests {
- #![allow(deprecated)] // rand
-
- use prelude::v1::*;
-
- use iter::repeat;
- use os::{env, getcwd, getenv, make_absolute};
- use os::{split_paths, join_paths, setenv, unsetenv};
- use os;
- use rand::Rng;
- use rand;
- use old_path::{Path, GenericPath};
- use old_io::{Reader, Writer, Seek};
-
- #[test]
- pub fn last_os_error() {
- debug!("{}", os::last_os_error());
- }
-
- fn make_rand_name() -> String {
- let mut rng = rand::thread_rng();
- let n = format!("TEST{}", rng.gen_ascii_chars().take(10)
- .collect::<String>());
- assert!(getenv(&n).is_none());
- n
- }
-
- #[test]
- fn test_num_cpus() {
- assert!(os::num_cpus() > 0);
- }
-
- #[test]
- fn test_setenv() {
- let n = make_rand_name();
- setenv(&n, "VALUE");
- assert_eq!(getenv(&n), Some("VALUE".to_string()));
- }
-
- #[test]
- fn test_unsetenv() {
- let n = make_rand_name();
- setenv(&n, "VALUE");
- unsetenv(&n);
- assert_eq!(getenv(&n), None);
- }
-
- #[test]
- #[ignore]
- fn test_setenv_overwrite() {
- let n = make_rand_name();
- setenv(&n, "1");
- setenv(&n, "2");
- assert_eq!(getenv(&n), Some("2".to_string()));
- setenv(&n, "");
- assert_eq!(getenv(&n), Some("".to_string()));
- }
-
- // Windows GetEnvironmentVariable requires some extra work to make sure
- // the buffer the variable is copied into is the right size
- #[test]
- #[ignore]
- fn test_getenv_big() {
- let mut s = "".to_string();
- let mut i = 0;
- while i < 100 {
- s.push_str("aaaaaaaaaa");
- i += 1;
- }
- let n = make_rand_name();
- setenv(&n, &s);
- debug!("{}", s.clone());
- assert_eq!(getenv(&n), Some(s));
- }
-
- #[test]
- fn test_self_exe_name() {
- let path = os::self_exe_name();
- assert!(path.is_some());
- let path = path.unwrap();
- debug!("{}", path.display());
-
- // Hard to test this function
- assert!(path.is_absolute());
- }
-
- #[test]
- fn test_self_exe_path() {
- let path = os::self_exe_path();
- assert!(path.is_some());
- let path = path.unwrap();
- debug!("{}", path.display());
-
- // Hard to test this function
- assert!(path.is_absolute());
- }
-
- #[test]
- #[ignore]
- fn test_env_getenv() {
- let e = env();
- assert!(e.len() > 0);
- for p in &e {
- let (n, v) = (*p).clone();
- debug!("{}", n);
- let v2 = getenv(&n);
- // MingW seems to set some funky environment variables like
- // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned
- // from env() but not visible from getenv().
- assert!(v2.is_none() || v2 == Some(v));
- }
- }
-
- #[test]
- fn test_env_set_get_huge() {
- let n = make_rand_name();
- let s = repeat("x").take(10000).collect::<String>();
- setenv(&n, &s);
- assert_eq!(getenv(&n), Some(s));
- unsetenv(&n);
- assert_eq!(getenv(&n), None);
- }
-
- #[test]
- fn test_env_setenv() {
- let n = make_rand_name();
-
- let mut e = env();
- setenv(&n, "VALUE");
- assert!(!e.contains(&(n.clone(), "VALUE".to_string())));
-
- e = env();
- assert!(e.contains(&(n, "VALUE".to_string())));
- }
-
- #[test]
- fn test() {
- assert!((!Path::new("test-path").is_absolute()));
-
- let cwd = getcwd().unwrap();
- debug!("Current working directory: {}", cwd.display());
-
- debug!("{}", make_absolute(&Path::new("test-path")).unwrap().display());
- debug!("{}", make_absolute(&Path::new("/usr/bin")).unwrap().display());
- }
-
- #[test]
- #[cfg(unix)]
- fn homedir() {
- let oldhome = getenv("HOME");
-
- setenv("HOME", "/home/MountainView");
- assert!(os::homedir() == Some(Path::new("/home/MountainView")));
-
- setenv("HOME", "");
- assert!(os::homedir().is_none());
-
- if let Some(s) = oldhome {
- setenv("HOME", s);
- }
- }
-
- #[test]
- #[cfg(windows)]
- fn homedir() {
-
- let oldhome = getenv("HOME");
- let olduserprofile = getenv("USERPROFILE");
-
- setenv("HOME", "");
- setenv("USERPROFILE", "");
-
- assert!(os::homedir().is_none());
-
- setenv("HOME", "/home/MountainView");
- assert!(os::homedir() == Some(Path::new("/home/MountainView")));
-
- setenv("HOME", "");
-
- setenv("USERPROFILE", "/home/MountainView");
- assert!(os::homedir() == Some(Path::new("/home/MountainView")));
-
- setenv("HOME", "/home/MountainView");
- setenv("USERPROFILE", "/home/PaloAlto");
- assert!(os::homedir() == Some(Path::new("/home/MountainView")));
-
- if let Some(s) = oldhome {
- setenv("HOME", &s);
- }
- if let Some(s) = olduserprofile {
- setenv("USERPROFILE", &s);
- }
- }
-
- #[test]
- fn memory_map_rw() {
- use result::Result::{Ok, Err};
-
- let chunk = match os::MemoryMap::new(16, &[
- os::MapOption::MapReadable,
- os::MapOption::MapWritable
- ]) {
- Ok(chunk) => chunk,
- Err(msg) => panic!("{:?}", msg)
- };
- assert!(chunk.len >= 16);
-
- unsafe {
- *chunk.data = 0xBE;
- assert!(*chunk.data == 0xBE);
- }
- }
-
- #[test]
- fn memory_map_file() {
- use libc;
- use os::*;
- use old_io::fs::{File, unlink};
- use old_io::SeekStyle::SeekSet;
- use old_io::FileMode::Open;
- use old_io::FileAccess::ReadWrite;
-
- #[cfg(not(windows))]
- fn get_fd(file: &File) -> libc::c_int {
- use os::unix::prelude::*;
- file.as_raw_fd()
- }
-
- #[cfg(windows)]
- fn get_fd(file: &File) -> libc::HANDLE {
- use os::windows::prelude::*;
- file.as_raw_handle()
- }
-
- let mut path = tmpdir();
- path.push("mmap_file.tmp");
- let size = MemoryMap::granularity() * 2;
- let mut file = File::open_mode(&path, Open, ReadWrite).unwrap();
- file.seek(size as i64, SeekSet).unwrap();
- file.write_u8(0).unwrap();
-
- let chunk = MemoryMap::new(size / 2, &[
- MapOption::MapReadable,
- MapOption::MapWritable,
- MapOption::MapFd(get_fd(&file)),
- MapOption::MapOffset(size / 2)
- ]).unwrap();
- assert!(chunk.len > 0);
-
- unsafe {
- *chunk.data = 0xbe;
- assert!(*chunk.data == 0xbe);
- }
- drop(chunk);
-
- unlink(&path).unwrap();
- }
-
- #[test]
- #[cfg(windows)]
- fn split_paths_windows() {
- fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
- split_paths(unparsed) ==
- parsed.iter().map(|s| Path::new(*s)).collect::<Vec<_>>()
- }
-
- assert!(check_parse("", &mut [""]));
- assert!(check_parse(r#""""#, &mut [""]));
- assert!(check_parse(";;", &mut ["", "", ""]));
- assert!(check_parse(r"c:\", &mut [r"c:\"]));
- assert!(check_parse(r"c:\;", &mut [r"c:\", ""]));
- assert!(check_parse(r"c:\;c:\Program Files\",
- &mut [r"c:\", r"c:\Program Files\"]));
- assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"]));
- assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#,
- &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"]));
- }
-
- #[test]
- #[cfg(unix)]
- fn split_paths_unix() {
- fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
- split_paths(unparsed) ==
- parsed.iter().map(|s| Path::new(*s)).collect::<Vec<_>>()
- }
-
- assert!(check_parse("", &mut [""]));
- assert!(check_parse("::", &mut ["", "", ""]));
- assert!(check_parse("/", &mut ["/"]));
- assert!(check_parse("/:", &mut ["/", ""]));
- assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"]));
- }
-
- #[test]
- #[cfg(unix)]
- fn join_paths_unix() {
- fn test_eq(input: &[&str], output: &str) -> bool {
- join_paths(input).unwrap() == output.as_bytes()
- }
-
- assert!(test_eq(&[], ""));
- assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"],
- "/bin:/usr/bin:/usr/local/bin"));
- assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""],
- ":/bin:::/usr/bin:"));
- assert!(join_paths(&["/te:st"]).is_err());
- }
-
- #[test]
- #[cfg(windows)]
- fn join_paths_windows() {
- fn test_eq(input: &[&str], output: &str) -> bool {
- join_paths(input).unwrap() == output.as_bytes()
- }
-
- assert!(test_eq(&[], ""));
- assert!(test_eq(&[r"c:\windows", r"c:\"],
- r"c:\windows;c:\"));
- assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""],
- r";c:\windows;;;c:\;"));
- assert!(test_eq(&[r"c:\te;st", r"c:\"],
- r#""c:\te;st";c:\"#));
- assert!(join_paths(&[r#"c:\te"st"#]).is_err());
- }
-
- // More recursive_mkdir tests are in extra::tempfile
-}
//! To build or modify paths, use `PathBuf`:
//!
//! ```rust
-//! # #![feature(convert)]
//! use std::path::PathBuf;
//!
//! let mut path = PathBuf::from("c:\\");
pub fn as_os_str(self) -> &'a OsStr {
match self {
Component::Prefix(p) => p.as_os_str(),
- Component::RootDir => OsStr::from_str(MAIN_SEP_STR),
- Component::CurDir => OsStr::from_str("."),
- Component::ParentDir => OsStr::from_str(".."),
+ Component::RootDir => OsStr::new(MAIN_SEP_STR),
+ Component::CurDir => OsStr::new("."),
+ Component::ParentDir => OsStr::new(".."),
Component::Normal(path) => path,
}
}
/// # Examples
///
/// ```
-/// # #![feature(convert)]
/// use std::path::PathBuf;
///
/// let mut path = PathBuf::from("c:\\");
PathBuf { inner: OsString::new() }
}
+ /// Coerce to a `Path` slice.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn as_path(&self) -> &Path {
+ self
+ }
+
/// Extend `self` with `path`.
///
/// If `path` is absolute, it replaces the current path.
/// # Examples
///
/// ```
- /// # #![feature(convert)]
/// use std::path::PathBuf;
///
/// let mut buf = PathBuf::from("/");
#[stable(feature = "rust1", since = "1.0.0")]
pub fn file_name(&self) -> Option<&OsStr> {
self.components().next_back().and_then(|p| match p {
- Component::Normal(p) => Some(p.as_os_str()),
+ Component::Normal(p) => Some(p.as_ref()),
_ => None
})
}
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use result::Result::{self, Ok, Err};
#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
-#[doc(no_inline)] pub use slice::{SliceConcatExt, AsSlice};
-#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
-#[doc(no_inline)] pub use str::Str;
+#[doc(no_inline)] pub use slice::SliceConcatExt;
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use string::{String, ToString};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use vec::Vec;
+
+#[allow(deprecated)] pub use slice::AsSlice;
+#[allow(deprecated)] pub use str::Str;
use prelude::v1::*;
use io::prelude::*;
-use ffi::AsOsStr;
+use ffi::OsStr;
use fmt;
use io::{self, Error, ErrorKind};
use libc;
use path;
use sync::mpsc::{channel, Receiver};
use sys::pipe2::{self, AnonPipe};
-use sys::process2::Process as ProcessImp;
use sys::process2::Command as CommandImp;
+use sys::process2::Process as ProcessImp;
use sys::process2::ExitStatus as ExitStatusImp;
use sys_common::{AsInner, AsInnerMut};
use thread;
/// Builder methods are provided to change these defaults and
/// otherwise configure the process.
#[stable(feature = "process", since = "1.0.0")]
- pub fn new<S: AsOsStr>(program: S) -> Command {
+ pub fn new<S: AsRef<OsStr>>(program: S) -> Command {
Command {
- inner: CommandImp::new(program.as_os_str()),
+ inner: CommandImp::new(program.as_ref()),
stdin: None,
stdout: None,
stderr: None,
/// Add an argument to pass to the program.
#[stable(feature = "process", since = "1.0.0")]
- pub fn arg<S: AsOsStr>(&mut self, arg: S) -> &mut Command {
- self.inner.arg(arg.as_os_str());
+ pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command {
+ self.inner.arg(arg.as_ref());
self
}
/// Add multiple arguments to pass to the program.
#[stable(feature = "process", since = "1.0.0")]
- pub fn args<S: AsOsStr>(&mut self, args: &[S]) -> &mut Command {
- self.inner.args(args.iter().map(AsOsStr::as_os_str));
+ pub fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut Command {
+ self.inner.args(args.iter().map(AsRef::as_ref));
self
}
/// and case-sensitive on all other platforms.
#[stable(feature = "process", since = "1.0.0")]
pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Command
- where K: AsOsStr, V: AsOsStr
+ where K: AsRef<OsStr>, V: AsRef<OsStr>
{
- self.inner.env(key.as_os_str(), val.as_os_str());
+ self.inner.env(key.as_ref(), val.as_ref());
self
}
/// Removes an environment variable mapping.
#[stable(feature = "process", since = "1.0.0")]
- pub fn env_remove<K: AsOsStr>(&mut self, key: K) -> &mut Command {
- self.inner.env_remove(key.as_os_str());
+ pub fn env_remove<K: AsRef<OsStr>>(&mut self, key: K) -> &mut Command {
+ self.inner.env_remove(key.as_ref());
self
}
/// Set the working directory for the child process.
#[stable(feature = "process", since = "1.0.0")]
pub fn current_dir<P: AsRef<path::Path>>(&mut self, dir: P) -> &mut Command {
- self.inner.cwd(dir.as_ref().as_os_str());
+ self.inner.cwd(dir.as_ref().as_ref());
self
}
}
impl Stdio {
- /// A new pipe should be arranged to connect the parent and child processes.
- #[unstable(feature = "process_capture")]
- #[deprecated(since = "1.0.0", reason = "renamed to `Stdio::piped`")]
- pub fn capture() -> Stdio { Stdio::piped() }
-
/// A new pipe should be arranged to connect the parent and child processes.
#[stable(feature = "process", since = "1.0.0")]
pub fn piped() -> Stdio { Stdio(StdioImp::Piped) }
return Err(Error::new(
ErrorKind::InvalidInput,
"invalid argument: can't kill an exited process",
- None
))
}
}
}
+/// Terminates the current process with the specified exit code.
+///
+/// This function will never return and will immediately terminate the current
+/// process. The exit code is passed through to the underlying OS and will be
+/// available for consumption by another process.
+///
+/// Note that because this function never returns, and that it terminates the
+/// process, no destructors on the current stack or any other thread's stack
+/// will be run. If a clean shutdown is needed it is recommended to only call
+/// this function at a known point where there are no more destructors left
+/// to run.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn exit(code: i32) -> ! {
+ ::sys::os::exit(code)
+}
+
#[cfg(test)]
mod tests {
- use io::ErrorKind;
+ use prelude::v1::*;
use io::prelude::*;
- use prelude::v1::{Ok, Err, drop, Some, Vec};
- use prelude::v1::{String, Clone};
- use prelude::v1::{Str, AsSlice, ToString};
+
+ use io::ErrorKind;
use old_path::{self, GenericPath};
use old_io::fs::PathExtensions;
use rt::running_on_valgrind;
assert!(p.is_ok());
let mut p = p.unwrap();
assert!(p.wait().unwrap().code() == Some(1));
- drop(p.wait().clone());
+ drop(p.wait());
}
#[cfg(all(unix, not(target_os="android")))]
fn test_process_output_output() {
let Output {status, stdout, stderr}
= Command::new("echo").arg("hello").output().unwrap();
- let output_str = str::from_utf8(stdout.as_slice()).unwrap();
+ let output_str = str::from_utf8(&stdout).unwrap();
assert!(status.success());
assert_eq!(output_str.trim().to_string(), "hello");
let prog = Command::new("echo").arg("hello").stdout(Stdio::piped())
.spawn().unwrap();
let Output {status, stdout, stderr} = prog.wait_with_output().unwrap();
- let output_str = str::from_utf8(stdout.as_slice()).unwrap();
+ let output_str = str::from_utf8(&stdout).unwrap();
assert!(status.success());
assert_eq!(output_str.trim().to_string(), "hello");
let prog = pwd_cmd().spawn().unwrap();
let output = String::from_utf8(prog.wait_with_output().unwrap().stdout).unwrap();
- let parent_dir = os::getcwd().unwrap();
+ let parent_dir = ::env::current_dir().unwrap().to_str().unwrap().to_string();
+ let parent_dir = old_path::Path::new(parent_dir);
let child_dir = old_path::Path::new(output.trim());
let parent_stat = parent_dir.stat().unwrap();
use os;
// test changing to the parent of os::getcwd() because we know
// the path exists (and os::getcwd() is not expected to be root)
- let parent_dir = os::getcwd().unwrap().dir_path();
+ let parent_dir = ::env::current_dir().unwrap().to_str().unwrap().to_string();
+ let parent_dir = old_path::Path::new(parent_dir).dir_path();
let result = pwd_cmd().current_dir(parent_dir.as_str().unwrap()).output().unwrap();
let output = String::from_utf8(result.stdout).unwrap();
#[cfg(target_os="android")]
#[test]
fn test_inherit_env() {
- use os;
+ use std::env;
if running_on_valgrind() { return; }
let mut result = env_cmd().output().unwrap();
let output = String::from_utf8(result.stdout).unwrap();
- let r = os::env();
- for &(ref k, ref v) in &r {
+ for (ref k, ref v) in env::vars() {
// don't check android RANDOM variables
if *k != "RANDOM".to_string() {
assert!(output.contains(&format!("{}={}",
cmd.env("PATH", &p);
}
let result = cmd.output().unwrap();
- let output = String::from_utf8_lossy(result.stdout.as_slice()).to_string();
+ let output = String::from_utf8_lossy(&result.stdout).to_string();
assert!(output.contains("RUN_TEST_NEW_ENV=123"),
"didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
#[test]
fn test_add_to_env() {
let result = env_cmd().env("RUN_TEST_NEW_ENV", "123").output().unwrap();
- let output = String::from_utf8_lossy(result.stdout.as_slice()).to_string();
+ let output = String::from_utf8_lossy(&result.stdout).to_string();
assert!(output.contains("RUN_TEST_NEW_ENV=123"),
"didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
- extern crate libc;
-
+ use prelude::v1::*;
use self::OsRngInner::*;
+ use libc;
+ use mem;
use old_io::{IoResult, File};
use old_path::Path;
use rand::Rng;
use rand::reader::ReaderRng;
- use result::Result::Ok;
- use mem;
- use os::errno;
+ use sys::os::errno;
#[cfg(all(target_os = "linux",
any(target_arch = "x86_64",
#[cfg(target_os = "ios")]
mod imp {
- extern crate libc;
+ use prelude::v1::*;
- use old_io::{IoResult};
+ use old_io::IoResult;
use mem;
use os;
use rand::Rng;
- use result::Result::{Ok};
- use self::libc::{c_int, size_t};
+ use libc::{c_int, size_t};
/// A random number generator that retrieves randomness straight from
/// the operating system. Platform sources:
#[cfg(windows)]
mod imp {
- extern crate libc;
+ use prelude::v1::*;
- use old_io::{IoResult, IoError};
+ use io;
use mem;
- use ops::Drop;
- use os;
+ use old_io::{IoResult, IoError};
use rand::Rng;
- use result::Result::{Ok, Err};
- use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
- use self::libc::types::os::arch::extra::{LONG_PTR};
+ use libc::types::os::arch::extra::{LONG_PTR};
+ use libc::{DWORD, BYTE, LPCSTR, BOOL};
type HCRYPTPROV = LONG_PTR;
v.as_mut_ptr())
};
if ret == 0 {
- panic!("couldn't generate random bytes: {}", os::last_os_error());
+ panic!("couldn't generate random bytes: {}",
+ io::Error::last_os_error());
}
}
}
CryptReleaseContext(self.hcryptprov, 0)
};
if ret == 0 {
- panic!("couldn't release context: {}", os::last_os_error());
+ panic!("couldn't release context: {}",
+ io::Error::last_os_error());
}
}
}
#[cfg(test)]
mod tests {
use prelude::v1::*;
- use finally::Finally;
use super::*;
assert!(take() == Some(expected.clone()));
assert!(take() == None);
- (|| {
- }).finally(|| {
- // Restore the actual global state.
- match saved_value {
- Some(ref args) => put(args.clone()),
- None => ()
- }
- })
+ // Restore the actual global state.
+ match saved_value {
+ Some(ref args) => put(args.clone()),
+ None => ()
+ }
}
}
}
pub use self::poison::{PoisonError, TryLockError, TryLockResult, LockResult};
pub use self::future::Future;
-#[allow(deprecated)]
-pub use self::task_pool::TaskPool;
pub mod mpsc;
mod poison;
mod rwlock;
mod semaphore;
-mod task_pool;
//! ```
//!
//! Reading from a channel with a timeout requires to use a Timer together
-//! with the channel. You can use the select! macro to select either and
+//! with the channel. You can use the `select!` macro to select either and
//! handle the timeout case. This first example will break out of the loop
//! after 10 seconds no matter what:
//!
use prelude::v1::*;
use cell::UnsafeCell;
-use error::{Error, FromError};
+use error::{Error};
use fmt;
use thread;
PoisonError { guard: guard }
}
- /// Consumes this error indicating that a lock is poisoned, returning the
- /// underlying guard to allow access regardless.
- #[unstable(feature = "std_misc")]
- #[deprecated(since = "1.0.0", reason = "renamed to into_inner")]
- pub fn into_guard(self) -> T { self.guard }
-
/// Consumes this error indicating that a lock is poisoned, returning the
/// underlying guard to allow access regardless.
#[unstable(feature = "std_misc")]
pub fn get_mut(&mut self) -> &mut T { &mut self.guard }
}
-impl<T> FromError<PoisonError<T>> for TryLockError<T> {
- fn from_error(err: PoisonError<T>) -> TryLockError<T> {
+impl<T> From<PoisonError<T>> for TryLockError<T> {
+ fn from(err: PoisonError<T>) -> TryLockError<T> {
TryLockError::Poisoned(err)
}
}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Abstraction of a thread pool for basic parallelism.
-
-#![deprecated(since = "1.0.0",
- reason = "This kind of API needs some time to bake in \
- crates.io. This functionality is available through \
- https://crates.io/crates/threadpool")]
-#![unstable(feature = "std_misc")]
-
-#![allow(deprecated)]
-
-use core::prelude::*;
-
-use sync::{Arc, Mutex};
-use sync::mpsc::{channel, Sender, Receiver};
-use thread;
-use thunk::Thunk;
-
-struct Sentinel<'a> {
- jobs: &'a Arc<Mutex<Receiver<Thunk<'static>>>>,
- active: bool
-}
-
-impl<'a> Sentinel<'a> {
- fn new(jobs: &'a Arc<Mutex<Receiver<Thunk<'static>>>>) -> Sentinel<'a> {
- Sentinel {
- jobs: jobs,
- active: true
- }
- }
-
- // Cancel and destroy this sentinel.
- fn cancel(mut self) {
- self.active = false;
- }
-}
-
-#[unsafe_destructor]
-impl<'a> Drop for Sentinel<'a> {
- fn drop(&mut self) {
- if self.active {
- spawn_in_pool(self.jobs.clone())
- }
- }
-}
-
-/// A thread pool used to execute functions in parallel.
-///
-/// Spawns `n` worker threads and replenishes the pool if any worker threads
-/// panic.
-///
-/// # Examples
-///
-/// ```
-/// # #![feature(std_misc, core)]
-/// use std::sync::TaskPool;
-/// use std::iter::AdditiveIterator;
-/// use std::sync::mpsc::channel;
-///
-/// let pool = TaskPool::new(4);
-///
-/// let (tx, rx) = channel();
-/// for _ in 0..8 {
-/// let tx = tx.clone();
-/// pool.execute(move|| {
-/// tx.send(1_u32).unwrap();
-/// });
-/// }
-///
-/// assert_eq!(rx.iter().take(8).sum(), 8);
-/// ```
-pub struct TaskPool {
- // How the threadpool communicates with subthreads.
- //
- // This is the only such Sender, so when it is dropped all subthreads will
- // quit.
- jobs: Sender<Thunk<'static>>
-}
-
-impl TaskPool {
- /// Spawns a new thread pool with `threads` threads.
- ///
- /// # Panics
- ///
- /// This function will panic if `threads` is 0.
- pub fn new(threads: usize) -> TaskPool {
- assert!(threads >= 1);
-
- let (tx, rx) = channel::<Thunk>();
- let rx = Arc::new(Mutex::new(rx));
-
- // Threadpool threads
- for _ in 0..threads {
- spawn_in_pool(rx.clone());
- }
-
- TaskPool { jobs: tx }
- }
-
- /// Executes the function `job` on a thread in the pool.
- pub fn execute<F>(&self, job: F)
- where F : FnOnce(), F : Send + 'static
- {
- self.jobs.send(Thunk::new(job)).unwrap();
- }
-}
-
-fn spawn_in_pool(jobs: Arc<Mutex<Receiver<Thunk<'static>>>>) {
- thread::spawn(move || {
- // Will spawn a new thread on panic unless it is cancelled.
- let sentinel = Sentinel::new(&jobs);
-
- loop {
- let message = {
- // Only lock jobs for the time it takes
- // to get a job, not run it.
- let lock = jobs.lock().unwrap();
- lock.recv()
- };
-
- match message {
- Ok(job) => job.invoke(()),
-
- // The Taskpool was dropped.
- Err(..) => break
- }
- }
-
- sentinel.cancel();
- });
-}
-
-#[cfg(test)]
-mod test {
- use prelude::v1::*;
- use super::*;
- use sync::mpsc::channel;
-
- const TEST_TASKS: usize = 4;
-
- #[test]
- fn test_works() {
- use iter::AdditiveIterator;
-
- let pool = TaskPool::new(TEST_TASKS);
-
- let (tx, rx) = channel();
- for _ in 0..TEST_TASKS {
- let tx = tx.clone();
- pool.execute(move|| {
- tx.send(1).unwrap();
- });
- }
-
- assert_eq!(rx.iter().take(TEST_TASKS).sum(), TEST_TASKS);
- }
-
- #[test]
- #[should_panic]
- fn test_zero_tasks_panic() {
- TaskPool::new(0);
- }
-
- #[test]
- fn test_recovery_from_subtask_panic() {
- use iter::AdditiveIterator;
-
- let pool = TaskPool::new(TEST_TASKS);
-
- // Panic all the existing threads.
- for _ in 0..TEST_TASKS {
- pool.execute(move|| -> () { panic!() });
- }
-
- // Ensure new threads were spawned to compensate.
- let (tx, rx) = channel();
- for _ in 0..TEST_TASKS {
- let tx = tx.clone();
- pool.execute(move|| {
- tx.send(1).unwrap();
- });
- }
-
- assert_eq!(rx.iter().take(TEST_TASKS).sum(), TEST_TASKS);
- }
-
- #[test]
- fn test_should_not_panic_on_drop_if_subtasks_panic_after_drop() {
- use sync::{Arc, Barrier};
-
- let pool = TaskPool::new(TEST_TASKS);
- let waiter = Arc::new(Barrier::new(TEST_TASKS + 1));
-
- // Panic all the existing threads in a bit.
- for _ in 0..TEST_TASKS {
- let waiter = waiter.clone();
- pool.execute(move|| {
- waiter.wait();
- panic!();
- });
- }
-
- drop(pool);
-
- // Kick off the failure.
- waiter.wait();
- }
-}
})))
}
_ => {
- Err(Error::new(ErrorKind::InvalidInput, "invalid argument", None))
+ Err(Error::new(ErrorKind::InvalidInput, "invalid argument"))
}
}
}
match from_utf8(data.to_bytes()) {
Ok(name) => Ok(name.to_string()),
Err(_) => Err(io::Error::new(io::ErrorKind::Other,
- "failed to lookup address information",
- Some("invalid host name".to_string())))
+ "failed to lookup address information"))
}
}
}
}
+impl FromInner<Socket> for TcpStream {
+ fn from_inner(socket: Socket) -> TcpStream {
+ TcpStream { inner: socket }
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// TCP listeners
////////////////////////////////////////////////////////////////////////////////
}
}
+impl FromInner<Socket> for TcpListener {
+ fn from_inner(socket: Socket) -> TcpListener {
+ TcpListener { inner: socket }
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// UDP
////////////////////////////////////////////////////////////////////////////////
self.inner.duplicate().map(|s| UdpSocket { inner: s })
}
}
+
+impl FromInner<Socket> for UdpSocket {
+ fn from_inner(socket: Socket) -> UdpSocket {
+ UdpSocket { inner: socket }
+ }
+}
fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void,
symaddr: *mut libc::c_void) -> io::Result<()> {
use env;
- use ffi::AsOsStr;
use os::unix::prelude::*;
use ptr;
#![stable(feature = "rust1", since = "1.0.0")]
/// Unix-specific extensions to general I/O primitives
-#[unstable(feature = "io_ext",
- reason = "may want a slightly different organization or a more \
- general file descriptor primitive")]
+#[stable(feature = "rust1", since = "1.0.0")]
pub mod io {
#[allow(deprecated)] use old_io;
use fs;
use libc;
use net;
- use sys_common::AsInner;
+ use sys_common::{net2, AsInner, FromInner};
+ use sys;
/// Raw file descriptors.
- pub type Fd = libc::c_int;
-
- /// Extract raw file descriptor
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub type RawFd = libc::c_int;
+
+ /// A trait to extract the raw unix file descriptor from an underlying
+ /// object.
+ ///
+ /// This is only available on unix platforms and must be imported in order
+ /// to call the method. Windows platforms have a corresponding `AsRawHandle`
+ /// and `AsRawSocket` set of traits.
+ #[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRawFd {
- /// Extract the raw file descriptor, without taking any ownership.
- fn as_raw_fd(&self) -> Fd;
+ /// Extract the raw file descriptor.
+ ///
+ /// This method does **not** pass ownership of the raw file descriptor
+ /// to the caller. The descriptor is only guarantee to be valid while
+ /// the original object has not yet been destroyed.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_raw_fd(&self) -> RawFd;
+ }
+
+ /// A trait to express the ability to construct an object from a raw file
+ /// descriptor.
+ #[unstable(feature = "from_raw_os",
+ reason = "recent addition to std::os::unix::io")]
+ pub trait FromRawFd {
+ /// Constructs a new instances of `Self` from the given raw file
+ /// descriptor.
+ ///
+ /// This function **consumes ownership** of the specified file
+ /// descriptor. The returned object will take responsibility for closing
+ /// it when the object goes out of scope.
+ ///
+ /// Callers should normally only pass in a valid file descriptor to this
+ /// method or otherwise methods will return errors.
+ fn from_raw_fd(fd: RawFd) -> Self;
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for old_io::fs::File {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for fs::File {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd().raw()
}
}
+ #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+ impl FromRawFd for fs::File {
+ fn from_raw_fd(fd: RawFd) -> fs::File {
+ fs::File::from_inner(sys::fs2::File::from_inner(fd))
+ }
+ }
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for old_io::pipe::PipeStream {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for old_io::net::pipe::UnixStream {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for old_io::net::pipe::UnixListener {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for old_io::net::pipe::UnixAcceptor {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
+ #[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
impl AsRawFd for old_io::net::tcp::TcpStream {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
+ #[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
impl AsRawFd for old_io::net::tcp::TcpListener {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
+ #[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
impl AsRawFd for old_io::net::tcp::TcpAcceptor {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for old_io::net::udp::UdpSocket {
- fn as_raw_fd(&self) -> Fd {
+ fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd()
}
}
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::TcpStream {
- fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() }
+ fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
}
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::TcpListener {
- fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() }
+ fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
}
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::UdpSocket {
- fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() }
+ fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+ }
+
+ #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+ impl FromRawFd for net::TcpStream {
+ fn from_raw_fd(fd: RawFd) -> net::TcpStream {
+ let socket = sys::net::Socket::from_inner(fd);
+ net::TcpStream::from_inner(net2::TcpStream::from_inner(socket))
+ }
+ }
+ #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+ impl FromRawFd for net::TcpListener {
+ fn from_raw_fd(fd: RawFd) -> net::TcpListener {
+ let socket = sys::net::Socket::from_inner(fd);
+ net::TcpListener::from_inner(net2::TcpListener::from_inner(socket))
+ }
+ }
+ #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+ impl FromRawFd for net::UdpSocket {
+ fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
+ let socket = sys::net::Socket::from_inner(fd);
+ net::UdpSocket::from_inner(net2::UdpSocket::from_inner(socket))
+ }
}
}
/// Unix-specific extension to the primitives in the `std::ffi` module
#[stable(feature = "rust1", since = "1.0.0")]
pub mod ffi {
- use ffi::{CString, NulError, OsStr, OsString};
+ use ffi::{OsStr, OsString};
use mem;
use prelude::v1::*;
use sys::os_str::Buf;
/// Get the underlying byte view of the `OsStr` slice.
#[stable(feature = "rust1", since = "1.0.0")]
fn as_bytes(&self) -> &[u8];
-
- /// Convert the `OsStr` slice into a `CString`.
- #[stable(feature = "rust1", since = "1.0.0")]
- fn to_cstring(&self) -> Result<CString, NulError>;
}
#[stable(feature = "rust1", since = "1.0.0")]
fn as_bytes(&self) -> &[u8] {
&self.as_inner().inner
}
- fn to_cstring(&self) -> Result<CString, NulError> {
- CString::new(self.as_bytes())
- }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
pub mod prelude {
#[doc(no_inline)]
- pub use super::io::{Fd, AsRawFd};
+ pub use super::io::{RawFd, AsRawFd};
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::ffi::{OsStrExt, OsStringExt};
#[doc(no_inline)]
fn test_file_desc() {
// Run this test with some pipes so we don't have to mess around with
// opening or closing files.
- let os::Pipe { reader, writer } = unsafe { os::pipe().unwrap() };
- let mut reader = FileDesc::new(reader, true);
- let mut writer = FileDesc::new(writer, true);
+ let (mut reader, mut writer) = unsafe { ::sys::os::pipe().unwrap() };
writer.write(b"test").unwrap();
let mut buf = [0; 4];
use io::prelude::*;
use os::unix::prelude::*;
-use ffi::{CString, CStr, OsString, AsOsStr, OsStr};
+use ffi::{CString, CStr, OsString, OsStr};
use io::{self, Error, SeekFrom};
use libc::{self, c_int, size_t, off_t, c_char, mode_t};
use mem;
}
fn cstr(path: &Path) -> io::Result<CString> {
- let cstring = try!(path.as_os_str().to_cstring());
- Ok(cstring)
+ path.as_os_str().to_cstring().ok_or(
+ io::Error::new(io::ErrorKind::InvalidInput, "path contained a null"))
+}
+
+impl FromInner<c_int> for File {
+ fn from_inner(fd: c_int) -> File {
+ File(FileDesc::new(fd))
+ }
}
pub fn mkdir(p: &Path) -> io::Result<()> {
#![allow(deprecated)]
use libc;
-use os;
+use sys::os;
use sys::fs::FileDesc;
pub type signal = libc::c_int;
pub fn new() -> (signal, signal) {
- let os::Pipe { reader, writer } = unsafe { os::pipe().unwrap() };
- (reader, writer)
+ let (a, b) = unsafe { os::pipe().unwrap() };
+ (a.unwrap(), b.unwrap())
}
pub fn signal(fd: libc::c_int) {
use sys::c;
use net::SocketAddr;
use sys::fd::FileDesc;
-use sys_common::AsInner;
+use sys_common::{AsInner, FromInner};
pub use sys::{cvt, cvt_r};
.to_string()
};
Err(io::Error::new(io::ErrorKind::Other,
- "failed to lookup address information", Some(detail)))
+ &format!("failed to lookup address information: {}",
+ detail)[..]))
}
impl Socket {
impl AsInner<c_int> for Socket {
fn as_inner(&self) -> &c_int { self.0.as_inner() }
}
+
+impl FromInner<c_int> for Socket {
+ fn from_inner(fd: c_int) -> Socket { Socket(FileDesc::new(fd)) }
+}
use os::unix::prelude::*;
use error::Error as StdError;
-use ffi::{CString, CStr, OsString, OsStr, AsOsStr};
+use ffi::{CString, CStr, OsString, OsStr};
use fmt;
use io;
use iter;
}
pub fn chdir(p: &path::Path) -> io::Result<()> {
- let p = try!(CString::new(p.as_os_str().as_bytes()));
+ let p: &OsStr = p.as_ref();
+ let p = try!(CString::new(p.as_bytes()));
unsafe {
match libc::chdir(p.as_ptr()) == (0 as c_int) {
true => Ok(()),
pub struct JoinPathsError;
pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
- where I: Iterator<Item=T>, T: AsOsStr
+ where I: Iterator<Item=T>, T: AsRef<OsStr>
{
let mut joined = Vec::new();
let sep = b':';
for (i, path) in paths.enumerate() {
- let path = path.as_os_str().as_bytes();
+ let path = path.as_ref().as_bytes();
if i > 0 { joined.push(sep) }
if path.contains(&sep) {
return Err(JoinPathsError)
}
pub fn temp_dir() -> PathBuf {
- getenv("TMPDIR".as_os_str()).map(os2path).unwrap_or_else(|| {
+ getenv("TMPDIR".as_ref()).map(os2path).unwrap_or_else(|| {
if cfg!(target_os = "android") {
PathBuf::from("/data/local/tmp")
} else {
}
pub fn home_dir() -> Option<PathBuf> {
- return getenv("HOME".as_os_str()).or_else(|| unsafe {
+ return getenv("HOME".as_ref()).or_else(|| unsafe {
fallback()
}).map(os2path);
}
}
}
+
+pub fn exit(code: i32) -> ! {
+ unsafe { libc::exit(code as c_int) }
+}
use old_io::process::{ProcessExit, ExitStatus, ExitSignal};
use old_io::{IoResult, EndOfFile};
use libc::{self, pid_t, c_void, c_int};
+use io;
use mem;
-use os;
+use sys::os;
use old_path::BytesContainer;
use ptr;
use sync::mpsc::{channel, Sender, Receiver};
n if n > 0 => { ret = true; }
0 => return true,
-1 if wouldblock() => return ret,
- n => panic!("bad read {:?} ({:?})", os::last_os_error(), n),
+ n => panic!("bad read {} ({})",
+ io::Error::last_os_error(), n),
}
}
}
self.args.push(arg.to_cstring().unwrap())
}
pub fn args<'a, I: Iterator<Item = &'a OsStr>>(&mut self, args: I) {
- self.args.extend(args.map(|s| OsStrExt::to_cstring(s).unwrap()))
+ self.args.extend(args.map(|s| s.to_cstring().unwrap()))
}
fn init_env_map(&mut self) {
if self.env.is_none() {
use old_io::IoResult;
use libc;
use mem;
-use os;
+use sys::os;
+use io;
use ptr;
use sync::atomic::{self, Ordering};
use sync::mpsc::{channel, Sender, Receiver, TryRecvError};
-1 if os::errno() == libc::EINTR as i32 => {}
n => panic!("helper thread failed in select() with error: {} ({})",
- n, os::last_os_error())
+ n, io::Error::last_os_error())
}
}
}
TokenHandle: *mut libc::HANDLE) -> libc::BOOL;
pub fn GetCurrentProcess() -> libc::HANDLE;
pub fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
+ pub fn ExitProcess(uExitCode: libc::c_uint) -> !;
}
#[link(name = "userenv")]
#![stable(feature = "rust1", since = "1.0.0")]
-#[unstable(feature = "io_ext",
- reason = "organization may change slightly and the primitives \
- provided may be tweaked")]
+#[stable(feature = "rust1", since = "1.0.0")]
pub mod io {
use fs;
use libc;
use net;
- use sys_common::AsInner;
+ use sys_common::{net2, AsInner, FromInner};
+ use sys;
#[allow(deprecated)]
use old_io;
/// Raw HANDLEs.
- pub type Handle = libc::HANDLE;
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub type RawHandle = libc::HANDLE;
/// Raw SOCKETs.
- pub type Socket = libc::SOCKET;
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub type RawSocket = libc::SOCKET;
/// Extract raw handles.
+ #[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRawHandle {
/// Extract the raw handle, without taking any ownership.
- fn as_raw_handle(&self) -> Handle;
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_raw_handle(&self) -> RawHandle;
+ }
+
+ /// Construct I/O objects from raw handles.
+ #[unstable(feature = "from_raw_os",
+ reason = "recent addition to the std::os::windows::io module")]
+ pub trait FromRawHandle {
+ /// Construct a new I/O object from the specified raw handle.
+ ///
+ /// This function will **consume ownership** of the handle given,
+ /// passing responsibility for closing the handle to the returned
+ /// object.
+ fn from_raw_handle(handle: RawHandle) -> Self;
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for old_io::fs::File {
- fn as_raw_handle(&self) -> Handle {
+ fn as_raw_handle(&self) -> RawHandle {
self.as_inner().handle()
}
}
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for fs::File {
- fn as_raw_handle(&self) -> Handle {
+ fn as_raw_handle(&self) -> RawHandle {
self.as_inner().handle().raw()
}
}
+ #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+ impl FromRawHandle for fs::File {
+ fn from_raw_handle(handle: RawHandle) -> fs::File {
+ fs::File::from_inner(sys::fs2::File::from_inner(handle))
+ }
+ }
+
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for old_io::pipe::PipeStream {
- fn as_raw_handle(&self) -> Handle {
+ fn as_raw_handle(&self) -> RawHandle {
self.as_inner().handle()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for old_io::net::pipe::UnixStream {
- fn as_raw_handle(&self) -> Handle {
+ fn as_raw_handle(&self) -> RawHandle {
self.as_inner().handle()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for old_io::net::pipe::UnixListener {
- fn as_raw_handle(&self) -> Handle {
+ fn as_raw_handle(&self) -> RawHandle {
self.as_inner().handle()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawHandle for old_io::net::pipe::UnixAcceptor {
- fn as_raw_handle(&self) -> Handle {
+ fn as_raw_handle(&self) -> RawHandle {
self.as_inner().handle()
}
}
/// Extract raw sockets.
+ #[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRawSocket {
- fn as_raw_socket(&self) -> Socket;
+ /// Extract the underlying raw socket from this object.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_raw_socket(&self) -> RawSocket;
+ }
+
+ /// Create I/O objects from raw sockets.
+ #[unstable(feature = "from_raw_os", reason = "recent addition to module")]
+ pub trait FromRawSocket {
+ /// Creates a new I/O object from the given raw socket.
+ ///
+ /// This function will **consume ownership** of the socket provided and
+ /// it will be closed when the returned object goes out of scope.
+ fn from_raw_socket(sock: RawSocket) -> Self;
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for old_io::net::tcp::TcpStream {
- fn as_raw_socket(&self) -> Socket {
+ fn as_raw_socket(&self) -> RawSocket {
self.as_inner().fd()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for old_io::net::tcp::TcpListener {
- fn as_raw_socket(&self) -> Socket {
+ fn as_raw_socket(&self) -> RawSocket {
self.as_inner().socket()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for old_io::net::tcp::TcpAcceptor {
- fn as_raw_socket(&self) -> Socket {
+ fn as_raw_socket(&self) -> RawSocket {
self.as_inner().socket()
}
}
#[allow(deprecated)]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for old_io::net::udp::UdpSocket {
- fn as_raw_socket(&self) -> Socket {
+ fn as_raw_socket(&self) -> RawSocket {
self.as_inner().fd()
}
}
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for net::TcpStream {
- fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() }
+ fn as_raw_socket(&self) -> RawSocket {
+ *self.as_inner().socket().as_inner()
+ }
}
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for net::TcpListener {
- fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() }
+ fn as_raw_socket(&self) -> RawSocket {
+ *self.as_inner().socket().as_inner()
+ }
}
+ #[stable(feature = "rust1", since = "1.0.0")]
impl AsRawSocket for net::UdpSocket {
- fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() }
+ fn as_raw_socket(&self) -> RawSocket {
+ *self.as_inner().socket().as_inner()
+ }
+ }
+
+ #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+ impl FromRawSocket for net::TcpStream {
+ fn from_raw_socket(sock: RawSocket) -> net::TcpStream {
+ let sock = sys::net::Socket::from_inner(sock);
+ net::TcpStream::from_inner(net2::TcpStream::from_inner(sock))
+ }
+ }
+ #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+ impl FromRawSocket for net::TcpListener {
+ fn from_raw_socket(sock: RawSocket) -> net::TcpListener {
+ let sock = sys::net::Socket::from_inner(sock);
+ net::TcpListener::from_inner(net2::TcpListener::from_inner(sock))
+ }
+ }
+ #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+ impl FromRawSocket for net::UdpSocket {
+ fn from_raw_socket(sock: RawSocket) -> net::UdpSocket {
+ let sock = sys::net::Socket::from_inner(sock);
+ net::UdpSocket::from_inner(net2::UdpSocket::from_inner(sock))
+ }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
pub mod prelude {
#[doc(no_inline)]
- pub use super::io::{Socket, Handle, AsRawSocket, AsRawHandle};
+ pub use super::io::{RawSocket, RawHandle, AsRawSocket, AsRawHandle};
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::ffi::{OsStrExt, OsStringExt};
#[doc(no_inline)]
}
}
- /// Extract the actual filedescriptor without closing it.
+ #[allow(dead_code)]
pub fn unwrap(self) -> fd_t {
let fd = self.fd;
unsafe { mem::forget(self) };
use path::{Path, PathBuf};
use ptr;
use sync::Arc;
-use sys::handle::Handle as RawHandle;
+use sys::handle::Handle;
use sys::{c, cvt};
+use sys_common::FromInner;
use vec::Vec;
-pub struct File { handle: RawHandle }
+pub struct File { handle: Handle }
pub struct FileAttr { data: c::WIN32_FILE_ATTRIBUTE_DATA }
pub struct ReadDir {
if handle == libc::INVALID_HANDLE_VALUE {
Err(Error::last_os_error())
} else {
- Ok(File { handle: RawHandle::new(handle) })
+ Ok(File { handle: Handle::new(handle) })
}
}
Ok(newpos as u64)
}
- pub fn handle(&self) -> &RawHandle { &self.handle }
+ pub fn handle(&self) -> &Handle { &self.handle }
+}
+
+impl FromInner<libc::HANDLE> for File {
+ fn from_inner(handle: libc::HANDLE) -> File {
+ File { handle: Handle::new(handle) }
+ }
}
pub fn to_utf16(s: &Path) -> Vec<u16> {
use rt;
use sync::{Once, ONCE_INIT};
use sys::c;
-use sys_common::AsInner;
+use sys_common::{AsInner, FromInner};
pub type wrlen_t = i32;
impl Drop for Socket {
fn drop(&mut self) {
- unsafe { cvt(libc::closesocket(self.0)).unwrap(); }
+ let _ = unsafe { libc::closesocket(self.0) };
}
}
impl AsInner<libc::SOCKET> for Socket {
fn as_inner(&self) -> &libc::SOCKET { &self.0 }
}
+
+impl FromInner<libc::SOCKET> for Socket {
+ fn from_inner(sock: libc::SOCKET) -> Socket { Socket(sock) }
+}
use os::windows::prelude::*;
use error::Error as StdError;
-use ffi::{OsString, OsStr, AsOsStr};
+use ffi::{OsString, OsStr};
use fmt;
use io;
use libc::types::os::arch::extra::LPWCH;
use slice;
use sys::c;
use sys::fs::FileDesc;
-use sys::handle::Handle as RawHandle;
+use sys::handle::Handle;
use libc::funcs::extra::kernel32::{
GetEnvironmentStringsW,
pub struct JoinPathsError;
pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
- where I: Iterator<Item=T>, T: AsOsStr
+ where I: Iterator<Item=T>, T: AsRef<OsStr>
{
let mut joined = Vec::new();
let sep = b';' as u16;
for (i, path) in paths.enumerate() {
- let path = path.as_os_str();
+ let path = path.as_ref();
if i > 0 { joined.push(sep) }
let v = path.encode_wide().collect::<Vec<u16>>();
if v.contains(&(b'"' as u16)) {
}
pub fn chdir(p: &path::Path) -> io::Result<()> {
- let mut p = p.as_os_str().encode_wide().collect::<Vec<_>>();
+ let p: &OsStr = p.as_ref();
+ let mut p = p.encode_wide().collect::<Vec<_>>();
p.push(0);
unsafe {
}
pub fn home_dir() -> Option<PathBuf> {
- getenv("HOME".as_os_str()).or_else(|| {
- getenv("USERPROFILE".as_os_str())
+ getenv("HOME".as_ref()).or_else(|| {
+ getenv("USERPROFILE".as_ref())
}).map(PathBuf::from).or_else(|| unsafe {
let me = c::GetCurrentProcess();
let mut token = ptr::null_mut();
if c::OpenProcessToken(me, c::TOKEN_READ, &mut token) == 0 {
return None
}
- let _handle = RawHandle::new(token);
+ let _handle = Handle::new(token);
super::fill_utf16_buf_new(|buf, mut sz| {
match c::GetUserProfileDirectoryW(token, buf, &mut sz) {
0 if libc::GetLastError() != 0 => 0,
}, super::os2path).ok()
})
}
+
+pub fn exit(code: i32) -> ! {
+ unsafe { c::ExitProcess(code as libc::c_uint) }
+}
use old_io::process::{ProcessExit, ExitStatus};
use old_io::{IoResult, IoError};
use old_io;
-use os;
+use fs::PathExt;
use old_path::{BytesContainer, GenericPath};
use ptr;
use str;
let program = cfg.env().and_then(|env| {
for (key, v) in env {
if b"PATH" != key.container_as_bytes() { continue }
+ let v = match ::str::from_utf8(v.container_as_bytes()) {
+ Ok(s) => s,
+ Err(..) => continue,
+ };
// Split the value and test each path to see if the
// program exists.
- for path in os::split_paths(v.container_as_bytes()) {
- let path = path.join(cfg.program().as_bytes())
+ for path in ::env::split_paths(v) {
+ let program = str::from_utf8(cfg.program().as_bytes()).unwrap();
+ let path = path.join(program)
.with_extension(env::consts::EXE_EXTENSION);
if path.exists() {
- return Some(CString::from_slice(path.as_vec()))
+ return Some(CString::new(path.to_str().unwrap()).unwrap())
}
}
break
#[test]
fn test_make_command_line() {
fn test_wrapper(prog: &str, args: &[&str]) -> String {
- make_command_line(&CString::from_slice(prog.as_bytes()),
+ make_command_line(&CString::new(prog).unwrap(),
&args.iter()
- .map(|a| CString::from_slice(a.as_bytes()))
+ .map(|a| CString::new(*a).unwrap())
.collect::<Vec<CString>>())
}
fn test_wrapper(prog: &str, args: &[&str]) -> String {
String::from_utf16(
&make_command_line(OsStr::from_str(prog),
- args.iter()
- .map(|a| OsString::from_str(a))
- .collect::<Vec<OsString>>()
- .as_slice())).unwrap()
+ &args.iter()
+ .map(|a| OsString::from(a))
+ .collect::<Vec<OsString>>())).unwrap()
}
assert_eq!(
Err(io::Error::last_os_error())
} else if handle.is_null() {
Err(io::Error::new(io::ErrorKind::Other,
- "no stdio handle available for this process", None))
+ "no stdio handle available for this process"))
} else {
let ret = NoClose::new(handle);
let mut out = 0;
}
fn invalid_encoding() -> io::Error {
- io::Error::new(io::ErrorKind::InvalidInput, "text was not valid unicode",
- None)
+ io::Error::new(io::ErrorKind::InvalidInput, "text was not valid unicode")
}
}
}
}
-
- /// Deprecated
- #[unstable(feature = "std_misc")]
- #[deprecated(since = "1.0.0",
- reason = "function renamed to state() and returns more info")]
- pub fn destroyed(&'static self) -> bool { self.state() == LocalKeyState::Destroyed }
}
#[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
use thunk::Thunk;
use time::Duration;
-#[allow(deprecated)] use old_io::Writer;
-
////////////////////////////////////////////////////////////////////////////////
// Thread-local storage
////////////////////////////////////////////////////////////////////////////////
self
}
- /// Redirect thread-local stdout.
- #[unstable(feature = "std_misc",
- reason = "Will likely go away after proc removal")]
- #[deprecated(since = "1.0.0",
- reason = "the old I/O module is deprecated and this function \
- will be removed with no replacement")]
- #[allow(deprecated)]
- pub fn stdout(self, _stdout: Box<Writer + Send + 'static>) -> Builder {
- self
- }
-
- /// Redirect thread-local stderr.
- #[unstable(feature = "std_misc",
- reason = "Will likely go away after proc removal")]
- #[deprecated(since = "1.0.0",
- reason = "the old I/O module is deprecated and this function \
- will be removed with no replacement")]
- #[allow(deprecated)]
- pub fn stderr(self, _stderr: Box<Writer + Send + 'static>) -> Builder {
- self
- }
-
/// Spawn a new thread, and return a join handle for it.
///
/// The child thread may outlive the parent (unless the parent thread
}
}
- /// Deprecated: use module-level free function.
- #[deprecated(since = "1.0.0", reason = "use module-level free function")]
- #[unstable(feature = "std_misc",
- reason = "may change with specifics of new Send semantics")]
- pub fn spawn<F>(f: F) -> Thread where F: FnOnce(), F: Send + 'static {
- Builder::new().spawn(f).unwrap().thread().clone()
- }
-
- /// Deprecated: use module-level free function.
- #[deprecated(since = "1.0.0", reason = "use module-level free function")]
- #[unstable(feature = "std_misc",
- reason = "may change with specifics of new Send semantics")]
- pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where
- T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
- {
- Builder::new().scoped(f).unwrap()
- }
-
- /// Deprecated: use module-level free function.
- #[deprecated(since = "1.0.0", reason = "use module-level free function")]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn current() -> Thread {
- thread_info::current_thread()
- }
-
- /// Deprecated: use module-level free function.
- #[deprecated(since = "1.0.0", reason = "use module-level free function")]
- #[unstable(feature = "std_misc", reason = "name may change")]
- pub fn yield_now() {
- unsafe { imp::yield_now() }
- }
-
- /// Deprecated: use module-level free function.
- #[deprecated(since = "1.0.0", reason = "use module-level free function")]
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn panicking() -> bool {
- unwind::panicking()
- }
-
- /// Deprecated: use module-level free function.
- #[deprecated(since = "1.0.0", reason = "use module-level free function")]
- #[unstable(feature = "std_misc", reason = "recently introduced")]
- pub fn park() {
- let thread = current();
- let mut guard = thread.inner.lock.lock().unwrap();
- while !*guard {
- guard = thread.inner.cvar.wait(guard).unwrap();
- }
- *guard = false;
- }
-
- /// Deprecated: use module-level free function.
- #[deprecated(since = "1.0.0", reason = "use module-level free function")]
- #[unstable(feature = "std_misc", reason = "recently introduced")]
- pub fn park_timeout(duration: Duration) {
- let thread = current();
- let mut guard = thread.inner.lock.lock().unwrap();
- if !*guard {
- let (g, _) = thread.inner.cvar.wait_timeout(guard, duration).unwrap();
- guard = g;
- }
- *guard = false;
- }
-
/// Atomically makes the handle's token available if it is not already.
///
/// See the module doc for more detail.
&self.inner.thread
}
- /// Wait for the associated thread to finish, returning the result of the thread's
- /// calculation.
+ /// Wait for the associated thread to finish, returning the result of the
+ /// thread's calculation.
///
/// # Panics
///
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send> JoinGuard<'static, T> {
- /// Detaches the child thread, allowing it to outlive its parent.
- #[deprecated(since = "1.0.0", reason = "use spawn instead")]
- #[unstable(feature = "std_misc")]
- pub fn detach(mut self) {
- unsafe { imp::detach(self.inner.native) };
- self.inner.joined = true; // avoid joining in the destructor
- }
-}
-
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> {
use any::Any;
use sync::mpsc::{channel, Sender};
- use boxed::BoxAny;
use result;
use std::old_io::{ChanReader, ChanWriter};
use super::{Builder};
}
#[derive(Clone)]
-struct LinkedPathNode<'a> {
+pub struct LinkedPathNode<'a> {
node: PathElem,
next: LinkedPath<'a>,
}
-type LinkedPath<'a> = Option<&'a LinkedPathNode<'a>>;
+#[derive(Copy, Clone)]
+pub struct LinkedPath<'a>(Option<&'a LinkedPathNode<'a>>);
+
+impl<'a> LinkedPath<'a> {
+ pub fn empty() -> LinkedPath<'a> {
+ LinkedPath(None)
+ }
+
+ pub fn from(node: &'a LinkedPathNode) -> LinkedPath<'a> {
+ LinkedPath(Some(node))
+ }
+}
impl<'a> Iterator for LinkedPath<'a> {
type Item = PathElem;
fn next(&mut self) -> Option<PathElem> {
- match *self {
+ match self.0 {
Some(node) => {
*self = node.next;
Some(node.node)
pub fn with_path<T, F>(&self, id: NodeId, f: F) -> T where
F: FnOnce(PathElems) -> T,
{
- self.with_path_next(id, None, f)
+ self.with_path_next(id, LinkedPath::empty(), f)
}
pub fn path_to_string(&self, id: NodeId) -> String {
_ => f([].iter().cloned().chain(next))
}
} else {
- self.with_path_next(parent, Some(&LinkedPathNode {
+ self.with_path_next(parent, LinkedPath::from(&LinkedPathNode {
node: self.get_path_elem(id),
next: next
}), f)
("start", "1.0.0", Active),
("main", "1.0.0", Active),
+ ("fundamental", "1.0.0", Active),
+
// Deprecate after snapshot
- // SNAP a923278
+ // SNAP 5520801
("unsafe_destructor", "1.0.0", Active),
// A temporary feature gate used to enable parser extensions needed
// A way to temporarily opt out of opt in copy. This will *never* be accepted.
("opt_out_copy", "1.0.0", Removed),
- // A way to temporarily opt out of the new orphan rules. This will *never* be accepted.
- ("old_orphan_check", "1.0.0", Deprecated),
-
// OIBIT specific features
("optin_builtin_traits", "1.0.0", Active),
/// currently being considered for addition/removal.
Active,
- /// Represents a feature gate that is temporarily enabling deprecated behavior.
- /// This gate will never be accepted.
- Deprecated,
-
/// Represents a feature which has since been removed (it was once Active)
Removed,
("allow_internal_unstable", Gated("allow_internal_unstable",
EXPLAIN_ALLOW_INTERNAL_UNSTABLE)),
+ ("fundamental", Gated("fundamental",
+ "the `#[fundamental]` attribute \
+ is an experimental feature")),
+
// FIXME: #14408 whitelist docs since rustdoc looks at them
("doc", Whitelisted),
("stable", Whitelisted),
("unstable", Whitelisted),
- // FIXME: #19470 this shouldn't be needed forever
- ("old_orphan_check", Whitelisted),
-
("rustc_paren_sugar", Gated("unboxed_closures",
"unboxed_closures are still evolving")),
("rustc_reflect_like", Gated("reflect",
pub allow_trace_macros: bool,
pub allow_internal_unstable: bool,
pub allow_custom_derive: bool,
- pub old_orphan_check: bool,
pub simd_ffi: bool,
pub unmarked_api: bool,
/// spans of #![feature] attrs for stable language features. for error reporting
allow_trace_macros: false,
allow_internal_unstable: false,
allow_custom_derive: false,
- old_orphan_check: false,
simd_ffi: false,
unmarked_api: false,
declared_stable_lang_features: Vec::new(),
},
_ => {}
}
-
- if attr::contains_name(&i.attrs[..],
- "old_orphan_check") {
- self.gate_feature(
- "old_orphan_check",
- i.span,
- "the new orphan check rules will eventually be strictly enforced");
- }
}
_ => {}
Some(&(name, _, Active)) => {
cx.features.push(name);
}
- Some(&(name, _, Deprecated)) => {
- cx.features.push(name);
- span_handler.span_warn(
- mi.span,
- "feature is deprecated and will only be available \
- for a limited time, please rewrite code that relies on it");
- }
Some(&(_, _, Removed)) => {
span_handler.span_err(mi.span, "feature has been removed");
}
allow_trace_macros: cx.has_feature("trace_macros"),
allow_internal_unstable: cx.has_feature("allow_internal_unstable"),
allow_custom_derive: cx.has_feature("custom_derive"),
- old_orphan_check: cx.has_feature("old_orphan_check"),
simd_ffi: cx.has_feature("simd_ffi"),
unmarked_api: cx.has_feature("unmarked_api"),
declared_stable_lang_features: accepted_features,
#![feature(unicode)]
#![feature(path_ext)]
#![feature(str_char)]
-#![feature(convert)]
#![feature(into_cow)]
#![feature(slice_patterns)]
let base = 10;
// find the integer representing the name
- self.scan_digits(base);
- let encoded_name: u32 = self.with_str_from(start_bpos, |s| {
+ self.scan_digits(base, base);
+ let encoded_name : u32 = self.with_str_from(start_bpos, |s| {
u32::from_str_radix(s, 10).unwrap_or_else(|_| {
panic!("expected digits representing a name, got {:?}, {}, range [{:?},{:?}]",
s, whence, start_bpos, self.last_pos);
// find the integer representing the ctxt
let start_bpos = self.last_pos;
- self.scan_digits(base);
+ self.scan_digits(base, base);
let encoded_ctxt : ast::SyntaxContext = self.with_str_from(start_bpos, |s| {
u32::from_str_radix(s, 10).unwrap_or_else(|_| {
panic!("expected digits representing a ctxt, got {:?}, {}", s, whence);
ctxt: encoded_ctxt, }
}
- /// Scan through any digits (base `radix`) or underscores, and return how
- /// many digits there were.
- fn scan_digits(&mut self, radix: u32) -> usize {
+ /// Scan through any digits (base `scan_radix`) or underscores,
+ /// and return how many digits there were.
+ ///
+ /// `real_radix` represents the true radix of the number we're
+ /// interested in, and errors will be emitted for any digits
+ /// between `real_radix` and `scan_radix`.
+ fn scan_digits(&mut self, real_radix: u32, scan_radix: u32) -> usize {
+ assert!(real_radix <= scan_radix);
let mut len = 0;
loop {
let c = self.curr;
if c == Some('_') { debug!("skipping a _"); self.bump(); continue; }
- match c.and_then(|cc| cc.to_digit(radix)) {
+ match c.and_then(|cc| cc.to_digit(scan_radix)) {
Some(_) => {
debug!("{:?} in scan_digits", c);
+ // check that the hypothetical digit is actually
+ // in range for the true radix
+ if c.unwrap().to_digit(real_radix).is_none() {
+ self.err_span_(self.last_pos, self.pos,
+ &format!("invalid digit for a base {} literal",
+ real_radix));
+ }
len += 1;
self.bump();
}
if c == '0' {
match self.curr.unwrap_or('\0') {
- 'b' => { self.bump(); base = 2; num_digits = self.scan_digits(2); }
- 'o' => { self.bump(); base = 8; num_digits = self.scan_digits(8); }
- 'x' => { self.bump(); base = 16; num_digits = self.scan_digits(16); }
+ 'b' => { self.bump(); base = 2; num_digits = self.scan_digits(2, 10); }
+ 'o' => { self.bump(); base = 8; num_digits = self.scan_digits(8, 10); }
+ 'x' => { self.bump(); base = 16; num_digits = self.scan_digits(16, 16); }
'0'...'9' | '_' | '.' => {
- num_digits = self.scan_digits(10) + 1;
+ num_digits = self.scan_digits(10, 10) + 1;
}
_ => {
// just a 0
}
}
} else if c.is_digit(10) {
- num_digits = self.scan_digits(10) + 1;
+ num_digits = self.scan_digits(10, 10) + 1;
} else {
num_digits = 0;
}
// with a number
self.bump();
if self.curr.unwrap_or('\0').is_digit(10) {
- self.scan_digits(10);
+ self.scan_digits(10, 10);
self.scan_float_exponent();
}
let last_pos = self.last_pos;
if self.curr_is('-') || self.curr_is('+') {
self.bump();
}
- if self.scan_digits(10) == 0 {
+ if self.scan_digits(10, 10) == 0 {
self.err_span_(self.last_pos, self.pos, "expected at least one digit in exponent")
}
}
let res = match u64::from_str_radix(s, base).ok() {
Some(r) => r,
- None => { sd.span_err(sp, "int literal is too large"); 0 }
+ None => {
+ // small bases are lexed as if they were base 10, e.g, the string
+ // might be `0b10201`. This will cause the conversion above to fail,
+ // but these cases have errors in the lexer: we don't want to emit
+ // two errors, and we especially don't want to emit this error since
+ // it isn't necessarily true.
+ let already_errored = base < 10 &&
+ s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base));
+
+ if !already_errored {
+ sd.span_err(sp, "int literal is too large");
+ }
+ 0
+ }
};
// adjust the sign
NodeName(&'a ast::Name),
NodeBlock(&'a ast::Block),
NodeItem(&'a ast::Item),
+ NodeSubItem(ast::NodeId),
NodeExpr(&'a ast::Expr),
NodePat(&'a ast::Pat),
}
pub fn print_trait_item(&mut self, ti: &ast::TraitItem)
-> io::Result<()> {
+ try!(self.ann.pre(self, NodeSubItem(ti.id)));
try!(self.hardbreak_if_not_bol());
try!(self.maybe_print_comment(ti.span.lo));
try!(self.print_outer_attributes(&ti.attrs));
try!(self.print_method_sig(ti.ident, sig, ast::Inherited));
if let Some(ref body) = *body {
try!(self.nbsp());
- self.print_block_with_attrs(body, &ti.attrs)
+ try!(self.print_block_with_attrs(body, &ti.attrs));
} else {
- word(&mut self.s, ";")
+ try!(word(&mut self.s, ";"));
}
}
ast::TypeTraitItem(ref bounds, ref default) => {
- self.print_associated_type(ti.ident, Some(bounds),
- default.as_ref().map(|ty| &**ty))
+ try!(self.print_associated_type(ti.ident, Some(bounds),
+ default.as_ref().map(|ty| &**ty)));
}
}
+ self.ann.post(self, NodeSubItem(ti.id))
}
pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> io::Result<()> {
+ try!(self.ann.pre(self, NodeSubItem(ii.id)));
try!(self.hardbreak_if_not_bol());
try!(self.maybe_print_comment(ii.span.lo));
try!(self.print_outer_attributes(&ii.attrs));
try!(self.head(""));
try!(self.print_method_sig(ii.ident, sig, ii.vis));
try!(self.nbsp());
- self.print_block_with_attrs(body, &ii.attrs)
+ try!(self.print_block_with_attrs(body, &ii.attrs));
}
ast::TypeImplItem(ref ty) => {
- self.print_associated_type(ii.ident, None, Some(ty))
+ try!(self.print_associated_type(ii.ident, None, Some(ty)));
}
ast::MacImplItem(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _),
..}) => {
try!(self.print_tts(&tts[..]));
try!(self.pclose());
try!(word(&mut self.s, ";"));
- self.end()
+ try!(self.end())
}
}
+ self.ann.post(self, NodeSubItem(ii.id))
}
pub fn print_outer_attributes(&mut self,
fn test_move_iter() {
let v = SmallVector::zero();
let v: Vec<isize> = v.into_iter().collect();
- assert_eq!(Vec::new(), v);
+ assert_eq!(v, Vec::new());
let v = SmallVector::one(1);
- assert_eq!([1], v.into_iter().collect::<Vec<_>>());
+ assert_eq!(v.into_iter().collect::<Vec<_>>(), [1]);
let v = SmallVector::many(vec![1, 2, 3]);
- assert_eq!([1, 2, 3], v.into_iter().collect::<Vec<_>>());
+ assert_eq!(v.into_iter().collect::<Vec<_>>(), [1, 2, 3]);
}
#[test]
#![feature(std_misc)]
#![feature(str_char)]
#![feature(path_ext)]
-#![feature(convert)]
#![cfg_attr(windows, feature(libc))]
#[macro_use] extern crate log;
#![feature(std_misc)]
#![feature(libc)]
#![feature(set_stdio)]
-#![feature(os)]
-#![feature(convert)]
#![cfg_attr(test, feature(old_io))]
extern crate getopts;
if std::rt::util::limit_thread_creation_due_to_osx_and_valgrind() {
1
} else {
- std::os::num_cpus()
+ extern { fn rust_get_num_cpus() -> libc::uintptr_t; }
+ unsafe { rust_get_num_cpus() as usize }
}
}
}
#![feature(rustdoc)]
#![feature(rustc_private)]
#![feature(path_relative_from)]
-#![feature(convert)]
extern crate rustdoc;
extern crate rustc_back;
+S 2015-03-27 5520801
+ bitrig-x86_64 41de2c7a69a1ac648d3fa3b65e96a29bdc122163
+ freebsd-x86_64 0910bbad35e213f679d0433884fd51398eb3bc8d
+ linux-i386 1ef82402ed16f5a6d2f87a9a62eaa83170e249ec
+ linux-x86_64 ef2154372e97a3cb687897d027fd51c8f2c5f349
+ macos-i386 0310b1a970f2da7e61770fd14dbbbdca3b518234
+ macos-x86_64 5f35d9c920b8083a7420ef8cf5b00d5ef3085dfa
+ winnt-i386 808b7961f85872f04ec15ad0d3e9e23ae9bc0c3b
+ winnt-x86_64 903a99a58f57a9bd9848cc68a2445dda881f1ee8
+
S 2015-03-25 a923278
bitrig-x86_64 41de2c7a69a1ac648d3fa3b65e96a29bdc122163
freebsd-x86_64 cd02c86a9218da73b2a45aff293787010d33bf3e
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "rlib"]
+#![feature(fundamental)]
+
+use std::marker::MarkerTrait;
+
+pub trait MyCopy : MarkerTrait { }
+impl MyCopy for i32 { }
+
+pub struct MyStruct<T>(T);
+
+#[fundamental]
+pub struct MyFundamentalStruct<T>(T);
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
-#![feature(rustc_private, core)]
+#![feature(rustc_private, core, step_by)]
extern crate arena;
-use std::iter::range_step;
use std::thread;
use arena::TypedArena;
let long_lived_arena = TypedArena::new();
let long_lived_tree = bottom_up_tree(&long_lived_arena, 0, max_depth);
- let messages = range_step(min_depth, max_depth + 1, 2).map(|depth| {
+ let messages = (min_depth..max_depth + 1).step_by(2).map(|depth| {
use std::num::Int;
let iterations = 2.pow((max_depth - depth + min_depth) as u32);
thread::scoped(move || inner(depth, iterations))
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
-#![feature(core)]
+#![feature(step_by)]
-use std::{cmp, iter, mem};
+use std::{cmp, mem};
use std::thread;
fn rotate(x: &mut [i32]) {
let mut futures = vec![];
let k = perm.max() / N;
- for (_, j) in (0..N).zip(iter::count(0, k)) {
+ for (_, j) in (0..N).zip((0..).step_by(k)) {
let max = cmp::min(j+k, perm.max());
futures.push(thread::scoped(move|| {
// start processing if this is the one
('>', false) => {
- match line[1..].find_str("THREE") {
+ match line[1..].find("THREE") {
Some(_) => { proc_mode = true; }
None => { }
}
fn parallel<'a,T, F>(v: &mut [T], ref f: F)
where T: Send + Sync + 'a,
F: Fn(usize, &mut [T]) + Sync + 'a {
- let size = v.len() / os::num_cpus() + 1;
+ // FIXME: pick a more appropriate parallel factor
+ let parallelism = 4;
+ let size = v.len() / parallelism + 1;
v.chunks_mut(size).enumerate().map(|(i, chunk)| {
thread::scoped(move|| {
f(i * size, chunk)
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:coherence_lib.rs
+
+// pretty-expanded FIXME #23616
+
+// Test that the `Pair` type reports an error if it contains type
+// parameters, even when they are covered by local types. This test
+// was originally intended to test the opposite, but the rules changed
+// with RFC 1023 and this became illegal.
+
+extern crate coherence_lib as lib;
+use lib::{Remote,Pair};
+
+pub struct Cover<T>(T);
+
+impl<T> Remote for Pair<T,Cover<T>> { }
+//~^ ERROR E0210
+
+fn main() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:coherence_lib.rs
+
+// Test that the `Pair` type reports an error if it contains type
+// parameters, even when they are covered by local types. This test
+// was originally intended to test the opposite, but the rules changed
+// with RFC 1023 and this became illegal.
+
+// pretty-expanded FIXME #23616
+
+extern crate coherence_lib as lib;
+use lib::{Remote,Pair};
+
+pub struct Cover<T>(T);
+
+impl<T> Remote for Pair<Cover<T>,T> { } //~ ERROR E0210
+
+fn main() { }
// aux-build:coherence_lib.rs
-// Test that it's not ok for U to appear uncovered
+// Test that it's not ok for T to appear uncovered
extern crate coherence_lib as lib;
use lib::{Remote,Pair};
pub struct Cover<T>(T);
impl<T,U> Remote for Pair<Cover<T>,U> { }
-//~^ ERROR type parameter `U` must be used as the type parameter for some local type
+//~^ ERROR type parameter `T` must be used as the type parameter for some local type
fn main() { }
impl Copy for TestE {}
impl Copy for MyType {}
+
+impl Copy for &'static mut MyType {}
+//~^ ERROR E0206
+
impl Copy for (MyType, MyType) {}
//~^ ERROR E0206
+//~| ERROR E0117
impl Copy for &'static NotSync {}
//~^ ERROR E0206
impl Copy for [MyType] {}
//~^ ERROR E0206
+//~| ERROR E0117
impl Copy for &'static [NotSync] {}
//~^ ERROR E0206
+//~| ERROR E0117
fn main() {
}
unsafe impl Send for TestE {}
unsafe impl Send for MyType {}
unsafe impl Send for (MyType, MyType) {}
-//~^ ERROR E0321
+//~^ ERROR E0117
unsafe impl Send for &'static NotSync {}
//~^ ERROR E0321
unsafe impl Send for [MyType] {}
-//~^ ERROR E0321
+//~^ ERROR E0117
unsafe impl Send for &'static [NotSync] {}
-//~^ ERROR E0321
-//~| ERROR conflicting implementations
+//~^ ERROR E0117
+//~| ERROR E0119
fn main() {
}
impl !Sync for NotSync {}
impl Sized for TestE {} //~ ERROR E0322
+
impl Sized for MyType {} //~ ERROR E0322
-impl Sized for (MyType, MyType) {} //~ ERROR E0322
+
+impl Sized for (MyType, MyType) {} //~ ERROR E0117
+
impl Sized for &'static NotSync {} //~ ERROR E0322
-impl Sized for [MyType] {} //~ ERROR E0322
+
+impl Sized for [MyType] {} //~ ERROR E0117
//~^ ERROR E0277
-impl Sized for &'static [NotSync] {} //~ ERROR E0322
+
+impl Sized for &'static [NotSync] {} //~ ERROR E0117
fn main() {
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Tests that we consider `Box<U>: !Sugar` to be ambiguous, even
+// though we see no impl of `Sugar` for `Box`. Therefore, an overlap
+// error is reported for the following pair of impls (#23516).
+
+pub trait Sugar { fn dummy(&self) { } }
+pub trait Sweet { fn dummy(&self) { } }
+impl<T:Sugar> Sweet for T { } //~ ERROR E0119
+impl<U:Sugar> Sweet for Box<U> { }
+fn main() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that a local, generic type appearing within a
+// *non-fundamental* remote type like `Vec` is not considered local.
+
+// aux-build:coherence_lib.rs
+
+// pretty-expanded FIXME #23616
+
+extern crate coherence_lib as lib;
+use lib::Remote;
+
+struct Local<T>(T);
+
+impl<T> Remote for Vec<Local<T>> { } //~ ERROR E0210
+
+fn main() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that a local type (with no type parameters) appearing within a
+// *non-fundamental* remote type like `Vec` is not considered local.
+
+// aux-build:coherence_lib.rs
+
+// pretty-expanded FIXME #23616
+
+extern crate coherence_lib as lib;
+use lib::Remote;
+
+struct Local;
+
+impl Remote for Vec<Local> { } //~ ERROR E0117
+
+fn main() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+// aux-build:coherence_copy_like_lib.rs
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+extern crate coherence_copy_like_lib as lib;
+
+use std::marker::MarkerTrait;
+
+struct MyType { x: i32 }
+
+trait MyTrait : MarkerTrait { }
+impl<T: lib::MyCopy> MyTrait for T { }
+
+// `MyFundamentalStruct` is declared fundamental, so we can test that
+//
+// MyFundamentalStruct<MyTrait>: !MyTrait
+//
+// Huzzah.
+impl MyTrait for lib::MyFundamentalStruct<MyType> { }
+
+#[rustc_error]
+fn main() { } //~ ERROR compilation successful
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+// aux-build:coherence_copy_like_lib.rs
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+extern crate coherence_copy_like_lib as lib;
+
+use std::marker::MarkerTrait;
+
+struct MyType { x: i32 }
+
+trait MyTrait : MarkerTrait { }
+impl<T: lib::MyCopy> MyTrait for T { }
+
+// `MyFundamentalStruct` is declared fundamental, so we can test that
+//
+// MyFundamentalStruct<&MyTrait>: !MyTrait
+//
+// Huzzah.
+impl<'a> MyTrait for lib::MyFundamentalStruct<&'a MyType> { }
+
+#[rustc_error]
+fn main() { } //~ ERROR compilation successful
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+// aux-build:coherence_copy_like_lib.rs
+
+#![feature(rustc_attrs)]
+
+extern crate coherence_copy_like_lib as lib;
+
+use std::marker::MarkerTrait;
+
+struct MyType { x: i32 }
+
+trait MyTrait : MarkerTrait { }
+
+impl<T: lib::MyCopy> MyTrait for T { } //~ ERROR E0119
+
+// Tuples are not fundamental.
+impl MyTrait for lib::MyFundamentalStruct<(MyType,)> { }
+
+#[rustc_error]
+fn main() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:coherence_copy_like_lib.rs
+
+// Test that we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+extern crate coherence_copy_like_lib as lib;
+
+use std::marker::MarkerTrait;
+
+struct MyType { x: i32 }
+
+trait MyTrait : MarkerTrait { }
+impl<T: lib::MyCopy> MyTrait for T { } //~ ERROR E0119
+
+// `MyStruct` is not declared fundamental, therefore this would
+// require that
+//
+// MyStruct<MyType>: !MyTrait
+//
+// which we cannot approve.
+impl MyTrait for lib::MyStruct<MyType> { }
+
+fn main() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+// aux-build:coherence_copy_like_lib.rs
+
+extern crate coherence_copy_like_lib as lib;
+
+use std::marker::MarkerTrait;
+
+struct MyType { x: i32 }
+
+trait MyTrait : MarkerTrait { }
+impl<T: lib::MyCopy> MyTrait for T { } //~ ERROR E0119
+
+// Tuples are not fundamental, therefore this would require that
+//
+// (MyType,): !MyTrait
+//
+// which we cannot approve.
+impl MyTrait for (MyType,) { }
+
+fn main() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+// aux-build:coherence_copy_like_lib.rs
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+extern crate coherence_copy_like_lib as lib;
+
+struct MyType { x: i32 }
+
+// These are all legal because they are all fundamental types:
+
+impl lib::MyCopy for MyType { }
+impl<'a> lib::MyCopy for &'a MyType { }
+impl<'a> lib::MyCopy for &'a Box<MyType> { }
+impl lib::MyCopy for Box<MyType> { }
+impl lib::MyCopy for lib::MyFundamentalStruct<MyType> { }
+impl lib::MyCopy for lib::MyFundamentalStruct<Box<MyType>> { }
+
+#[rustc_error]
+fn main() { } //~ ERROR compilation successful
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+// aux-build:coherence_copy_like_lib.rs
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+extern crate coherence_copy_like_lib as lib;
+
+struct MyType { x: i32 }
+
+// These are all legal because they are all fundamental types:
+
+// MyStruct is not fundamental.
+impl lib::MyCopy for lib::MyStruct<MyType> { } //~ ERROR E0117
+
+#[rustc_error]
+fn main() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+// aux-build:coherence_copy_like_lib.rs
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+extern crate coherence_copy_like_lib as lib;
+
+struct MyType { x: i32 }
+
+// These are all legal because they are all fundamental types:
+
+// Tuples are not fundamental, so this is not a local impl.
+impl lib::MyCopy for (MyType,) { } //~ ERROR E0117
+
+#[rustc_error]
+fn main() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+// aux-build:coherence_copy_like_lib.rs
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+extern crate coherence_copy_like_lib as lib;
+
+struct MyType { x: i32 }
+
+// naturally, legal
+impl lib::MyCopy for MyType { }
+
+#[rustc_error]
+fn main() { } //~ ERROR compilation successful
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Evaluation of constants in refutable patterns goes through
+// different compiler control-flow paths.
+
+#![allow(unused_imports)]
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const NEG_128: i8 = -128;
+const NEG_NEG_128: i8 = -NEG_128;
+//~^ ERROR constant evaluation error: attempted to negate with overflow
+//~| ERROR attempted to negate with overflow
+
+fn main() {
+ match -128i8 {
+ NEG_NEG_128 => println!("A"),
+ _ => println!("B"),
+ }
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Evaluation of constants in array-elem count goes through different
+// compiler control-flow paths.
+//
+// This test is checking the count in an array expression.
+
+// FIXME (#23926): the error output is not consistent between a
+// self-hosted and a cross-compiled setup; therefore resorting to
+// error-pattern for now.
+
+// error-pattern: expected constant integer for repeat count, but attempted to add with overflow
+
+#![allow(unused_imports)]
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const A_I8_I
+ : [u32; (i8::MAX as usize) + 1]
+ = [0; (i8::MAX + 1) as usize];
+
+fn main() {
+ foo(&A_I8_I[..]);
+}
+
+fn foo<T:fmt::Debug>(x: T) {
+ println!("{:?}", x);
+}
+
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Evaluation of constants in array-elem count goes through different
+// compiler control-flow paths.
+//
+// This test is checking the count in an array expression.
+//
+// This is a variation of another such test, but in this case the
+// types for the left- and right-hand sides of the addition do not
+// match (as well as overflow).
+
+// FIXME (#23926): the error output is not consistent between a
+// self-hosted and a cross-compiled setup; therefore resorting to
+// error-pattern for now.
+
+// error-pattern: mismatched types
+
+#![allow(unused_imports)]
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const A_I8_I
+ : [u32; (i8::MAX as usize) + 1]
+ = [0; (i8::MAX + 1u8) as usize];
+
+fn main() {
+ foo(&A_I8_I[..]);
+}
+
+fn foo<T:fmt::Debug>(x: T) {
+ println!("{:?}", x);
+}
+
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-test this should fail to compile (#23833)
+
+// Evaluation of constants in array-elem count goes through different
+// compiler control-flow paths.
+//
+// This test is checking the count in an array type.
+
+#![allow(unused_imports)]
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const A_I8_T
+ : [u32; (i8::MAX as i8 + 1i8) as usize]
+ //~^ ERROR error evaluating count: attempted to add with overflow
+ = [0; (i8::MAX as usize) + 1];
+
+fn main() {
+ foo(&A_I8_T[..]);
+}
+
+fn foo<T:fmt::Debug>(x: T) {
+ println!("{:?}", x);
+}
+
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Evaluation of constants in array-elem count goes through different
+// compiler control-flow paths.
+//
+// This test is checking the count in an array type.
+
+#![allow(unused_imports)]
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const A_I8_T
+ : [u32; (i8::MAX as i8 + 1u8) as usize]
+ //~^ ERROR mismatched types
+ //~| the trait `core::ops::Add<u8>` is not implemented for the type `i8`
+ //~| the trait `core::ops::Add<u8>` is not implemented for the type `i8`
+ = [0; (i8::MAX as usize) + 1];
+
+fn main() {
+ foo(&A_I8_T[..]);
+}
+
+fn foo<T:fmt::Debug>(x: T) {
+ println!("{:?}", x);
+}
+
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(unused_imports)]
+
+// Note: the relevant lint pass here runs before some of the constant
+// evaluation below (e.g. that performed by trans and llvm), so if you
+// change this warn to a deny, then the compiler will exit before
+// those errors are detected.
+#![warn(unsigned_negation)]
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const VALS_I8: (i8, i8, i8, i8) =
+ (-i8::MIN,
+ //~^ ERROR attempted to negate with overflow
+ i8::MIN - 1,
+ //~^ ERROR attempted to sub with overflow
+ i8::MAX + 1,
+ //~^ ERROR attempted to add with overflow
+ i8::MIN * 2,
+ //~^ ERROR attempted to mul with overflow
+ );
+
+const VALS_I16: (i16, i16, i16, i16) =
+ (-i16::MIN,
+ //~^ ERROR attempted to negate with overflow
+ i16::MIN - 1,
+ //~^ ERROR attempted to sub with overflow
+ i16::MAX + 1,
+ //~^ ERROR attempted to add with overflow
+ i16::MIN * 2,
+ //~^ ERROR attempted to mul with overflow
+ );
+
+const VALS_I32: (i32, i32, i32, i32) =
+ (-i32::MIN,
+ //~^ ERROR attempted to negate with overflow
+ i32::MIN - 1,
+ //~^ ERROR attempted to sub with overflow
+ i32::MAX + 1,
+ //~^ ERROR attempted to add with overflow
+ i32::MIN * 2,
+ //~^ ERROR attempted to mul with overflow
+ );
+
+const VALS_I64: (i64, i64, i64, i64) =
+ (-i64::MIN,
+ //~^ ERROR attempted to negate with overflow
+ i64::MIN - 1,
+ //~^ ERROR attempted to sub with overflow
+ i64::MAX + 1,
+ //~^ ERROR attempted to add with overflow
+ i64::MAX * 2,
+ //~^ ERROR attempted to mul with overflow
+ );
+
+const VALS_U8: (u8, u8, u8, u8) =
+ (-u8::MIN,
+ //~^ WARNING negation of unsigned int variable may be unintentional
+ // (The above is separately linted; unsigned negation is defined to be !x+1.)
+ u8::MIN - 1,
+ //~^ ERROR attempted to sub with overflow
+ u8::MAX + 1,
+ //~^ ERROR attempted to add with overflow
+ u8::MAX * 2,
+ //~^ ERROR attempted to mul with overflow
+ );
+
+const VALS_U16: (u16, u16, u16, u16) =
+ (-u16::MIN,
+ //~^ WARNING negation of unsigned int variable may be unintentional
+ // (The above is separately linted; unsigned negation is defined to be !x+1.)
+ u16::MIN - 1,
+ //~^ ERROR attempted to sub with overflow
+ u16::MAX + 1,
+ //~^ ERROR attempted to add with overflow
+ u16::MAX * 2,
+ //~^ ERROR attempted to mul with overflow
+ );
+
+const VALS_U32: (u32, u32, u32, u32) =
+ (-u32::MIN,
+ //~^ WARNING negation of unsigned int variable may be unintentional
+ // (The above is separately linted; unsigned negation is defined to be !x+1.)
+ u32::MIN - 1,
+ //~^ ERROR attempted to sub with overflow
+ u32::MAX + 1,
+ //~^ ERROR attempted to add with overflow
+ u32::MAX * 2,
+ //~^ ERROR attempted to mul with overflow
+ );
+
+const VALS_U64: (u64, u64, u64, u64) =
+ (-u64::MIN,
+ //~^ WARNING negation of unsigned int variable may be unintentional
+ // (The above is separately linted; unsigned negation is defined to be !x+1.)
+ u64::MIN - 1,
+ //~^ ERROR attempted to sub with overflow
+ u64::MAX + 1,
+ //~^ ERROR attempted to add with overflow
+ u64::MAX * 2,
+ //~^ ERROR attempted to mul with overflow
+ );
+
+fn main() {
+ foo(VALS_I8);
+ foo(VALS_I16);
+ foo(VALS_I32);
+ foo(VALS_I64);
+
+ foo(VALS_U8);
+ foo(VALS_U16);
+ foo(VALS_U32);
+ foo(VALS_U64);
+}
+
+fn foo<T:fmt::Debug>(x: T) {
+ println!("{:?}", x);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// When explicit discriminant value has
+// a type that does not match the representation
+// type, rustc should fail gracefully.
+
+// See also run-pass/discrim-explicit-23030.rs where the input types
+// are correct.
+
+#![allow(dead_code, unused_variables, unused_imports)]
+
+use std::{i8,u8,i16,u16,i32,u32,i64, u64};
+
+fn f_i8() {
+ #[repr(i8)]
+ enum A {
+ Ok = i8::MAX - 1,
+ Ok2,
+ OhNo = 0_u8,
+ //~^ ERROR mismatched types
+ }
+
+ let x = A::Ok;
+}
+
+fn f_u8() {
+ #[repr(u8)]
+ enum A {
+ Ok = u8::MAX - 1,
+ Ok2,
+ OhNo = 0_i8,
+ //~^ ERROR mismatched types
+ }
+
+ let x = A::Ok;
+}
+
+fn f_i16() {
+ #[repr(i16)]
+ enum A {
+ Ok = i16::MAX - 1,
+ Ok2,
+ OhNo = 0_u16,
+ //~^ ERROR mismatched types
+ }
+
+ let x = A::Ok;
+}
+
+fn f_u16() {
+ #[repr(u16)]
+ enum A {
+ Ok = u16::MAX - 1,
+ Ok2,
+ OhNo = 0_i16,
+ //~^ ERROR mismatched types
+ }
+
+ let x = A::Ok;
+}
+
+fn f_i32() {
+ #[repr(i32)]
+ enum A {
+ Ok = i32::MAX - 1,
+ Ok2,
+ OhNo = 0_u32,
+ //~^ ERROR mismatched types
+ }
+
+ let x = A::Ok;
+}
+
+fn f_u32() {
+ #[repr(u32)]
+ enum A {
+ Ok = u32::MAX - 1,
+ Ok2,
+ OhNo = 0_i32,
+ //~^ ERROR mismatched types
+ }
+
+ let x = A::Ok;
+}
+
+fn f_i64() {
+ #[repr(i64)]
+ enum A {
+ Ok = i64::MAX - 1,
+ Ok2,
+ OhNo = 0_u64,
+ //~^ ERROR mismatched types
+ }
+
+ let x = A::Ok;
+}
+
+fn f_u64() {
+ #[repr(u64)]
+ enum A {
+ Ok = u64::MAX - 1,
+ Ok2,
+ OhNo = 0_i64,
+ //~^ ERROR mismatched types
+ }
+
+ let x = A::Ok;
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+
+// Issue 23030: Detect overflowing discriminant
+//
+// Check that we detect the overflow even if enum is not used.
+
+// See also run-pass/discrim-explicit-23030.rs where the suggested
+// workaround is tested.
+
+use std::{i8,u8,i16,u16,i32,u32,i64, u64};
+
+fn f_i8() {
+ #[repr(i8)]
+ enum A {
+ Ok = i8::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed on value after 127: i8; set explicitly via OhNo = -128 if that is desired outcome
+ }
+}
+
+fn f_u8() {
+ #[repr(u8)]
+ enum A {
+ Ok = u8::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed on value after 255: u8; set explicitly via OhNo = 0 if that is desired outcome
+ }
+}
+
+fn f_i16() {
+ #[repr(i16)]
+ enum A {
+ Ok = i16::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+}
+
+fn f_u16() {
+ #[repr(u16)]
+ enum A {
+ Ok = u16::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+}
+
+fn f_i32() {
+ #[repr(i32)]
+ enum A {
+ Ok = i32::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+}
+
+fn f_u32() {
+ #[repr(u32)]
+ enum A {
+ Ok = u32::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+}
+
+fn f_i64() {
+ #[repr(i64)]
+ enum A {
+ Ok = i64::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+}
+
+fn f_u64() {
+ #[repr(u64)]
+ enum A {
+ Ok = u64::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+
+// Issue 23030: Detect overflowing discriminant
+
+// See also run-pass/discrim-explicit-23030.rs where the suggested
+// workaround is tested.
+
+use std::{i8,u8,i16,u16,i32,u32,i64, u64};
+
+fn f_i8() {
+ #[repr(i8)]
+ enum A {
+ Ok = i8::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed on value after 127: i8; set explicitly via OhNo = -128 if that is desired outcome
+ }
+
+ let x = A::Ok;
+}
+
+fn f_u8() {
+ #[repr(u8)]
+ enum A {
+ Ok = u8::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed on value after 255: u8; set explicitly via OhNo = 0 if that is desired outcome
+ }
+
+ let x = A::Ok;
+}
+
+fn f_i16() {
+ #[repr(i16)]
+ enum A {
+ Ok = i16::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+
+ let x = A::Ok;
+}
+
+fn f_u16() {
+ #[repr(u16)]
+ enum A {
+ Ok = u16::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+
+ let x = A::Ok;
+}
+
+fn f_i32() {
+ #[repr(i32)]
+ enum A {
+ Ok = i32::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+
+ let x = A::Ok;
+}
+
+fn f_u32() {
+ #[repr(u32)]
+ enum A {
+ Ok = u32::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+
+ let x = A::Ok;
+}
+
+fn f_i64() {
+ #[repr(i64)]
+ enum A {
+ Ok = i64::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+
+ let x = A::Ok;
+}
+
+fn f_u64() {
+ #[repr(u64)]
+ enum A {
+ Ok = u64::MAX - 1,
+ Ok2,
+ OhNo, //~ ERROR enum discriminant overflowed
+ }
+
+ let x = A::Ok;
+}
+
+fn main() { }
mod s {
#![allow(unstable)]
- use std::sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
+ use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
- static S_COUNT: AtomicUint = ATOMIC_UINT_INIT;
+ static S_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
pub fn next_count() -> usize {
S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
mod s {
#![allow(unstable)]
- use std::sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
+ use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
- static S_COUNT: AtomicUint = ATOMIC_UINT_INIT;
+ static S_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
pub fn next_count() -> usize {
S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
mod s {
#![allow(unstable)]
- use std::sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
+ use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
- static S_COUNT: AtomicUint = ATOMIC_UINT_INIT;
+ static S_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
pub fn next_count() -> usize {
S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
let f2: &Fat<[isize; 3]> = &f1;
let f3: &Fat<[usize]> = f2;
//~^ ERROR mismatched types
- //~| expected `&Fat<[usize]>`
- //~| found `&Fat<[isize; 3]>`
- //~| expected usize
- //~| found isize
// With a trait.
let f1 = Fat { ptr: Foo };
fn has_slice(x: &str) {
wants_uniq(x); //~ ERROR mismatched types
- wants_slice(x.as_slice());
+ wants_slice(x);
}
fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: too big for the current
+// FIXME (#23926): the error output is not consistent between a
+// self-hosted and a cross-compiled setup. Skipping for now.
+
+// ignore-test FIXME(#23926)
+
#![allow(exceeding_bitshifts)]
fn main() {
- let fat : [u8; (1<<61)+(1<<31)] = [0; (1u64<<61) as usize +(1u64<<31) as usize];
+ let _fat : [u8; (1<<61)+(1<<31)] =
+ [0; (1u64<<61) as usize +(1u64<<31) as usize];
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::iter::{Range,range};
+use std::ops::Range;
trait Itble<'r, T, I: Iterator<Item=T>> { fn iter(&'r self) -> I; }
impl<'r> Itble<'r, usize, Range<usize>> for (usize, usize) {
fn iter(&'r self) -> Range<usize> {
let &(min, max) = self;
- range(min, max)
+ min..max
}
}
fn main() {
// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
- (|| Box::new(*[0].as_slice()))();
+ (|| Box::new(*(&[0][..])))();
//~^ ERROR the trait `core::marker::Sized` is not implemented for the type `[_]`
}
// ignore-tidy-linelength
-use std::iter::{Range,range};
+use std::ops::Range;
trait Itble<'r, T, I: Iterator<Item=T>> { fn iter(&'r self) -> I; }
impl<'r> Itble<'r, usize, Range<usize>> for (usize, usize) {
fn iter(&'r self) -> Range<usize> {
let &(min, max) = self;
- range(min, max)
+ min..max
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// Note: This test is checking that we forbid a coding pattern that
+// Issue #5873 explicitly wants to allow.
+
enum State { ST_NULL, ST_WHITESPACE }
fn main() {
[State::ST_NULL; (State::ST_WHITESPACE as usize)];
- //~^ ERROR expected constant integer for repeat count, found non-constant expression
+ //~^ ERROR expected constant integer for repeat count, but non-constant path
}
fn main() {
fn bar(n: usize) {
- let _x = [0; n]; //~ ERROR expected constant integer for repeat count, found variable
+ let _x = [0; n];
+ //~^ ERROR expected constant integer for repeat count, found variable
}
}
// which fails to type check.
ss
- //~^ ERROR cannot infer
- //~| ERROR mismatched types
+ //~^ ERROR lifetime of the source pointer does not outlive lifetime bound
+ //~| ERROR cannot infer
}
fn main() {
// `Box<SomeTrait>` defaults to a `'static` bound, so this return
// is illegal.
- ss.r //~ ERROR mismatched types
+ ss.r //~ ERROR lifetime of the source pointer does not outlive lifetime bound
}
fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) {
fn store1<'b>(ss: &mut SomeStruct, b: Box<SomeTrait+'b>) {
// Here we override the lifetimes explicitly, and so naturally we get an error.
- ss.r = b; //~ ERROR mismatched types
+ ss.r = b; //~ ERROR lifetime of the source pointer does not outlive lifetime bound
}
fn main() {
fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'c> {
// A outlives 'a AND 'b...but not 'c.
- box v as Box<SomeTrait+'a> //~ ERROR mismatched types
+ box v as Box<SomeTrait+'a> //~ ERROR lifetime of the source pointer does not outlive
}
fn main() {
fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy {
// Without knowing 'a:'b, we can't coerce
- x //~ ERROR mismatched types
+ x //~ ERROR lifetime of the source pointer does not outlive
//~^ ERROR cannot infer
}
use lib::DefaultedTrait;
struct A;
-impl DefaultedTrait for (A,) { } //~ ERROR E0321
+impl DefaultedTrait for (A,) { } //~ ERROR E0117
struct B;
-impl !DefaultedTrait for (B,) { } //~ ERROR E0321
+impl !DefaultedTrait for (B,) { } //~ ERROR E0117
struct C;
struct D<T>(T);
impl DefaultedTrait for Box<C> { } //~ ERROR E0321
-impl DefaultedTrait for lib::Something<C> { } //~ ERROR E0321
+impl DefaultedTrait for lib::Something<C> { } //~ ERROR E0117
impl DefaultedTrait for D<C> { } // OK
fn main() { }
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Test that the deprecated markers still have their old effect.
-
-#![feature(rustc_attrs)]
-
-use std::marker;
-
-#[rustc_variance]
-struct A<T>(marker::CovariantType<T>); //~ ERROR types=[[+];[];[]]
-
-#[rustc_variance]
-struct B<T>(marker::ContravariantType<T>); //~ ERROR types=[[-];[];[]]
-
-#[rustc_variance]
-struct C<T>(marker::InvariantType<T>); //~ ERROR types=[[o];[];[]]
-
-#[rustc_variance]
-struct D<'a>(marker::CovariantLifetime<'a>); //~ ERROR regions=[[+];[];[]]
-
-#[rustc_variance]
-struct E<'a>(marker::ContravariantLifetime<'a>); //~ ERROR regions=[[-];[];[]]
-
-#[rustc_variance]
-struct F<'a>(marker::InvariantLifetime<'a>); //~ ERROR regions=[[o];[];[]]
-
-fn main() { }
mod s {
#![allow(unstable)]
- use std::sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
+ use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
- static S_COUNT: AtomicUint = ATOMIC_UINT_INIT;
+ static S_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
/// generates globally unique count (global across the current
/// process, that is)
v.push(&x); //~ ERROR `x` does not live long enough
v.push(&y); //~ ERROR `y` does not live long enough
- assert_eq!(v.as_slice(), [&3, &4]);
+ assert_eq!(v, [&3, &4]);
}
(a, ref b) => {}
}
for a in &[111i32] {}
+ let test = if some_predicate() { 1 } else { 2 };
+ while some_predicate() {
+ let abc = !some_predicate();
+ }
+ loop {
+ let abc = !some_predicate();
+ break;
+ }
+ // nested block
+ {
+ let abc = !some_predicate();
+
+ {
+ let def = !some_predicate();
+ }
+ }
}
fn after_panic() {
(a, ref b) => {}
}
for a in &[111i32] {}
+ let test = if some_predicate() { 1 } else { 2 };
+ while some_predicate() {
+ let abc = !some_predicate();
+ }
+ loop {
+ let abc = !some_predicate();
+ break;
+ }
+ // nested block
+ {
+ let abc = !some_predicate();
+
+ {
+ let def = !some_predicate();
+ }
+ }
}
fn after_diverging_function() {
(a, ref b) => {}
}
for a in &[111i32] {}
+ let test = if some_predicate() { 1 } else { 2 };
+ while some_predicate() {
+ let abc = !some_predicate();
+ }
+ loop {
+ let abc = !some_predicate();
+ break;
+ }
+ // nested block
+ {
+ let abc = !some_predicate();
+
+ {
+ let def = !some_predicate();
+ }
+ }
}
fn after_break() {
(a, ref b) => {}
}
for a in &[111i32] {}
+ let test = if some_predicate() { 1 } else { 2 };
+ while some_predicate() {
+ let abc = !some_predicate();
+ }
+ loop {
+ let abc = !some_predicate();
+ break;
+ }
+ // nested block
+ {
+ let abc = !some_predicate();
+
+ {
+ let def = !some_predicate();
+ }
+ }
}
}
fn after_continue() {
for _ in 0..10i32 {
- break;
+ continue;
let x = "0";
let (ref y,z) = (1i32, 2u32);
match (20i32, 'c') {
(a, ref b) => {}
}
for a in &[111i32] {}
+ let test = if some_predicate() { 1 } else { 2 };
+ while some_predicate() {
+ let abc = !some_predicate();
+ }
+ loop {
+ let abc = !some_predicate();
+ break;
+ }
+ // nested block
+ {
+ let abc = !some_predicate();
+
+ {
+ let def = !some_predicate();
+ }
+ }
}
}
fn diverge() -> ! {
panic!();
}
+
+fn some_predicate() -> bool { true || false }
+
// error-pattern:no valid digits found for number
fn main() {
- log(error, 0b42);
+ log(error, 0b);
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ 0b121; //~ ERROR invalid digit for a base 2 literal
+ 0b10_10301; //~ ERROR invalid digit for a base 2 literal
+ 0b30; //~ ERROR invalid digit for a base 2 literal
+ 0b41; //~ ERROR invalid digit for a base 2 literal
+ 0b5; //~ ERROR invalid digit for a base 2 literal
+ 0b6; //~ ERROR invalid digit for a base 2 literal
+ 0b7; //~ ERROR invalid digit for a base 2 literal
+ 0b8; //~ ERROR invalid digit for a base 2 literal
+ 0b9; //~ ERROR invalid digit for a base 2 literal
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ 0o18; //~ ERROR invalid digit for a base 8 literal
+ 0o1234_9_5670; //~ ERROR invalid digit for a base 8 literal
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern:assertion failed: `(left == right) && (right == left)` (left: `14`, right: `15`)
+// error-pattern:assertion failed: `(left == right)` (left: `14`, right: `15`)
fn main() {
assert_eq!(14,15);
// error-pattern:whatever
-#![feature(os, rustc_private)]
+#![feature(exit_status, rustc_private)]
#[macro_use] extern crate log;
-use std::os;
+use std::env;
fn main() {
error!("whatever");
// Setting the exit status only works when the scheduler terminates
// normally. In this case we're going to panic, so instead of
// returning 50 the process will return the typical rt failure code.
- os::set_exit_status(50);
+ env::set_exit_status(50);
panic!();
}
// error-pattern:whatever
-#![feature(os, rustc_private)]
+#![feature(exit_status, rustc_private)]
#[macro_use] extern crate log;
-use std::os;
+use std::env;
use std::thread;
struct r {
// runtime's exit code
impl Drop for r {
fn drop(&mut self) {
- os::set_exit_status(50);
+ env::set_exit_status(50);
}
}
// error-pattern:whatever
-#![feature(rustc_private, os)]
+#![feature(rustc_private, exit_status)]
#[macro_use] extern crate log;
-use std::os;
+use std::env;
fn main() {
error!("whatever");
// 101 is the code the runtime uses on task panic and the value
// compiletest expects run-fail tests to return.
- os::set_exit_status(101);
+ env::set_exit_status(101);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(libc, os)]
+#![feature(libc, exit_status)]
extern crate libc;
};
if result != 1 {
- std::os::set_exit_status(255);
+ std::env::set_exit_status(255);
}
}
let expected_span = format!("\n{}^{}\n",
repeat(" ").take(offset + 7).collect::<String>(),
repeat("~").take(8).collect::<String>());
- assert!(err.contains(expected_span.as_slice()));
+ assert!(err.contains(&expected_span));
// Second snake is 8 ~s long, with 36 preceding spaces
let expected_span = format!("\n{}^{}\n",
repeat(" ").take(offset + 36).collect::<String>(),
repeat("~").take(8).collect::<String>());
- assert!(err.contains(expected_span.as_slice()));
+ assert!(err.contains(&expected_span));
}
let mut tc = TestCalls { count: 1 };
// we should never get use this filename, but lets make sure they are valid args.
let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
- rustc_driver::run_compiler(args.as_slice(), &mut tc);
+ rustc_driver::run_compiler(&args, &mut tc);
assert!(tc.count == 30);
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-android
+
+#![feature(rustc_private)]
+
+extern crate rustc_back;
+
+use std::env;
+use std::fs;
+use rustc_back::tempdir::TempDir;
+
+fn main() {
+ let td = TempDir::new("create-dir-all-bare").unwrap();
+ env::set_current_dir(td.path()).unwrap();
+ fs::create_dir_all("create-dir-all-bare").unwrap();
+}
--- /dev/null
+// Copyright 2013-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.
+
+// This test can't be a unit test in std,
+// because it needs TempDir, which is in extra
+
+// ignore-android
+// pretty-expanded FIXME #23616
+
+#![feature(rustc_private, path_ext)]
+
+extern crate rustc_back;
+
+use std::ffi::CString;
+use std::fs::{self, File, PathExt};
+use rustc_back::tempdir::TempDir;
+
+fn rename_directory() {
+ let tmpdir = TempDir::new("rename_directory").ok().expect("rename_directory failed");
+ let tmpdir = tmpdir.path();
+ let old_path = tmpdir.join("foo/bar/baz");
+ fs::create_dir_all(&old_path).unwrap();
+ let test_file = &old_path.join("temp.txt");
+
+ File::create(test_file).unwrap();
+
+ let new_path = tmpdir.join("quux/blat");
+ fs::create_dir_all(&new_path).unwrap();
+ fs::rename(&old_path, &new_path.join("newdir"));
+ assert!(new_path.join("newdir").is_dir());
+ assert!(new_path.join("newdir/temp.txt").exists());
+}
+
+pub fn main() { rename_directory() }
let s = str::from_utf8(&out.error).unwrap();
let mut i = 0;
for _ in 0..2 {
- i += s[i + 10..].find_str("stack backtrace").unwrap() + 10;
+ i += s[i + 10..].find("stack backtrace").unwrap() + 10;
}
- assert!(s[i + 10..].find_str("stack backtrace").is_none(),
+ assert!(s[i + 10..].find("stack backtrace").is_none(),
"bad output4: {}", s);
}
// pretty-expanded FIXME #23616
+#![feature(core)]
+
+// Catch mistakes in the overflowing literals lint.
+#![deny(overflowing_literals)]
+
pub fn main() {
assert_eq!(0xffffffff, (-1 as u32));
assert_eq!(4294967295, (-1 as u32));
assert_eq!(0xffffffffffffffff, (-1 as u64));
assert_eq!(18446744073709551615, (-1 as u64));
- assert_eq!(-2147483648 - 1, 2147483647);
+ assert_eq!((-2147483648i32).wrapping_sub(1), 2147483647);
}
use std::sync::mpsc::channel;
use std::fmt;
use std::old_io::{ChanReader, ChanWriter, Reader, Writer};
-use std::thread::Thread;
+use std::thread;
struct MyWriter(ChanWriter);
fn main() {
let (tx, rx) = channel();
let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx));
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
set_logger(box MyWriter(w) as Box<Logger+Send>);
debug!("debug");
info!("info");
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
fn child2(_s: String) { }
pub fn main() {
- let _x = Thread::spawn(move|| child2("hi".to_string()));
+ let _x = thread::spawn(move|| child2("hi".to_string()));
}
#![allow(unknown_features)]
#![feature(box_syntax, std_misc)]
-use std::thread::Thread;
+use std::thread;
struct Pair {
a: isize,
pub fn main() {
let z: Box<_> = box Pair { a : 10, b : 12};
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
assert_eq!(z.a, 10);
assert_eq!(z.b, 12);
});
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// aux-build:coherence_lib.rs
-
-// Test that it's ok for T to appear first in the self-type, as long
-// as it's covered somewhere.
-
-// pretty-expanded FIXME #23616
-
-extern crate coherence_lib as lib;
-use lib::{Remote,Pair};
-
-pub struct Cover<T>(T);
-
-impl<T> Remote for Pair<T,Cover<T>> { }
-
-fn main() { }
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// aux-build:coherence_lib.rs
-
-// Test that it's ok for T to appear second in the self-type, as long
-// as it's covered somewhere.
-
-// pretty-expanded FIXME #23616
-
-extern crate coherence_lib as lib;
-use lib::{Remote,Pair};
-
-pub struct Cover<T>(T);
-
-impl<T> Remote for Pair<Cover<T>,T> { }
-
-fn main() { }
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// aux-build:coherence_lib.rs
-
-// pretty-expanded FIXME #23616
-
-extern crate coherence_lib as lib;
-use lib::Remote;
-
-struct Local;
-
-impl Remote for Vec<Local> { }
-
-fn main() { }
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// aux-build:coherence_lib.rs
-
-// pretty-expanded FIXME #23616
-
-extern crate coherence_lib as lib;
-use lib::Remote;
-
-struct Local<T>(T);
-
-impl<T> Remote for Vec<Local<T>> { }
-
-fn main() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we are able to introduce a negative constraint that
+// `MyType: !MyTrait` along with other "fundamental" wrappers.
+
+// aux-build:coherence_copy_like_lib.rs
+
+extern crate coherence_copy_like_lib as lib;
+
+use std::marker::MarkerTrait;
+
+struct MyType { x: i32 }
+
+trait MyTrait : MarkerTrait { }
+impl<T: lib::MyCopy> MyTrait for T { }
+impl MyTrait for MyType { }
+impl<'a> MyTrait for &'a MyType { }
+impl MyTrait for Box<MyType> { }
+impl<'a> MyTrait for &'a Box<MyType> { }
+
+fn main() { }
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::{channel, Sender};
pub fn main() {
let (tx, rx) = channel();
- let _t = Thread::spawn(move|| { child(&tx) });
+ let _t = thread::scoped(move|| { child(&tx) });
let y = rx.recv().unwrap();
println!("received");
println!("{}", y);
use std::time::Duration;
use std::str;
use std::sync::mpsc::channel;
-use std::thread::Thread;
+use std::thread;
macro_rules! succeed { ($e:expr) => (
match $e { Ok(..) => {}, Err(e) => panic!("panic: {}", e) }
let (tx, rx1) = channel();
let mut t = timer::Timer::new().unwrap();
let rx2 = t.oneshot(Duration::milliseconds(1000));
- Thread::spawn(move|| {
+ thread::spawn(move|| {
select! {
_ = rx2.recv() => unsafe { libc::exit(1) },
_ = rx1.recv() => {}
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(tempdir)]
-
-use std::env;
-use std::fs::{self, TempDir};
-
-fn main() {
- let td = TempDir::new("create-dir-all-bare").unwrap();
- env::set_current_dir(td.path()).unwrap();
- fs::create_dir_all("create-dir-all-bare").unwrap();
-}
#![allow(unknown_features)]
#![feature(box_syntax)]
-#![feature(old_orphan_check, rustc_private)]
+#![feature(rustc_private)]
extern crate serialize;
// pretty-expanded FIXME #23616
-#![feature(old_orphan_check, rustc_private)]
+#![feature(rustc_private)]
extern crate serialize;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(old_orphan_check, rand, rustc_private)]
+#![feature(rand, rustc_private)]
extern crate serialize;
extern crate rand;
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Issue 23030: Workaround overflowing discriminant
+// with explicit assignments.
+
+// See also compile-fail/overflow-discrim.rs, which shows what
+// happens if you leave the OhNo explicit cases out here.
+
+use std::{i8,u8,i16,u16,i32,u32,i64,u64,isize,usize};
+
+fn f_i8() {
+ #[repr(i8)]
+ enum A {
+ Ok = i8::MAX - 1,
+ Ok2,
+ OhNo = i8::MIN,
+ NotTheEnd = -1,
+ Zero,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+ let z = (A::NotTheEnd, A::Zero).1 as i8;
+ assert_eq!(z, 0);
+}
+
+fn f_u8() {
+ #[repr(u8)]
+ enum A {
+ Ok = u8::MAX - 1,
+ Ok2,
+ OhNo = u8::MIN,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+}
+
+fn f_i16() {
+ #[repr(i16)]
+ enum A {
+ Ok = i16::MAX - 1,
+ Ok2,
+ OhNo = i16::MIN,
+ NotTheEnd = -1,
+ Zero,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+ let z = (A::NotTheEnd, A::Zero).1 as i16;
+ assert_eq!(z, 0);
+}
+
+fn f_u16() {
+ #[repr(u16)]
+ enum A {
+ Ok = u16::MAX - 1,
+ Ok2,
+ OhNo = u16::MIN,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+}
+
+fn f_i32() {
+ #[repr(i32)]
+ enum A {
+ Ok = i32::MAX - 1,
+ Ok2,
+ OhNo = i32::MIN,
+ NotTheEnd = -1,
+ Zero,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+ let z = (A::NotTheEnd, A::Zero).1 as i32;
+ assert_eq!(z, 0);
+}
+
+fn f_u32() {
+ #[repr(u32)]
+ enum A {
+ Ok = u32::MAX - 1,
+ Ok2,
+ OhNo = u32::MIN,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+}
+
+fn f_i64() {
+ #[repr(i64)]
+ enum A {
+ Ok = i64::MAX - 1,
+ Ok2,
+ OhNo = i64::MIN,
+ NotTheEnd = -1,
+ Zero,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+ let z = (A::NotTheEnd, A::Zero).1 as i64;
+ assert_eq!(z, 0);
+}
+
+fn f_u64() {
+ #[repr(u64)]
+ enum A {
+ Ok = u64::MAX - 1,
+ Ok2,
+ OhNo = u64::MIN,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+}
+
+fn f_isize() {
+ #[repr(isize)]
+ enum A {
+ Ok = isize::MAX - 1,
+ Ok2,
+ OhNo = isize::MIN,
+ NotTheEnd = -1,
+ Zero,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+ let z = (A::NotTheEnd, A::Zero).1 as isize;
+ assert_eq!(z, 0);
+}
+
+fn f_usize() {
+ #[repr(usize)]
+ enum A {
+ Ok = usize::MAX - 1,
+ Ok2,
+ OhNo = usize::MIN,
+ }
+
+ let _x = (A::Ok, A::Ok2, A::OhNo);
+}
+
+fn main() {
+ f_i8(); f_u8();
+ f_i16(); f_u16();
+ f_i32(); f_u32();
+ f_i64(); f_u64();
+
+ f_isize(); f_usize();
+}
fn main() {
let args = vec!("foobie", "asdf::asdf");
- let arr: Vec<&str> = args[1].split_str("::").collect();
+ let arr: Vec<&str> = args[1].split("::").collect();
assert_eq!(arr[0], "asdf");
assert_eq!(arr[0], "asdf");
}
// pretty-expanded FIXME #23616
#![feature(path)]
-#![feature(convert)]
use std::env::*;
use std::path::PathBuf;
#![feature(libc, std_misc)]
extern crate libc;
-use std::thread::Thread;
+use std::thread;
mod rustrt {
extern crate libc;
pub fn main() {
// Make sure we're on a task with small Rust stacks (main currently
// has a large stack)
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
let result = count(12);
println!("result = {}", result);
assert_eq!(result, 2048);
use std::collections::HashMap;
use std::sync::mpsc::{channel, Sender};
use std::str;
- use std::thread::Thread;
+ use std::thread;
pub type putter<'a> = Box<FnMut(String, String) + 'a>;
for i in &inputs {
let ctrl = ctrl.clone();
let i = i.clone();
- Thread::spawn(move|| map_task(ctrl.clone(), i.clone()) );
+ thread::spawn(move|| map_task(ctrl.clone(), i.clone()) );
}
}
#![feature(intrinsics, std_misc)]
-use std::thread::Thread;
+use std::thread;
extern "rust-intrinsic" {
pub fn init<T>() -> T;
fn main() {
// do the test in a new thread to avoid (spurious?) stack overflows
- let _ = Thread::scoped(|| {
+ let _ = thread::scoped(|| {
let _memory: [u8; SIZE] = unsafe { init() };
}).join();
}
// pretty-expanded FIXME #23616
-#![feature(old_orphan_check, rustc_private, old_io)]
+#![feature(rustc_private, old_io)]
extern crate rbml;
extern crate serialize;
fn parent() {
let args: Vec<String> = env::args().collect();
let mut p = Command::new(&args[0]).arg("child")
- .stdout(Stdio::capture())
- .stdin(Stdio::capture())
+ .stdout(Stdio::piped())
+ .stdin(Stdio::piped())
.spawn().unwrap();
p.stdin.as_mut().unwrap().write_all(b"test1\ntest2\ntest3").unwrap();
let out = p.wait_with_output().unwrap();
#![feature(std_misc)]
use std::sync::mpsc::{channel, Sender, Receiver};
-use std::thread::Thread;
+use std::thread;
fn helper(rx: Receiver<Sender<()>>) {
for tx in rx.iter() {
fn main() {
let (tx, rx) = channel();
- let _t = Thread::spawn(move|| { helper(rx) });
+ let _t = thread::scoped(move|| { helper(rx) });
let (snd, rcv) = channel::<isize>();
for _ in 1..100000 {
snd.send(1).unwrap();
_ = rcv.recv() => ()
}
}
+ drop(tx);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(old_orphan_check, rustc_private)]
+#![feature(rustc_private)]
extern crate serialize;
fn test() {
let args: Vec<String> = env::args().collect();
let mut p = Command::new(&args[0]).arg("child")
- .stdin(Stdio::capture())
- .stdout(Stdio::capture())
- .stderr(Stdio::capture())
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .stderr(Stdio::piped())
.spawn().unwrap();
assert!(p.wait().unwrap().success());
}
// pretty-expanded FIXME #23616
-#![feature(old_orphan_check, core)]
+#![feature(core)]
use std::ops::Index;
#![feature(core)]
+trait Str { fn foo(&self) {} }
+impl Str for str {}
+impl<'a, S: ?Sized> Str for &'a S where S: Str {}
+
fn main() {
let _: &Str = &"x";
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for #17746
+
+fn main() {}
+
+struct A;
+
+impl A {
+ fn b(&mut self) {
+ self.a()
+ }
+}
+
+trait Foo {
+ fn dummy(&self) {}
+}
+trait Bar {
+ fn a(&self);
+}
+
+impl Foo for A {}
+impl<T> Bar for T where T: Foo {
+ fn a(&self) {}
+}
use std::thread;
-fn main() {
- thread::Thread::spawn(move || { // no need for -> ()
+fn _foo() {
+ let _t = thread::scoped(move || { // no need for -> ()
loop {
println!("hello");
}
});
}
+
+fn main() {}
// pretty-expanded FIXME #23616
-#![feature(convert)]
-
use std::default::Default;
use std::io;
use std::fs;
use std::{fs, net};
fn assert_both<T: Send + Sync>() {}
+fn assert_send<T: Send>() {}
fn main() {
assert_both::<fs::File>();
assert_both::<fs::Metadata>();
assert_both::<fs::ReadDir>();
assert_both::<fs::DirEntry>();
- assert_both::<fs::WalkDir>();
+ assert_send::<fs::WalkDir>();
assert_both::<fs::OpenOptions>();
assert_both::<fs::Permissions>();
use std::mem::{forget, transmute};
use std::mem::{replace, swap};
use std::mem;
- use std::thread::Thread;
+ use std::thread;
use std::marker::Send;
pub struct Stuff<T> {
let old_state = swap_state_acq(&mut (*p).state,
blocked);
match old_state {
- empty | blocked => { Thread::yield_now(); }
+ empty | blocked => { thread::yield_now(); }
full => {
let payload = replace(&mut p.payload, None);
return Some(payload.unwrap())
#![allow(unknown_features)]
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::Sender;
use std::thunk::Invoke;
}
fn foo(name: String, samples_chan: Sender<Msg>) {
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
let mut samples_chan = samples_chan;
// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
// If `Mul` used an associated type for its output, this test would
// work more smoothly.
-#![feature(old_orphan_check)]
use std::ops::Mul;
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::{channel, Receiver};
fn periodical(n: isize) -> Receiver<bool> {
let (chan, port) = channel();
- Thread::spawn(move|| {
+ thread::spawn(move|| {
loop {
for _ in 1..n {
match chan.send(false) {
fn integers() -> Receiver<isize> {
let (chan, port) = channel();
- Thread::spawn(move|| {
+ thread::spawn(move|| {
let mut i = 1;
loop {
match chan.send(i) {
use std::sync::mpsc::{TryRecvError, channel};
use std::old_io::timer::Timer;
-use std::thread::Thread;
+use std::thread;
use std::time::Duration;
pub fn main() {
let (tx, rx) = channel();
- let _t = Thread::scoped(move||{
+ let _t = thread::scoped(move||{
let mut timer = Timer::new().unwrap();
timer.sleep(Duration::milliseconds(10));
tx.send(()).unwrap();
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::{channel, Sender};
fn producer(tx: &Sender<Vec<u8>>) {
pub fn main() {
let (tx, rx) = channel::<Vec<u8>>();
- let _prod = Thread::spawn(move|| {
+ let _prod = thread::scoped(move|| {
producer(&tx)
});
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
fn user(_i: isize) {}
// Here, i is *copied* into the proc (heap closure).
// Requires allocation. The proc's copy is not mutable.
let mut i = 0;
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
user(i);
println!("spawned {}", i)
});
// mutable outside of the proc.
let mut i = 0;
while i < 10 {
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
user(i);
});
i += 1;
// Here, i must be shadowed in the proc to be mutable.
let mut i = 0;
while i < 10 {
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
let mut i = i;
i += 1;
user(i);
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
macro_rules! expr { ($e: expr) => { $e } }
macro_rules! spawn {
($($code: tt)*) => {
- expr!(Thread::spawn(move|| {$($code)*}))
+ expr!(thread::spawn(move|| {$($code)*}))
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Test that we pick which version of `Foo` to run based on whether
-// the type we (ultimately) inferred for `x` is copyable or not.
-//
-// In this case, the two versions are both impls of same trait, and
-// hence we we can resolve method even without knowing yet which
-// version will run (note that the `push` occurs after the call to
-// `foo()`).
+// Test that when we write `x.foo()`, we do nothave to know the
+// complete type of `x` in order to type-check the method call. In
+// this case, we know that `x: Vec<_1>`, but we don't know what type
+// `_1` is (because the call to `push` comes later). To pick between
+// the impls, we would have to know `_1`, since we have to know
+// whether `_1: MyCopy` or `_1 == Box<i32>`. However (and this is the
+// point of the test), we don't have to pick between the two impls --
+// it is enough to know that `foo` comes from the `Foo` trait. We can
+// translate the call as `Foo::foo(&x)` and let the specific impl get
+// chosen later.
// pretty-expanded FIXME #23616
fn foo(&self) -> isize;
}
-impl<T:Copy> Foo for Vec<T> {
+trait MyCopy { fn foo(&self) { } }
+impl MyCopy for i32 { }
+
+impl<T:MyCopy> Foo for Vec<T> {
fn foo(&self) -> isize {1}
}
-impl<T> Foo for Vec<Box<T>> {
+impl Foo for Vec<Box<i32>> {
fn foo(&self) -> isize {2}
}
fn call_foo_copy() -> isize {
let mut x = Vec::new();
let y = x.foo();
- x.push(0_usize);
+ x.push(0_i32);
y
}
fn call_foo_other() -> isize {
- let mut x: Vec<Box<_>> = Vec::new();
+ let mut x: Vec<_> = Vec::new();
let y = x.foo();
- x.push(box 0);
+ let z: Box<i32> = box 0;
+ x.push(z);
y
}
fn main() {
let x: [isize; 4] = [1,2,3,4];
- let xptr = x.as_slice() as *const [isize];
+ let xptr = &x[..] as *const [isize];
xptr.foo();
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(core)]
+use std::fmt::Debug;
+use std::cmp::{self, PartialOrd, Ordering};
+use std::iter::MinMaxResult::MinMax;
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+struct Foo {
+ n: u8,
+ name: &'static str
+}
+
+impl PartialOrd for Foo {
+ fn partial_cmp(&self, other: &Foo) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Foo {
+ fn cmp(&self, other: &Foo) -> Ordering {
+ self.n.cmp(&other.n)
+ }
+}
+
+fn main() {
+ let a = Foo { n: 4, name: "a" };
+ let b = Foo { n: 4, name: "b" };
+ let c = Foo { n: 8, name: "c" };
+ let d = Foo { n: 8, name: "d" };
+ let e = Foo { n: 22, name: "e" };
+ let f = Foo { n: 22, name: "f" };
+
+ let data = [a, b, c, d, e, f];
+
+ // `min` should return the left when the values are equal
+ assert_eq!(data.iter().min(), Some(&a));
+ assert_eq!(data.iter().min_by(|a| a.n), Some(&a));
+ assert_eq!(cmp::min(a, b), a);
+ assert_eq!(cmp::min(b, a), b);
+ assert_eq!(cmp::partial_min(a, b), Some(a));
+ assert_eq!(cmp::partial_min(b, a), Some(b));
+
+ // `max` should return the right when the values are equal
+ assert_eq!(data.iter().max(), Some(&f));
+ assert_eq!(data.iter().max_by(|a| a.n), Some(&f));
+ assert_eq!(cmp::max(e, f), f);
+ assert_eq!(cmp::max(f, e), e);
+ assert_eq!(cmp::partial_max(e, f), Some(f));
+ assert_eq!(cmp::partial_max(f, e), Some(e));
+
+ // Similar for `min_max`
+ assert_eq!(data.iter().min_max(), MinMax(&a, &f));
+ assert_eq!(data[1..5].iter().min_max(), MinMax(&b, &e));
+ assert_eq!(data[2..4].iter().min_max(), MinMax(&c, &d));
+
+ let mut presorted = data.to_vec();
+ presorted.sort();
+ assert_stable(&presorted);
+
+ let mut presorted = data.to_vec();
+ presorted.sort_by(|a, b| a.cmp(b));
+ assert_stable(&presorted);
+
+ // Assert that sorted and min/max are the same
+ fn assert_stable<T: Ord + Debug>(presorted: &[T]) {
+ for slice in presorted.windows(2) {
+ let a = &slice[0];
+ let b = &slice[1];
+
+ assert_eq!(a, cmp::min(a, b));
+ assert_eq!(b, cmp::max(a, b));
+ }
+ }
+}
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
pub fn main() {
let x = "Hello world!".to_string();
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
println!("{}", x);
});
}
pub fn main() {
let thing = "{{ f }}";
- let f = thing.find_str("{{");
+ let f = thing.find("{{");
if f.is_none() {
println!("None!");
use std::old_io::process::Command;
use std::env;
-use std::thread::Thread;
+use std::thread;
// lifted from the test module
// Inlining to avoid llvm turning the recursive functions into tail calls,
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() > 1 && args[1] == "recurse" {
- let _t = Thread::scoped(recurse);
+ let _t = thread::scoped(recurse);
} else {
let recurse = Command::new(&args[0]).arg("recurse").output().unwrap();
assert!(!recurse.status.success());
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::env;
+use std::process::{self, Command, Stdio};
+
+fn main() {
+ let args: Vec<String> = env::args().collect();
+ if args.len() > 1 && args[1] == "child" {
+ child();
+ } else {
+ parent();
+ }
+}
+
+fn parent() {
+ let args: Vec<String> = env::args().collect();
+ let status = Command::new(&args[0]).arg("child").status().unwrap();
+ assert_eq!(status.code(), Some(2));
+}
+
+fn child() -> i32 {
+ process::exit(2);
+}
// supposed to match the lifetime `'a`) ...
fn foo<'a>(map: RefCell<HashMap<&'static str, &'a [u8]>>) {
let one = [1];
- assert_eq!(map.borrow().get("one"), Some(&one.as_slice()));
+ assert_eq!(map.borrow().get("one"), Some(&&one[..]));
}
#[cfg(all(not(cannot_use_this_yet),not(cannot_use_this_yet_either)))]
+++ /dev/null
-// Copyright 2013-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.
-
-// This test can't be a unit test in std,
-// because it needs TempDir, which is in extra
-
-// pretty-expanded FIXME #23616
-
-#![feature(tempdir, path_ext)]
-
-use std::ffi::CString;
-use std::fs::{self, TempDir, File, PathExt};
-
-fn rename_directory() {
- let tmpdir = TempDir::new("rename_directory").ok().expect("rename_directory failed");
- let tmpdir = tmpdir.path();
- let old_path = tmpdir.join("foo/bar/baz");
- fs::create_dir_all(&old_path).unwrap();
- let test_file = &old_path.join("temp.txt");
-
- File::create(test_file).unwrap();
-
- let new_path = tmpdir.join("quux/blat");
- fs::create_dir_all(&new_path).unwrap();
- fs::rename(&old_path, &new_path.join("newdir"));
- assert!(new_path.join("newdir").is_dir());
- assert!(new_path.join("newdir/temp.txt").exists());
-}
-
-pub fn main() { rename_directory() }
#![feature(start, os, std_misc, old_io)]
-use std::ffi;
+use std::ffi::CStr;
use std::old_io::process::{Command, ProcessOutput};
use std::os;
use std::rt::unwind::try;
let args = unsafe {
(0..argc as usize).map(|i| {
let ptr = *argv.offset(i as isize) as *const _;
- ffi::c_str_to_bytes(&ptr).to_vec()
+ CStr::from_ptr(ptr).to_bytes().to_vec()
}).collect::<Vec<_>>()
};
let me = &*args[0];
extern crate log;
use std::sync::mpsc::{channel, Sender, Receiver};
-use std::thread::Thread;
+use std::thread;
pub struct ChannelLogger {
tx: Sender<String>
pub fn main() {
let (logger, rx) = ChannelLogger::new();
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
log::set_logger(logger);
info!("foo");
// pretty-expanded FIXME #23616
#![feature(core, std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::Mutex;
fn par_for<I, F>(iter: I, f: F)
{
let f = &f;
let _guards: Vec<_> = iter.map(|elem| {
- Thread::scoped(move || {
+ thread::scoped(move || {
f(elem)
})
}).collect();
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::channel;
struct test {
pub fn main() {
let (tx, rx) = channel();
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
let (tx2, rx2) = channel();
tx.send(tx2).unwrap();
assert!(eq_u32x4(u32x4(1, 2, 3, 4) + u32x4(4, 3, 2, 1), u32x4(5, 5, 5, 5)));
assert!(eq_u32x4(u32x4(4, 5, 6, 7) - u32x4(4, 3, 2, 1), u32x4(0, 2, 4, 6)));
assert!(eq_u32x4(u32x4(1, 2, 3, 4) * u32x4(4, 3, 2, 1), u32x4(4, 6, 6, 4)));
+ assert!(eq_u32x4(u32x4(1, 2, 3, 4) / u32x4(4, 3, 2, 1), u32x4(0, 0, 1, 4)));
assert!(eq_u32x4(u32x4(1, 2, 3, 4) & u32x4(4, 3, 2, 1), u32x4(0, 2, 2, 0)));
assert!(eq_u32x4(u32x4(1, 2, 3, 4) | u32x4(4, 3, 2, 1), u32x4(5, 3, 3, 5)));
assert!(eq_u32x4(u32x4(1, 2, 3, 4) ^ u32x4(4, 3, 2, 1), u32x4(5, 1, 1, 5)));
assert!(eq_i32x4(i32x4(1, 2, 3, 4) + i32x4(4, 3, 2, 1), i32x4(5, 5, 5, 5)));
assert!(eq_i32x4(i32x4(1, 2, 3, 4) - i32x4(4, 3, 2, 1), i32x4(-3, -1, 1, 3)));
assert!(eq_i32x4(i32x4(1, 2, 3, 4) * i32x4(4, 3, 2, 1), i32x4(4, 6, 6, 4)));
+ assert!(eq_i32x4(i32x4(1, 2, 3, 4) / i32x4(4, 3, 2, 1), i32x4(0, 0, 1, 4)));
assert!(eq_i32x4(i32x4(1, 2, 3, 4) & i32x4(4, 3, 2, 1), i32x4(0, 2, 2, 0)));
assert!(eq_i32x4(i32x4(1, 2, 3, 4) | i32x4(4, 3, 2, 1), i32x4(5, 3, 3, 5)));
assert!(eq_i32x4(i32x4(1, 2, 3, 4) ^ i32x4(4, 3, 2, 1), i32x4(5, 1, 1, 5)));
// pretty-expanded FIXME #23616
+// this is for the wrapping_add call below.
+#![feature(core)]
+
/*!
* Tests the range assertion wraparound case in trans::middle::adt::load_discr.
*/
static CHs: Es = Es::Hs;
pub fn main() {
- assert_eq!((Eu::Hu as u8) + 1, Eu::Lu as u8);
- assert_eq!((Es::Hs as i8) + 1, Es::Ls as i8);
+ assert_eq!((Eu::Hu as u8).wrapping_add(1), Eu::Lu as u8);
+ assert_eq!((Es::Hs as i8).wrapping_add(1), Es::Ls as i8);
assert_eq!(CLu as u8, Eu::Lu as u8);
assert_eq!(CHu as u8, Eu::Hu as u8);
assert_eq!(CLs as i8, Es::Ls as i8);
+++ /dev/null
-// Copyright 2012-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.
-
-// pretty-expanded FIXME #23616
-
-#![feature(tempdir, path_ext)]
-
-use std::fs::{File, TempDir};
-use std::io::prelude::*;
-
-pub fn main() {
- let dir = TempDir::new_in(".", "").unwrap();
- let path = dir.path().join("file");
-
- {
- match File::create(&path) {
- Err(..) => unreachable!(),
- Ok(f) => {
- let mut f = f;
- for _ in 0..1000 {
- f.write(&[0]);
- }
- }
- }
- }
-
- assert!(path.exists());
- assert_eq!(path.metadata().unwrap().len(), 1000);
-}
assert!(
include_str!("syntax-extension-source-utils-files/includeme.\
fragment").to_string()
- .as_slice()
.starts_with("/* this is for "));
assert!(
include_bytes!("syntax-extension-source-utils-files/includeme.fragment")
// The Windows tests are wrapped in an extra module for some reason
assert!((m1::m2::where_am_i().ends_with("m1::m2")));
- assert!(match (47, "( 2 * 3 ) + 5") {
- (line!(), stringify!((2*3) + 5)) => true,
- _ => false
- })
+ assert_eq!((46, "( 2 * 3 ) + 5"), (line!(), stringify!((2*3) + 5)));
}
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::{channel, Sender};
pub fn main() { test05(); }
fn test05() {
let (tx, rx) = channel();
- let _t = Thread::spawn(move|| { test05_start(&tx) });
+ let _t = thread::scoped(move|| { test05_start(&tx) });
let mut value: isize = rx.recv().unwrap();
println!("{}", value);
value = rx.recv().unwrap();
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
pub fn main() { test00(); }
fn start() { println!("Started / Finished task."); }
fn test00() {
- let _ = Thread::scoped(move|| start() ).join();
+ let _ = thread::scoped(move|| start() ).join();
println!("Completing.");
}
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::{channel, Sender};
fn start(tx: &Sender<Sender<String>>) {
pub fn main() {
let (tx, rx) = channel();
- let _child = Thread::spawn(move|| { start(&tx) });
+ let _child = thread::scoped(move|| { start(&tx) });
let mut c = rx.recv().unwrap();
c.send("A".to_string()).unwrap();
c.send("B".to_string()).unwrap();
- Thread::yield_now();
+ thread::yield_now();
}
#![feature(std_misc)]
use std::sync::mpsc::{channel, Sender};
-use std::thread::Thread;
+use std::thread;
fn start(tx: &Sender<Sender<isize>>) {
let (tx2, _rx) = channel();
pub fn main() {
let (tx, rx) = channel();
- let _child = Thread::spawn(move|| {
+ let _child = thread::scoped(move|| {
start(&tx)
});
let _tx = rx.recv().unwrap();
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
pub fn main() { test00(); }
fn test00() {
let i: isize = 0;
- let mut result = Thread::scoped(move|| {
+ let mut result = thread::scoped(move|| {
start(i)
});
// Sleep long enough for the task to finish.
let mut i = 0_usize;
while i < 10000 {
- Thread::yield_now();
+ thread::yield_now();
i += 1;
}
#![feature(std_misc)]
use std::sync::mpsc::{channel, Sender};
-use std::thread::Thread;
+use std::thread;
fn start(tx: &Sender<isize>, start: isize, number_of_messages: isize) {
let mut i: isize = 0;
pub fn main() {
println!("Check that we don't deadlock.");
let (tx, rx) = channel();
- let _ = Thread::scoped(move|| { start(&tx, 0, 10) }).join();
+ let _t = thread::scoped(move|| { start(&tx, 0, 10) }).join();
println!("Joined task");
}
#![feature(std_misc)]
use std::sync::mpsc::{channel, Sender};
-use std::thread::Thread;
+use std::thread;
pub fn main() {
let (tx, rx) = channel();
while (i > 0) {
println!("{}", i);
let tx = tx.clone();
- Thread::spawn({let i = i; move|| { child(i, &tx) }});
+ thread::scoped({let i = i; move|| { child(i, &tx) }});
i = i - 1;
}
#![feature(std_misc)]
use std::sync::mpsc::{channel, Sender};
-use std::thread::Thread;
+use std::thread;
fn start(tx: &Sender<isize>, i0: isize) {
let mut i = i0;
// the child's point of view the receiver may die. We should
// drop messages on the floor in this case, and not crash!
let (tx, rx) = channel();
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
start(&tx, 10)
});
rx.recv();
// This test is specifically about spawning temporary closures.
-use std::thread::Thread;
+use std::thread;
fn f() {
}
pub fn main() {
- let _t = Thread::scoped(move|| f() ).join();
+ let _t = thread::scoped(move|| f() ).join();
}
// no-pretty-expanded FIXME #15189
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::{channel, Sender};
pub fn main() { println!("===== WITHOUT THREADS ====="); test00(); }
let mut results = Vec::new();
while i < number_of_tasks {
let tx = tx.clone();
- results.push(Thread::scoped({
+ results.push(thread::scoped({
let i = i;
move|| {
test00_start(&tx, i, number_of_messages)
#![allow(dead_assignment)]
use std::sync::mpsc::{channel, Sender};
-use std::thread::Thread;
+use std::thread;
pub fn main() { test00(); }
let number_of_messages: isize = 10;
let tx2 = tx.clone();
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
test00_start(&tx2, number_of_messages * 0, number_of_messages);
});
let tx2 = tx.clone();
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
test00_start(&tx2, number_of_messages * 1, number_of_messages);
});
let tx2 = tx.clone();
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
test00_start(&tx2, number_of_messages * 2, number_of_messages);
});
let tx2 = tx.clone();
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
test00_start(&tx2, number_of_messages * 3, number_of_messages);
});
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::{channel, Sender};
pub fn main() { test00(); }
let (tx, rx) = channel();
let number_of_messages: isize = 10;
- let result = Thread::scoped(move|| {
+ let result = thread::scoped(move|| {
test00_start(&tx, number_of_messages);
});
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
pub fn main() {
- let _t = Thread::spawn(move|| child("Hello".to_string()) );
+ let _t = thread::scoped(move|| child("Hello".to_string()) );
}
fn child(_s: String) {
#![allow(unknown_features)]
#![feature(box_syntax, std_misc)]
-use std::thread::Thread;
+use std::thread;
use std::sync::mpsc::channel;
pub fn main() {
let x: Box<isize> = box 1;
let x_in_parent = &(*x) as *const isize as usize;
- let _t = Thread::spawn(move || {
+ let _t = thread::scoped(move || {
let x_in_child = &(*x) as *const isize as usize;
tx.send(x_in_child).unwrap();
});
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::channel;
-use std::thread::Thread;
+use std::thread;
static N: usize = 8;
static M: usize = 20;
let a = a.clone();
let cnt = cnt.clone();
let srv_tx = srv_tx.clone();
- Thread::scoped(move|| {
+ thread::scoped(move|| {
let mut a = a;
loop {
match a.accept() {
let _t = (0..N).map(|_| {
let cli_tx = cli_tx.clone();
- Thread::scoped(move|| {
+ thread::scoped(move|| {
for _ in 0..M {
let _s = TcpStream::connect(addr).unwrap();
}
use std::old_io;
use std::time::Duration;
use std::sync::mpsc::channel;
-use std::thread::Thread;
+use std::thread;
#[cfg_attr(target_os = "freebsd", ignore)]
fn eventual_timeout() {
let (tx1, rx1) = channel();
let (_tx2, rx2) = channel::<()>();
- let _t = Thread::spawn(move|| {
+ let _t = thread::scoped(move|| {
let _l = TcpListener::bind(addr).unwrap().listen();
tx1.send(()).unwrap();
let _ = rx2.recv();
use std::sync::mpsc::channel;
use std::old_io::net::tcp::{TcpListener, TcpStream};
use std::old_io::{Acceptor, Listener, Reader, Writer};
-use std::thread::{Builder, Thread};
+use std::thread::{self, Builder};
use std::time::Duration;
fn main() {
// This test has a chance to time out, try to not let it time out
- Thread::spawn(move|| -> () {
+ thread::spawn(move|| -> () {
use std::old_io::timer;
timer::sleep(Duration::milliseconds(30 * 1000));
println!("timed out!");
});
let (tx, rx) = channel();
- Thread::spawn(move || -> () {
+ thread::spawn(move || -> () {
let mut listener = TcpListener::bind("127.0.0.1:0").unwrap();
tx.send(listener.socket_name().unwrap()).unwrap();
let mut acceptor = listener.listen();
use std::old_io::fs::PathExtensions;
use std::old_io::{fs, TempDir};
use std::old_io;
-use std::os;
+use std::env;
use std::sync::mpsc::channel;
use std::thread;
// to depend on std
fn recursive_mkdir_rel() {
let path = Path::new("frob");
- let cwd = os::getcwd().unwrap();
+ let cwd = Path::new(env::current_dir().unwrap().to_str().unwrap());
println!("recursive_mkdir_rel: Making: {} in cwd {} [{}]", path.display(),
cwd.display(), path.exists());
fs::mkdir_recursive(&path, old_io::USER_RWX);
fn recursive_mkdir_rel_2() {
let path = Path::new("./frob/baz");
- let cwd = os::getcwd().unwrap();
+ let cwd = Path::new(env::current_dir().unwrap().to_str().unwrap());
println!("recursive_mkdir_rel_2: Making: {} in cwd {} [{}]", path.display(),
cwd.display(), path.exists());
fs::mkdir_recursive(&path, old_io::USER_RWX);
fn in_tmpdir<F>(f: F) where F: FnOnce() {
let tmpdir = TempDir::new("test").ok().expect("can't make tmpdir");
- assert!(os::change_dir(tmpdir.path()).is_ok());
+ assert!(env::set_current_dir(tmpdir.path().as_str().unwrap()).is_ok());
f();
}
#![feature(std_misc)]
-use std::thread::Thread;
+use std::thread;
pub fn main() {
let mut i = 10;
while i > 0 {
- Thread::scoped({let i = i; move|| child(i)});
+ thread::scoped({let i = i; move|| child(i)});
i = i - 1;
}
println!("main thread exiting");
use std::sync::Arc;
use std::sync::mpsc::channel;
-use std::thread::Thread;
+use std::thread;
trait Pet {
fn name(&self, blk: Box<FnMut(&str)>);
box dogge2 as Box<Pet+Sync+Send>));
let (tx1, rx1) = channel();
let arc1 = arc.clone();
- let _t1 = Thread::spawn(move|| { check_legs(arc1); tx1.send(()); });
+ let _t1 = thread::scoped(move|| { check_legs(arc1); tx1.send(()); });
let (tx2, rx2) = channel();
let arc2 = arc.clone();
- let _t2 = Thread::spawn(move|| { check_names(arc2); tx2.send(()); });
+ let _t2 = thread::scoped(move|| { check_names(arc2); tx2.send(()); });
let (tx3, rx3) = channel();
let arc3 = arc.clone();
- let _t3 = Thread::spawn(move|| { check_pedigree(arc3); tx3.send(()); });
+ let _t3 = thread::scoped(move|| { check_pedigree(arc3); tx3.send(()); });
rx1.recv();
rx2.recv();
rx3.recv();
#![allow(unknown_features)]
#![feature(box_syntax)]
+use std::marker::MarkerTrait;
+
trait Get {
fn get(&self) -> Self;
}
-impl<T:Copy> Get for T {
- fn get(&self) -> T { *self }
+trait MyCopy : MarkerTrait { fn copy(&self) -> Self; }
+impl MyCopy for u16 { fn copy(&self) -> Self { *self } }
+impl MyCopy for u32 { fn copy(&self) -> Self { *self } }
+impl MyCopy for i32 { fn copy(&self) -> Self { *self } }
+impl<T:Copy> MyCopy for Option<T> { fn copy(&self) -> Self { *self } }
+
+impl<T:MyCopy> Get for T {
+ fn get(&self) -> T { self.copy() }
}
-impl<T:Get> Get for Box<T> {
- fn get(&self) -> Box<T> { box get_it(&**self) }
+impl Get for Box<i32> {
+ fn get(&self) -> Box<i32> { box get_it(&**self) }
}
fn get_it<T:Get>(t: &T) -> T {
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that you can supply `&F` where `F: FnMut()`.
+
+// pretty-expanded FIXME #23616
+
+#![feature(lang_items, unboxed_closures)]
+
+fn a<F:FnMut() -> i32>(mut f: F) -> i32 {
+ f()
+}
+
+fn b(f: &mut FnMut() -> i32) -> i32 {
+ a(f)
+}
+
+fn c<F:FnMut() -> i32>(f: &mut F) -> i32 {
+ a(f)
+}
+
+fn main() {
+ let z: isize = 7;
+
+ let x = b(&mut || 22);
+ assert_eq!(x, 22);
+
+ let x = c(&mut || 22);
+ assert_eq!(x, 22);
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that you can supply `&F` where `F: Fn()`.
+
+// pretty-expanded FIXME #23616
+
+#![feature(lang_items, unboxed_closures)]
+
+fn a<F:Fn() -> i32>(f: F) -> i32 {
+ f()
+}
+
+fn b(f: &Fn() -> i32) -> i32 {
+ a(f)
+}
+
+fn c<F:Fn() -> i32>(f: &F) -> i32 {
+ a(f)
+}
+
+fn main() {
+ let z: isize = 7;
+
+ let x = b(&|| 22);
+ assert_eq!(x, 22);
+
+ let x = c(&|| 22);
+ assert_eq!(x, 22);
+}
#![feature(alloc)]
-use std::boxed::BoxAny;
use std::thread;
struct Foo;
extern crate libc;
-use std::ffi::{self, CString};
+use std::ffi::{CStr, CString};
use libc::{c_char, c_int};
unsafe fn check<T, F>(expected: &str, f: F) where F: FnOnce(*mut c_char) -> T {
let mut x = [0 as c_char; 50];
f(&mut x[0] as *mut c_char);
- assert_eq!(expected.as_bytes(), ffi::c_str_to_bytes(&x.as_ptr()));
+ assert_eq!(expected.as_bytes(), CStr::from_ptr(x.as_ptr()).to_bytes());
}
pub fn main() {