Avoid `cat_expr Erred` notes when already in error state.
Also, to ensure we do not let the dropck get skipped, ICE if `cat_expr` errors when *not* in error state.
This is not known to be a breaking change (i.e. I do not know of a current case that causes the new ICE to be exercised).
Fix #22265
* [Language Design FAQ](complement-design-faq.html)
* [Language FAQ](complement-lang-faq.html)
* [Project FAQ](complement-project-faq.html)
-* [How to submit a bug report](complement-bugreport.html)
+* [How to submit a bug report](https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports)
# The standard library
pairs when they occur at the beginning of, or immediately after, a `$(...)*`;
requiring a distinctive token in front can solve the problem.
-## Syntax extensions useful for the macro author
+## Syntax extensions useful in macros
-* `log_syntax!` : print out the arguments at compile time
-* `trace_macros!` : supply `true` or `false` to enable or disable macro expansion logging
* `stringify!` : turn the identifier argument into a string literal
* `concat!` : concatenates a comma-separated list of literals
-* `concat_idents!` : create a new identifier by concatenating the arguments
-The following attributes are used for quasiquoting in procedural macros:
+## Syntax extensions for macro debugging
+
+* `log_syntax!` : print out the arguments at compile time
+* `trace_macros!` : supply `true` or `false` to enable or disable macro expansion logging
+
+## Quasiquoting
+
+The following syntax extensions are used for quasiquoting Rust syntax trees,
+usually in [procedural macros](book/plugins.html#syntax-extensions):
* `quote_expr!`
* `quote_item!`
* `quote_tokens!`
* `quote_ty!`
+Documentation is very limited at the moment.
+
# Crates and source files
Rust is a *compiled* language. Its semantics obey a *phase distinction*
only appear at the root of your crate, not inside `mod`. This ensures that
`$crate` is a single identifier.
-# A final note
+# The deep end
-Macros, as currently implemented, are not for the faint of heart. Even
-ordinary syntax errors can be more difficult to debug when they occur inside a
-macro, and errors caused by parse problems in generated code can be very
-tricky. Invoking the `log_syntax!` macro can help elucidate intermediate
-states, invoking `trace_macros!(true)` will automatically print those
-intermediate states out, and passing the flag `--pretty expanded` as a
-command-line argument to the compiler will show the result of expansion.
+The introductory chapter mentioned recursive macros, but it did not give the
+full story. Recursive macros are useful for another reason: Each recursive
+invocation gives you another opportunity to pattern-match the macro's
+arguments.
+
+As an extreme example, it is possible, though hardly advisable, to implement
+the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton
+within Rust's macro system.
+
+```rust
+#![feature(trace_macros)]
+
+macro_rules! bct {
+ // cmd 0: d ... => ...
+ (0, $($ps:tt),* ; $_d:tt)
+ => (bct!($($ps),*, 0 ; ));
+ (0, $($ps:tt),* ; $_d:tt, $($ds:tt),*)
+ => (bct!($($ps),*, 0 ; $($ds),*));
+
+ // cmd 1p: 1 ... => 1 ... p
+ (1, $p:tt, $($ps:tt),* ; 1)
+ => (bct!($($ps),*, 1, $p ; 1, $p));
+ (1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*)
+ => (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p));
+
+ // cmd 1p: 0 ... => 0 ...
+ (1, $p:tt, $($ps:tt),* ; $($ds:tt),*)
+ => (bct!($($ps),*, 1, $p ; $($ds),*));
+
+ // halt on empty data string
+ ( $($ps:tt),* ; )
+ => (());
+}
+
+fn main() {
+ trace_macros!(true);
+# /* just check the definition
+ bct!(0, 0, 1, 1, 1 ; 1, 0, 1);
+# */
+}
+```
+
+Exercise: use macros to reduce duplication in the above definition of the
+`bct!` macro.
+
+# Procedural macros
If Rust's macro system can't do what you need, you may want to write a
[compiler plugin](plugins.html) instead. Compared to `macro_rules!`
macros, this is significantly more work, the interfaces are much less stable,
-and the warnings about debugging apply ten-fold. In exchange you get the
+and bugs can be much harder to track down. In exchange you get the
flexibility of running arbitrary Rust code within the compiler. Syntax
extension plugins are sometimes called *procedural macros* for this reason.
.ok()
.expect("Failed to read line");
```
+
`ok()` converts the `IoResult` into an `Option`, and `expect()` does the same
thing as `unwrap()`, but takes a message. This message is passed along to the
underlying `panic!`, providing a better error message if the code errors.
+
+# Using `try!`
+
+When writing code that calls many functions that return the `Result` type, the
+error handling can be tedious. The `try!` macro hides some of the boilerplate
+of propagating errors up the call stack.
+
+It replaces this:
+
+```rust
+use std::fs::File;
+use std::io;
+use std::io::prelude::*;
+
+struct Info {
+ name: String,
+ age: i32,
+ rating: i32,
+}
+
+fn write_info(info: &Info) -> io::Result<()> {
+ let mut file = File::open("my_best_friends.txt").unwrap();
+
+ if let Err(e) = writeln!(&mut file, "name: {}", info.name) {
+ return Err(e)
+ }
+ if let Err(e) = writeln!(&mut file, "age: {}", info.age) {
+ return Err(e)
+ }
+ if let Err(e) = writeln!(&mut file, "rating: {}", info.rating) {
+ return Err(e)
+ }
+
+ return Ok(());
+}
+```
+
+With this:
+
+```rust
+use std::fs::File;
+use std::io;
+use std::io::prelude::*;
+
+struct Info {
+ name: String,
+ age: i32,
+ rating: i32,
+}
+
+fn write_info(info: &Info) -> io::Result<()> {
+ let mut file = try!(File::open("my_best_friends.txt"));
+
+ try!(writeln!(&mut file, "name: {}", info.name));
+ try!(writeln!(&mut file, "age: {}", info.age));
+ try!(writeln!(&mut file, "rating: {}", info.rating));
+
+ return Ok(());
+}
+```
+
+Wrapping an expression in `try!` will result in the unwrapped success (`Ok`)
+value, unless the result is `Err`, in which case `Err` is returned early from
+the enclosing function.
+
+It's worth noting that you can only use `try!` from a function that returns a
+`Result`, which means that you cannot use `try!` inside of `main()`, because
+`main()` doesn't return anything.
+
+`try!` makes use of [`FromError`](../std/error/#the-fromerror-trait) to determine
+what to return in the error case.
};
}
# fn main() {
-# assert_eq!(&[1,2,3], &vec![1,2,3]);
+# assert_eq!([1,2,3], vec![1,2,3]);
# }
```
## Repetition
-The repetition behavior can seem somewhat magical, especially when multiple
-names are bound at multiple nested levels of repetition. The two rules to keep
-in mind are:
+The repetition operator follows two principal rules:
-1. the behavior of `$(...)*` is to walk through one "layer" of repetitions, for
-all of the `$name`s it contains, in lockstep, and
+1. `$(...)*` walks through one "layer" of repetitions, for all of the `$name`s
+ it contains, in lockstep, and
2. each `$name` must be under at least as many `$(...)*`s as it was matched
-against. If it is under more, it'll be duplicated, as appropriate.
+ against. If it is under more, it'll be duplicated, as appropriate.
This baroque macro illustrates the duplication of variables from outer
repetition levels.
more" match. Both forms optionally include a separator, which can be any token
except `+` or `*`.
+This system is based on
+"[Macro-by-Example](http://www.cs.indiana.edu/ftp/techreports/TR206.pdf)"
+(PDF link).
+
# Hygiene
Some languages implement macros using simple text substitution, which leads to
})
```
-This looks reasonable, but watch what happens in this example:
+Here's a simple use case that goes terribly wrong:
```text
const char *state = "reticulating splines";
-LOG(state);
+LOG(state)
```
-The program will likely segfault, after it tries to execute
+This expands to
```text
-printf("log(%d): %s\n", state, state);
+const char *state = "reticulating splines";
+int state = get_log_state();
+if (state > 0) {
+ printf("log(%d): %s\n", state, state);
+}
```
+The second variable named `state` shadows the first one. This is a problem
+because the print statement should refer to both of them.
+
The equivalent Rust macro has the desired behavior.
```rust
[items]: ../reference.html#items
+# Recursive macros
+
+A macro's expansion can include more macro invocations, including invocations
+of the very same macro being expanded. These recursive macros are useful for
+processing tree-structured input, as illustrated by this (simplistic) HTML
+shorthand:
+
+```rust
+# #![allow(unused_must_use)]
+macro_rules! write_html {
+ ($w:expr, ) => (());
+
+ ($w:expr, $e:tt) => (write!($w, "{}", $e));
+
+ ($w:expr, $tag:ident [ $($inner:tt)* ] $($rest:tt)*) => {{
+ write!($w, "<{}>", stringify!($tag));
+ write_html!($w, $($inner)*);
+ write!($w, "</{}>", stringify!($tag));
+ write_html!($w, $($rest)*);
+ }};
+}
+
+fn main() {
+# // FIXME(#21826)
+ use std::fmt::Write;
+ let mut out = String::new();
+
+ write_html!(&mut out,
+ html[
+ head[title["Macros guide"]]
+ body[h1["Macros are the best!"]]
+ ]);
+
+ assert_eq!(out,
+ "<html><head><title>Macros guide</title></head>\
+ <body><h1>Macros are the best!</h1></body></html>");
+}
+```
+
+# Debugging macro code
+
+To see the results of expanding macros, run `rustc --pretty expanded`. The
+output represents a whole crate, so you can also feed it back in to `rustc`,
+which will sometimes produce better error messages than the original
+compilation. Note that the `--pretty expanded` output may have a different
+meaning if multiple variables of the same name (but different syntax contexts)
+are in play in the same scope. In this case `--pretty expanded,hygiene` will
+tell you about the syntax contexts.
+
+`rustc` provides two syntax extensions that help with macro debugging. For now,
+they are unstable and require feature gates.
+
+* `log_syntax!(...)` will print its arguments to standard output, at compile
+ time, and "expand" to nothing.
+
+* `trace_macros!(true)` will enable a compiler message every time a macro is
+ expanded. Use `trace_macros!(false)` later in expansion to turn it off.
+
# Further reading
The [advanced macros chapter][] goes into more detail about macro syntax. It
## Tips and tricks
-To see the results of expanding syntax extensions, run
-`rustc --pretty expanded`. The output represents a whole crate, so you
-can also feed it back in to `rustc`, which will sometimes produce better
-error messages than the original compilation. Note that the
-`--pretty expanded` output may have a different meaning if multiple
-variables of the same name (but different syntax contexts) are in play
-in the same scope. In this case `--pretty expanded,hygiene` will tell
-you about the syntax contexts.
+Some of the [macro debugging tips](macros.html#debugging-macro-code) are applicable.
You can use [`syntax::parse`](../syntax/parse/index.html) to turn token trees into
higher-level syntax elements like expressions:
[`DummyResult`](../syntax/ext/base/struct.DummyResult.html),
so that the compiler can continue and find further errors.
+To print syntax fragments for debugging, you can use
+[`span_note`](../syntax/ext/base/struct.ExtCtxt.html#method.span_note) together
+with
+[`syntax::print::pprust::*_to_string`](http://doc.rust-lang.org/syntax/print/pprust/index.html#functions).
+
The example above produced an integer literal using
[`AstBuilder::expr_uint`](../syntax/ext/build/trait.AstBuilder.html#tymethod.expr_uint).
As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![feature(core)]
+#![feature(unique)]
#![cfg_attr(test, feature(test, alloc, rustc_private))]
#![cfg_attr(all(not(feature = "external_funcs"), not(feature = "external_crate")),
feature(libc))]
/// heap.push(3);
///
/// let vec = heap.into_sorted_vec();
- /// assert_eq!(vec, vec![1, 2, 3, 4, 5, 6, 7]);
+ /// assert_eq!(vec, [1, 2, 3, 4, 5, 6, 7]);
/// ```
pub fn into_sorted_vec(mut self) -> Vec<T> {
let mut end = self.len();
/// let mut bv = BitVec::from_elem(3, true);
/// bv.set(1, false);
///
- /// assert_eq!(bv.to_bytes(), vec!(0b10100000));
+ /// assert_eq!(bv.to_bytes(), [0b10100000]);
///
/// let mut bv = BitVec::from_elem(9, false);
/// bv.set(2, true);
/// bv.set(8, true);
///
- /// assert_eq!(bv.to_bytes(), vec!(0b00100000, 0b10000000));
+ /// assert_eq!(bv.to_bytes(), [0b00100000, 0b10000000]);
/// ```
pub fn to_bytes(&self) -> Vec<u8> {
fn bit(bit_vec: &BitVec, byte: usize, bit: usize) -> u8 {
/// let mut bv = BitVec::from_bytes(&[0b01001011]);
/// bv.grow(2, true);
/// assert_eq!(bv.len(), 10);
- /// assert_eq!(bv.to_bytes(), vec!(0b01001011, 0b11000000));
+ /// assert_eq!(bv.to_bytes(), [0b01001011, 0b11000000]);
/// ```
pub fn grow(&mut self, n: usize, value: bool) {
// Note: we just bulk set all the bits in the last word in this fn in multiple places
impl fmt::Debug for BitVec {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
for bit in self {
- try!(write!(fmt, "{}", if bit { 1u32 } else { 0u32 }));
+ try!(write!(fmt, "{}", if bit { 1 } else { 0 }));
}
Ok(())
}
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for BitSet {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- try!(write!(fmt, "BitSet {{"));
+ try!(write!(fmt, "{{"));
let mut first = true;
for n in self {
if !first {
fn test_to_bytes() {
let mut bv = BitVec::from_elem(3, true);
bv.set(1, false);
- assert_eq!(bv.to_bytes(), vec!(0b10100000));
+ assert_eq!(bv.to_bytes(), [0b10100000]);
let mut bv = BitVec::from_elem(9, false);
bv.set(2, true);
bv.set(8, true);
- assert_eq!(bv.to_bytes(), vec!(0b00100000, 0b10000000));
+ assert_eq!(bv.to_bytes(), [0b00100000, 0b10000000]);
}
#[test]
s.insert(10);
s.insert(50);
s.insert(2);
- assert_eq!("BitSet {1, 2, 10, 50}", format!("{:?}", s));
+ assert_eq!("{1, 2, 10, 50}", format!("{:?}", s));
}
#[test]
let bit_vec: BitSet = usizes.into_iter().collect();
let idxs: Vec<_> = bit_vec.iter().collect();
- assert_eq!(idxs, vec![0, 2, 3]);
+ 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 result = stack.with(move |pusher, node| {
// Same basic logic as found in `find`, but with PartialSearchStack mediating the
// actual nodes for us
- return match Node::search(node, &key) {
+ match Node::search(node, &key) {
Found(mut handle) => {
// Perfect match, swap the values and return the old one
mem::swap(handle.val_mut(), &mut value);
}
});
match result {
- Finished(ret) => { return ret; },
+ Finished(ret) => return ret,
Continue((new_stack, renewed_key, renewed_val)) => {
stack = new_stack;
key = renewed_key;
let mut stack = stack::PartialSearchStack::new(self);
loop {
let result = stack.with(move |pusher, node| {
- return match Node::search(node, key) {
+ match Node::search(node, key) {
Found(handle) => {
// Perfect match. Terminate the stack here, and remove the entry
Finished(Some(pusher.seal(handle).remove()))
#[stable(feature = "rust1", since = "1.0.0")]
impl<K: Debug, V: Debug> Debug for BTreeMap<K, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- try!(write!(f, "BTreeMap {{"));
+ try!(write!(f, "{{"));
for (i, (k, v)) in self.iter().enumerate() {
if i != 0 { try!(write!(f, ", ")); }
/// a.insert(2, "b");
///
/// let keys: Vec<usize> = a.keys().cloned().collect();
- /// assert_eq!(keys, vec![1,2,]);
+ /// assert_eq!(keys, [1, 2]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn keys<'a>(&'a self) -> Keys<'a, K, V> {
/// a.insert(2, "b");
///
/// let values: Vec<&str> = a.values().cloned().collect();
- /// assert_eq!(values, vec!["a","b"]);
+ /// assert_eq!(values, ["a", "b"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn values<'a>(&'a self) -> Values<'a, K, V> {
let mut stack = stack::PartialSearchStack::new(self);
loop {
let result = stack.with(move |pusher, node| {
- return match Node::search(node, &key) {
+ match Node::search(node, &key) {
Found(handle) => {
// Perfect match
Finished(Occupied(OccupiedEntry {
// This must be followed by insert_edge on an internal node.
#[inline]
unsafe fn insert_kv(&mut self, index: usize, key: K, val: V) -> &mut V {
- ptr::copy_memory(
+ ptr::copy(
self.keys_mut().as_mut_ptr().offset(index as isize + 1),
self.keys().as_ptr().offset(index as isize),
self.len() - index
);
- ptr::copy_memory(
+ ptr::copy(
self.vals_mut().as_mut_ptr().offset(index as isize + 1),
self.vals().as_ptr().offset(index as isize),
self.len() - index
// This can only be called immediately after a call to insert_kv.
#[inline]
unsafe fn insert_edge(&mut self, index: usize, edge: Node<K, V>) {
- ptr::copy_memory(
+ ptr::copy(
self.edges_mut().as_mut_ptr().offset(index as isize + 1),
self.edges().as_ptr().offset(index as isize),
self.len() - index
let key = ptr::read(self.keys().get_unchecked(index));
let val = ptr::read(self.vals().get_unchecked(index));
- ptr::copy_memory(
+ ptr::copy(
self.keys_mut().as_mut_ptr().offset(index as isize),
self.keys().as_ptr().offset(index as isize + 1),
self.len() - index - 1
);
- ptr::copy_memory(
+ ptr::copy(
self.vals_mut().as_mut_ptr().offset(index as isize),
self.vals().as_ptr().offset(index as isize + 1),
self.len() - index - 1
unsafe fn remove_edge(&mut self, index: usize) -> Node<K, V> {
let edge = ptr::read(self.edges().get_unchecked(index));
- ptr::copy_memory(
+ ptr::copy(
self.edges_mut().as_mut_ptr().offset(index as isize),
self.edges().as_ptr().offset(index as isize + 1),
self.len() - index + 1
unsafe {
right._len = self.len() / 2;
let right_offset = self.len() - right.len();
- ptr::copy_nonoverlapping_memory(
+ ptr::copy_nonoverlapping(
right.keys_mut().as_mut_ptr(),
self.keys().as_ptr().offset(right_offset as isize),
right.len()
);
- ptr::copy_nonoverlapping_memory(
+ ptr::copy_nonoverlapping(
right.vals_mut().as_mut_ptr(),
self.vals().as_ptr().offset(right_offset as isize),
right.len()
);
if !self.is_leaf() {
- ptr::copy_nonoverlapping_memory(
+ ptr::copy_nonoverlapping(
right.edges_mut().as_mut_ptr(),
self.edges().as_ptr().offset(right_offset as isize),
right.len() + 1
ptr::write(self.keys_mut().get_unchecked_mut(old_len), key);
ptr::write(self.vals_mut().get_unchecked_mut(old_len), val);
- ptr::copy_nonoverlapping_memory(
+ ptr::copy_nonoverlapping(
self.keys_mut().as_mut_ptr().offset(old_len as isize + 1),
right.keys().as_ptr(),
right.len()
);
- ptr::copy_nonoverlapping_memory(
+ ptr::copy_nonoverlapping(
self.vals_mut().as_mut_ptr().offset(old_len as isize + 1),
right.vals().as_ptr(),
right.len()
);
if !self.is_leaf() {
- ptr::copy_nonoverlapping_memory(
+ ptr::copy_nonoverlapping(
self.edges_mut().as_mut_ptr().offset(old_len as isize + 1),
right.edges().as_ptr(),
right.len() + 1
/// }
///
/// let v: Vec<usize> = set.iter().cloned().collect();
- /// assert_eq!(v, vec![1,2,3,4]);
+ /// assert_eq!(v, [1, 2, 3, 4]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter(&self) -> Iter<T> {
/// let set: BTreeSet<usize> = [1, 2, 3, 4].iter().cloned().collect();
///
/// let v: Vec<usize> = set.into_iter().collect();
- /// assert_eq!(v, vec![1,2,3,4]);
+ /// assert_eq!(v, [1, 2, 3, 4]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_iter(self) -> IntoIter<T> {
/// b.insert(3);
///
/// let diff: Vec<usize> = a.difference(&b).cloned().collect();
- /// assert_eq!(diff, vec![1]);
+ /// assert_eq!(diff, [1]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn difference<'a>(&'a self, other: &'a BTreeSet<T>) -> Difference<'a, T> {
/// b.insert(3);
///
/// let sym_diff: Vec<usize> = a.symmetric_difference(&b).cloned().collect();
- /// assert_eq!(sym_diff, vec![1,3]);
+ /// assert_eq!(sym_diff, [1, 3]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn symmetric_difference<'a>(&'a self, other: &'a BTreeSet<T>)
/// b.insert(3);
///
/// let intersection: Vec<usize> = a.intersection(&b).cloned().collect();
- /// assert_eq!(intersection, vec![2]);
+ /// assert_eq!(intersection, [2]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn intersection<'a>(&'a self, other: &'a BTreeSet<T>)
/// b.insert(2);
///
/// let union: Vec<usize> = a.union(&b).cloned().collect();
- /// assert_eq!(union, vec![1,2]);
+ /// assert_eq!(union, [1, 2]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn union<'a>(&'a self, other: &'a BTreeSet<T>) -> Union<'a, T> {
///
/// let result = &a - &b;
/// let result_vec: Vec<_> = result.into_iter().collect();
- /// assert_eq!(result_vec, vec![1, 2]);
+ /// assert_eq!(result_vec, [1, 2]);
/// ```
fn sub(self, rhs: &BTreeSet<T>) -> BTreeSet<T> {
self.difference(rhs).cloned().collect()
///
/// let result = &a ^ &b;
/// let result_vec: Vec<_> = result.into_iter().collect();
- /// assert_eq!(result_vec, vec![1, 4]);
+ /// assert_eq!(result_vec, [1, 4]);
/// ```
fn bitxor(self, rhs: &BTreeSet<T>) -> BTreeSet<T> {
self.symmetric_difference(rhs).cloned().collect()
///
/// let result = &a & &b;
/// let result_vec: Vec<_> = result.into_iter().collect();
- /// assert_eq!(result_vec, vec![2, 3]);
+ /// assert_eq!(result_vec, [2, 3]);
/// ```
fn bitand(self, rhs: &BTreeSet<T>) -> BTreeSet<T> {
self.intersection(rhs).cloned().collect()
///
/// let result = &a | &b;
/// let result_vec: Vec<_> = result.into_iter().collect();
- /// assert_eq!(result_vec, vec![1, 2, 3, 4, 5]);
+ /// assert_eq!(result_vec, [1, 2, 3, 4, 5]);
/// ```
fn bitor(self, rhs: &BTreeSet<T>) -> BTreeSet<T> {
self.union(rhs).cloned().collect()
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Debug> Debug for BTreeSet<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- try!(write!(f, "BTreeSet {{"));
+ try!(write!(f, "{{"));
for (i, x) in self.iter().enumerate() {
if i != 0 { try!(write!(f, ", ")); }
let set_str = format!("{:?}", set);
- assert_eq!(set_str, "BTreeSet {1, 2}");
- assert_eq!(format!("{:?}", empty), "BTreeSet {}");
+ assert_eq!(set_str, "{1, 2}");
+ assert_eq!(format!("{:?}", empty), "{}");
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<E:CLike + fmt::Debug> fmt::Debug for EnumSet<E> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- try!(write!(fmt, "EnumSet {{"));
+ try!(write!(fmt, "{{"));
let mut first = true;
for e in self {
if !first {
#[test]
fn test_show() {
let mut e = EnumSet::new();
- assert!(format!("{:?}", e) == "EnumSet {}");
+ assert!(format!("{:?}", e) == "{}");
e.insert(A);
- assert!(format!("{:?}", e) == "EnumSet {A}");
+ assert!(format!("{:?}", e) == "{A}");
e.insert(C);
- assert!(format!("{:?}", e) == "EnumSet {A, C}");
+ assert!(format!("{:?}", e) == "{A, C}");
}
#[test]
e1.insert(A);
let elems: ::vec::Vec<_> = e1.iter().collect();
- assert_eq!(vec![A], elems);
+ assert_eq!([A], elems);
e1.insert(C);
let elems: ::vec::Vec<_> = e1.iter().collect();
- assert_eq!(vec![A,C], elems);
+ assert_eq!([A,C], elems);
e1.insert(C);
let elems: ::vec::Vec<_> = e1.iter().collect();
- assert_eq!(vec![A,C], elems);
+ assert_eq!([A,C], elems);
e1.insert(B);
let elems: ::vec::Vec<_> = e1.iter().collect();
- assert_eq!(vec![A,B,C], elems);
+ assert_eq!([A,B,C], elems);
}
///////////////////////////////////////////////////////////////////////////
let e_union = e1 | e2;
let elems: ::vec::Vec<_> = e_union.iter().collect();
- assert_eq!(vec![A,B,C], elems);
+ assert_eq!([A,B,C], elems);
let e_intersection = e1 & e2;
let elems: ::vec::Vec<_> = e_intersection.iter().collect();
- assert_eq!(vec![C], elems);
+ assert_eq!([C], elems);
// Another way to express intersection
let e_intersection = e1 - (e1 - e2);
let elems: ::vec::Vec<_> = e_intersection.iter().collect();
- assert_eq!(vec![C], elems);
+ assert_eq!([C], elems);
let e_subtract = e1 - e2;
let elems: ::vec::Vec<_> = e_subtract.iter().collect();
- assert_eq!(vec![A], elems);
+ assert_eq!([A], elems);
// Bitwise XOR of two sets, aka symmetric difference
let e_symmetric_diff = e1 ^ e2;
let elems: ::vec::Vec<_> = e_symmetric_diff.iter().collect();
- assert_eq!(vec![A,B], elems);
+ assert_eq!([A,B], elems);
// Another way to express symmetric difference
let e_symmetric_diff = (e1 - e2) | (e2 - e1);
let elems: ::vec::Vec<_> = e_symmetric_diff.iter().collect();
- assert_eq!(vec![A,B], elems);
+ assert_eq!([A,B], elems);
// Yet another way to express symmetric difference
let e_symmetric_diff = (e1 | e2) - (e1 & e2);
let elems: ::vec::Vec<_> = e_symmetric_diff.iter().collect();
- assert_eq!(vec![A,B], elems);
+ assert_eq!([A,B], elems);
}
#[test]
#![feature(unboxed_closures)]
#![feature(unicode)]
#![feature(unsafe_destructor)]
+#![feature(unique)]
#![feature(unsafe_no_drop_flag)]
#![cfg_attr(test, feature(rand, rustc_private, test))]
#![cfg_attr(test, allow(deprecated))] // rand
/// }
/// {
/// let vec: Vec<_> = list.into_iter().collect();
- /// assert_eq!(vec, vec![1, 2, 3, 4]);
+ /// assert_eq!(vec, [1, 2, 3, 4]);
/// }
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: fmt::Debug> fmt::Debug for LinkedList<A> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- try!(write!(f, "LinkedList ["));
+ try!(write!(f, "["));
for (i, e) in self.iter().enumerate() {
if i != 0 { try!(write!(f, ", ")); }
}
check_links(&m);
assert_eq!(m.len(), 3 + len * 2);
- assert_eq!(m.into_iter().collect::<Vec<_>>(), vec![-2,0,1,2,3,4,5,6,7,8,9,0,1]);
+ assert_eq!(m.into_iter().collect::<Vec<_>>(), [-2,0,1,2,3,4,5,6,7,8,9,0,1]);
}
#[test]
#[test]
fn test_show() {
let list: LinkedList<_> = (0..10).collect();
- assert_eq!(format!("{:?}", list), "LinkedList [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
+ assert_eq!(format!("{:?}", list), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
let list: LinkedList<_> = vec!["just", "one", "test", "more"].iter().cloned().collect();
- assert_eq!(format!("{:?}", list), "LinkedList [\"just\", \"one\", \"test\", \"more\"]");
+ assert_eq!(format!("{:?}", list), "[\"just\", \"one\", \"test\", \"more\"]");
}
#[cfg(test)]
///
/// ```
/// let v = vec![1; 3];
-/// assert_eq!(v, vec![1, 1, 1]);
+/// assert_eq!(v, [1, 1, 1]);
/// ```
///
/// Note that unlike array expressions this syntax supports all elements
fn ends_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq;
/// Convert `self` into a vector without clones or allocation.
- #[unstable(feature = "collections")]
+ #[stable(feature = "rust1", since = "1.0.0")]
fn into_vec(self: Box<Self>) -> Vec<Self::Item>;
}
if i != j {
let tmp = ptr::read(read_ptr);
- ptr::copy_memory(buf_v.offset(j + 1),
- &*buf_v.offset(j),
- (i - j) as usize);
- ptr::copy_nonoverlapping_memory(buf_v.offset(j),
- &tmp,
- 1);
+ ptr::copy(buf_v.offset(j + 1),
+ &*buf_v.offset(j),
+ (i - j) as usize);
+ ptr::copy_nonoverlapping(buf_v.offset(j), &tmp, 1);
mem::forget(tmp);
}
}
// j + 1 could be `len` (for the last `i`), but in
// that case, `i == j` so we don't copy. The
// `.offset(j)` is always in bounds.
- ptr::copy_memory(buf_dat.offset(j + 1),
- &*buf_dat.offset(j),
- i - j as usize);
- ptr::copy_nonoverlapping_memory(buf_dat.offset(j), read_ptr, 1);
+ ptr::copy(buf_dat.offset(j + 1),
+ &*buf_dat.offset(j),
+ i - j as usize);
+ ptr::copy_nonoverlapping(buf_dat.offset(j), read_ptr, 1);
}
}
}
if left == right_start {
// the number remaining in this run.
let elems = (right_end as usize - right as usize) / mem::size_of::<T>();
- ptr::copy_nonoverlapping_memory(out, &*right, elems);
+ ptr::copy_nonoverlapping(out, &*right, elems);
break;
} else if right == right_end {
let elems = (right_start as usize - left as usize) / mem::size_of::<T>();
- ptr::copy_nonoverlapping_memory(out, &*left, elems);
+ ptr::copy_nonoverlapping(out, &*left, elems);
break;
}
} else {
step(&mut left)
};
- ptr::copy_nonoverlapping_memory(out, &*to_copy, 1);
+ ptr::copy_nonoverlapping(out, &*to_copy, 1);
step(&mut out);
}
}
// write the result to `v` in one go, so that there are never two copies
// of the same object in `v`.
unsafe {
- ptr::copy_nonoverlapping_memory(v.as_mut_ptr(), &*buf_dat, len);
+ ptr::copy_nonoverlapping(v.as_mut_ptr(), &*buf_dat, len);
}
// increment the pointer, returning the old pointer.
let mut v = vec![1, 2, 3, 4, 5];
let mut e = v.swap_remove(0);
assert_eq!(e, 1);
- assert_eq!(v, vec![5, 2, 3, 4]);
+ assert_eq!(v, [5, 2, 3, 4]);
e = v.swap_remove(3);
assert_eq!(e, 4);
- assert_eq!(v, vec![5, 2, 3]);
+ assert_eq!(v, [5, 2, 3]);
}
#[test]
fn test_retain() {
let mut v = vec![1, 2, 3, 4, 5];
v.retain(is_odd);
- assert_eq!(v, vec![1, 3, 5]);
+ assert_eq!(v, [1, 3, 5]);
}
#[test]
let v: [Vec<i32>; 0] = [];
let c = v.concat();
assert_eq!(c, []);
- let d = [vec![1], vec![2,3]].concat();
- assert_eq!(d, vec![1, 2, 3]);
+ let d = [vec![1], vec![2, 3]].concat();
+ assert_eq!(d, [1, 2, 3]);
let v: &[&[_]] = &[&[1], &[2, 3]];
- assert_eq!(v.connect(&0), vec![1, 0, 2, 3]);
+ assert_eq!(v.connect(&0), [1, 0, 2, 3]);
let v: &[&[_]] = &[&[1], &[2], &[3]];
- assert_eq!(v.connect(&0), vec![1, 0, 2, 0, 3]);
+ assert_eq!(v.connect(&0), [1, 0, 2, 0, 3]);
}
#[test]
fn test_connect() {
let v: [Vec<i32>; 0] = [];
- assert_eq!(v.connect(&0), vec![]);
- assert_eq!([vec![1], vec![2, 3]].connect(&0), vec![1, 0, 2, 3]);
- assert_eq!([vec![1], vec![2], vec![3]].connect(&0), vec![1, 0, 2, 0, 3]);
+ assert_eq!(v.connect(&0), []);
+ assert_eq!([vec![1i], vec![2, 3]].connect(&0), [1, 0, 2, 3]);
+ assert_eq!([vec![1i], vec![2], vec![3]].connect(&0), [1, 0, 2, 0, 3]);
let v: [&[_]; 2] = [&[1], &[2, 3]];
- assert_eq!(v.connect(&0), vec![1, 0, 2, 3]);
+ assert_eq!(v.connect(&0), [1, 0, 2, 3]);
let v: [&[_]; 3] = [&[1], &[2], &[3]];
- assert_eq!(v.connect(&0), vec![1, 0, 2, 0, 3]);
+ assert_eq!(v.connect(&0), [1, 0, 2, 0, 3]);
}
#[test]
fn test_insert() {
let mut a = vec![1, 2, 4];
a.insert(2, 3);
- assert_eq!(a, vec![1, 2, 3, 4]);
+ assert_eq!(a, [1, 2, 3, 4]);
let mut a = vec![1, 2, 3];
a.insert(0, 0);
- assert_eq!(a, vec![0, 1, 2, 3]);
+ assert_eq!(a, [0, 1, 2, 3]);
let mut a = vec![1, 2, 3];
a.insert(3, 4);
- assert_eq!(a, vec![1, 2, 3, 4]);
+ assert_eq!(a, [1, 2, 3, 4]);
let mut a = vec![];
a.insert(0, 1);
- assert_eq!(a, vec![1]);
+ assert_eq!(a, [1]);
}
#[test]
let mut a = vec![1, 2, 3, 4];
assert_eq!(a.remove(2), 3);
- assert_eq!(a, vec![1, 2, 4]);
+ assert_eq!(a, [1, 2, 4]);
assert_eq!(a.remove(2), 4);
- assert_eq!(a, vec![1, 2]);
+ assert_eq!(a, [1, 2]);
assert_eq!(a.remove(0), 1);
- assert_eq!(a, vec![2]);
+ assert_eq!(a, [2]);
assert_eq!(a.remove(0), 2);
- assert_eq!(a, vec![]);
+ assert_eq!(a, []);
}
#[test]
/// ```
/// let v: Vec<char> = "abc åäö".chars().collect();
///
- /// assert_eq!(v, vec!['a', 'b', 'c', ' ', 'å', 'ä', 'ö']);
+ /// assert_eq!(v, ['a', 'b', 'c', ' ', 'å', 'ä', 'ö']);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn chars(&self) -> Chars {
///
/// ```
/// let v: Vec<&str> = "Mary had a little lamb".split(' ').collect();
- /// assert_eq!(v, vec!["Mary", "had", "a", "little", "lamb"]);
+ /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
///
/// let v: Vec<&str> = "".split('X').collect();
- /// assert_eq!(v, vec![""]);
+ /// assert_eq!(v, [""]);
/// ```
///
/// More complex patterns with a lambda:
///
/// ```
/// let v: Vec<&str> = "abc1def2ghi".split(|c: char| c.is_numeric()).collect();
- /// assert_eq!(v, vec!["abc", "def", "ghi"]);
+ /// assert_eq!(v, ["abc", "def", "ghi"]);
///
/// let v: Vec<&str> = "lionXXtigerXleopard".split('X').collect();
- /// assert_eq!(v, vec!["lion", "", "tiger", "leopard"]);
+ /// assert_eq!(v, ["lion", "", "tiger", "leopard"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
///
/// ```
/// let v: Vec<&str> = "Mary had a little lambda".splitn(2, ' ').collect();
- /// assert_eq!(v, vec!["Mary", "had", "a little lambda"]);
+ /// assert_eq!(v, ["Mary", "had", "a little lambda"]);
///
/// let v: Vec<&str> = "lionXXtigerXleopard".splitn(2, 'X').collect();
- /// assert_eq!(v, vec!["lion", "", "tigerXleopard"]);
+ /// assert_eq!(v, ["lion", "", "tigerXleopard"]);
///
/// let v: Vec<&str> = "abcXdef".splitn(0, 'X').collect();
- /// assert_eq!(v, vec!["abcXdef"]);
+ /// assert_eq!(v, ["abcXdef"]);
///
/// let v: Vec<&str> = "".splitn(1, 'X').collect();
- /// assert_eq!(v, vec![""]);
+ /// assert_eq!(v, [""]);
/// ```
///
/// More complex patterns with a lambda:
///
/// ```
/// let v: Vec<&str> = "abc1def2ghi".splitn(1, |c: char| c.is_numeric()).collect();
- /// assert_eq!(v, vec!["abc", "def2ghi"]);
+ /// assert_eq!(v, ["abc", "def2ghi"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> {
///
/// ```
/// let v: Vec<&str> = "A.B.".split_terminator('.').collect();
- /// assert_eq!(v, vec!["A", "B"]);
+ /// assert_eq!(v, ["A", "B"]);
///
/// let v: Vec<&str> = "A..B..".split_terminator('.').collect();
- /// assert_eq!(v, vec!["A", "", "B", ""]);
+ /// assert_eq!(v, ["A", "", "B", ""]);
/// ```
///
/// More complex patterns with a lambda:
///
/// ```
/// let v: Vec<&str> = "abc1def2ghi3".split_terminator(|c: char| c.is_numeric()).collect();
- /// assert_eq!(v, vec!["abc", "def", "ghi"]);
+ /// assert_eq!(v, ["abc", "def", "ghi"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> {
///
/// ```
/// let v: Vec<&str> = "Mary had a little lamb".rsplitn(2, ' ').collect();
- /// assert_eq!(v, vec!["lamb", "little", "Mary had a"]);
+ /// assert_eq!(v, ["lamb", "little", "Mary had a"]);
///
/// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(2, 'X').collect();
- /// assert_eq!(v, vec!["leopard", "tiger", "lionX"]);
+ /// assert_eq!(v, ["leopard", "tiger", "lionX"]);
/// ```
///
/// More complex patterns with a lambda:
///
/// ```
/// let v: Vec<&str> = "abc1def2ghi".rsplitn(1, |c: char| c.is_numeric()).collect();
- /// assert_eq!(v, vec!["ghi", "abc1def"]);
+ /// assert_eq!(v, ["ghi", "abc1def"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> {
///
/// ```
/// let v: Vec<(usize, usize)> = "abcXXXabcYYYabc".match_indices("abc").collect();
- /// assert_eq!(v, vec![(0,3), (6,9), (12,15)]);
+ /// assert_eq!(v, [(0,3), (6,9), (12,15)]);
///
/// let v: Vec<(usize, usize)> = "1abcabc2".match_indices("abc").collect();
- /// assert_eq!(v, vec![(1,4), (4,7)]);
+ /// assert_eq!(v, [(1,4), (4,7)]);
///
/// let v: Vec<(usize, usize)> = "ababa".match_indices("aba").collect();
- /// assert_eq!(v, vec![(0, 3)]); // only the first `aba`
+ /// assert_eq!(v, [(0, 3)]); // only the first `aba`
/// ```
#[unstable(feature = "collections",
reason = "might have its iterator type changed")]
///
/// ```
/// let v: Vec<&str> = "abcXXXabcYYYabc".split_str("abc").collect();
- /// assert_eq!(v, vec!["", "XXX", "YYY", ""]);
+ /// assert_eq!(v, ["", "XXX", "YYY", ""]);
///
/// let v: Vec<&str> = "1abcabc2".split_str("abc").collect();
- /// assert_eq!(v, vec!["1", "", "2"]);
+ /// assert_eq!(v, ["1", "", "2"]);
/// ```
#[unstable(feature = "collections")]
#[deprecated(since = "1.0.0", reason = "use `split()` with a `&str`")]
/// let four_lines = "foo\nbar\n\nbaz";
/// let v: Vec<&str> = four_lines.lines().collect();
///
- /// assert_eq!(v, vec!["foo", "bar", "", "baz"]);
+ /// assert_eq!(v, ["foo", "bar", "", "baz"]);
/// ```
///
/// Leaving off the trailing character:
/// let four_lines = "foo\nbar\n\nbaz\n";
/// let v: Vec<&str> = four_lines.lines().collect();
///
- /// assert_eq!(v, vec!["foo", "bar", "", "baz"]);
+ /// assert_eq!(v, ["foo", "bar", "", "baz"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn lines(&self) -> Lines {
/// let four_lines = "foo\r\nbar\n\r\nbaz";
/// let v: Vec<&str> = four_lines.lines_any().collect();
///
- /// assert_eq!(v, vec!["foo", "bar", "", "baz"]);
+ /// assert_eq!(v, ["foo", "bar", "", "baz"]);
/// ```
///
/// Leaving off the trailing character:
/// let four_lines = "foo\r\nbar\n\r\nbaz\n";
/// let v: Vec<&str> = four_lines.lines_any().collect();
///
- /// assert_eq!(v, vec!["foo", "bar", "", "baz"]);
+ /// assert_eq!(v, ["foo", "bar", "", "baz"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn lines_any(&self) -> LinesAny {
/// let some_words = " Mary had\ta little \n\t lamb";
/// let v: Vec<&str> = some_words.words().collect();
///
- /// assert_eq!(v, vec!["Mary", "had", "a", "little", "lamb"]);
+ /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
/// ```
#[unstable(feature = "str_words",
reason = "the precise algorithm to use is unclear")]
let data = "\nMäry häd ä little lämb\nLittle lämb\n";
let split: Vec<&str> = data.splitn(3, ' ').collect();
- assert_eq!(split, vec!["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]);
+ assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]);
let split: Vec<&str> = data.splitn(3, |c: char| c == ' ').collect();
- assert_eq!(split, vec!["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]);
+ assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]);
// Unicode
let split: Vec<&str> = data.splitn(3, 'ä').collect();
- assert_eq!(split, vec!["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]);
+ assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]);
let split: Vec<&str> = data.splitn(3, |c: char| c == 'ä').collect();
- assert_eq!(split, vec!["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]);
+ assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]);
}
#[test]
let data = "\nMäry häd ä little lämb\nLittle lämb\n";
let split: Vec<&str> = data.split('\n').collect();
- assert_eq!(split, vec!["", "Märy häd ä little lämb", "Little lämb", ""]);
+ assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb", ""]);
let split: Vec<&str> = data.split_terminator('\n').collect();
- assert_eq!(split, vec!["", "Märy häd ä little lämb", "Little lämb"]);
+ assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]);
}
#[test]
fn test_words() {
let data = "\n \tMäry häd\tä little lämb\nLittle lämb\n";
let words: Vec<&str> = data.words().collect();
- assert_eq!(words, vec!["Märy", "häd", "ä", "little", "lämb", "Little", "lämb"])
+ assert_eq!(words, ["Märy", "häd", "ä", "little", "lämb", "Little", "lämb"])
}
#[test]
fn test_lines() {
let data = "\nMäry häd ä little lämb\n\nLittle lämb\n";
let lines: Vec<&str> = data.lines().collect();
- assert_eq!(lines, vec!["", "Märy häd ä little lämb", "", "Little lämb"]);
+ assert_eq!(lines, ["", "Märy häd ä little lämb", "", "Little lämb"]);
let data = "\nMäry häd ä little lämb\n\nLittle lämb"; // no trailing \n
let lines: Vec<&str> = data.lines().collect();
- assert_eq!(lines, vec!["", "Märy häd ä little lämb", "", "Little lämb"]);
+ assert_eq!(lines, ["", "Märy häd ä little lämb", "", "Little lämb"]);
}
#[test]
/// let invalid_vec = vec![240, 144, 128];
/// let s = String::from_utf8(invalid_vec).err().unwrap();
/// assert_eq!(s.utf8_error(), Utf8Error::TooShort);
- /// assert_eq!(s.into_bytes(), vec![240, 144, 128]);
+ /// assert_eq!(s.into_bytes(), [240, 144, 128]);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
/// let s = String::from_str("hello");
/// let bytes = s.into_bytes();
- /// assert_eq!(bytes, vec![104, 101, 108, 108, 111]);
+ /// assert_eq!(bytes, [104, 101, 108, 108, 111]);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
let CharRange { ch, next } = self.char_range_at(idx);
unsafe {
- ptr::copy_memory(self.vec.as_mut_ptr().offset(idx as isize),
- self.vec.as_ptr().offset(next as isize),
- len - next);
+ ptr::copy(self.vec.as_mut_ptr().offset(idx as isize),
+ self.vec.as_ptr().offset(next as isize),
+ len - next);
self.vec.set_len(len - (next - idx));
}
ch
let amt = ch.encode_utf8(&mut bits).unwrap();
unsafe {
- ptr::copy_memory(self.vec.as_mut_ptr().offset((idx + amt) as isize),
- self.vec.as_ptr().offset(idx as isize),
- len - idx);
- ptr::copy_memory(self.vec.as_mut_ptr().offset(idx as isize),
- bits.as_ptr(),
- amt);
+ ptr::copy(self.vec.as_mut_ptr().offset((idx + amt) as isize),
+ self.vec.as_ptr().offset(idx as isize),
+ len - idx);
+ ptr::copy(self.vec.as_mut_ptr().offset(idx as isize),
+ bits.as_ptr(),
+ amt);
self.vec.set_len(len + amt);
}
}
/// let mut s = String::from_str("hello");
/// unsafe {
/// let vec = s.as_mut_vec();
- /// assert!(vec == &mut vec![104, 101, 108, 108, 111]);
+ /// assert!(vec == &[104, 101, 108, 108, 111]);
/// vec.reverse();
/// }
/// assert_eq!(s.as_slice(), "olleh");
/// for x in vec.iter() {
/// println!("{}", x);
/// }
-/// assert_eq!(vec, vec![7, 1, 2, 3]);
+/// assert_eq!(vec, [7, 1, 2, 3]);
/// ```
///
/// The `vec!` macro is provided to make initialization more convenient:
/// ```
/// let mut vec = vec![1, 2, 3];
/// vec.push(4);
-/// assert_eq!(vec, vec![1, 2, 3, 4]);
+/// assert_eq!(vec, [1, 2, 3, 4]);
/// ```
///
/// Use a `Vec<T>` as an efficient stack:
///
/// // Put everything back together into a Vec
/// let rebuilt = Vec::from_raw_parts(p, len, cap);
- /// assert_eq!(rebuilt, vec![4, 5, 6]);
+ /// assert_eq!(rebuilt, [4, 5, 6]);
/// }
/// }
/// ```
pub unsafe fn from_raw_buf(ptr: *const T, elts: usize) -> Vec<T> {
let mut dst = Vec::with_capacity(elts);
dst.set_len(elts);
- ptr::copy_nonoverlapping_memory(dst.as_mut_ptr(), ptr, elts);
+ ptr::copy_nonoverlapping(dst.as_mut_ptr(), ptr, elts);
dst
}
/// ```
/// let mut vec = vec![1, 2, 3, 4];
/// vec.truncate(2);
- /// assert_eq!(vec, vec![1, 2]);
+ /// assert_eq!(vec, [1, 2]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn truncate(&mut self, len: usize) {
/// let mut v = vec!["foo", "bar", "baz", "qux"];
///
/// assert_eq!(v.swap_remove(1), "bar");
- /// assert_eq!(v, vec!["foo", "qux", "baz"]);
+ /// assert_eq!(v, ["foo", "qux", "baz"]);
///
/// assert_eq!(v.swap_remove(0), "foo");
- /// assert_eq!(v, vec!["baz", "qux"]);
+ /// assert_eq!(v, ["baz", "qux"]);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
/// let mut vec = vec![1, 2, 3];
/// vec.insert(1, 4);
- /// assert_eq!(vec, vec![1, 4, 2, 3]);
+ /// assert_eq!(vec, [1, 4, 2, 3]);
/// vec.insert(4, 5);
- /// assert_eq!(vec, vec![1, 4, 2, 3, 5]);
+ /// assert_eq!(vec, [1, 4, 2, 3, 5]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn insert(&mut self, index: usize, element: T) {
let p = self.as_mut_ptr().offset(index as isize);
// Shift everything over to make space. (Duplicating the
// `index`th element into two consecutive places.)
- ptr::copy_memory(p.offset(1), &*p, len - index);
+ ptr::copy(p.offset(1), &*p, len - index);
// Write it in, overwriting the first copy of the `index`th
// element.
ptr::write(&mut *p, element);
/// ```
/// let mut v = vec![1, 2, 3];
/// assert_eq!(v.remove(1), 2);
- /// assert_eq!(v, vec![1, 3]);
+ /// assert_eq!(v, [1, 3]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn remove(&mut self, index: usize) -> T {
ret = ptr::read(ptr);
// Shift everything down to fill in that spot.
- ptr::copy_memory(ptr, &*ptr.offset(1), len - index - 1);
+ ptr::copy(ptr, &*ptr.offset(1), len - index - 1);
}
self.set_len(len - 1);
ret
/// ```
/// let mut vec = vec![1, 2, 3, 4];
/// vec.retain(|&x| x%2 == 0);
- /// assert_eq!(vec, vec![2, 4]);
+ /// assert_eq!(vec, [2, 4]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn retain<F>(&mut self, mut f: F) where F: FnMut(&T) -> bool {
/// ```rust
/// let mut vec = vec!(1, 2);
/// vec.push(3);
- /// assert_eq!(vec, vec!(1, 2, 3));
+ /// assert_eq!(vec, [1, 2, 3]);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// ```rust
/// let mut vec = vec![1, 2, 3];
/// assert_eq!(vec.pop(), Some(3));
- /// assert_eq!(vec, vec![1, 2]);
+ /// assert_eq!(vec, [1, 2]);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// let mut vec = vec![1, 2, 3];
/// let mut vec2 = vec![4, 5, 6];
/// vec.append(&mut vec2);
- /// assert_eq!(vec, vec![1, 2, 3, 4, 5, 6]);
- /// assert_eq!(vec2, vec![]);
+ /// assert_eq!(vec, [1, 2, 3, 4, 5, 6]);
+ /// assert_eq!(vec2, []);
/// ```
#[inline]
#[unstable(feature = "collections",
self.reserve(other.len());
let len = self.len();
unsafe {
- ptr::copy_nonoverlapping_memory(
+ ptr::copy_nonoverlapping(
self.get_unchecked_mut(len),
other.as_ptr(),
other.len());
/// ```
/// let mut vec = vec![1,2,3];
/// let vec2 = vec.split_off(1);
- /// assert_eq!(vec, vec![1]);
- /// assert_eq!(vec2, vec![2, 3]);
+ /// assert_eq!(vec, [1]);
+ /// assert_eq!(vec2, [2, 3]);
/// ```
#[inline]
#[unstable(feature = "collections",
self.set_len(at);
other.set_len(other_len);
- ptr::copy_nonoverlapping_memory(
+ ptr::copy_nonoverlapping(
other.as_mut_ptr(),
self.as_ptr().offset(at as isize),
other.len());
/// ```
/// let mut vec = vec!["hello"];
/// vec.resize(3, "world");
- /// assert_eq!(vec, vec!["hello", "world", "world"]);
+ /// assert_eq!(vec, ["hello", "world", "world"]);
///
/// let mut vec = vec![1, 2, 3, 4];
/// vec.resize(2, 0);
- /// assert_eq!(vec, vec![1, 2]);
+ /// assert_eq!(vec, [1, 2]);
/// ```
#[unstable(feature = "collections",
reason = "matches collection reform specification; waiting for dust to settle")]
/// ```
/// let mut vec = vec![1];
/// vec.push_all(&[2, 3, 4]);
- /// assert_eq!(vec, vec![1, 2, 3, 4]);
+ /// assert_eq!(vec, [1, 2, 3, 4]);
/// ```
#[inline]
#[unstable(feature = "collections",
///
/// vec.dedup();
///
- /// assert_eq!(vec, vec![1, 2, 3, 2]);
+ /// assert_eq!(vec, [1, 2, 3, 2]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn dedup(&mut self) {
}
}
- assert!(values == vec![2, 3, 5, 6, 7]);
+ assert_eq!(values, [2, 3, 5, 6, 7]);
}
#[test]
fn test_retain() {
let mut vec = vec![1, 2, 3, 4];
vec.retain(|&x| x % 2 == 0);
- assert!(vec == vec![2, 4]);
+ assert_eq!(vec, [2, 4]);
}
#[test]
let a = [1, 2, 3];
let ptr = a.as_ptr();
let b = Vec::from_raw_buf(ptr, 3);
- assert_eq!(b, vec![1, 2, 3]);
+ assert_eq!(b, [1, 2, 3]);
// Test on-heap copy-from-buf.
let c = vec![1, 2, 3, 4, 5];
let ptr = c.as_ptr();
let d = Vec::from_raw_buf(ptr, 5);
- assert_eq!(d, vec![1, 2, 3, 4, 5]);
+ assert_eq!(d, [1, 2, 3, 4, 5]);
}
}
for i in vec {
vec2.push(i);
}
- assert!(vec2 == vec![1, 2, 3]);
+ assert_eq!(vec2, [1, 2, 3]);
}
#[test]
for i in vec.into_iter().rev() {
vec2.push(i);
}
- assert!(vec2 == vec![3, 2, 1]);
+ assert_eq!(vec2, [3, 2, 1]);
}
#[test]
for i in vec {
vec2.push(i);
}
- assert!(vec2 == vec![(), (), ()]);
+ assert_eq!(vec2, [(), (), ()]);
}
#[test]
let mut vec = vec![1, 2, 3];
let mut vec2 = vec![4, 5, 6];
vec.append(&mut vec2);
- assert_eq!(vec, vec![1, 2, 3, 4, 5, 6]);
- assert_eq!(vec2, vec![]);
+ assert_eq!(vec, [1, 2, 3, 4, 5, 6]);
+ assert_eq!(vec2, []);
}
#[test]
fn test_split_off() {
let mut vec = vec![1, 2, 3, 4, 5, 6];
let vec2 = vec.split_off(4);
- assert_eq!(vec, vec![1, 2, 3, 4]);
- assert_eq!(vec2, vec![5, 6]);
+ assert_eq!(vec, [1, 2, 3, 4]);
+ assert_eq!(vec2, [5, 6]);
}
#[bench]
self.cap);
debug_assert!(src + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len,
self.cap);
- ptr::copy_memory(
+ ptr::copy(
self.ptr.offset(dst as isize),
self.ptr.offset(src as isize),
len);
self.cap);
debug_assert!(src + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len,
self.cap);
- ptr::copy_nonoverlapping_memory(
+ ptr::copy_nonoverlapping(
self.ptr.offset(dst as isize),
self.ptr.offset(src as isize),
len);
// `at` lies in the first half.
let amount_in_first = first_len - at;
- ptr::copy_nonoverlapping_memory(*other.ptr,
- first_half.as_ptr().offset(at as isize),
- amount_in_first);
+ ptr::copy_nonoverlapping(*other.ptr,
+ first_half.as_ptr().offset(at as isize),
+ amount_in_first);
// just take all of the second half.
- ptr::copy_nonoverlapping_memory(other.ptr.offset(amount_in_first as isize),
- second_half.as_ptr(),
- second_len);
+ ptr::copy_nonoverlapping(other.ptr.offset(amount_in_first as isize),
+ second_half.as_ptr(),
+ second_len);
} else {
// `at` lies in the second half, need to factor in the elements we skipped
// in the first half.
let offset = at - first_len;
let amount_in_second = second_len - offset;
- ptr::copy_nonoverlapping_memory(*other.ptr,
- second_half.as_ptr().offset(offset as isize),
- amount_in_second);
+ ptr::copy_nonoverlapping(*other.ptr,
+ second_half.as_ptr().offset(offset as isize),
+ amount_in_second);
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Debug> fmt::Debug for VecDeque<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- try!(write!(f, "VecDeque ["));
+ try!(write!(f, "["));
for (i, e) in self.iter().enumerate() {
if i != 0 { try!(write!(f, ", ")); }
let mut d: VecDeque<_> = (0..5).collect();
d.pop_front();
d.swap(0, 3);
- assert_eq!(d.iter().cloned().collect::<Vec<_>>(), vec!(4, 2, 3, 1));
+ assert_eq!(d.iter().cloned().collect::<Vec<_>>(), [4, 2, 3, 1]);
}
#[test]
#[test]
fn test_show() {
let ringbuf: VecDeque<_> = (0..10).collect();
- assert_eq!(format!("{:?}", ringbuf), "VecDeque [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
+ assert_eq!(format!("{:?}", ringbuf), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
let ringbuf: VecDeque<_> = vec!["just", "one", "test", "more"].iter()
.cloned()
.collect();
- assert_eq!(format!("{:?}", ringbuf), "VecDeque [\"just\", \"one\", \"test\", \"more\"]");
+ assert_eq!(format!("{:?}", ringbuf), "[\"just\", \"one\", \"test\", \"more\"]");
}
#[test]
// normal append
a.append(&mut b);
- assert_eq!(a.iter().cloned().collect(), vec![1, 2, 3, 4, 5, 6]);
- assert_eq!(b.iter().cloned().collect(), vec![]);
+ assert_eq!(a.iter().cloned().collect::<Vec<_>>(), [1, 2, 3, 4, 5, 6]);
+ assert_eq!(b.iter().cloned().collect::<Vec<_>>(), []);
// append nothing to something
a.append(&mut b);
- assert_eq!(a.iter().cloned().collect(), vec![1, 2, 3, 4, 5, 6]);
- assert_eq!(b.iter().cloned().collect(), vec![]);
+ assert_eq!(a.iter().cloned().collect::<Vec<_>>(), [1, 2, 3, 4, 5, 6]);
+ assert_eq!(b.iter().cloned().collect::<Vec<_>>(), []);
// append something to nothing
b.append(&mut a);
- assert_eq!(b.iter().cloned().collect(), vec![1, 2, 3, 4, 5, 6]);
- assert_eq!(a.iter().cloned().collect(), vec![]);
+ assert_eq!(b.iter().cloned().collect::<Vec<_>>(), [1, 2, 3, 4, 5, 6]);
+ assert_eq!(a.iter().cloned().collect::<Vec<_>>(), []);
}
}
///
/// let vec: Vec<(usize, &str)> = map.into_iter().collect();
///
- /// assert_eq!(vec, vec![(1, "a"), (2, "b"), (3, "c")]);
+ /// assert_eq!(vec, [(1, "a"), (2, "b"), (3, "c")]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_iter(self) -> IntoIter<V> {
///
/// let vec: Vec<(usize, &str)> = map.drain().collect();
///
- /// assert_eq!(vec, vec![(1, "a"), (2, "b"), (3, "c")]);
+ /// assert_eq!(vec, [(1, "a"), (2, "b"), (3, "c")]);
/// ```
#[unstable(feature = "collections",
reason = "matches collection reform specification, waiting for dust to settle")]
#[stable(feature = "rust1", since = "1.0.0")]
impl<V: fmt::Debug> fmt::Debug for VecMap<V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- try!(write!(f, "VecMap {{"));
+ try!(write!(f, "{{"));
for (i, (k, v)) in self.iter().enumerate() {
if i != 0 { try!(write!(f, ", ")); }
let vec: Vec<_> = map.drain().collect();
- assert_eq!(vec, vec![(1, "a"), (2, "b"), (3, "c")]);
+ assert_eq!(vec, [(1, "a"), (2, "b"), (3, "c")]);
assert_eq!(map.len(), 0);
}
map.insert(3, 4);
let map_str = format!("{:?}", map);
- assert!(map_str == "VecMap {1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}");
- assert_eq!(format!("{:?}", empty), "VecMap {}");
+ assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}");
+ assert_eq!(format!("{:?}", empty), "{}");
}
#[test]
/// }
/// }
/// ```
- #[unstable(feature = "core")]
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: usize);
/// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
/// }
/// ```
///
- #[unstable(feature = "core")]
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn copy_memory<T>(dst: *mut T, src: *const T, count: usize);
/// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
/// bytes of memory starting at `dst` to `c`.
- #[unstable(feature = "core",
- reason = "uncertain about naming and semantics")]
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn set_memory<T>(dst: *mut T, val: u8, count: usize);
/// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with
/// ```
/// let vec = vec![1, 2, 3, 4];
/// let (even, odd): (Vec<_>, Vec<_>) = vec.into_iter().partition(|&n| n % 2 == 0);
- /// assert_eq!(even, vec![2, 4]);
- /// assert_eq!(odd, vec![1, 3]);
+ /// assert_eq!(even, [2, 4]);
+ /// assert_eq!(odd, [1, 3]);
/// ```
#[unstable(feature = "core",
reason = "recently added as part of collections reform")]
#[unstable(feature = "core", reason = "recent addition")]
fn cloned(self) -> Cloned<Self> where
Self::Item: Deref,
- <Self::Item as Deref>::Output: Clone,
+ <Self::Item as Deref>::Target: Clone,
{
Cloned { it: self }
}
let mut t: T = uninitialized();
// Perform the swap, `&mut` pointers never alias
- ptr::copy_nonoverlapping_memory(&mut t, &*x, 1);
- ptr::copy_nonoverlapping_memory(x, &*y, 1);
- ptr::copy_nonoverlapping_memory(y, &t, 1);
+ ptr::copy_nonoverlapping(&mut t, &*x, 1);
+ ptr::copy_nonoverlapping(x, &*y, 1);
+ ptr::copy_nonoverlapping(y, &t, 1);
// y and t now point to the same thing, but we need to completely forget `t`
// because it's no longer relevant.
let is_signed_ty = (0 as $T) > Int::min_value();
match src.slice_shift_char() {
+ Some(('-', "")) => Err(PIE { kind: Empty }),
Some(('-', src)) if is_signed_ty => {
// The number is negative
let mut result = 0;
/// ```
/// let x = Some("string");
/// let v: Vec<&str> = x.into_iter().collect();
- /// assert_eq!(v, vec!["string"]);
+ /// assert_eq!(v, ["string"]);
///
/// let x = None;
/// let v: Vec<&str> = x.into_iter().collect();
// FIXME #19649: intrinsic docs don't render, so these have no docs :(
-#[unstable(feature = "core")]
-pub use intrinsics::copy_nonoverlapping_memory;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use intrinsics::copy_nonoverlapping_memory as copy_nonoverlapping;
-#[unstable(feature = "core")]
-pub use intrinsics::copy_memory;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use intrinsics::copy_memory as copy;
-#[unstable(feature = "core",
- reason = "uncertain about naming and semantics")]
-pub use intrinsics::set_memory;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use intrinsics::set_memory as write_bytes;
+extern "rust-intrinsic" {
+ #[unstable(feature = "core")]
+ #[deprecated(since = "1.0.0", reason = "renamed to `copy_nonoverlapping`")]
+ pub fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: usize);
+ #[unstable(feature = "core")]
+ #[deprecated(since = "1.0.0", reason = "renamed to `copy`")]
+ pub fn copy_memory<T>(dst: *mut T, src: *const T, count: usize);
+
+ #[unstable(feature = "core",
+ reason = "uncertain about naming and semantics")]
+ #[deprecated(since = "1.0.0", reason = "renamed to `write_bytes`")]
+ pub fn set_memory<T>(dst: *mut T, val: u8, count: usize);
+}
/// Creates a null raw pointer.
///
#[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) {
- set_memory(dst, 0, count);
+ write_bytes(dst, 0, count);
}
/// Swaps the values at two mutable locations of the same type, without
let t: *mut T = &mut tmp;
// Perform the swap
- copy_nonoverlapping_memory(t, &*x, 1);
- copy_memory(x, &*y, 1); // `x` and `y` may overlap
- copy_nonoverlapping_memory(y, &*t, 1);
+ copy_nonoverlapping(t, &*x, 1);
+ copy(x, &*y, 1); // `x` and `y` may overlap
+ copy_nonoverlapping(y, &*t, 1);
// y and t now point to the same thing, but we need to completely forget `tmp`
// because it's no longer relevant.
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn read<T>(src: *const T) -> T {
let mut tmp: T = mem::uninitialized();
- copy_nonoverlapping_memory(&mut tmp, src, 1);
+ copy_nonoverlapping(&mut tmp, src, 1);
tmp
}
let tmp = read(&*dest);
// Now zero out `dest`:
- zero_memory(dest, 1);
+ write_bytes(dest, 0, 1);
tmp
}
/// Methods on raw pointers
#[stable(feature = "rust1", since = "1.0.0")]
-pub trait PtrExt: Sized {
+pub trait PtrExt {
/// The type which is being pointed at
- type Target;
+ type Target: ?Sized;
/// Returns true if the pointer is null.
#[stable(feature = "rust1", since = "1.0.0")]
/// Otherwise `offset` invokes Undefined Behaviour, regardless of whether
/// the pointer is used.
#[stable(feature = "rust1", since = "1.0.0")]
- unsafe fn offset(self, count: isize) -> Self;
+ unsafe fn offset(self, count: isize) -> Self where Self::Target: Sized;
}
/// Methods on mutable raw pointers
#[stable(feature = "rust1", since = "1.0.0")]
pub trait MutPtrExt {
/// The type which is being pointed at
- type Target;
+ type Target: ?Sized;
/// Returns `None` if the pointer is null, or else returns a mutable
/// reference to the value wrapped in `Some`.
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> PtrExt for *const T {
+impl<T: ?Sized> PtrExt for *const T {
type Target = T;
#[inline]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- unsafe fn offset(self, count: isize) -> *const T {
+ unsafe fn offset(self, count: isize) -> *const T where T: Sized {
intrinsics::offset(self, count)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> PtrExt for *mut T {
+impl<T: ?Sized> PtrExt for *mut T {
type Target = T;
#[inline]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- unsafe fn offset(self, count: isize) -> *mut T {
+ unsafe fn offset(self, count: isize) -> *mut T where T: Sized {
intrinsics::offset(self, count) as *mut T
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> MutPtrExt for *mut T {
+impl<T: ?Sized> MutPtrExt for *mut T {
type Target = T;
#[inline]
// Equality for pointers
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> PartialEq for *const T {
+impl<T: ?Sized> PartialEq for *const T {
#[inline]
- fn eq(&self, other: &*const T) -> bool {
- *self == *other
- }
- #[inline]
- fn ne(&self, other: &*const T) -> bool { !self.eq(other) }
+ fn eq(&self, other: &*const T) -> bool { *self == *other }
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Eq for *const T {}
+impl<T: ?Sized> Eq for *const T {}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> PartialEq for *mut T {
- #[inline]
- fn eq(&self, other: &*mut T) -> bool {
- *self == *other
- }
+impl<T: ?Sized> PartialEq for *mut T {
#[inline]
- fn ne(&self, other: &*mut T) -> bool { !self.eq(other) }
+ fn eq(&self, other: &*mut T) -> bool { *self == *other }
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Eq for *mut T {}
+impl<T: ?Sized> Eq for *mut T {}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Clone for *const T {
+impl<T: ?Sized> Clone for *const T {
#[inline]
fn clone(&self) -> *const T {
*self
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Clone for *mut T {
+impl<T: ?Sized> Clone for *mut T {
#[inline]
fn clone(&self) -> *mut T {
*self
// Comparison for pointers
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Ord for *const T {
+impl<T: ?Sized> Ord for *const T {
#[inline]
fn cmp(&self, other: &*const T) -> Ordering {
if self < other {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> PartialOrd for *const T {
+impl<T: ?Sized> PartialOrd for *const T {
#[inline]
fn partial_cmp(&self, other: &*const T) -> Option<Ordering> {
Some(self.cmp(other))
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Ord for *mut T {
+impl<T: ?Sized> Ord for *mut T {
#[inline]
fn cmp(&self, other: &*mut T) -> Ordering {
if self < other {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> PartialOrd for *mut T {
+impl<T: ?Sized> PartialOrd for *mut T {
#[inline]
fn partial_cmp(&self, other: &*mut T) -> Option<Ordering> {
Some(self.cmp(other))
/// modified without a unique path to the `Unique` reference. Useful
/// for building abstractions like `Vec<T>` or `Box<T>`, which
/// internally use raw pointers to manage the memory that they own.
-#[unstable(feature = "core", reason = "recently added to this module")]
-pub struct Unique<T:?Sized> {
+#[unstable(feature = "unique")]
+pub struct Unique<T: ?Sized> {
pointer: NonZero<*const T>,
_marker: PhantomData<T>,
}
/// reference is unaliased. Note that this aliasing invariant is
/// unenforced by the type system; the abstraction using the
/// `Unique` must enforce it.
-#[unstable(feature = "core", reason = "recently added to this module")]
+#[unstable(feature = "unique")]
unsafe impl<T: Send + ?Sized> Send for Unique<T> { }
/// `Unique` pointers are `Sync` if `T` is `Sync` because the data they
/// reference is unaliased. Note that this aliasing invariant is
/// unenforced by the type system; the abstraction using the
/// `Unique` must enforce it.
-#[unstable(feature = "core", reason = "recently added to this module")]
+#[unstable(feature = "unique")]
unsafe impl<T: Sync + ?Sized> Sync for Unique<T> { }
-impl<T:?Sized> Unique<T> {
+impl<T: ?Sized> Unique<T> {
/// Create a new `Unique`.
- #[unstable(feature = "core",
- reason = "recently added to this module")]
+ #[unstable(feature = "unique")]
pub unsafe fn new(ptr: *mut T) -> Unique<T> {
Unique { pointer: NonZero::new(ptr as *const T), _marker: PhantomData }
}
/// Dereference the content.
- #[unstable(feature = "core",
- reason = "recently added to this module")]
+ #[unstable(feature = "unique")]
pub unsafe fn get(&self) -> &T {
&**self.pointer
}
/// Mutably dereference the content.
- #[unstable(feature = "core",
- reason = "recently added to this module")]
+ #[unstable(feature = "unique")]
pub unsafe fn get_mut(&mut self) -> &mut T {
&mut ***self
}
}
+#[unstable(feature = "unique")]
impl<T:?Sized> Deref for Unique<T> {
type Target = *mut T;
/// ```
/// let x: Result<u32, &str> = Ok(5);
/// let v: Vec<u32> = x.into_iter().collect();
- /// assert_eq!(v, vec![5]);
+ /// assert_eq!(v, [5]);
///
/// let x: Result<u32, &str> = Err("nothing!");
/// let v: Vec<u32> = x.into_iter().collect();
- /// assert_eq!(v, vec![]);
+ /// assert_eq!(v, []);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
impl MutableByteVector for [u8] {
#[inline]
fn set_memory(&mut self, value: u8) {
- unsafe { ptr::set_memory(self.as_mut_ptr(), value, self.len()) };
+ unsafe { ptr::write_bytes(self.as_mut_ptr(), value, self.len()) };
}
}
// `dst` is unaliasable, so we know statically it doesn't overlap
// with `src`.
unsafe {
- ptr::copy_nonoverlapping_memory(dst.as_mut_ptr(),
- src.as_ptr(),
- len_src);
+ ptr::copy_nonoverlapping(dst.as_mut_ptr(),
+ src.as_ptr(),
+ len_src);
}
}
}
fn test_counter_from_iter() {
let it = count(0, 5).take(10);
let xs: Vec<int> = FromIterator::from_iter(it);
- assert!(xs == vec![0, 5, 10, 15, 20, 25, 30, 35, 40, 45]);
+ assert_eq!(xs, [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]);
}
#[test]
fn test_filter_map() {
let it = count(0, 1).take(10)
.filter_map(|x| if x % 2 == 0 { Some(x*x) } else { None });
- assert!(it.collect::<Vec<uint>>() == vec![0*0, 2*2, 4*4, 6*6, 8*8]);
+ assert_eq!(it.collect::<Vec<uint>>(), [0*0, 2*2, 4*4, 6*6, 8*8]);
}
#[test]
#[test]
fn test_double_ended_range() {
- assert!((11..14).rev().collect::<Vec<_>>() == vec![13, 12, 11]);
+ assert_eq!((11..14).rev().collect::<Vec<_>>(), [13, 12, 11]);
for _ in (10..0).rev() {
panic!("unreachable");
}
- assert!((11..14).rev().collect::<Vec<_>>() == vec![13, 12, 11]);
+ assert_eq!((11..14).rev().collect::<Vec<_>>(), [13, 12, 11]);
for _ in (10..0).rev() {
panic!("unreachable");
}
#[test]
fn test_range() {
- assert!((0..5).collect::<Vec<_>>() == vec![0, 1, 2, 3, 4]);
- assert!((-10..-1).collect::<Vec<_>>() ==
- vec![-10, -9, -8, -7, -6, -5, -4, -3, -2]);
- assert!((0..5).rev().collect::<Vec<_>>() == vec![4, 3, 2, 1, 0]);
+ assert_eq!((0..5).collect::<Vec<_>>(), [0, 1, 2, 3, 4]);
+ assert_eq!((-10..-1).collect::<Vec<_>>(), [-10, -9, -8, -7, -6, -5, -4, -3, -2]);
+ assert_eq!((0..5).rev().collect::<Vec<_>>(), [4, 3, 2, 1, 0]);
assert_eq!((200..-5).count(), 0);
assert_eq!((200..-5).rev().count(), 0);
assert_eq!((200..200).count(), 0);
vec![5, 4, 3, 2, 1, 0]);
assert_eq!(range_inclusive(200, -5).count(), 0);
assert_eq!(range_inclusive(200, -5).rev().count(), 0);
- assert!(range_inclusive(200, 200).collect::<Vec<int>>() == vec![200]);
- assert!(range_inclusive(200, 200).rev().collect::<Vec<int>>() == vec![200]);
+ assert_eq!(range_inclusive(200, 200).collect::<Vec<int>>(), [200]);
+ assert_eq!(range_inclusive(200, 200).rev().collect::<Vec<int>>(), [200]);
}
#[test]
fn test_range_step() {
- assert!(range_step(0, 20, 5).collect::<Vec<int>>() ==
- vec![0, 5, 10, 15]);
- assert!(range_step(20, 0, -5).collect::<Vec<int>>() ==
- vec![20, 15, 10, 5]);
- assert!(range_step(20, 0, -6).collect::<Vec<int>>() ==
- vec![20, 14, 8, 2]);
- assert!(range_step(200u8, 255, 50).collect::<Vec<u8>>() ==
- vec![200u8, 250]);
- assert!(range_step(200, -5, 1).collect::<Vec<int>>() == vec![]);
- assert!(range_step(200, 200, 1).collect::<Vec<int>>() == vec![]);
+ assert_eq!(range_step(0, 20, 5).collect::<Vec<int>>(), [0, 5, 10, 15]);
+ assert_eq!(range_step(20, 0, -5).collect::<Vec<int>>(), [20, 15, 10, 5]);
+ assert_eq!(range_step(20, 0, -6).collect::<Vec<int>>(), [20, 14, 8, 2]);
+ assert_eq!(range_step(200u8, 255, 50).collect::<Vec<u8>>(), [200u8, 250]);
+ assert_eq!(range_step(200i, -5, 1).collect::<Vec<int>>(), []);
+ assert_eq!(range_step(200i, 200, 1).collect::<Vec<int>>(), []);
}
#[test]
fn test_range_step_inclusive() {
- assert!(range_step_inclusive(0, 20, 5).collect::<Vec<int>>() ==
- vec![0, 5, 10, 15, 20]);
- assert!(range_step_inclusive(20, 0, -5).collect::<Vec<int>>() ==
- vec![20, 15, 10, 5, 0]);
- assert!(range_step_inclusive(20, 0, -6).collect::<Vec<int>>() ==
- vec![20, 14, 8, 2]);
- assert!(range_step_inclusive(200u8, 255, 50).collect::<Vec<u8>>() ==
- vec![200u8, 250]);
- assert!(range_step_inclusive(200, -5, 1).collect::<Vec<int>>() ==
- vec![]);
- assert!(range_step_inclusive(200, 200, 1).collect::<Vec<int>>() ==
- vec![200]);
+ assert_eq!(range_step_inclusive(0, 20, 5).collect::<Vec<int>>(), [0, 5, 10, 15, 20]);
+ assert_eq!(range_step_inclusive(20, 0, -5).collect::<Vec<int>>(), [20, 15, 10, 5, 0]);
+ assert_eq!(range_step_inclusive(20, 0, -6).collect::<Vec<int>>(), [20, 14, 8, 2]);
+ assert_eq!(range_step_inclusive(200u8, 255, 50).collect::<Vec<u8>>(), [200u8, 250]);
+ assert_eq!(range_step_inclusive(200, -5, 1).collect::<Vec<int>>(), []);
+ assert_eq!(range_step_inclusive(200, 200, 1).collect::<Vec<int>>(), [200]);
}
#[test]
}
unsafe {
- assert!(vec![76u8] == transmute::<_, Vec<u8>>("L".to_string()));
+ assert_eq!([76u8], transmute::<_, Vec<u8>>("L".to_string()));
}
}
fn test_match_option_vec() {
let a = Some(vec![1, 2, 3, 4]);
match a {
- Some(v) => assert_eq!(v, vec![1, 2, 3, 4]),
+ Some(v) => assert_eq!(v, [1, 2, 3, 4]),
None => panic!("unexpected None while matching on Some(vec![1, 2, 3, 4])")
}
}
assert_eq!("-9223372036854775808".parse::<i64>().ok(), Some(i64_val));
assert_eq!("-9223372036854775809".parse::<i64>().ok(), None);
}
+
+ #[test]
+ fn test_int_from_minus_sign() {
+ assert_eq!("-".parse::<i32>().ok(), None);
+ }
}
m_ptr = m_ptr.offset(-1);
}
- assert!(xs_mut == vec![0,2,4,6,8,10,12,14,16,18]);
+ assert_eq!(xs_mut, [0,2,4,6,8,10,12,14,16,18]);
}
}
fn test_empty_match_indices() {
let data = "aä中!";
let vec: Vec<_> = data.match_indices("").collect();
- assert_eq!(vec, vec![(0, 0), (1, 1), (3, 3), (6, 6), (7, 7)]);
+ assert_eq!(vec, [(0, 0), (1, 1), (3, 3), (6, 6), (7, 7)]);
}
#[test]
let mut split: Vec<&str> = data.rsplitn(3, ' ').collect();
split.reverse();
- assert_eq!(split, vec!["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
+ assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
let mut split: Vec<&str> = data.rsplitn(3, |c: char| c == ' ').collect();
split.reverse();
- assert_eq!(split, vec!["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
+ assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
// Unicode
let mut split: Vec<&str> = data.rsplitn(3, 'ä').collect();
split.reverse();
- assert_eq!(split, vec!["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
+ assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
let mut split: Vec<&str> = data.rsplitn(3, |c: char| c == 'ä').collect();
split.reverse();
- assert_eq!(split, vec!["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
+ assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
}
#[test]
let data = "\nMäry häd ä little lämb\nLittle lämb\n";
let split: Vec<&str> = data.split(' ').collect();
- assert_eq!( split, vec!["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
+ assert_eq!( split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
let mut rsplit: Vec<&str> = data.split(' ').rev().collect();
rsplit.reverse();
- assert_eq!(rsplit, vec!["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
+ assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
let split: Vec<&str> = data.split(|c: char| c == ' ').collect();
- assert_eq!( split, vec!["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
+ assert_eq!( split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
let mut rsplit: Vec<&str> = data.split(|c: char| c == ' ').rev().collect();
rsplit.reverse();
- assert_eq!(rsplit, vec!["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
+ assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
// Unicode
let split: Vec<&str> = data.split('ä').collect();
- assert_eq!( split, vec!["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
+ assert_eq!( split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
let mut rsplit: Vec<&str> = data.split('ä').rev().collect();
rsplit.reverse();
- assert_eq!(rsplit, vec!["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
+ assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
let split: Vec<&str> = data.split(|c: char| c == 'ä').collect();
- assert_eq!( split, vec!["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
+ assert_eq!( split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
let mut rsplit: Vec<&str> = data.split(|c: char| c == 'ä').rev().collect();
rsplit.reverse();
- assert_eq!(rsplit, vec!["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
+ assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
}
#[test]
let mut split: Vec<&str> = data.split('\n').rev().collect();
split.reverse();
- assert_eq!(split, vec!["", "Märy häd ä little lämb", "Little lämb", ""]);
+ assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb", ""]);
let mut split: Vec<&str> = data.split_terminator('\n').rev().collect();
split.reverse();
- assert_eq!(split, vec!["", "Märy häd ä little lämb", "Little lämb"]);
+ assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]);
}
#[test]
fn test_utf16_code_units() {
use unicode::str::Utf16Encoder;
assert_eq!(Utf16Encoder::new(vec!['é', '\u{1F4A9}'].into_iter()).collect::<Vec<u16>>(),
- vec![0xE9, 0xD83D, 0xDCA9])
+ [0xE9, 0xD83D, 0xDCA9])
}
#[test]
#![feature(int_uint)]
#![feature(libc)]
#![feature(staged_api)]
+#![feature(unique)]
#[cfg(test)] #[macro_use] extern crate log;
use types::os::arch::c95::{c_long};
pub type off_t = i64;
pub type dev_t = i32;
- pub type ino_t = u64;
pub type pid_t = i32;
pub type uid_t = u32;
pub type gid_t = u32;
/// let mut w = SeekableMemWriter::new();
/// w.write(&[0, 1, 2]);
///
-/// assert_eq!(w.unwrap(), vec!(0, 1, 2));
+/// assert_eq!(w.unwrap(), [0, 1, 2]);
/// ```
pub struct SeekableMemWriter {
buf: Vec<u8>,
#![feature(staged_api)]
#![feature(std_misc)]
#![feature(unicode)]
+#![feature(os)]
#![cfg_attr(test, feature(test))]
extern crate arena;
}
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
- fn check_def(&mut self, sp: Span, ty_id: ast::NodeId, path_id: ast::NodeId) {
- match self.cx.tcx.def_map.borrow()[path_id].clone() {
+ fn check_def(&mut self, sp: Span, id: ast::NodeId) {
+ match self.cx.tcx.def_map.borrow()[id].full_def() {
def::DefPrimTy(ast::TyInt(ast::TyIs(_))) => {
self.cx.span_lint(IMPROPER_CTYPES, sp,
"found rust type `isize` in foreign module, while \
libc::c_uint or libc::c_ulong should be used");
}
def::DefTy(..) => {
- let tty = match self.cx.tcx.ast_ty_to_ty_cache.borrow().get(&ty_id) {
+ let tty = match self.cx.tcx.ast_ty_to_ty_cache.borrow().get(&id) {
Some(&ty::atttce_resolved(t)) => t,
_ => panic!("ast_ty_to_ty_cache was incomplete after typeck!")
};
impl<'a, 'tcx, 'v> Visitor<'v> for ImproperCTypesVisitor<'a, 'tcx> {
fn visit_ty(&mut self, ty: &ast::Ty) {
- match ty.node {
- ast::TyPath(_, id) => self.check_def(ty.span, ty.id, id),
- _ => (),
+ if let ast::TyPath(..) = ty.node {
+ self.check_def(ty.span, ty.id);
}
visit::walk_ty(self, ty);
}
match s.node {
ast::StmtSemi(ref expr, _) => {
match expr.node {
- ast::ExprPath(_) => cx.span_lint(PATH_STATEMENTS, s.span,
- "path statement with no effect"),
+ ast::ExprPath(..) => cx.span_lint(PATH_STATEMENTS, s.span,
+ "path statement with no effect"),
_ => ()
}
}
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
if let &ast::PatIdent(_, ref path1, _) = &p.node {
- if let Some(&def::DefLocal(_)) = cx.tcx.def_map.borrow().get(&p.id) {
+ let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def());
+ if let Some(def::DefLocal(_)) = def {
self.check_snake_case(cx, "variable", path1.node, p.span);
}
}
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
// Lint for constants that look like binding identifiers (#7526)
- match (&p.node, cx.tcx.def_map.borrow().get(&p.id)) {
- (&ast::PatIdent(_, ref path1, _), Some(&def::DefConst(..))) => {
+ match (&p.node, cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def())) {
+ (&ast::PatIdent(_, ref path1, _), Some(def::DefConst(..))) => {
NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern",
path1.node, p.span);
}
fn check_pat(&mut self, cx: &Context, pat: &ast::Pat) {
let def_map = cx.tcx.def_map.borrow();
if let ast::PatStruct(_, ref v, _) = pat.node {
- for fieldpat in v.iter()
- .filter(|fieldpat| !fieldpat.node.is_shorthand)
- .filter(|fieldpat| def_map.get(&fieldpat.node.pat.id)
- == Some(&def::DefLocal(fieldpat.node.pat.id))) {
+ let field_pats = v.iter()
+ .filter(|fieldpat| !fieldpat.node.is_shorthand)
+ .filter(|fieldpat| {
+ let def = def_map.get(&fieldpat.node.pat.id).map(|d| d.full_def());
+ def == Some(def::DefLocal(fieldpat.node.pat.id))
+ });
+ for fieldpat in field_pats {
if let ast::PatIdent(_, ident, None) = fieldpat.node.pat.node {
if ident.node.as_str() == fieldpat.node.ident.as_str() {
cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span,
}
fn check_item(&mut self, cx: &Context, it: &ast::Item) {
- use syntax::ast::Unsafety::Unsafe;
-
- fn check_method(cx: &Context, meth: &P<ast::Method>) {
- if let ast::Method_::MethDecl(_, _, _, _, Unsafe, _, _, _) = meth.node {
- cx.span_lint(UNSAFE_CODE, meth.span, "implementation of an `unsafe` method");
- }
- }
-
match it.node {
- ast::ItemFn(_, Unsafe, _, _, _) =>
- cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` function"),
+ ast::ItemTrait(ast::Unsafety::Unsafe, _, _, _) =>
+ cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait"),
- ast::ItemTrait(trait_safety, _, _, ref items) => {
- if trait_safety == Unsafe {
- cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait");
- }
+ ast::ItemImpl(ast::Unsafety::Unsafe, _, _, _, _, _) =>
+ cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait"),
- for it in items {
- match *it {
- ast::RequiredMethod(ast::TypeMethod { unsafety: Unsafe, span, ..}) =>
- cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` method"),
- ast::ProvidedMethod(ref meth) => check_method(cx, meth),
- _ => (),
- }
- }
- },
+ _ => return,
+ }
+ }
- ast::ItemImpl(impl_safety, _, _, _, _, ref impls) => {
- if impl_safety == Unsafe {
- cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait");
- }
+ fn check_fn(&mut self, cx: &Context, fk: visit::FnKind, _: &ast::FnDecl,
+ _: &ast::Block, span: Span, _: ast::NodeId) {
+ match fk {
+ visit::FkItemFn(_, _, ast::Unsafety::Unsafe, _) =>
+ cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function"),
- for item in impls {
- if let ast::ImplItem::MethodImplItem(ref meth) = *item {
- check_method(cx, meth);
- }
+ visit::FkMethod(_, _, m) => {
+ if let ast::Method_::MethDecl(_, _, _, _, ast::Unsafety::Unsafe, _, _, _) = m.node {
+ cx.span_lint(UNSAFE_CODE, m.span, "implementation of an `unsafe` method")
}
},
- _ => return,
+ _ => (),
+ }
+ }
+
+ fn check_ty_method(&mut self, cx: &Context, ty_method: &ast::TypeMethod) {
+ if let ast::TypeMethod { unsafety: ast::Unsafety::Unsafe, span, ..} = *ty_method {
+ cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` method")
}
}
}
_: ast::Ident,
id: ast::NodeId) -> bool {
tcx.def_map.borrow().get(&id)
- .map_or(false, |def| {
- let did = def.def_id();
- ast_util::is_local(did) && did.node == fn_id
- })
+ .map_or(false, |def| def.def_id() == ast_util::local_def(fn_id))
}
// check if the method call `id` refers to method `method_id`
def.node)
}
-pub fn get_trait_item_name_and_kind(cstore: &cstore::CStore, def: ast::DefId)
- -> (ast::Name, def::TraitItemKind) {
+pub fn is_static_method(cstore: &cstore::CStore, def: ast::DefId) -> bool {
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_trait_item_name_and_kind(cstore.intr.clone(),
- &*cdata,
- def.node)
+ decoder::is_static_method(&*cdata, def.node)
}
pub fn get_trait_item_def_ids(cstore: &cstore::CStore, def: ast::DefId)
StaticMethod, // F
Method, // h
Type, // y
- ForeignType, // T
Mod, // m
ForeignMod, // n
Enum, // t
'F' => StaticMethod,
'h' => Method,
'y' => Type,
- 'T' => ForeignType,
'm' => Mod,
'n' => ForeignMod,
't' => Enum,
}
}
-fn item_sort(item: rbml::Doc) -> char {
+fn item_sort(item: rbml::Doc) -> Option<char> {
let mut ret = None;
reader::tagged_docs(item, tag_item_trait_item_sort, |doc| {
ret = Some(doc.as_str_slice().as_bytes()[0] as char);
false
});
- match ret {
- Some(r) => r,
- None => panic!("No item_sort found")
- }
+ ret
}
fn item_symbol(item: rbml::Doc) -> String {
def::FromImpl(item_reqd_and_translated_parent_item(cnum,
item))
};
- match fam {
- // We don't bother to get encode/decode the trait id, we don't need it.
- Method => DlDef(def::DefMethod(did, None, provenance)),
- StaticMethod => DlDef(def::DefStaticMethod(did, provenance)),
- _ => panic!()
+ DlDef(def::DefMethod(did, provenance))
+ }
+ Type => {
+ if item_sort(item) == Some('t') {
+ let trait_did = item_reqd_and_translated_parent_item(cnum, item);
+ DlDef(def::DefAssociatedTy(trait_did, did))
+ } else {
+ DlDef(def::DefTy(did, false))
}
}
- Type | ForeignType => DlDef(def::DefTy(did, false)),
Mod => DlDef(def::DefMod(did)),
ForeignMod => DlDef(def::DefForeignMod(did)),
StructVariant => {
let enum_did = item_reqd_and_translated_parent_item(cnum, item);
DlDef(def::DefVariant(enum_did, did, false))
}
- Trait => DlDef(def::DefaultImpl(did)),
+ Trait => DlDef(def::DefTrait(did)),
Enum => DlDef(def::DefTy(did, true)),
Impl | DefaultImpl => DlImpl(did),
PublicField | InheritedField => DlField,
tag_item_impl_item, |doc| {
let def_id = item_def_id(doc, cdata);
match item_sort(doc) {
- 'r' | 'p' => impl_items.push(ty::MethodTraitItemId(def_id)),
- 't' => impl_items.push(ty::TypeTraitItemId(def_id)),
+ Some('r') | Some('p') => {
+ impl_items.push(ty::MethodTraitItemId(def_id))
+ }
+ Some('t') => impl_items.push(ty::TypeTraitItemId(def_id)),
_ => panic!("unknown impl item sort"),
}
true
item_name(&*intr, doc)
}
-pub fn get_trait_item_name_and_kind(intr: Rc<IdentInterner>,
- cdata: Cmd,
- id: ast::NodeId)
- -> (ast::Name, def::TraitItemKind) {
+pub fn is_static_method(cdata: Cmd, id: ast::NodeId) -> bool {
let doc = lookup_item(id, cdata.data());
- let name = item_name(&*intr, doc);
match item_sort(doc) {
- 'r' | 'p' => {
- let explicit_self = get_explicit_self(doc);
- (name, def::TraitItemKind::from_explicit_self_category(explicit_self))
- }
- 't' => (name, def::TypeTraitItemKind),
- c => {
- panic!("get_trait_item_name_and_kind(): unknown trait item kind \
- in metadata: `{}`", c)
+ Some('r') | Some('p') => {
+ get_explicit_self(doc) == ty::StaticExplicitSelfCategory
}
+ _ => false
}
}
let vis = item_visibility(method_doc);
match item_sort(method_doc) {
- 'r' | 'p' => {
+ Some('r') | Some('p') => {
let generics = doc_generics(method_doc, tcx, cdata, tag_method_ty_generics);
let predicates = doc_predicates(method_doc, tcx, cdata, tag_method_ty_generics);
let fty = doc_method_fty(method_doc, tcx, cdata);
container,
provided_source)))
}
- 't' => {
+ Some('t') => {
ty::TypeTraitItem(Rc::new(ty::AssociatedType {
name: name,
vis: vis,
reader::tagged_docs(item, tag_item_trait_item, |mth| {
let def_id = item_def_id(mth, cdata);
match item_sort(mth) {
- 'r' | 'p' => result.push(ty::MethodTraitItemId(def_id)),
- 't' => result.push(ty::TypeTraitItemId(def_id)),
+ Some('r') | Some('p') => {
+ result.push(ty::MethodTraitItemId(def_id));
+ }
+ Some('t') => result.push(ty::TypeTraitItemId(def_id)),
_ => panic!("unknown trait item sort"),
}
true
let did = item_def_id(mth_id, cdata);
let mth = lookup_item(did.node, data);
- if item_sort(mth) == 'p' {
+ if item_sort(mth) == Some('p') {
let trait_item = get_impl_or_trait_item(intr.clone(),
cdata,
did.node,
let items = reader::get_doc(rbml::Doc::new(cdata.data()), tag_items);
match maybe_find_item(id, items) {
None => false,
- Some(item) => item_sort(item) == 't',
+ Some(item) => item_sort(item) == Some('t'),
}
}
None => {}
}
}
- ast::ItemDefaultImpl(unsafety, ref ast_trait_ref) => {
+ ast::ItemDefaultImpl(unsafety, _) => {
add_to_index(item, rbml_w, index);
rbml_w.start_tag(tag_items_data_item);
encode_def_id(rbml_w, def_id);
encode_name(rbml_w, item.ident.name);
encode_unsafety(rbml_w, unsafety);
- let trait_ref = ty::node_id_to_trait_ref(tcx, ast_trait_ref.ref_id);
+ let trait_ref = ty::impl_id_to_trait_ref(tcx, item.id);
encode_trait_ref(rbml_w, ecx, &*trait_ref, tag_item_trait_ref);
rbml_w.end_tag();
}
encode_unsafety(rbml_w, unsafety);
encode_polarity(rbml_w, polarity);
match ty.node {
- ast::TyPath(ref path, _) if path.segments.len() == 1 => {
+ ast::TyPath(None, ref path) if path.segments.len() == 1 => {
let ident = path.segments.last().unwrap().identifier;
encode_impl_type_basename(rbml_w, ident);
}
}
rbml_w.end_tag();
}
- if let Some(ref ast_trait_ref) = *opt_trait {
- let trait_ref = ty::node_id_to_trait_ref(
- tcx, ast_trait_ref.ref_id);
+ if opt_trait.is_some() {
+ let trait_ref = ty::impl_id_to_trait_ref(tcx, item.id);
encode_trait_ref(rbml_w, ecx, &*trait_ref, tag_item_trait_ref);
}
encode_path(rbml_w, path.clone());
impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'b, 'c, 'tcx> {
fn visit_item(&mut self, item: &ast::Item) {
if let ast::ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node {
- let def_map = &self.ecx.tcx.def_map;
- let trait_def = def_map.borrow()[trait_ref.ref_id].clone();
- let def_id = trait_def.def_id();
+ let def_id = self.ecx.tcx.def_map.borrow()[trait_ref.ref_id].def_id();
// Load eagerly if this is an implementation of the Drop trait
// or if the trait is not defined in this crate.
use std::collections::HashSet;
use std::env;
+use std::os;
use std::old_io::fs::PathExtensions;
use std::old_io::fs;
})
}
- match canonicalize(env::current_exe().ok()) {
+ match canonicalize(os::self_exe_name()) {
Some(mut p) => { p.pop(); p.pop(); p }
None => panic!("can't determine value for sysroot")
}
}
None => Vec::new()
};
- let mut cwd = env::current_dir().unwrap();
+ let mut cwd = os::getcwd().unwrap();
// now add in default entries
let cwd_dot_rust = cwd.join(".rust");
if !env_rust_path.contains(&cwd_dot_rust) {
}
cwd.pop();
}
- if let Some(h) = env::home_dir() {
+ if let Some(h) = os::homedir() {
let p = h.join(".rust");
if !env_rust_path.contains(&p) && p.exists() {
env_rust_path.push(p);
}
};
return match ArchiveMetadata::new(archive).map(|ar| MetadataArchive(ar)) {
- None => {
- return Err((format!("failed to read rlib metadata: '{}'",
- filename.display())))
- }
- Some(blob) => return Ok(blob)
- }
+ None => Err(format!("failed to read rlib metadata: '{}'",
+ filename.display())),
+ Some(blob) => Ok(blob)
+ };
}
unsafe {
let buf = CString::new(filename.as_vec()).unwrap();
}
llvm::LLVMMoveToNextSection(si.llsi);
}
- return Err(format!("metadata not found: '{}'", filename.display()));
+ Err(format!("metadata not found: '{}'", filename.display()))
}
}
assert_eq!(next(st), '|');
let index = parse_u32(st);
assert_eq!(next(st), '|');
- let bounds = parse_bounds_(st, conv);
let default = parse_opt(st, |st| parse_ty_(st, conv));
let object_lifetime_default = parse_object_lifetime_default(st, conv);
def_id: def_id,
space: space,
index: index,
- bounds: bounds,
default: default,
object_lifetime_default: object_lifetime_default,
}
{
let builtin_bounds = parse_builtin_bounds_(st, conv);
+ let region_bounds = parse_region_bounds_(st, conv);
+
let mut param_bounds = ty::ParamBounds {
- region_bounds: Vec::new(),
+ region_bounds: region_bounds,
builtin_bounds: builtin_bounds,
trait_bounds: Vec::new(),
projection_bounds: Vec::new(),
};
+
+
loop {
match next(st) {
- 'R' => {
- param_bounds.region_bounds.push(
- parse_region_(st, conv));
- }
'I' => {
param_bounds.trait_bounds.push(
ty::Binder(parse_trait_ref_(st, conv)));
}
}
}
+
+fn parse_region_bounds_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
+ -> Vec<ty::Region> where
+ F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
+ let mut region_bounds = Vec::new();
+ loop {
+ match next(st) {
+ 'R' => { region_bounds.push(parse_region_(st, conv)); }
+ '.' => { return region_bounds; }
+ c => { panic!("parse_bounds: bad bounds ('{}')", c); }
+ }
+ }
+}
+
bs: &ty::ParamBounds<'tcx>) {
enc_builtin_bounds(w, cx, &bs.builtin_bounds);
- for &r in &bs.region_bounds {
- mywrite!(w, "R");
- enc_region(w, cx, r);
- }
+ enc_region_bounds(w, cx, &bs.region_bounds);
for tp in &bs.trait_bounds {
mywrite!(w, "I");
mywrite!(w, ".");
}
+pub fn enc_region_bounds<'a, 'tcx>(w: &mut SeekableMemWriter,
+ cx: &ctxt<'a, 'tcx>,
+ rs: &[ty::Region]) {
+ for &r in rs {
+ mywrite!(w, "R");
+ enc_region(w, cx, r);
+ }
+
+ mywrite!(w, ".");
+}
+
pub fn enc_type_param_def<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
v: &ty::TypeParameterDef<'tcx>) {
mywrite!(w, "{}:{}|{}|{}|",
token::get_name(v.name), (cx.ds)(v.def_id),
v.space.to_uint(), v.index);
- enc_bounds(w, cx, &v.bounds);
enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
enc_object_lifetime_default(w, cx, v.object_lifetime_default);
}
pub const NO_REGIONS: uint = 1;
pub const NO_TPS: uint = 2;
-pub fn check_path_args(tcx: &ty::ctxt,
- path: &ast::Path,
- flags: uint) {
- if (flags & NO_TPS) != 0 {
- if path.segments.iter().any(|s| s.parameters.has_types()) {
- span_err!(tcx.sess, path.span, E0109,
- "type parameters are not allowed on this type");
+pub fn check_path_args(tcx: &ty::ctxt, segments: &[ast::PathSegment], flags: uint) {
+ for segment in segments {
+ if (flags & NO_TPS) != 0 {
+ for typ in segment.parameters.types() {
+ span_err!(tcx.sess, typ.span, E0109,
+ "type parameters are not allowed on this type");
+ break;
+ }
}
- }
- if (flags & NO_REGIONS) != 0 {
- if path.segments.iter().any(|s| s.parameters.has_lifetimes()) {
- span_err!(tcx.sess, path.span, E0110,
- "region parameters are not allowed on this type");
+ if (flags & NO_REGIONS) != 0 {
+ for lifetime in segment.parameters.lifetimes() {
+ span_err!(tcx.sess, lifetime.span, E0110,
+ "lifetime parameters are not allowed on this type");
+ break;
+ }
}
}
}
+pub fn prim_ty_to_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
+ segments: &[ast::PathSegment],
+ nty: ast::PrimTy)
+ -> Ty<'tcx> {
+ check_path_args(tcx, segments, NO_TPS | NO_REGIONS);
+ match nty {
+ ast::TyBool => tcx.types.bool,
+ ast::TyChar => tcx.types.char,
+ ast::TyInt(it) => ty::mk_mach_int(tcx, it),
+ ast::TyUint(uit) => ty::mk_mach_uint(tcx, uit),
+ ast::TyFloat(ft) => ty::mk_mach_float(tcx, ft),
+ ast::TyStr => ty::mk_str(tcx)
+ }
+}
+
pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty)
-> Option<Ty<'tcx>> {
- match ast_ty.node {
- ast::TyPath(ref path, id) => {
- let a_def = match tcx.def_map.borrow().get(&id) {
- None => {
- tcx.sess.span_bug(ast_ty.span,
- &format!("unbound path {}",
- path.repr(tcx)))
- }
- Some(&d) => d
- };
- match a_def {
- def::DefPrimTy(nty) => {
- match nty {
- ast::TyBool => {
- check_path_args(tcx, path, NO_TPS | NO_REGIONS);
- Some(tcx.types.bool)
- }
- ast::TyChar => {
- check_path_args(tcx, path, NO_TPS | NO_REGIONS);
- Some(tcx.types.char)
- }
- ast::TyInt(it) => {
- check_path_args(tcx, path, NO_TPS | NO_REGIONS);
- Some(ty::mk_mach_int(tcx, it))
- }
- ast::TyUint(uit) => {
- check_path_args(tcx, path, NO_TPS | NO_REGIONS);
- Some(ty::mk_mach_uint(tcx, uit))
- }
- ast::TyFloat(ft) => {
- check_path_args(tcx, path, NO_TPS | NO_REGIONS);
- Some(ty::mk_mach_float(tcx, ft))
- }
- ast::TyStr => {
- Some(ty::mk_str(tcx))
- }
- }
- }
- _ => None
+ if let ast::TyPath(None, ref path) = ast_ty.node {
+ let def = match tcx.def_map.borrow().get(&ast_ty.id) {
+ None => {
+ tcx.sess.span_bug(ast_ty.span,
+ &format!("unbound path {}", path.repr(tcx)))
}
+ Some(d) => d.full_def()
+ };
+ if let def::DefPrimTy(nty) = def {
+ Some(prim_ty_to_ty(tcx, &path.segments[], nty))
+ } else {
+ None
}
- _ => None
+ } else {
+ None
}
}
use metadata::tyencode;
use middle::check_const::ConstQualif;
use middle::mem_categorization::Typer;
+use middle::privacy::{AllPublic, LastMod};
use middle::subst;
use middle::subst::VecPerParamSpace;
use middle::ty::{self, Ty, MethodCall, MethodCallee, MethodOrigin};
fn tr(&self, dcx: &DecodeContext) -> def::Def {
match *self {
def::DefFn(did, is_ctor) => def::DefFn(did.tr(dcx), is_ctor),
- def::DefStaticMethod(did, p) => {
- def::DefStaticMethod(did.tr(dcx), p.map(|did2| did2.tr(dcx)))
- }
- def::DefMethod(did0, did1, p) => {
- def::DefMethod(did0.tr(dcx),
- did1.map(|did1| did1.tr(dcx)),
- p.map(|did2| did2.tr(dcx)))
+ def::DefMethod(did, p) => {
+ def::DefMethod(did.tr(dcx), p.map(|did2| did2.tr(dcx)))
}
def::DefSelfTy(nid) => { def::DefSelfTy(dcx.tr_id(nid)) }
def::DefMod(did) => { def::DefMod(did.tr(dcx)) }
def::DefVariant(e_did, v_did, is_s) => {
def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s)
},
- def::DefaultImpl(did) => def::DefaultImpl(did.tr(dcx)),
+ def::DefTrait(did) => def::DefTrait(did.tr(dcx)),
def::DefTy(did, is_enum) => def::DefTy(did.tr(dcx), is_enum),
- def::DefAssociatedTy(did) => def::DefAssociatedTy(did.tr(dcx)),
- def::DefAssociatedPath(def::TyParamProvenance::FromSelf(did), ident) =>
- def::DefAssociatedPath(def::TyParamProvenance::FromSelf(did.tr(dcx)), ident),
- def::DefAssociatedPath(def::TyParamProvenance::FromParam(did), ident) =>
- def::DefAssociatedPath(def::TyParamProvenance::FromParam(did.tr(dcx)), ident),
+ def::DefAssociatedTy(trait_did, did) =>
+ def::DefAssociatedTy(trait_did.tr(dcx), did.tr(dcx)),
def::DefPrimTy(p) => def::DefPrimTy(p),
def::DefTyParam(s, index, def_id, n) => def::DefTyParam(s, index, def_id.tr(dcx), n),
def::DefUse(did) => def::DefUse(did.tr(dcx)),
}
def::DefStruct(did) => def::DefStruct(did.tr(dcx)),
def::DefRegion(nid) => def::DefRegion(dcx.tr_id(nid)),
- def::DefTyParamBinder(nid) => {
- def::DefTyParamBinder(dcx.tr_id(nid))
- }
def::DefLabel(nid) => def::DefLabel(dcx.tr_id(nid))
}
}
debug!("Encoding side tables for id {}", id);
- if let Some(def) = tcx.def_map.borrow().get(&id) {
+ if let Some(def) = tcx.def_map.borrow().get(&id).map(|d| d.full_def()) {
rbml_w.tag(c::tag_table_def, |rbml_w| {
rbml_w.id(id);
- rbml_w.tag(c::tag_table_val, |rbml_w| (*def).encode(rbml_w).unwrap());
+ rbml_w.tag(c::tag_table_val, |rbml_w| def.encode(rbml_w).unwrap());
})
}
match value {
c::tag_table_def => {
let def = decode_def(dcx, val_doc);
- dcx.tcx.def_map.borrow_mut().insert(id, def);
+ dcx.tcx.def_map.borrow_mut().insert(id, def::PathResolution {
+ base_def: def,
+ // This doesn't matter cross-crate.
+ last_private: LastMod(AllPublic),
+ depth: 0
+ });
}
c::tag_table_node_type => {
let ty = val_dsr.read_ty(dcx);
ast::ExprMac(..) |
ast::ExprClosure(..) |
ast::ExprLit(..) |
- ast::ExprPath(..) |
- ast::ExprQPath(..) => {
+ ast::ExprPath(..) => {
self.straightline(expr, pred, None::<ast::Expr>.iter())
}
}
fn find_scope(&self,
expr: &ast::Expr,
label: Option<ast::Ident>) -> LoopScope {
- match label {
- None => {
- return *self.loop_scopes.last().unwrap();
- }
-
- Some(_) => {
- match self.tcx.def_map.borrow().get(&expr.id) {
- Some(&def::DefLabel(loop_id)) => {
- for l in &self.loop_scopes {
- if l.loop_id == loop_id {
- return *l;
- }
- }
- self.tcx.sess.span_bug(
- expr.span,
- &format!("no loop scope for id {}",
- loop_id));
- }
+ if label.is_none() {
+ return *self.loop_scopes.last().unwrap();
+ }
- r => {
- self.tcx.sess.span_bug(
- expr.span,
- &format!("bad entry `{:?}` in def_map for label",
- r));
+ match self.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) {
+ Some(def::DefLabel(loop_id)) => {
+ for l in &self.loop_scopes {
+ if l.loop_id == loop_id {
+ return *l;
}
}
+ self.tcx.sess.span_bug(expr.span,
+ &format!("no loop scope for id {}", loop_id));
+ }
+
+ r => {
+ self.tcx.sess.span_bug(expr.span,
+ &format!("bad entry `{:?}` in def_map for label", r));
}
}
}
}
}
}
- ast::ExprPath(_) | ast::ExprQPath(_) => {
- let def = v.tcx.def_map.borrow().get(&e.id).cloned();
+ ast::ExprPath(..) => {
+ let def = v.tcx.def_map.borrow().get(&e.id).map(|d| d.full_def());
match def {
Some(def::DefVariant(_, _, _)) => {
// Count the discriminator or function pointer.
v.add_qualif(NON_ZERO_SIZED);
}
}
- Some(def::DefFn(..)) |
- Some(def::DefStaticMethod(..)) | Some(def::DefMethod(..)) => {
+ Some(def::DefFn(..)) | Some(def::DefMethod(..)) => {
// Count the function pointer.
v.add_qualif(NON_ZERO_SIZED);
}
_ => break
};
}
- let def = v.tcx.def_map.borrow().get(&callee.id).cloned();
+ let def = v.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def());
match def {
Some(def::DefStruct(..)) => {}
Some(def::DefVariant(..)) => {
ast::PatIdent(ast::BindByValue(ast::MutImmutable), ident, None) => {
let pat_ty = ty::pat_ty(cx.tcx, p);
if let ty::ty_enum(def_id, _) = pat_ty.sty {
- let def = cx.tcx.def_map.borrow().get(&p.id).cloned();
+ let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def());
if let Some(DefLocal(_)) = def {
if ty::enum_variants(cx.tcx, def_id).iter().any(|variant|
token::get_name(variant.name) == token::get_name(ident.node.name)
fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
return match pat.node {
ast::PatIdent(..) | ast::PatEnum(..) => {
- let def = self.tcx.def_map.borrow().get(&pat.id).cloned();
+ let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def());
match def {
Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did) {
Some(const_expr) => {
let pat = raw_pat(p);
match pat.node {
ast::PatIdent(..) =>
- match cx.tcx.def_map.borrow().get(&pat.id) {
- Some(&DefConst(..)) =>
+ match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
+ Some(DefConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
- Some(&DefStruct(_)) => vec!(Single),
- Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
+ Some(DefStruct(_)) => vec!(Single),
+ Some(DefVariant(_, id, _)) => vec!(Variant(id)),
_ => vec!()
},
ast::PatEnum(..) =>
- match cx.tcx.def_map.borrow().get(&pat.id) {
- Some(&DefConst(..)) =>
+ match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
+ Some(DefConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
- Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
+ Some(DefVariant(_, id, _)) => vec!(Variant(id)),
_ => vec!(Single)
},
ast::PatStruct(..) =>
- match cx.tcx.def_map.borrow().get(&pat.id) {
- Some(&DefConst(..)) =>
+ match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
+ Some(DefConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
- Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
+ Some(DefVariant(_, id, _)) => vec!(Variant(id)),
_ => vec!(Single)
},
ast::PatLit(ref expr) =>
Some(repeat(DUMMY_WILD_PAT).take(arity).collect()),
ast::PatIdent(_, _, _) => {
- let opt_def = cx.tcx.def_map.borrow().get(&pat_id).cloned();
+ let opt_def = cx.tcx.def_map.borrow().get(&pat_id).map(|d| d.full_def());
match opt_def {
Some(DefConst(..)) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
}
ast::PatEnum(_, ref args) => {
- let def = cx.tcx.def_map.borrow()[pat_id].clone();
+ let def = cx.tcx.def_map.borrow()[pat_id].full_def();
match def {
DefConst(..) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
ast::PatStruct(_, ref pattern_fields, _) => {
// Is this a struct or an enum variant?
- let def = cx.tcx.def_map.borrow()[pat_id].clone();
+ let def = cx.tcx.def_map.borrow()[pat_id].full_def();
let class_id = match def {
DefConst(..) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
fn visit_expr(&mut self, e: &ast::Expr) {
match e.node {
- ast::ExprPath(_) | ast::ExprQPath(_) => {
- match self.def_map.borrow().get(&e.id) {
- Some(&DefStatic(def_id, _)) |
- Some(&DefConst(def_id)) if
+ ast::ExprPath(..) => {
+ match self.def_map.borrow().get(&e.id).map(|d| d.base_def) {
+ Some(DefStatic(def_id, _)) |
+ Some(DefConst(def_id)) if
ast_util::is_local(def_id) => {
match self.ast_map.get(def_id.node) {
ast_map::NodeItem(item) =>
use std::rc::Rc;
fn lookup_const<'a>(tcx: &'a ty::ctxt, e: &Expr) -> Option<&'a Expr> {
- let opt_def = tcx.def_map.borrow().get(&e.id).cloned();
+ let opt_def = tcx.def_map.borrow().get(&e.id).map(|d| d.full_def());
match opt_def {
Some(def::DefConst(def_id)) => {
lookup_const_by_id(tcx, def_id)
ast::PatTup(exprs.iter().map(|expr| const_expr_to_pat(tcx, &**expr, span)).collect()),
ast::ExprCall(ref callee, ref args) => {
- let def = tcx.def_map.borrow()[callee.id].clone();
+ let def = tcx.def_map.borrow()[callee.id];
if let Vacant(entry) = tcx.def_map.borrow_mut().entry(expr.id) {
entry.insert(def);
}
- let path = match def {
+ let path = match def.full_def() {
def::DefStruct(def_id) => def_to_path(tcx, def_id),
def::DefVariant(_, variant_did, _) => def_to_path(tcx, variant_did),
_ => unreachable!()
ast::PatVec(pats, None, vec![])
}
- ast::ExprPath(ref path) => {
- let opt_def = tcx.def_map.borrow().get(&expr.id).cloned();
+ ast::ExprPath(_, ref path) => {
+ let opt_def = tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def());
match opt_def {
Some(def::DefStruct(..)) =>
ast::PatStruct(path.clone(), vec![], false),
}
}
- ast::ExprQPath(_) => {
- match lookup_const(tcx, expr) {
- Some(actual) => return const_expr_to_pat(tcx, actual, span),
- _ => unreachable!()
- }
- }
-
_ => ast::PatLit(P(expr.clone()))
};
P(ast::Pat { id: expr.id, node: pat, span: span })
let val = try!(eval_const_expr_partial(tcx, &**base, Some(base_hint)));
cast_const(val, ety)
}
- ast::ExprPath(_) | ast::ExprQPath(_) => {
- let opt_def = tcx.def_map.borrow().get(&e.id).cloned();
+ ast::ExprPath(..) => {
+ let opt_def = tcx.def_map.borrow().get(&e.id).map(|d| d.full_def());
let (const_expr, const_ty) = match opt_def {
Some(def::DefConst(def_id)) => {
if ast_util::is_local(def_id) {
fn lookup_and_handle_definition(&mut self, id: &ast::NodeId) {
self.tcx.def_map.borrow().get(id).map(|def| {
- match def {
- &def::DefConst(_) => {
+ match def.full_def() {
+ def::DefConst(_) => {
self.check_def_id(def.def_id())
}
_ if self.ignore_non_const_paths => (),
- &def::DefPrimTy(_) => (),
- &def::DefVariant(enum_id, variant_id, _) => {
+ def::DefPrimTy(_) => (),
+ def::DefVariant(enum_id, variant_id, _) => {
self.check_def_id(enum_id);
self.check_def_id(variant_id);
}
fn handle_field_pattern_match(&mut self, lhs: &ast::Pat,
pats: &[codemap::Spanned<ast::FieldPat>]) {
- let id = match (*self.tcx.def_map.borrow())[lhs.id] {
+ let id = match self.tcx.def_map.borrow()[lhs.id].full_def() {
def::DefVariant(_, id, _) => id,
_ => {
match ty::ty_to_def_id(ty::node_id_to_type(self.tcx,
pub use self::Def::*;
pub use self::MethodProvenance::*;
-pub use self::TraitItemKind::*;
+use middle::privacy::LastPrivate;
use middle::subst::ParamSpace;
-use middle::ty::{ExplicitSelfCategory, StaticExplicitSelfCategory};
use util::nodemap::NodeMap;
use syntax::ast;
use syntax::ast_util::local_def;
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Def {
DefFn(ast::DefId, bool /* is_ctor */),
- DefStaticMethod(/* method */ ast::DefId, MethodProvenance),
DefSelfTy(/* trait id */ ast::NodeId),
DefMod(ast::DefId),
DefForeignMod(ast::DefId),
DefLocal(ast::NodeId),
DefVariant(ast::DefId /* enum */, ast::DefId /* variant */, bool /* is_structure */),
DefTy(ast::DefId, bool /* is_enum */),
- DefAssociatedTy(ast::DefId),
- // A partially resolved path to an associated type `T::U` where `T` is a concrete
- // type (indicated by the DefId) which implements a trait which has an associated
- // type `U` (indicated by the Ident).
- // FIXME(#20301) -- should use Name
- DefAssociatedPath(TyParamProvenance, ast::Ident),
- DefaultImpl(ast::DefId),
+ DefAssociatedTy(ast::DefId /* trait */, ast::DefId),
+ DefTrait(ast::DefId),
DefPrimTy(ast::PrimTy),
DefTyParam(ParamSpace, u32, ast::DefId, ast::Name),
DefUse(ast::DefId),
/// - If it's an ExprPath referring to some tuple struct, then DefMap maps
/// it to a def whose id is the StructDef.ctor_id.
DefStruct(ast::DefId),
- DefTyParamBinder(ast::NodeId), /* struct, impl or trait with ty params */
DefRegion(ast::NodeId),
DefLabel(ast::NodeId),
- DefMethod(ast::DefId /* method */, Option<ast::DefId> /* trait */, MethodProvenance),
+ DefMethod(ast::DefId /* method */, MethodProvenance),
+}
+
+/// The result of resolving a path.
+/// Before type checking completes, `depth` represents the number of
+/// trailing segments which are yet unresolved. Afterwards, if there
+/// were no errors, all paths should be fully resolved, with `depth`
+/// set to `0` and `base_def` representing the final resolution.
+///
+/// module::Type::AssocX::AssocY::MethodOrAssocType
+/// ^~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+/// base_def depth = 3
+///
+/// <T as Trait>::AssocX::AssocY::MethodOrAssocType
+/// ^~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~
+/// base_def depth = 2
+#[derive(Copy, Debug)]
+pub struct PathResolution {
+ pub base_def: Def,
+ pub last_private: LastPrivate,
+ pub depth: usize
+}
+
+impl PathResolution {
+ /// Get the definition, if fully resolved, otherwise panic.
+ pub fn full_def(&self) -> Def {
+ if self.depth != 0 {
+ panic!("path not fully resolved: {:?}", self);
+ }
+ self.base_def
+ }
+
+ /// Get the DefId, if fully resolved, otherwise panic.
+ pub fn def_id(&self) -> ast::DefId {
+ self.full_def().def_id()
+ }
}
// Definition mapping
-pub type DefMap = RefCell<NodeMap<Def>>;
+pub type DefMap = RefCell<NodeMap<PathResolution>>;
// This is the replacement export map. It maps a module to all of the exports
// within.
pub type ExportMap = NodeMap<Vec<Export>>;
FromImpl(ast::DefId),
}
-#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum TyParamProvenance {
- FromSelf(ast::DefId),
- FromParam(ast::DefId),
-}
-
impl MethodProvenance {
pub fn map<F>(self, f: F) -> MethodProvenance where
F: FnOnce(ast::DefId) -> ast::DefId,
}
}
-impl TyParamProvenance {
- pub fn def_id(&self) -> ast::DefId {
- match *self {
- TyParamProvenance::FromSelf(ref did) => did.clone(),
- TyParamProvenance::FromParam(ref did) => did.clone(),
- }
- }
-}
-
-#[derive(Clone, Copy, Eq, PartialEq)]
-pub enum TraitItemKind {
- NonstaticMethodTraitItemKind,
- StaticMethodTraitItemKind,
- TypeTraitItemKind,
-}
-
-impl TraitItemKind {
- pub fn from_explicit_self_category(explicit_self_category:
- ExplicitSelfCategory)
- -> TraitItemKind {
- if explicit_self_category == StaticExplicitSelfCategory {
- StaticMethodTraitItemKind
- } else {
- NonstaticMethodTraitItemKind
- }
- }
-}
-
impl Def {
pub fn local_node_id(&self) -> ast::NodeId {
let def_id = self.def_id();
pub fn def_id(&self) -> ast::DefId {
match *self {
- DefFn(id, _) | DefStaticMethod(id, _) | DefMod(id) |
- DefForeignMod(id) | DefStatic(id, _) |
- DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(id) |
- DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefaultImpl(id) |
- DefMethod(id, _, _) | DefConst(id) |
- DefAssociatedPath(TyParamProvenance::FromSelf(id), _) |
- DefAssociatedPath(TyParamProvenance::FromParam(id), _) => {
+ DefFn(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) |
+ DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) |
+ DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
+ DefMethod(id, _) | DefConst(id) => {
id
}
DefLocal(id) |
DefSelfTy(id) |
DefUpvar(id, _) |
DefRegion(id) |
- DefTyParamBinder(id) |
DefLabel(id) => {
local_def(id)
}
- DefPrimTy(_) => panic!()
+ DefPrimTy(_) => panic!("attempted .def_id() on DefPrimTy")
}
}
ast::ExprInlineAsm(..) => {
self.require_unsafe(expr.span, "use of inline assembly");
}
- ast::ExprPath(_) | ast::ExprQPath(_) => {
+ ast::ExprPath(..) => {
if let def::DefStatic(_, true) = ty::resolve_expr(self.tcx, expr) {
self.require_unsafe(expr.span, "use of mutable static");
}
self.walk_expr(&**subexpr)
}
- ast::ExprPath(_) | ast::ExprQPath(_) => { }
+ ast::ExprPath(..) => { }
ast::ExprUnary(ast::UnDeref, ref base) => { // *base
if !self.walk_overloaded_operator(expr, &**base, Vec::new(), PassArgs::ByRef) {
// Each match binding is effectively an assignment to the
// binding being produced.
- let def = def_map.borrow()[pat.id].clone();
+ let def = def_map.borrow()[pat.id].full_def();
match mc.cat_def(pat.id, pat.span, pat_ty, def) {
Ok(binding_cmt) => {
delegate.mutate(pat.id, pat.span, binding_cmt, Init);
match pat.node {
ast::PatEnum(_, _) | ast::PatIdent(_, _, None) | ast::PatStruct(..) => {
- match def_map.get(&pat.id) {
+ match def_map.get(&pat.id).map(|d| d.full_def()) {
None => {
// no definition found: pat is not a
// struct or enum pattern.
}
- Some(&def::DefVariant(enum_did, variant_did, _is_struct)) => {
+ Some(def::DefVariant(enum_did, variant_did, _is_struct)) => {
let downcast_cmt =
if ty::enum_is_univariant(tcx, enum_did) {
cmt_pat
delegate.matched_pat(pat, downcast_cmt, match_mode);
}
- Some(&def::DefStruct(..)) | Some(&def::DefTy(_, false)) => {
+ Some(def::DefStruct(..)) | Some(def::DefTy(_, false)) => {
// A struct (in either the value or type
// namespace; we encounter the former on
// e.g. patterns for unit structs).
delegate.matched_pat(pat, cmt_pat, match_mode);
}
- Some(&def::DefConst(..)) |
- Some(&def::DefLocal(..)) => {
+ Some(def::DefConst(..)) |
+ Some(def::DefLocal(..)) => {
// This is a leaf (i.e. identifier binding
// or constant value to match); thus no
// `matched_pat` call.
}
- Some(def @ &def::DefTy(_, true)) => {
+ Some(def @ def::DefTy(_, true)) => {
// An enum's type -- should never be in a
// pattern.
variadic: a.variadic});
- fn argvecs<'tcx, C: Combine<'tcx>>(combiner: &C,
- a_args: &[Ty<'tcx>],
- b_args: &[Ty<'tcx>])
- -> cres<'tcx, Vec<Ty<'tcx>>>
- {
+ 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()
Err(ty::terr_projection_name_mismatched(
expected_found(self, a.item_name, b.item_name)))
} else {
- // Note that the trait refs for the projection must be
- // *equal*. This is because there is no inherent
- // relationship between `<T as Foo>::Bar` and `<U as
- // Foo>::Bar` that we can derive based on how `T` relates
- // to `U`. Issue #21726 contains further discussion and
- // in-depth examples.
- let trait_ref = try!(self.equate().trait_refs(&*a.trait_ref, &*b.trait_ref));
+ 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 })
}
}
impl<'tcx,T> Combineable<'tcx> for Rc<T>
where T : Combineable<'tcx>
{
- fn combine<C:Combine<'tcx>>(combiner: &C,
- a: &Rc<T>,
- b: &Rc<T>)
- -> cres<'tcx, Rc<T>>
- {
+ 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:Combine<'tcx>>(combiner: &C,
- a: &ty::TraitRef<'tcx>,
- b: &ty::TraitRef<'tcx>)
- -> cres<'tcx, 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:Combine<'tcx>>(combiner: &C,
- a: &Ty<'tcx>,
- b: &Ty<'tcx>)
- -> cres<'tcx, 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:Combine<'tcx>>(combiner: &C,
- a: &ty::ProjectionPredicate<'tcx>,
- b: &ty::ProjectionPredicate<'tcx>)
- -> cres<'tcx, 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:Combine<'tcx>>(combiner: &C,
- a: &ty::FnSig<'tcx>,
- b: &ty::FnSig<'tcx>)
- -> cres<'tcx, 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)
}
}
pub trace: TypeTrace<'tcx>,
}
-pub fn expected_found<'tcx, C: Combine<'tcx>, T>(
- this: &C, a: T, b: T) -> ty::expected_found<T> {
+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 {
}
}
-pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C,
- a: Ty<'tcx>,
- b: Ty<'tcx>)
- -> cres<'tcx, Ty<'tcx>>
-{
+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)
- }
+ // 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),
// Relate integral variables to other types
(&ty::ty_infer(IntVar(a_id)), &ty::ty_infer(IntVar(b_id))) => {
unify_float_variable(this, !this.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_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)))
- }
-
- (&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 => {
+ (&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_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)))
+ }
+
+ (&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_region, a_substs),
- &ty::ty_closure(b_id, b_region, 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 region = try!(this.equate().regions(*a_region, *b_region));
- let substs = try!(this.substs_variances(None, a_substs, b_substs));
- Ok(ty::mk_closure(tcx, a_id, tcx.mk_region(region), 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)) => {
+ }
+
+ (&ty::ty_closure(a_id, a_region, a_substs),
+ &ty::ty_closure(b_id, b_region, 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 region = try!(this.equate().regions(*a_region, *b_region));
+ let substs = try!(this.substs_variances(None, a_substs, b_substs));
+ Ok(ty::mk_closure(tcx, a_id, tcx.mk_region(region), 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));
// FIXME(14985) If we have mutable references to trait objects, we
_ => 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, 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))
+ (&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_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 =>
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))
- }
+ (&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)))
+ _ => Err(ty::terr_sorts(expected_found(this, a, b))),
};
- fn unify_integral_variable<'tcx, C: Combine<'tcx>>(
- this: &C,
- vid_is_expected: bool,
- vid: ty::IntVid,
- val: ty::IntVarValue) -> cres<'tcx, Ty<'tcx>>
- {
+ 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))
+ UintType(v) => Ok(ty::mk_mach_uint(this.tcx(), v)),
}
}
- fn unify_float_variable<'tcx, C: Combine<'tcx>>(
- this: &C,
- vid_is_expected: bool,
- vid: ty::FloatVid,
- val: ast::FloatTy) -> cres<'tcx, Ty<'tcx>>
- {
+ 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))
}
None => { // ...not yet instantiated:
// Generalize type if necessary.
let generalized_ty = try!(match dir {
- EqTo => {
- self.generalize(a_ty, b_vid, false)
- }
- BiTo | SupertypeOf | SubtypeOf => {
- self.generalize(a_ty, b_vid, true)
- }
+ EqTo => self.generalize(a_ty, b_vid, false),
+ BiTo | SupertypeOf | SubtypeOf => self.generalize(a_ty, b_vid, true),
});
debug!("instantiate(a_ty={}, dir={:?}, \
b_vid={}, generalized_ty={})",
// 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));
- }
+ BiTo => try!(self.bivariate().tys(a_ty, b_ty)),
- EqTo => {
- try!(self.equate().tys(a_ty, b_ty));
- }
+ EqTo => try!(self.equate().tys(a_ty, b_ty)),
- SubtypeOf => {
- try!(self.sub().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));
- }
- }
+ SupertypeOf => try!(self.sub().tys_with_variance(ty::Contravariant, a_ty, b_ty)),
+ };
}
Ok(())
make_region_vars: bool)
-> cres<'tcx, Ty<'tcx>>
{
- let mut generalize = Generalizer { infcx: self.infcx,
- span: self.trace.origin.span(),
- for_vid: for_vid,
- make_region_vars: make_region_vars,
- cycle_detected: false };
+ let mut generalize = Generalizer {
+ infcx: self.infcx,
+ span: self.trace.origin.span(),
+ for_vid: for_vid,
+ make_region_vars: make_region_vars,
+ cycle_detected: false
+ };
let u = ty.fold_with(&mut generalize);
if generalize.cycle_detected {
Err(ty::terr_cyclic_ty)
}
ty_queue.push(&*mut_ty.ty);
}
- ast::TyPath(ref path, id) => {
- let a_def = match self.tcx.def_map.borrow().get(&id) {
+ ast::TyPath(ref maybe_qself, ref path) => {
+ let a_def = match self.tcx.def_map.borrow().get(&cur_ty.id) {
None => {
self.tcx
.sess
"unbound path {}",
pprust::path_to_string(path)))
}
- Some(&d) => d
+ Some(d) => d.full_def()
};
match a_def {
def::DefTy(did, _) | def::DefStruct(did) => {
region_names: region_names
};
let new_path = self.rebuild_path(rebuild_info, lifetime);
+ let qself = maybe_qself.as_ref().map(|qself| {
+ ast::QSelf {
+ ty: self.rebuild_arg_ty_or_output(&qself.ty, lifetime,
+ anon_nums, region_names),
+ position: qself.position
+ }
+ });
let to = ast::Ty {
id: cur_ty.id,
- node: ast::TyPath(new_path, id),
+ node: ast::TyPath(qself, new_path),
span: cur_ty.span
};
new_ty = self.rebuild_ty(new_ty, P(to));
true // changed
}
- ErrorValue => {
- false // no change
- }
+ ErrorValue => false, // no change
Value(a_region) => {
match a_data.classification {
- Expanding => {
- check_node(self, a_vid, a_data, a_region, b_region)
- }
- Contracting => {
- adjust_node(self, a_vid, a_data, a_region, b_region)
- }
+ Expanding => check_node(self, a_vid, a_data, a_region, b_region),
+ Contracting => adjust_node(self, a_vid, a_data, a_region, b_region),
}
}
};
a_data: &mut VarData,
a_region: Region,
b_region: Region)
- -> bool {
+ -> bool {
if !this.is_subregion_of(a_region, b_region) {
debug!("Setting {:?} to ErrorValue: {} not subregion of {}",
a_vid,
a_data: &mut VarData,
a_region: Region,
b_region: Region)
- -> bool {
+ -> bool {
match this.glb_concrete_regions(a_region, b_region) {
Ok(glb) => {
if glb == a_region {
fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
match expr.node {
// live nodes required for uses or definitions of variables:
- ast::ExprPath(_) | ast::ExprQPath(_) => {
- let def = ir.tcx.def_map.borrow()[expr.id].clone();
+ ast::ExprPath(..) => {
+ let def = ir.tcx.def_map.borrow()[expr.id].full_def();
debug!("expr {}: path that leads to {:?}", expr.id, def);
if let DefLocal(..) = def {
ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
Some(_) => {
// Refers to a labeled loop. Use the results of resolve
// to find with one
- match self.ir.tcx.def_map.borrow().get(&id) {
- Some(&DefLabel(loop_id)) => loop_id,
+ match self.ir.tcx.def_map.borrow().get(&id).map(|d| d.full_def()) {
+ Some(DefLabel(loop_id)) => loop_id,
_ => self.ir.tcx.sess.span_bug(sp, "label on break/loop \
doesn't refer to a loop")
}
match expr.node {
// Interesting cases with control flow or which gen/kill
- ast::ExprPath(_) | ast::ExprQPath(_) => {
+ ast::ExprPath(..) => {
self.access_path(expr, succ, ACC_READ | ACC_USE)
}
// just ignore such cases and treat them as reads.
match expr.node {
- ast::ExprPath(_) | ast::ExprQPath(_) => succ,
+ ast::ExprPath(..) => succ,
ast::ExprField(ref e, _) => self.propagate_through_expr(&**e, succ),
ast::ExprTupField(ref e, _) => self.propagate_through_expr(&**e, succ),
_ => self.propagate_through_expr(expr, succ)
fn write_lvalue(&mut self, expr: &Expr, succ: LiveNode, acc: uint)
-> LiveNode {
match expr.node {
- ast::ExprPath(_) | ast::ExprQPath(_) => {
+ ast::ExprPath(..) => {
self.access_path(expr, succ, acc)
}
fn access_path(&mut self, expr: &Expr, succ: LiveNode, acc: uint)
-> LiveNode {
- match self.ir.tcx.def_map.borrow()[expr.id].clone() {
+ match self.ir.tcx.def_map.borrow()[expr.id].full_def() {
DefLocal(nid) => {
let ln = self.live_node(expr.id, expr.span);
if acc != 0 {
ast::ExprBlock(..) | ast::ExprMac(..) | ast::ExprAddrOf(..) |
ast::ExprStruct(..) | ast::ExprRepeat(..) | ast::ExprParen(..) |
ast::ExprClosure(..) | ast::ExprPath(..) | ast::ExprBox(..) |
- ast::ExprRange(..) | ast::ExprQPath(..) => {
+ ast::ExprRange(..) => {
visit::walk_expr(this, expr);
}
ast::ExprIfLet(..) => {
fn check_lvalue(&mut self, expr: &Expr) {
match expr.node {
- ast::ExprPath(_) | ast::ExprQPath(_) => {
- if let DefLocal(nid) = self.ir.tcx.def_map.borrow()[expr.id].clone() {
+ ast::ExprPath(..) => {
+ if let DefLocal(nid) = self.ir.tcx.def_map.borrow()[expr.id].full_def() {
// Assignment to an immutable variable or argument: only legal
// if there is no later assignment. If this local is actually
// mutable, then check for a reassignment to flag the mutability
}
}
- ast::ExprPath(_) | ast::ExprQPath(_) => {
- let def = (*self.tcx().def_map.borrow())[expr.id];
+ ast::ExprPath(..) => {
+ let def = self.tcx().def_map.borrow()[expr.id].full_def();
self.cat_def(expr.id, expr.span, expr_ty, def)
}
match def {
def::DefStruct(..) | def::DefVariant(..) | def::DefConst(..) |
- def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) => {
+ def::DefFn(..) | def::DefMethod(..) => {
Ok(self.cat_rvalue_node(id, span, expr_ty))
}
def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) |
- def::DefaultImpl(_) | def::DefTy(..) | def::DefPrimTy(_) |
- def::DefTyParam(..) | def::DefTyParamBinder(..) | def::DefRegion(_) |
+ def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) |
+ def::DefTyParam(..) | def::DefRegion(_) |
def::DefLabel(_) | def::DefSelfTy(..) |
- def::DefAssociatedTy(..) | def::DefAssociatedPath(..)=> {
+ def::DefAssociatedTy(..) => {
Ok(Rc::new(cmt_ {
id:id,
span:span,
(*op)(self, cmt.clone(), pat);
- let def_map = self.tcx().def_map.borrow();
- let opt_def = def_map.get(&pat.id);
+ let opt_def = self.tcx().def_map.borrow().get(&pat.id).map(|d| d.full_def());
// Note: This goes up here (rather than within the PatEnum arm
// alone) because struct patterns can refer to struct types or
// to struct variants within enums.
let cmt = match opt_def {
- Some(&def::DefVariant(enum_did, variant_did, _))
+ Some(def::DefVariant(enum_did, variant_did, _))
// univariant enums do not need downcasts
if !ty::enum_is_univariant(self.tcx(), enum_did) => {
self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did)
}
ast::PatEnum(_, Some(ref subpats)) => {
match opt_def {
- Some(&def::DefVariant(..)) => {
+ Some(def::DefVariant(..)) => {
// variant(x, y, z)
for (i, subpat) in subpats.iter().enumerate() {
let subpat_ty = try!(self.pat_ty(&**subpat)); // see (*2)
try!(self.cat_pattern_(subcmt, &**subpat, op));
}
}
- Some(&def::DefStruct(..)) => {
+ Some(def::DefStruct(..)) => {
for (i, subpat) in subpats.iter().enumerate() {
let subpat_ty = try!(self.pat_ty(&**subpat)); // see (*2)
let cmt_field =
try!(self.cat_pattern_(cmt_field, &**subpat, op));
}
}
- Some(&def::DefConst(..)) => {
+ Some(def::DefConst(..)) => {
for subpat in subpats {
try!(self.cat_pattern_(cmt.clone(), &**subpat, op));
}
ast::PatEnum(_, _) |
ast::PatIdent(_, _, None) |
ast::PatStruct(..) => {
- match dm.borrow().get(&pat.id) {
- Some(&DefVariant(..)) => true,
+ match dm.borrow().get(&pat.id).map(|d| d.full_def()) {
+ Some(DefVariant(..)) => true,
_ => false
}
}
ast::PatEnum(_, _) |
ast::PatIdent(_, _, None) |
ast::PatStruct(..) => {
- match dm.borrow().get(&pat.id) {
- Some(&DefVariant(..)) | Some(&DefStruct(..)) => true,
+ match dm.borrow().get(&pat.id).map(|d| d.full_def()) {
+ Some(DefVariant(..)) | Some(DefStruct(..)) => true,
_ => false
}
}
pub fn pat_is_const(dm: &DefMap, pat: &ast::Pat) -> bool {
match pat.node {
ast::PatIdent(_, _, None) | ast::PatEnum(..) => {
- match dm.borrow().get(&pat.id) {
- Some(&DefConst(..)) => true,
+ match dm.borrow().get(&pat.id).map(|d| d.full_def()) {
+ Some(DefConst(..)) => true,
_ => false
}
}
pub use self::ImportUse::*;
pub use self::LastPrivate::*;
-use util::nodemap::{DefIdSet, NodeMap, NodeSet};
+use util::nodemap::{DefIdSet, NodeSet};
use syntax::ast;
/// reexporting a public struct doesn't inline the doc).
pub type PublicItems = NodeSet;
-// FIXME: dox
-pub type LastPrivateMap = NodeMap<LastPrivate>;
-
#[derive(Copy, Debug)]
pub enum LastPrivate {
LastMod(PrivateDep),
fn visit_expr(&mut self, expr: &ast::Expr) {
match expr.node {
- ast::ExprPath(_) | ast::ExprQPath(_) => {
+ ast::ExprPath(..) => {
let def = match self.tcx.def_map.borrow().get(&expr.id) {
- Some(&def) => def,
+ Some(d) => d.full_def(),
None => {
self.tcx.sess.span_bug(expr.span,
"def ID not in def map?!")
visit::walk_ty(this, ty);
});
}
- ast::TyPath(ref path, id) => {
+ ast::TyPath(None, ref path) => {
// if this path references a trait, then this will resolve to
// a trait ref, which introduces a binding scope.
- match self.def_map.borrow().get(&id) {
- Some(&def::DefaultImpl(..)) => {
+ match self.def_map.borrow().get(&ty.id).map(|d| (d.base_def, d.depth)) {
+ Some((def::DefTrait(..), 0)) => {
self.with(LateScope(&Vec::new(), self.scope), |_, this| {
- this.visit_path(path, id);
+ this.visit_path(path, ty.id);
});
}
_ => {
for lifetime in &trait_ref.bound_lifetimes {
this.visit_lifetime_def(lifetime);
}
- this.visit_trait_ref(&trait_ref.trait_ref)
+ visit::walk_path(this, &trait_ref.trait_ref.path)
})
} else {
self.visit_trait_ref(&trait_ref.trait_ref)
}
}
-
- fn visit_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
- self.visit_path(&trait_ref.path, trait_ref.ref_id);
- }
}
impl<'a> LifetimeContext<'a> {
pub fn check_path(tcx: &ty::ctxt, path: &ast::Path, id: ast::NodeId,
cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
- let did = match tcx.def_map.borrow().get(&id) {
- Some(&def::DefPrimTy(..)) => return,
- Some(def) => def.def_id(),
- None => return
- };
- maybe_do_stability_check(tcx, did, path.span, cb)
+ match tcx.def_map.borrow().get(&id).map(|d| d.full_def()) {
+ Some(def::DefPrimTy(..)) => {}
+ Some(def) => {
+ maybe_do_stability_check(tcx, def.def_id(), path.span, cb);
+ }
+ None => {}
+ }
+
}
fn maybe_do_stability_check(tcx: &ty::ctxt, id: ast::DefId, span: Span,
b_def_id: ast::DefId)
-> bool
{
+ debug!("overlap(a_def_id={}, b_def_id={})",
+ 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);
+ 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.
if let Err(_) = infer::mk_sub_poly_trait_refs(selcx.infcx(),
true,
return false;
}
+ debug!("overlap: subtraitref check succeeded");
+
// Are any of the obligations unsatisfiable? If so, no overlap.
- a_obligations.iter()
- .chain(b_obligations.iter())
- .all(|o| selcx.evaluate_obligation(o))
+ let opt_failing_obligation =
+ a_obligations.iter()
+ .chain(b_obligations.iter())
+ .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;
+ }
+
+ true
}
/// Instantiate fresh variables for all bound parameters of the impl
use middle::subst;
use middle::ty::{self, HasProjectionTypes, Ty};
use middle::ty_fold::TypeFoldable;
-use middle::infer::{self, InferCtxt};
+use middle::infer::{self, fixup_err_to_string, InferCtxt};
use std::slice::Iter;
use std::rc::Rc;
use syntax::ast;
}
}
+/// Normalizes the parameter environment, reporting errors if they occur.
pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvironment<'a,'tcx>,
cause: ObligationCause<'tcx>)
-> ty::ParameterEnvironment<'a,'tcx>
{
- match normalize_param_env(&unnormalized_env, cause) {
- Ok(p) => p,
+ // I'm not wild about reporting errors here; I'd prefer to
+ // have the errors get reported at a defined place (e.g.,
+ // during typeck). Instead I have all parameter
+ // environments, in effect, going through this function
+ // and hence potentially reporting errors. This ensurse of
+ // course that we never forget to normalize (the
+ // alternative seemed like it would involve a lot of
+ // manual invocations of this fn -- and then we'd have to
+ // deal with the errors at each of those sites).
+ //
+ // In any case, in practice, typeck constructs all the
+ // parameter environments once for every fn as it goes,
+ // and errors will get reported then; so after typeck we
+ // can be sure that no errors should occur.
+
+ let tcx = unnormalized_env.tcx;
+ let span = cause.span;
+ let body_id = cause.body_id;
+
+ debug!("normalize_param_env_or_error(unnormalized_env={})",
+ unnormalized_env.repr(tcx));
+
+ let infcx = infer::new_infer_ctxt(tcx);
+ let predicates = match fully_normalize(&infcx, &unnormalized_env, cause,
+ &unnormalized_env.caller_bounds) {
+ Ok(predicates) => predicates,
Err(errors) => {
- // I'm not wild about reporting errors here; I'd prefer to
- // have the errors get reported at a defined place (e.g.,
- // during typeck). Instead I have all parameter
- // environments, in effect, going through this function
- // and hence potentially reporting errors. This ensurse of
- // course that we never forget to normalize (the
- // alternative seemed like it would involve a lot of
- // manual invocations of this fn -- and then we'd have to
- // deal with the errors at each of those sites).
- //
- // In any case, in practice, typeck constructs all the
- // parameter environments once for every fn as it goes,
- // and errors will get reported then; so after typeck we
- // can be sure that no errors should occur.
- let infcx = infer::new_infer_ctxt(unnormalized_env.tcx);
report_fulfillment_errors(&infcx, &errors);
-
- // Normalized failed? use what they gave us, it's better than nothing.
- unnormalized_env
+ return unnormalized_env; // an unnormalized env is better than nothing
}
- }
-}
-
-pub fn normalize_param_env<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx>,
- cause: ObligationCause<'tcx>)
- -> Result<ty::ParameterEnvironment<'a,'tcx>,
- Vec<FulfillmentError<'tcx>>>
-{
- let tcx = param_env.tcx;
-
- debug!("normalize_param_env(param_env={})",
- param_env.repr(tcx));
+ };
- let infcx = infer::new_infer_ctxt(tcx);
- let predicates = try!(fully_normalize(&infcx, param_env, cause, ¶m_env.caller_bounds));
+ infcx.resolve_regions_and_report_errors(body_id);
+ let predicates = match infcx.fully_resolve(&predicates) {
+ Ok(predicates) => predicates,
+ Err(fixup_err) => {
+ // If we encounter a fixup error, it means that some type
+ // variable wound up unconstrained. I actually don't know
+ // if this can happen, and I certainly don't expect it to
+ // happen often, but if it did happen it probably
+ // represents a legitimate failure due to some kind of
+ // unconstrained variable, and it seems better not to ICE,
+ // all things considered.
+ let err_msg = fixup_err_to_string(fixup_err);
+ tcx.sess.span_err(span, &err_msg);
+ return unnormalized_env; // an unnormalized env is better than nothing
+ }
+ };
- debug!("normalize_param_env: predicates={}",
+ debug!("normalize_param_env_or_error: predicates={}",
predicates.repr(tcx));
- Ok(param_env.with_caller_bounds(predicates))
+ unnormalized_env.with_caller_bounds(predicates)
}
pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
{
let tcx = closure_typer.tcx();
- debug!("normalize_param_env(value={})",
- value.repr(tcx));
+ debug!("normalize_param_env(value={})", value.repr(tcx));
let mut selcx = &mut SelectionContext::new(infcx, closure_typer);
let mut fulfill_cx = FulfillmentContext::new();
}
try!(fulfill_cx.select_all_or_error(infcx, closure_typer));
let resolved_value = infcx.resolve_type_vars_if_possible(&normalized_value);
- debug!("normalize_param_env: resolved_value={}",
- resolved_value.repr(tcx));
+ debug!("normalize_param_env: resolved_value={}", resolved_value.repr(tcx));
Ok(resolved_value)
}
let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty());
return match self_ty.sty {
- ty::ty_infer(ty::IntVar(_)) |
- ty::ty_infer(ty::FloatVar(_)) |
- ty::ty_uint(_) |
- ty::ty_int(_) |
- ty::ty_bool |
- ty::ty_float(_) |
- ty::ty_bare_fn(..) |
- ty::ty_char => {
+ ty::ty_infer(ty::IntVar(_))
+ | ty::ty_infer(ty::FloatVar(_))
+ | ty::ty_uint(_)
+ | ty::ty_int(_)
+ | ty::ty_bool
+ | ty::ty_float(_)
+ | ty::ty_bare_fn(..)
+ | ty::ty_char => {
// safe for everything
Ok(If(Vec::new()))
}
ty::ty_uniq(_) => { // Box<T>
match bound {
- ty::BoundCopy => {
- Err(Unimplemented)
- }
+ ty::BoundCopy => Err(Unimplemented),
- ty::BoundSized => {
- Ok(If(Vec::new()))
- }
+ ty::BoundSized => Ok(If(Vec::new())),
ty::BoundSync | ty::BoundSend => {
self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()");
ty::ty_ptr(..) => { // *const T, *mut T
match bound {
- ty::BoundCopy | ty::BoundSized => {
- Ok(If(Vec::new()))
- }
+ ty::BoundCopy | ty::BoundSized => Ok(If(Vec::new())),
ty::BoundSync | ty::BoundSend => {
self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()");
ty::ty_trait(ref data) => {
match bound {
- ty::BoundSized => {
- Err(Unimplemented)
- }
+ ty::BoundSized => Err(Unimplemented),
ty::BoundCopy => {
if data.bounds.builtin_bounds.contains(&bound) {
Ok(If(Vec::new()))
ty::BoundCopy => {
match mutbl {
// &mut T is affine and hence never `Copy`
- ast::MutMutable => {
- Err(Unimplemented)
- }
+ ast::MutMutable => Err(Unimplemented),
// &T is always copyable
- ast::MutImmutable => {
- Ok(If(Vec::new()))
- }
+ ast::MutImmutable => Ok(If(Vec::new())),
}
}
- ty::BoundSized => {
- Ok(If(Vec::new()))
- }
+ ty::BoundSized => Ok(If(Vec::new())),
ty::BoundSync | ty::BoundSend => {
self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()");
match bound {
ty::BoundCopy => {
match *len {
- Some(_) => {
- // [T, ..n] is copy iff T is copy
- Ok(If(vec![element_ty]))
- }
- None => {
- // [T] is unsized and hence affine
- Err(Unimplemented)
- }
+ // [T, ..n] is copy iff T is copy
+ Some(_) => Ok(If(vec![element_ty])),
+
+ // [T] is unsized and hence affine
+ None => Err(Unimplemented),
}
}
self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()");
}
- ty::BoundCopy | ty::BoundSized => {
- Err(Unimplemented)
- }
+ ty::BoundCopy | ty::BoundSized => Err(Unimplemented),
}
}
- ty::ty_tup(ref tys) => {
- // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
- Ok(If(tys.clone()))
- }
+ // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
+ ty::ty_tup(ref tys) => Ok(If(tys.clone())),
ty::ty_closure(def_id, _, substs) => {
// FIXME -- This case is tricky. In the case of by-ref
}
match self.closure_typer.closure_upvars(def_id, substs) {
- Some(upvars) => {
- Ok(If(upvars.iter().map(|c| c.ty).collect()))
- }
+ Some(upvars) => Ok(If(upvars.iter().map(|c| c.ty).collect())),
None => {
debug!("assemble_builtin_bound_candidates: no upvar types available yet");
Ok(AmbiguousBuiltin)
nominal(bound, types)
}
- ty::ty_projection(_) |
- ty::ty_param(_) => {
+ ty::ty_projection(_) | ty::ty_param(_) => {
// Note: A type parameter is only considered to meet a
// particular bound if there is a where clause telling
// us that it does, and that case is handled by
Ok(AmbiguousBuiltin)
}
- ty::ty_err => {
- Ok(If(Vec::new()))
- }
+ ty::ty_err => Ok(If(Vec::new())),
- ty::ty_infer(ty::FreshTy(_)) |
- ty::ty_infer(ty::FreshIntTy(_)) => {
+ ty::ty_infer(ty::FreshTy(_))
+ | ty::ty_infer(ty::FreshIntTy(_)) => {
self.tcx().sess.bug(
&format!(
"asked to assemble builtin bounds of unexpected type: {}",
fn nominal<'cx, 'tcx>(bound: ty::BuiltinBound,
types: Vec<Ty<'tcx>>)
- -> Result<BuiltinBoundConditions<'tcx>,SelectionError<'tcx>>
+ -> Result<BuiltinBoundConditions<'tcx>, SelectionError<'tcx>>
{
// First check for markers and other nonsense.
match bound {
self.tcx().sess.bug(
&format!(
"asked to assemble constituent types of unexpected type: {}",
- t.repr(self.tcx()))[]);
+ t.repr(self.tcx())));
}
ty::ty_uniq(referent_ty) => { // Box<T>
}).collect::<Result<_, _>>();
let obligations = match obligations {
Ok(o) => o,
- Err(ErrorReported) => Vec::new()
+ Err(ErrorReported) => Vec::new(),
};
let obligations = VecPerParamSpace::new(obligations, Vec::new(), Vec::new());
let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty());
match self.constituent_types_for_ty(self_ty) {
- Some(types) => {
- Ok(self.vtable_default_impl(obligation, impl_def_id, types))
- }
+ Some(types) => Ok(self.vtable_default_impl(obligation, impl_def_id, types)),
None => {
self.tcx().sess.bug(
&format!(
"asked to confirm default implementation for ambiguous type: {}",
- self_ty.repr(self.tcx()))[]);
+ self_ty.repr(self.tcx())));
}
}
}
{
match self.match_impl(impl_def_id, obligation, snapshot,
skol_map, skol_obligation_trait_ref) {
- Ok(substs) => {
- substs
- }
+ Ok(substs) => substs,
Err(()) => {
self.tcx().sess.bug(
&format!("Impl {} was matchable against {} but now is not",
skol_obligation_trait_ref.repr(self.tcx()));
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
- match self.infcx.sub_trait_refs(false,
- origin,
- impl_trait_ref.value.clone(),
- skol_obligation_trait_ref) {
- Ok(()) => { }
- Err(e) => {
- debug!("match_impl: failed sub_trait_refs due to `{}`",
- ty::type_err_to_str(self.tcx(), &e));
- return Err(());
- }
+ if let Err(e) = self.infcx.sub_trait_refs(false,
+ origin,
+ impl_trait_ref.value.clone(),
+ skol_obligation_trait_ref) {
+ debug!("match_impl: failed sub_trait_refs due to `{}`",
+ ty::type_err_to_str(self.tcx(), &e));
+ return Err(());
}
- match self.infcx.leak_check(skol_map, snapshot) {
- Ok(()) => { }
- Err(e) => {
- debug!("match_impl: failed leak check due to `{}`",
- ty::type_err_to_str(self.tcx(), &e));
- return Err(());
- }
+ if let Err(e) = self.infcx.leak_check(skol_map, snapshot) {
+ debug!("match_impl: failed leak check due to `{}`",
+ ty::type_err_to_str(self.tcx(), &e));
+ return Err(());
}
debug!("match_impl: success impl_substs={}", impl_substs.repr(self.tcx()));
- Ok(Normalized { value: impl_substs,
- obligations: impl_trait_ref.obligations })
+ Ok(Normalized {
+ value: impl_substs,
+ obligations: impl_trait_ref.obligations
+ })
}
fn fast_reject_trait_refs(&mut self,
where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
-> Result<Vec<PredicateObligation<'tcx>>,()>
{
- let () =
- try!(self.match_poly_trait_ref(obligation, where_clause_trait_ref));
-
+ try!(self.match_poly_trait_ref(obligation, where_clause_trait_ref));
Ok(Vec::new())
}
match self.tcx().trait_impls.borrow().get(&trait_def_id) {
None => Vec::new(),
- Some(impls) => impls.borrow().clone()
+ Some(impls) => impls.borrow().clone(),
}
}
DefaultImplCandidate(t) => format!("DefaultImplCandidate({:?})", t),
ProjectionCandidate => format!("ProjectionCandidate"),
FnPointerCandidate => format!("FnPointerCandidate"),
- ObjectCandidate => {
- format!("ObjectCandidate")
- }
+ ObjectCandidate => format!("ObjectCandidate"),
ClosureCandidate(c, ref s) => {
format!("ClosureCandidate({:?},{})", c, s.repr(tcx))
}
*self = o.previous;
Some(o)
}
- None => {
- None
- }
+ None => None
}
}
}
impl<'tcx> EvaluationResult<'tcx> {
fn may_apply(&self) -> bool {
match *self {
- EvaluatedToOk |
- EvaluatedToAmbig |
- EvaluatedToErr(Overflow) |
- EvaluatedToErr(OutputTypeParameterMismatch(..)) => {
- true
- }
- EvaluatedToErr(Unimplemented) => {
- false
- }
+ EvaluatedToOk
+ | EvaluatedToAmbig
+ | EvaluatedToErr(Overflow)
+ | EvaluatedToErr(OutputTypeParameterMismatch(..)) => true,
+ EvaluatedToErr(Unimplemented) => false,
}
}
}
use middle::resolve_lifetime;
use middle::infer;
use middle::stability;
-use middle::subst::{self, Subst, Substs, VecPerParamSpace};
+use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace};
use middle::traits;
use middle::ty;
use middle::ty_fold::{self, TypeFoldable, TypeFolder};
pub impl_trait_cache: RefCell<DefIdMap<Option<Rc<ty::TraitRef<'tcx>>>>>,
- pub trait_refs: RefCell<NodeMap<Rc<TraitRef<'tcx>>>>,
+ pub impl_trait_refs: RefCell<NodeMap<Rc<TraitRef<'tcx>>>>,
pub trait_defs: RefCell<DefIdMap<Rc<TraitDef<'tcx>>>>,
/// Maps from the def-id of an item (trait/struct/enum/fn) to its
pub def_id: ast::DefId,
pub space: subst::ParamSpace,
pub index: u32,
- pub bounds: ParamBounds<'tcx>,
pub default: Option<Ty<'tcx>>,
pub object_lifetime_default: Option<ObjectLifetimeDefault>,
}
pub fn mk_ctxt<'tcx>(s: Session,
arenas: &'tcx CtxtArenas<'tcx>,
- dm: DefMap,
+ def_map: DefMap,
named_region_map: resolve_lifetime::NamedRegionMap,
map: ast_map::Map<'tcx>,
freevars: RefCell<FreevarMap>,
item_variance_map: RefCell::new(DefIdMap()),
variance_computed: Cell::new(false),
sess: s,
- def_map: dm,
+ def_map: def_map,
region_maps: region_maps,
node_types: RefCell::new(FnvHashMap()),
item_substs: RefCell::new(NodeMap()),
- trait_refs: RefCell::new(NodeMap()),
+ impl_trait_refs: RefCell::new(NodeMap()),
trait_defs: RefCell::new(DefIdMap()),
predicates: RefCell::new(DefIdMap()),
object_cast_map: RefCell::new(NodeMap()),
{
self.closure_tys.borrow()[def_id].subst(self, substs)
}
+
+ pub fn type_parameter_def(&self,
+ node_id: ast::NodeId)
+ -> TypeParameterDef<'tcx>
+ {
+ self.ty_param_defs.borrow()[node_id].clone()
+ }
}
// Interns a type/name combination, stores the resulting box in cx.interner,
_ => None,
}
}
+
+ pub fn is_param(&self, space: ParamSpace, index: u32) -> bool {
+ match self.sty {
+ ty::ty_param(ref data) => data.space == space && data.idx == index,
+ _ => false,
+ }
+ }
}
pub fn walk_ty<'tcx, F>(ty_root: Ty<'tcx>, mut f: F)
}
}
-pub fn node_id_to_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId)
+pub fn impl_id_to_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId)
-> Rc<ty::TraitRef<'tcx>> {
- match cx.trait_refs.borrow().get(&id) {
+ match cx.impl_trait_refs.borrow().get(&id) {
Some(ty) => ty.clone(),
None => cx.sess.bug(
- &format!("node_id_to_trait_ref: no trait ref for node `{}`",
+ &format!("impl_id_to_trait_ref: no trait ref for impl `{}`",
cx.map.node_to_string(id)))
}
}
pub fn resolve_expr(tcx: &ctxt, expr: &ast::Expr) -> def::Def {
match tcx.def_map.borrow().get(&expr.id) {
- Some(&def) => def,
+ Some(def) => def.full_def(),
None => {
tcx.sess.span_bug(expr.span, &format!(
"no def-map entry for expr {}", expr.id));
}
match expr.node {
- ast::ExprPath(_) | ast::ExprQPath(_) => {
+ ast::ExprPath(..) => {
match resolve_expr(tcx, expr) {
def::DefVariant(tid, vid, _) => {
let variant_info = enum_variant_with_id(tcx, tid, vid);
def::DefFn(_, true) => RvalueDpsExpr,
// Fn pointers are just scalar values.
- def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) => RvalueDatumExpr,
+ def::DefFn(..) | def::DefMethod(..) => RvalueDatumExpr,
// Note: there is actually a good case to be made that
// DefArg's, particularly those of immediate type, ought to
ast::ExprBox(Some(ref place), _) => {
// Special case `Box<T>` for now:
- let definition = match tcx.def_map.borrow().get(&place.id) {
- Some(&def) => def,
+ let def_id = match tcx.def_map.borrow().get(&place.id) {
+ Some(def) => def.def_id(),
None => panic!("no def for place"),
};
- let def_id = definition.def_id();
if tcx.lang_items.exchange_heap() == Some(def_id) {
RvalueDatumExpr
} else {
memoized(&cx.impl_trait_cache, id, |id: ast::DefId| {
if id.krate == ast::LOCAL_CRATE {
debug!("(impl_trait_ref) searching for trait impl {:?}", id);
- match cx.map.find(id.node) {
- Some(ast_map::NodeItem(item)) => {
- match item.node {
- ast::ItemImpl(_, _, _, ref opt_trait, _, _) => {
- match opt_trait {
- &Some(ref t) => {
- let trait_ref = ty::node_id_to_trait_ref(cx, t.ref_id);
- Some(trait_ref)
- }
- &None => None
- }
- }
- ast::ItemDefaultImpl(_, ref ast_trait_ref) => {
- Some(ty::node_id_to_trait_ref(cx, ast_trait_ref.ref_id))
- }
- _ => None
+ if let Some(ast_map::NodeItem(item)) = cx.map.find(id.node) {
+ match item.node {
+ ast::ItemImpl(_, _, _, Some(_), _, _) |
+ ast::ItemDefaultImpl(..) => {
+ Some(ty::impl_id_to_trait_ref(cx, id.node))
}
+ _ => None
}
- _ => None
+ } else {
+ None
}
} else {
csearch::get_impl_trait(cx, id)
}
pub fn trait_ref_to_def_id(tcx: &ctxt, tr: &ast::TraitRef) -> ast::DefId {
- let def = *tcx.def_map.borrow()
- .get(&tr.ref_id)
- .expect("no def-map entry for trait");
- def.def_id()
+ tcx.def_map.borrow().get(&tr.ref_id).expect("no def-map entry for trait").def_id()
}
pub fn try_add_builtin_trait(
}
Err(_) => {
let found = match count_expr.node {
- ast::ExprPath(ast::Path {
+ ast::ExprPath(None, ast::Path {
global: false,
ref segments,
..
def_id: self.def_id,
space: self.space,
index: self.index,
- bounds: self.bounds.fold_with(folder),
default: self.default.fold_with(folder),
object_lifetime_default: self.object_lifetime_default.fold_with(folder),
}
use plugin::registry::Registry;
use std::mem;
-use std::env;
+use std::os;
use std::dynamic_lib::DynamicLibrary;
use std::borrow::ToOwned;
use syntax::ast;
path: Path,
symbol: String) -> PluginRegistrarFun {
// Make sure the path contains a / or the linker will search for it.
- let path = env::current_dir().unwrap().join(&path);
+ let path = os::getcwd().unwrap().join(&path);
let lib = match DynamicLibrary::open(Some(&path)) {
Ok(lib) => lib,
pub test: bool,
pub parse_only: bool,
pub no_trans: bool,
+ pub treat_err_as_bug: bool,
pub no_analysis: bool,
pub debugging_opts: DebuggingOptions,
/// Whether to write dependency files. It's (enabled, optional filename).
test: false,
parse_only: false,
no_trans: false,
+ treat_err_as_bug: false,
no_analysis: false,
debugging_opts: basic_debugging_options(),
write_dependency_info: (false, None),
"Parse only; do not compile, assemble, or link"),
no_trans: bool = (false, parse_bool,
"Run all passes except translation; no output"),
+ treat_err_as_bug: bool = (false, parse_bool,
+ "Treat all errors that occur as bugs"),
no_analysis: bool = (false, parse_bool,
"Parse and expand the source, but run no analysis"),
extra_plugins: Vec<String> = (Vec::new(), parse_list,
let parse_only = debugging_opts.parse_only;
let no_trans = debugging_opts.no_trans;
+ let treat_err_as_bug = debugging_opts.treat_err_as_bug;
let no_analysis = debugging_opts.no_analysis;
if debugging_opts.debug_llvm {
test: test,
parse_only: parse_only,
no_trans: no_trans,
+ treat_err_as_bug: treat_err_as_bug,
no_analysis: no_analysis,
debugging_opts: debugging_opts,
write_dependency_info: write_dependency_info,
use rustc_back::target::Target;
-use std::env;
use std::cell::{Cell, RefCell};
+use std::os;
pub mod config;
pub mod search_paths;
self.diagnostic().handler().fatal(msg)
}
pub fn span_err(&self, sp: Span, msg: &str) {
+ if self.opts.treat_err_as_bug {
+ self.span_bug(sp, msg);
+ }
match split_msg_into_multilines(msg) {
Some(msg) => self.diagnostic().span_err(sp, &msg[..]),
None => self.diagnostic().span_err(sp, msg)
}
}
pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) {
+ if self.opts.treat_err_as_bug {
+ self.span_bug(sp, msg);
+ }
match split_msg_into_multilines(msg) {
Some(msg) => self.diagnostic().span_err_with_code(sp, &msg[..], code),
None => self.diagnostic().span_err_with_code(sp, msg, code)
}
}
pub fn err(&self, msg: &str) {
+ if self.opts.treat_err_as_bug {
+ self.bug(msg);
+ }
self.diagnostic().handler().err(msg)
}
pub fn err_count(&self) -> uint {
if path.is_absolute() {
path.clone()
} else {
- env::current_dir().unwrap().join(&path)
+ os::getcwd().unwrap().join(&path)
}
);
plugin_registrar_fn: Cell::new(None),
default_sysroot: default_sysroot,
local_crate_source_file: local_crate_source_file,
- working_dir: env::current_dir().unwrap(),
+ working_dir: os::getcwd().unwrap(),
lint_store: RefCell::new(lint::LintStore::new()),
lints: RefCell::new(NodeMap()),
crate_types: RefCell::new(Vec::new()),
use std::old_io::process::{Command, ProcessOutput};
use std::old_io::{fs, TempDir};
use std::old_io;
-use std::env;
+use std::os;
use std::str;
use syntax::diagnostic::Handler as ErrorHandler;
pub fn build(self) -> Archive<'a> {
// Get an absolute path to the destination, so `ar` will work even
// though we run it from `self.work_dir`.
- let abs_dst = env::current_dir().unwrap().join(&self.archive.dst);
+ let abs_dst = os::getcwd().unwrap().join(&self.archive.dst);
assert!(!abs_dst.is_relative());
let mut args = vec![&abs_dst];
let mut total_len = abs_dst.as_vec().len();
// First, extract the contents of the archive to a temporary directory.
// We don't unpack directly into `self.work_dir` due to the possibility
// of filename collisions.
- let archive = env::current_dir().unwrap().join(archive);
+ let archive = os::getcwd().unwrap().join(archive);
run_ar(self.archive.handler, &self.archive.maybe_ar_prog,
"x", Some(loc.path()), &[&archive]);
use std::old_io;
use std::old_io::fs;
-use std::env;
+use std::os;
/// Returns an absolute path in the filesystem that `path` points to. The
/// returned path does not contain any symlinks in its hierarchy.
pub fn realpath(original: &Path) -> old_io::IoResult<Path> {
static MAX_LINKS_FOLLOWED: uint = 256;
- let original = try!(env::current_dir()).join(original);
+ let original = try!(os::getcwd()).join(original);
// Right now lstat on windows doesn't work quite well
if cfg!(windows) {
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(env)]
+#![feature(path)]
extern crate syntax;
extern crate serialize;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
use std::collections::HashSet;
use std::env;
use std::old_io::IoError;
+use std::os;
use syntax::ast;
pub struct RPathConfig<F, G> where
"$ORIGIN"
};
- let cwd = env::current_dir().unwrap();
+ let cwd = os::getcwd().unwrap();
let mut lib = (config.realpath)(&cwd.join(lib)).unwrap();
lib.pop();
let mut output = (config.realpath)(&cwd.join(&config.out_filename)).unwrap();
let path = (config.get_install_prefix_lib_path)();
let path = env::current_dir().unwrap().join(&path);
// FIXME (#9639): This needs to handle non-utf8 paths
- path.as_str().expect("non-utf8 component in rpath").to_string()
+ path.to_str().expect("non-utf8 component in rpath").to_string()
}
fn minimize_rpaths(rpaths: &[String]) -> Vec<String> {
SawExprAssignOp(ast::BinOp_),
SawExprIndex,
SawExprRange,
- SawExprPath,
- SawExprQPath,
+ SawExprPath(Option<usize>),
SawExprAddrOf(ast::Mutability),
SawExprRet,
SawExprInlineAsm(&'a ast::InlineAsm),
ExprTupField(_, id) => SawExprTupField(id.node),
ExprIndex(..) => SawExprIndex,
ExprRange(..) => SawExprRange,
- ExprPath(..) => SawExprPath,
- ExprQPath(..) => SawExprQPath,
+ ExprPath(ref qself, _) => SawExprPath(qself.as_ref().map(|q| q.position)),
ExprAddrOf(m, _) => SawExprAddrOf(m),
ExprBreak(id) => SawExprBreak(id.map(content)),
ExprAgain(id) => SawExprAgain(id.map(content)),
/// JSON decoding.
pub fn search(target: &str) -> Result<Target, String> {
use std::env;
+ use std::os;
use std::ffi::OsString;
use std::old_io::File;
use std::old_path::Path;
// FIXME 16351: add a sane default search path?
- for dir in env::split_paths(&target_path) {
+ for dir in os::split_paths(target_path.to_str().unwrap()).iter() {
let p = dir.join(path.clone());
if p.is_file() {
return load_file(&p);
ast::ItemConst(_, ref ex) => {
gather_loans::gather_loans_in_static_initializer(this, &**ex);
}
- _ => {
- visit::walk_item(this, item);
- }
+ _ => { }
}
+
+ visit::walk_item(this, item);
}
/// Collection of conclusions determined via borrow checker analyses.
use serialize::json;
use std::env;
+use std::os;
use std::ffi::OsString;
use std::old_io::fs;
use std::old_io;
if cfg!(windows) {
_old_path = env::var_os("PATH").unwrap_or(_old_path);
let mut new_path = sess.host_filesearch(PathKind::All).get_dylib_search_paths();
- new_path.extend(env::split_paths(&_old_path));
+ new_path.extend(os::split_paths(_old_path.to_str().unwrap()).into_iter());
env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap());
}
let features = sess.features.borrow();
export_map,
trait_map,
external_exports,
- last_private_map,
glob_map,
} =
time(time_passes, "resolution", (),
time(time_passes, "const checking", (), |_|
middle::check_const::check_crate(&ty_cx));
- let maps = (external_exports, last_private_map);
let (exported_items, public_items) =
- time(time_passes, "privacy checking", maps, |(a, b)|
- rustc_privacy::check_crate(&ty_cx, &export_map, a, b));
+ time(time_passes, "privacy checking", (), |_|
+ rustc_privacy::check_crate(&ty_cx, &export_map, external_exports));
// Do not move this check past lint
time(time_passes, "stability index", (), |_|
outputs: &OutputFilenames) {
let old_path = env::var_os("PATH").unwrap_or(OsString::from_str(""));
let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths();
- new_path.extend(env::split_paths(&old_path));
+ new_path.extend(os::split_paths(old_path.to_str().unwrap()).into_iter());
env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap());
time(sess.time_passes(), "linking", (), |_|
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!(vec!(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),
+ 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);
})
}
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
-#![feature(core)]
#![feature(int_uint)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
use rustc::middle::privacy::ImportUse::*;
use rustc::middle::privacy::LastPrivate::*;
use rustc::middle::privacy::PrivateDep::*;
-use rustc::middle::privacy::{ExportedItems, PublicItems, LastPrivateMap};
-use rustc::middle::privacy::{ExternalExports};
+use rustc::middle::privacy::{ExternalExports, ExportedItems, PublicItems};
use rustc::middle::ty::{MethodTypeParam, MethodStatic};
use rustc::middle::ty::{MethodCall, MethodMap, MethodOrigin, MethodParam};
use rustc::middle::ty::{MethodStaticClosure, MethodObject};
// * Private trait impls for private types can be completely ignored
ast::ItemImpl(_, _, _, _, ref ty, ref impl_items) => {
let public_ty = match ty.node {
- ast::TyPath(_, id) => {
- match self.tcx.def_map.borrow()[id].clone() {
+ ast::TyPath(..) => {
+ match self.tcx.def_map.borrow()[ty.id].full_def() {
def::DefPrimTy(..) => true,
def => {
let did = def.def_id();
}
ast::ItemTy(ref ty, _) if public_first => {
- if let ast::TyPath(_, id) = ty.node {
- match self.tcx.def_map.borrow()[id].clone() {
+ if let ast::TyPath(..) = ty.node {
+ match self.tcx.def_map.borrow()[ty.id].full_def() {
def::DefPrimTy(..) | def::DefTyParam(..) => {},
def => {
let did = def.def_id();
in_foreign: bool,
parents: NodeMap<ast::NodeId>,
external_exports: ExternalExports,
- last_private_map: LastPrivateMap,
}
enum PrivacyResult {
// back up the chains to find the relevant struct/enum that
// was private.
ast::ItemImpl(_, _, _, _, ref ty, _) => {
- let id = match ty.node {
- ast::TyPath(_, id) => id,
+ match ty.node {
+ ast::TyPath(..) => {}
_ => return Some((err_span, err_msg, None)),
};
- let def = self.tcx.def_map.borrow()[id].clone();
+ let def = self.tcx.def_map.borrow()[ty.id].full_def();
let did = def.def_id();
assert!(is_local(did));
match self.tcx.map.get(did.node) {
}
// Checks that a path is in scope.
- fn check_path(&mut self, span: Span, path_id: ast::NodeId, path: &ast::Path) {
+ fn check_path(&mut self, span: Span, path_id: ast::NodeId, last: ast::Ident) {
debug!("privacy - path {}", self.nodestr(path_id));
- let orig_def = self.tcx.def_map.borrow()[path_id].clone();
+ let path_res = self.tcx.def_map.borrow()[path_id];
let ck = |tyname: &str| {
let ck_public = |def: ast::DefId| {
debug!("privacy - ck_public {:?}", def);
- let name = token::get_ident(path.segments.last().unwrap().identifier);
- let origdid = orig_def.def_id();
+ let name = token::get_ident(last);
+ let origdid = path_res.def_id();
self.ensure_public(span,
def,
Some(origdid),
&format!("{} `{}`", tyname, name))
};
- match self.last_private_map[path_id] {
+ match path_res.last_private {
LastMod(AllPublic) => {},
LastMod(DependsOn(def)) => {
self.report_error(ck_public(def));
// def map is not. Therefore the names we work out below will not always
// be accurate and we can get slightly wonky error messages (but type
// checking is always correct).
- match self.tcx.def_map.borrow()[path_id].clone() {
- def::DefStaticMethod(..) => ck("static method"),
+ match path_res.full_def() {
def::DefFn(..) => ck("function"),
def::DefStatic(..) => ck("static"),
def::DefConst(..) => ck("const"),
def::DefVariant(..) => ck("variant"),
def::DefTy(_, false) => ck("type"),
def::DefTy(_, true) => ck("enum"),
- def::DefaultImpl(..) => ck("trait"),
+ def::DefTrait(..) => ck("trait"),
def::DefStruct(..) => ck("struct"),
- def::DefMethod(_, Some(..), _) => ck("trait method"),
def::DefMethod(..) => ck("method"),
def::DefMod(..) => ck("module"),
_ => {}
impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
fn visit_item(&mut self, item: &ast::Item) {
- match item.node {
- ast::ItemUse(ref vpath) => {
- match vpath.node {
- ast::ViewPathSimple(..) | ast::ViewPathGlob(..) => {}
- ast::ViewPathList(ref prefix, ref list) => {
- for pid in list {
- match pid.node {
- ast::PathListIdent { id, name } => {
- debug!("privacy - ident item {}", id);
- let seg = ast::PathSegment {
- identifier: name,
- parameters: ast::PathParameters::none(),
- };
- let segs = vec![seg];
- let path = ast::Path {
- global: false,
- span: pid.span,
- segments: segs,
- };
- self.check_path(pid.span, id, &path);
- }
- ast::PathListMod { id } => {
- debug!("privacy - mod item {}", id);
- self.check_path(pid.span, id, prefix);
- }
- }
+ if let ast::ItemUse(ref vpath) = item.node {
+ if let ast::ViewPathList(ref prefix, ref list) = vpath.node {
+ for pid in list {
+ match pid.node {
+ ast::PathListIdent { id, name } => {
+ debug!("privacy - ident item {}", id);
+ self.check_path(pid.span, id, name);
+ }
+ ast::PathListMod { id } => {
+ debug!("privacy - mod item {}", id);
+ let name = prefix.segments.last().unwrap().identifier;
+ self.check_path(pid.span, id, name);
}
}
}
}
- _ => {}
}
let orig_curitem = replace(&mut self.curitem, item.id);
visit::walk_item(self, item);
}
}
ty::ty_enum(_, _) => {
- match self.tcx.def_map.borrow()[expr.id].clone() {
+ match self.tcx.def_map.borrow()[expr.id].full_def() {
def::DefVariant(_, variant_id, _) => {
for field in fields {
self.check_field(expr.span, variant_id,
struct type?!"),
}
}
- ast::ExprPath(_) | ast::ExprQPath(_) => {
+ ast::ExprPath(..) => {
let guard = |did: ast::DefId| {
let fields = ty::lookup_struct_fields(self.tcx, did);
let any_priv = fields.iter().any(|f| {
with private fields");
}
};
- match self.tcx.def_map.borrow().get(&expr.id) {
- Some(&def::DefStruct(did)) => {
+ match self.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) {
+ Some(def::DefStruct(did)) => {
guard(if is_local(did) {
local_def(self.tcx.map.get_parent(did.node))
} else {
}
}
ty::ty_enum(_, _) => {
- match self.tcx.def_map.borrow().get(&pattern.id) {
- Some(&def::DefVariant(_, variant_id, _)) => {
+ match self.tcx.def_map.borrow().get(&pattern.id).map(|d| d.full_def()) {
+ Some(def::DefVariant(_, variant_id, _)) => {
for field in fields {
self.check_field(pattern.span, variant_id,
NamedField(field.node.ident.name));
}
fn visit_path(&mut self, path: &ast::Path, id: ast::NodeId) {
- self.check_path(path.span, id, path);
+ self.check_path(path.span, id, path.segments.last().unwrap().identifier);
visit::walk_path(self, path);
}
}
impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> {
fn path_is_private_type(&self, path_id: ast::NodeId) -> bool {
- let did = match self.tcx.def_map.borrow().get(&path_id).cloned() {
+ let did = match self.tcx.def_map.borrow().get(&path_id).map(|d| d.full_def()) {
// `int` etc. (None doesn't seem to occur.)
None | Some(def::DefPrimTy(..)) => return false,
Some(def) => def.def_id()
impl<'a, 'b, 'tcx, 'v> Visitor<'v> for CheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> {
fn visit_ty(&mut self, ty: &ast::Ty) {
- if let ast::TyPath(_, path_id) = ty.node {
- if self.inner.path_is_private_type(path_id) {
+ if let ast::TyPath(..) = ty.node {
+ if self.inner.path_is_private_type(ty.id) {
self.contains_private = true;
// found what we're looking for so let's stop
// working.
//
// Those in 2. are warned via walk_generics and this
// call here.
- self.visit_trait_ref(tr)
+ visit::walk_path(self, &tr.path);
}
}
} else if trait_ref.is_none() && self_is_public_path {
}
fn visit_ty(&mut self, t: &ast::Ty) {
- if let ast::TyPath(ref p, path_id) = t.node {
+ if let ast::TyPath(_, ref p) = t.node {
if !self.tcx.sess.features.borrow().visible_private_types &&
- self.path_is_private_type(path_id) {
+ self.path_is_private_type(t.id) {
self.tcx.sess.span_err(p.span,
"private type in exported type signature");
}
pub fn check_crate(tcx: &ty::ctxt,
export_map: &def::ExportMap,
- external_exports: ExternalExports,
- last_private_map: LastPrivateMap)
+ external_exports: ExternalExports)
-> (ExportedItems, PublicItems) {
let krate = tcx.map.krate();
tcx: tcx,
parents: visitor.parents,
external_exports: external_exports,
- last_private_map: last_private_map,
};
visit::walk_crate(&mut visitor, krate);
use NameBindings;
use ParentLink::{self, ModuleParentLink, BlockParentLink};
use Resolver;
-use RibKind::*;
use Shadowable;
use TypeNsDef;
-use TypeParameters::HasTypeParameters;
use self::DuplicateCheckingMode::*;
use self::NamespaceError::*;
use rustc::metadata::csearch;
use rustc::metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
use rustc::middle::def::*;
-use rustc::middle::subst::FnSpace;
use syntax::ast::{Block, Crate};
use syntax::ast::{DeclItem, DefId};
use syntax::ast::{Item, ItemConst, ItemEnum, ItemExternCrate, ItemFn};
use syntax::ast::{ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl};
use syntax::ast::{ItemStruct, ItemTrait, ItemTy, ItemUse};
-use syntax::ast::{MethodImplItem, Name, NamedField, NodeId};
-use syntax::ast::{PathListIdent, PathListMod};
-use syntax::ast::{Public, SelfStatic};
+use syntax::ast::{Name, NamedField, NodeId};
+use syntax::ast::{PathListIdent, PathListMod, Public};
use syntax::ast::StmtDecl;
use syntax::ast::StructVariantKind;
use syntax::ast::TupleVariantKind;
-use syntax::ast::TyObjectSum;
-use syntax::ast::{TypeImplItem, UnnamedField};
+use syntax::ast::UnnamedField;
use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
use syntax::ast::{Visibility};
-use syntax::ast::TyPath;
use syntax::ast;
-use syntax::ast_util::{self, PostExpansionMethod, local_def};
+use syntax::ast_util::{self, local_def};
use syntax::attr::AttrMetaMethods;
use syntax::parse::token::{self, special_idents};
use syntax::codemap::{Span, DUMMY_SP};
Some(TypeNS)
}
ForbidDuplicateTypesAndModules => {
- match child.def_for_namespace(TypeNS) {
- None => {}
- Some(_) if child.get_module_if_available()
- .map(|m| m.kind.get()) ==
- Some(ImplModuleKind) => {}
- Some(_) => duplicate_type = TypeError
+ if child.defined_in_namespace(TypeNS) {
+ duplicate_type = TypeError;
}
Some(TypeNS)
}
name_bindings.define_type(DefTy(local_def(item.id), true), sp, modifiers);
let parent_link = self.get_parent_link(parent, name);
- // We want to make sure the module type is EnumModuleKind
- // even if there's already an ImplModuleKind module defined,
- // since that's how we prevent duplicate enum definitions
name_bindings.set_module_kind(parent_link,
Some(local_def(item.id)),
EnumModuleKind,
parent.clone()
}
- ItemImpl(_, _, _, None, ref ty, ref impl_items) => {
- // If this implements an anonymous trait, then add all the
- // methods within to a new module, if the type was defined
- // within this module.
-
- let mod_name = match ty.node {
- TyPath(ref path, _) if path.segments.len() == 1 => {
- // FIXME(18446) we should distinguish between the name of
- // a trait and the name of an impl of that trait.
- Some(path.segments.last().unwrap().identifier.name)
- }
- TyObjectSum(ref lhs_ty, _) => {
- match lhs_ty.node {
- TyPath(ref path, _) if path.segments.len() == 1 => {
- Some(path.segments.last().unwrap().identifier.name)
- }
- _ => {
- None
- }
- }
- }
- _ => {
- None
- }
- };
-
- let mod_name = match mod_name {
- Some(mod_name) => mod_name,
- None => {
- self.resolve_error(ty.span,
- "inherent implementations may \
- only be implemented in the same \
- module as the type they are \
- implemented for");
- return parent.clone();
- }
- };
- // Create the module and add all methods.
- let child_opt = parent.children.borrow().get(&mod_name)
- .and_then(|m| m.get_module_if_available());
- let new_parent = match child_opt {
- // It already exists
- Some(ref child) if (child.kind.get() == ImplModuleKind ||
- child.kind.get() == TraitModuleKind) => {
- child.clone()
- }
- Some(ref child) if child.kind.get() == EnumModuleKind ||
- child.kind.get() == TypeModuleKind => {
- child.clone()
- }
- // Create the module
- _ => {
- let name_bindings =
- self.add_child(mod_name, parent, ForbidDuplicateModules, sp);
-
- let parent_link = self.get_parent_link(parent, name);
- let def_id = local_def(item.id);
- let ns = TypeNS;
- let is_public =
- !name_bindings.defined_in_namespace(ns) ||
- name_bindings.defined_in_public_namespace(ns);
-
- name_bindings.define_module(parent_link,
- Some(def_id),
- ImplModuleKind,
- false,
- is_public,
- sp);
-
- name_bindings.get_module()
- }
- };
-
- // For each implementation item...
- for impl_item in impl_items {
- match *impl_item {
- MethodImplItem(ref method) => {
- // Add the method to the module.
- let name = method.pe_ident().name;
- let method_name_bindings =
- self.add_child(name,
- &new_parent,
- ForbidDuplicateValues,
- method.span);
- let def = match method.pe_explicit_self()
- .node {
- SelfStatic => {
- // Static methods become
- // `DefStaticMethod`s.
- DefStaticMethod(local_def(method.id),
- FromImpl(local_def(item.id)))
- }
- _ => {
- // Non-static methods become
- // `DefMethod`s.
- DefMethod(local_def(method.id),
- None,
- FromImpl(local_def(item.id)))
- }
- };
-
- // NB: not IMPORTABLE
- let modifiers = if method.pe_vis() == ast::Public {
- PUBLIC
- } else {
- DefModifiers::empty()
- };
- method_name_bindings.define_value(
- def,
- method.span,
- modifiers);
- }
- TypeImplItem(ref typedef) => {
- // Add the typedef to the module.
- let name = typedef.ident.name;
- let typedef_name_bindings =
- self.add_child(
- name,
- &new_parent,
- ForbidDuplicateTypesAndModules,
- typedef.span);
- let def = DefAssociatedTy(local_def(
- typedef.id));
- // NB: not IMPORTABLE
- let modifiers = if typedef.vis == ast::Public {
- PUBLIC
- } else {
- DefModifiers::empty()
- };
- typedef_name_bindings.define_type(
- def,
- typedef.span,
- modifiers);
- }
- }
- }
- parent.clone()
- }
-
ItemDefaultImpl(_, _) |
- ItemImpl(_, _, _, Some(_), _, _) => parent.clone(),
+ ItemImpl(..) => parent.clone(),
ItemTrait(_, _, _, ref items) => {
let name_bindings =
// Add the names of all the items to the trait info.
for trait_item in items {
- let (name, kind) = match *trait_item {
+ let (name, trait_item_id) = match *trait_item {
ast::RequiredMethod(_) |
ast::ProvidedMethod(_) => {
let ty_m = ast_util::trait_item_to_ty_method(trait_item);
let name = ty_m.ident.name;
// Add it as a name in the trait module.
- let (def, static_flag) = match ty_m.explicit_self
- .node {
- SelfStatic => {
- // Static methods become `DefStaticMethod`s.
- (DefStaticMethod(
- local_def(ty_m.id),
- FromTrait(local_def(item.id))),
- StaticMethodTraitItemKind)
- }
- _ => {
- // Non-static methods become `DefMethod`s.
- (DefMethod(local_def(ty_m.id),
- Some(local_def(item.id)),
- FromTrait(local_def(item.id))),
- NonstaticMethodTraitItemKind)
- }
- };
+ let def = DefMethod(local_def(ty_m.id),
+ FromTrait(local_def(item.id)));
let method_name_bindings =
self.add_child(name,
ty_m.span,
PUBLIC);
- (name, static_flag)
+ (name, local_def(ty_m.id))
}
ast::TypeTraitItem(ref associated_type) => {
- let def = DefAssociatedTy(local_def(
- associated_type.ty_param.id));
+ let def = DefAssociatedTy(local_def(item.id),
+ local_def(associated_type.ty_param.id));
let name_bindings =
self.add_child(associated_type.ty_param.ident.name,
associated_type.ty_param.span,
PUBLIC);
- (associated_type.ty_param.ident.name, TypeTraitItemKind)
+ (associated_type.ty_param.ident.name,
+ local_def(associated_type.ty_param.id))
}
};
- self.trait_item_map.insert((name, def_id), kind);
+ self.trait_item_map.insert((name, def_id), trait_item_id);
}
- name_bindings.define_type(DefaultImpl(def_id), sp, modifiers);
+ name_bindings.define_type(DefTrait(def_id), sp, modifiers);
parent.clone()
}
ItemMac(..) => parent.clone()
}
/// Constructs the reduced graph for one foreign item.
- fn build_reduced_graph_for_foreign_item<F>(&mut self,
- foreign_item: &ForeignItem,
- parent: &Rc<Module>,
- f: F) where
- F: FnOnce(&mut Resolver),
- {
+ fn build_reduced_graph_for_foreign_item(&mut self,
+ foreign_item: &ForeignItem,
+ parent: &Rc<Module>) {
let name = foreign_item.ident.name;
let is_public = foreign_item.vis == ast::Public;
let modifiers = if is_public { PUBLIC } else { DefModifiers::empty() } | IMPORTABLE;
self.add_child(name, parent, ForbidDuplicateValues,
foreign_item.span);
- match foreign_item.node {
- ForeignItemFn(_, ref generics) => {
- let def = DefFn(local_def(foreign_item.id), false);
- name_bindings.define_value(def, foreign_item.span, modifiers);
-
- self.with_type_parameter_rib(
- HasTypeParameters(generics,
- FnSpace,
- foreign_item.id,
- NormalRibKind),
- f);
+ let def = match foreign_item.node {
+ ForeignItemFn(..) => {
+ DefFn(local_def(foreign_item.id), false)
}
ForeignItemStatic(_, m) => {
- let def = DefStatic(local_def(foreign_item.id), m);
- name_bindings.define_value(def, foreign_item.span, modifiers);
-
- f(self.resolver)
+ DefStatic(local_def(foreign_item.id), m)
}
- }
+ };
+ name_bindings.define_value(def, foreign_item.span, modifiers);
}
fn build_reduced_graph_for_block(&mut self, block: &Block, parent: &Rc<Module>) -> Rc<Module> {
let kind = match def {
DefTy(_, true) => EnumModuleKind,
- DefTy(_, false) => TypeModuleKind,
- DefStruct(..) => ImplModuleKind,
+ DefTy(_, false) | DefStruct(..) => TypeModuleKind,
_ => NormalModuleKind
};
csearch::get_tuple_struct_definition_if_ctor(&self.session.cstore, ctor_id)
.map_or(def, |_| DefStruct(ctor_id)), DUMMY_SP, modifiers);
}
- DefFn(..) | DefStaticMethod(..) | DefStatic(..) | DefConst(..) | DefMethod(..) => {
+ DefFn(..) | DefStatic(..) | DefConst(..) | DefMethod(..) => {
debug!("(building reduced graph for external \
crate) building value (fn/static) {}", final_ident);
// impl methods have already been defined with the correct importability modifier
}
child_name_bindings.define_value(def, DUMMY_SP, modifiers);
}
- DefaultImpl(def_id) => {
+ DefTrait(def_id) => {
debug!("(building reduced graph for external \
crate) building type {}", final_ident);
let trait_item_def_ids =
csearch::get_trait_item_def_ids(&self.session.cstore, def_id);
- for trait_item_def_id in &trait_item_def_ids {
- let (trait_item_name, trait_item_kind) =
- csearch::get_trait_item_name_and_kind(
- &self.session.cstore,
- trait_item_def_id.def_id());
+ for trait_item_def in &trait_item_def_ids {
+ let trait_item_name = csearch::get_trait_name(&self.session.cstore,
+ trait_item_def.def_id());
debug!("(building reduced graph for external crate) ... \
adding trait item '{}'",
token::get_name(trait_item_name));
- self.trait_item_map.insert((trait_item_name, def_id), trait_item_kind);
+ self.trait_item_map.insert((trait_item_name, def_id),
+ trait_item_def.def_id());
if is_exported {
- self.external_exports
- .insert(trait_item_def_id.def_id());
+ self.external_exports.insert(trait_item_def.def_id());
}
}
is_public,
DUMMY_SP)
}
- DefTy(..) | DefAssociatedTy(..) | DefAssociatedPath(..) => {
+ DefTy(..) | DefAssociatedTy(..) => {
debug!("(building reduced graph for external \
crate) building type {}", final_ident);
}
DefLocal(..) | DefPrimTy(..) | DefTyParam(..) |
DefUse(..) | DefUpvar(..) | DefRegion(..) |
- DefTyParamBinder(..) | DefLabel(..) | DefSelfTy(..) => {
+ DefLabel(..) | DefSelfTy(..) => {
panic!("didn't expect `{:?}`", def);
}
}
}
}
}
- DlImpl(def) => {
- match csearch::get_type_name_if_impl(&self.session.cstore, def) {
- None => {}
- Some(final_name) => {
- let methods_opt =
- csearch::get_methods_if_impl(&self.session.cstore, def);
- match methods_opt {
- Some(ref methods) if
- methods.len() >= 1 => {
- debug!("(building reduced graph for \
- external crate) processing \
- static methods for type name {}",
- token::get_name(final_name));
-
- let child_name_bindings =
- self.add_child(
- final_name,
- root,
- OverwriteDuplicates,
- DUMMY_SP);
-
- // Process the static methods. First,
- // create the module.
- let type_module;
- let type_def = child_name_bindings.type_def.borrow().clone();
- match type_def {
- Some(TypeNsDef {
- module_def: Some(module_def),
- ..
- }) => {
- // We already have a module. This
- // is OK.
- type_module = module_def;
-
- // Mark it as an impl module if
- // necessary.
- type_module.kind.set(ImplModuleKind);
- }
- Some(_) | None => {
- let parent_link =
- self.get_parent_link(root, final_name);
- child_name_bindings.define_module(
- parent_link,
- Some(def),
- ImplModuleKind,
- true,
- true,
- DUMMY_SP);
- type_module =
- child_name_bindings.
- get_module();
- }
- }
-
- // Add each static method to the module.
- let new_parent = type_module;
- for method_info in methods {
- let name = method_info.name;
- debug!("(building reduced graph for \
- external crate) creating \
- static method '{}'",
- token::get_name(name));
-
- let method_name_bindings =
- self.add_child(name,
- &new_parent,
- OverwriteDuplicates,
- DUMMY_SP);
- let def = DefFn(method_info.def_id, false);
-
- // NB: not IMPORTABLE
- let modifiers = if method_info.vis == ast::Public {
- PUBLIC
- } else {
- DefModifiers::empty()
- };
- method_name_bindings.define_value(
- def, DUMMY_SP, modifiers);
- }
- }
-
- // Otherwise, do nothing.
- Some(_) | None => {}
- }
- }
- }
+ DlImpl(_) => {
+ debug!("(building reduced graph for external crate) \
+ ignoring impl");
}
DlField => {
debug!("(building reduced graph for external crate) \
}
fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
- let parent = &self.parent;
- self.builder.build_reduced_graph_for_foreign_item(foreign_item,
- parent,
- |r| {
- let mut v = BuildReducedGraphVisitor {
- builder: GraphBuilder { resolver: r },
- parent: parent.clone()
- };
- visit::walk_foreign_item(&mut v, foreign_item);
- })
+ self.builder.build_reduced_graph_for_foreign_item(foreign_item, &self.parent);
}
fn visit_block(&mut self, block: &Block) {
"unused import".to_string());
}
- let (v_priv, t_priv) = match self.last_private.get(&id) {
- Some(&LastImport {
- value_priv: v,
- value_used: _,
- type_priv: t,
- type_used: _
- }) => (v, t),
- Some(_) => {
+ let mut def_map = self.def_map.borrow_mut();
+ let path_res = if let Some(r) = def_map.get_mut(&id) {
+ r
+ } else {
+ return;
+ };
+ let (v_priv, t_priv) = match path_res.last_private {
+ LastImport { value_priv, type_priv, .. } => (value_priv, type_priv),
+ _ => {
panic!("we should only have LastImport for `use` directives")
}
- _ => return,
};
let mut v_used = if self.used_imports.contains(&(id, ValueNS)) {
_ => {},
}
- self.last_private.insert(id, LastImport{value_priv: v_priv,
- value_used: v_used,
- type_priv: t_priv,
- type_used: t_used});
+ path_res.last_private = LastImport {
+ value_priv: v_priv,
+ value_used: v_used,
+ type_priv: t_priv,
+ type_used: t_used
+ };
}
}
use self::FallbackSuggestion::*;
use self::TypeParameters::*;
use self::RibKind::*;
-use self::MethodSort::*;
use self::UseLexicalScopeFlag::*;
use self::ModulePrefixResult::*;
use self::NameSearchType::*;
use self::BareIdentifierPatternResolution::*;
use self::ParentLink::*;
use self::ModuleKind::*;
-use self::TraitReferenceType::*;
use self::FallbackChecks::*;
use rustc::session::Session;
use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate, CrateNum};
use syntax::ast::{DefId, Expr, ExprAgain, ExprBreak, ExprField};
-use syntax::ast::{ExprClosure, ExprLoop, ExprWhile, ExprMethodCall};
-use syntax::ast::{ExprPath, ExprQPath, ExprStruct, FnDecl};
+use syntax::ast::{ExprLoop, ExprWhile, ExprMethodCall};
+use syntax::ast::{ExprPath, ExprStruct, FnDecl};
use syntax::ast::{ForeignItemFn, ForeignItemStatic, Generics};
use syntax::ast::{Ident, ImplItem, Item, ItemConst, ItemEnum, ItemExternCrate};
use syntax::ast::{ItemFn, ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl};
use syntax::ast::{ItemStruct, ItemTrait, ItemTy, ItemUse};
-use syntax::ast::{Local, MethodImplItem, Mod, Name, NodeId};
+use syntax::ast::{Local, MethodImplItem, Name, NodeId};
use syntax::ast::{Pat, PatEnum, PatIdent, PatLit};
-use syntax::ast::{PatRange, PatStruct, Path};
-use syntax::ast::{PolyTraitRef, PrimTy, SelfExplicit};
-use syntax::ast::{RegionTyParamBound, StructField};
-use syntax::ast::{TraitRef, TraitTyParamBound};
-use syntax::ast::{Ty, TyBool, TyChar, TyF32};
-use syntax::ast::{TyF64, TyFloat, TyIs, TyI8, TyI16, TyI32, TyI64, TyInt, TyObjectSum};
-use syntax::ast::{TyParam, TyParamBound, TyPath, TyPtr, TyPolyTraitRef, TyQPath};
+use syntax::ast::{PatRange, PatStruct, Path, PrimTy};
+use syntax::ast::{TraitRef, Ty, TyBool, TyChar, TyF32};
+use syntax::ast::{TyF64, TyFloat, TyIs, TyI8, TyI16, TyI32, TyI64, TyInt};
+use syntax::ast::{TyPath, TyPtr};
use syntax::ast::{TyRptr, TyStr, TyUs, TyU8, TyU16, TyU32, TyU64, TyUint};
use syntax::ast::{TypeImplItem};
use syntax::ast;
use syntax::attr::AttrMetaMethods;
use syntax::ext::mtwt;
use syntax::parse::token::{self, special_names, special_idents};
-use syntax::codemap::{Span, Pos};
-use syntax::owned_slice::OwnedSlice;
+use syntax::codemap::{self, Span, Pos};
use syntax::visit::{self, Visitor};
use std::collections::{HashMap, HashSet};
fn visit_ty(&mut self, ty: &Ty) {
self.resolve_type(ty);
}
+ fn visit_generics(&mut self, generics: &Generics) {
+ self.resolve_generics(generics);
+ }
+ fn visit_poly_trait_ref(&mut self,
+ tref: &ast::PolyTraitRef,
+ m: &ast::TraitBoundModifier) {
+ match self.resolve_trait_reference(tref.trait_ref.ref_id, &tref.trait_ref.path, 0) {
+ Ok(def) => self.record_def(tref.trait_ref.ref_id, def),
+ Err(_) => { /* error already reported */ }
+ }
+ visit::walk_poly_trait_ref(self, tref, m);
+ }
+ fn visit_variant(&mut self, variant: &ast::Variant, generics: &Generics) {
+ if let Some(ref dis_expr) = variant.node.disr_expr {
+ // resolve the discriminator expr as a constant
+ self.with_constant_rib(|this| {
+ this.visit_expr(&**dis_expr);
+ });
+ }
+
+ // `visit::walk_variant` without the discriminant expression.
+ match variant.node.kind {
+ ast::TupleVariantKind(ref variant_arguments) => {
+ for variant_argument in variant_arguments.iter() {
+ self.visit_ty(&*variant_argument.ty);
+ }
+ }
+ ast::StructVariantKind(ref struct_definition) => {
+ self.visit_struct_def(&**struct_definition,
+ variant.node.name,
+ generics,
+ variant.node.id);
+ }
+ }
+ }
+ fn visit_foreign_item(&mut self, foreign_item: &ast::ForeignItem) {
+ let type_parameters = match foreign_item.node {
+ ForeignItemFn(_, ref generics) => {
+ HasTypeParameters(generics, FnSpace, ItemRibKind)
+ }
+ ForeignItemStatic(..) => NoTypeParameters
+ };
+ self.with_type_parameter_rib(type_parameters, |this| {
+ visit::walk_foreign_item(this, foreign_item);
+ });
+ }
+ fn visit_fn(&mut self,
+ function_kind: visit::FnKind<'v>,
+ declaration: &'v FnDecl,
+ block: &'v Block,
+ _: Span,
+ node_id: NodeId) {
+ let rib_kind = match function_kind {
+ visit::FkItemFn(_, generics, _, _) => {
+ self.visit_generics(generics);
+ ItemRibKind
+ }
+ visit::FkMethod(_, generics, method) => {
+ self.visit_generics(generics);
+ self.visit_explicit_self(method.pe_explicit_self());
+ MethodRibKind
+ }
+ visit::FkFnBlock(..) => ClosureRibKind(node_id)
+ };
+ self.resolve_function(rib_kind, declaration, block);
+ }
}
/// Contains data for specific types of import directives.
// were declared on (type, fn, etc)
ParamSpace,
- // ID of the enclosing item.
- NodeId,
-
// The kind of the rib used for type parameters.
RibKind)
}
// methods. Allow references to ty params that impl or trait
// binds. Disallow any other upvars (including other ty params that are
// upvars).
- // parent; method itself
- MethodRibKind(NodeId, MethodSort),
+ MethodRibKind,
// We passed through an item scope. Disallow upvars.
ItemRibKind,
ConstantItemRibKind
}
-// Methods can be required or provided. RequiredMethod methods only occur in traits.
-#[derive(Copy, Debug)]
-enum MethodSort {
- RequiredMethod,
- ProvidedMethod(NodeId)
-}
-
#[derive(Copy)]
enum UseLexicalScopeFlag {
DontUseLexicalScope,
enum ModuleKind {
NormalModuleKind,
TraitModuleKind,
- ImplModuleKind,
EnumModuleKind,
TypeModuleKind,
AnonymousModuleKind,
value_def: RefCell<Option<ValueNsDef>>, //< Meaning in value namespace.
}
-/// Ways in which a trait can be referenced
-#[derive(Copy)]
-enum TraitReferenceType {
- TraitImplementation, // impl SomeTrait for T { ... }
- TraitDerivation, // trait T : SomeTrait { ... }
- TraitBoundingTypeParameter, // fn f<T:SomeTrait>() { ... }
- TraitObject, // Box<for<'a> SomeTrait>
- TraitQPath, // <T as SomeTrait>::
-}
-
impl NameBindings {
fn new() -> NameBindings {
NameBindings {
graph_root: NameBindings,
- trait_item_map: FnvHashMap<(Name, DefId), TraitItemKind>,
+ trait_item_map: FnvHashMap<(Name, DefId), DefId>,
structs: FnvHashMap<DefId, Vec<Name>>,
export_map: ExportMap,
trait_map: TraitMap,
external_exports: ExternalExports,
- last_private: LastPrivateMap,
// Whether or not to print error messages. Can be set to true
// when getting additional info for error message suggestions,
used_imports: HashSet::new(),
used_crates: HashSet::new(),
external_exports: DefIdSet(),
- last_private: NodeMap(),
emit_errors: true,
make_glob_map: make_glob_map == MakeGlobMap::Yes,
result
}
- fn path_names_to_string(&self, path: &Path) -> String {
- let names: Vec<ast::Name> = path.segments
+ fn path_names_to_string(&self, path: &Path, depth: usize) -> String {
+ let names: Vec<ast::Name> = path.segments[..path.segments.len()-depth]
.iter()
.map(|seg| seg.identifier.name)
.collect();
// record what this import resolves to for later uses in documentation,
// this may resolve to either a value or a type, but for documentation
// purposes it's good enough to just favor one over the other.
- let value_private = match import_resolution.value_target {
- Some(ref target) => {
- let def = target.bindings.def_for_namespace(ValueNS).unwrap();
- self.def_map.borrow_mut().insert(directive.id, def);
- let did = def.def_id();
- if value_used_public {Some(lp)} else {Some(DependsOn(did))}
- },
- // AllPublic here and below is a dummy value, it should never be used because
- // _exists is false.
- None => None,
- };
- let type_private = match import_resolution.type_target {
- Some(ref target) => {
- let def = target.bindings.def_for_namespace(TypeNS).unwrap();
- self.def_map.borrow_mut().insert(directive.id, def);
- let did = def.def_id();
- if type_used_public {Some(lp)} else {Some(DependsOn(did))}
- },
- None => None,
+ let value_def_and_priv = import_resolution.value_target.as_ref().map(|target| {
+ let def = target.bindings.def_for_namespace(ValueNS).unwrap();
+ (def, if value_used_public { lp } else { DependsOn(def.def_id()) })
+ });
+ let type_def_and_priv = import_resolution.type_target.as_ref().map(|target| {
+ let def = target.bindings.def_for_namespace(TypeNS).unwrap();
+ (def, if type_used_public { lp } else { DependsOn(def.def_id()) })
+ });
+
+ let import_lp = LastImport {
+ value_priv: value_def_and_priv.map(|(_, p)| p),
+ value_used: Used,
+ type_priv: type_def_and_priv.map(|(_, p)| p),
+ type_used: Used
};
- self.last_private.insert(directive.id, LastImport{value_priv: value_private,
- value_used: Used,
- type_priv: type_private,
- type_used: Used});
+ if let Some((def, _)) = value_def_and_priv {
+ self.def_map.borrow_mut().insert(directive.id, PathResolution {
+ base_def: def,
+ last_private: import_lp,
+ depth: 0
+ });
+ }
+ if let Some((def, _)) = type_def_and_priv {
+ self.def_map.borrow_mut().insert(directive.id, PathResolution {
+ base_def: def,
+ last_private: import_lp,
+ depth: 0
+ });
+ }
debug!("(resolving single import) successfully resolved import");
return Success(());
}
// Record the destination of this import
- match containing_module.def_id.get() {
- Some(did) => {
- self.def_map.borrow_mut().insert(id, DefMod(did));
- self.last_private.insert(id, lp);
- }
- None => {}
+ if let Some(did) = containing_module.def_id.get() {
+ self.def_map.borrow_mut().insert(id, PathResolution {
+ base_def: DefMod(did),
+ last_private: lp,
+ depth: 0
+ });
}
debug!("(resolving glob import) successfully resolved import");
match import_resolution.value_target {
Some(ref target) if target.shadowable != Shadowable::Always => {
if let Some(ref value) = *name_bindings.value_def.borrow() {
- let msg = format!("import `{}` conflicts with value \
- in this module",
- &token::get_name(name));
- span_err!(self.session, import_span, E0255, "{}", &msg[..]);
+ span_err!(self.session, import_span, E0255,
+ "import `{}` conflicts with value in this module",
+ &token::get_name(name));
if let Some(span) = value.value_span {
- self.session.span_note(span,
- "conflicting value here");
+ self.session.span_note(span, "conflicting value here");
}
}
}
match import_resolution.type_target {
Some(ref target) if target.shadowable != Shadowable::Always => {
if let Some(ref ty) = *name_bindings.type_def.borrow() {
- match ty.module_def {
- None => {
- let msg = format!("import `{}` conflicts with type in \
- this module",
- &token::get_name(name));
- span_err!(self.session, import_span, E0256, "{}", &msg[..]);
- if let Some(span) = ty.type_span {
- self.session.span_note(span,
- "note conflicting type here")
- }
- }
- Some(ref module_def) => {
- match module_def.kind.get() {
- ImplModuleKind => {
- if let Some(span) = ty.type_span {
- let msg = format!("inherent implementations \
- are only allowed on types \
- defined in the current module");
- span_err!(self.session, span, E0257, "{}", &msg[..]);
- self.session.span_note(import_span,
- "import from other module here")
- }
- }
- _ => {
- let msg = format!("import `{}` conflicts with existing \
- submodule",
- &token::get_name(name));
- span_err!(self.session, import_span, E0258, "{}", &msg[..]);
- if let Some(span) = ty.type_span {
- self.session.span_note(span,
- "note conflicting module here")
- }
- }
- }
- }
+ let (what, note) = if ty.module_def.is_some() {
+ ("existing submodule", "note conflicting module here")
+ } else {
+ ("type in this module", "note conflicting type here")
+ };
+ span_err!(self.session, import_span, E0256,
+ "import `{}` conflicts with {}",
+ &token::get_name(name), what);
+ if let Some(span) = ty.type_span {
+ self.session.span_note(span, note);
}
}
}
return Failed(None);
}
TraitModuleKind |
- ImplModuleKind |
EnumModuleKind |
TypeModuleKind |
AnonymousModuleKind => {
match new_module.kind.get() {
NormalModuleKind => return Some(new_module),
TraitModuleKind |
- ImplModuleKind |
EnumModuleKind |
TypeModuleKind |
AnonymousModuleKind => module_ = new_module,
match module_.kind.get() {
NormalModuleKind => return module_,
TraitModuleKind |
- ImplModuleKind |
EnumModuleKind |
TypeModuleKind |
AnonymousModuleKind => {
def_like: DefLike,
span: Span)
-> Option<DefLike> {
- match def_like {
- DlDef(d @ DefUpvar(..)) => {
+ let mut def = match def_like {
+ DlDef(def) => def,
+ _ => return Some(def_like)
+ };
+ match def {
+ DefUpvar(..) => {
self.session.span_bug(span,
- &format!("unexpected {:?} in bindings", d))
+ &format!("unexpected {:?} in bindings", def))
}
- DlDef(d @ DefLocal(_)) => {
- let node_id = d.def_id().node;
- let mut def = d;
+ DefLocal(node_id) => {
for rib in ribs {
match rib.kind {
NormalRibKind => {
}.push(Freevar { def: prev_def, span: span });
seen.insert(node_id);
}
- MethodRibKind(item_id, _) => {
- // If the def is a ty param, and came from the parent
- // item, it's ok
- match def {
- DefTyParam(_, _, did, _) if {
- self.def_map.borrow().get(&did.node).cloned()
- == Some(DefTyParamBinder(item_id))
- } => {} // ok
- DefSelfTy(did) if did == item_id => {} // ok
- _ => {
- // This was an attempt to access an upvar inside a
- // named function item. This is not allowed, so we
- // report an error.
-
- self.resolve_error(
- span,
- "can't capture dynamic environment in a fn item; \
- use the || { ... } closure form instead");
-
- return None;
- }
- }
- }
- ItemRibKind => {
+ ItemRibKind | MethodRibKind => {
// This was an attempt to access an upvar inside a
// named function item. This is not allowed, so we
// report an error.
- self.resolve_error(
- span,
+ self.resolve_error(span,
"can't capture dynamic environment in a fn item; \
- use the || { ... } closure form instead");
-
+ use the || { ... } closure form instead");
return None;
}
ConstantItemRibKind => {
self.resolve_error(span,
"attempt to use a non-constant \
value in a constant");
-
+ return None;
}
}
}
- Some(DlDef(def))
}
- DlDef(def @ DefTyParam(..)) |
- DlDef(def @ DefSelfTy(..)) => {
+ DefTyParam(..) | DefSelfTy(_) => {
for rib in ribs {
match rib.kind {
- NormalRibKind | ClosureRibKind(..) => {
+ NormalRibKind | MethodRibKind | ClosureRibKind(..) => {
// Nothing to do. Continue.
}
- MethodRibKind(item_id, _) => {
- // If the def is a ty param, and came from the parent
- // item, it's ok
- match def {
- DefTyParam(_, _, did, _) if {
- self.def_map.borrow().get(&did.node).cloned()
- == Some(DefTyParamBinder(item_id))
- } => {} // ok
- DefSelfTy(did) if did == item_id => {} // ok
-
- _ => {
- // This was an attempt to use a type parameter outside
- // its scope.
-
- self.resolve_error(span,
- "can't use type parameters from \
- outer function; try using a local \
- type parameter instead");
-
- return None;
- }
- }
- }
ItemRibKind => {
// This was an attempt to use a type parameter outside
// its scope.
"can't use type parameters from \
outer function; try using a local \
type parameter instead");
-
return None;
}
ConstantItemRibKind => {
self.resolve_error(span,
"cannot use an outer type \
parameter in this context");
-
+ return None;
}
}
}
- Some(DlDef(def))
}
- _ => Some(def_like)
+ _ => {}
}
+ Some(DlDef(def))
}
/// Searches the current set of local scopes and
// FIXME #4950: Try caching?
for (i, rib) in ribs.iter().enumerate().rev() {
- match rib.bindings.get(&name).cloned() {
- Some(def_like) => {
- return self.upvarify(&ribs[i + 1..], def_like, span);
- }
- None => {
- // Continue.
- }
+ if let Some(def_like) = rib.bindings.get(&name).cloned() {
+ return self.upvarify(&ribs[i + 1..], def_like, span);
}
}
token::get_name(name));
match item.node {
-
- // enum item: resolve all the variants' discrs,
- // then resolve the ty params
- ItemEnum(ref enum_def, ref generics) => {
+ ItemEnum(_, ref generics) |
+ ItemTy(_, ref generics) |
+ ItemStruct(_, ref generics) => {
self.check_if_primitive_type_name(name, item.span);
- for variant in &(*enum_def).variants {
- if let Some(ref dis_expr) = variant.node.disr_expr {
- // resolve the discriminator expr
- // as a constant
- self.with_constant_rib(|this| {
- this.resolve_expr(&**dis_expr);
- });
- }
- }
-
- // n.b. the discr expr gets visited twice.
- // but maybe it's okay since the first time will signal an
- // error if there is one? -- tjc
self.with_type_parameter_rib(HasTypeParameters(generics,
TypeSpace,
- item.id,
ItemRibKind),
- |this| {
- this.resolve_type_parameters(&generics.ty_params);
- this.resolve_where_clause(&generics.where_clause);
- visit::walk_item(this, item);
- });
+ |this| visit::walk_item(this, item));
}
-
- ItemTy(_, ref generics) => {
- self.check_if_primitive_type_name(name, item.span);
-
+ ItemFn(_, _, _, ref generics, _) => {
self.with_type_parameter_rib(HasTypeParameters(generics,
- TypeSpace,
- item.id,
+ FnSpace,
ItemRibKind),
- |this| {
- this.resolve_type_parameters(&generics.ty_params);
- visit::walk_item(this, item);
- });
+ |this| visit::walk_item(this, item));
}
ItemDefaultImpl(_, ref trait_ref) => {
- self.resolve_trait_reference(item.id, trait_ref, TraitImplementation);
+ self.with_optional_trait_ref(Some(trait_ref), |_| {});
}
ItemImpl(_, _,
ref generics,
ref implemented_traits,
ref self_type,
ref impl_items) => {
- self.resolve_implementation(item.id,
- generics,
+ self.resolve_implementation(generics,
implemented_traits,
&**self_type,
&impl_items[..]);
// Create a new rib for the trait-wide type parameters.
self.with_type_parameter_rib(HasTypeParameters(generics,
TypeSpace,
- item.id,
NormalRibKind),
|this| {
- this.resolve_type_parameters(&generics.ty_params);
- this.resolve_where_clause(&generics.where_clause);
-
- this.resolve_type_parameter_bounds(item.id, bounds,
- TraitDerivation);
+ this.visit_generics(generics);
+ visit::walk_ty_param_bounds_helper(this, bounds);
for trait_item in &(*trait_items) {
// Create a new rib for the trait_item-specific type
//
// FIXME #4951: Do we need a node ID here?
- match *trait_item {
- ast::RequiredMethod(ref ty_m) => {
- this.with_type_parameter_rib
- (HasTypeParameters(&ty_m.generics,
- FnSpace,
- item.id,
- MethodRibKind(item.id, RequiredMethod)),
- |this| {
-
- // Resolve the method-specific type
- // parameters.
- this.resolve_type_parameters(
- &ty_m.generics.ty_params);
- this.resolve_where_clause(&ty_m.generics
- .where_clause);
-
- for argument in &ty_m.decl.inputs {
- this.resolve_type(&*argument.ty);
- }
-
- if let SelfExplicit(ref typ, _) = ty_m.explicit_self.node {
- this.resolve_type(&**typ)
- }
-
- if let ast::Return(ref ret_ty) = ty_m.decl.output {
- this.resolve_type(&**ret_ty);
- }
- });
- }
- ast::ProvidedMethod(ref m) => {
- this.resolve_method(MethodRibKind(item.id,
- ProvidedMethod(m.id)),
- &**m)
- }
- ast::TypeTraitItem(ref data) => {
- this.resolve_type_parameter(&data.ty_param);
- visit::walk_trait_item(this, trait_item);
- }
- }
+ let type_parameters = match *trait_item {
+ ast::RequiredMethod(ref ty_m) => {
+ HasTypeParameters(&ty_m.generics,
+ FnSpace,
+ MethodRibKind)
+ }
+ ast::ProvidedMethod(ref m) => {
+ HasTypeParameters(m.pe_generics(),
+ FnSpace,
+ MethodRibKind)
+ }
+ ast::TypeTraitItem(ref assoc_ty) => {
+ let ty_param = &assoc_ty.ty_param;
+ this.check_if_primitive_type_name(ty_param.ident.name,
+ ty_param.span);
+ NoTypeParameters
+ }
+ };
+ this.with_type_parameter_rib(type_parameters, |this| {
+ visit::walk_trait_item(this, trait_item)
+ });
}
});
self.type_ribs.pop();
}
- ItemStruct(ref struct_def, ref generics) => {
- self.check_if_primitive_type_name(name, item.span);
-
- self.resolve_struct(item.id,
- generics,
- &struct_def.fields);
- }
-
- ItemMod(ref module_) => {
+ ItemMod(_) | ItemForeignMod(_) => {
self.with_scope(Some(name), |this| {
- this.resolve_module(module_, item.span, name,
- item.id);
- });
- }
-
- ItemForeignMod(ref foreign_module) => {
- self.with_scope(Some(name), |this| {
- for foreign_item in &foreign_module.items {
- match foreign_item.node {
- ForeignItemFn(_, ref generics) => {
- this.with_type_parameter_rib(
- HasTypeParameters(
- generics, FnSpace, foreign_item.id,
- ItemRibKind),
- |this| {
- this.resolve_type_parameters(&generics.ty_params);
- this.resolve_where_clause(&generics.where_clause);
- visit::walk_foreign_item(this, &**foreign_item)
- });
- }
- ForeignItemStatic(..) => {
- visit::walk_foreign_item(this,
- &**foreign_item);
- }
- }
- }
+ visit::walk_item(this, item);
});
}
- ItemFn(ref fn_decl, _, _, ref generics, ref block) => {
- self.resolve_function(ItemRibKind,
- Some(&**fn_decl),
- HasTypeParameters
- (generics,
- FnSpace,
- item.id,
- ItemRibKind),
- &**block);
- }
-
ItemConst(..) | ItemStatic(..) => {
self.with_constant_rib(|this| {
visit::walk_item(this, item);
ItemUse(ref view_path) => {
// check for imports shadowing primitive types
if let ast::ViewPathSimple(ident, _) = view_path.node {
- match self.def_map.borrow().get(&item.id) {
- Some(&DefTy(..)) | Some(&DefStruct(..)) | Some(&DefaultImpl(..)) | None => {
+ match self.def_map.borrow().get(&item.id).map(|d| d.full_def()) {
+ Some(DefTy(..)) | Some(DefStruct(..)) | Some(DefTrait(..)) | None => {
self.check_if_primitive_type_name(ident.name, item.span);
}
_ => {}
F: FnOnce(&mut Resolver),
{
match type_parameters {
- HasTypeParameters(generics, space, node_id, rib_kind) => {
+ HasTypeParameters(generics, space, rib_kind) => {
let mut function_type_rib = Rib::new(rib_kind);
let mut seen_bindings = HashSet::new();
for (index, type_parameter) in generics.ty_params.iter().enumerate() {
let name = type_parameter.ident.name;
- debug!("with_type_parameter_rib: {} {}", node_id,
- type_parameter.id);
+ debug!("with_type_parameter_rib: {}", type_parameter.id);
if seen_bindings.contains(&name) {
self.resolve_error(type_parameter.span,
&format!("the name `{}` is already \
- used for a type \
- parameter in this type \
- parameter list",
- token::get_name(
- name)))
+ used for a type \
+ parameter in this type \
+ parameter list",
+ token::get_name(name)))
}
seen_bindings.insert(name);
- let def_like = DlDef(DefTyParam(space,
- index as u32,
- local_def(type_parameter.id),
- name));
- // Associate this type parameter with
- // the item that bound it
- self.record_def(type_parameter.id,
- (DefTyParamBinder(node_id), LastMod(AllPublic)));
// plain insert (no renaming)
- function_type_rib.bindings.insert(name, def_like);
+ function_type_rib.bindings.insert(name,
+ DlDef(DefTyParam(space,
+ index as u32,
+ local_def(type_parameter.id),
+ name)));
}
self.type_ribs.push(function_type_rib);
}
fn resolve_function(&mut self,
rib_kind: RibKind,
- optional_declaration: Option<&FnDecl>,
- type_parameters: TypeParameters,
+ declaration: &FnDecl,
block: &Block) {
// Create a value rib for the function.
- let function_value_rib = Rib::new(rib_kind);
- self.value_ribs.push(function_value_rib);
+ self.value_ribs.push(Rib::new(rib_kind));
// Create a label rib for the function.
- let function_label_rib = Rib::new(rib_kind);
- self.label_ribs.push(function_label_rib);
+ self.label_ribs.push(Rib::new(rib_kind));
- // If this function has type parameters, add them now.
- self.with_type_parameter_rib(type_parameters, |this| {
- // Resolve the type parameters.
- match type_parameters {
- NoTypeParameters => {
- // Continue.
- }
- HasTypeParameters(ref generics, _, _, _) => {
- this.resolve_type_parameters(&generics.ty_params);
- this.resolve_where_clause(&generics.where_clause);
- }
- }
-
- // Add each argument to the rib.
- match optional_declaration {
- None => {
- // Nothing to do.
- }
- Some(declaration) => {
- let mut bindings_list = HashMap::new();
- for argument in &declaration.inputs {
- this.resolve_pattern(&*argument.pat,
- ArgumentIrrefutableMode,
- &mut bindings_list);
-
- this.resolve_type(&*argument.ty);
+ // Add each argument to the rib.
+ let mut bindings_list = HashMap::new();
+ for argument in &declaration.inputs {
+ self.resolve_pattern(&*argument.pat,
+ ArgumentIrrefutableMode,
+ &mut bindings_list);
- debug!("(resolving function) recorded argument");
- }
+ self.visit_ty(&*argument.ty);
- if let ast::Return(ref ret_ty) = declaration.output {
- this.resolve_type(&**ret_ty);
- }
- }
- }
+ debug!("(resolving function) recorded argument");
+ }
+ visit::walk_fn_ret_ty(self, &declaration.output);
- // Resolve the function body.
- this.resolve_block(&*block);
+ // Resolve the function body.
+ self.visit_block(&*block);
- debug!("(resolving function) leaving function");
- });
+ debug!("(resolving function) leaving function");
self.label_ribs.pop();
self.value_ribs.pop();
}
- fn resolve_type_parameters(&mut self,
- type_parameters: &OwnedSlice<TyParam>) {
- for type_parameter in &**type_parameters {
- self.resolve_type_parameter(type_parameter);
- }
- }
-
- fn resolve_type_parameter(&mut self,
- type_parameter: &TyParam) {
- self.check_if_primitive_type_name(type_parameter.ident.name, type_parameter.span);
- for bound in &*type_parameter.bounds {
- self.resolve_type_parameter_bound(type_parameter.id, bound,
- TraitBoundingTypeParameter);
- }
- match type_parameter.default {
- Some(ref ty) => self.resolve_type(&**ty),
- None => {}
- }
- }
-
- fn resolve_type_parameter_bounds(&mut self,
- id: NodeId,
- type_parameter_bounds: &OwnedSlice<TyParamBound>,
- reference_type: TraitReferenceType) {
- for type_parameter_bound in &**type_parameter_bounds {
- self.resolve_type_parameter_bound(id, type_parameter_bound,
- reference_type);
- }
- }
-
- fn resolve_type_parameter_bound(&mut self,
- id: NodeId,
- type_parameter_bound: &TyParamBound,
- reference_type: TraitReferenceType) {
- match *type_parameter_bound {
- TraitTyParamBound(ref tref, _) => {
- self.resolve_poly_trait_reference(id, tref, reference_type)
- }
- RegionTyParamBound(..) => {}
- }
- }
-
- fn resolve_poly_trait_reference(&mut self,
- id: NodeId,
- poly_trait_reference: &PolyTraitRef,
- reference_type: TraitReferenceType) {
- self.resolve_trait_reference(id, &poly_trait_reference.trait_ref, reference_type)
- }
-
fn resolve_trait_reference(&mut self,
id: NodeId,
- trait_reference: &TraitRef,
- reference_type: TraitReferenceType) {
- match self.resolve_path(id, &trait_reference.path, TypeNS, true) {
- None => {
- let path_str = self.path_names_to_string(&trait_reference.path);
- let usage_str = match reference_type {
- TraitBoundingTypeParameter => "bound type parameter with",
- TraitImplementation => "implement",
- TraitDerivation => "derive",
- TraitObject => "reference",
- TraitQPath => "extract an associated item from",
- };
-
- let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str);
- self.resolve_error(trait_reference.path.span, &msg[..]);
- }
- Some(def) => {
- match def {
- (DefaultImpl(_), _) => {
- debug!("(resolving trait) found trait def: {:?}", def);
- self.record_def(trait_reference.ref_id, def);
- }
- (def, _) => {
- self.resolve_error(trait_reference.path.span,
- &format!("`{}` is not a trait",
- self.path_names_to_string(
- &trait_reference.path)));
-
- // If it's a typedef, give a note
- if let DefTy(..) = def {
- self.session.span_note(
- trait_reference.path.span,
- &format!("`type` aliases cannot be used for traits")
- );
- }
- }
+ trait_path: &Path,
+ path_depth: usize)
+ -> Result<PathResolution, ()> {
+ if let Some(path_res) = self.resolve_path(id, trait_path, path_depth, TypeNS, true) {
+ if let DefTrait(_) = path_res.base_def {
+ debug!("(resolving trait) found trait def: {:?}", path_res);
+ Ok(path_res)
+ } else {
+ self.resolve_error(trait_path.span,
+ &format!("`{}` is not a trait",
+ self.path_names_to_string(trait_path, path_depth)));
+
+ // If it's a typedef, give a note
+ if let DefTy(..) = path_res.base_def {
+ self.session.span_note(trait_path.span,
+ "`type` aliases cannot be used for traits");
}
+ Err(())
}
+ } else {
+ let msg = format!("use of undeclared trait name `{}`",
+ self.path_names_to_string(trait_path, path_depth));
+ self.resolve_error(trait_path.span, &msg[]);
+ Err(())
}
}
- fn resolve_where_clause(&mut self, where_clause: &ast::WhereClause) {
- for predicate in &where_clause.predicates {
+ fn resolve_generics(&mut self, generics: &Generics) {
+ for type_parameter in &*generics.ty_params {
+ self.check_if_primitive_type_name(type_parameter.ident.name, type_parameter.span);
+ }
+ for predicate in &generics.where_clause.predicates {
match predicate {
- &ast::WherePredicate::BoundPredicate(ref bound_pred) => {
- self.resolve_type(&*bound_pred.bounded_ty);
-
- for bound in &*bound_pred.bounds {
- self.resolve_type_parameter_bound(bound_pred.bounded_ty.id, bound,
- TraitBoundingTypeParameter);
- }
- }
+ &ast::WherePredicate::BoundPredicate(_) |
&ast::WherePredicate::RegionPredicate(_) => {}
&ast::WherePredicate::EqPredicate(ref eq_pred) => {
- match self.resolve_path(eq_pred.id, &eq_pred.path, TypeNS, true) {
- Some((def @ DefTyParam(..), last_private)) => {
- self.record_def(eq_pred.id, (def, last_private));
- }
- _ => {
- self.resolve_error(eq_pred.path.span,
- "undeclared associated type");
- }
+ let path_res = self.resolve_path(eq_pred.id, &eq_pred.path, 0, TypeNS, true);
+ if let Some(PathResolution { base_def: DefTyParam(..), .. }) = path_res {
+ self.record_def(eq_pred.id, path_res.unwrap());
+ } else {
+ self.resolve_error(eq_pred.path.span, "undeclared associated type");
}
-
- self.resolve_type(&*eq_pred.ty);
}
}
}
- }
-
- fn resolve_struct(&mut self,
- id: NodeId,
- generics: &Generics,
- fields: &[StructField]) {
- // If applicable, create a rib for the type parameters.
- self.with_type_parameter_rib(HasTypeParameters(generics,
- TypeSpace,
- id,
- ItemRibKind),
- |this| {
- // Resolve the type parameters.
- this.resolve_type_parameters(&generics.ty_params);
- this.resolve_where_clause(&generics.where_clause);
-
- // Resolve fields.
- for field in fields {
- this.resolve_type(&*field.node.ty);
- }
- });
- }
-
- // Does this really need to take a RibKind or is it always going
- // to be NormalRibKind?
- fn resolve_method(&mut self,
- rib_kind: RibKind,
- method: &ast::Method) {
- let method_generics = method.pe_generics();
- let type_parameters = HasTypeParameters(method_generics,
- FnSpace,
- method.id,
- rib_kind);
-
- if let SelfExplicit(ref typ, _) = method.pe_explicit_self().node {
- self.resolve_type(&**typ);
- }
-
- self.resolve_function(rib_kind,
- Some(method.pe_fn_decl()),
- type_parameters,
- method.pe_body());
+ visit::walk_generics(self, generics);
}
fn with_current_self_type<T, F>(&mut self, self_type: &Ty, f: F) -> T where
result
}
- fn with_optional_trait_ref<T, F>(&mut self, id: NodeId,
- opt_trait_ref: &Option<TraitRef>,
+ fn with_optional_trait_ref<T, F>(&mut self,
+ opt_trait_ref: Option<&TraitRef>,
f: F) -> T where
F: FnOnce(&mut Resolver) -> T,
{
- let new_val = match *opt_trait_ref {
- Some(ref trait_ref) => {
- self.resolve_trait_reference(id, trait_ref, TraitImplementation);
-
- match self.def_map.borrow().get(&trait_ref.ref_id) {
- Some(def) => {
- let did = def.def_id();
- Some((did, trait_ref.clone()))
- }
- None => None
+ let mut new_val = None;
+ if let Some(trait_ref) = opt_trait_ref {
+ match self.resolve_trait_reference(trait_ref.ref_id, &trait_ref.path, 0) {
+ Ok(path_res) => {
+ self.record_def(trait_ref.ref_id, path_res);
+ new_val = Some((path_res.base_def.def_id(), trait_ref.clone()));
}
+ Err(_) => { /* error was already reported */ }
}
- None => None
- };
+ visit::walk_trait_ref(self, trait_ref);
+ }
let original_trait_ref = replace(&mut self.current_trait_ref, new_val);
let result = f(self);
self.current_trait_ref = original_trait_ref;
}
fn resolve_implementation(&mut self,
- id: NodeId,
generics: &Generics,
opt_trait_reference: &Option<TraitRef>,
self_type: &Ty,
// If applicable, create a rib for the type parameters.
self.with_type_parameter_rib(HasTypeParameters(generics,
TypeSpace,
- id,
- NormalRibKind),
+ ItemRibKind),
|this| {
// Resolve the type parameters.
- this.resolve_type_parameters(&generics.ty_params);
- this.resolve_where_clause(&generics.where_clause);
+ this.visit_generics(generics);
// Resolve the trait reference, if necessary.
- this.with_optional_trait_ref(id, opt_trait_reference, |this| {
+ this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this| {
// Resolve the self type.
- this.resolve_type(self_type);
+ this.visit_ty(self_type);
this.with_current_self_type(self_type, |this| {
for impl_item in impl_items {
// We also need a new scope for the method-
// specific type parameters.
- this.resolve_method(
- MethodRibKind(id, ProvidedMethod(method.id)),
- &**method);
+ let type_parameters =
+ HasTypeParameters(method.pe_generics(),
+ FnSpace,
+ MethodRibKind);
+ this.with_type_parameter_rib(type_parameters, |this| {
+ visit::walk_method_helper(this, &**method);
+ });
}
TypeImplItem(ref typedef) => {
// If this is a trait impl, ensure the method
this.check_trait_item(typedef.ident.name,
typedef.span);
- this.resolve_type(&*typedef.typ);
+ this.visit_ty(&*typedef.typ);
}
}
}
});
});
});
-
- // Check that the current type is indeed a type, if we have an anonymous impl
- if opt_trait_reference.is_none() {
- match self_type.node {
- // TyPath is the only thing that we handled in `build_reduced_graph_for_item`,
- // where we created a module with the name of the type in order to implement
- // an anonymous trait. In the case that the path does not resolve to an actual
- // type, the result will be that the type name resolves to a module but not
- // a type (shadowing any imported modules or types with this name), leading
- // to weird user-visible bugs. So we ward this off here. See #15060.
- TyPath(ref path, path_id) => {
- match self.def_map.borrow().get(&path_id) {
- // FIXME: should we catch other options and give more precise errors?
- Some(&DefMod(_)) => {
- self.resolve_error(path.span, "inherent implementations are not \
- allowed for types not defined in \
- the current module");
- }
- _ => {}
- }
- }
- _ => { }
- }
- }
}
fn check_trait_item(&self, name: Name, span: Span) {
// If there is a TraitRef in scope for an impl, then the method must be in the trait.
if let Some((did, ref trait_ref)) = self.current_trait_ref {
- if self.trait_item_map.get(&(name, did)).is_none() {
- let path_str = self.path_names_to_string(&trait_ref.path);
+ if !self.trait_item_map.contains_key(&(name, did)) {
+ let path_str = self.path_names_to_string(&trait_ref.path, 0);
self.resolve_error(span,
&format!("method `{}` is not a member of trait `{}`",
token::get_name(name),
}
}
- fn resolve_module(&mut self, module: &Mod, _span: Span,
- _name: Name, id: NodeId) {
- // Write the implementations in scope into the module metadata.
- debug!("(resolving module) resolving module ID {}", id);
- visit::walk_mod(self, module);
- }
-
fn resolve_local(&mut self, local: &Local) {
// Resolve the type.
- if let Some(ref ty) = local.ty {
- self.resolve_type(&**ty);
- }
+ visit::walk_ty_opt(self, &local.ty);
- // Resolve the initializer, if necessary.
- match local.init {
- None => {
- // Nothing to do.
- }
- Some(ref initializer) => {
- self.resolve_expr(&**initializer);
- }
- }
+ // Resolve the initializer.
+ visit::walk_expr_opt(self, &local.init);
// Resolve the pattern.
- let mut bindings_list = HashMap::new();
self.resolve_pattern(&*local.pat,
LocalIrrefutableMode,
- &mut bindings_list);
+ &mut HashMap::new());
}
// build a map from pattern identifiers to binding-info's.
self.check_consistent_bindings(arm);
visit::walk_expr_opt(self, &arm.guard);
- self.resolve_expr(&*arm.body);
+ self.visit_expr(&*arm.body);
self.value_ribs.pop();
}
fn resolve_type(&mut self, ty: &Ty) {
match ty.node {
- // Like path expressions, the interpretation of path types depends
- // on whether the path has multiple elements in it or not.
+ // `<T>::a::b::c` is resolved by typeck alone.
+ TyPath(Some(ast::QSelf { position: 0, .. }), _) => {}
+
+ TyPath(ref maybe_qself, ref path) => {
+ let max_assoc_types = if let Some(ref qself) = *maybe_qself {
+ // Make sure the trait is valid.
+ let _ = self.resolve_trait_reference(ty.id, path, 1);
+ path.segments.len() - qself.position
+ } else {
+ path.segments.len()
+ };
- TyPath(ref path, path_id) => {
- // This is a path in the type namespace. Walk through scopes
- // looking for it.
- let mut result_def = None;
-
- // First, check to see whether the name is a primitive type.
- if path.segments.len() == 1 {
- let id = path.segments.last().unwrap().identifier;
-
- match self.primitive_type_table
- .primitive_types
- .get(&id.name) {
-
- Some(&primitive_type) => {
- result_def =
- Some((DefPrimTy(primitive_type), LastMod(AllPublic)));
-
- if path.segments[0].parameters.has_lifetimes() {
- span_err!(self.session, path.span, E0157,
- "lifetime parameters are not allowed on this type");
- } else if !path.segments[0].parameters.is_empty() {
- span_err!(self.session, path.span, E0153,
- "type parameters are not allowed on this type");
- }
- }
- None => {
- // Continue.
- }
+ let mut resolution = None;
+ for depth in 0..max_assoc_types {
+ self.with_no_errors(|this| {
+ resolution = this.resolve_path(ty.id, path, depth, TypeNS, true);
+ });
+ if resolution.is_some() {
+ break;
}
}
-
- if let None = result_def {
- result_def = self.resolve_path(ty.id, path, TypeNS, true);
+ if let Some(DefMod(_)) = resolution.map(|r| r.base_def) {
+ // A module is not a valid type.
+ resolution = None;
}
- match result_def {
+ // This is a path in the type namespace. Walk through scopes
+ // looking for it.
+ match resolution {
Some(def) => {
// Write the result into the def map.
debug!("(resolving type) writing resolution for `{}` \
(id {}) = {:?}",
- self.path_names_to_string(path),
- path_id, def);
- self.record_def(path_id, def);
+ self.path_names_to_string(path, 0),
+ ty.id, def);
+ self.record_def(ty.id, def);
}
None => {
- let msg = format!("use of undeclared type name `{}`",
- self.path_names_to_string(path));
- self.resolve_error(ty.span, &msg[..]);
- }
- }
- }
+ // Keep reporting some errors even if they're ignored above.
+ self.resolve_path(ty.id, path, 0, TypeNS, true);
- TyObjectSum(ref ty, ref bound_vec) => {
- self.resolve_type(&**ty);
- self.resolve_type_parameter_bounds(ty.id, bound_vec,
- TraitBoundingTypeParameter);
- }
+ let kind = if maybe_qself.is_some() {
+ "associated type"
+ } else {
+ "type name"
+ };
- TyQPath(ref qpath) => {
- self.resolve_type(&*qpath.self_type);
- self.resolve_trait_reference(ty.id, &*qpath.trait_ref, TraitQPath);
- for ty in qpath.item_path.parameters.types() {
- self.resolve_type(&**ty);
- }
- for binding in qpath.item_path.parameters.bindings() {
- self.resolve_type(&*binding.ty);
+ let msg = format!("use of undeclared {} `{}`", kind,
+ self.path_names_to_string(path, 0));
+ self.resolve_error(ty.span, &msg[..]);
+ }
}
}
-
- TyPolyTraitRef(ref bounds) => {
- self.resolve_type_parameter_bounds(
- ty.id,
- bounds,
- TraitObject);
- visit::walk_ty(self, ty);
- }
- _ => {
- // Just resolve embedded types.
- visit::walk_ty(self, ty);
- }
+ _ => {}
}
+ // Resolve embedded types.
+ visit::walk_ty(self, ty);
}
fn resolve_pattern(&mut self,
let renamed = mtwt::resolve(ident);
match self.resolve_bare_identifier_pattern(ident.name, pattern.span) {
- FoundStructOrEnumVariant(ref def, lp)
+ FoundStructOrEnumVariant(def, lp)
if mode == RefutableMode => {
debug!("(resolving pattern) resolving `{}` to \
struct or enum variant",
pattern,
binding_mode,
"an enum variant");
- self.record_def(pattern.id, (def.clone(), lp));
+ self.record_def(pattern.id, PathResolution {
+ base_def: def,
+ last_private: lp,
+ depth: 0
+ });
}
FoundStructOrEnumVariant(..) => {
self.resolve_error(
scope",
token::get_name(renamed)));
}
- FoundConst(ref def, lp) if mode == RefutableMode => {
+ FoundConst(def, lp) if mode == RefutableMode => {
debug!("(resolving pattern) resolving `{}` to \
constant",
token::get_name(renamed));
pattern,
binding_mode,
"a constant");
- self.record_def(pattern.id, (def.clone(), lp));
+ self.record_def(pattern.id, PathResolution {
+ base_def: def,
+ last_private: lp,
+ depth: 0
+ });
}
FoundConst(..) => {
self.resolve_error(pattern.span,
// will be able to distinguish variants from
// locals in patterns.
- self.record_def(pattern.id, (def, LastMod(AllPublic)));
+ self.record_def(pattern.id, PathResolution {
+ base_def: def,
+ last_private: LastMod(AllPublic),
+ depth: 0
+ });
// Add the binding to the local ribs, if it
// doesn't already exist in the bindings list. (We
PatEnum(ref path, _) => {
// This must be an enum variant, struct or const.
- match self.resolve_path(pat_id, path, ValueNS, false) {
- Some(def @ (DefVariant(..), _)) |
- Some(def @ (DefStruct(..), _)) |
- Some(def @ (DefConst(..), _)) => {
- self.record_def(pattern.id, def);
- }
- Some((DefStatic(..), _)) => {
- self.resolve_error(path.span,
- "static variables cannot be \
- referenced in a pattern, \
- use a `const` instead");
- }
- Some(_) => {
- self.resolve_error(path.span,
- &format!("`{}` is not an enum variant, struct or const",
- token::get_ident(
- path.segments.last().unwrap().identifier)));
- }
- None => {
- self.resolve_error(path.span,
- &format!("unresolved enum variant, struct or const `{}`",
- token::get_ident(path.segments.last().unwrap().identifier)));
+ if let Some(path_res) = self.resolve_path(pat_id, path, 0, ValueNS, false) {
+ match path_res.base_def {
+ DefVariant(..) | DefStruct(..) | DefConst(..) => {
+ self.record_def(pattern.id, path_res);
+ }
+ DefStatic(..) => {
+ self.resolve_error(path.span,
+ "static variables cannot be \
+ referenced in a pattern, \
+ use a `const` instead");
+ }
+ _ => {
+ self.resolve_error(path.span,
+ &format!("`{}` is not an enum variant, struct or const",
+ token::get_ident(
+ path.segments.last().unwrap().identifier)));
+ }
}
+ } else {
+ self.resolve_error(path.span,
+ &format!("unresolved enum variant, struct or const `{}`",
+ token::get_ident(path.segments.last().unwrap().identifier)));
}
-
- // Check the types in the path pattern.
- for ty in path.segments
- .iter()
- .flat_map(|s| s.parameters.types().into_iter()) {
- self.resolve_type(&**ty);
- }
- }
-
- PatLit(ref expr) => {
- self.resolve_expr(&**expr);
- }
-
- PatRange(ref first_expr, ref last_expr) => {
- self.resolve_expr(&**first_expr);
- self.resolve_expr(&**last_expr);
+ visit::walk_path(self, path);
}
PatStruct(ref path, _, _) => {
- match self.resolve_path(pat_id, path, TypeNS, false) {
+ match self.resolve_path(pat_id, path, 0, TypeNS, false) {
Some(definition) => {
self.record_def(pattern.id, definition);
}
debug!("(resolving pattern) didn't find struct \
def: {:?}", result);
let msg = format!("`{}` does not name a structure",
- self.path_names_to_string(path));
+ self.path_names_to_string(path, 0));
self.resolve_error(path.span, &msg[..]);
}
}
+ visit::walk_path(self, path);
+ }
+
+ PatLit(_) | PatRange(..) => {
+ visit::walk_pat(self, pattern);
}
_ => {
/// If `check_ribs` is true, checks the local definitions first; i.e.
/// doesn't skip straight to the containing module.
+ /// Skips `path_depth` trailing segments, which is also reflected in the
+ /// returned value. See `middle::def::PathResolution` for more info.
fn resolve_path(&mut self,
id: NodeId,
path: &Path,
+ path_depth: usize,
namespace: Namespace,
- check_ribs: bool) -> Option<(Def, LastPrivate)> {
- // First, resolve the types and associated type bindings.
- for ty in path.segments.iter().flat_map(|s| s.parameters.types().into_iter()) {
- self.resolve_type(&**ty);
- }
- for binding in path.segments.iter().flat_map(|s| s.parameters.bindings().into_iter()) {
- self.resolve_type(&*binding.ty);
- }
-
- // A special case for sugared associated type paths `T::A` where `T` is
- // a type parameter and `A` is an associated type on some bound of `T`.
- if namespace == TypeNS && path.segments.len() == 2 {
- match self.resolve_identifier(path.segments[0].identifier,
- TypeNS,
- true,
- path.span) {
- Some((def, last_private)) => {
- match def {
- DefTyParam(_, _, did, _) => {
- let def = DefAssociatedPath(TyParamProvenance::FromParam(did),
- path.segments.last()
- .unwrap().identifier);
- return Some((def, last_private));
- }
- DefSelfTy(nid) => {
- let def = DefAssociatedPath(TyParamProvenance::FromSelf(local_def(nid)),
- path.segments.last()
- .unwrap().identifier);
- return Some((def, last_private));
- }
- _ => {}
- }
- }
- _ => {}
- }
- }
+ check_ribs: bool) -> Option<PathResolution> {
+ 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
+ };
if path.global {
- return self.resolve_crate_relative_path(path, namespace);
+ let def = self.resolve_crate_relative_path(span, segments, namespace);
+ return def.map(mk_res);
}
// Try to find a path to an item in a module.
let unqualified_def =
- self.resolve_identifier(path.segments.last().unwrap().identifier,
+ self.resolve_identifier(segments.last().unwrap().identifier,
namespace,
check_ribs,
- path.span);
+ span);
- if path.segments.len() > 1 {
- let def = self.resolve_module_relative_path(path, namespace);
+ 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,
- path.span,
+ id, span,
"unnecessary qualification".to_string());
}
_ => ()
}
- return def;
+ def.map(mk_res)
+ } else {
+ unqualified_def.map(mk_res)
}
-
- return unqualified_def;
}
// resolve a single identifier (used as a varref)
check_ribs: bool,
span: Span)
-> Option<(Def, LastPrivate)> {
+ // First, check to see whether the name is a primitive type.
+ if namespace == TypeNS {
+ if let Some(&prim_ty) = self.primitive_type_table
+ .primitive_types
+ .get(&identifier.name) {
+ return Some((DefPrimTy(prim_ty), LastMod(AllPublic)));
+ }
+ }
+
if check_ribs {
- match self.resolve_identifier_in_local_ribs(identifier,
- namespace,
- span) {
- Some(def) => {
- return Some((def, LastMod(AllPublic)));
- }
- None => {
- // Continue.
- }
+ if let Some(def) = self.resolve_identifier_in_local_ribs(identifier,
+ namespace,
+ span) {
+ return Some((def, LastMod(AllPublic)));
}
}
- return self.resolve_item_by_name_in_lexical_scope(identifier.name, namespace);
+ self.resolve_item_by_name_in_lexical_scope(identifier.name, namespace)
}
// FIXME #4952: Merge me with resolve_name_in_module?
// resolve a "module-relative" path, e.g. a::b::c
fn resolve_module_relative_path(&mut self,
- path: &Path,
+ span: Span,
+ segments: &[ast::PathSegment],
namespace: Namespace)
-> Option<(Def, LastPrivate)> {
- let module_path = path.segments.init().iter()
- .map(|ps| ps.identifier.name)
- .collect::<Vec<_>>();
+ let module_path = segments.init().iter()
+ .map(|ps| ps.identifier.name)
+ .collect::<Vec<_>>();
let containing_module;
let last_private;
match self.resolve_module_path(module,
&module_path[..],
UseLexicalScope,
- path.span,
+ span,
PathSearch) {
Failed(err) => {
let (span, msg) = match err {
None => {
let msg = format!("Use of undeclared type or module `{}`",
self.names_to_string(&module_path));
- (path.span, msg)
+ (span, msg)
}
};
}
}
- let name = path.segments.last().unwrap().identifier.name;
+ let name = segments.last().unwrap().identifier.name;
let def = match self.resolve_definition_of_name_in_module(containing_module.clone(),
name,
namespace) {
/// Invariant: This must be called only during main resolution, not during
/// import resolution.
fn resolve_crate_relative_path(&mut self,
- path: &Path,
+ span: Span,
+ segments: &[ast::PathSegment],
namespace: Namespace)
-> Option<(Def, LastPrivate)> {
- let module_path = path.segments.init().iter()
- .map(|ps| ps.identifier.name)
- .collect::<Vec<_>>();
+ let module_path = segments.init().iter()
+ .map(|ps| ps.identifier.name)
+ .collect::<Vec<_>>();
let root_module = self.graph_root.get_module();
match self.resolve_module_path_from_root(root_module,
&module_path[..],
0,
- path.span,
+ span,
PathSearch,
LastMod(AllPublic)) {
Failed(err) => {
None => {
let msg = format!("Use of undeclared module `::{}`",
self.names_to_string(&module_path[..]));
- (path.span, msg)
+ (span, msg)
}
};
}
}
- let name = path.segments.last().unwrap().identifier.name;
+ let name = segments.last().unwrap().identifier.name;
match self.resolve_definition_of_name_in_module(containing_module,
name,
namespace) {
local: {:?}",
token::get_ident(ident),
def);
- return Some(def);
+ Some(def)
}
Some(DlField) | Some(DlImpl(_)) | None => {
- return None;
+ None
}
}
}
fn extract_path_and_node_id(t: &Ty, allow: FallbackChecks)
-> Option<(Path, NodeId, FallbackChecks)> {
match t.node {
- TyPath(ref path, node_id) => Some((path.clone(), node_id, allow)),
+ TyPath(None, ref path) => Some((path.clone(), t.id, allow)),
TyPtr(ref mut_ty) => extract_path_and_node_id(&*mut_ty.ty, OnlyTraitAndStatics),
TyRptr(_, ref mut_ty) => extract_path_and_node_id(&*mut_ty.ty, allow),
// This doesn't handle the remaining `Ty` variants as they are not
}
}
+ fn is_static_method(this: &Resolver, did: DefId) -> bool {
+ if did.krate == ast::LOCAL_CRATE {
+ let explicit_self = match this.ast_map.get(did.node) {
+ ast_map::NodeTraitItem(m) => match *m {
+ ast::RequiredMethod(ref m) => &m.explicit_self,
+ ast::ProvidedMethod(ref m) => m.pe_explicit_self(),
+ _ => return false
+ },
+ ast_map::NodeImplItem(m) => match *m {
+ ast::MethodImplItem(ref m) => m.pe_explicit_self(),
+ _ => return false
+ },
+ _ => return false
+ };
+ explicit_self.node == ast::SelfStatic
+ } else {
+ csearch::is_static_method(&this.session.cstore, did)
+ }
+ }
+
let (path, node_id, allowed) = match self.current_self_type {
Some(ref ty) => match extract_path_and_node_id(ty, Everything) {
Some(x) => x,
if allowed == Everything {
// Look for a field with the same name in the current self_type.
- match self.def_map.borrow().get(&node_id) {
- Some(&DefTy(did, _))
- | Some(&DefStruct(did))
- | Some(&DefVariant(_, did, _)) => match self.structs.get(&did) {
+ match self.def_map.borrow().get(&node_id).map(|d| d.full_def()) {
+ Some(DefTy(did, _)) |
+ Some(DefStruct(did)) |
+ Some(DefVariant(_, did, _)) => match self.structs.get(&did) {
None => {}
Some(fields) => {
if fields.iter().any(|&field_name| name == field_name) {
let name_path = path.segments.iter().map(|seg| seg.identifier.name).collect::<Vec<_>>();
// Look for a method in the current self type's impl module.
- match get_module(self, path.span, &name_path[..]) {
- Some(module) => match module.children.borrow().get(&name) {
- Some(binding) => {
- let p_str = self.path_names_to_string(&path);
- match binding.def_for_namespace(ValueNS) {
- Some(DefStaticMethod(_, provenance)) => {
- match provenance {
- FromImpl(_) => return StaticMethod(p_str),
- FromTrait(_) => unreachable!()
- }
- }
- Some(DefMethod(_, None, _)) if allowed == Everything => return Method,
- Some(DefMethod(_, Some(_), _)) => return TraitItem,
- _ => ()
+ if let Some(module) = get_module(self, path.span, &name_path) {
+ if let Some(binding) = module.children.borrow().get(&name) {
+ if let Some(DefMethod(did, _)) = binding.def_for_namespace(ValueNS) {
+ if is_static_method(self, did) {
+ return StaticMethod(self.path_names_to_string(&path, 0))
+ }
+ if self.current_trait_ref.is_some() {
+ return TraitItem;
+ } else if allowed == Everything {
+ return Method;
}
}
- None => {}
- },
- None => {}
+ }
}
// Look for a method in the current trait.
- match self.current_trait_ref {
- Some((did, ref trait_ref)) => {
- let path_str = self.path_names_to_string(&trait_ref.path);
-
- match self.trait_item_map.get(&(name, did)) {
- Some(&StaticMethodTraitItemKind) => {
- return TraitMethod(path_str)
- }
- Some(_) => return TraitItem,
- None => {}
+ if let Some((trait_did, ref trait_ref)) = self.current_trait_ref {
+ if let Some(&did) = self.trait_item_map.get(&(name, trait_did)) {
+ if is_static_method(self, did) {
+ return TraitMethod(self.path_names_to_string(&trait_ref.path, 0));
+ } else {
+ return TraitItem;
}
}
- None => {}
}
NoSuggestion
// Next, resolve the node.
match expr.node {
- // The interpretation of paths depends on whether the path has
- // multiple elements in it or not.
-
- ExprPath(_) | ExprQPath(_) => {
- let mut path_from_qpath;
- let path = match expr.node {
- ExprPath(ref path) => path,
- ExprQPath(ref qpath) => {
- self.resolve_type(&*qpath.self_type);
- self.resolve_trait_reference(expr.id, &*qpath.trait_ref, TraitQPath);
- path_from_qpath = qpath.trait_ref.path.clone();
- path_from_qpath.segments.push(qpath.item_path.clone());
- &path_from_qpath
- }
- _ => unreachable!()
+ // `<T>::a::b::c` is resolved by typeck alone.
+ ExprPath(Some(ast::QSelf { position: 0, .. }), ref path) => {
+ let method_name = path.segments.last().unwrap().identifier.name;
+ let traits = self.search_for_traits_containing_method(method_name);
+ self.trait_map.insert(expr.id, traits);
+ visit::walk_expr(self, expr);
+ }
+
+ ExprPath(ref maybe_qself, ref path) => {
+ let max_assoc_types = if let Some(ref qself) = *maybe_qself {
+ // Make sure the trait is valid.
+ let _ = self.resolve_trait_reference(expr.id, path, 1);
+ path.segments.len() - qself.position
+ } else {
+ path.segments.len()
};
+
+ let mut resolution = self.with_no_errors(|this| {
+ this.resolve_path(expr.id, path, 0, ValueNS, true)
+ });
+ for depth in 1..max_assoc_types {
+ if resolution.is_some() {
+ break;
+ }
+ self.with_no_errors(|this| {
+ resolution = this.resolve_path(expr.id, path, depth, TypeNS, true);
+ });
+ }
+ if let Some(DefMod(_)) = resolution.map(|r| r.base_def) {
+ // A module is not a valid type or value.
+ resolution = None;
+ }
+
// This is a local path in the value namespace. Walk through
// scopes looking for it.
- match self.resolve_path(expr.id, path, ValueNS, true) {
+ if let Some(path_res) = resolution {
// Check if struct variant
- Some((DefVariant(_, _, true), _)) => {
- let path_name = self.path_names_to_string(path);
+ if let DefVariant(_, _, true) = path_res.base_def {
+ let path_name = self.path_names_to_string(path, 0);
self.resolve_error(expr.span,
&format!("`{}` is a struct variant name, but \
this expression \
&format!("Did you mean to write: \
`{} {{ /* fields */ }}`?",
path_name));
- }
- Some(def) => {
+ } else {
// Write the result into the def map.
debug!("(resolving expr) resolved `{}`",
- self.path_names_to_string(path));
+ self.path_names_to_string(path, 0));
+
+ // Partial resolutions will need the set of traits in scope,
+ // so they can be completed during typeck.
+ if path_res.depth != 0 {
+ let method_name = path.segments.last().unwrap().identifier.name;
+ let traits = self.search_for_traits_containing_method(method_name);
+ self.trait_map.insert(expr.id, traits);
+ }
- self.record_def(expr.id, def);
+ self.record_def(expr.id, path_res);
}
- None => {
- // Be helpful if the name refers to a struct
- // (The pattern matching def_tys where the id is in self.structs
- // matches on regular structs while excluding tuple- and enum-like
- // structs, which wouldn't result in this error.)
- let path_name = self.path_names_to_string(path);
- match self.with_no_errors(|this|
- this.resolve_path(expr.id, path, TypeNS, false)) {
- Some((DefTy(struct_id, _), _))
- if self.structs.contains_key(&struct_id) => {
- self.resolve_error(expr.span,
- &format!("`{}` is a structure name, but \
- this expression \
- uses it like a function name",
- path_name));
-
- self.session.span_help(expr.span,
- &format!("Did you mean to write: \
- `{} {{ /* fields */ }}`?",
- path_name));
-
- }
- _ => {
- let mut method_scope = false;
- self.value_ribs.iter().rev().all(|rib| {
- let res = match *rib {
- Rib { bindings: _, kind: MethodRibKind(_, _) } => true,
- Rib { bindings: _, kind: ItemRibKind } => false,
- _ => return true, // Keep advancing
- };
-
- method_scope = res;
- false // Stop advancing
- });
+ } else {
+ // Be helpful if the name refers to a struct
+ // (The pattern matching def_tys where the id is in self.structs
+ // matches on regular structs while excluding tuple- and enum-like
+ // structs, which wouldn't result in this error.)
+ let path_name = self.path_names_to_string(path, 0);
+ let type_res = self.with_no_errors(|this| {
+ this.resolve_path(expr.id, path, 0, TypeNS, false)
+ });
+ match type_res.map(|r| r.base_def) {
+ Some(DefTy(struct_id, _))
+ if self.structs.contains_key(&struct_id) => {
+ self.resolve_error(expr.span,
+ &format!("`{}` is a structure name, but \
+ this expression \
+ uses it like a function name",
+ path_name));
+
+ self.session.span_help(expr.span,
+ &format!("Did you mean to write: \
+ `{} {{ /* fields */ }}`?",
+ path_name));
- if method_scope && &token::get_name(self.self_name)[..]
- == path_name {
- self.resolve_error(
- expr.span,
- "`self` is not available \
- in a static method. Maybe a \
- `self` argument is missing?");
- } else {
- let last_name = path.segments.last().unwrap().identifier.name;
- let mut msg = match self.find_fallback_in_self_type(last_name) {
- NoSuggestion => {
- // limit search to 5 to reduce the number
- // of stupid suggestions
- self.find_best_match_for_name(&path_name, 5)
- .map_or("".to_string(),
- |x| format!("`{}`", x))
- }
- Field =>
- format!("`self.{}`", path_name),
- Method
- | TraitItem =>
- format!("to call `self.{}`", path_name),
- TraitMethod(path_str)
- | StaticMethod(path_str) =>
- format!("to call `{}::{}`", path_str, path_name)
- };
-
- if msg.len() > 0 {
- msg = format!(". Did you mean {}?", msg)
- }
+ }
+ _ => {
+ // Keep reporting some errors even if they're ignored above.
+ self.resolve_path(expr.id, path, 0, ValueNS, true);
+
+ let mut method_scope = false;
+ self.value_ribs.iter().rev().all(|rib| {
+ method_scope = match rib.kind {
+ MethodRibKind => true,
+ ItemRibKind | ConstantItemRibKind => false,
+ _ => return true, // Keep advancing
+ };
+ false // Stop advancing
+ });
+ if method_scope && &token::get_name(self.self_name)[..]
+ == path_name {
self.resolve_error(
expr.span,
- &format!("unresolved name `{}`{}",
- path_name,
- msg));
+ "`self` is not available \
+ in a static method. Maybe a \
+ `self` argument is missing?");
+ } else {
+ let last_name = path.segments.last().unwrap().identifier.name;
+ let mut msg = match self.find_fallback_in_self_type(last_name) {
+ NoSuggestion => {
+ // limit search to 5 to reduce the number
+ // of stupid suggestions
+ self.find_best_match_for_name(&path_name, 5)
+ .map_or("".to_string(),
+ |x| format!("`{}`", x))
+ }
+ Field => format!("`self.{}`", path_name),
+ Method |
+ TraitItem =>
+ format!("to call `self.{}`", path_name),
+ TraitMethod(path_str) |
+ StaticMethod(path_str) =>
+ format!("to call `{}::{}`", path_str, path_name)
+ };
+
+ if msg.len() > 0 {
+ msg = format!(". Did you mean {}?", msg)
}
+
+ self.resolve_error(
+ expr.span,
+ &format!("unresolved name `{}`{}",
+ path_name, msg));
}
}
}
visit::walk_expr(self, expr);
}
- ExprClosure(_, ref fn_decl, ref block) => {
- self.resolve_function(ClosureRibKind(expr.id),
- Some(&**fn_decl), NoTypeParameters,
- &**block);
- }
-
ExprStruct(ref path, _, _) => {
// Resolve the path to the structure it goes to. We don't
// check to ensure that the path is actually a structure; that
// is checked later during typeck.
- match self.resolve_path(expr.id, path, TypeNS, false) {
+ match self.resolve_path(expr.id, path, 0, TypeNS, false) {
Some(definition) => self.record_def(expr.id, definition),
- result => {
- debug!("(resolving expression) didn't find struct \
- def: {:?}", result);
+ None => {
+ debug!("(resolving expression) didn't find struct def",);
let msg = format!("`{}` does not name a structure",
- self.path_names_to_string(path));
+ self.path_names_to_string(path, 0));
self.resolve_error(path.span, &msg[..]);
}
}
}
Some(DlDef(def @ DefLabel(_))) => {
// Since this def is a label, it is never read.
- self.record_def(expr.id, (def, LastMod(AllPublic)))
+ self.record_def(expr.id, PathResolution {
+ base_def: def,
+ last_private: LastMod(AllPublic),
+ depth: 0
+ })
}
Some(_) => {
self.session.span_bug(expr.span,
None => continue
};
let trait_def_id = match def {
- DefaultImpl(trait_def_id) => trait_def_id,
+ DefTrait(trait_def_id) => trait_def_id,
_ => continue,
};
if self.trait_item_map.contains_key(&(name, trait_def_id)) {
Some(target) => target,
};
let did = match target.bindings.def_for_namespace(TypeNS) {
- Some(DefaultImpl(trait_def_id)) => trait_def_id,
+ Some(DefTrait(trait_def_id)) => trait_def_id,
Some(..) | None => continue,
};
if self.trait_item_map.contains_key(&(name, did)) {
found_traits
}
- fn record_def(&mut self, node_id: NodeId, (def, lp): (Def, LastPrivate)) {
- debug!("(recording def) recording {:?} for {}, last private {:?}",
- def, node_id, lp);
- assert!(match lp {LastImport{..} => false, _ => true},
+ fn record_def(&mut self, node_id: NodeId, resolution: PathResolution) {
+ debug!("(recording def) recording {:?} for {}", resolution, node_id);
+ assert!(match resolution.last_private {LastImport{..} => false, _ => true},
"Import should only be used for `use` directives");
- self.last_private.insert(node_id, lp);
- match self.def_map.borrow_mut().entry(node_id) {
- // Resolve appears to "resolve" the same ID multiple
- // times, so here is a sanity check it at least comes to
- // the same conclusion! - nmatsakis
- Occupied(entry) => if def != *entry.get() {
- self.session
- .bug(&format!("node_id {} resolved first to {:?} and \
- then {:?}",
- node_id,
- *entry.get(),
- def));
- },
- Vacant(entry) => { entry.insert(def); },
+ if let Some(prev_res) = self.def_map.borrow_mut().insert(node_id, resolution) {
+ let span = self.ast_map.opt_span(node_id).unwrap_or(codemap::DUMMY_SP);
+ self.session.span_bug(span, &format!("path resolved multiple times \
+ ({:?} before, {:?} now)",
+ prev_res, resolution));
}
}
pub export_map: ExportMap,
pub trait_map: TraitMap,
pub external_exports: ExternalExports,
- pub last_private_map: LastPrivateMap,
pub glob_map: Option<GlobMap>
}
export_map: resolver.export_map,
trait_map: resolver.trait_map,
external_exports: resolver.external_exports,
- last_private_map: resolver.last_private,
glob_map: if resolver.make_glob_map {
Some(resolver.glob_map)
} else {
llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _);
- let opt = sess.opts.cg.opt_level.unwrap_or(0) as libc::c_uint;
+ let opt = match sess.opts.optimize {
+ config::No => 0,
+ config::Less => 1,
+ config::Default => 2,
+ config::Aggressive => 3,
+ };
let builder = llvm::LLVMPassManagerBuilderCreate();
llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt);
self.sess.bug(&format!("def_map has no key for {} in lookup_type_ref",
ref_id));
}
- let def = (*self.analysis.ty_cx.def_map.borrow())[ref_id];
+ let def = self.analysis.ty_cx.def_map.borrow()[ref_id].full_def();
match def {
def::DefPrimTy(_) => None,
_ => Some(def.def_id()),
self.sess.span_bug(span, &format!("def_map has no key for {} in lookup_def_kind",
ref_id));
}
- let def = (*def_map)[ref_id];
+ let def = def_map[ref_id].full_def();
match def {
def::DefMod(_) |
def::DefForeignMod(_) => Some(recorder::ModRef),
def::DefStruct(_) => Some(recorder::StructRef),
def::DefTy(..) |
def::DefAssociatedTy(..) |
- def::DefAssociatedPath(..) |
- def::DefaultImpl(_) => Some(recorder::TypeRef),
+ def::DefTrait(_) => Some(recorder::TypeRef),
def::DefStatic(_, _) |
def::DefConst(_) |
def::DefLocal(_) |
def::DefSelfTy(_) |
def::DefRegion(_) |
- def::DefTyParamBinder(_) |
def::DefLabel(_) |
- def::DefStaticMethod(..) |
def::DefTyParam(..) |
def::DefUse(_) |
def::DefMethod(..) |
let trait_id = trait_ref.as_ref().and_then(|tr| self.lookup_type_ref(tr.ref_id));
match typ.node {
// Common case impl for a struct or something basic.
- ast::TyPath(ref path, id) => {
+ ast::TyPath(None, ref path) => {
let sub_span = self.span.sub_span_for_type_name(path.span);
- let self_id = self.lookup_type_ref(id).map(|id| {
+ let self_id = self.lookup_type_ref(typ.id).map(|id| {
self.fmt.ref_str(recorder::TypeRef,
path.span,
sub_span,
self.sess.span_bug(span,
&format!("def_map has no key for {} in visit_expr", id));
}
- let def = &(*def_map)[id];
+ let def = def_map[id].full_def();
let sub_span = self.span.span_for_last_ident(span);
- match *def {
+ match def {
def::DefUpvar(..) |
def::DefLocal(..) |
def::DefStatic(..) |
sub_span,
def_id,
self.cur_scope),
- def::DefStaticMethod(declid, provenence) |
- def::DefMethod(declid, _, provenence) => {
+ def::DefMethod(declid, provenence) => {
let sub_span = self.span.sub_span_for_meth_name(span);
let defid = if declid.krate == ast::LOCAL_CRATE {
let ti = ty::impl_or_trait_item(&self.analysis.ty_cx,
&format!("Unexpected def kind while looking \
up path in `{}`: `{:?}`",
self.span.snippet(span),
- *def)),
+ def)),
}
// modules or types in the path prefix
- match *def {
- def::DefStaticMethod(..) => self.write_sub_path_trait_truncated(path),
+ match def {
+ def::DefMethod(did, _) => {
+ let ti = ty::impl_or_trait_item(&self.analysis.ty_cx, did);
+ if let ty::MethodTraitItem(m) = ti {
+ if m.explicit_self == ty::StaticExplicitSelfCategory {
+ self.write_sub_path_trait_truncated(path);
+ }
+ }
+ }
def::DefLocal(_) |
def::DefStatic(_,_) |
def::DefConst(..) |
self.collected_paths.push((p.id, path.clone(), false, recorder::StructRef));
visit::walk_path(self, path);
- let def = self.analysis.ty_cx.def_map.borrow()[p.id];
+ let def = self.analysis.ty_cx.def_map.borrow()[p.id].full_def();
let struct_def = match def {
def::DefConst(..) => None,
def::DefVariant(_, variant_id, _) => Some(variant_id),
}
match t.node {
- ast::TyPath(ref path, id) => {
- match self.lookup_type_ref(id) {
+ ast::TyPath(_, ref path) => {
+ match self.lookup_type_ref(t.id) {
Some(id) => {
let sub_span = self.span.sub_span_for_type_name(t.span);
self.fmt.ref_str(recorder::TypeRef,
// Don't need to do anything for function calls,
// because just walking the callee path does what we want.
visit::walk_expr(self, ex);
- },
- ast::ExprPath(ref path) => {
- self.process_path(ex.id, path.span, path, None);
- visit::walk_path(self, path);
}
- ast::ExprQPath(ref qpath) => {
- let mut path = qpath.trait_ref.path.clone();
- path.segments.push(qpath.item_path.clone());
- self.process_path(ex.id, ex.span, &path, None);
- visit::walk_qpath(self, ex.span, &**qpath);
+ ast::ExprPath(_, ref path) => {
+ self.process_path(ex.id, path.span, path, None);
+ visit::walk_expr(self, ex);
}
ast::ExprStruct(ref path, ref fields, ref base) =>
self.process_struct_lit(ex, path, fields, base),
&format!("def_map has no key for {} in visit_arm",
id));
}
- let def = &(*def_map)[id];
- match *def {
+ let def = def_map[id].full_def();
+ match def {
def::DefLocal(id) => {
let value = if *immut {
self.span.snippet(p.span).to_string()
def::DefStatic(_, _) => {}
def::DefConst(..) => {}
_ => error!("unexpected definition kind when processing collected paths: {:?}",
- *def)
+ def)
}
}
for &(id, ref path, ref_kind) in &paths_to_process {
let mut toks = self.retokenise_span(span);
// We keep track of how many brackets we're nested in
let mut bracket_count = 0;
+ let mut found_ufcs_sep = false;
loop {
let ts = toks.real_token();
if ts.tok == token::Eof {
}
bracket_count += match ts.tok {
token::Lt => 1,
- token::Gt => -1,
+ token::Gt => {
+ // Ignore the `>::` in `<Type as Trait>::AssocTy`.
+ if !found_ufcs_sep && bracket_count == 0 {
+ found_ufcs_sep = true;
+ 0
+ } else {
+ -1
+ }
+ }
token::BinOp(token::Shl) => 2,
token::BinOp(token::Shr) => -2,
_ => 0
};
- if ts.tok.is_ident() &&
- bracket_count == nesting {
+ if ts.tok.is_ident() && bracket_count == nesting {
result.push(self.make_sub_span(span, Some(ts.sp)).unwrap());
}
}
}
ast::PatIdent(..) | ast::PatEnum(..) | ast::PatStruct(..) => {
// This is either an enum variant or a variable binding.
- let opt_def = tcx.def_map.borrow().get(&cur.id).cloned();
+ let opt_def = tcx.def_map.borrow().get(&cur.id).map(|d| d.full_def());
match opt_def {
Some(def::DefVariant(enum_id, var_id, _)) => {
let variant = ty::enum_variant_with_id(tcx, enum_id, var_id);
match pat.node {
ast::PatTup(_) => true,
ast::PatStruct(..) => {
- match tcx.def_map.borrow().get(&pat.id) {
- Some(&def::DefVariant(..)) => false,
+ match tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
+ Some(def::DefVariant(..)) => false,
_ => true,
}
}
ast::PatEnum(..) | ast::PatIdent(_, _, None) => {
- match tcx.def_map.borrow().get(&pat.id) {
- Some(&def::DefStruct(..)) => true,
+ match tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
+ Some(def::DefStruct(..)) => true,
_ => false
}
}
/// Checks whether the binding in `discr` is assigned to anywhere in the expression `body`
fn is_discr_reassigned(bcx: Block, discr: &ast::Expr, body: &ast::Expr) -> bool {
let (vid, field) = match discr.node {
- ast::ExprPath(_) | ast::ExprQPath(_) => match bcx.def(discr.id) {
+ ast::ExprPath(..) => match bcx.def(discr.id) {
def::DefLocal(vid) | def::DefUpvar(vid, _) => (vid, None),
_ => return false
},
ast::ExprField(ref base, field) => {
- let vid = match bcx.tcx().def_map.borrow().get(&base.id) {
- Some(&def::DefLocal(vid)) | Some(&def::DefUpvar(vid, _)) => vid,
+ let vid = match bcx.tcx().def_map.borrow().get(&base.id).map(|d| d.full_def()) {
+ Some(def::DefLocal(vid)) | Some(def::DefUpvar(vid, _)) => vid,
_ => return false
};
(vid, Some(mc::NamedField(field.node.name)))
},
ast::ExprTupField(ref base, field) => {
- let vid = match bcx.tcx().def_map.borrow().get(&base.id) {
- Some(&def::DefLocal(vid)) | Some(&def::DefUpvar(vid, _)) => vid,
+ let vid = match bcx.tcx().def_map.borrow().get(&base.id).map(|d| d.full_def()) {
+ Some(def::DefLocal(vid)) | Some(def::DefUpvar(vid, _)) => vid,
_ => return false
};
(vid, Some(mc::PositionalField(field.node)))
}
}
ast::PatEnum(_, ref sub_pats) => {
- let opt_def = bcx.tcx().def_map.borrow().get(&pat.id).cloned();
+ let opt_def = bcx.tcx().def_map.borrow().get(&pat.id).map(|d| d.full_def());
match opt_def {
Some(def::DefVariant(enum_id, var_id, _)) => {
let repr = adt::represent_node(bcx, pat.id);
// pick out special kinds of expressions that can be called:
match expr.node {
- ast::ExprPath(_) | ast::ExprQPath(_) => {
+ ast::ExprPath(..) => {
return trans_def(bcx, bcx.def(expr.id), expr);
}
_ => {}
let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did);
Callee { bcx: bcx, data: Intrinsic(def_id.node, substs) }
}
- def::DefFn(did, _) | def::DefMethod(did, _, def::FromImpl(_)) |
- def::DefStaticMethod(did, def::FromImpl(_)) => {
+ def::DefFn(did, _) | def::DefMethod(did, def::FromImpl(_)) => {
fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id),
bcx.fcx.param_substs).val)
}
- def::DefStaticMethod(meth_did, def::FromTrait(trait_did)) |
- def::DefMethod(meth_did, _, def::FromTrait(trait_did)) => {
+ def::DefMethod(meth_did, def::FromTrait(trait_did)) => {
fn_callee(bcx, meth::trans_static_method_callee(bcx.ccx(),
meth_did,
trait_did,
def::DefUpvar(..) => {
datum_callee(bcx, ref_expr)
}
- def::DefMod(..) | def::DefForeignMod(..) | def::DefaultImpl(..) |
+ def::DefMod(..) | def::DefForeignMod(..) | def::DefTrait(..) |
def::DefTy(..) | def::DefPrimTy(..) | def::DefAssociatedTy(..) |
- def::DefUse(..) | def::DefTyParamBinder(..) |
- def::DefRegion(..) | def::DefLabel(..) | def::DefTyParam(..) |
- def::DefSelfTy(..) | def::DefAssociatedPath(..) => {
+ def::DefUse(..) | def::DefRegion(..) | def::DefLabel(..) |
+ def::DefTyParam(..) | def::DefSelfTy(..) => {
bcx.tcx().sess.span_bug(
ref_expr.span,
&format!("cannot translate def {:?} \
pub fn def(&self, nid: ast::NodeId) -> def::Def {
match self.tcx().def_map.borrow().get(&nid) {
- Some(v) => v.clone(),
+ Some(v) => v.full_def(),
None => {
self.tcx().sess.bug(&format!(
"no def associated with node id {}", nid));
-> ValueRef {
// Special-case constants to cache a common global for all uses.
match expr.node {
- ast::ExprPath(_) => {
- let def = ccx.tcx().def_map.borrow()[expr.id];
+ ast::ExprPath(..) => {
+ let def = ccx.tcx().def_map.borrow()[expr.id].full_def();
match def {
def::DefConst(def_id) => {
if !ccx.tcx().adjustments.borrow().contains_key(&expr.id) {
};
unsafe {
let _icx = push_ctxt("const_expr");
- return match e.node {
+ match e.node {
ast::ExprLit(ref lit) => {
const_lit(cx, e, &**lit)
}
let (te2, _) = const_expr(cx, &**e2, param_substs);
let te2 = base::cast_shift_const_rhs(b, te1, te2);
- return match b.node {
+ match b.node {
ast::BiAdd => {
if is_float { llvm::LLVMConstFAdd(te1, te2) }
else { llvm::LLVMConstAdd(te1, te2) }
ast::ExprUnary(u, ref e) => {
let (te, ty) = const_expr(cx, &**e, param_substs);
let is_float = ty::type_is_fp(ty);
- return match u {
+ match u {
ast::UnUniq | ast::UnDeref => {
const_deref(cx, te, ty).0
}
if expr::cast_is_noop(basety, ety) {
return v;
}
- return match (expr::cast_type_kind(cx.tcx(), basety),
- expr::cast_type_kind(cx.tcx(), ety)) {
+ match (expr::cast_type_kind(cx.tcx(), basety),
+ expr::cast_type_kind(cx.tcx(), ety)) {
(expr::cast_integral, expr::cast_integral) => {
let s = ty::type_is_signed(basety) as Bool;
_ => break,
}
}
- let opt_def = cx.tcx().def_map.borrow().get(&cur.id).cloned();
+ let opt_def = cx.tcx().def_map.borrow().get(&cur.id).map(|d| d.full_def());
if let Some(def::DefStatic(def_id, _)) = opt_def {
- return get_static_val(cx, def_id, ety);
+ get_static_val(cx, def_id, ety)
+ } else {
+ // If this isn't the address of a static, then keep going through
+ // normal constant evaluation.
+ let (v, _) = const_expr(cx, &**sub, param_substs);
+ addr_of(cx, v, "ref", e.id)
}
-
- // If this isn't the address of a static, then keep going through
- // normal constant evaluation.
- let (v, _) = const_expr(cx, &**sub, param_substs);
- addr_of(cx, v, "ref", e.id)
}
ast::ExprAddrOf(ast::MutMutable, ref sub) => {
let (v, _) = const_expr(cx, &**sub, param_substs);
C_array(llunitty, &vs[..])
}
}
- ast::ExprPath(_) | ast::ExprQPath(_) => {
- let def = cx.tcx().def_map.borrow()[e.id];
+ ast::ExprPath(..) => {
+ let def = cx.tcx().def_map.borrow()[e.id].full_def();
match def {
- def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) => {
+ def::DefFn(..) | def::DefMethod(..) => {
expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
}
def::DefConst(def_id) => {
}
}
ast::ExprCall(ref callee, ref args) => {
- let opt_def = cx.tcx().def_map.borrow().get(&callee.id).cloned();
+ let opt_def = cx.tcx().def_map.borrow().get(&callee.id).map(|d| d.full_def());
let arg_vals = map_list(&args[..]);
match opt_def {
Some(def::DefStruct(_)) => {
}
_ => cx.sess().span_bug(e.span,
"bad constant expression type in consts::const_expr")
- };
+ }
}
}
let loop_id = match opt_label {
None => fcx.top_loop_scope(),
Some(_) => {
- match bcx.tcx().def_map.borrow().get(&expr.id) {
- Some(&def::DefLabel(loop_id)) => loop_id,
- ref r => {
- bcx.tcx().sess.bug(&format!("{:?} in def-map for label",
- r))
+ match bcx.tcx().def_map.borrow().get(&expr.id).map(|d| d.full_def()) {
+ Some(def::DefLabel(loop_id)) => loop_id,
+ r => {
+ bcx.tcx().sess.bug(&format!("{:?} in def-map for label", r))
}
}
}
ast::ExprLit(_) |
ast::ExprBreak(_) |
ast::ExprAgain(_) |
- ast::ExprPath(_) |
- ast::ExprQPath(_) => {}
+ ast::ExprPath(..) => {}
ast::ExprCast(ref sub_exp, _) |
ast::ExprAddrOf(_, ref sub_exp) |
// it prefers in-place instantiation, likely because it contains
// `[x; N]` somewhere within.
match expr.node {
- ast::ExprPath(_) | ast::ExprQPath(_) => {
+ ast::ExprPath(..) => {
match bcx.def(expr.id) {
def::DefConst(did) => {
let expr = consts::get_const_expr(bcx.ccx(), did, expr);
ast::ExprParen(ref e) => {
trans(bcx, &**e)
}
- ast::ExprPath(_) | ast::ExprQPath(_) => {
+ ast::ExprPath(..) => {
trans_def(bcx, expr, bcx.def(expr.id))
}
ast::ExprField(ref base, ident) => {
let _icx = push_ctxt("trans_def_lvalue");
match def {
- def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) |
+ def::DefFn(..) | def::DefMethod(..) |
def::DefStruct(_) | def::DefVariant(..) => {
let datum = trans_def_fn_unadjusted(bcx.ccx(), ref_expr, def,
bcx.fcx.param_substs);
ast::ExprParen(ref e) => {
trans_into(bcx, &**e, dest)
}
- ast::ExprPath(_) | ast::ExprQPath(_) => {
+ ast::ExprPath(..) => {
trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest)
}
ast::ExprIf(ref cond, ref thn, ref els) => {
match def {
def::DefFn(did, _) |
def::DefStruct(did) | def::DefVariant(_, did, _) |
- def::DefStaticMethod(did, def::FromImpl(_)) |
- def::DefMethod(did, _, def::FromImpl(_)) => {
+ def::DefMethod(did, def::FromImpl(_)) => {
callee::trans_fn_ref(ccx, did, ExprId(ref_expr.id), param_substs)
}
- def::DefStaticMethod(impl_did, def::FromTrait(trait_did)) |
- def::DefMethod(impl_did, _, def::FromTrait(trait_did)) => {
+ def::DefMethod(impl_did, def::FromTrait(trait_did)) => {
meth::trans_static_method_callee(ccx, impl_did,
trait_did, ref_expr.id,
param_substs)
ty.repr(tcx)));
}
Some(node_id) => {
- let def = tcx.def_map.borrow()[node_id].clone();
+ let def = tcx.def_map.borrow()[node_id].full_def();
match def {
def::DefVariant(enum_id, variant_id, _) => {
let variant_info = ty::enum_variant_with_id(
//! case but `&a` in the second. Basically, defaults that appear inside
//! an rptr (`&r.T`) use the region `r` that appears in the rptr.
-use middle::astconv_util::{ast_ty_to_prim_ty, check_path_args, NO_TPS, NO_REGIONS};
+use middle::astconv_util::{prim_ty_to_ty, check_path_args, NO_TPS, NO_REGIONS};
use middle::const_eval;
use middle::def;
use middle::resolve_lifetime as rl;
+use middle::privacy::{AllPublic, LastMod};
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
use middle::traits;
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
-use TypeAndSubsts;
use util::common::{ErrorReported, FN_OUTPUT_NAME};
use util::nodemap::DefIdMap;
use util::ppaux::{self, Repr, UserString};
-use std::rc::Rc;
use std::iter::{repeat, AdditiveIterator};
+use std::rc::Rc;
+use std::slice;
use syntax::{abi, ast, ast_util};
use syntax::codemap::Span;
use syntax::parse::token;
pub trait AstConv<'tcx> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>;
- fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx>;
+ fn get_item_type_scheme(&self, span: Span, id: ast::DefId)
+ -> Result<ty::TypeScheme<'tcx>, ErrorReported>;
- fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef<'tcx>>;
+ fn get_trait_def(&self, span: Span, id: ast::DefId)
+ -> Result<Rc<ty::TraitDef<'tcx>>, ErrorReported>;
+
+ fn get_type_parameter_bounds(&self, span: Span, def_id: ast::NodeId)
+ -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>;
/// Return an (optional) substitution to convert bound type parameters that
/// are in scope into free ones. This function should only return Some
pub fn ast_path_substs_for_ty<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
+ span: Span,
+ param_mode: PathParamMode,
decl_generics: &ty::Generics<'tcx>,
- path: &ast::Path)
+ item_segment: &ast::PathSegment)
-> Substs<'tcx>
{
let tcx = this.tcx();
assert!(decl_generics.regions.all(|d| d.space == TypeSpace));
assert!(decl_generics.types.all(|d| d.space != FnSpace));
- let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
+ let (regions, types, assoc_bindings) = match item_segment.parameters {
ast::AngleBracketedParameters(ref data) => {
- convert_angle_bracketed_parameters(this, rscope, path.span, decl_generics, data)
+ convert_angle_bracketed_parameters(this, rscope, span, decl_generics, data)
}
ast::ParenthesizedParameters(ref data) => {
- span_err!(tcx.sess, path.span, E0214,
+ span_err!(tcx.sess, span, E0214,
"parenthesized parameters may only be used with a trait");
- convert_parenthesized_parameters(this, rscope, path.span, decl_generics, data)
+ convert_parenthesized_parameters(this, rscope, span, decl_generics, data)
}
};
prohibit_projections(this.tcx(), &assoc_bindings);
create_substs_for_ast_path(this,
- path.span,
+ span,
+ param_mode,
decl_generics,
None,
types,
regions)
}
+#[derive(PartialEq, Eq)]
+pub enum PathParamMode {
+ // Any path in a type context.
+ Explicit,
+ // The `module::Type` in `module::Type::method` in an expression.
+ Optional
+}
+
fn create_region_substs<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
fn create_substs_for_ast_path<'tcx>(
this: &AstConv<'tcx>,
span: Span,
+ param_mode: PathParamMode,
decl_generics: &ty::Generics<'tcx>,
self_ty: Option<Ty<'tcx>>,
types_provided: Vec<Ty<'tcx>>,
// Convert the type parameters supplied by the user.
let ty_param_defs = decl_generics.types.get_slice(TypeSpace);
- let supplied_ty_param_count = types_provided.len();
let formal_ty_param_count = ty_param_defs.len();
let required_ty_param_count = ty_param_defs.iter()
.take_while(|x| x.default.is_none())
.count();
- let mut type_substs = types_provided;
+ // Fill with `ty_infer` if no params were specified, as long as
+ // they were optional (e.g. paths inside expressions).
+ let mut type_substs = if param_mode == PathParamMode::Optional &&
+ types_provided.is_empty() {
+ (0..formal_ty_param_count).map(|_| this.ty_infer(span)).collect()
+ } else {
+ types_provided
+ };
+
+ let supplied_ty_param_count = type_substs.len();
check_type_argument_count(this.tcx(), span, supplied_ty_param_count,
required_ty_param_count, formal_ty_param_count);
}
}
- return substs;
+ substs
}
struct ConvertedBinding<'tcx> {
// lifetimes. Oh well, not there yet.
let shifted_rscope = ShiftedRscope::new(rscope);
- let trait_ref =
- instantiate_trait_ref(this, &shifted_rscope, &ast_trait_ref.trait_ref,
- self_ty, Some(&mut projections));
+ let trait_ref = instantiate_trait_ref(this, &shifted_rscope,
+ &ast_trait_ref.trait_ref,
+ None, self_ty, Some(&mut projections));
for projection in projections {
poly_projections.push(ty::Binder(projection));
pub fn instantiate_trait_ref<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
- ast_trait_ref: &ast::TraitRef,
+ trait_ref: &ast::TraitRef,
+ impl_id: Option<ast::NodeId>,
self_ty: Option<Ty<'tcx>>,
projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>)
-> Rc<ty::TraitRef<'tcx>>
{
- match ::lookup_def_tcx(this.tcx(), ast_trait_ref.path.span, ast_trait_ref.ref_id) {
- def::DefaultImpl(trait_def_id) => {
+ let path = &trait_ref.path;
+ match ::lookup_full_def(this.tcx(), path.span, trait_ref.ref_id) {
+ def::DefTrait(trait_def_id) => {
let trait_ref = ast_path_to_trait_ref(this,
rscope,
+ path.span,
+ PathParamMode::Explicit,
trait_def_id,
self_ty,
- &ast_trait_ref.path,
+ path.segments.last().unwrap(),
projections);
- this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id, trait_ref.clone());
+ if let Some(id) = impl_id {
+ this.tcx().impl_trait_refs.borrow_mut().insert(id, trait_ref.clone());
+ }
trait_ref
}
_ => {
- span_fatal!(this.tcx().sess, ast_trait_ref.path.span, E0245,
- "`{}` is not a trait",
- ast_trait_ref.path.user_string(this.tcx()));
+ span_fatal!(this.tcx().sess, path.span, E0245, "`{}` is not a trait",
+ path.user_string(this.tcx()));
}
}
}
fn object_path_to_poly_trait_ref<'a,'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
+ span: Span,
+ param_mode: PathParamMode,
trait_def_id: ast::DefId,
- path: &ast::Path,
+ trait_segment: &ast::PathSegment,
mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
-> ty::PolyTraitRef<'tcx>
{
let mut tmp = Vec::new();
let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
&shifted_rscope,
+ span,
+ param_mode,
trait_def_id,
None,
- path,
+ trait_segment,
Some(&mut tmp)));
projections.extend(tmp.into_iter().map(ty::Binder));
trait_ref
fn ast_path_to_trait_ref<'a,'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
+ span: Span,
+ param_mode: PathParamMode,
trait_def_id: ast::DefId,
self_ty: Option<Ty<'tcx>>,
- path: &ast::Path,
+ trait_segment: &ast::PathSegment,
mut projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>)
-> Rc<ty::TraitRef<'tcx>>
{
- debug!("ast_path_to_trait_ref {:?}", path);
- let trait_def = this.get_trait_def(trait_def_id);
+ debug!("ast_path_to_trait_ref {:?}", trait_segment);
+ let trait_def = match this.get_trait_def(span, trait_def_id) {
+ Ok(trait_def) => trait_def,
+ Err(ErrorReported) => {
+ // No convenient way to recover from a cycle here. Just bail. Sorry!
+ this.tcx().sess.abort_if_errors();
+ this.tcx().sess.bug("ErrorReported returned, but no errors reports?")
+ }
+ };
- let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
+ let (regions, types, assoc_bindings) = match trait_segment.parameters {
ast::AngleBracketedParameters(ref data) => {
// For now, require that parenthetical notation be used
// only with `Fn()` etc.
if !this.tcx().sess.features.borrow().unboxed_closures && trait_def.paren_sugar {
- span_err!(this.tcx().sess, path.span, E0215,
+ span_err!(this.tcx().sess, span, E0215,
"angle-bracket notation is not stable when \
used with the `Fn` family of traits, use parentheses");
- span_help!(this.tcx().sess, path.span,
+ span_help!(this.tcx().sess, span,
"add `#![feature(unboxed_closures)]` to \
the crate attributes to enable");
}
- convert_angle_bracketed_parameters(this, rscope, path.span, &trait_def.generics, data)
+ convert_angle_bracketed_parameters(this, rscope, span, &trait_def.generics, data)
}
ast::ParenthesizedParameters(ref data) => {
// For now, require that parenthetical notation be used
// only with `Fn()` etc.
if !this.tcx().sess.features.borrow().unboxed_closures && !trait_def.paren_sugar {
- span_err!(this.tcx().sess, path.span, E0216,
+ span_err!(this.tcx().sess, span, E0216,
"parenthetical notation is only stable when \
used with the `Fn` family of traits");
- span_help!(this.tcx().sess, path.span,
+ span_help!(this.tcx().sess, span,
"add `#![feature(unboxed_closures)]` to \
the crate attributes to enable");
}
- convert_parenthesized_parameters(this, rscope, path.span, &trait_def.generics, data)
+ convert_parenthesized_parameters(this, rscope, span, &trait_def.generics, data)
}
};
let substs = create_substs_for_ast_path(this,
- path.span,
+ span,
+ param_mode,
&trait_def.generics,
self_ty,
types,
})
}
-pub fn ast_path_to_ty<'tcx>(
+fn ast_path_to_ty<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
+ span: Span,
+ param_mode: PathParamMode,
did: ast::DefId,
- path: &ast::Path)
- -> TypeAndSubsts<'tcx>
+ item_segment: &ast::PathSegment)
+ -> Ty<'tcx>
{
let tcx = this.tcx();
- let ty::TypeScheme {
- generics,
- ty: decl_ty
- } = this.get_item_type_scheme(did);
-
- let substs = ast_path_substs_for_ty(this,
- rscope,
- &generics,
- path);
- let ty = decl_ty.subst(tcx, &substs);
- TypeAndSubsts { substs: substs, ty: ty }
-}
+ let (generics, decl_ty) = match this.get_item_type_scheme(span, did) {
+ Ok(ty::TypeScheme { generics, ty: decl_ty }) => {
+ (generics, decl_ty)
+ }
+ Err(ErrorReported) => {
+ return tcx.types.err;
+ }
+ };
-/// Converts the given AST type to a built-in type. A "built-in type" is, at
-/// present, either a core numeric type, a string, or `Box`.
-pub fn ast_ty_to_builtin_ty<'tcx>(
- this: &AstConv<'tcx>,
- rscope: &RegionScope,
- ast_ty: &ast::Ty)
- -> Option<Ty<'tcx>> {
- match ast_ty_to_prim_ty(this.tcx(), ast_ty) {
- Some(typ) => return Some(typ),
- None => {}
- }
+ let substs = ast_path_substs_for_ty(this, rscope,
+ span, param_mode,
+ &generics, item_segment);
- match ast_ty.node {
- ast::TyPath(ref path, id) => {
- let a_def = match this.tcx().def_map.borrow().get(&id) {
- None => {
- this.tcx()
- .sess
- .span_bug(ast_ty.span,
- &format!("unbound path {}",
- path.repr(this.tcx())))
- }
- Some(&d) => d
- };
-
- // FIXME(#12938): This is a hack until we have full support for
- // DST.
- match a_def {
- def::DefTy(did, _) |
- def::DefStruct(did) if Some(did) == this.tcx().lang_items.owned_box() => {
- let ty = ast_path_to_ty(this, rscope, did, path).ty;
- match ty.sty {
- ty::ty_struct(struct_def_id, ref substs) => {
- assert_eq!(struct_def_id, did);
- assert_eq!(substs.types.len(TypeSpace), 1);
- let referent_ty = *substs.types.get(TypeSpace, 0);
- Some(ty::mk_uniq(this.tcx(), referent_ty))
- }
- _ => {
- this.tcx().sess.span_bug(
- path.span,
- &format!("converting `Box` to `{}`",
- ty.repr(this.tcx())));
- }
- }
- }
- _ => None
- }
- }
- _ => None
+ // FIXME(#12938): This is a hack until we have full support for DST.
+ if Some(did) == this.tcx().lang_items.owned_box() {
+ assert_eq!(substs.types.len(TypeSpace), 1);
+ return ty::mk_uniq(this.tcx(), *substs.types.get(TypeSpace, 0));
}
+
+ decl_ty.subst(this.tcx(), &substs)
}
type TraitAndProjections<'tcx> = (ty::PolyTraitRef<'tcx>, Vec<ty::PolyProjectionPredicate<'tcx>>);
*/
match ty.node {
- ast::TyPath(ref path, id) => {
- match this.tcx().def_map.borrow().get(&id) {
- Some(&def::DefaultImpl(trait_def_id)) => {
+ ast::TyPath(None, ref path) => {
+ let def = match this.tcx().def_map.borrow().get(&ty.id) {
+ Some(&def::PathResolution { base_def, depth: 0, .. }) => Some(base_def),
+ _ => None
+ };
+ match def {
+ Some(def::DefTrait(trait_def_id)) => {
let mut projection_bounds = Vec::new();
let trait_ref = object_path_to_poly_trait_ref(this,
rscope,
+ path.span,
+ PathParamMode::Explicit,
trait_def_id,
- path,
+ path.segments.last().unwrap(),
&mut projection_bounds);
Ok((trait_ref, projection_bounds))
}
}
fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
- ast_ty: &ast::Ty,
- provenance: def::TyParamProvenance,
- assoc_name: ast::Name)
- -> Ty<'tcx>
+ span: Span,
+ ty: Ty<'tcx>,
+ ty_path_def: def::Def,
+ item_segment: &ast::PathSegment)
+ -> (Ty<'tcx>, def::Def)
{
let tcx = this.tcx();
- let ty_param_def_id = provenance.def_id();
-
- let mut suitable_bounds: Vec<_>;
- let ty_param_name: ast::Name;
- { // contain scope of refcell:
- let ty_param_defs = tcx.ty_param_defs.borrow();
- let ty_param_def = &ty_param_defs[ty_param_def_id.node];
- ty_param_name = ty_param_def.name;
-
- // FIXME(#20300) -- search where clauses, not bounds
- suitable_bounds =
- traits::transitive_bounds(tcx, &ty_param_def.bounds.trait_bounds)
- .filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name))
- .collect();
- }
+ 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
+ };
+
+ let ty_param_node_id = if is_param {
+ ty_path_def.local_node_id()
+ } else {
+ span_err!(tcx.sess, span, E0223,
+ "ambiguous associated type; specify the type using the syntax \
+ `<{} as Trait>::{}`",
+ ty.user_string(tcx), token::get_name(assoc_name));
+ return (tcx.types.err, ty_path_def);
+ };
+
+ let ty_param_name = tcx.ty_param_defs.borrow()[ty_param_node_id].name;
+
+ // FIXME(#20300) -- search where clauses, not bounds
+ let bounds =
+ this.get_type_parameter_bounds(span, ty_param_node_id)
+ .unwrap_or(Vec::new());
+
+ let mut suitable_bounds: Vec<_> =
+ traits::transitive_bounds(tcx, &bounds)
+ .filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name))
+ .collect();
if suitable_bounds.len() == 0 {
- span_err!(tcx.sess, ast_ty.span, E0220,
+ span_err!(tcx.sess, span, E0220,
"associated type `{}` not found for type parameter `{}`",
token::get_name(assoc_name),
token::get_name(ty_param_name));
- return this.tcx().types.err;
+ return (this.tcx().types.err, ty_path_def);
}
if suitable_bounds.len() > 1 {
- span_err!(tcx.sess, ast_ty.span, E0221,
+ span_err!(tcx.sess, span, E0221,
"ambiguous associated type `{}` in bounds of `{}`",
token::get_name(assoc_name),
token::get_name(ty_param_name));
for suitable_bound in &suitable_bounds {
- span_note!(this.tcx().sess, ast_ty.span,
+ span_note!(this.tcx().sess, span,
"associated type `{}` could derive from `{}`",
token::get_name(ty_param_name),
suitable_bound.user_string(this.tcx()));
}
let suitable_bound = suitable_bounds.pop().unwrap().clone();
- return this.projected_ty_from_poly_trait_ref(ast_ty.span, suitable_bound, assoc_name);
+ let trait_did = suitable_bound.0.def_id;
+
+ let ty = this.projected_ty_from_poly_trait_ref(span, suitable_bound, assoc_name);
+
+ let item_did = if trait_did.krate == ast::LOCAL_CRATE {
+ // `ty::trait_items` used below requires information generated
+ // 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) => {
+ trait_items.iter().filter_map(|i| {
+ if let ast::TypeTraitItem(ref assoc) = *i {
+ if assoc.ty_param.ident.name == assoc_name {
+ return Some(ast_util::local_def(assoc.ty_param.id));
+ }
+ }
+ None
+ }).next().expect("missing associated type")
+ }
+ _ => unreachable!()
+ }
+ } else {
+ let trait_items = ty::trait_items(this.tcx(), trait_did);
+ 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))
}
fn trait_defines_associated_type_named(this: &AstConv,
fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
rscope: &RegionScope,
- ast_ty: &ast::Ty, // the TyQPath
- qpath: &ast::QPath)
+ span: Span,
+ param_mode: PathParamMode,
+ opt_self_ty: Option<Ty<'tcx>>,
+ trait_def_id: ast::DefId,
+ trait_segment: &ast::PathSegment,
+ item_segment: &ast::PathSegment)
-> Ty<'tcx>
{
- debug!("qpath_to_ty(ast_ty={})",
- ast_ty.repr(this.tcx()));
+ let tcx = this.tcx();
- let self_type = ast_ty_to_ty(this, rscope, &*qpath.self_type);
+ check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS);
- debug!("qpath_to_ty: self_type={}", self_type.repr(this.tcx()));
+ let self_ty = if let Some(ty) = opt_self_ty {
+ ty
+ } else {
+ let path_str = ty::item_path_str(tcx, trait_def_id);
+ span_err!(tcx.sess, span, E0223,
+ "ambiguous associated type; specify the type using the syntax \
+ `<Type as {}>::{}`",
+ path_str, &token::get_ident(item_segment.identifier));
+ return tcx.types.err;
+ };
+
+ debug!("qpath_to_ty: self_type={}", self_ty.repr(tcx));
- let trait_ref = instantiate_trait_ref(this,
+ let trait_ref = ast_path_to_trait_ref(this,
rscope,
- &*qpath.trait_ref,
- Some(self_type),
+ span,
+ param_mode,
+ trait_def_id,
+ Some(self_ty),
+ trait_segment,
None);
- debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(this.tcx()));
-
- // `<T as Trait>::U<V>` shouldn't parse right now.
- assert!(qpath.item_path.parameters.is_empty());
+ debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx));
- return this.projected_ty(ast_ty.span,
- trait_ref,
- qpath.item_path.identifier.name);
+ this.projected_ty(span, trait_ref, item_segment.identifier.name)
}
/// Convert a type supplied as value for a type argument from AST into our
}
}
+pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>,
+ rscope: &RegionScope,
+ span: Span,
+ param_mode: PathParamMode,
+ def: &mut def::Def,
+ opt_self_ty: Option<Ty<'tcx>>,
+ segments: &[ast::PathSegment],
+ assoc_segments: &[ast::PathSegment])
+ -> Ty<'tcx> {
+ let tcx = this.tcx();
+
+ let base_ty = match *def {
+ def::DefTrait(trait_def_id) => {
+ // N.B. this case overlaps somewhat with
+ // TyObjectSum, see that fn for details
+ let mut projection_bounds = Vec::new();
+
+ let trait_ref = object_path_to_poly_trait_ref(this,
+ rscope,
+ span,
+ param_mode,
+ trait_def_id,
+ 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, &[])
+ }
+ def::DefTy(did, _) | def::DefStruct(did) => {
+ check_path_args(tcx, segments.init(), NO_TPS | NO_REGIONS);
+ ast_path_to_ty(this, rscope, span,
+ param_mode, did,
+ segments.last().unwrap())
+ }
+ def::DefTyParam(space, index, _, name) => {
+ check_path_args(tcx, 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
+ // trait, which we rely upon in various places when creating
+ // substs
+ check_path_args(tcx, 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())
+ }
+ 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 {
+ tcx.sess.span_bug(span,
+ &format!("found module name used as a type: {}",
+ tcx.map.node_to_string(id.node)));
+ }
+ }
+ def::DefPrimTy(prim_ty) => {
+ prim_ty_to_ty(tcx, segments, prim_ty)
+ }
+ _ => {
+ span_fatal!(tcx.sess, span, E0248,
+ "found value name used as a type: {:?}", *def);
+ }
+ };
+
+ // If any associated type segments remain, attempt to resolve them.
+ let mut ty = base_ty;
+ 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);
+ ty = a_ty;
+ *def = a_def;
+ }
+ ty
+}
+
/// Parses the programmer's textual representation of a type into our
/// internal notion of a type.
pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
ast_ty_to_ty_cache.insert(ast_ty.id, ty::atttce_unresolved);
drop(ast_ty_to_ty_cache);
- let typ = ast_ty_to_builtin_ty(this, rscope, ast_ty).unwrap_or_else(|| {
- match ast_ty.node {
- ast::TyVec(ref ty) => {
- ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), None)
- }
- ast::TyObjectSum(ref ty, ref bounds) => {
- match ast_ty_to_trait_ref(this, rscope, &**ty, &bounds[..]) {
- Ok((trait_ref, projection_bounds)) => {
- trait_ref_to_object_type(this,
- rscope,
- ast_ty.span,
- trait_ref,
- projection_bounds,
- &bounds[..])
- }
- Err(ErrorReported) => {
- this.tcx().types.err
- }
+ let typ = match ast_ty.node {
+ ast::TyVec(ref ty) => {
+ ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), None)
+ }
+ ast::TyObjectSum(ref ty, ref bounds) => {
+ match ast_ty_to_trait_ref(this, rscope, &**ty, bounds) {
+ Ok((trait_ref, projection_bounds)) => {
+ trait_ref_to_object_type(this,
+ rscope,
+ ast_ty.span,
+ trait_ref,
+ projection_bounds,
+ bounds)
}
- }
- ast::TyPtr(ref mt) => {
- ty::mk_ptr(tcx, ty::mt {
- ty: ast_ty_to_ty(this, rscope, &*mt.ty),
- mutbl: mt.mutbl
- })
- }
- ast::TyRptr(ref region, ref mt) => {
- let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region);
- debug!("ty_rptr r={}", r.repr(this.tcx()));
- let rscope1 =
- &ObjectLifetimeDefaultRscope::new(
- rscope,
- Some(ty::ObjectLifetimeDefault::Specific(r)));
- let t = ast_ty_to_ty(this, rscope1, &*mt.ty);
- ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl})
- }
- ast::TyTup(ref fields) => {
- let flds = fields.iter()
- .map(|t| ast_ty_to_ty(this, rscope, &**t))
- .collect();
- ty::mk_tup(tcx, flds)
- }
- ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ),
- ast::TyBareFn(ref bf) => {
- if bf.decl.variadic && bf.abi != abi::C {
- span_err!(tcx.sess, ast_ty.span, E0222,
- "variadic function must have C calling convention");
+ Err(ErrorReported) => {
+ this.tcx().types.err
}
- let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl);
- ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(bare_fn))
}
- ast::TyPolyTraitRef(ref bounds) => {
- conv_ty_poly_trait_ref(this, rscope, ast_ty.span, &bounds[..])
+ }
+ ast::TyPtr(ref mt) => {
+ ty::mk_ptr(tcx, ty::mt {
+ ty: ast_ty_to_ty(this, rscope, &*mt.ty),
+ mutbl: mt.mutbl
+ })
+ }
+ ast::TyRptr(ref region, ref mt) => {
+ let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region);
+ debug!("ty_rptr r={}", r.repr(this.tcx()));
+ let rscope1 =
+ &ObjectLifetimeDefaultRscope::new(
+ rscope,
+ Some(ty::ObjectLifetimeDefault::Specific(r)));
+ let t = ast_ty_to_ty(this, rscope1, &*mt.ty);
+ ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl})
+ }
+ ast::TyTup(ref fields) => {
+ let flds = fields.iter()
+ .map(|t| ast_ty_to_ty(this, rscope, &**t))
+ .collect();
+ ty::mk_tup(tcx, flds)
+ }
+ ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ),
+ ast::TyBareFn(ref bf) => {
+ if bf.decl.variadic && bf.abi != abi::C {
+ span_err!(tcx.sess, ast_ty.span, E0222,
+ "variadic function must have C calling convention");
}
- ast::TyPath(ref path, id) => {
- let a_def = match tcx.def_map.borrow().get(&id) {
- None => {
- tcx.sess
- .span_bug(ast_ty.span,
- &format!("unbound path {}",
- path.repr(tcx)))
- }
- Some(&d) => d
- };
- match a_def {
- def::DefaultImpl(trait_def_id) => {
- // N.B. this case overlaps somewhat with
- // TyObjectSum, see that fn for details
- let mut projection_bounds = Vec::new();
-
- let trait_ref = object_path_to_poly_trait_ref(this,
- rscope,
- trait_def_id,
- path,
- &mut projection_bounds);
-
- trait_ref_to_object_type(this, rscope, path.span,
- trait_ref, projection_bounds, &[])
- }
- def::DefTy(did, _) | def::DefStruct(did) => {
- ast_path_to_ty(this, rscope, did, path).ty
- }
- def::DefTyParam(space, index, _, name) => {
- check_path_args(tcx, path, 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
- // trait, which we rely upon in various places when creating
- // substs
- check_path_args(tcx, path, NO_TPS | NO_REGIONS);
- ty::mk_self_type(tcx)
- }
- def::DefMod(id) => {
- span_fatal!(tcx.sess, ast_ty.span, E0247,
- "found module name used as a type: {}",
- tcx.map.node_to_string(id.node));
- }
- def::DefPrimTy(_) => {
- panic!("DefPrimTy arm missed in previous ast_ty_to_prim_ty call");
- }
- def::DefAssociatedTy(trait_type_id) => {
- let path_str = tcx.map.path_to_string(
- tcx.map.get_parent(trait_type_id.node));
- span_err!(tcx.sess, ast_ty.span, E0223,
- "ambiguous associated \
- type; specify the type \
- using the syntax `<Type \
- as {}>::{}`",
- path_str,
- &token::get_ident(
- path.segments
- .last()
- .unwrap()
- .identifier));
- this.tcx().types.err
- }
- def::DefAssociatedPath(provenance, assoc_ident) => {
- associated_path_def_to_ty(this, ast_ty, provenance, assoc_ident.name)
- }
- _ => {
- span_fatal!(tcx.sess, ast_ty.span, E0248,
- "found value name used \
- as a type: {:?}",
- a_def);
- }
+ let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl);
+ ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(bare_fn))
+ }
+ ast::TyPolyTraitRef(ref bounds) => {
+ conv_ty_poly_trait_ref(this, rscope, ast_ty.span, bounds)
+ }
+ ast::TyPath(ref maybe_qself, ref path) => {
+ let path_res = if let Some(&d) = tcx.def_map.borrow().get(&ast_ty.id) {
+ d
+ } else if let Some(ast::QSelf { position: 0, .. }) = *maybe_qself {
+ // Create some fake resolution that can't possibly be a type.
+ def::PathResolution {
+ base_def: def::DefMod(ast_util::local_def(ast::CRATE_NODE_ID)),
+ last_private: LastMod(AllPublic),
+ depth: path.segments.len()
}
+ } else {
+ tcx.sess.span_bug(ast_ty.span,
+ &format!("unbound path {}", ast_ty.repr(tcx)))
+ };
+ let mut 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,
+ opt_self_ty,
+ &path.segments[..base_ty_end],
+ &path.segments[base_ty_end..]);
+
+ if path_res.depth != 0 && ty.sty != ty::ty_err {
+ // Write back the new resolution.
+ tcx.def_map.borrow_mut().insert(ast_ty.id, def::PathResolution {
+ base_def: def,
+ last_private: path_res.last_private,
+ depth: 0
+ });
}
- ast::TyQPath(ref qpath) => {
- qpath_to_ty(this, rscope, ast_ty, &**qpath)
- }
- ast::TyFixedLengthVec(ref ty, ref e) => {
- match const_eval::eval_const_expr_partial(tcx, &**e, Some(tcx.types.uint)) {
- Ok(ref r) => {
- match *r {
- const_eval::const_int(i) =>
- ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty),
- Some(i as uint)),
- const_eval::const_uint(i) =>
- ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty),
- Some(i as uint)),
- _ => {
- span_fatal!(tcx.sess, ast_ty.span, E0249,
- "expected constant expr for array length");
- }
+
+ ty
+ }
+ ast::TyFixedLengthVec(ref ty, ref e) => {
+ match const_eval::eval_const_expr_partial(tcx, &**e, Some(tcx.types.uint)) {
+ Ok(r) => {
+ match r {
+ const_eval::const_int(i) =>
+ ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty),
+ Some(i as uint)),
+ const_eval::const_uint(i) =>
+ ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty),
+ Some(i as uint)),
+ _ => {
+ span_fatal!(tcx.sess, ast_ty.span, E0249,
+ "expected constant expr for array length");
}
}
- Err(ref r) => {
- span_fatal!(tcx.sess, ast_ty.span, E0250,
- "expected constant expr for array \
- length: {}",
- *r);
- }
}
- }
- ast::TyTypeof(ref _e) => {
- tcx.sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented");
- }
- ast::TyInfer => {
- // TyInfer also appears as the type of arguments or return
- // values in a ExprClosure, or as
- // the type of local variables. Both of these cases are
- // handled specially and will not descend into this routine.
- this.ty_infer(ast_ty.span)
+ Err(r) => {
+ span_fatal!(tcx.sess, ast_ty.span, E0250,
+ "expected constant expr for array length: {}", r);
+ }
}
}
- });
+ ast::TyTypeof(ref _e) => {
+ tcx.sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented");
+ }
+ ast::TyInfer => {
+ // TyInfer also appears as the type of arguments or return
+ // values in a ExprClosure, or as
+ // the type of local variables. Both of these cases are
+ // handled specially and will not descend into this routine.
+ this.ty_infer(ast_ty.span)
+ }
+ };
tcx.ast_ty_to_ty_cache.borrow_mut().insert(ast_ty.id, ty::atttce_resolved(typ));
return typ;
for ast_bound in ast_bounds {
match *ast_bound {
ast::TraitTyParamBound(ref b, ast::TraitBoundModifier::None) => {
- match ::lookup_def_tcx(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) {
- def::DefaultImpl(trait_did) => {
+ match ::lookup_full_def(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) {
+ def::DefTrait(trait_did) => {
match trait_def_ids.get(&trait_did) {
// Already seen this trait. We forbid
// duplicates in the list (for some
demand::eqtype(fcx, pat.span, expected, lhs_ty);
}
ast::PatEnum(..) | ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => {
- let const_did = tcx.def_map.borrow()[pat.id].clone().def_id();
+ let const_did = tcx.def_map.borrow()[pat.id].def_id();
let const_scheme = ty::lookup_item_type(tcx, const_did);
assert!(const_scheme.generics.is_empty());
let const_ty = pcx.fcx.instantiate_type_scheme(pat.span,
let fcx = pcx.fcx;
let tcx = pcx.fcx.ccx.tcx;
- let def = tcx.def_map.borrow()[pat.id].clone();
+ let def = tcx.def_map.borrow()[pat.id].full_def();
let (enum_def_id, variant_def_id) = match def {
- def::DefaultImpl(_) => {
+ def::DefTrait(_) => {
let name = pprust::path_to_string(path);
span_err!(tcx.sess, pat.span, E0168,
"use of trait `{}` in a struct pattern", name);
};
instantiate_path(pcx.fcx,
- path,
+ &path.segments,
ty::lookup_item_type(tcx, enum_def_id),
&ty::lookup_predicates(tcx, enum_def_id),
None,
let fcx = pcx.fcx;
let tcx = pcx.fcx.ccx.tcx;
- let def = tcx.def_map.borrow()[pat.id].clone();
+ let def = tcx.def_map.borrow()[pat.id].full_def();
let enum_def = def.variant_def_ids()
.map_or_else(|| def.def_id(), |(enum_def, _)| enum_def);
} else {
ctor_scheme
};
- instantiate_path(pcx.fcx, path, path_scheme, &ctor_predicates, None, def, pat.span, pat.id);
+ instantiate_path(pcx.fcx, &path.segments,
+ path_scheme, &ctor_predicates,
+ None, def, pat.span, pat.id);
let pat_ty = fcx.node_ty(pat.id);
demand::eqtype(fcx, pat.span, expected, pat_ty);
use check::{FnCtxt};
use check::vtable;
use check::vtable::select_new_fcx_obligations;
+use middle::def;
+use middle::privacy::{AllPublic, DependsOn, LastPrivate, LastMod};
use middle::subst;
use middle::traits;
use middle::ty::*;
call_expr_id: ast::NodeId)
-> bool
{
- match probe::probe(fcx, span, method_name, self_ty, call_expr_id) {
+ let mode = probe::Mode::MethodCall;
+ match probe::probe(fcx, span, mode, method_name, self_ty, call_expr_id) {
Ok(..) => true,
Err(NoMatch(..)) => false,
Err(Ambiguity(..)) => true,
call_expr.repr(fcx.tcx()),
self_expr.repr(fcx.tcx()));
+ let mode = probe::Mode::MethodCall;
let self_ty = fcx.infcx().resolve_type_vars_if_possible(&self_ty);
- let pick = try!(probe::probe(fcx, span, method_name, self_ty, call_expr.id));
+ let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, call_expr.id));
Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types))
}
Some(callee)
}
+pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+ span: Span,
+ method_name: ast::Name,
+ self_ty: Ty<'tcx>,
+ expr_id: ast::NodeId)
+ -> Result<(def::Def, LastPrivate), MethodError>
+{
+ let mode = probe::Mode::Path;
+ let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id));
+ let def_id = pick.method_ty.def_id;
+ let mut lp = LastMod(AllPublic);
+ let provenance = match pick.kind {
+ probe::InherentImplPick(impl_def_id) => {
+ if pick.method_ty.vis != ast::Public {
+ lp = LastMod(DependsOn(def_id));
+ }
+ def::FromImpl(impl_def_id)
+ }
+ _ => def::FromTrait(pick.method_ty.container.id())
+ };
+ Ok((def::DefMethod(def_id, provenance), lp))
+}
+
/// Find method with name `method_name` defined in `trait_def_id` and return it, along with its
/// index (or `None`, if no such method).
struct ProbeContext<'a, 'tcx:'a> {
fcx: &'a FnCtxt<'a, 'tcx>,
span: Span,
+ mode: Mode,
method_name: ast::Name,
steps: Rc<Vec<CandidateStep<'tcx>>>,
opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>,
AutoRef(ast::Mutability, Box<PickAdjustment>),
}
+#[derive(PartialEq, Eq, Copy)]
+pub enum Mode {
+ // An expression of the form `receiver.method_name(...)`.
+ // Autoderefs are performed on `receiver`, lookup is done based on the
+ // `self` argument of the method, and static methods aren't considered.
+ MethodCall,
+ // An expression of the form `Type::method` or `<T>::method`.
+ // No autoderefs are performed, lookup is done based on the type each
+ // implementation is for, and static methods are included.
+ Path
+}
+
pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span,
+ mode: Mode,
method_name: ast::Name,
self_ty: Ty<'tcx>,
- call_expr_id: ast::NodeId)
+ scope_expr_id: ast::NodeId)
-> PickResult<'tcx>
{
- debug!("probe(self_ty={}, method_name={}, call_expr_id={})",
+ debug!("probe(self_ty={}, method_name={}, scope_expr_id={})",
self_ty.repr(fcx.tcx()),
method_name,
- call_expr_id);
+ scope_expr_id);
// FIXME(#18741) -- right now, creating the steps involves evaluating the
// `*` operator, which registers obligations that then escape into
// it ride, although it's really not great, and in fact could I
// think cause spurious errors. Really though this part should
// take place in the `fcx.infcx().probe` below.
- let steps = match create_steps(fcx, span, self_ty) {
- Some(steps) => steps,
- None => return Err(MethodError::NoMatch(Vec::new(), Vec::new())),
+ let steps = if mode == Mode::MethodCall {
+ match create_steps(fcx, span, self_ty) {
+ Some(steps) => steps,
+ None => return Err(MethodError::NoMatch(Vec::new(), Vec::new())),
+ }
+ } else {
+ vec![CandidateStep {
+ self_ty: self_ty,
+ adjustment: AutoDeref(0)
+ }]
};
// Create a list of simplified self types, if we can.
// this creates one big transaction so that all type variables etc
// that we create during the probe process are removed later
- let mut dummy = Some((steps, opt_simplified_steps)); // FIXME(#18101) need once closures
fcx.infcx().probe(|_| {
- let (steps, opt_simplified_steps) = dummy.take().unwrap();
- let mut probe_cx = ProbeContext::new(fcx, span, method_name, steps, opt_simplified_steps);
+ let mut probe_cx = ProbeContext::new(fcx,
+ span,
+ mode,
+ method_name,
+ steps,
+ opt_simplified_steps);
probe_cx.assemble_inherent_candidates();
- try!(probe_cx.assemble_extension_candidates_for_traits_in_scope(call_expr_id));
+ try!(probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id));
probe_cx.pick()
})
}
impl<'a,'tcx> ProbeContext<'a,'tcx> {
fn new(fcx: &'a FnCtxt<'a,'tcx>,
span: Span,
+ mode: Mode,
method_name: ast::Name,
steps: Vec<CandidateStep<'tcx>>,
opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>)
ProbeContext {
fcx: fcx,
span: span,
+ mode: mode,
method_name: method_name,
inherent_candidates: Vec::new(),
extension_candidates: Vec::new(),
ty::ty_closure(did, _, _) => {
self.assemble_inherent_impl_candidates_for_type(did);
}
+ ty::ty_uniq(_) => {
+ if let Some(box_did) = self.tcx().lang_items.owned_box() {
+ self.assemble_inherent_impl_candidates_for_type(box_did);
+ }
+ }
ty::ty_param(p) => {
self.assemble_inherent_candidates_from_param(self_ty, p);
}
return self.record_static_candidate(ImplSource(impl_def_id));
}
- let impl_substs = self.impl_substs(impl_def_id);
+ let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
+ let impl_ty = self.fcx.instantiate_type_scheme(self.span, &impl_substs, &impl_ty);
// Determine the receiver type that the method itself expects.
let xform_self_ty =
- self.xform_self_ty(&method, &impl_substs);
+ self.xform_self_ty(&method, impl_ty, &impl_substs);
self.inherent_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
new_trait_ref.def_id,
method_num);
- let xform_self_ty = this.xform_self_ty(&m, new_trait_ref.substs);
+ let xform_self_ty = this.xform_self_ty(&m,
+ new_trait_ref.self_ty(),
+ new_trait_ref.substs);
this.inherent_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
this.erase_late_bound_regions(&poly_trait_ref);
let xform_self_ty =
- this.xform_self_ty(&m, trait_ref.substs);
+ this.xform_self_ty(&m,
+ trait_ref.self_ty(),
+ trait_ref.substs);
debug!("found match: trait_ref={} substs={} m={}",
trait_ref.repr(this.tcx()),
continue;
}
- let impl_substs = self.impl_substs(impl_def_id);
+ let (_, impl_substs) = self.impl_ty_and_substs(impl_def_id);
debug!("impl_substs={}", impl_substs.repr(self.tcx()));
// Determine the receiver type that the method itself expects.
let xform_self_ty =
- self.xform_self_ty(&method, impl_trait_ref.substs);
+ self.xform_self_ty(&method,
+ impl_trait_ref.self_ty(),
+ impl_trait_ref.substs);
debug!("xform_self_ty={}", xform_self_ty.repr(self.tcx()));
&trait_def.generics,
step.self_ty);
- let xform_self_ty = self.xform_self_ty(&method_ty, &substs);
+ let xform_self_ty = self.xform_self_ty(&method_ty,
+ step.self_ty,
+ &substs);
self.inherent_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
method_ty: method_ty.clone(),
bound.repr(self.tcx()));
if self.infcx().can_equate(&step.self_ty, &bound.self_ty()).is_ok() {
- let xform_self_ty = self.xform_self_ty(&method, bound.substs);
+ let xform_self_ty = self.xform_self_ty(&method,
+ bound.self_ty(),
+ bound.substs);
debug!("assemble_projection_candidates: bound={} xform_self_ty={}",
bound.repr(self.tcx()),
.filter(|b| b.def_id() == trait_def_id)
{
let bound = self.erase_late_bound_regions(&poly_bound);
- let xform_self_ty = self.xform_self_ty(&method_ty, bound.substs);
+ let xform_self_ty = self.xform_self_ty(&method_ty,
+ bound.self_ty(),
+ bound.substs);
debug!("assemble_where_clause_candidates: bound={} xform_self_ty={}",
bound.repr(self.tcx()),
// "fast track" -- check for usage of sugar
match method.explicit_self {
ty::StaticExplicitSelfCategory => {
- // fallthrough
+ if self.mode == Mode::Path {
+ return true;
+ }
}
ty::ByValueExplicitSelfCategory |
ty::ByReferenceExplicitSelfCategory(..) |
fn xform_self_ty(&self,
method: &Rc<ty::Method<'tcx>>,
+ impl_ty: Ty<'tcx>,
substs: &subst::Substs<'tcx>)
-> Ty<'tcx>
{
- debug!("xform_self_ty(self_ty={}, substs={})",
- method.fty.sig.0.inputs[0].repr(self.tcx()),
+ debug!("xform_self_ty(impl_ty={}, self_ty={}, substs={})",
+ impl_ty.repr(self.tcx()),
+ method.fty.sig.0.inputs.get(0).repr(self.tcx()),
substs.repr(self.tcx()));
assert!(!substs.has_escaping_regions());
// if there are any.
assert_eq!(substs.types.len(subst::FnSpace), 0);
assert_eq!(substs.regions().len(subst::FnSpace), 0);
+
+ if self.mode == Mode::Path {
+ return impl_ty;
+ }
+
let placeholder;
let mut substs = substs;
if
xform_self_ty
}
- fn impl_substs(&self,
- impl_def_id: ast::DefId)
- -> subst::Substs<'tcx>
+ /// Get the type of an impl and generate substitutions with placeholders.
+ fn impl_ty_and_substs(&self,
+ impl_def_id: ast::DefId)
+ -> (Ty<'tcx>, subst::Substs<'tcx>)
{
let impl_pty = ty::lookup_item_type(self.tcx(), impl_def_id);
impl_pty.generics.regions.map(
|_| ty::ReStatic); // see erase_late_bound_regions() for an expl of why 'static
- subst::Substs::new(type_vars, region_placeholders)
+ let substs = subst::Substs::new(type_vars, region_placeholders);
+ (impl_pty.ty, substs)
}
/// Replace late-bound-regions bound by `value` with `'static` using
span: Span,
rcvr_ty: Ty<'tcx>,
method_name: ast::Name,
- callee_expr: &ast::Expr,
+ rcvr_expr: Option<&ast::Expr>,
error: MethodError)
{
// avoid suggestions when we don't know what's going on.
let cx = fcx.tcx();
let method_ustring = method_name.user_string(cx);
- // True if the type is a struct and contains a field with
- // the same name as the not-found method
- let is_field = match rcvr_ty.sty {
- ty::ty_struct(did, _) =>
- ty::lookup_struct_fields(cx, did)
- .iter()
- .any(|f| f.name.user_string(cx) == method_ustring),
- _ => false
- };
-
fcx.type_error_message(
span,
|actual| {
None);
// If the method has the name of a field, give a help note
- if is_field {
- cx.sess.span_note(span,
- &format!("use `(s.{0})(...)` if you meant to call the \
- function stored in the `{0}` field", method_ustring));
+ if let (&ty::ty_struct(did, _), Some(_)) = (&rcvr_ty.sty, rcvr_expr) {
+ let fields = ty::lookup_struct_fields(cx, did);
+ if fields.iter().any(|f| f.name == method_name) {
+ cx.sess.span_note(span,
+ &format!("use `(s.{0})(...)` if you meant to call the \
+ function stored in the `{0}` field", method_ustring));
+ }
}
if static_sources.len() > 0 {
report_candidates(fcx, span, method_name, static_sources);
}
- suggest_traits_to_import(fcx, span, rcvr_ty, method_name, out_of_scope_traits)
+ suggest_traits_to_import(fcx, span, rcvr_ty, method_name,
+ rcvr_expr, out_of_scope_traits)
}
MethodError::Ambiguity(sources) => {
}
MethodError::ClosureAmbiguity(trait_def_id) => {
- fcx.sess().span_err(
- span,
- &*format!("the `{}` method from the `{}` trait cannot be explicitly \
- invoked on this closure as we have not yet inferred what \
- kind of closure it is; use overloaded call notation instead \
- (e.g., `{}()`)",
- method_name.user_string(fcx.tcx()),
- ty::item_path_str(fcx.tcx(), trait_def_id),
- pprust::expr_to_string(callee_expr)));
+ let msg = format!("the `{}` method from the `{}` trait cannot be explicitly \
+ invoked on this closure as we have not yet inferred what \
+ kind of closure it is",
+ method_name.user_string(fcx.tcx()),
+ ty::item_path_str(fcx.tcx(), trait_def_id));
+ let msg = if let Some(callee) = rcvr_expr {
+ format!("{}; use overloaded call notation instead (e.g., `{}()`)",
+ msg, pprust::expr_to_string(callee))
+ } else {
+ msg
+ };
+ fcx.sess().span_err(span, &msg);
}
}
span: Span,
rcvr_ty: Ty<'tcx>,
method_name: ast::Name,
+ rcvr_expr: Option<&ast::Expr>,
valid_out_of_scope_traits: Vec<ast::DefId>)
{
let tcx = fcx.tcx();
return
}
- let type_is_local = type_derefs_to_local(fcx, span, rcvr_ty);
+ let type_is_local = type_derefs_to_local(fcx, span, rcvr_ty, rcvr_expr);
// there's no implemented traits, so lets suggest some traits to
// implement, by finding ones that have the method name, and are
/// autoderefs of `rcvr_ty`.
fn type_derefs_to_local<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span,
- rcvr_ty: Ty<'tcx>) -> bool {
- check::autoderef(fcx, span, rcvr_ty, None,
- check::UnresolvedTypeAction::Ignore, check::NoPreference,
- |&: ty, _| {
- let is_local = match ty.sty {
+ rcvr_ty: Ty<'tcx>,
+ rcvr_expr: Option<&ast::Expr>) -> bool {
+ fn is_local(ty: Ty) -> bool {
+ match ty.sty {
ty::ty_enum(did, _) | ty::ty_struct(did, _) => ast_util::is_local(did),
ty::ty_trait(ref tr) => ast_util::is_local(tr.principal_def_id()),
ty::ty_param(_) => true,
- // the user cannot implement traits for unboxed closures, so
- // there's no point suggesting anything at all, local or not.
- ty::ty_closure(..) => return Some(false),
-
// everything else (primitive types etc.) is effectively
// non-local (there are "edge" cases, e.g. (LocalType,), but
// the noise from these sort of types is usually just really
// annoying, rather than any sort of help).
_ => false
- };
- if is_local {
- Some(true)
+ }
+ }
+
+ // This occurs for UFCS desugaring of `T::method`, where there is no
+ // receiver expression for the method call, and thus no autoderef.
+ if rcvr_expr.is_none() {
+ return is_local(fcx.resolve_type_vars_if_possible(rcvr_ty));
+ }
+
+ check::autoderef(fcx, span, rcvr_ty, None,
+ check::UnresolvedTypeAction::Ignore, check::NoPreference,
+ |ty, _| {
+ if is_local(ty) {
+ Some(())
} else {
None
}
- }).2.unwrap_or(false)
+ }).2.is_some()
}
#[derive(Copy)]
cstore: &cstore::CStore,
dl: decoder::DefLike) {
match dl {
- decoder::DlDef(def::DefaultImpl(did)) => {
+ decoder::DlDef(def::DefTrait(did)) => {
traits.push(TraitInfo::new(did));
}
decoder::DlDef(def::DefMod(did)) => {
use self::IsBinopAssignment::*;
use self::TupleArgumentsFlag::*;
-use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv};
+use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode};
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::infer;
use middle::mem_categorization as mc;
use middle::mem_categorization::McResult;
use middle::pat_util::{self, pat_id_map};
+use middle::privacy::{AllPublic, LastMod};
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::{Disr, ParamTy, ParameterEnvironment};
-use middle::ty::{self, HasProjectionTypes, RegionEscape, Ty};
+use middle::ty::{self, HasProjectionTypes, RegionEscape, ToPolyTraitRef, Ty};
use middle::ty::liberate_late_bound_regions;
use middle::ty::{MethodCall, MethodCallee, MethodMap, ObjectCastMap};
use middle::ty_fold::{TypeFolder, TypeFoldable};
use rscope::RegionScope;
use session::Session;
-use {CrateCtxt, lookup_def_ccx, require_same_types};
+use {CrateCtxt, lookup_full_def, require_same_types};
use TypeAndSubsts;
use lint;
-use util::common::{block_query, indenter, loop_query};
+use util::common::{block_query, ErrorReported, indenter, loop_query};
use util::ppaux::{self, Repr};
use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
use util::lev_distance::lev_distance;
impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx }
- fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx> {
- ty::lookup_item_type(self.tcx(), id)
+ fn get_item_type_scheme(&self, _: Span, id: ast::DefId)
+ -> Result<ty::TypeScheme<'tcx>, ErrorReported>
+ {
+ Ok(ty::lookup_item_type(self.tcx(), id))
}
- fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef<'tcx>> {
- ty::lookup_trait_def(self.tcx(), id)
+ fn get_trait_def(&self, _: Span, id: ast::DefId)
+ -> Result<Rc<ty::TraitDef<'tcx>>, ErrorReported>
+ {
+ Ok(ty::lookup_trait_def(self.tcx(), id))
}
fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
Some(&self.inh.param_env.free_substs)
}
+ fn get_type_parameter_bounds(&self,
+ _: Span,
+ node_id: ast::NodeId)
+ -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>
+ {
+ let def = self.tcx().type_parameter_def(node_id);
+ let r = self.inh.param_env.caller_bounds
+ .iter()
+ .filter_map(|predicate| {
+ match *predicate {
+ ty::Predicate::Trait(ref data) => {
+ if data.0.self_ty().is_param(def.space, def.index) {
+ Some(data.to_poly_trait_ref())
+ } else {
+ None
+ }
+ }
+ _ => {
+ None
+ }
+ }
+ })
+ .collect();
+ Ok(r)
+ }
+
fn ty_infer(&self, _span: Span) -> Ty<'tcx> {
self.infcx().next_ty_var()
}
let ty::TypeScheme { generics, ty: decl_ty } =
ty::lookup_item_type(tcx, did);
- let wants_params =
- generics.has_type_params(TypeSpace) || generics.has_region_params(TypeSpace);
-
- let needs_defaults =
- wants_params &&
- path.segments.iter().all(|s| s.parameters.is_empty());
-
- let substs = if needs_defaults {
- let tps =
- self.infcx().next_ty_vars(generics.types.len(TypeSpace));
- let rps =
- self.infcx().region_vars_for_defs(path.span,
- generics.regions.get_slice(TypeSpace));
- Substs::new_type(tps, rps)
- } else {
- astconv::ast_path_substs_for_ty(self, self, &generics, path)
- };
+ let substs = astconv::ast_path_substs_for_ty(self, self,
+ path.span,
+ PathParamMode::Optional,
+ &generics,
+ path.segments.last().unwrap());
let ty = self.instantiate_type_scheme(path.span, &substs, &decl_ty);
}
Err(error) => {
method::report_error(fcx, method_name.span, expr_t,
- method_name.node.name, rcvr, error);
+ method_name.node.name, Some(rcvr), error);
fcx.write_error(expr.id);
fcx.tcx().types.err
}
let mut checked = false;
opt_place.as_ref().map(|place| match place.node {
- ast::ExprPath(ref path) => {
+ ast::ExprPath(None, ref path) => {
// FIXME(pcwalton): For now we hardcode the two permissible
// places: the exchange heap and the managed heap.
- let definition = lookup_def(fcx, path.span, place.id);
+ let definition = lookup_full_def(tcx, path.span, place.id);
let def_id = definition.def_id();
let referent_ty = fcx.expr_ty(&**subexpr);
if tcx.lang_items.exchange_heap() == Some(def_id) {
};
fcx.write_ty(id, oprnd_t);
}
- ast::ExprPath(ref path) => {
- let defn = lookup_def(fcx, path.span, id);
- let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, expr.span, defn);
- instantiate_path(fcx, path, scheme, &predicates, None, defn, expr.span, expr.id);
+ ast::ExprPath(ref maybe_qself, ref path) => {
+ let opt_self_ty = maybe_qself.as_ref().map(|qself| {
+ fcx.to_ty(&qself.ty)
+ });
- // We always require that the type provided as the value for
- // a type parameter outlives the moment of instantiation.
- constrain_path_type_parameters(fcx, expr);
- }
- ast::ExprQPath(ref qpath) => {
- // Require explicit type params for the trait.
- let self_ty = fcx.to_ty(&*qpath.self_type);
- astconv::instantiate_trait_ref(fcx, fcx, &*qpath.trait_ref, Some(self_ty), None);
-
- let defn = lookup_def(fcx, expr.span, id);
- let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, expr.span, defn);
- let mut path = qpath.trait_ref.path.clone();
- path.segments.push(qpath.item_path.clone());
- instantiate_path(fcx, &path, scheme, &predicates, Some(self_ty),
- defn, expr.span, expr.id);
+ let path_res = if let Some(&d) = tcx.def_map.borrow().get(&id) {
+ d
+ } else if let Some(ast::QSelf { position: 0, .. }) = *maybe_qself {
+ // Create some fake resolution that can't possibly be a type.
+ def::PathResolution {
+ base_def: def::DefMod(local_def(ast::CRATE_NODE_ID)),
+ last_private: LastMod(AllPublic),
+ depth: path.segments.len()
+ }
+ } else {
+ tcx.sess.span_bug(expr.span,
+ &format!("unbound path {}", expr.repr(tcx)))
+ };
+
+ let mut def = path_res.base_def;
+ if path_res.depth == 0 {
+ let (scheme, predicates) =
+ type_scheme_and_predicates_for_def(fcx, expr.span, def);
+ instantiate_path(fcx, &path.segments,
+ scheme, &predicates,
+ opt_self_ty, def, expr.span, id);
+ } 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,
+ PathParamMode::Optional,
+ &mut def,
+ opt_self_ty,
+ &ty_segments[..base_ty_end],
+ &ty_segments[base_ty_end..]);
+ let method_segment = path.segments.last().unwrap();
+ let method_name = method_segment.identifier.name;
+ match method::resolve_ufcs(fcx, expr.span, method_name, ty, id) {
+ Ok((def, lp)) => {
+ // Write back the new resolution.
+ tcx.def_map.borrow_mut().insert(id, def::PathResolution {
+ base_def: def,
+ last_private: path_res.last_private.or(lp),
+ depth: 0
+ });
+
+ let (scheme, predicates) =
+ type_scheme_and_predicates_for_def(fcx, expr.span, def);
+ instantiate_path(fcx, slice::ref_slice(method_segment),
+ scheme, &predicates,
+ Some(ty), def, expr.span, id);
+ }
+ Err(error) => {
+ method::report_error(fcx, expr.span, ty,
+ method_name, None, error);
+ fcx.write_error(id);
+ }
+ }
+ }
// We always require that the type provided as the value for
// a type parameter outlives the moment of instantiation.
}
ast::ExprStruct(ref path, ref fields, ref base_expr) => {
// Resolve the path.
- let def = tcx.def_map.borrow().get(&id).cloned();
+ let def = lookup_full_def(tcx, path.span, id);
let struct_id = match def {
- Some(def::DefVariant(enum_id, variant_id, true)) => {
+ def::DefVariant(enum_id, variant_id, true) => {
check_struct_enum_variant(fcx, id, expr.span, enum_id,
variant_id, &fields[..]);
enum_id
}
- Some(def::DefaultImpl(def_id)) => {
+ def::DefTrait(def_id) => {
span_err!(tcx.sess, path.span, E0159,
"use of trait `{}` as a struct constructor",
pprust::path_to_string(path));
base_expr);
def_id
},
- Some(def) => {
+ def => {
// Verify that this was actually a struct.
let typ = ty::lookup_item_type(fcx.ccx.tcx, def.def_id());
match typ.ty.sty {
def.def_id()
}
- _ => {
- tcx.sess.span_bug(path.span,
- "structure constructor wasn't resolved")
- }
};
// Turn the path into a type and verify that that type unifies with
check_instantiable(ccx.tcx, sp, id);
}
-pub fn lookup_def(fcx: &FnCtxt, sp: Span, id: ast::NodeId) -> def::Def {
- lookup_def_ccx(fcx.ccx, sp, id)
-}
-
// Returns the type parameter count and the type for the given definition.
fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
sp: Span,
(ty::TypeScheme { generics: ty::Generics::empty(), ty: typ },
ty::GenericPredicates::empty())
}
- def::DefFn(id, _) | def::DefStaticMethod(id, _) | def::DefMethod(id, _, _) |
+ def::DefFn(id, _) | def::DefMethod(id, _) |
def::DefStatic(id, _) | def::DefVariant(_, id, _) |
def::DefStruct(id) | def::DefConst(id) => {
(ty::lookup_item_type(fcx.tcx(), id), ty::lookup_predicates(fcx.tcx(), id))
}
- def::DefaultImpl(_) |
+ def::DefTrait(_) |
def::DefTy(..) |
def::DefAssociatedTy(..) |
- def::DefAssociatedPath(..) |
def::DefPrimTy(_) |
def::DefTyParam(..) |
def::DefMod(..) |
def::DefForeignMod(..) |
def::DefUse(..) |
def::DefRegion(..) |
- def::DefTyParamBinder(..) |
def::DefLabel(..) |
def::DefSelfTy(..) => {
fcx.ccx.tcx.sess.span_bug(sp, &format!("expected value, found {:?}", defn));
// Instantiates the given path, which must refer to an item with the given
// number of type parameters and type.
pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
- path: &ast::Path,
+ segments: &[ast::PathSegment],
type_scheme: TypeScheme<'tcx>,
type_predicates: &ty::GenericPredicates<'tcx>,
opt_self_ty: Option<Ty<'tcx>>,
def: def::Def,
span: Span,
node_id: ast::NodeId) {
- debug!("instantiate_path(path={}, def={}, node_id={}, type_scheme={})",
- path.repr(fcx.tcx()),
+ debug!("instantiate_path(path={:?}, def={}, node_id={}, type_scheme={})",
+ segments,
def.repr(fcx.tcx()),
node_id,
type_scheme.repr(fcx.tcx()));
//
// The first step then is to categorize the segments appropriately.
- assert!(path.segments.len() >= 1);
+ assert!(segments.len() >= 1);
+
+ let mut ufcs_method = None;
let mut segment_spaces: Vec<_>;
match def {
// Case 1 and 1b. Reference to a *type* or *enum variant*.
def::DefSelfTy(..) |
def::DefStruct(..) |
def::DefVariant(..) |
- def::DefTyParamBinder(..) |
def::DefTy(..) |
def::DefAssociatedTy(..) |
- def::DefAssociatedPath(..) |
- def::DefaultImpl(..) |
+ def::DefTrait(..) |
def::DefPrimTy(..) |
def::DefTyParam(..) => {
// Everything but the final segment should have no
// parameters at all.
- segment_spaces = repeat(None).take(path.segments.len() - 1).collect();
+ segment_spaces = repeat(None).take(segments.len() - 1).collect();
segment_spaces.push(Some(subst::TypeSpace));
}
def::DefFn(..) |
def::DefConst(..) |
def::DefStatic(..) => {
- segment_spaces = repeat(None).take(path.segments.len() - 1).collect();
+ segment_spaces = repeat(None).take(segments.len() - 1).collect();
segment_spaces.push(Some(subst::FnSpace));
}
// Case 3. Reference to a method.
- def::DefStaticMethod(_, providence) |
- def::DefMethod(_, _, providence) => {
- assert!(path.segments.len() >= 2);
-
- match providence {
+ def::DefMethod(_, provenance) => {
+ match provenance {
def::FromTrait(trait_did) => {
callee::check_legal_trait_for_method_call(fcx.ccx, span, trait_did)
}
def::FromImpl(_) => {}
}
- segment_spaces = repeat(None).take(path.segments.len() - 2).collect();
- segment_spaces.push(Some(subst::TypeSpace));
- segment_spaces.push(Some(subst::FnSpace));
+ if segments.len() >= 2 {
+ segment_spaces = repeat(None).take(segments.len() - 2).collect();
+ segment_spaces.push(Some(subst::TypeSpace));
+ segment_spaces.push(Some(subst::FnSpace));
+ } else {
+ // `<T>::method` will end up here, and so can `T::method`.
+ let self_ty = opt_self_ty.expect("UFCS sugared method missing Self");
+ segment_spaces = vec![Some(subst::FnSpace)];
+ ufcs_method = Some((provenance, self_ty));
+ }
}
// Other cases. Various nonsense that really shouldn't show up
def::DefRegion(..) |
def::DefLabel(..) |
def::DefUpvar(..) => {
- segment_spaces = repeat(None).take(path.segments.len()).collect();
+ segment_spaces = repeat(None).take(segments.len()).collect();
}
}
- assert_eq!(segment_spaces.len(), path.segments.len());
+ assert_eq!(segment_spaces.len(), segments.len());
+
+ // In `<T as Trait<A, B>>::method`, `A` and `B` are mandatory, but
+ // `opt_self_ty` can also be Some for `Foo::method`, where Foo's
+ // type parameters are not mandatory.
+ let require_type_space = opt_self_ty.is_some() && ufcs_method.is_none();
debug!("segment_spaces={:?}", segment_spaces);
// provided (if any) into their appropriate spaces. We'll also report
// errors if type parameters are provided in an inappropriate place.
let mut substs = Substs::empty();
- for (opt_space, segment) in segment_spaces.iter().zip(path.segments.iter()) {
+ for (opt_space, segment) in segment_spaces.iter().zip(segments.iter()) {
match *opt_space {
None => {
- report_error_if_segment_contains_type_parameters(fcx, segment);
+ check_path_args(fcx.tcx(), slice::ref_slice(segment),
+ NO_TPS | NO_REGIONS);
}
Some(space) => {
push_explicit_parameters_from_segment_to_substs(fcx,
space,
- path.span,
+ span,
type_defs,
region_defs,
segment,
}
}
if let Some(self_ty) = opt_self_ty {
- // `<T as Trait>::foo` shouldn't have resolved to a `Self`-less item.
- assert_eq!(type_defs.len(subst::SelfSpace), 1);
- substs.types.push(subst::SelfSpace, self_ty);
+ if type_defs.len(subst::SelfSpace) == 1 {
+ substs.types.push(subst::SelfSpace, self_ty);
+ }
}
// Now we have to compare the types that the user *actually*
// to add defaults. If the user provided *too many* types, that's
// a problem.
for &space in &ParamSpace::all() {
- adjust_type_parameters(fcx, span, space, type_defs, &mut substs);
+ adjust_type_parameters(fcx, span, space, type_defs,
+ require_type_space, &mut substs);
assert_eq!(substs.types.len(space), type_defs.len(space));
adjust_region_parameters(fcx, span, space, region_defs, &mut substs);
// the referenced item.
let ty_substituted = fcx.instantiate_type_scheme(span, &substs, &type_scheme.ty);
- fcx.write_ty(node_id, ty_substituted);
- fcx.write_substs(node_id, ty::ItemSubsts { substs: substs });
- return;
- fn report_error_if_segment_contains_type_parameters(
- fcx: &FnCtxt,
- segment: &ast::PathSegment)
- {
- for typ in &segment.parameters.types() {
- span_err!(fcx.tcx().sess, typ.span, E0085,
- "type parameters may not appear here");
- break;
- }
+ if let Some((def::FromImpl(impl_def_id), self_ty)) = ufcs_method {
+ // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
+ // is inherent, there is no `Self` parameter, instead, the impl needs
+ // type parameters, which we can infer by unifying the provided `Self`
+ // with the substituted impl type.
+ let impl_scheme = ty::lookup_item_type(fcx.tcx(), impl_def_id);
+ assert_eq!(substs.types.len(subst::TypeSpace),
+ impl_scheme.generics.types.len(subst::TypeSpace));
+ assert_eq!(substs.regions().len(subst::TypeSpace),
+ impl_scheme.generics.regions.len(subst::TypeSpace));
- for lifetime in &segment.parameters.lifetimes() {
- span_err!(fcx.tcx().sess, lifetime.span, E0086,
- "lifetime parameters may not appear here");
- break;
+ let impl_ty = fcx.instantiate_type_scheme(span, &substs, &impl_scheme.ty);
+ if fcx.mk_subty(false, infer::Misc(span), self_ty, impl_ty).is_err() {
+ fcx.tcx().sess.span_bug(span,
+ &format!(
+ "instantiate_path: (UFCS) {} was a subtype of {} but now is not?",
+ self_ty.repr(fcx.tcx()),
+ impl_ty.repr(fcx.tcx())));
}
}
+ fcx.write_ty(node_id, ty_substituted);
+ fcx.write_substs(node_id, ty::ItemSubsts { substs: substs });
+ return;
+
/// Finds the parameters that the user provided and adds them to `substs`. If too many
/// parameters are provided, then reports an error and clears the output vector.
///
span: Span,
space: ParamSpace,
defs: &VecPerParamSpace<ty::TypeParameterDef<'tcx>>,
+ require_type_space: bool,
substs: &mut Substs<'tcx>)
{
let provided_len = substs.types.len(space);
// Nothing specified at all: supply inference variables for
// everything.
- if provided_len == 0 {
- substs.types.replace(space,
- fcx.infcx().next_ty_vars(desired.len()));
+ if provided_len == 0 && !(require_type_space && space == subst::TypeSpace) {
+ substs.types.replace(space, fcx.infcx().next_ty_vars(desired.len()));
return;
}
_ => false
}
})) ||
- // Second: is there a labeled break with label
- // <id> nested anywhere inside the loop?
+ // Second: is there a labeled break with label
+ // <id> nested anywhere inside the loop?
(block_query(b, |e| {
- match e.node {
- ast::ExprBreak(Some(_)) => {
- match cx.def_map.borrow().get(&e.id) {
- Some(&def::DefLabel(loop_id)) if id == loop_id => true,
- _ => false,
- }
- }
- _ => false
- }}))
+ if let ast::ExprBreak(Some(_)) = e.node {
+ lookup_full_def(cx, e.span, e.id) == def::DefLabel(id)
+ } else {
+ false
+ }
+ }))
}
pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
ast::ItemImpl(_, ast::ImplPolarity::Positive, _, _, _, _) => {
self.check_impl(item);
}
- ast::ItemImpl(_, ast::ImplPolarity::Negative, _, Some(ref tref), _, _) => {
- let trait_ref = ty::node_id_to_trait_ref(ccx.tcx, tref.ref_id);
+ ast::ItemImpl(_, ast::ImplPolarity::Negative, _, Some(_), _, _) => {
+ let trait_ref = ty::impl_id_to_trait_ref(ccx.tcx, item.id);
ty::populate_implementations_for_trait_if_necessary(ccx.tcx, trait_ref.def_id);
match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) {
Some(ty::BoundSend) | Some(ty::BoundSync) => {}
impl<'cx, 'tcx,'v> visit::Visitor<'v> for ImplsChecker<'cx, 'tcx> {
fn visit_item(&mut self, item: &'v ast::Item) {
match item.node {
- ast::ItemImpl(_, _, _, Some(ref opt_trait), _, _) => {
- let trait_ref = ty::node_id_to_trait_ref(self.tcx, opt_trait.ref_id);
+ ast::ItemImpl(_, _, _, Some(_), _, _) => {
+ let trait_ref = ty::impl_id_to_trait_ref(self.tcx, item.id);
if let Some(_) = self.tcx.lang_items.to_builtin_kind(trait_ref.def_id) {
match trait_ref.self_ty().sty {
ty::ty_struct(..) | ty::ty_enum(..) => {}
//debug!("(checking coherence) item '{}'", token::get_ident(item.ident));
- match item.node {
- ItemImpl(_, _, _, ref opt_trait, _, _) => {
- match opt_trait.clone() {
- Some(opt_trait) => {
- self.cc.check_implementation(item, &[opt_trait]);
- }
- None => self.cc.check_implementation(item, &[])
- }
- }
- _ => {
- // Nothing to do.
- }
- };
+ if let ItemImpl(_, _, _, ref opt_trait, _, _) = item.node {
+ self.cc.check_implementation(item, opt_trait.as_ref())
+ }
visit::walk_item(self, item);
}
self.check_implementations_of_copy();
}
- fn check_implementation(&self,
- item: &Item,
- associated_traits: &[TraitRef]) {
+ fn check_implementation(&self, item: &Item, opt_trait: Option<&TraitRef>) {
let tcx = self.crate_context.tcx;
let impl_did = local_def(item.id);
let self_type = ty::lookup_item_type(tcx, impl_did);
let impl_items = self.create_impl_from_item(item);
- for associated_trait in associated_traits {
- let trait_ref = ty::node_id_to_trait_ref(self.crate_context.tcx,
- associated_trait.ref_id);
+ if opt_trait.is_some() {
+ let trait_ref = ty::impl_id_to_trait_ref(self.crate_context.tcx, item.id);
debug!("(checking implementation) adding impl for trait '{}', item '{}'",
trait_ref.repr(self.crate_context.tcx),
token::get_ident(item.ident));
}
Some(base_type_def_id) => {
// FIXME: Gather up default methods?
- if associated_traits.len() == 0 {
+ if opt_trait.is_none() {
self.add_inherent_impl(base_type_def_id, impl_did);
}
}
// Converts an implementation in the AST to a vector of items.
fn create_impl_from_item(&self, item: &Item) -> Vec<ImplOrTraitItemId> {
match item.node {
- ItemImpl(_, _, _, ref trait_refs, _, ref ast_items) => {
+ ItemImpl(_, _, _, ref opt_trait, _, ref ast_items) => {
let mut items: Vec<ImplOrTraitItemId> =
ast_items.iter()
.map(|ast_item| {
}
}).collect();
- if let Some(ref trait_ref) = *trait_refs {
- let ty_trait_ref = ty::node_id_to_trait_ref(
- self.crate_context.tcx,
- trait_ref.ref_id);
+ if opt_trait.is_some() {
+ let trait_ref = ty::impl_id_to_trait_ref(self.crate_context.tcx,
+ item.id);
self.instantiate_default_methods(local_def(item.id),
- &*ty_trait_ref,
+ &*trait_ref,
&mut items);
}
use syntax::ast::{Item, ItemImpl};
use syntax::ast;
use syntax::ast_util;
-use syntax::codemap::Span;
use syntax::visit;
use util::ppaux::{Repr, UserString};
}
impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
- fn check_def_id(&self, span: Span, def_id: ast::DefId) {
+ fn check_def_id(&self, item: &ast::Item, def_id: ast::DefId) {
if def_id.krate != ast::LOCAL_CRATE {
- span_err!(self.tcx.sess, span, E0116,
+ span_err!(self.tcx.sess, item.span, E0116,
"cannot associate methods with a type outside the \
crate the type is defined in; define and implement \
a trait or new type instead");
}
impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
- fn visit_item(&mut self, item: &'v ast::Item) {
+ fn visit_item(&mut self, item: &ast::Item) {
let def_id = ast_util::local_def(item.id);
match item.node {
ast::ItemImpl(_, _, _, None, _, _) => {
match self_ty.sty {
ty::ty_enum(def_id, _) |
ty::ty_struct(def_id, _) => {
- self.check_def_id(item.span, def_id);
+ self.check_def_id(item, def_id);
}
ty::ty_trait(ref data) => {
- self.check_def_id(item.span, data.principal_def_id());
+ self.check_def_id(item, data.principal_def_id());
}
ty::ty_uniq(..) => {
- self.check_def_id(item.span,
- self.tcx.lang_items.owned_box()
- .unwrap());
+ self.check_def_id(item, self.tcx.lang_items.owned_box().unwrap());
}
_ => {
span_err!(self.tcx.sess, item.span, E0118,
}
}
}
- ast::ItemDefaultImpl(_, ref ast_trait_ref) => {
+ ast::ItemDefaultImpl(..) => {
// "Trait" impl
debug!("coherence2::orphan check: default trait impl {}", item.repr(self.tcx));
- let trait_ref = ty::node_id_to_trait_ref(self.tcx, ast_trait_ref.ref_id);
+ let trait_ref = ty::impl_trait_ref(self.tcx, def_id).unwrap();
if trait_ref.def_id.krate != ast::LOCAL_CRATE {
span_err!(self.tcx.sess, item.span, E0318,
"cannot create default implementations for traits outside the \
None => {
self.tcx.sess.bug(
&format!("no default implementation recorded for `{:?}`",
- item)[]);
+ item));
}
}
}
use middle::lang_items::SizedTraitLangItem;
use middle::region;
use middle::resolve_lifetime;
-use middle::subst;
-use middle::subst::{Substs, SelfSpace, TypeSpace, VecPerParamSpace};
+use middle::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace};
use middle::ty::{AsPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer};
-use middle::ty::{self, RegionEscape, Ty, TypeScheme};
+use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty, TypeScheme};
use middle::ty_fold::{self, TypeFolder, TypeFoldable};
use middle::infer;
use rscope::*;
-use util::common::memoized;
+use util::common::{ErrorReported, memoized};
use util::nodemap::{FnvHashMap, FnvHashSet};
use util::ppaux;
use util::ppaux::{Repr,UserString};
use write_ty_to_tcx;
+use std::cell::RefCell;
use std::collections::HashSet;
use std::rc::Rc;
// Main entry point
pub fn collect_item_types(tcx: &ty::ctxt) {
- let ccx = &CollectCtxt { tcx: tcx };
+ let ccx = &CrateCtxt { tcx: tcx, stack: RefCell::new(Vec::new()) };
match ccx.tcx.lang_items.ty_desc() {
Some(id) => { collect_intrinsic_type(ccx, id); }
///////////////////////////////////////////////////////////////////////////
-struct CollectCtxt<'a,'tcx:'a> {
+struct CrateCtxt<'a,'tcx:'a> {
tcx: &'a ty::ctxt<'tcx>,
+
+ // This stack is used to identify cycles in the user's source.
+ // Note that these cycles can cross multiple items.
+ stack: RefCell<Vec<AstConvRequest>>,
+}
+
+/// Context specific to some particular item. This is what implements
+/// AstConv. It has information about the predicates that are defined
+/// on the trait. Unfortunately, this predicate information is
+/// available in various different forms at various points in the
+/// process. So we can't just store a pointer to e.g. the AST or the
+/// parsed ty form, we have to be more flexible. To this end, the
+/// `ItemCtxt` is parameterized by a `GetTypeParameterBounds` object
+/// that it uses to satisfy `get_type_parameter_bounds` requests.
+/// This object might draw the information from the AST
+/// (`ast::Generics`) or it might draw from a `ty::GenericPredicates`
+/// or both (a tuple).
+struct ItemCtxt<'a,'tcx:'a> {
+ ccx: &'a CrateCtxt<'a,'tcx>,
+ param_bounds: &'a (GetTypeParameterBounds<'tcx>+'a),
+}
+
+#[derive(Copy, PartialEq, Eq)]
+enum AstConvRequest {
+ GetItemTypeScheme(ast::DefId),
+ GetTraitDef(ast::DefId),
+ GetTypeParameterBounds(ast::NodeId),
}
///////////////////////////////////////////////////////////////////////////
// Zeroth phase: collect types of intrinsics
-fn collect_intrinsic_type(ccx: &CollectCtxt,
+fn collect_intrinsic_type(ccx: &CrateCtxt,
lang_item: ast::DefId) {
- let ty::TypeScheme { ty, .. } =
- ccx.get_item_type_scheme(lang_item);
+ let ty::TypeScheme { ty, .. } = type_scheme_of_def_id(ccx, lang_item);
ccx.tcx.intrinsic_defs.borrow_mut().insert(lang_item, ty);
}
// know later when parsing field defs.
struct CollectTraitDefVisitor<'a, 'tcx: 'a> {
- ccx: &'a CollectCtxt<'a, 'tcx>
+ ccx: &'a CrateCtxt<'a, 'tcx>
}
impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectTraitDefVisitor<'a, 'tcx> {
// Second phase: collection proper.
struct CollectItemTypesVisitor<'a, 'tcx: 'a> {
- ccx: &'a CollectCtxt<'a, 'tcx>
+ ccx: &'a CrateCtxt<'a, 'tcx>
}
impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> {
///////////////////////////////////////////////////////////////////////////
// Utility types and common code for the above passes.
-pub trait ToTy<'tcx> {
- fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx>;
-}
+impl<'a,'tcx> CrateCtxt<'a,'tcx> {
+ fn icx(&'a self, param_bounds: &'a GetTypeParameterBounds<'tcx>) -> ItemCtxt<'a,'tcx> {
+ ItemCtxt { ccx: self, param_bounds: param_bounds }
+ }
-impl<'a,'tcx> ToTy<'tcx> for CollectCtxt<'a,'tcx> {
- fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx> {
- ast_ty_to_ty(self, rs, ast_ty)
+ fn method_ty(&self, method_id: ast::NodeId) -> Rc<ty::Method<'tcx>> {
+ let def_id = local_def(method_id);
+ match self.tcx.impl_or_trait_items.borrow()[def_id] {
+ ty::MethodTraitItem(ref mty) => mty.clone(),
+ ty::TypeTraitItem(..) => {
+ self.tcx.sess.bug(&format!("method with id {} has the wrong type", method_id));
+ }
+ }
}
-}
-impl<'a, 'tcx> AstConv<'tcx> for CollectCtxt<'a, 'tcx> {
- fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }
+ fn cycle_check<F,R>(&self,
+ span: Span,
+ request: AstConvRequest,
+ code: F)
+ -> Result<R,ErrorReported>
+ where F: FnOnce() -> R
+ {
+ {
+ let mut stack = self.stack.borrow_mut();
+ match stack.iter().enumerate().rev().find(|&(_, r)| *r == request) {
+ None => { }
+ Some((i, _)) => {
+ let cycle = &stack[i..];
+ self.report_cycle(span, cycle);
+ return Err(ErrorReported);
+ }
+ }
+ stack.push(request);
+ }
+
+ let result = code();
- fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx> {
- if id.krate != ast::LOCAL_CRATE {
- return ty::lookup_item_type(self.tcx, id);
+ self.stack.borrow_mut().pop();
+ Ok(result)
+ }
+
+ fn report_cycle(&self,
+ span: Span,
+ cycle: &[AstConvRequest])
+ {
+ assert!(!cycle.is_empty());
+ let tcx = self.tcx;
+
+ tcx.sess.span_err(
+ span,
+ &format!("unsupported cyclic reference between types/traits detected"));
+
+ match cycle[0] {
+ AstConvRequest::GetItemTypeScheme(def_id) |
+ AstConvRequest::GetTraitDef(def_id) => {
+ tcx.sess.note(
+ &format!("the cycle begins when processing `{}`...",
+ ty::item_path_str(tcx, def_id)));
+ }
+ AstConvRequest::GetTypeParameterBounds(id) => {
+ let def = tcx.type_parameter_def(id);
+ tcx.sess.note(
+ &format!("the cycle begins when computing the bounds \
+ for type parameter `{}`...",
+ def.name.user_string(tcx)));
+ }
}
- match self.tcx.map.find(id.node) {
- Some(ast_map::NodeItem(item)) => {
- type_scheme_of_item(self, &*item)
+ for request in cycle[1..].iter() {
+ match *request {
+ AstConvRequest::GetItemTypeScheme(def_id) |
+ AstConvRequest::GetTraitDef(def_id) => {
+ tcx.sess.note(
+ &format!("...which then requires processing `{}`...",
+ ty::item_path_str(tcx, def_id)));
+ }
+ AstConvRequest::GetTypeParameterBounds(id) => {
+ let def = tcx.type_parameter_def(id);
+ tcx.sess.note(
+ &format!("...which then requires computing the bounds \
+ for type parameter `{}`...",
+ def.name.user_string(tcx)));
+ }
}
- Some(ast_map::NodeForeignItem(foreign_item)) => {
- let abi = self.tcx.map.get_foreign_abi(id.node);
- type_scheme_of_foreign_item(self, &*foreign_item, abi)
+ }
+
+ match cycle[0] {
+ AstConvRequest::GetItemTypeScheme(def_id) |
+ AstConvRequest::GetTraitDef(def_id) => {
+ tcx.sess.note(
+ &format!("...which then again requires processing `{}`, completing the cycle.",
+ ty::item_path_str(tcx, def_id)));
}
- x => {
- self.tcx.sess.bug(&format!("unexpected sort of node \
- in get_item_type_scheme(): {:?}",
- x));
+ AstConvRequest::GetTypeParameterBounds(id) => {
+ let def = tcx.type_parameter_def(id);
+ tcx.sess.note(
+ &format!("...which then again requires computing the bounds \
+ for type parameter `{}`, completing the cycle.",
+ def.name.user_string(tcx)));
}
}
}
+}
- fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef<'tcx>> {
- get_trait_def(self, id)
+impl<'a,'tcx> ItemCtxt<'a,'tcx> {
+ fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx> {
+ ast_ty_to_ty(self, rs, ast_ty)
+ }
+}
+
+impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> {
+ fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx }
+
+ fn get_item_type_scheme(&self, span: Span, id: ast::DefId)
+ -> Result<ty::TypeScheme<'tcx>, ErrorReported>
+ {
+ self.ccx.cycle_check(span, AstConvRequest::GetItemTypeScheme(id), || {
+ type_scheme_of_def_id(self.ccx, id)
+ })
+ }
+
+ fn get_trait_def(&self, span: Span, id: ast::DefId)
+ -> Result<Rc<ty::TraitDef<'tcx>>, ErrorReported>
+ {
+ self.ccx.cycle_check(span, AstConvRequest::GetTraitDef(id), || {
+ get_trait_def(self.ccx, id)
+ })
+ }
+
+ fn get_type_parameter_bounds(&self,
+ span: Span,
+ node_id: ast::NodeId)
+ -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>
+ {
+ self.ccx.cycle_check(span, AstConvRequest::GetTypeParameterBounds(node_id), || {
+ self.param_bounds.get_type_parameter_bounds(self, span, node_id)
+ })
}
fn ty_infer(&self, span: Span) -> Ty<'tcx> {
}
}
-fn get_enum_variant_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+/// Interface used to find the bounds on a type parameter from within
+/// an `ItemCtxt`. This allows us to use multiple kinds of sources.
+trait GetTypeParameterBounds<'tcx> {
+ fn get_type_parameter_bounds(&self,
+ astconv: &AstConv<'tcx>,
+ span: Span,
+ node_id: ast::NodeId)
+ -> Vec<ty::PolyTraitRef<'tcx>>;
+}
+
+/// Find bounds from both elements of the tuple.
+impl<'a,'b,'tcx,A,B> GetTypeParameterBounds<'tcx> for (&'a A,&'b B)
+ where A : GetTypeParameterBounds<'tcx>, B : GetTypeParameterBounds<'tcx>
+{
+ fn get_type_parameter_bounds(&self,
+ astconv: &AstConv<'tcx>,
+ span: Span,
+ node_id: ast::NodeId)
+ -> Vec<ty::PolyTraitRef<'tcx>>
+ {
+ let mut v = self.0.get_type_parameter_bounds(astconv, span, node_id);
+ v.extend(self.1.get_type_parameter_bounds(astconv, span, node_id).into_iter());
+ v
+ }
+}
+
+/// Empty set of bounds.
+impl<'tcx> GetTypeParameterBounds<'tcx> for () {
+ fn get_type_parameter_bounds(&self,
+ _astconv: &AstConv<'tcx>,
+ _span: Span,
+ _node_id: ast::NodeId)
+ -> Vec<ty::PolyTraitRef<'tcx>>
+ {
+ Vec::new()
+ }
+}
+
+/// Find bounds from the parsed and converted predicates. This is
+/// used when converting methods, because by that time the predicates
+/// from the trait/impl have been fully converted.
+impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> {
+ fn get_type_parameter_bounds(&self,
+ astconv: &AstConv<'tcx>,
+ _span: Span,
+ node_id: ast::NodeId)
+ -> Vec<ty::PolyTraitRef<'tcx>>
+ {
+ let def = astconv.tcx().type_parameter_def(node_id);
+
+ self.predicates
+ .iter()
+ .filter_map(|predicate| {
+ match *predicate {
+ ty::Predicate::Trait(ref data) => {
+ if data.0.self_ty().is_param(def.space, def.index) {
+ Some(data.to_poly_trait_ref())
+ } else {
+ None
+ }
+ }
+ ty::Predicate::Equate(..) |
+ ty::Predicate::RegionOutlives(..) |
+ ty::Predicate::TypeOutlives(..) |
+ ty::Predicate::Projection(..) => {
+ None
+ }
+ }
+ })
+ .collect()
+ }
+}
+
+/// Find bounds from ast::Generics. This requires scanning through the
+/// AST. We do this to avoid having to convert *all* the bounds, which
+/// would create artificial cycles. Instead we can only convert the
+/// bounds for those a type parameter `X` if `X::Foo` is used.
+impl<'tcx> GetTypeParameterBounds<'tcx> for ast::Generics {
+ fn get_type_parameter_bounds(&self,
+ astconv: &AstConv<'tcx>,
+ _: Span,
+ node_id: ast::NodeId)
+ -> Vec<ty::PolyTraitRef<'tcx>>
+ {
+ // In the AST, bounds can derive from two places. Either
+ // written inline like `<T:Foo>` or in a where clause like
+ // `where T:Foo`.
+
+ let def = astconv.tcx().type_parameter_def(node_id);
+ let ty = ty::mk_param_from_def(astconv.tcx(), &def);
+
+ let from_ty_params =
+ self.ty_params
+ .iter()
+ .filter(|p| p.id == node_id)
+ .flat_map(|p| p.bounds.iter())
+ .filter_map(|b| poly_trait_ref_from_bound(astconv, ty, b, &mut Vec::new()));
+
+ let from_where_clauses =
+ self.where_clause
+ .predicates
+ .iter()
+ .filter_map(|wp| match *wp {
+ ast::WherePredicate::BoundPredicate(ref bp) => Some(bp),
+ _ => None
+ })
+ .filter(|bp| is_param(astconv.tcx(), &bp.bounded_ty, node_id))
+ .flat_map(|bp| bp.bounds.iter())
+ .filter_map(|b| poly_trait_ref_from_bound(astconv, ty, b, &mut Vec::new()));
+
+ from_ty_params.chain(from_where_clauses).collect()
+ }
+}
+
+/// Tests whether this is the AST for a reference to the type
+/// parameter with id `param_id`. We use this so as to avoid running
+/// `ast_ty_to_ty`, because we want to avoid triggering an all-out
+/// conversion of the type to avoid inducing unnecessary cycles.
+fn is_param<'tcx>(tcx: &ty::ctxt<'tcx>,
+ ast_ty: &ast::Ty,
+ param_id: ast::NodeId)
+ -> bool
+{
+ if let ast::TyPath(None, _) = ast_ty.node {
+ let path_res = tcx.def_map.borrow()[ast_ty.id];
+ if let def::DefTyParam(_, _, def_id, _) = path_res.base_def {
+ path_res.depth == 0 && def_id == local_def(param_id)
+ } else {
+ false
+ }
+ } else {
+ false
+ }
+}
+
+fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
enum_scheme: ty::TypeScheme<'tcx>,
enum_predicates: ty::GenericPredicates<'tcx>,
variants: &[P<ast::Variant>]) {
let tcx = ccx.tcx;
+ let icx = ccx.icx(&enum_predicates);
// Create a set of parameter types shared among all the variants.
for variant in variants {
let result_ty = match variant.node.kind {
ast::TupleVariantKind(ref args) if args.len() > 0 => {
let rs = ExplicitRscope;
- let input_tys: Vec<_> = args.iter().map(|va| ccx.to_ty(&rs, &*va.ty)).collect();
- ty::mk_ctor_fn(tcx, variant_def_id, &input_tys[..], enum_scheme.ty)
+ let input_tys: Vec<_> = args.iter().map(|va| icx.to_ty(&rs, &*va.ty)).collect();
+ ty::mk_ctor_fn(tcx, variant_def_id, &input_tys, enum_scheme.ty)
}
ast::TupleVariantKind(_) => {
}
}
-fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
trait_id: ast::NodeId,
trait_def: &ty::TraitDef<'tcx>,
trait_predicates: &ty::GenericPredicates<'tcx>) {
}
}
- fn make_method_ty<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, m: &ty::Method<'tcx>) {
+ fn make_method_ty<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, m: &ty::Method<'tcx>) {
ccx.tcx.tcache.borrow_mut().insert(
m.def_id,
TypeScheme {
m.predicates.clone());
}
- fn ty_method_of_trait_method<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+ fn ty_method_of_trait_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
trait_id: ast::NodeId,
trait_generics: &ty::Generics<'tcx>,
trait_bounds: &ty::GenericPredicates<'tcx>,
m_generics: &ast::Generics,
m_unsafety: &ast::Unsafety,
m_decl: &ast::FnDecl)
- -> ty::Method<'tcx> {
+ -> ty::Method<'tcx>
+ {
let ty_generics =
- ty_generics_for_fn_or_method(ccx,
- m_generics,
- trait_generics.clone());
+ ty_generics_for_fn(ccx, m_generics, trait_generics);
- let ty_bounds =
- ty_generic_bounds_for_fn_or_method(ccx,
- m_generics,
- &ty_generics,
- trait_bounds.clone());
+ let ty_generic_predicates =
+ ty_generic_predicates_for_fn(ccx, m_generics, trait_bounds);
let (fty, explicit_self_category) = {
let trait_self_ty = ty::mk_self_type(ccx.tcx);
- astconv::ty_of_method(ccx,
+ astconv::ty_of_method(&ccx.icx(&(trait_bounds, m_generics)),
*m_unsafety,
trait_self_ty,
m_explicit_self,
ty::Method::new(
*m_name,
ty_generics,
- ty_bounds,
+ ty_generic_predicates,
fty,
explicit_self_category,
// assume public, because this is only invoked on trait methods
}
}
-fn convert_field<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
- struct_generics: &ty::Generics<'tcx>,
- struct_predicates: &ty::GenericPredicates<'tcx>,
- v: &ast::StructField,
- origin: ast::DefId) -> ty::field_ty {
- let tt = ccx.to_ty(&ExplicitRscope, &*v.node.ty);
+fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+ struct_generics: &ty::Generics<'tcx>,
+ struct_predicates: &ty::GenericPredicates<'tcx>,
+ v: &ast::StructField,
+ origin: ast::DefId)
+ -> ty::field_ty
+{
+ let tt = ccx.icx(struct_predicates).to_ty(&ExplicitRscope, &*v.node.ty);
write_ty_to_tcx(ccx.tcx, v.node.id, tt);
/* add the field to the tcache */
}
}
-fn convert_associated_type<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
trait_def: &ty::TraitDef<'tcx>,
associated_type: &ast::AssociatedType)
{
ccx.tcx
.impl_or_trait_items
.borrow_mut()
- .insert(associated_type.def_id,
- ty::TypeTraitItem(associated_type));
+ .insert(associated_type.def_id, ty::TypeTraitItem(associated_type));
}
-fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>,
+fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>,
container: ImplOrTraitItemContainer,
ms: I,
untransformed_rcvr_ty: Ty<'tcx>,
rcvr_ty_generics: &ty::Generics<'tcx>,
rcvr_ty_predicates: &ty::GenericPredicates<'tcx>,
rcvr_visibility: ast::Visibility)
- where I: Iterator<Item=&'i ast::Method> {
+ where I: Iterator<Item=&'i ast::Method>
+{
debug!("convert_methods(untransformed_rcvr_ty={}, rcvr_ty_generics={})",
untransformed_rcvr_ty.repr(ccx.tcx),
rcvr_ty_generics.repr(ccx.tcx));
.insert(mty.def_id, ty::MethodTraitItem(mty));
}
- fn ty_of_method<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+ fn ty_of_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
container: ImplOrTraitItemContainer,
m: &ast::Method,
untransformed_rcvr_ty: Ty<'tcx>,
rcvr_ty_generics: &ty::Generics<'tcx>,
rcvr_ty_predicates: &ty::GenericPredicates<'tcx>,
rcvr_visibility: ast::Visibility)
- -> ty::Method<'tcx> {
+ -> ty::Method<'tcx>
+ {
let m_ty_generics =
- ty_generics_for_fn_or_method(ccx,
- m.pe_generics(),
- rcvr_ty_generics.clone());
-
- let m_ty_bounds =
- ty_generic_bounds_for_fn_or_method(ccx,
- m.pe_generics(),
- &m_ty_generics,
- rcvr_ty_predicates.clone());
-
- let (fty, explicit_self_category) = astconv::ty_of_method(ccx,
- m.pe_unsafety(),
- untransformed_rcvr_ty,
- m.pe_explicit_self(),
- &*m.pe_fn_decl(),
- m.pe_abi());
+ ty_generics_for_fn(ccx, m.pe_generics(), rcvr_ty_generics);
+
+ let m_ty_generic_predicates =
+ ty_generic_predicates_for_fn(ccx, m.pe_generics(), rcvr_ty_predicates);
+
+ let (fty, explicit_self_category) =
+ astconv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, m.pe_generics())),
+ m.pe_unsafety(),
+ untransformed_rcvr_ty,
+ m.pe_explicit_self(),
+ &*m.pe_fn_decl(),
+ m.pe_abi());
// if the method specifies a visibility, use that, otherwise
// inherit the visibility from the impl (so `foo` in `pub impl
ty::Method::new(m.pe_ident().name,
m_ty_generics,
- m_ty_bounds,
+ m_ty_generic_predicates,
fty,
explicit_self_category,
method_vis,
}
}
-fn ensure_no_ty_param_bounds(ccx: &CollectCtxt,
+fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
span: Span,
generics: &ast::Generics,
thing: &'static str) {
}
}
-fn convert_item(ccx: &CollectCtxt, it: &ast::Item) {
+fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
let tcx = ccx.tcx;
debug!("convert: item {} with id {}", token::get_ident(it.ident), it.id);
match it.node {
&enum_definition.variants);
},
ast::ItemDefaultImpl(_, ref ast_trait_ref) => {
- let trait_ref = astconv::instantiate_trait_ref(ccx, &ExplicitRscope,
- ast_trait_ref, None, None);
+ let trait_ref = astconv::instantiate_trait_ref(&ccx.icx(&()),
+ &ExplicitRscope,
+ ast_trait_ref,
+ Some(it.id),
+ None,
+ None);
ty::record_default_trait_implementation(tcx, trait_ref.def_id, local_def(it.id))
}
debug!("convert: ast_generics={:?}", generics);
let ty_generics = ty_generics_for_type_or_impl(ccx, generics);
- let ty_predicates = ty_generic_bounds_for_type_or_impl(ccx, &ty_generics, generics);
+ let ty_predicates = ty_generic_predicates_for_type_or_impl(ccx, generics);
debug!("convert: impl_bounds={:?}", ty_predicates);
- let selfty = ccx.to_ty(&ExplicitRscope, &**selfty);
+ let selfty = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, &**selfty);
write_ty_to_tcx(tcx, it.id, selfty);
tcx.tcache.borrow_mut().insert(local_def(it.id),
for impl_item in impl_items {
match *impl_item {
ast::MethodImplItem(ref method) => {
- let body_id = method.pe_body().id;
- check_method_self_type(ccx,
- &BindingRscope::new(),
- selfty,
- method.pe_explicit_self(),
- body_id);
methods.push(&**method);
}
ast::TypeImplItem(ref typedef) => {
"associated items are not allowed in inherent impls");
}
- let typ = ccx.to_ty(&ExplicitRscope, &*typedef.typ);
+ let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, &*typedef.typ);
tcx.tcache.borrow_mut().insert(local_def(typedef.id),
TypeScheme {
generics: ty::Generics::empty(),
&ty_predicates,
parent_visibility);
+ for impl_item in impl_items {
+ match *impl_item {
+ ast::MethodImplItem(ref method) => {
+ let body_id = method.pe_body().id;
+ check_method_self_type(ccx,
+ &BindingRscope::new(),
+ ccx.method_ty(method.id),
+ selfty,
+ method.pe_explicit_self(),
+ body_id);
+ }
+ ast::TypeImplItem(..) => { }
+ }
+ }
+
if let Some(ref trait_ref) = *opt_trait_ref {
- astconv::instantiate_trait_ref(ccx,
+ astconv::instantiate_trait_ref(&ccx.icx(&ty_predicates),
&ExplicitRscope,
trait_ref,
+ Some(it.id),
Some(selfty),
None);
}
generics,
local_def(it.id));
},
- ast::ItemTrait(_, _, _, ref trait_methods) => {
+ ast::ItemTrait(_, _, _, ref trait_items) => {
let trait_def = trait_def_of_item(ccx, it);
convert_trait_predicates(ccx, it);
let trait_predicates = ty::lookup_predicates(ccx.tcx, local_def(it.id));
debug!("convert: trait_bounds={:?}", trait_predicates);
- for trait_method in trait_methods {
+ // Run convert_methods on the provided methods.
+ let untransformed_rcvr_ty = ty::mk_self_type(tcx);
+ convert_methods(ccx,
+ TraitContainer(local_def(it.id)),
+ trait_items.iter().filter_map(|m| match *m {
+ ast::RequiredMethod(_) => None,
+ ast::ProvidedMethod(ref m) => Some(&**m),
+ ast::TypeTraitItem(_) => None,
+ }),
+ untransformed_rcvr_ty,
+ &trait_def.generics,
+ &trait_predicates,
+ it.vis);
+
+ // We need to do this *after* converting methods, since
+ // convert_methods produces a tcache entry that is wrong for
+ // static trait methods. This is somewhat unfortunate.
+ collect_trait_methods(ccx, it.id, &*trait_def, &trait_predicates);
+
+ // This must be done after `collect_trait_methods` so that
+ // we have a method type stored for every method.
+ for trait_item in trait_items {
let self_type = ty::mk_self_type(tcx);
- match *trait_method {
+ match *trait_item {
ast::RequiredMethod(ref type_method) => {
let rscope = BindingRscope::new();
check_method_self_type(ccx,
&rscope,
+ ccx.method_ty(type_method.id),
self_type,
&type_method.explicit_self,
it.id)
ast::ProvidedMethod(ref method) => {
check_method_self_type(ccx,
&BindingRscope::new(),
+ ccx.method_ty(method.id),
self_type,
method.pe_explicit_self(),
it.id)
}
}
}
-
- // Run convert_methods on the provided methods.
- let untransformed_rcvr_ty = ty::mk_self_type(tcx);
- convert_methods(ccx,
- TraitContainer(local_def(it.id)),
- trait_methods.iter().filter_map(|m| match *m {
- ast::RequiredMethod(_) => None,
- ast::ProvidedMethod(ref m) => Some(&**m),
- ast::TypeTraitItem(_) => None,
- }),
- untransformed_rcvr_ty,
- &trait_def.generics,
- &trait_predicates,
- it.vis);
-
- // We need to do this *after* converting methods, since
- // convert_methods produces a tcache entry that is wrong for
- // static trait methods. This is somewhat unfortunate.
- collect_trait_methods(ccx, it.id, &*trait_def, &trait_predicates);
},
ast::ItemStruct(ref struct_def, _) => {
// Write the class type.
}
}
-fn convert_struct<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
struct_def: &ast::StructDef,
scheme: ty::TypeScheme<'tcx>,
predicates: ty::GenericPredicates<'tcx>,
}
}
-fn get_trait_def<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+fn get_trait_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
trait_id: ast::DefId)
-> Rc<ty::TraitDef<'tcx>> {
let tcx = ccx.tcx;
}
}
-fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
it: &ast::Item)
-> Rc<ty::TraitDef<'tcx>>
{
let self_param_ty = ty::ParamTy::for_self().to_ty(ccx.tcx);
// supertraits:
- let bounds = compute_bounds(ccx,
+ let bounds = compute_bounds(&ccx.icx(generics),
self_param_ty,
bounds,
SizedByDefault::No,
return trait_def;
- fn mk_trait_substs<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+ fn mk_trait_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
generics: &ast::Generics)
- -> subst::Substs<'tcx>
+ -> Substs<'tcx>
{
let tcx = ccx.tcx;
.iter()
.enumerate()
.map(|(i, def)| ty::ReEarlyBound(def.lifetime.id,
- subst::TypeSpace,
+ TypeSpace,
i as u32,
def.lifetime.name))
.collect();
generics.ty_params
.iter()
.enumerate()
- .map(|(i, def)| ty::mk_param(tcx, subst::TypeSpace,
+ .map(|(i, def)| ty::mk_param(tcx, TypeSpace,
i as u32, def.ident.name))
.collect();
// ...and also create the `Self` parameter.
let self_ty = ty::mk_self_type(tcx);
- subst::Substs::new_trait(types, regions, self_ty)
+ Substs::new_trait(types, regions, self_ty)
}
}
-fn convert_trait_predicates<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, it: &ast::Item) {
+fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) {
let tcx = ccx.tcx;
let trait_def = trait_def_of_item(ccx, it);
let super_predicates = ty::predicates(ccx.tcx, self_param_ty, &trait_def.bounds);
- let assoc_predicates = predicates_for_associated_types(ccx, &trait_def.trait_ref, items);
-
- // `ty_generic_bounds` below will consider the bounds on the type
+ // `ty_generic_predicates` below will consider the bounds on the type
// parameters (including `Self`) and the explicit where-clauses,
// but to get the full set of predicates on a trait we need to add
// in the supertrait bounds and anything declared on the
ty::GenericPredicates {
predicates: VecPerParamSpace::new(super_predicates, vec![], vec![])
};
- base_predicates.predicates.extend(subst::TypeSpace, assoc_predicates.into_iter());
- let self_bounds = &trait_def.generics.types.get_self().unwrap().bounds;
- base_predicates.predicates.extend(
- subst::SelfSpace,
- ty::predicates(ccx.tcx, self_param_ty, self_bounds).into_iter());
+ // Add in a predicate that `Self:Trait` (where `Trait` is the
+ // current trait). This is needed for builtin bounds.
+ let self_predicate = trait_def.trait_ref.to_poly_trait_ref().as_predicate();
+ base_predicates.predicates.push(SelfSpace, self_predicate);
// add in the explicit where-clauses
- let trait_predicates =
- ty_generic_bounds(ccx,
- subst::TypeSpace,
- &trait_def.generics,
- base_predicates,
- &generics.where_clause);
+ let mut trait_predicates =
+ ty_generic_predicates(ccx, TypeSpace, generics, &base_predicates);
+
+ let assoc_predicates = predicates_for_associated_types(ccx,
+ generics,
+ &trait_predicates,
+ &trait_def.trait_ref,
+ items);
+ trait_predicates.predicates.extend(TypeSpace, assoc_predicates.into_iter());
let prev_predicates = tcx.predicates.borrow_mut().insert(def_id, trait_predicates);
assert!(prev_predicates.is_none());
return;
- fn predicates_for_associated_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+ fn predicates_for_associated_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+ ast_generics: &ast::Generics,
+ trait_predicates: &ty::GenericPredicates<'tcx>,
self_trait_ref: &Rc<ty::TraitRef<'tcx>>,
trait_items: &[ast::TraitItem])
-> Vec<ty::Predicate<'tcx>>
self_trait_ref.clone(),
assoc_type_def.ident.name);
- let bounds = compute_bounds(ccx,
+ let bounds = compute_bounds(&ccx.icx(&(ast_generics, trait_predicates)),
assoc_ty,
&*assoc_type_def.bounds,
SizedByDefault::Yes,
}
}
-fn type_scheme_of_item<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
+fn type_scheme_of_def_id<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
+ def_id: ast::DefId)
+ -> ty::TypeScheme<'tcx>
+{
+ if def_id.krate != ast::LOCAL_CRATE {
+ return ty::lookup_item_type(ccx.tcx, def_id);
+ }
+
+ match ccx.tcx.map.find(def_id.node) {
+ Some(ast_map::NodeItem(item)) => {
+ type_scheme_of_item(ccx, &*item)
+ }
+ Some(ast_map::NodeForeignItem(foreign_item)) => {
+ let abi = ccx.tcx.map.get_foreign_abi(def_id.node);
+ type_scheme_of_foreign_item(ccx, &*foreign_item, abi)
+ }
+ x => {
+ ccx.tcx.sess.bug(&format!("unexpected sort of node \
+ in get_item_type_scheme(): {:?}",
+ x));
+ }
+ }
+}
+
+fn type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
it: &ast::Item)
-> ty::TypeScheme<'tcx>
{
|_| compute_type_scheme_of_item(ccx, it))
}
-
-fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
- it: &ast::Item)
- -> ty::TypeScheme<'tcx>
+fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
+ it: &ast::Item)
+ -> ty::TypeScheme<'tcx>
{
let tcx = ccx.tcx;
match it.node {
ast::ItemStatic(ref t, _, _) | ast::ItemConst(ref t, _) => {
- let ty = ccx.to_ty(&ExplicitRscope, &**t);
+ let ty = ccx.icx(&()).to_ty(&ExplicitRscope, &**t);
ty::TypeScheme { ty: ty, generics: ty::Generics::empty() }
}
ast::ItemFn(ref decl, unsafety, abi, ref generics, _) => {
- let ty_generics = ty_generics_for_fn_or_method(ccx,
- generics,
- ty::Generics::empty());
- let tofd = astconv::ty_of_bare_fn(ccx, unsafety, abi, &**decl);
+ let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty());
+ let tofd = astconv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &**decl);
let ty = ty::mk_bare_fn(tcx, Some(local_def(it.id)), tcx.mk_bare_fn(tofd));
ty::TypeScheme { ty: ty, generics: ty_generics }
}
ast::ItemTy(ref t, ref generics) => {
- let ty = ccx.to_ty(&ExplicitRscope, &**t);
let ty_generics = ty_generics_for_type_or_impl(ccx, generics);
+ let ty = ccx.icx(generics).to_ty(&ExplicitRscope, &**t);
ty::TypeScheme { ty: ty, generics: ty_generics }
}
ast::ItemEnum(_, ref generics) => {
}
}
-fn convert_typed_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
it: &ast::Item)
-> (ty::TypeScheme<'tcx>, ty::GenericPredicates<'tcx>)
{
ty::GenericPredicates::empty()
}
ast::ItemFn(_, _, _, ref ast_generics, _) => {
- ty_generic_bounds_for_fn_or_method(ccx,
- ast_generics,
- &scheme.generics,
- ty::GenericPredicates::empty())
+ ty_generic_predicates_for_fn(ccx, ast_generics, &ty::GenericPredicates::empty())
}
ast::ItemTy(_, ref generics) => {
- ty_generic_bounds_for_type_or_impl(ccx, &scheme.generics, generics)
+ ty_generic_predicates_for_type_or_impl(ccx, generics)
}
ast::ItemEnum(_, ref generics) => {
- ty_generic_bounds_for_type_or_impl(ccx, &scheme.generics, generics)
+ ty_generic_predicates_for_type_or_impl(ccx, generics)
}
ast::ItemStruct(_, ref generics) => {
- ty_generic_bounds_for_type_or_impl(ccx, &scheme.generics, generics)
+ ty_generic_predicates_for_type_or_impl(ccx, generics)
}
ast::ItemDefaultImpl(..) |
ast::ItemTrait(..) |
ast::ItemMac(..) => {
tcx.sess.span_bug(
it.span,
- format!("compute_type_scheme_of_item: unexpected item type: {:?}",
- it.node).as_slice());
+ &format!("compute_type_scheme_of_item: unexpected item type: {:?}",
+ it.node));
}
};
Some(ty::ObjectLifetimeDefault::Specific(r)) =>
r.user_string(tcx),
d =>
- d.repr(ccx.tcx()),
+ d.repr(ccx.tcx),
})
.collect::<Vec<String>>()
.connect(",");
}
fn type_scheme_of_foreign_item<'a, 'tcx>(
- ccx: &CollectCtxt<'a, 'tcx>,
+ ccx: &CrateCtxt<'a, 'tcx>,
it: &ast::ForeignItem,
abi: abi::Abi)
-> ty::TypeScheme<'tcx>
{
- memoized(&ccx.tcx().tcache,
+ memoized(&ccx.tcx.tcache,
local_def(it.id),
|_| compute_type_scheme_of_foreign_item(ccx, it, abi))
}
fn compute_type_scheme_of_foreign_item<'a, 'tcx>(
- ccx: &CollectCtxt<'a, 'tcx>,
+ ccx: &CrateCtxt<'a, 'tcx>,
it: &ast::ForeignItem,
abi: abi::Abi)
-> ty::TypeScheme<'tcx>
ast::ForeignItemStatic(ref t, _) => {
ty::TypeScheme {
generics: ty::Generics::empty(),
- ty: ast_ty_to_ty(ccx, &ExplicitRscope, t)
+ ty: ast_ty_to_ty(&ccx.icx(&()), &ExplicitRscope, t)
}
}
}
}
-fn convert_foreign_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
it: &ast::ForeignItem)
{
// For reasons I cannot fully articulate, I do so hate the AST
let predicates = match it.node {
ast::ForeignItemFn(_, ref generics) => {
- ty_generic_bounds_for_fn_or_method(ccx,
- generics,
- &scheme.generics,
- ty::GenericPredicates::empty())
+ ty_generic_predicates_for_fn(ccx, generics, &ty::GenericPredicates::empty())
}
ast::ForeignItemStatic(..) => {
ty::GenericPredicates::empty()
assert!(prev_predicates.is_none());
}
-fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
generics: &ast::Generics)
-> ty::Generics<'tcx> {
- ty_generics(ccx,
- subst::TypeSpace,
- &generics.lifetimes,
- &generics.ty_params,
- &generics.where_clause,
- ty::Generics::empty())
+ ty_generics(ccx, TypeSpace, generics, &ty::Generics::empty())
}
-fn ty_generic_bounds_for_type_or_impl<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
- ty_generics: &ty::Generics<'tcx>,
- generics: &ast::Generics)
- -> ty::GenericPredicates<'tcx>
+fn ty_generic_predicates_for_type_or_impl<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
+ generics: &ast::Generics)
+ -> ty::GenericPredicates<'tcx>
{
- ty_generic_bounds(ccx,
- subst::TypeSpace,
- ty_generics,
- ty::GenericPredicates::empty(),
- &generics.where_clause)
+ ty_generic_predicates(ccx, TypeSpace, generics, &ty::GenericPredicates::empty())
}
-fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
trait_id: ast::NodeId,
- substs: &'tcx subst::Substs<'tcx>,
+ substs: &'tcx Substs<'tcx>,
ast_generics: &ast::Generics)
-> ty::Generics<'tcx>
{
debug!("ty_generics_for_trait(trait_id={}, substs={})",
local_def(trait_id).repr(ccx.tcx), substs.repr(ccx.tcx));
- let mut generics =
- ty_generics(ccx,
- subst::TypeSpace,
- &ast_generics.lifetimes,
- &ast_generics.ty_params,
- &ast_generics.where_clause,
- ty::Generics::empty());
+ let mut generics = ty_generics_for_type_or_impl(ccx, ast_generics);
// Add in the self type parameter.
//
// the node id for the Self type parameter.
let param_id = trait_id;
- let self_trait_ref =
- Rc::new(ty::TraitRef { def_id: local_def(trait_id),
- substs: substs });
-
let def = ty::TypeParameterDef {
- space: subst::SelfSpace,
+ space: SelfSpace,
index: 0,
name: special_idents::type_self.name,
def_id: local_def(param_id),
- bounds: ty::ParamBounds {
- region_bounds: vec!(),
- builtin_bounds: ty::empty_builtin_bounds(),
- trait_bounds: vec!(ty::Binder(self_trait_ref.clone())),
- projection_bounds: vec!(),
- },
default: None,
object_lifetime_default: None,
};
ccx.tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone());
- generics.types.push(subst::SelfSpace, def);
+ generics.types.push(SelfSpace, def);
return generics;
}
-fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
- generics: &ast::Generics,
- base_generics: ty::Generics<'tcx>)
- -> ty::Generics<'tcx>
+fn ty_generics_for_fn<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
+ generics: &ast::Generics,
+ base_generics: &ty::Generics<'tcx>)
+ -> ty::Generics<'tcx>
{
- let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics);
- ty_generics(ccx,
- subst::FnSpace,
- &early_lifetimes[..],
- &generics.ty_params,
- &generics.where_clause,
- base_generics)
+ ty_generics(ccx, FnSpace, generics, base_generics)
}
-fn ty_generic_bounds_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
- generics: &ast::Generics,
- ty_generics: &ty::Generics<'tcx>,
- base: ty::GenericPredicates<'tcx>)
- -> ty::GenericPredicates<'tcx>
+fn ty_generic_predicates_for_fn<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
+ generics: &ast::Generics,
+ base_predicates: &ty::GenericPredicates<'tcx>)
+ -> ty::GenericPredicates<'tcx>
{
- ty_generic_bounds(ccx,
- subst::FnSpace,
- ty_generics,
- base,
- &generics.where_clause)
+ ty_generic_predicates(ccx, FnSpace, generics, base_predicates)
}
// Add the Sized bound, unless the type parameter is marked as `?Sized`.
-fn add_unsized_bound<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
- bounds: &mut ty::BuiltinBounds,
- ast_bounds: &[ast::TyParamBound],
- span: Span)
+fn add_unsized_bound<'tcx>(astconv: &AstConv<'tcx>,
+ bounds: &mut ty::BuiltinBounds,
+ ast_bounds: &[ast::TyParamBound],
+ span: Span)
{
+ let tcx = astconv.tcx();
+
// Try to find an unbound in bounds.
let mut unbound = None;
for ab in ast_bounds {
assert!(ptr.bound_lifetimes.is_empty());
unbound = Some(ptr.trait_ref.clone());
} else {
- span_err!(ccx.tcx.sess, span, E0203,
+ span_err!(tcx.sess, span, E0203,
"type parameter has more than one relaxed default \
bound, only one is supported");
}
}
}
- let kind_id = ccx.tcx.lang_items.require(SizedTraitLangItem);
+ let kind_id = tcx.lang_items.require(SizedTraitLangItem);
match unbound {
Some(ref tpb) => {
// FIXME(#8559) currently requires the unbound to be built-in.
- let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, tpb);
+ let trait_def_id = ty::trait_ref_to_def_id(tcx, tpb);
match kind_id {
Ok(kind_id) if trait_def_id != kind_id => {
- ccx.tcx.sess.span_warn(span,
- "default bound relaxed for a type parameter, but \
- this does nothing because the given bound is not \
- a default. Only `?Sized` is supported");
- ty::try_add_builtin_trait(ccx.tcx,
- kind_id,
- bounds);
+ tcx.sess.span_warn(span,
+ "default bound relaxed for a type parameter, but \
+ this does nothing because the given bound is not \
+ a default. Only `?Sized` is supported");
+ ty::try_add_builtin_trait(tcx, kind_id, bounds);
}
_ => {}
}
}
_ if kind_id.is_ok() => {
- ty::try_add_builtin_trait(ccx.tcx, kind_id.unwrap(), bounds);
+ ty::try_add_builtin_trait(tcx, kind_id.unwrap(), bounds);
}
// No lang item for Sized, so we can't add it as a bound.
None => {}
}
}
-fn ty_generic_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
- space: subst::ParamSpace,
- generics: &ty::Generics<'tcx>,
- base: ty::GenericPredicates<'tcx>,
- where_clause: &ast::WhereClause)
- -> ty::GenericPredicates<'tcx>
+/// Returns the early-bound lifetimes declared in this generics
+/// listing. For anything other than fns/methods, this is just all
+/// the lifetimes that are declared. For fns or methods, we have to
+/// screen out those that do not appear in any where-clauses etc using
+/// `resolve_lifetime::early_bound_lifetimes`.
+fn early_bound_lifetimes_from_generics(space: ParamSpace,
+ ast_generics: &ast::Generics)
+ -> Vec<ast::LifetimeDef>
+{
+ match space {
+ SelfSpace | TypeSpace => ast_generics.lifetimes.to_vec(),
+ FnSpace => resolve_lifetime::early_bound_lifetimes(ast_generics),
+ }
+}
+
+fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
+ space: ParamSpace,
+ ast_generics: &ast::Generics,
+ base_predicates: &ty::GenericPredicates<'tcx>)
+ -> ty::GenericPredicates<'tcx>
{
let tcx = ccx.tcx;
- let mut result = base;
-
- // For now, scrape the bounds out of parameters from Generics. This is not great.
- for def in generics.regions.get_slice(space) {
- let r_a = def.to_early_bound_region();
- for &r_b in &def.bounds {
- let outlives = ty::Binder(ty::OutlivesPredicate(r_a, r_b));
- result.predicates.push(def.space, ty::Predicate::RegionOutlives(outlives));
- }
+ let mut result = base_predicates.clone();
+
+ // Collect the predicates that were written inline by the user on each
+ // type parameter (e.g., `<T:Foo>`).
+ for (index, param) in ast_generics.ty_params.iter().enumerate() {
+ let index = index as u32;
+ let param_ty = ty::ParamTy::new(space, index, param.ident.name).to_ty(ccx.tcx);
+ let bounds = compute_bounds(&ccx.icx(&(base_predicates, ast_generics)),
+ param_ty,
+ ¶m.bounds,
+ SizedByDefault::Yes,
+ param.span);
+ let predicates = ty::predicates(ccx.tcx, param_ty, &bounds);
+ result.predicates.extend(space, predicates.into_iter());
}
- for def in generics.types.get_slice(space) {
- let t = ty::mk_param_from_def(ccx.tcx, def);
- result.predicates.extend(def.space, ty::predicates(ccx.tcx, t, &def.bounds).into_iter());
+
+ // Collect the region predicates that were declared inline as
+ // well. In the case of parameters declared on a fn or method, we
+ // have to be careful to only iterate over early-bound regions.
+ let early_lifetimes = early_bound_lifetimes_from_generics(space, ast_generics);
+ for (index, param) in early_lifetimes.iter().enumerate() {
+ let index = index as u32;
+ let region = ty::ReEarlyBound(param.lifetime.id, space, index, param.lifetime.name);
+ for bound in ¶m.bounds {
+ let bound_region = ast_region_to_region(ccx.tcx, bound);
+ let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region));
+ result.predicates.push(space, outlives.as_predicate());
+ }
}
- // Add the bounds not associated with a type parameter
+ // Add in the bounds that appear in the where-clause
+ let where_clause = &ast_generics.where_clause;
for predicate in &where_clause.predicates {
match predicate {
&ast::WherePredicate::BoundPredicate(ref bound_pred) => {
- let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &*bound_pred.bounded_ty);
+ let ty = ast_ty_to_ty(&ccx.icx(&(base_predicates, ast_generics)),
+ &ExplicitRscope,
+ &*bound_pred.bounded_ty);
for bound in &*bound_pred.bounds {
match bound {
&ast::TyParamBound::TraitTyParamBound(ref poly_trait_ref, _) => {
let mut projections = Vec::new();
- let trait_ref = astconv::instantiate_poly_trait_ref(
- ccx,
- &ExplicitRscope,
- poly_trait_ref,
- Some(ty),
- &mut projections,
- );
+ let trait_ref =
+ conv_poly_trait_ref(&ccx.icx(&(base_predicates, ast_generics)),
+ ty,
+ poly_trait_ref,
+ &mut projections);
result.predicates.push(space, trait_ref.as_predicate());
return result;
}
-fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
- space: subst::ParamSpace,
- lifetime_defs: &[ast::LifetimeDef],
- types: &[ast::TyParam],
- where_clause: &ast::WhereClause,
- base_generics: ty::Generics<'tcx>)
+fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
+ space: ParamSpace,
+ ast_generics: &ast::Generics,
+ base_generics: &ty::Generics<'tcx>)
-> ty::Generics<'tcx>
{
let tcx = ccx.tcx;
- let mut result = base_generics;
+ let mut result = base_generics.clone();
- for (i, l) in lifetime_defs.iter().enumerate() {
+ let early_lifetimes = early_bound_lifetimes_from_generics(space, ast_generics);
+ for (i, l) in early_lifetimes.iter().enumerate() {
let bounds = l.bounds.iter()
.map(|l| ast_region_to_region(tcx, l))
.collect();
index: i as u32,
def_id: local_def(l.lifetime.id),
bounds: bounds };
- // debug!("ty_generics: def for region param: {:?}",
- // def.repr(tcx));
result.regions.push(space, def);
}
assert!(result.types.is_empty_in(space));
// Now create the real type parameters.
- for (i, param) in types.iter().enumerate() {
- let def = get_or_create_type_parameter_def(ccx, space, param, i as u32, where_clause);
+ for i in 0..ast_generics.ty_params.len() {
+ let def = get_or_create_type_parameter_def(ccx, ast_generics, space, i as u32);
debug!("ty_generics: def for type param: {:?}, {:?}", def, space);
result.types.push(space, def);
}
result
}
-fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
- space: subst::ParamSpace,
- param: &ast::TyParam,
- index: u32,
- where_clause: &ast::WhereClause)
+fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
+ ast_generics: &ast::Generics,
+ space: ParamSpace,
+ index: u32)
-> ty::TypeParameterDef<'tcx>
{
+ let param = &ast_generics.ty_params[index as usize];
+
let tcx = ccx.tcx;
match tcx.ty_param_defs.borrow().get(¶m.id) {
Some(d) => { return d.clone(); }
None => { }
}
- let param_ty = ty::ParamTy::new(space, index, param.ident.name);
- let bounds = compute_bounds(ccx,
- param_ty.to_ty(ccx.tcx),
- ¶m.bounds,
- SizedByDefault::Yes,
- param.span);
let default = match param.default {
None => None,
Some(ref path) => {
- let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &**path);
+ let ty = ast_ty_to_ty(&ccx.icx(&()), &ExplicitRscope, &**path);
let cur_idx = index;
ty::walk_ty(ty, |t| {
};
let object_lifetime_default =
- compute_object_lifetime_default(ccx, space, index, ¶m.bounds, where_clause);
+ compute_object_lifetime_default(ccx, param.id,
+ ¶m.bounds, &ast_generics.where_clause);
let def = ty::TypeParameterDef {
space: space,
index: index,
name: param.ident.name,
def_id: local_def(param.id),
- bounds: bounds,
default: default,
object_lifetime_default: object_lifetime_default,
};
/// intentionally avoid just asking astconv to convert all the where
/// clauses into a `ty::Predicate`. This is because that could induce
/// artificial cycles.
-fn compute_object_lifetime_default<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
- space: subst::ParamSpace,
- index: u32,
+fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
+ param_id: ast::NodeId,
param_bounds: &[ast::TyParamBound],
where_clause: &ast::WhereClause)
-> Option<ty::ObjectLifetimeDefault>
{
let inline_bounds = from_bounds(ccx, param_bounds);
- let where_bounds = from_predicates(ccx, space, index, &where_clause.predicates);
+ let where_bounds = from_predicates(ccx, param_id, &where_clause.predicates);
let all_bounds: HashSet<_> = inline_bounds.into_iter()
.chain(where_bounds.into_iter())
.collect();
.map(ty::ObjectLifetimeDefault::Specific)
};
- fn from_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
+ fn from_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
bounds: &[ast::TyParamBound])
-> Vec<ty::Region>
{
ast::TraitTyParamBound(..) =>
None,
ast::RegionTyParamBound(ref lifetime) =>
- Some(astconv::ast_region_to_region(ccx.tcx(), lifetime)),
+ Some(astconv::ast_region_to_region(ccx.tcx, lifetime)),
}
})
.collect()
}
- fn from_predicates<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
- space: subst::ParamSpace,
- index: u32,
+ fn from_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
+ param_id: ast::NodeId,
predicates: &[ast::WherePredicate])
-> Vec<ty::Region>
{
match *predicate {
ast::WherePredicate::BoundPredicate(ref data) => {
if data.bound_lifetimes.len() == 0 &&
- is_param(ccx, &data.bounded_ty, space, index)
+ is_param(ccx.tcx, &data.bounded_ty, param_id)
{
from_bounds(ccx, &data.bounds).into_iter()
} else {
})
.collect()
}
-
- fn is_param(ccx: &CollectCtxt,
- ast_ty: &ast::Ty,
- space: subst::ParamSpace,
- index: u32)
- -> bool
- {
- match ast_ty.node {
- ast::TyPath(_, id) => {
- match ccx.tcx.def_map.borrow()[id] {
- def::DefTyParam(s, i, _, _) => {
- space == s && index == i
- }
- _ => {
- false
- }
- }
- }
- _ => {
- false
- }
- }
- }
}
enum SizedByDefault { Yes, No }
/// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or
/// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the
/// built-in trait (formerly known as kind): Send.
-fn compute_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
- param_ty: ty::Ty<'tcx>,
- ast_bounds: &[ast::TyParamBound],
- sized_by_default: SizedByDefault,
- span: Span)
- -> ty::ParamBounds<'tcx>
+fn compute_bounds<'tcx>(astconv: &AstConv<'tcx>,
+ param_ty: ty::Ty<'tcx>,
+ ast_bounds: &[ast::TyParamBound],
+ sized_by_default: SizedByDefault,
+ span: Span)
+ -> ty::ParamBounds<'tcx>
{
- let mut param_bounds = conv_param_bounds(ccx,
+ let mut param_bounds = conv_param_bounds(astconv,
span,
param_ty,
ast_bounds);
if let SizedByDefault::Yes = sized_by_default {
- add_unsized_bound(ccx,
+ add_unsized_bound(astconv,
&mut param_bounds.builtin_bounds,
ast_bounds,
span);
- check_bounds_compatible(ccx,
+ check_bounds_compatible(astconv,
param_ty,
¶m_bounds,
span);
param_bounds
}
-fn check_bounds_compatible<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
- param_ty: Ty<'tcx>,
- param_bounds: &ty::ParamBounds<'tcx>,
- span: Span) {
+fn check_bounds_compatible<'tcx>(astconv: &AstConv<'tcx>,
+ param_ty: Ty<'tcx>,
+ param_bounds: &ty::ParamBounds<'tcx>,
+ span: Span) {
+ let tcx = astconv.tcx();
if !param_bounds.builtin_bounds.contains(&ty::BoundSized) {
ty::each_bound_trait_and_supertraits(
- ccx.tcx,
+ tcx,
¶m_bounds.trait_bounds,
|trait_ref| {
- let trait_def = ccx.get_trait_def(trait_ref.def_id());
- if trait_def.bounds.builtin_bounds.contains(&ty::BoundSized) {
- span_err!(ccx.tcx.sess, span, E0129,
- "incompatible bounds on `{}`, \
- bound `{}` does not allow unsized type",
- param_ty.user_string(ccx.tcx),
- trait_ref.user_string(ccx.tcx));
+ match astconv.get_trait_def(span, trait_ref.def_id()) {
+ Ok(trait_def) => {
+ if trait_def.bounds.builtin_bounds.contains(&ty::BoundSized) {
+ span_err!(tcx.sess, span, E0129,
+ "incompatible bounds on `{}`, \
+ bound `{}` does not allow unsized type",
+ param_ty.user_string(tcx),
+ trait_ref.user_string(tcx));
+ }
+ }
+ Err(ErrorReported) => { }
}
true
});
}
}
-fn conv_param_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
+/// Converts a specific TyParamBound from the AST into the
+/// appropriate poly-trait-reference.
+fn poly_trait_ref_from_bound<'tcx>(astconv: &AstConv<'tcx>,
+ param_ty: Ty<'tcx>,
+ bound: &ast::TyParamBound,
+ projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
+ -> Option<ty::PolyTraitRef<'tcx>>
+{
+ match *bound {
+ ast::TraitTyParamBound(ref tr, ast::TraitBoundModifier::None) => {
+ Some(conv_poly_trait_ref(astconv, param_ty, tr, projections))
+ }
+ ast::TraitTyParamBound(_, ast::TraitBoundModifier::Maybe) |
+ ast::RegionTyParamBound(_) => {
+ None
+ }
+ }
+}
+
+fn conv_poly_trait_ref<'tcx>(astconv: &AstConv<'tcx>,
+ param_ty: Ty<'tcx>,
+ trait_ref: &ast::PolyTraitRef,
+ projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
+ -> ty::PolyTraitRef<'tcx>
+{
+ astconv::instantiate_poly_trait_ref(astconv,
+ &ExplicitRscope,
+ trait_ref,
+ Some(param_ty),
+ projections)
+}
+
+fn conv_param_bounds<'a,'tcx>(astconv: &AstConv<'tcx>,
span: Span,
param_ty: ty::Ty<'tcx>,
ast_bounds: &[ast::TyParamBound])
-> ty::ParamBounds<'tcx>
{
- let tcx = ccx.tcx;
+ let tcx = astconv.tcx();
let astconv::PartitionedBounds {
builtin_bounds,
trait_bounds,
let mut projection_bounds = Vec::new();
let trait_bounds: Vec<ty::PolyTraitRef> =
- trait_bounds.into_iter()
- .map(|bound| {
- astconv::instantiate_poly_trait_ref(ccx,
- &ExplicitRscope,
- bound,
- Some(param_ty),
- &mut projection_bounds)
- })
- .collect();
+ trait_bounds.iter()
+ .map(|bound| conv_poly_trait_ref(astconv,
+ param_ty,
+ *bound,
+ &mut projection_bounds))
+ .collect();
let region_bounds: Vec<ty::Region> =
region_bounds.into_iter()
- .map(|r| ast_region_to_region(ccx.tcx, r))
+ .map(|r| ast_region_to_region(tcx, r))
.collect();
ty::ParamBounds {
}
fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>(
- ccx: &CollectCtxt<'a, 'tcx>,
+ ccx: &CrateCtxt<'a, 'tcx>,
decl: &ast::FnDecl,
ast_generics: &ast::Generics,
abi: abi::Abi)
}
}
- let ty_generics = ty_generics_for_fn_or_method(ccx, ast_generics, ty::Generics::empty());
+ let ty_generics = ty_generics_for_fn(ccx, ast_generics, &ty::Generics::empty());
let rb = BindingRscope::new();
let input_tys = decl.inputs
.iter()
- .map(|a| ty_of_arg(ccx, &rb, a, None))
+ .map(|a| ty_of_arg(&ccx.icx(ast_generics), &rb, a, None))
.collect();
let output = match decl.output {
ast::Return(ref ty) =>
- ty::FnConverging(ast_ty_to_ty(ccx, &rb, &**ty)),
+ ty::FnConverging(ast_ty_to_ty(&ccx.icx(ast_generics), &rb, &**ty)),
ast::DefaultReturn(..) =>
ty::FnConverging(ty::mk_nil(ccx.tcx)),
ast::NoReturn(..) =>
}
}
-fn mk_item_substs<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
ty_generics: &ty::Generics<'tcx>)
- -> subst::Substs<'tcx>
+ -> Substs<'tcx>
{
let types =
ty_generics.types.map(
ty_generics.regions.map(
|def| def.to_early_bound_region());
- subst::Substs::new(types, regions)
+ Substs::new(types, regions)
}
/// Verifies that the explicit self type of a method matches the impl
/// comes back to check after the fact that explicit type the user
/// wrote actually matches what the pre-defined option said.
fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
- ccx: &CollectCtxt<'a, 'tcx>,
+ ccx: &CrateCtxt<'a, 'tcx>,
rs: &RS,
+ method_type: Rc<ty::Method<'tcx>>,
required_type: Ty<'tcx>,
explicit_self: &ast::ExplicitSelf,
body_id: ast::NodeId)
{
let tcx = ccx.tcx;
if let ast::SelfExplicit(ref ast_type, _) = explicit_self.node {
- let typ = ccx.to_ty(rs, &**ast_type);
+ let typ = ccx.icx(&method_type.predicates).to_ty(rs, &**ast_type);
let base_type = match typ.sty {
ty::ty_ptr(tm) | ty::ty_rptr(_, tm) => tm.ty,
ty::ty_uniq(typ) => typ,
E0120,
E0121,
E0122,
+ E0123,
E0124,
E0127,
E0128,
tcx.item_substs.borrow_mut().insert(node_id, item_substs);
}
}
-fn lookup_def_tcx(tcx:&ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def {
+
+fn lookup_full_def(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def {
match tcx.def_map.borrow().get(&id) {
- Some(x) => x.clone(),
- _ => {
+ Some(x) => x.full_def(),
+ None => {
span_fatal!(tcx.sess, sp, E0242, "internal error looking up a definition")
}
}
}
-fn lookup_def_ccx(ccx: &CrateCtxt, sp: Span, id: ast::NodeId)
- -> def::Def {
- lookup_def_tcx(ccx.tcx, sp, id)
-}
-
fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>,
maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>,
t1_is_expected: bool,
//! failure, but rather because the target type `Foo<Y>` is itself just
//! not well-formed. Basically we get to assume well-formedness of all
//! types involved before considering variance.
+//!
+//! ### Associated types
+//!
+//! Any trait with an associated type is invariant with respect to all
+//! of its inputs. To see why this makes sense, consider what
+//! subtyping for a trait reference means:
+//!
+//! <T as Trait> <: <U as Trait>
+//!
+//! means that if I know that `T as Trait`,
+//! I also know that `U as
+//! Trait`. Moreover, if you think of it as
+//! dictionary passing style, it means that
+//! a dictionary for `<T as Trait>` is safe
+//! to use where a dictionary for `<U as
+//! Trait>` is expected.
+//!
+//! The problem is that when you can
+//! project types out from `<T as Trait>`,
+//! the relationship to types projected out
+//! of `<U as Trait>` is completely unknown
+//! unless `T==U` (see #21726 for more
+//! details). Making `Trait` invariant
+//! ensures that this is true.
+//!
+//! *Historical note: we used to preserve this invariant another way,
+//! by tweaking the subtyping rules and requiring that when a type `T`
+//! appeared as part of a projection, that was considered an invariant
+//! location, but this version does away with the need for those
+//! somewhat "special-case-feeling" rules.*
+//!
+//! Another related reason is that if we didn't make traits with
+//! associated types invariant, then projection is no longer a
+//! function with a single result. Consider:
+//!
+//! ```
+//! trait Identity { type Out; fn foo(&self); }
+//! impl<T> Identity for T { type Out = T; ... }
+//! ```
+//!
+//! Now if I have `<&'static () as Identity>::Out`, this can be
+//! validly derived as `&'a ()` for any `'a`:
+//!
+//! <&'a () as Identity> <: <&'static () as Identity>
+//! if &'static () < : &'a () -- Identity is contravariant in Self
+//! if 'static : 'a -- Subtyping rules for relations
+//!
+//! This change otoh means that `<'static () as Identity>::Out` is
+//! always `&'static ()` (which might then be upcast to `'a ()`,
+//! separately). This was helpful in solving #21750.
use self::VarianceTerm::*;
use self::ParamKind::*;
&method.fty.sig,
self.covariant);
}
- ty::TypeTraitItem(_) => {}
+ ty::TypeTraitItem(ref data) => {
+ // Any trait with an associated type is
+ // invariant with respect to all of its
+ // inputs. See length discussion in the comment
+ // on this module.
+ let projection_ty = ty::mk_projection(tcx,
+ trait_def.trait_ref.clone(),
+ data.name);
+ self.add_constraints_from_ty(&trait_def.generics,
+ projection_ty,
+ self.invariant);
+ }
}
}
}
trait_def.generics.types.as_slice(),
trait_def.generics.regions.as_slice(),
trait_ref.substs,
- self.invariant);
+ variance);
}
ty::ty_trait(ref data) => {
None => return None,
};
let def = match tcx.def_map.borrow().get(&id) {
- Some(def) => *def,
+ Some(d) => d.full_def(),
None => return None,
};
let did = def.def_id();
let mut ret = Vec::new();
let did = def.def_id();
let inner = match def {
- def::DefaultImpl(did) => {
+ def::DefTrait(did) => {
record_extern_fqn(cx, did, clean::TypeTrait);
clean::TraitItem(build_external_trait(cx, tcx, did))
}
fn clean(&self, cx: &DocContext) -> TyParam {
cx.external_typarams.borrow_mut().as_mut().unwrap()
.insert(self.def_id, self.name.clean(cx));
- let bounds = self.bounds.clean(cx);
TyParam {
name: self.name.clean(cx),
did: self.def_id,
- bounds: bounds,
+ bounds: vec![], // these are filled in from the where-clauses
default: self.default.clean(cx),
}
}
// Bounds in the type_params and lifetimes fields are repeated in the predicates
// field (see rustc_typeck::collect::ty_generics), so remove them.
let stripped_typarams = gens.types.get_slice(space).iter().map(|tp| {
- let mut stp = tp.clone();
- stp.bounds = ty::ParamBounds::empty();
- stp.clean(cx)
+ tp.clean(cx)
}).collect::<Vec<_>>();
let stripped_lifetimes = gens.regions.get_slice(space).iter().map(|rp| {
let mut srp = rp.clone();
typarams: Option<Vec<TyParamBound>>,
did: ast::DefId,
},
- // I have no idea how to usefully use this.
- TyParamBinder(ast::NodeId),
/// For parameterized types, so the consumer of the JSON don't go
/// looking for types which don't exist anywhere.
Generic(String),
TyFixedLengthVec(ref ty, ref e) => FixedVector(box ty.clean(cx),
e.span.to_src(cx)),
TyTup(ref tys) => Tuple(tys.clean(cx)),
- TyPath(ref p, id) => {
- resolve_type(cx, p.clean(cx), id)
+ TyPath(None, ref p) => {
+ resolve_type(cx, p.clean(cx), self.id)
+ }
+ TyPath(Some(ref qself), ref p) => {
+ let mut trait_path = p.clone();
+ trait_path.segments.pop();
+ Type::QPath {
+ name: p.segments.last().unwrap().identifier.clean(cx),
+ self_type: box qself.ty.clean(cx),
+ trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
+ }
}
TyObjectSum(ref lhs, ref bounds) => {
let lhs_ty = lhs.clean(cx);
}
TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
TyParen(ref ty) => ty.clean(cx),
- TyQPath(ref qp) => qp.clean(cx),
TyPolyTraitRef(ref bounds) => {
PolyTraitRef(bounds.clean(cx))
},
}
}
-impl Clean<Type> for ast::QPath {
- fn clean(&self, cx: &DocContext) -> Type {
- Type::QPath {
- name: self.item_path.identifier.clean(cx),
- self_type: box self.self_type.clean(cx),
- trait_: box self.trait_ref.clean(cx)
- }
- }
-}
-
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub enum StructField {
HiddenStructField, // inserted later by strip passes
};
debug!("searching for {} in defmap", id);
let def = match tcx.def_map.borrow().get(&id) {
- Some(&k) => k,
+ Some(k) => k.full_def(),
None => panic!("unresolved id not in defmap")
};
ast::TyFloat(ast::TyF64) => return Primitive(F64),
},
def::DefTyParam(_, _, _, n) => return Generic(token::get_name(n).to_string()),
- def::DefTyParamBinder(i) => return TyParamBinder(i),
_ => {}
};
let did = register_def(&*cx, def);
def::DefFn(i, _) => (i, TypeFunction),
def::DefTy(i, false) => (i, TypeTypedef),
def::DefTy(i, true) => (i, TypeEnum),
- def::DefaultImpl(i) => (i, TypeTrait),
+ def::DefTrait(i) => (i, TypeTrait),
def::DefStruct(i) => (i, TypeStruct),
def::DefMod(i) => (i, TypeModule),
def::DefStatic(i, _) => (i, TypeStatic),
fn resolve_def(cx: &DocContext, id: ast::NodeId) -> Option<ast::DefId> {
cx.tcx_opt().and_then(|tcx| {
- tcx.def_map.borrow().get(&id).map(|&def| register_def(cx, def))
+ tcx.def_map.borrow().get(&id).map(|d| register_def(cx, d.full_def()))
})
}
impl fmt::Display for clean::Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
- clean::TyParamBinder(id) => {
- f.write_str(&cache().typarams[ast_util::local_def(id)])
- }
clean::Generic(ref name) => {
f.write_str(name)
}
use std::dynamic_lib::DynamicLibrary;
use std::old_io::{Command, TempDir};
use std::old_io;
-use std::env;
+use std::os;
use std::str;
use std::thread;
use std::thunk::Thunk;
let input = config::Input::File(input_path.clone());
let sessopts = config::Options {
- maybe_sysroot: Some(env::current_exe().unwrap().dir_path().dir_path()),
+ maybe_sysroot: Some(os::self_exe_name().unwrap().dir_path().dir_path()),
search_paths: libs.clone(),
crate_types: vec!(config::CrateTypeDylib),
externs: externs.clone(),
let input = config::Input::Str(test.to_string());
let sessopts = config::Options {
- maybe_sysroot: Some(env::current_exe().unwrap().dir_path().dir_path()),
+ maybe_sysroot: Some(os::self_exe_name().unwrap().dir_path().dir_path()),
search_paths: libs,
crate_types: vec!(config::CrateTypeExecutable),
output_types: vec!(config::OutputTypeExe),
Some(tcx) => tcx,
None => return false
};
- let def = (*tcx.def_map.borrow())[id].def_id();
+ let def = tcx.def_map.borrow()[id].def_id();
if !ast_util::is_local(def) { return false }
let analysis = match self.analysis {
Some(analysis) => analysis, None => return false
#[test]
fn test_decode_array() {
let v: Vec<()> = super::decode("[]").unwrap();
- assert_eq!(v, vec![]);
+ assert_eq!(v, []);
let v: Vec<()> = super::decode("[null]").unwrap();
- assert_eq!(v, vec![()]);
+ assert_eq!(v, [()]);
let v: Vec<bool> = super::decode("[true]").unwrap();
- assert_eq!(v, vec![true]);
+ assert_eq!(v, [true]);
let v: Vec<int> = super::decode("[3, 1]").unwrap();
- assert_eq!(v, vec![3, 1]);
+ assert_eq!(v, [3, 1]);
let v: Vec<Vec<uint>> = super::decode("[[3], [1, 2]]").unwrap();
- assert_eq!(v, vec![vec![3], vec![1, 2]]);
+ assert_eq!(v, [vec![3], vec![1, 2]]);
}
#[test]
where K: Eq + Hash + Debug, V: Debug, S: HashState
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- try!(write!(f, "HashMap {{"));
+ try!(write!(f, "{{"));
for (i, (k, v)) in self.iter().enumerate() {
if i != 0 { try!(write!(f, ", ")); }
let map_str = format!("{:?}", map);
- assert!(map_str == "HashMap {1: 2, 3: 4}" ||
- map_str == "HashMap {3: 4, 1: 2}");
- assert_eq!(format!("{:?}", empty), "HashMap {}");
+ assert!(map_str == "{1: 2, 3: 4}" ||
+ map_str == "{3: 4, 1: 2}");
+ assert_eq!(format!("{:?}", empty), "{}");
}
#[test]
S: HashState
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- try!(write!(f, "HashSet {{"));
+ try!(write!(f, "{{"));
for (i, x) in self.iter().enumerate() {
if i != 0 { try!(write!(f, ", ")); }
let set_str = format!("{:?}", set);
- assert!(set_str == "HashSet {1, 2}" || set_str == "HashSet {2, 1}");
- assert_eq!(format!("{:?}", empty), "HashSet {}");
+ assert!(set_str == "{1, 2}" || set_str == "{2, 1}");
+ assert_eq!(format!("{:?}", empty), "{}");
}
#[test]
use ops::{Deref, DerefMut, Drop};
use option::Option;
use option::Option::{Some, None};
-use ptr::{self, PtrExt, copy_nonoverlapping_memory, Unique, zero_memory};
+use ptr::{self, PtrExt, Unique};
use rt::heap::{allocate, deallocate, EMPTY};
use collections::hash_state::HashState;
pub fn shift(mut self) -> Option<GapThenFull<K, V, M>> {
unsafe {
*self.gap.raw.hash = mem::replace(&mut *self.full.raw.hash, EMPTY_BUCKET);
- copy_nonoverlapping_memory(self.gap.raw.key, self.full.raw.key, 1);
- copy_nonoverlapping_memory(self.gap.raw.val, self.full.raw.val, 1);
+ ptr::copy_nonoverlapping(self.gap.raw.key, self.full.raw.key, 1);
+ ptr::copy_nonoverlapping(self.gap.raw.val, self.full.raw.val, 1);
}
let FullBucket { raw: prev_raw, idx: prev_idx, .. } = self.full;
pub fn new(capacity: usize) -> RawTable<K, V> {
unsafe {
let ret = RawTable::new_uninitialized(capacity);
- zero_memory(*ret.hashes, capacity);
+ ptr::write_bytes(*ret.hashes, 0, capacity);
ret
}
}
use mem;
use env;
use str;
+use os;
pub struct DynamicLibrary {
handle: *mut u8
/// process
pub fn search_path() -> Vec<Path> {
match env::var_os(DynamicLibrary::envvar()) {
- Some(var) => env::split_paths(&var).collect(),
+ Some(var) => os::split_paths(var.to_str().unwrap()),
None => Vec::new(),
}
}
use error::Error;
use ffi::{OsString, AsOsStr};
use fmt;
-use old_io::IoResult;
+use io;
+use path::{AsPath, PathBuf};
use sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT, Ordering};
use sync::{StaticMutex, MUTEX_INIT};
use sys::os as os_imp;
/// let p = env::current_dir().unwrap();
/// println!("The current directory is {}", p.display());
/// ```
-pub fn current_dir() -> IoResult<Path> {
+pub fn current_dir() -> io::Result<PathBuf> {
os_imp::getcwd()
}
///
/// ```rust
/// use std::env;
-/// use std::old_path::Path;
+/// use std::path::Path;
///
/// let root = Path::new("/");
/// assert!(env::set_current_dir(&root).is_ok());
/// println!("Successfully changed working directory to {}!", root.display());
/// ```
-pub fn set_current_dir(p: &Path) -> IoResult<()> {
- os_imp::chdir(p)
+pub fn set_current_dir<P: AsPath + ?Sized>(p: &P) -> io::Result<()> {
+ os_imp::chdir(p.as_path())
}
static ENV_LOCK: StaticMutex = MUTEX_INIT;
}
impl<'a> Iterator for SplitPaths<'a> {
- type Item = Path;
- fn next(&mut self) -> Option<Path> { self.inner.next() }
+ type Item = PathBuf;
+ fn next(&mut self) -> Option<PathBuf> { self.inner.next() }
fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
}
///
/// ```rust
/// use std::env;
+/// use std::path::PathBuf;
///
/// if let Some(path) = env::var_os("PATH") {
/// let mut paths = env::split_paths(&path).collect::<Vec<_>>();
-/// paths.push(Path::new("/home/xyz/bin"));
+/// paths.push(PathBuf::new("/home/xyz/bin"));
/// let new_path = env::join_paths(paths.iter()).unwrap();
/// env::set_var("PATH", &new_path);
/// }
/// None => println!("Impossible to get your home dir!")
/// }
/// ```
-pub fn home_dir() -> Option<Path> {
+pub fn home_dir() -> Option<PathBuf> {
os_imp::home_dir()
}
/// 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.
-pub fn temp_dir() -> Path {
+pub fn temp_dir() -> PathBuf {
os_imp::temp_dir()
}
/// Err(e) => println!("failed to get current exe path: {}", e),
/// };
/// ```
-pub fn current_exe() -> IoResult<Path> {
+pub fn current_exe() -> io::Result<PathBuf> {
os_imp::current_exe()
}
use iter::repeat;
use rand::{self, Rng};
use ffi::{OsString, OsStr};
+ use path::PathBuf;
fn make_rand_name() -> OsString {
let mut rng = rand::thread_rng();
fn split_paths_windows() {
fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
split_paths(unparsed).collect::<Vec<_>>() ==
- parsed.iter().map(|s| Path::new(*s)).collect::<Vec<_>>()
+ parsed.iter().map(|s| PathBuf::new(*s)).collect::<Vec<_>>()
}
assert!(check_parse("", &mut [""]));
fn split_paths_unix() {
fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
split_paths(unparsed).collect::<Vec<_>>() ==
- parsed.iter().map(|s| Path::new(*s)).collect::<Vec<_>>()
+ parsed.iter().map(|s| PathBuf::new(*s)).collect::<Vec<_>>()
}
assert!(check_parse("", &mut [""]));
+++ /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`.
-
-#![unstable(feature = "fs")]
-
-use core::prelude::*;
-
-use io::{self, Error, ErrorKind, SeekFrom, Seek, Read, Write};
-use path::{AsPath, 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.
-///
-/// # Example
-///
-/// ```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(())
-/// # }
-/// ```
-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.
-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.
-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.
-pub struct DirEntry(fs_imp::DirEntry);
-
-/// An iterator that recursively walks over the contents of a directory.
-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)]
-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)]
-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`.
- pub fn open<P: AsPath + ?Sized>(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.
- pub fn create<P: AsPath + ?Sized>(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.
- 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.
- 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`.
- 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.
- pub fn set_len(&self, size: u64) -> io::Result<()> {
- self.inner.truncate(size)
- }
-
- /// Queries information about the underlying file.
- 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 Read for File {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- self.inner.read(buf)
- }
-}
-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() }
-}
-impl Seek for File {
- fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
- self.inner.seek(pos)
- }
-}
-impl<'a> Read for &'a File {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- self.inner.read(buf)
- }
-}
-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() }
-}
-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`.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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)
- pub fn open<P: AsPath + ?Sized>(&self, path: &P) -> io::Result<File> {
- let path = path.as_path();
- let inner = try!(fs_imp::File::open(path, &self.0));
-
- // On *BSD systems, we can open a directory as a file and read from
- // it: fd=open("/tmp", O_RDONLY); read(fd, buf, N); due to an old
- // tradition before the introduction of opendir(3). We explicitly
- // reject it because there are few use cases.
- if cfg!(not(any(target_os = "linux", target_os = "android"))) &&
- try!(inner.file_attr()).is_dir() {
- Err(Error::new(ErrorKind::InvalidInput, "is a directory", None))
- } else {
- 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.
- pub fn is_dir(&self) -> bool { self.0.is_dir() }
-
- /// Returns whether this metadata is for a regular file.
- pub fn is_file(&self) -> bool { self.0.is_file() }
-
- /// Returns the size of the file, in bytes, this metadata is for.
- pub fn len(&self) -> u64 { self.0.size() }
-
- /// Returns the permissions of the file this metadata is for.
- 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.
- 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.
- pub fn modified(&self) -> u64 { self.0.modified() }
-}
-
-impl Permissions {
- /// Returns whether these permissions describe a readonly file.
- 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.
- 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 Iterator for ReadDir {
- type Item = io::Result<DirEntry>;
-
- fn next(&mut self) -> Option<io::Result<DirEntry>> {
- self.0.next().map(|entry| entry.map(DirEntry))
- }
-}
-
-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.
- pub fn path(&self) -> PathBuf { self.0.path() }
-}
-
-/// Remove a file from the underlying filesystem.
-///
-/// # Example
-///
-/// ```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.
-pub fn remove_file<P: AsPath + ?Sized>(path: &P) -> io::Result<()> {
- let path = path.as_path();
- let e = match fs_imp::unlink(path) {
- Ok(()) => return Ok(()),
- Err(e) => e,
- };
- if !cfg!(windows) { return Err(e) }
-
- // On unix, a readonly file can be successfully removed. On windows,
- // however, it cannot. To keep the two platforms in line with
- // respect to their behavior, catch this case on windows, attempt to
- // change it to read-write, and then remove the file.
- if e.kind() != ErrorKind::PermissionDenied { return Err(e) }
-
- let attr = match metadata(path) { Ok(a) => a, Err(..) => return Err(e) };
- let mut perms = attr.permissions();
- if !perms.readonly() { return Err(e) }
- perms.set_readonly(false);
-
- if set_permissions(path, perms).is_err() { return Err(e) }
- if fs_imp::unlink(path).is_ok() { return Ok(()) }
-
- // Oops, try to put things back the way we found it
- let _ = set_permissions(path, attr.permissions());
- Err(e)
-}
-
-/// 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.
-///
-/// # Example
-///
-/// ```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.
-pub fn metadata<P: AsPath + ?Sized>(path: &P) -> io::Result<Metadata> {
- fs_imp::stat(path.as_path()).map(Metadata)
-}
-
-/// Rename a file or directory to a new name.
-///
-/// # Example
-///
-/// ```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.
-pub fn rename<P: AsPath + ?Sized, Q: AsPath + ?Sized>(from: &P, to: &Q)
- -> io::Result<()> {
- fs_imp::rename(from.as_path(), to.as_path())
-}
-
-/// 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.
-///
-/// # Example
-///
-/// ```rust
-/// 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`
-pub fn copy<P: AsPath + ?Sized, Q: AsPath + ?Sized>(from: &P, to: &Q)
- -> io::Result<u64> {
- let from = from.as_path();
- if !from.is_file() {
- return Err(Error::new(ErrorKind::MismatchedFileTypeForOperation,
- "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.
-pub fn hard_link<P: AsPath + ?Sized, Q: AsPath + ?Sized>(src: &P, dst: &Q)
- -> io::Result<()> {
- fs_imp::link(src.as_path(), dst.as_path())
-}
-
-/// Creates a new soft link on the filesystem.
-///
-/// The `dst` path will be a soft link pointing to the `src` path.
-pub fn soft_link<P: AsPath + ?Sized, Q: AsPath + ?Sized>(src: &P, dst: &Q)
- -> io::Result<()> {
- fs_imp::symlink(src.as_path(), dst.as_path())
-}
-
-/// 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.
-pub fn read_link<P: AsPath + ?Sized>(path: &P) -> io::Result<PathBuf> {
- fs_imp::readlink(path.as_path())
-}
-
-/// Create a new, empty directory at the provided path
-///
-/// # Example
-///
-/// ```rust
-/// 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.
-pub fn create_dir<P: AsPath + ?Sized>(path: &P) -> io::Result<()> {
- fs_imp::mkdir(path.as_path())
-}
-
-/// 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`.
-pub fn create_dir_all<P: AsPath + ?Sized>(path: &P) -> io::Result<()> {
- let path = path.as_path();
- if path.is_dir() { return Ok(()) }
- match path.parent() {
- Some(p) if p != path => try!(create_dir_all(p)),
- _ => {}
- }
- create_dir(path)
-}
-
-/// Remove an existing, empty directory
-///
-/// # Example
-///
-/// ```rust
-/// 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.
-pub fn remove_dir<P: AsPath + ?Sized>(path: &P) -> io::Result<()> {
- fs_imp::rmdir(path.as_path())
-}
-
-/// 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`
-pub fn remove_dir_all<P: AsPath + ?Sized>(path: &P) -> io::Result<()> {
- let path = path.as_path();
- 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.
-///
-/// # Example
-///
-/// ```rust
-/// 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
-pub fn read_dir<P: AsPath + ?Sized>(path: &P) -> io::Result<ReadDir> {
- fs_imp::readdir(path.as_path()).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.
-pub fn walk_dir<P: AsPath + ?Sized>(path: &P) -> io::Result<WalkDir> {
- let start = try!(read_dir(path));
- Ok(WalkDir { cur: Some(start), stack: Vec::new() })
-}
-
-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.
-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.
-pub fn set_file_times<P: AsPath + ?Sized>(path: &P, accessed: u64,
- modified: u64) -> io::Result<()> {
- fs_imp::utimes(path.as_path(), accessed, modified)
-}
-
-/// Changes the permissions found on a file or a directory.
-///
-/// # Example
-///
-/// ```
-/// # 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.
-pub fn set_permissions<P: AsPath + ?Sized>(path: &P, perm: Permissions)
- -> io::Result<()> {
- fs_imp::set_perm(path.as_path(), perm.0)
-}
-
-#[cfg(test)]
-mod tests {
- #![allow(deprecated)] //rand
-
- use prelude::v1::*;
- use io::prelude::*;
-
- 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.as_slice()),
- 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 s = os::tmpdir();
- let p = Path2::new(s.as_str().unwrap());
- 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.as_slice(), 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 range(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 = [0u8; 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.as_slice(), 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 = [0u8; 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::PathAlreadyExists);
- }
-
- #[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());
- }
-
- #[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) {
- Ok(..) => panic!("wanted a panic"),
- Err(..) => {}
- }
- }
-
- #[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're seeked
- // 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().ok().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]
- 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));
- }
-}
--- /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`.
+
+#![unstable(feature = "fs")]
+
+use core::prelude::*;
+
+use io::{self, Error, ErrorKind, SeekFrom, Seek, Read, Write};
+use path::{AsPath, Path, PathBuf};
+use sys::fs2 as fs_imp;
+use sys_common::{AsInnerMut, FromInner, AsInner};
+use vec::Vec;
+
+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.
+///
+/// # Example
+///
+/// ```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(())
+/// # }
+/// ```
+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.
+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.
+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.
+pub struct DirEntry(fs_imp::DirEntry);
+
+/// An iterator that recursively walks over the contents of a directory.
+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)]
+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)]
+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`.
+ pub fn open<P: AsPath + ?Sized>(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.
+ pub fn create<P: AsPath + ?Sized>(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.
+ 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.
+ 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`.
+ 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.
+ pub fn set_len(&self, size: u64) -> io::Result<()> {
+ self.inner.truncate(size)
+ }
+
+ /// Queries information about the underlying file.
+ 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 Read for File {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(buf)
+ }
+}
+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() }
+}
+impl Seek for File {
+ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+ self.inner.seek(pos)
+ }
+}
+impl<'a> Read for &'a File {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.inner.read(buf)
+ }
+}
+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() }
+}
+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`.
+ 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.
+ 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.
+ 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.
+ 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.
+ 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.
+ 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)
+ pub fn open<P: AsPath + ?Sized>(&self, path: &P) -> io::Result<File> {
+ let path = path.as_path();
+ let inner = try!(fs_imp::File::open(path, &self.0));
+
+ // On *BSD systems, we can open a directory as a file and read from
+ // it: fd=open("/tmp", O_RDONLY); read(fd, buf, N); due to an old
+ // tradition before the introduction of opendir(3). We explicitly
+ // reject it because there are few use cases.
+ if cfg!(not(any(target_os = "linux", target_os = "android"))) &&
+ try!(inner.file_attr()).is_dir() {
+ Err(Error::new(ErrorKind::InvalidInput, "is a directory", None))
+ } else {
+ 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.
+ pub fn is_dir(&self) -> bool { self.0.is_dir() }
+
+ /// Returns whether this metadata is for a regular file.
+ pub fn is_file(&self) -> bool { self.0.is_file() }
+
+ /// Returns the size of the file, in bytes, this metadata is for.
+ pub fn len(&self) -> u64 { self.0.size() }
+
+ /// Returns the permissions of the file this metadata is for.
+ 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.
+ 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.
+ pub fn modified(&self) -> u64 { self.0.modified() }
+}
+
+impl Permissions {
+ /// Returns whether these permissions describe a readonly file.
+ 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.
+ 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 }
+}
+
+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))
+ }
+}
+
+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.
+ pub fn path(&self) -> PathBuf { self.0.path() }
+}
+
+/// Remove a file from the underlying filesystem.
+///
+/// # Example
+///
+/// ```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.
+pub fn remove_file<P: AsPath + ?Sized>(path: &P) -> io::Result<()> {
+ let path = path.as_path();
+ let e = match fs_imp::unlink(path) {
+ Ok(()) => return Ok(()),
+ Err(e) => e,
+ };
+ if !cfg!(windows) { return Err(e) }
+
+ // On unix, a readonly file can be successfully removed. On windows,
+ // however, it cannot. To keep the two platforms in line with
+ // respect to their behavior, catch this case on windows, attempt to
+ // change it to read-write, and then remove the file.
+ if e.kind() != ErrorKind::PermissionDenied { return Err(e) }
+
+ let attr = match metadata(path) { Ok(a) => a, Err(..) => return Err(e) };
+ let mut perms = attr.permissions();
+ if !perms.readonly() { return Err(e) }
+ perms.set_readonly(false);
+
+ if set_permissions(path, perms).is_err() { return Err(e) }
+ if fs_imp::unlink(path).is_ok() { return Ok(()) }
+
+ // Oops, try to put things back the way we found it
+ let _ = set_permissions(path, attr.permissions());
+ Err(e)
+}
+
+/// 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.
+///
+/// # Example
+///
+/// ```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.
+pub fn metadata<P: AsPath + ?Sized>(path: &P) -> io::Result<Metadata> {
+ fs_imp::stat(path.as_path()).map(Metadata)
+}
+
+/// Rename a file or directory to a new name.
+///
+/// # Example
+///
+/// ```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.
+pub fn rename<P: AsPath + ?Sized, Q: AsPath + ?Sized>(from: &P, to: &Q)
+ -> io::Result<()> {
+ fs_imp::rename(from.as_path(), to.as_path())
+}
+
+/// 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.
+///
+/// # Example
+///
+/// ```rust
+/// 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`
+pub fn copy<P: AsPath + ?Sized, Q: AsPath + ?Sized>(from: &P, to: &Q)
+ -> io::Result<u64> {
+ let from = from.as_path();
+ if !from.is_file() {
+ return Err(Error::new(ErrorKind::MismatchedFileTypeForOperation,
+ "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.
+pub fn hard_link<P: AsPath + ?Sized, Q: AsPath + ?Sized>(src: &P, dst: &Q)
+ -> io::Result<()> {
+ fs_imp::link(src.as_path(), dst.as_path())
+}
+
+/// Creates a new soft link on the filesystem.
+///
+/// The `dst` path will be a soft link pointing to the `src` path.
+pub fn soft_link<P: AsPath + ?Sized, Q: AsPath + ?Sized>(src: &P, dst: &Q)
+ -> io::Result<()> {
+ fs_imp::symlink(src.as_path(), dst.as_path())
+}
+
+/// 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.
+pub fn read_link<P: AsPath + ?Sized>(path: &P) -> io::Result<PathBuf> {
+ fs_imp::readlink(path.as_path())
+}
+
+/// Create a new, empty directory at the provided path
+///
+/// # Example
+///
+/// ```rust
+/// 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.
+pub fn create_dir<P: AsPath + ?Sized>(path: &P) -> io::Result<()> {
+ fs_imp::mkdir(path.as_path())
+}
+
+/// 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`.
+pub fn create_dir_all<P: AsPath + ?Sized>(path: &P) -> io::Result<()> {
+ let path = path.as_path();
+ if path.is_dir() { return Ok(()) }
+ match path.parent() {
+ Some(p) if p != path => try!(create_dir_all(p)),
+ _ => {}
+ }
+ // If the file name of the given `path` is blank then the creation of the
+ // parent directory will have taken care of the whole path for us, so we're
+ // good to go.
+ if path.file_name().is_none() {
+ Ok(())
+ } else {
+ create_dir(path)
+ }
+}
+
+/// Remove an existing, empty directory
+///
+/// # Example
+///
+/// ```rust
+/// 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.
+pub fn remove_dir<P: AsPath + ?Sized>(path: &P) -> io::Result<()> {
+ fs_imp::rmdir(path.as_path())
+}
+
+/// 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`
+pub fn remove_dir_all<P: AsPath + ?Sized>(path: &P) -> io::Result<()> {
+ let path = path.as_path();
+ 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.
+///
+/// # Example
+///
+/// ```rust
+/// 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
+pub fn read_dir<P: AsPath + ?Sized>(path: &P) -> io::Result<ReadDir> {
+ fs_imp::readdir(path.as_path()).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.
+pub fn walk_dir<P: AsPath + ?Sized>(path: &P) -> io::Result<WalkDir> {
+ let start = try!(read_dir(path));
+ Ok(WalkDir { cur: Some(start), stack: Vec::new() })
+}
+
+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.
+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.
+pub fn set_file_times<P: AsPath + ?Sized>(path: &P, accessed: u64,
+ modified: u64) -> io::Result<()> {
+ fs_imp::utimes(path.as_path(), accessed, modified)
+}
+
+/// Changes the permissions found on a file or a directory.
+///
+/// # Example
+///
+/// ```
+/// # 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.
+pub fn set_permissions<P: AsPath + ?Sized>(path: &P, perm: Permissions)
+ -> io::Result<()> {
+ fs_imp::set_perm(path.as_path(), perm.0)
+}
+
+#[cfg(test)]
+mod tests {
+ #![allow(deprecated)] //rand
+
+ use prelude::v1::*;
+ use io::prelude::*;
+
+ 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.as_slice()),
+ 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 s = os::tmpdir();
+ let p = Path2::new(s.as_str().unwrap());
+ 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.as_slice(), 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 range(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 = [0u8; 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.as_slice(), 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 = [0u8; 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::PathAlreadyExists);
+ }
+
+ #[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());
+ }
+
+ #[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) {
+ Ok(..) => panic!("wanted a panic"),
+ Err(..) => {}
+ }
+ }
+
+ #[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're seeked
+ // 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().ok().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]
+ 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")]
+
+use prelude::v1::*;
+
+use env;
+use io::{self, Error, ErrorKind};
+use fs;
+use path::{self, PathBuf, AsPath};
+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: uint = 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: AsPath + ?Sized>(tmpdir: &P, prefix: &str)
+ -> io::Result<TempDir> {
+ let storage;
+ let mut tmpdir = tmpdir.as_path();
+ 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::PathAlreadyExists => {}
+ Err(e) => return Err(e)
+ }
+ }
+
+ Err(Error::new(ErrorKind::PathAlreadyExists,
+ "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
}
/// Gets a reference to the underlying reader.
- pub fn get_ref<'a>(&self) -> &R { &self.inner }
+ pub fn get_ref(&self) -> &R { &self.inner }
/// Gets a mutable reference to the underlying reader.
///
if written > 0 {
// NB: would be better expressed as .remove(0..n) if it existed
unsafe {
- ptr::copy_memory(self.buf.as_mut_ptr(),
- self.buf.as_ptr().offset(written as isize),
- len - written);
+ ptr::copy(self.buf.as_mut_ptr(),
+ self.buf.as_ptr().offset(written as isize),
+ len - written);
}
}
self.buf.truncate(len - written);
#![feature(unsafe_no_drop_flag)]
#![feature(macro_reexport)]
#![feature(hash)]
+#![feature(unique)]
#![cfg_attr(test, feature(test, rustc_private, env))]
// Don't link to std. We are std.
let dirs = ["32-opt", "32-nopt", "64-opt", "64-nopt", "64-opt-vg",
"all-opt", "snap3", "dist"];
dirs.iter().enumerate().find(|&(_, dir)| {
- cwd.as_str().unwrap().contains(dir)
+ cwd.to_str().unwrap().contains(dir)
}).map(|p| p.0).unwrap_or(0) as u16 * 1000 + 19600
}
fn read_bytes() {
let mut reader = MemReader::new(vec!(10, 11, 12, 13));
let bytes = reader.read_exact(4).unwrap();
- assert!(bytes == vec!(10, 11, 12, 13));
+ assert_eq!(bytes, [10, 11, 12, 13]);
}
#[test]
count: 0,
};
let bytes = reader.read_exact(4).unwrap();
- assert!(bytes == vec!(10, 11, 12, 13));
+ assert_eq!(bytes, [10, 11, 12, 13]);
}
#[test]
let mut reader = MemReader::new(vec![10, 11, 12, 13]);
let mut buf = vec![8, 9];
assert!(reader.push_at_least(4, 4, &mut buf).is_ok());
- assert!(buf == vec![8, 9, 10, 11, 12, 13]);
+ assert_eq!(buf, [8, 9, 10, 11, 12, 13]);
}
#[test]
};
let mut buf = vec![8, 9];
assert!(reader.push_at_least(4, 4, &mut buf).is_ok());
- assert!(buf == vec![8, 9, 10, 11, 12, 13]);
+ assert_eq!(buf, [8, 9, 10, 11, 12, 13]);
}
#[test]
let mut reader = MemReader::new(vec![10, 11]);
let mut buf = vec![8, 9];
assert!(reader.push_at_least(4, 4, &mut buf).is_err());
- assert!(buf == vec![8, 9, 10, 11]);
+ assert_eq!(buf, [8, 9, 10, 11]);
}
#[test]
};
let mut buf = vec![8, 9];
assert!(reader.push_at_least(4, 4, &mut buf).is_err());
- assert!(buf == vec![8, 9, 10]);
+ assert_eq!(buf, [8, 9, 10]);
}
#[test]
count: 0,
};
let buf = reader.read_to_end().unwrap();
- assert!(buf == vec!(10, 11, 12, 13));
+ assert_eq!(buf, [10, 11, 12, 13]);
}
#[test]
count: 0,
};
let buf = reader.read_to_end().unwrap();
- assert!(buf == vec!(10, 11));
+ assert_eq!(buf, [10, 11]);
}
#[test]
/// let mut w = MemWriter::new();
/// w.write(&[0, 1, 2]);
///
-/// assert_eq!(w.into_inner(), vec!(0, 1, 2));
+/// assert_eq!(w.into_inner(), [0, 1, 2]);
/// ```
#[unstable(feature = "io")]
#[deprecated(since = "1.0.0",
///
/// let mut r = MemReader::new(vec!(0, 1, 2));
///
-/// assert_eq!(r.read_to_end().unwrap(), vec!(0, 1, 2));
+/// assert_eq!(r.read_to_end().unwrap(), [0, 1, 2]);
/// ```
pub struct MemReader {
buf: Vec<u8>,
/// let buf = [0, 1, 2, 3];
/// let mut r = BufReader::new(&buf);
///
-/// assert_eq!(r.read_to_end().unwrap(), vec![0, 1, 2, 3]);
+/// assert_eq!(r.read_to_end().unwrap(), [0, 1, 2, 3]);
/// ```
pub struct BufReader<'a> {
buf: &'a [u8],
assert_eq!(&buf[..3], b);
assert!(reader.read(&mut buf).is_err());
let mut reader = MemReader::new(vec!(0, 1, 2, 3, 4, 5, 6, 7));
- assert_eq!(reader.read_until(3).unwrap(), vec!(0, 1, 2, 3));
- assert_eq!(reader.read_until(3).unwrap(), vec!(4, 5, 6, 7));
+ assert_eq!(reader.read_until(3).unwrap(), [0, 1, 2, 3]);
+ assert_eq!(reader.read_until(3).unwrap(), [4, 5, 6, 7]);
assert!(reader.read(&mut buf).is_err());
}
assert_eq!(&buf[..3], b);
assert!(reader.read(&mut buf).is_err());
let mut reader = &mut &*in_buf;
- assert_eq!(reader.read_until(3).unwrap(), vec!(0, 1, 2, 3));
- assert_eq!(reader.read_until(3).unwrap(), vec!(4, 5, 6, 7));
+ assert_eq!(reader.read_until(3).unwrap(), [0, 1, 2, 3]);
+ assert_eq!(reader.read_until(3).unwrap(), [4, 5, 6, 7]);
assert!(reader.read(&mut buf).is_err());
}
assert_eq!(&buf[..3], b);
assert!(reader.read(&mut buf).is_err());
let mut reader = BufReader::new(&in_buf);
- assert_eq!(reader.read_until(3).unwrap(), vec!(0, 1, 2, 3));
- assert_eq!(reader.read_until(3).unwrap(), vec!(4, 5, 6, 7));
+ assert_eq!(reader.read_until(3).unwrap(), [0, 1, 2, 3]);
+ assert_eq!(reader.read_until(3).unwrap(), [4, 5, 6, 7]);
assert!(reader.read(&mut buf).is_err());
}
let mut writer: old_io::IoResult<Vec<u8>> = Ok(Vec::new());
writer.write_all(&[0, 1, 2]).unwrap();
writer.flush().unwrap();
- assert_eq!(writer.unwrap(), vec!(0, 1, 2));
+ assert_eq!(writer.unwrap(), [0, 1, 2]);
}
#[test]
/// deleted once the returned wrapper is destroyed.
///
/// If no directory can be created, `Err` is returned.
+ #[allow(deprecated)]
pub fn new_in(tmpdir: &Path, prefix: &str) -> IoResult<TempDir> {
if !tmpdir.is_absolute() {
- let cur_dir = try!(env::current_dir());
+ let cur_dir = try!(::os::getcwd());
return TempDir::new_in(&cur_dir.join(tmpdir), prefix);
}
/// deleted once the returned wrapper is destroyed.
///
/// If no directory can be created, `Err` is returned.
+ #[allow(deprecated)]
pub fn new(prefix: &str) -> IoResult<TempDir> {
- TempDir::new_in(&env::temp_dir(), prefix)
+ TempDir::new_in(&::os::tmpdir(), prefix)
}
/// Unwrap the wrapped `std::path::Path` from the `TempDir` wrapper.
/// Get a temporary path which could be the location of a unix socket
#[cfg(not(target_os = "ios"))]
+#[allow(deprecated)]
pub fn next_test_unix() -> Path {
let string = next_test_unix_socket();
if cfg!(unix) {
- env::temp_dir().join(string)
+ ::os::tmpdir().join(string)
} else {
Path::new(format!("{}{}", r"\\.\pipe\", string))
}
// FIXME (#9639): This needs to handle non-utf8 paths
let path = env::current_dir().unwrap();
- let path_s = path.as_str().unwrap();
+ let path_s = path.to_str().unwrap();
let mut final_base = base;
let mut r = MemReader::new(vec!(0, 1, 2));
{
let mut r = LimitReader::new(r.by_ref(), 4);
- assert_eq!(vec!(0, 1, 2), r.read_to_end().unwrap());
+ assert_eq!([0, 1, 2], r.read_to_end().unwrap());
}
}
let mut r = MemReader::new(vec!(0, 1, 2));
{
let mut r = LimitReader::new(r.by_ref(), 2);
- assert_eq!(vec!(0, 1), r.read_to_end().unwrap());
+ assert_eq!([0, 1], r.read_to_end().unwrap());
}
- assert_eq!(vec!(2), r.read_to_end().unwrap());
+ assert_eq!([2], r.read_to_end().unwrap());
}
#[test]
assert_eq!(3, r.limit());
assert_eq!(0, r.read_byte().unwrap());
assert_eq!(2, r.limit());
- assert_eq!(vec!(1, 2), r.read_to_end().unwrap());
+ assert_eq!([1, 2], r.read_to_end().unwrap());
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!(vec![], 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!(vec![0, 0, 0], buf);
+ assert_eq!([0, 0, 0], buf);
}
#[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!(vec!(0, 1, 2, 3), r.read_to_end().unwrap());
+ assert_eq!([0, 1, 2, 3], r.read_to_end().unwrap());
}
#[test]
fn test_tee_reader() {
let mut r = TeeReader::new(MemReader::new(vec!(0, 1, 2)),
Vec::new());
- assert_eq!(vec!(0, 1, 2), r.read_to_end().unwrap());
+ assert_eq!([0, 1, 2], r.read_to_end().unwrap());
let (_, w) = r.into_inner();
- assert_eq!(vec!(0, 1, 2), w);
+ assert_eq!([0, 1, 2], w);
}
#[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!(vec!(0, 1, 2, 3, 4), w);
+ assert_eq!([0, 1, 2, 3, 4], w);
}
#[test]
use option::Option::{Some, None};
use option::Option;
use old_path::{Path, GenericPath, BytesContainer};
+use path::{self, PathBuf};
use ptr::PtrExt;
use ptr;
use result::Result::{Err, Ok};
#[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::new(path.as_str().unwrap())
+}
+#[cfg(unix)]
+fn path2new(path: &Path) -> PathBuf {
+ use os::unix::prelude::*;
+ PathBuf::new(<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() -> uint {
unsafe {
/// let current_working_directory = os::getcwd().unwrap();
/// println!("The current directory is {:?}", current_working_directory.display());
/// ```
-#[deprecated(since = "1.0.0", reason = "renamed to std::env::current_dir")]
#[unstable(feature = "os")]
pub fn getcwd() -> IoResult<Path> {
- env::current_dir()
+ env::current_dir().map_err(err2old).map(|s| path2old(&s))
}
/// Returns a vector of (variable, value) pairs, for all the environment
/// None => println!("{} is not defined in the environment.", key)
/// }
/// ```
-#[deprecated(since = "1.0.0", reason = "renamed to env::split_paths")]
#[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).collect()
+ env::split_paths(s).map(|s| path2old(&s)).collect()
}
/// Joins a collection of `Path`s appropriately for the `PATH`
/// paths.push(Path::new("/home/xyz/bin"));
/// os::setenv(key, os::join_paths(paths.as_slice()).unwrap());
/// ```
-#[deprecated(since = "1.0.0", reason = "renamed to env::join_paths")]
#[unstable(feature = "os")]
pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
env::join_paths(paths.iter().map(|s| {
/// None => println!("Unable to get the path of this executable!")
/// };
/// ```
-#[deprecated(since = "1.0.0", reason = "renamed to env::current_exe")]
#[unstable(feature = "os")]
pub fn self_exe_name() -> Option<Path> {
- env::current_exe().ok()
+ env::current_exe().ok().map(|p| path2old(&p))
}
/// Optionally returns the filesystem path to the current executable which is
/// None => println!("Impossible to fetch the path of this executable.")
/// };
/// ```
-#[deprecated(since = "1.0.0", reason = "use env::current_exe + dir_path/pop")]
#[unstable(feature = "os")]
pub fn self_exe_path() -> Option<Path> {
- env::current_exe().ok().map(|mut p| { p.pop(); p })
+ 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.
/// None => println!("Impossible to get your home dir!")
/// }
/// ```
-#[deprecated(since = "1.0.0", reason = "renamed to env::home_dir")]
-#[allow(deprecated)]
#[unstable(feature = "os")]
+#[allow(deprecated)]
pub fn homedir() -> Option<Path> {
#[inline]
#[cfg(unix)]
/// 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.
-#[deprecated(since = "1.0.0", reason = "renamed to env::temp_dir")]
-#[allow(deprecated)]
#[unstable(feature = "os")]
+#[allow(deprecated)]
pub fn tmpdir() -> Path {
return lookup();
if p.is_absolute() {
Ok(p.clone())
} else {
- env::current_dir().map(|mut cwd| {
+ env::current_dir().map_err(err2old).map(|cwd| {
+ let mut cwd = path2old(&cwd);
cwd.push(p);
cwd
})
/// assert!(os::change_dir(&root).is_ok());
/// println!("Successfully changed working directory to {}!", root.display());
/// ```
-#[deprecated(since = "1.0.0", reason = "renamed to env::set_current_dir")]
#[unstable(feature = "os")]
pub fn change_dir(p: &Path) -> IoResult<()> {
- return sys::os::chdir(p);
+ sys::os::chdir(&path2new(p)).map_err(err2old)
}
/// Returns the platform-specific value of errno
pub fn capture() -> Stdio { Stdio(StdioImp::Capture) }
/// The child inherits from the corresponding parent descriptor.
- pub fn inherit() -> Stdio { Stdio(StdioImp::Capture) }
+ pub fn inherit() -> Stdio { Stdio(StdioImp::Inherit) }
/// This stream will be ignored. This is the equivalent of attaching the
/// stream to `/dev/null`
- pub fn null() -> Stdio { Stdio(StdioImp::Capture) }
+ pub fn null() -> Stdio { Stdio(StdioImp::Null) }
}
/// Describes the result of a process after it has terminated.
extern crate libc;
use old_io::{IoResult};
- use marker::Sync;
use mem;
use os;
use rand::Rng;
#[repr(C)]
struct SecRandom;
- unsafe impl Sync for *const SecRandom {}
-
#[allow(non_upper_case_globals)]
- static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;
+ const kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;
#[link(name = "Security", kind = "framework")]
extern "C" {
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Condvar { inner: Box<StaticCondvar> }
-unsafe impl Send for Condvar {}
-unsafe impl Sync for Condvar {}
-
/// Statically allocated condition variables.
///
/// This structure is identical to `Condvar` except that it is suitable for use
mutex: AtomicUsize,
}
-unsafe impl Send for StaticCondvar {}
-unsafe impl Sync for StaticCondvar {}
-
/// Constant initializer for a statically allocated condition variable.
#[unstable(feature = "std_misc",
reason = "may be merged with Condvar in the future")]
pub use self::poison::{PoisonError, TryLockError, TryLockResult, LockResult};
pub use self::future::Future;
+#[allow(deprecated)]
pub use self::task_pool::TaskPool;
pub mod mpsc;
poison: poison::Flag,
}
-unsafe impl Sync for StaticMutex {}
-
/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
/// dropped (falls out of scope), the lock will be unlocked.
///
//! This primitive is meant to be used to run one-time initialization. An
//! example use case would be for initializing an FFI library.
+use prelude::v1::*;
+
use isize;
-use marker::Sync;
-use mem::drop;
-use ops::FnOnce;
use sync::atomic::{AtomicIsize, Ordering, ATOMIC_ISIZE_INIT};
use sync::{StaticMutex, MUTEX_INIT};
lock_cnt: AtomicIsize,
}
-unsafe impl Sync for Once {}
-
/// Initialization value for static `Once` values.
#[stable(feature = "rust1", since = "1.0.0")]
pub const ONCE_INIT: Once = Once {
use thread;
pub struct Flag { failed: UnsafeCell<bool> }
+
+// This flag is only ever accessed with a lock previously held. Note that this
+// a totally private structure.
+unsafe impl Send for Flag {}
+unsafe impl Sync for Flag {}
+
pub const FLAG_INIT: Flag = Flag { failed: UnsafeCell { value: false } };
impl Flag {
poison: poison::Flag,
}
-unsafe impl Send for StaticRwLock {}
-unsafe impl Sync for StaticRwLock {}
-
/// Constant initialization for a statically-initialized rwlock.
#[unstable(feature = "std_misc",
reason = "may be merged with RwLock in the future")]
//! Abstraction of a thread pool for basic parallelism.
-#![unstable(feature = "std_misc",
- reason = "the semantics of a failing task and whether a thread is \
- re-attached to a thread pool are somewhat unclear, and the \
- utility of this type in `std::sync` is questionable with \
- respect to the jobs of other primitives")]
+#![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::*;
#[cfg(windows)] use libc::WSAEWOULDBLOCK as WOULDBLOCK;
// Make sure the call to connect() doesn't block
- try!(set_nonblocking(fd, true));
+ set_nonblocking(fd, true);
let ret = match unsafe { libc::connect(fd, addrp, len) } {
// If the connection is in progress, then we need to wait for it to
};
// be sure to turn blocking I/O back on
- try!(set_nonblocking(fd, false));
+ set_nonblocking(fd, false);
return ret;
#[cfg(unix)]
#[unsafe_destructor]
impl<'a> Drop for Guard<'a> {
fn drop(&mut self) {
- assert!(set_nonblocking(self.fd, false).is_ok());
+ set_nonblocking(self.fd, false);
}
}
fd: self.fd(),
guard: self.inner.lock.lock().unwrap(),
};
- assert!(set_nonblocking(self.fd(), true).is_ok());
+ set_nonblocking(self.fd(), true);
ret
}
fd: self.fd(),
guard: self.inner.lock.lock().unwrap(),
};
- assert!(set_nonblocking(self.fd(), true).is_ok());
+ set_nonblocking(self.fd(), true);
ret
}
storagep,
&mut addrlen) as libc::c_int
}));
- sockaddr_to_addr(&storage, addrlen as uint).and_then(|addr| {
- Ok((n as uint, addr))
- })
+ Ok((n as uint, sockaddr_to_addr(&storage, addrlen as uint).unwrap()))
}
pub fn send_to(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()> {
};
let n = try!(write(fd, self.write_deadline, buf, false, dolock, dowrite));
- if n != buf.len() {
- Err(short_write(n, "couldn't send entire packet at once"))
- } else {
- Ok(())
- }
+ assert!(n == buf.len(), "UDP packet not completely written.");
+ Ok(())
}
pub fn join_multicast(&mut self, multi: IpAddr) -> IoResult<()> {
string.code_points().map(|c| c.to_char()).collect::<Vec<_>>()
}
let mut string = Wtf8Buf::from_str("é ");
- assert_eq!(cp(&string), vec![Some('é'), Some(' ')]);
+ assert_eq!(cp(&string), [Some('é'), Some(' ')]);
string.push(c(0xD83D));
- assert_eq!(cp(&string), vec![Some('é'), Some(' '), None]);
+ assert_eq!(cp(&string), [Some('é'), Some(' '), None]);
string.push(c(0xDCA9));
- assert_eq!(cp(&string), vec![Some('é'), Some(' '), Some('💩')]);
+ assert_eq!(cp(&string), [Some('é'), Some(' '), Some('💩')]);
}
#[test]
/// all unix platforms we support right now, so it at least gets the job done.
use prelude::v1::*;
+use os::unix::prelude::*;
-use ffi::CStr;
+use ffi::{CStr, AsOsStr};
use old_io::IoResult;
use libc;
use mem;
};
let filename = match selfname {
Some(path) => {
- let bytes = path.as_vec();
+ let bytes = path.as_os_str().as_bytes();
if bytes.len() < LAST_FILENAME.len() {
let i = bytes.iter();
for (slot, val) in LAST_FILENAME.iter_mut().zip(i) {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use prelude::v1::*;
+
use cell::UnsafeCell;
use libc;
use ptr;
-use std::option::Option::{Some, None};
use sys::mutex::{self, Mutex};
use sys::time;
use sys::sync as ffi;
pub struct Condvar { inner: UnsafeCell<ffi::pthread_cond_t> }
+unsafe impl Send for Condvar {}
+unsafe impl Sync for Condvar {}
+
pub const CONDVAR_INIT: Condvar = Condvar {
inner: UnsafeCell { value: ffi::PTHREAD_COND_INITIALIZER },
};
// Unix-specific extensions to `Permissions`
pub trait PermissionsExt {
+ fn mode(&self) -> i32;
fn set_mode(&mut self, mode: i32);
}
impl PermissionsExt for Permissions {
+ fn mode(&self) -> i32 { self.as_inner().mode() }
+
fn set_mode(&mut self, mode: i32) {
*self = FromInner::from_inner(FromInner::from_inner(mode));
}
self.mode |= 0o222;
}
}
+ pub fn mode(&self) -> i32 { self.mode as i32 }
}
impl FromInner<i32> for FilePermissions {
err == libc::EWOULDBLOCK as i32 || err == libc::EAGAIN as i32
}
-pub fn set_nonblocking(fd: sock_t, nb: bool) -> IoResult<()> {
+pub fn set_nonblocking(fd: sock_t, nb: bool) {
let set = nb as libc::c_int;
- mkerr_libc(retry(|| unsafe { c::ioctl(fd, c::FIONBIO, &set) }))
+ mkerr_libc(retry(|| unsafe { c::ioctl(fd, c::FIONBIO, &set) })).unwrap();
}
// nothing needed on unix platforms
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use prelude::v1::*;
+
use cell::UnsafeCell;
-use marker::Sync;
use sys::sync as ffi;
use sys_common::mutex;
inner: UnsafeCell { value: ffi::PTHREAD_MUTEX_INITIALIZER },
};
+unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}
impl Mutex {
use error::Error as StdError;
use ffi::{CString, CStr, OsString, OsStr, AsOsStr};
use fmt;
+use io;
use iter;
use libc::{self, c_int, c_char, c_void};
use mem;
-use io;
-use old_io::{IoResult, IoError, fs};
+use old_io::{IoError, IoResult};
use ptr;
+use path::{self, PathBuf};
use slice;
use str;
use sys::c;
const BUF_BYTES: usize = 2048;
const TMPBUF_SZ: usize = 128;
+fn bytes2path(b: &[u8]) -> PathBuf {
+ PathBuf::new(<OsStr as OsStrExt>::from_bytes(b))
+}
+
+fn os2path(os: OsString) -> PathBuf {
+ bytes2path(os.as_bytes())
+}
+
/// Returns the platform-specific value of errno
pub fn errno() -> i32 {
#[cfg(any(target_os = "macos",
}
}
-pub fn getcwd() -> IoResult<Path> {
+pub fn getcwd() -> io::Result<PathBuf> {
let mut buf = [0 as c_char; BUF_BYTES];
unsafe {
if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
- Err(IoError::last_error())
+ Err(io::Error::last_os_error())
} else {
- Ok(Path::new(CStr::from_ptr(buf.as_ptr()).to_bytes()))
+ Ok(bytes2path(CStr::from_ptr(buf.as_ptr()).to_bytes()))
}
}
}
-pub fn chdir(p: &Path) -> IoResult<()> {
- let p = CString::new(p.as_vec()).unwrap();
+pub fn chdir(p: &path::Path) -> io::Result<()> {
+ let p = try!(CString::new(p.as_os_str().as_bytes()));
unsafe {
match libc::chdir(p.as_ptr()) == (0 as c_int) {
true => Ok(()),
- false => Err(IoError::last_error()),
+ false => Err(io::Error::last_os_error()),
}
}
}
pub struct SplitPaths<'a> {
iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>,
- fn(&'a [u8]) -> Path>,
+ fn(&'a [u8]) -> PathBuf>,
}
pub fn split_paths<'a>(unparsed: &'a OsStr) -> SplitPaths<'a> {
let unparsed = unparsed.as_bytes();
SplitPaths {
iter: unparsed.split(is_colon as fn(&u8) -> bool)
- .map(Path::new as fn(&'a [u8]) -> Path)
+ .map(bytes2path as fn(&'a [u8]) -> PathBuf)
}
}
impl<'a> Iterator for SplitPaths<'a> {
- type Item = Path;
- fn next(&mut self) -> Option<Path> { self.iter.next() }
+ type Item = PathBuf;
+ fn next(&mut self) -> Option<PathBuf> { self.iter.next() }
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}
}
#[cfg(target_os = "freebsd")]
-pub fn current_exe() -> IoResult<Path> {
+pub fn current_exe() -> io::Result<PathBuf> {
unsafe {
use libc::funcs::bsd44::*;
use libc::consts::os::extra::*;
let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
ptr::null_mut(), &mut sz, ptr::null_mut(),
0 as libc::size_t);
- if err != 0 { return Err(IoError::last_error()); }
- if sz == 0 { return Err(IoError::last_error()); }
+ if err != 0 { return Err(io::Error::last_os_error()); }
+ if sz == 0 { return Err(io::Error::last_os_error()); }
let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
v.as_mut_ptr() as *mut libc::c_void, &mut sz,
ptr::null_mut(), 0 as libc::size_t);
- if err != 0 { return Err(IoError::last_error()); }
- if sz == 0 { return Err(IoError::last_error()); }
+ if err != 0 { return Err(io::Error::last_os_error()); }
+ if sz == 0 { return Err(io::Error::last_os_error()); }
v.set_len(sz as uint - 1); // chop off trailing NUL
- Ok(Path::new(v))
+ Ok(PathBuf::new::<OsString>(&OsStringExt::from_vec(v)))
}
}
#[cfg(target_os = "dragonfly")]
-pub fn current_exe() -> IoResult<Path> {
- fs::readlink(&Path::new("/proc/curproc/file"))
+pub fn current_exe() -> io::Result<PathBuf> {
+ ::fs::read_link("/proc/curproc/file")
}
#[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
-pub fn current_exe() -> IoResult<Path> {
+pub fn current_exe() -> io::Result<PathBuf> {
use sync::{StaticMutex, MUTEX_INIT};
static LOCK: StaticMutex = MUTEX_INIT;
unsafe {
let v = rust_current_exe();
if v.is_null() {
- Err(IoError::last_error())
+ Err(io::Error::last_os_error())
} else {
Ok(Path::new(CStr::from_ptr(v).to_bytes().to_vec()))
}
}
#[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn current_exe() -> IoResult<Path> {
- fs::readlink(&Path::new("/proc/self/exe"))
+pub fn current_exe() -> io::Result<PathBuf> {
+ ::fs::read_link("/proc/self/exe")
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
-pub fn current_exe() -> IoResult<Path> {
+pub fn current_exe() -> io::Result<PathBuf> {
unsafe {
use libc::funcs::extra::_NSGetExecutablePath;
let mut sz: u32 = 0;
_NSGetExecutablePath(ptr::null_mut(), &mut sz);
- if sz == 0 { return Err(IoError::last_error()); }
+ if sz == 0 { return Err(io::Error::last_os_error()); }
let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
- if err != 0 { return Err(IoError::last_error()); }
+ if err != 0 { return Err(io::Error::last_os_error()); }
v.set_len(sz as uint - 1); // chop off trailing NUL
- Ok(Path::new(v))
+ Ok(PathBuf::new::<OsString>(&OsStringExt::from_vec(v)))
}
}
}
}
-pub fn temp_dir() -> Path {
- getenv("TMPDIR".as_os_str()).map(|p| Path::new(p.into_vec())).unwrap_or_else(|| {
+pub fn temp_dir() -> PathBuf {
+ getenv("TMPDIR".as_os_str()).map(os2path).unwrap_or_else(|| {
if cfg!(target_os = "android") {
- Path::new("/data/local/tmp")
+ PathBuf::new("/data/local/tmp")
} else {
- Path::new("/tmp")
+ PathBuf::new("/tmp")
}
})
}
-pub fn home_dir() -> Option<Path> {
+pub fn home_dir() -> Option<PathBuf> {
return getenv("HOME".as_os_str()).or_else(|| unsafe {
fallback()
- }).map(|os| {
- Path::new(os.into_vec())
- });
+ }).map(os2path);
#[cfg(any(target_os = "android",
target_os = "ios"))]
fd: self.fd(),
guard: unsafe { self.inner.lock.lock().unwrap() },
};
- assert!(set_nonblocking(self.fd(), true).is_ok());
+ set_nonblocking(self.fd(), true);
ret
}
_ => {
let (reader, writer) = try!(unsafe { sys::os::pipe() });
- try!(set_nonblocking(reader.fd(), true));
- try!(set_nonblocking(writer.fd(), true));
- try!(set_nonblocking(self.fd(), true));
+ set_nonblocking(reader.fd(), true);
+ set_nonblocking(writer.fd(), true);
+ set_nonblocking(self.fd(), true);
Ok(UnixAcceptor {
inner: Arc::new(AcceptorInner {
listener: self,
K: BytesContainer + Eq + Hash, V: BytesContainer
{
use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
- use libc::funcs::bsd44::getdtablesize;
mod rustrt {
extern {
assert_eq!(ret, 0);
}
+ #[cfg(all(target_os = "android", target_arch = "aarch64"))]
+ unsafe fn getdtablesize() -> c_int {
+ libc::sysconf(libc::consts::os::sysconf::_SC_OPEN_MAX) as c_int
+ }
+ #[cfg(not(all(target_os = "android", target_arch = "aarch64")))]
+ unsafe fn getdtablesize() -> c_int {
+ libc::funcs::bsd44::getdtablesize()
+ }
+
let dirp = cfg.cwd().map(|c| c.as_ptr()).unwrap_or(ptr::null());
// temporary until unboxed closures land
unsafe {
let mut pipes = [0; 2];
assert_eq!(libc::pipe(pipes.as_mut_ptr()), 0);
- set_nonblocking(pipes[0], true).ok().unwrap();
- set_nonblocking(pipes[1], true).ok().unwrap();
+ set_nonblocking(pipes[0], true);
+ set_nonblocking(pipes[1], true);
WRITE_FD = pipes[1];
let mut old: c::sigaction = mem::zeroed();
fn waitpid_helper(input: libc::c_int,
messages: Receiver<Req>,
(read_fd, old): (libc::c_int, c::sigaction)) {
- set_nonblocking(input, true).ok().unwrap();
+ set_nonblocking(input, true);
let mut set: c::fd_set = unsafe { mem::zeroed() };
let mut tv: libc::timeval;
let mut active = Vec::<(libc::pid_t, Sender<ProcessExit>, u64)>::new();
-> io::Result<Process>
{
use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
- use libc::funcs::bsd44::getdtablesize;
mod rustrt {
extern {
assert_eq!(ret, 0);
}
+ #[cfg(all(target_os = "android", target_arch = "aarch64"))]
+ unsafe fn getdtablesize() -> c_int {
+ libc::sysconf(libc::consts::os::sysconf::_SC_OPEN_MAX) as c_int
+ }
+
+ #[cfg(not(all(target_os = "android", target_arch = "aarch64")))]
+ unsafe fn getdtablesize() -> c_int {
+ libc::funcs::bsd44::getdtablesize()
+ }
+
let dirp = cfg.cwd.as_ref().map(|c| c.as_ptr()).unwrap_or(ptr::null());
with_envp(cfg.env.as_ref(), |envp: *const c_void| {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use prelude::v1::*;
+
use cell::UnsafeCell;
use sys::sync as ffi;
inner: UnsafeCell { value: ffi::PTHREAD_RWLOCK_INITIALIZER },
};
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {}
+
impl RWLock {
#[inline]
pub unsafe fn new() -> RWLock {
-1 => Err(last_net_error()),
_ => {
let (reader, writer) = try!(unsafe { sys::os::pipe() });
- try!(set_nonblocking(reader.fd(), true));
- try!(set_nonblocking(writer.fd(), true));
- try!(set_nonblocking(self.fd(), true));
+ set_nonblocking(reader.fd(), true);
+ set_nonblocking(writer.fd(), true);
+ set_nonblocking(self.fd(), true);
Ok(TcpAcceptor {
inner: Arc::new(AcceptorInner {
listener: self,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use prelude::v1::*;
+
use cell::UnsafeCell;
use libc::{self, DWORD};
use os;
pub struct Condvar { inner: UnsafeCell<ffi::CONDITION_VARIABLE> }
+unsafe impl Send for Condvar {}
+unsafe impl Sync for Condvar {}
+
pub const CONDVAR_INIT: Condvar = Condvar {
inner: UnsafeCell { value: ffi::CONDITION_VARIABLE_INIT }
};
buf as *const u16,
sz - 1,
libc::VOLUME_NAME_DOS)
- }, super::os2path);
+ }, |data| {
+ Path::new(String::from_utf16(data).unwrap())
+ });
assert!(unsafe { libc::CloseHandle(handle) } != 0);
return ret;
}
use prelude::v1::*;
-use ffi::OsStr;
+use ffi::{OsStr, OsString};
use io::{self, ErrorKind};
use libc;
use mem;
-use old_io::{self, IoResult, IoError};
use num::Int;
-use os::windows::OsStrExt;
+use old_io::{self, IoResult, IoError};
+use os::windows::{OsStrExt, OsStringExt};
+use path::PathBuf;
use sync::{Once, ONCE_INIT};
macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => (
err == libc::WSAEWOULDBLOCK as i32
}
-pub fn set_nonblocking(fd: sock_t, nb: bool) -> IoResult<()> {
+pub fn set_nonblocking(fd: sock_t, nb: bool) {
let mut set = nb as libc::c_ulong;
- if unsafe { c::ioctlsocket(fd, c::FIONBIO, &mut set) != 0 } {
- Err(last_error())
- } else {
- Ok(())
+ if unsafe { c::ioctlsocket(fd, c::FIONBIO, &mut set) } != 0 {
+ // The above function should not return an error unless we passed it
+ // invalid parameters. Panic on errors.
+ panic!("set_nonblocking called with invalid parameters: {}", last_error());
}
}
fill_utf16_buf_base(f1, f2).map_err(|()| io::Error::last_os_error())
}
-fn os2path(s: &[u16]) -> Path {
- // FIXME: this should not be a panicking conversion (aka path reform)
- Path::new(String::from_utf16(s).unwrap())
+fn os2path(s: &[u16]) -> PathBuf {
+ let os = <OsString as OsStringExt>::from_wide(s);
+ // FIXME(#22751) should consume `os`
+ PathBuf::new(&os)
}
pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use marker::Sync;
+use prelude::v1::*;
+
use cell::UnsafeCell;
use sys::sync as ffi;
inner: UnsafeCell { value: ffi::SRWLOCK_INIT }
};
+unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}
#[inline]
// So you might be asking why we're using SRWLock instead of CriticalSection?
//
-// 1. SRWLock is several times faster than CriticalSection according to benchmarks performed on both
-// Windows 8 and Windows 7.
+// 1. SRWLock is several times faster than CriticalSection according to
+// benchmarks performed on both Windows 8 and Windows 7.
//
-// 2. CriticalSection allows recursive locking while SRWLock deadlocks. The Unix implementation
-// deadlocks so consistency is preferred. See #19962 for more details.
+// 2. CriticalSection allows recursive locking while SRWLock deadlocks. The Unix
+// implementation deadlocks so consistency is preferred. See #19962 for more
+// details.
//
-// 3. While CriticalSection is fair and SRWLock is not, the current Rust policy is there there are
-// no guarantees of fairness.
+// 3. While CriticalSection is fair and SRWLock is not, the current Rust policy
+// is there there are no guarantees of fairness.
impl Mutex {
#[inline]
pub struct Socket(libc::SOCKET);
+/// Checks whether the Windows socket interface has been started already, and
+/// if not, starts it.
pub fn init() {
static START: Once = ONCE_INIT;
});
}
+/// Returns the last error from the Windows socket interface.
fn last_error() -> io::Error {
io::Error::from_os_error(unsafe { c::WSAGetLastError() })
}
+/// Checks if the signed integer is the Windows constant `SOCKET_ERROR` (-1)
+/// and if so, returns the last error from the Windows socket interface. . This
+/// function must be called before another call to the socket API is made.
+///
+/// FIXME: generics needed?
pub fn cvt<T: SignedInt>(t: T) -> io::Result<T> {
let one: T = Int::one();
if t == -one {
}
}
+/// Provides the functionality of `cvt` for the return values of `getaddrinfo`
+/// and similar, meaning that they return an error if the return value is 0.
pub fn cvt_gai(err: c_int) -> io::Result<()> {
if err == 0 { return Ok(()) }
cvt(err).map(|_| ())
}
+/// Provides the functionality of `cvt` for a closure.
pub fn cvt_r<T: SignedInt, F>(mut f: F) -> io::Result<T> where F: FnMut() -> T {
cvt(f())
}
impl Drop for Socket {
fn drop(&mut self) {
- unsafe { let _ = libc::closesocket(self.0); }
+ unsafe { cvt(libc::closesocket(self.0)).unwrap(); }
}
}
use error::Error as StdError;
use ffi::{OsString, OsStr, AsOsStr};
use fmt;
-use ops::Range;
+use io;
use libc::types::os::arch::extra::LPWCH;
use libc::{self, c_int, c_void};
use mem;
use old_io::{IoError, IoResult};
+use ops::Range;
+use path::{self, PathBuf};
use ptr;
use slice;
use sys::c;
}
impl<'a> Iterator for SplitPaths<'a> {
- type Item = Path;
- fn next(&mut self) -> Option<Path> {
+ type Item = PathBuf;
+ fn next(&mut self) -> Option<PathBuf> {
// On Windows, the PATH environment variable is semicolon separated.
// Double quotes are used as a way of introducing literal semicolons
// (since c:\some;dir is a valid Windows path). Double quotes are not
if !must_yield && in_progress.is_empty() {
None
} else {
- Some(super::os2path(&in_progress[..]))
+ Some(super::os2path(&in_progress))
}
}
}
fn description(&self) -> &str { "failed to join paths" }
}
-pub fn current_exe() -> IoResult<Path> {
- super::fill_utf16_buf(|buf, sz| unsafe {
+pub fn current_exe() -> io::Result<PathBuf> {
+ super::fill_utf16_buf_new(|buf, sz| unsafe {
libc::GetModuleFileNameW(ptr::null_mut(), buf, sz)
}, super::os2path)
}
-pub fn getcwd() -> IoResult<Path> {
- super::fill_utf16_buf(|buf, sz| unsafe {
+pub fn getcwd() -> io::Result<PathBuf> {
+ super::fill_utf16_buf_new(|buf, sz| unsafe {
libc::GetCurrentDirectoryW(sz, buf)
}, super::os2path)
}
-pub fn chdir(p: &Path) -> IoResult<()> {
+pub fn chdir(p: &path::Path) -> io::Result<()> {
let mut p = p.as_os_str().encode_wide().collect::<Vec<_>>();
p.push(0);
unsafe {
match libc::SetCurrentDirectoryW(p.as_ptr()) != (0 as libc::BOOL) {
true => Ok(()),
- false => Err(IoError::last_error()),
+ false => Err(io::Error::last_os_error()),
}
}
}
pub fn getenv(k: &OsStr) -> Option<OsString> {
let k = super::to_utf16_os(k);
- super::fill_utf16_buf(|buf, sz| unsafe {
+ super::fill_utf16_buf_new(|buf, sz| unsafe {
libc::GetEnvironmentVariableW(k.as_ptr(), buf, sz)
}, |buf| {
OsStringExt::from_wide(buf)
}
}
-pub fn temp_dir() -> Path {
- super::fill_utf16_buf(|buf, sz| unsafe {
+pub fn temp_dir() -> PathBuf {
+ super::fill_utf16_buf_new(|buf, sz| unsafe {
c::GetTempPathW(sz, buf)
}, super::os2path).unwrap()
}
-pub fn home_dir() -> Option<Path> {
+pub fn home_dir() -> Option<PathBuf> {
getenv("HOME".as_os_str()).or_else(|| {
getenv("USERPROFILE".as_os_str())
}).map(|os| {
- // FIXME: OsString => Path
- Path::new(os.to_str().unwrap())
+ // FIXME(#22751) should consume `os`
+ PathBuf::new(&os)
}).or_else(|| unsafe {
let me = c::GetCurrentProcess();
let mut token = ptr::null_mut();
return None
}
let _handle = RawHandle::new(token);
- super::fill_utf16_buf(|buf, mut sz| {
+ super::fill_utf16_buf_new(|buf, mut sz| {
match c::GetUserProfileDirectoryW(token, buf, &mut sz) {
0 if libc::GetLastError() != 0 => 0,
0 => sz,
use env;
use ffi::{OsString, OsStr};
use fmt;
+use fs;
use io::{self, Error};
use libc::{self, c_void};
-use old_io::fs;
-use old_path;
use os::windows::OsStrExt;
use ptr;
use sync::{StaticMutex, MUTEX_INIT};
+use sys::handle::Handle;
use sys::pipe2::AnonPipe;
use sys::{self, cvt};
-use sys::handle::Handle;
use sys_common::{AsInner, FromInner};
////////////////////////////////////////////////////////////////////////////////
for path in split_paths(&v) {
let path = path.join(cfg.program.to_str().unwrap())
.with_extension(env::consts::EXE_EXTENSION);
- // FIXME: update with new fs module once it lands
- if fs::stat(&old_path::Path::new(&path)).is_ok() {
- return Some(OsString::from_str(path.as_str().unwrap()))
+ if fs::metadata(&path).is_ok() {
+ return Some(path.into_os_string())
}
}
break
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use prelude::v1::*;
+
use cell::UnsafeCell;
use sys::sync as ffi;
inner: UnsafeCell { value: ffi::SRWLOCK_INIT }
};
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {}
+
impl RWLock {
#[inline]
pub unsafe fn read(&self) {
c::WSAEventSelect(socket, events[1], 0)
};
if ret != 0 { return Err(last_net_error()) }
- try!(set_nonblocking(socket, false));
+ set_nonblocking(socket, false);
return Ok(stream)
}
}
pub fn is_tty(fd: c_int) -> bool {
let mut out: DWORD = 0;
- // If this function doesn't panic then fd is a TTY
+ // If this function doesn't return an error, then fd is a TTY
match unsafe { GetConsoleMode(get_osfhandle(fd) as HANDLE,
&mut out as LPDWORD) } {
0 => false,
ExprIndex(P<Expr>, P<Expr>),
ExprRange(Option<P<Expr>>, Option<P<Expr>>),
- /// Variable reference, possibly containing `::` and/or
- /// type parameters, e.g. foo::bar::<baz>
- ExprPath(Path),
- /// A "qualified path", e.g. `<Vec<T> as SomeTrait>::SomeType`
- ExprQPath(P<QPath>),
+ /// Variable reference, possibly containing `::` and/or type
+ /// parameters, e.g. foo::bar::<baz>. Optionally "qualified",
+ /// e.g. `<Vec<T> as SomeTrait>::SomeType`.
+ ExprPath(Option<QSelf>, Path),
ExprAddrOf(Mutability, P<Expr>),
ExprBreak(Option<Ident>),
ExprParen(P<Expr>)
}
-/// A "qualified path":
+/// The explicit Self type in a "qualified path". The actual
+/// path, including the trait and the associated item, is stored
+/// sepparately. `position` represents the index of the associated
+/// item qualified with this Self type.
///
-/// <Vec<T> as SomeTrait>::SomeAssociatedItem
-/// ^~~~~ ^~~~~~~~~ ^~~~~~~~~~~~~~~~~~
-/// self_type trait_name item_path
+/// <Vec<T> as a::b::Trait>::AssociatedItem
+/// ^~~~~ ~~~~~~~~~~~~~~^
+/// ty position = 3
+///
+/// <Vec<T>>::AssociatedItem
+/// ^~~~~ ^
+/// ty position = 0
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct QPath {
- pub self_type: P<Ty>,
- pub trait_ref: P<TraitRef>,
- pub item_path: PathSegment,
+pub struct QSelf {
+ pub ty: P<Ty>,
+ pub position: usize
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
TyBareFn(P<BareFnTy>),
/// A tuple (`(A, B, C, D,...)`)
TyTup(Vec<P<Ty>> ),
- /// A path (`module::module::...::Type`) or primitive
+ /// A path (`module::module::...::Type`), optionally
+ /// "qualified", e.g. `<Vec<T> as SomeTrait>::SomeType`.
///
/// Type parameters are stored in the Path itself
- TyPath(Path, NodeId),
+ TyPath(Option<QSelf>, Path),
/// Something like `A+B`. Note that `B` must always be a path.
TyObjectSum(P<Ty>, TyParamBounds),
/// A type like `for<'a> Foo<&'a Bar>`
TyPolyTraitRef(TyParamBounds),
- /// A "qualified path", e.g. `<Vec<T> as SomeTrait>::SomeType`
- TyQPath(P<QPath>),
/// No-op; kept solely so that we can pretty-print faithfully
TyParen(P<Ty>),
/// Unused for now
}
pub fn is_path(e: P<Expr>) -> bool {
- return match e.node { ExprPath(_) => true, _ => false };
+ match e.node { ExprPath(..) => true, _ => false }
}
/// Get a string representation of a signed int type, with its value.
fn visit_ty(&mut self, typ: &Ty) {
self.operation.visit_id(typ.id);
- if let TyPath(_, id) = typ.node {
- self.operation.visit_id(id);
- }
visit::walk_ty(self, typ)
}
visit::walk_trait_item(self, tm);
}
- fn visit_lifetime_ref(&mut self, lifetime: &'v Lifetime) {
+ fn visit_lifetime_ref(&mut self, lifetime: &Lifetime) {
self.operation.visit_id(lifetime.id);
}
- fn visit_lifetime_def(&mut self, def: &'v LifetimeDef) {
+ fn visit_lifetime_def(&mut self, def: &LifetimeDef) {
self.visit_lifetime_ref(&def.lifetime);
}
+
+ fn visit_trait_ref(&mut self, trait_ref: &TraitRef) {
+ self.operation.visit_id(trait_ref.ref_id);
+ visit::walk_trait_ref(self, trait_ref);
+ }
}
pub fn visit_ids_for_inlined_item<O: IdVisitingOperation>(item: &InlinedItem,
-> ast::Path;
fn qpath(&self, self_type: P<ast::Ty>,
- trait_ref: P<ast::TraitRef>,
- ident: ast::Ident )
- -> P<ast::QPath>;
+ trait_path: ast::Path,
+ ident: ast::Ident)
+ -> (ast::QSelf, ast::Path);
fn qpath_all(&self, self_type: P<ast::Ty>,
- trait_ref: P<ast::TraitRef>,
+ trait_path: ast::Path,
ident: ast::Ident,
lifetimes: Vec<ast::Lifetime>,
types: Vec<P<ast::Ty>>,
- bindings: Vec<P<ast::TypeBinding>> )
- -> P<ast::QPath>;
+ bindings: Vec<P<ast::TypeBinding>>)
+ -> (ast::QSelf, ast::Path);
// types
fn ty_mt(&self, ty: P<ast::Ty>, mutbl: ast::Mutability) -> ast::MutTy;
// expressions
fn expr(&self, span: Span, node: ast::Expr_) -> P<ast::Expr>;
fn expr_path(&self, path: ast::Path) -> P<ast::Expr>;
- fn expr_qpath(&self, span: Span, qpath: P<ast::QPath>) -> P<ast::Expr>;
+ fn expr_qpath(&self, span: Span, qself: ast::QSelf, path: ast::Path) -> P<ast::Expr>;
fn expr_ident(&self, span: Span, id: ast::Ident) -> P<ast::Expr>;
fn expr_self(&self, span: Span) -> P<ast::Expr>;
/// Constructs a qualified path.
///
- /// Constructs a path like `<self_type as trait_ref>::ident`.
+ /// Constructs a path like `<self_type as trait_path>::ident`.
fn qpath(&self,
self_type: P<ast::Ty>,
- trait_ref: P<ast::TraitRef>,
+ trait_path: ast::Path,
ident: ast::Ident)
- -> P<ast::QPath> {
- self.qpath_all(self_type, trait_ref, ident, Vec::new(), Vec::new(), Vec::new())
+ -> (ast::QSelf, ast::Path) {
+ self.qpath_all(self_type, trait_path, ident, vec![], vec![], vec![])
}
/// Constructs a qualified path.
///
- /// Constructs a path like `<self_type as trait_ref>::ident<a, T, A=Bar>`.
+ /// Constructs a path like `<self_type as trait_path>::ident<'a, T, A=Bar>`.
fn qpath_all(&self,
self_type: P<ast::Ty>,
- trait_ref: P<ast::TraitRef>,
+ trait_path: ast::Path,
ident: ast::Ident,
lifetimes: Vec<ast::Lifetime>,
types: Vec<P<ast::Ty>>,
- bindings: Vec<P<ast::TypeBinding>> )
- -> P<ast::QPath> {
- let segment = ast::PathSegment {
+ bindings: Vec<P<ast::TypeBinding>>)
+ -> (ast::QSelf, ast::Path) {
+ let mut path = trait_path;
+ path.segments.push(ast::PathSegment {
identifier: ident,
parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
lifetimes: lifetimes,
types: OwnedSlice::from_vec(types),
bindings: OwnedSlice::from_vec(bindings),
})
- };
+ });
- P(ast::QPath {
- self_type: self_type,
- trait_ref: trait_ref,
- item_path: segment,
- })
+ (ast::QSelf {
+ ty: self_type,
+ position: path.segments.len() - 1
+ }, path)
}
fn ty_mt(&self, ty: P<ast::Ty>, mutbl: ast::Mutability) -> ast::MutTy {
}
fn ty_path(&self, path: ast::Path) -> P<ast::Ty> {
- self.ty(path.span, ast::TyPath(path, ast::DUMMY_NODE_ID))
+ self.ty(path.span, ast::TyPath(None, path))
}
fn ty_sum(&self, path: ast::Path, bounds: OwnedSlice<ast::TyParamBound>) -> P<ast::Ty> {
}
fn expr_path(&self, path: ast::Path) -> P<ast::Expr> {
- self.expr(path.span, ast::ExprPath(path))
+ self.expr(path.span, ast::ExprPath(None, path))
}
/// Constructs a QPath expression.
- fn expr_qpath(&self, span: Span, qpath: P<ast::QPath>) -> P<ast::Expr> {
- self.expr(span, ast::ExprQPath(qpath))
+ fn expr_qpath(&self, span: Span, qself: ast::QSelf, path: ast::Path) -> P<ast::Expr> {
+ self.expr(span, ast::ExprPath(Some(qself), path))
}
fn expr_ident(&self, span: Span, id: ast::Ident) -> P<ast::Expr> {
let e = P(ast::Expr {
id: ast::DUMMY_NODE_ID,
- node: ast::ExprPath(
+ node: ast::ExprPath(None,
ast::Path {
span: sp,
global: false,
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec!(borrowed_self()),
- ret_ty: Literal(path!(bool)),
+ ret_ty: Literal(path_local!(bool)),
attributes: attrs,
combine_substructure: combine_substructure(box |a, b, c| {
$f(a, b, c)
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec!(borrowed_self()),
- ret_ty: Literal(path!(bool)),
+ ret_ty: Literal(path_local!(bool)),
attributes: attrs,
combine_substructure: combine_substructure(box |cx, span, substr| {
cs_op($op, $equal, cx, span, substr)
)
}
+macro_rules! path_local {
+ ($x:ident) => (
+ ::ext::deriving::generic::ty::Path::new_local(stringify!($x))
+ )
+}
+
macro_rules! pathvec_std {
($cx:expr, $first:ident :: $($rest:ident)::+) => (
if $cx.use_std {
name: "from_i64",
generics: LifetimeBounds::empty(),
explicit_self: None,
- args: vec!(Literal(path!(i64))),
+ args: vec!(Literal(path_local!(i64))),
ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option),
None,
vec!(box Self_),
name: "from_u64",
generics: LifetimeBounds::empty(),
explicit_self: None,
- args: vec!(Literal(path!(u64))),
+ args: vec!(Literal(path_local!(u64))),
ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option),
None,
vec!(box Self_),
debug!("expanding type {:?} with impl_ty {:?}", t, impl_ty);
let t = match (t.node.clone(), impl_ty) {
// Expand uses of `Self` in impls to the concrete type.
- (ast::Ty_::TyPath(ref path, _), Some(ref impl_ty)) => {
+ (ast::Ty_::TyPath(None, ref path), Some(ref impl_ty)) => {
let path_as_ident = path_to_ident(path);
// Note unhygenic comparison here. I think this is correct, since
// even though `Self` is almost just a type parameter, the treatment
impl<'v> Visitor<'v> for PathExprFinderContext {
fn visit_expr(&mut self, expr: &ast::Expr) {
- match expr.node {
- ast::ExprPath(ref p) => {
- self.path_accumulator.push(p.clone());
- // not calling visit_path, but it should be fine.
- }
- _ => visit::walk_expr(self, expr)
+ if let ast::ExprPath(None, ref p) = expr.node {
+ self.path_accumulator.push(p.clone());
}
+ visit::walk_expr(self, expr);
}
}
let renamed_crate = renamer.fold_crate(the_crate);
let idents = crate_idents(&renamed_crate);
let resolved : Vec<ast::Name> = idents.iter().map(|id| mtwt::resolve(*id)).collect();
- assert_eq!(resolved,vec!(f_ident.name,Name(16),int_ident.name,Name(16),Name(16),Name(16)));
+ assert_eq!(resolved, [f_ident.name,Name(16),int_ident.name,Name(16),Name(16),Name(16)]);
}
// test the PatIdentRenamer; only PatIdents get renamed
let idents = crate_idents(&renamed_crate);
let resolved : Vec<ast::Name> = idents.iter().map(|id| mtwt::resolve(*id)).collect();
let x_name = x_ident.name;
- assert_eq!(resolved,vec!(f_ident.name,Name(16),int_ident.name,Name(16),x_name,x_name));
+ assert_eq!(resolved, [f_ident.name,Name(16),int_ident.name,Name(16),x_name,x_name]);
}
-
-
}
fn xorpush_test () {
let mut s = Vec::new();
xor_push(&mut s, 14);
- assert_eq!(s.clone(), vec!(14));
+ assert_eq!(s.clone(), [14]);
xor_push(&mut s, 14);
- assert_eq!(s.clone(), Vec::new());
+ assert_eq!(s.clone(), []);
xor_push(&mut s, 14);
- assert_eq!(s.clone(), vec!(14));
+ assert_eq!(s.clone(), [14]);
xor_push(&mut s, 15);
- assert_eq!(s.clone(), vec!(14, 15));
+ assert_eq!(s.clone(), [14, 15]);
xor_push(&mut s, 16);
- assert_eq!(s.clone(), vec!(14, 15, 16));
+ assert_eq!(s.clone(), [14, 15, 16]);
xor_push(&mut s, 16);
- assert_eq!(s.clone(), vec!(14, 15));
+ assert_eq!(s.clone(), [14, 15]);
xor_push(&mut s, 15);
- assert_eq!(s.clone(), vec!(14));
+ assert_eq!(s.clone(), [14]);
}
fn id(n: u32, s: SyntaxContext) -> Ident {
assert_eq!(marksof_internal (EMPTY_CTXT,stopname,&t),Vec::new());
// FIXME #5074: ANF'd to dodge nested calls
{ let ans = unfold_marks(vec!(4,98),EMPTY_CTXT,&mut t);
- assert_eq! (marksof_internal (ans,stopname,&t),vec!(4,98));}
+ assert_eq! (marksof_internal (ans,stopname,&t), [4, 98]);}
// does xoring work?
{ let ans = unfold_marks(vec!(5,5,16),EMPTY_CTXT,&mut t);
- assert_eq! (marksof_internal (ans,stopname,&t), vec!(16));}
+ assert_eq! (marksof_internal (ans,stopname,&t), [16]);}
// does nested xoring work?
{ let ans = unfold_marks(vec!(5,10,10,5,16),EMPTY_CTXT,&mut t);
- assert_eq! (marksof_internal (ans, stopname,&t), vec!(16));}
+ assert_eq! (marksof_internal (ans, stopname,&t), [16]);}
// rename where stop doesn't match:
{ let chain = vec!(M(9),
R(id(name1.usize() as u32,
Name(100101102)),
M(14));
let ans = unfold_test_sc(chain,EMPTY_CTXT,&mut t);
- assert_eq! (marksof_internal (ans, stopname, &t), vec!(9,14));}
+ assert_eq! (marksof_internal (ans, stopname, &t), [9, 14]);}
// rename where stop does match
{ let name1sc = apply_mark_internal(4, EMPTY_CTXT, &mut t);
let chain = vec!(M(9),
stopname),
M(14));
let ans = unfold_test_sc(chain,EMPTY_CTXT,&mut t);
- assert_eq! (marksof_internal (ans, stopname, &t), vec!(9)); }
+ assert_eq! (marksof_internal (ans, stopname, &t), [9]); }
}
("static_assert", Whitelisted),
("no_debug", Whitelisted),
("omit_gdb_pretty_printer_section", Whitelisted),
- ("unsafe_no_drop_flag", Whitelisted),
+ ("unsafe_no_drop_flag", Gated("unsafe_no_drop_flag",
+ "unsafe_no_drop_flag has unstable semantics \
+ and may be removed in the future")),
// used in resolve
("prelude_import", Whitelisted),
fn visit_ty(&mut self, t: &ast::Ty) {
match t.node {
- ast::TyPath(ref p, _) => {
+ ast::TyPath(None, ref p) => {
match &*p.segments {
[ast::PathSegment { identifier, .. }] => {
noop_fold_ty(t, self)
}
- fn fold_qpath(&mut self, t: P<QPath>) -> P<QPath> {
- noop_fold_qpath(t, self)
- }
-
fn fold_ty_binding(&mut self, t: P<TypeBinding>) -> P<TypeBinding> {
noop_fold_ty_binding(t, self)
}
}
TyTup(tys) => TyTup(tys.move_map(|ty| fld.fold_ty(ty))),
TyParen(ty) => TyParen(fld.fold_ty(ty)),
- TyPath(path, id) => {
- let id = fld.new_id(id);
- TyPath(fld.fold_path(path), id)
+ TyPath(qself, path) => {
+ let qself = qself.map(|QSelf { ty, position }| {
+ QSelf {
+ ty: fld.fold_ty(ty),
+ position: position
+ }
+ });
+ TyPath(qself, fld.fold_path(path))
}
TyObjectSum(ty, bounds) => {
TyObjectSum(fld.fold_ty(ty),
fld.fold_bounds(bounds))
}
- TyQPath(qpath) => {
- TyQPath(fld.fold_qpath(qpath))
- }
TyFixedLengthVec(ty, e) => {
TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e))
}
})
}
-pub fn noop_fold_qpath<T: Folder>(qpath: P<QPath>, fld: &mut T) -> P<QPath> {
- qpath.map(|qpath| {
- QPath {
- self_type: fld.fold_ty(qpath.self_type),
- trait_ref: qpath.trait_ref.map(|tr| fld.fold_trait_ref(tr)),
- item_path: PathSegment {
- identifier: fld.fold_ident(qpath.item_path.identifier),
- parameters: fld.fold_path_parameters(qpath.item_path.parameters),
- }
- }
- })
-}
-
pub fn noop_fold_foreign_mod<T: Folder>(ForeignMod {abi, items}: ForeignMod,
fld: &mut T) -> ForeignMod {
ForeignMod {
ExprRange(e1.map(|x| folder.fold_expr(x)),
e2.map(|x| folder.fold_expr(x)))
}
- ExprPath(pth) => ExprPath(folder.fold_path(pth)),
- ExprQPath(qpath) => ExprQPath(folder.fold_qpath(qpath)),
+ ExprPath(qself, path) => {
+ let qself = qself.map(|QSelf { ty, position }| {
+ QSelf {
+ ty: folder.fold_ty(ty),
+ position: position
+ }
+ });
+ ExprPath(qself, folder.fold_path(path))
+ }
ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|x| folder.fold_ident(x))),
ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|x| folder.fold_ident(x))),
ExprRet(e) => ExprRet(e.map(|x| folder.fold_expr(x))),
assert!(string_to_expr("a".to_string()) ==
P(ast::Expr{
id: ast::DUMMY_NODE_ID,
- node: ast::ExprPath(ast::Path {
+ node: ast::ExprPath(None, ast::Path {
span: sp(0, 1),
global: false,
segments: vec!(
assert!(string_to_expr("::a::b".to_string()) ==
P(ast::Expr {
id: ast::DUMMY_NODE_ID,
- node: ast::ExprPath(ast::Path {
+ node: ast::ExprPath(None, ast::Path {
span: sp(0, 6),
global: true,
segments: vec!(
id: ast::DUMMY_NODE_ID,
node:ast::ExprRet(Some(P(ast::Expr{
id: ast::DUMMY_NODE_ID,
- node:ast::ExprPath(ast::Path{
+ node:ast::ExprPath(None, ast::Path{
span: sp(7, 8),
global: false,
segments: vec!(
P(Spanned{
node: ast::StmtExpr(P(ast::Expr {
id: ast::DUMMY_NODE_ID,
- node: ast::ExprPath(ast::Path {
+ node: ast::ExprPath(None, ast::Path {
span:sp(0,1),
global:false,
segments: vec!(
node: ast::ItemFn(P(ast::FnDecl {
inputs: vec!(ast::Arg{
ty: P(ast::Ty{id: ast::DUMMY_NODE_ID,
- node: ast::TyPath(ast::Path{
+ node: ast::TyPath(None, ast::Path{
span:sp(10,13),
global:false,
segments: vec!(
parameters: ast::PathParameters::none(),
}
),
- }, ast::DUMMY_NODE_ID),
+ }),
span:sp(10,13)
}),
pat: P(ast::Pat {
stmts: vec!(P(Spanned{
node: ast::StmtSemi(P(ast::Expr{
id: ast::DUMMY_NODE_ID,
- node: ast::ExprPath(
+ node: ast::ExprPath(None,
ast::Path{
span:sp(17,18),
global:false,
use ast::{ExprBreak, ExprCall, ExprCast};
use ast::{ExprField, ExprTupField, ExprClosure, ExprIf, ExprIfLet, ExprIndex};
use ast::{ExprLit, ExprLoop, ExprMac, ExprRange};
-use ast::{ExprMethodCall, ExprParen, ExprPath, ExprQPath};
+use ast::{ExprMethodCall, ExprParen, ExprPath};
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl};
use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod, FunctionRetTy};
use ast::{Pat, PatEnum, PatIdent, PatLit, PatRange, PatRegion, PatStruct};
use ast::{PatTup, PatBox, PatWild, PatWildMulti, PatWildSingle};
use ast::{PolyTraitRef};
-use ast::{QPath, RequiredMethod};
+use ast::{QSelf, RequiredMethod};
use ast::{Return, BiShl, BiShr, Stmt, StmtDecl};
use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField};
use ast::{StructVariantKind, BiSub, StrStyle};
use ast::{TupleVariantKind, Ty, Ty_, TypeBinding};
use ast::{TyFixedLengthVec, TyBareFn};
use ast::{TyTypeof, TyInfer, TypeMethod};
-use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath};
+use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr};
use ast::{TyRptr, TyTup, TyU32, TyVec, UnUniq};
use ast::{TypeImplItem, TypeTraitItem, Typedef,};
use ast::{UnnamedField, UnsafeBlock};
_ => unreachable!()
};
let span = $p.span;
- Some($p.mk_expr(span.lo, span.hi, ExprPath(pt)))
+ Some($p.mk_expr(span.lo, span.hi, ExprPath(None, pt)))
}
token::Interpolated(token::NtBlock(_)) => {
// FIXME: The following avoids an issue with lexical borrowck scopes,
}
pub fn parse_ty_path(&mut self) -> Ty_ {
- let path = self.parse_path(LifetimeAndTypesWithoutColons);
- TyPath(path, ast::DUMMY_NODE_ID)
+ TyPath(None, self.parse_path(LifetimeAndTypesWithoutColons))
}
/// parse a TyBareFn type:
} else if self.eat_lt() {
// QUALIFIED PATH `<TYPE as TRAIT_REF>::item`
let self_type = self.parse_ty_sum();
- self.expect_keyword(keywords::As);
- let trait_ref = self.parse_trait_ref();
+
+ let mut path = if self.eat_keyword(keywords::As) {
+ self.parse_path(LifetimeAndTypesWithoutColons)
+ } else {
+ ast::Path {
+ span: self.span,
+ global: false,
+ segments: vec![]
+ }
+ };
+
+ let qself = QSelf {
+ ty: self_type,
+ position: path.segments.len()
+ };
+
self.expect(&token::Gt);
self.expect(&token::ModSep);
- let item_name = self.parse_ident();
- TyQPath(P(QPath {
- self_type: self_type,
- trait_ref: P(trait_ref),
- item_path: ast::PathSegment {
- identifier: item_name,
- parameters: ast::PathParameters::none()
- }
- }))
+
+ path.segments.push(ast::PathSegment {
+ identifier: self.parse_ident(),
+ parameters: ast::PathParameters::none()
+ });
+
+ if path.segments.len() == 1 {
+ path.span.lo = self.last_span.lo;
+ }
+ path.span.hi = self.last_span.hi;
+
+ TyPath(Some(qself), path)
} else if self.check(&token::ModSep) ||
self.token.is_ident() ||
self.token.is_path() {
}, token::Plain) => {
self.bump();
let path = ast_util::ident_to_path(mk_sp(lo, hi), id);
- ex = ExprPath(path);
+ ex = ExprPath(None, path);
hi = self.last_span.hi;
}
token::OpenDelim(token::Bracket) => {
if self.eat_lt() {
// QUALIFIED PATH `<TYPE as TRAIT_REF>::item::<'a, T>`
let self_type = self.parse_ty_sum();
- self.expect_keyword(keywords::As);
- let trait_ref = self.parse_trait_ref();
+ let mut path = if self.eat_keyword(keywords::As) {
+ self.parse_path(LifetimeAndTypesWithoutColons)
+ } else {
+ ast::Path {
+ span: self.span,
+ global: false,
+ segments: vec![]
+ }
+ };
+ let qself = QSelf {
+ ty: self_type,
+ position: path.segments.len()
+ };
self.expect(&token::Gt);
self.expect(&token::ModSep);
+
let item_name = self.parse_ident();
let parameters = if self.eat(&token::ModSep) {
self.expect_lt();
} else {
ast::PathParameters::none()
};
+ path.segments.push(ast::PathSegment {
+ identifier: item_name,
+ parameters: parameters
+ });
+
+ if path.segments.len() == 1 {
+ path.span.lo = self.last_span.lo;
+ }
+ path.span.hi = self.last_span.hi;
+
let hi = self.span.hi;
- return self.mk_expr(lo, hi, ExprQPath(P(QPath {
- self_type: self_type,
- trait_ref: P(trait_ref),
- item_path: ast::PathSegment {
- identifier: item_name,
- parameters: parameters
- }
- })));
+ return self.mk_expr(lo, hi, ExprPath(Some(qself), path));
}
if self.eat_keyword(keywords::Move) {
return self.parse_lambda_expr(CaptureByValue);
}
hi = pth.span.hi;
- ex = ExprPath(pth);
+ ex = ExprPath(None, pth);
} else {
// other literal expression
let lit = self.parse_lit();
let end = if self.token.is_ident() || self.token.is_path() {
let path = self.parse_path(LifetimeAndTypesWithColons);
let hi = self.span.hi;
- self.mk_expr(lo, hi, ExprPath(path))
+ self.mk_expr(lo, hi, ExprPath(None, path))
} else {
self.parse_literal_maybe_minus()
};
let opt_trait = if could_be_trait && self.eat_keyword(keywords::For) {
// New-style trait. Reinterpret the type as a trait.
match ty.node {
- TyPath(ref path, node_id) => {
+ TyPath(None, ref path) => {
Some(TraitRef {
path: (*path).clone(),
- ref_id: node_id,
+ ref_id: ty.id,
})
}
_ => {
}
pub fn path_to_string(p: &ast::Path) -> String {
- $to_string(|s| s.print_path(p, false))
+ $to_string(|s| s.print_path(p, false, 0))
}
pub fn ident_to_string(id: &ast::Ident) -> String {
&generics,
None));
}
- ast::TyPath(ref path, _) => {
- try!(self.print_path(path, false));
+ ast::TyPath(None, ref path) => {
+ try!(self.print_path(path, false, 0));
+ }
+ ast::TyPath(Some(ref qself), ref path) => {
+ try!(self.print_qpath(path, qself, false))
}
ast::TyObjectSum(ref ty, ref bounds) => {
try!(self.print_type(&**ty));
ast::TyPolyTraitRef(ref bounds) => {
try!(self.print_bounds("", &bounds[..]));
}
- ast::TyQPath(ref qpath) => {
- try!(self.print_qpath(&**qpath, false))
- }
ast::TyFixedLengthVec(ref ty, ref v) => {
try!(word(&mut self.s, "["));
try!(self.print_type(&**ty));
ast::ItemMac(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _),
..}) => {
try!(self.print_visibility(item.vis));
- try!(self.print_path(pth, false));
+ try!(self.print_path(pth, false, 0));
try!(word(&mut self.s, "! "));
try!(self.print_ident(item.ident));
try!(self.cbox(indent_unit));
}
fn print_trait_ref(&mut self, t: &ast::TraitRef) -> IoResult<()> {
- self.print_path(&t.path, false)
+ self.print_path(&t.path, false, 0)
}
fn print_formal_lifetime_list(&mut self, lifetimes: &[ast::LifetimeDef]) -> IoResult<()> {
ast::MethMac(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _),
..}) => {
// code copied from ItemMac:
- try!(self.print_path(pth, false));
+ try!(self.print_path(pth, false, 0));
try!(word(&mut self.s, "! "));
try!(self.cbox(indent_unit));
try!(self.popen());
match m.node {
// I think it's reasonable to hide the ctxt here:
ast::MacInvocTT(ref pth, ref tts, _) => {
- try!(self.print_path(pth, false));
+ try!(self.print_path(pth, false, 0));
try!(word(&mut self.s, "!"));
match delim {
token::Paren => try!(self.popen()),
path: &ast::Path,
fields: &[ast::Field],
wth: &Option<P<ast::Expr>>) -> IoResult<()> {
- try!(self.print_path(path, true));
+ try!(self.print_path(path, true, 0));
if !(fields.is_empty() && wth.is_none()) {
try!(word(&mut self.s, "{"));
try!(self.commasep_cmnt(
try!(self.print_expr(&**e));
}
}
- ast::ExprPath(ref path) => try!(self.print_path(path, true)),
- ast::ExprQPath(ref qpath) => try!(self.print_qpath(&**qpath, true)),
+ ast::ExprPath(None, ref path) => {
+ try!(self.print_path(path, true, 0))
+ }
+ ast::ExprPath(Some(ref qself), ref path) => {
+ try!(self.print_qpath(path, qself, true))
+ }
ast::ExprBreak(opt_ident) => {
try!(word(&mut self.s, "break"));
try!(space(&mut self.s));
fn print_path(&mut self,
path: &ast::Path,
- colons_before_params: bool)
+ colons_before_params: bool,
+ depth: usize)
-> IoResult<()>
{
try!(self.maybe_print_comment(path.span.lo));
- if path.global {
- try!(word(&mut self.s, "::"));
- }
- let mut first = true;
- for segment in &path.segments {
+ let mut first = !path.global;
+ for segment in &path.segments[..path.segments.len()-depth] {
if first {
first = false
} else {
}
fn print_qpath(&mut self,
- qpath: &ast::QPath,
+ path: &ast::Path,
+ qself: &ast::QSelf,
colons_before_params: bool)
-> IoResult<()>
{
try!(word(&mut self.s, "<"));
- try!(self.print_type(&*qpath.self_type));
- try!(space(&mut self.s));
- try!(self.word_space("as"));
- try!(self.print_trait_ref(&*qpath.trait_ref));
+ try!(self.print_type(&qself.ty));
+ if qself.position > 0 {
+ try!(space(&mut self.s));
+ try!(self.word_space("as"));
+ let depth = path.segments.len() - qself.position;
+ try!(self.print_path(&path, false, depth));
+ }
try!(word(&mut self.s, ">"));
try!(word(&mut self.s, "::"));
- try!(self.print_ident(qpath.item_path.identifier));
- self.print_path_parameters(&qpath.item_path.parameters, colons_before_params)
+ let item_segment = path.segments.last().unwrap();
+ try!(self.print_ident(item_segment.identifier));
+ self.print_path_parameters(&item_segment.parameters, colons_before_params)
}
fn print_path_parameters(&mut self,
}
}
ast::PatEnum(ref path, ref args_) => {
- try!(self.print_path(path, true));
+ try!(self.print_path(path, true, 0));
match *args_ {
None => try!(word(&mut self.s, "(..)")),
Some(ref args) => {
}
}
ast::PatStruct(ref path, ref fields, etc) => {
- try!(self.print_path(path, true));
+ try!(self.print_path(path, true, 0));
try!(self.nbsp());
try!(self.word_space("{"));
try!(self.commasep_cmnt(
}
}
&ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => {
- try!(self.print_path(path, false));
+ try!(self.print_path(path, false, 0));
try!(space(&mut self.s));
try!(self.word_space("="));
try!(self.print_type(&**ty));
pub fn print_view_path(&mut self, vp: &ast::ViewPath) -> IoResult<()> {
match vp.node {
ast::ViewPathSimple(ident, ref path) => {
- try!(self.print_path(path, false));
+ try!(self.print_path(path, false, 0));
// FIXME(#6993) can't compare identifiers directly here
if path.segments.last().unwrap().identifier.name !=
}
ast::ViewPathGlob(ref path) => {
- try!(self.print_path(path, false));
+ try!(self.print_path(path, false, 0));
word(&mut self.s, "::*")
}
if path.segments.is_empty() {
try!(word(&mut self.s, "{"));
} else {
- try!(self.print_path(path, false));
+ try!(self.print_path(path, false, 0));
try!(word(&mut self.s, "::{"));
}
try!(self.commasep(Inconsistent, &idents[..], |s, w| {
assert_eq!(Vec::new(), v);
let v = SmallVector::one(1);
- assert_eq!(vec![1], v.into_iter().collect::<Vec<_>>());
+ assert_eq!([1], v.into_iter().collect::<Vec<_>>());
let v = SmallVector::many(vec![1, 2, 3]);
- assert_eq!(vec!(1, 2, 3), v.into_iter().collect::<Vec<_>>());
+ assert_eq!([1, 2, 3], v.into_iter().collect::<Vec<_>>());
}
#[test]
fn visit_path(&mut self, path: &'v Path, _id: ast::NodeId) {
walk_path(self, path)
}
- fn visit_qpath(&mut self, qpath_span: Span, qpath: &'v QPath) {
- walk_qpath(self, qpath_span, qpath)
- }
fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment) {
walk_path_segment(self, path_span, path_segment)
}
walk_fn_ret_ty(visitor, &function_declaration.decl.output);
walk_lifetime_decls_helper(visitor, &function_declaration.lifetimes);
}
- TyPath(ref path, id) => {
- visitor.visit_path(path, id);
+ TyPath(ref maybe_qself, ref path) => {
+ if let Some(ref qself) = *maybe_qself {
+ visitor.visit_ty(&qself.ty);
+ }
+ visitor.visit_path(path, typ.id);
}
TyObjectSum(ref ty, ref bounds) => {
visitor.visit_ty(&**ty);
walk_ty_param_bounds_helper(visitor, bounds);
}
- TyQPath(ref qpath) => {
- visitor.visit_qpath(typ.span, &**qpath);
- }
TyFixedLengthVec(ref ty, ref expression) => {
visitor.visit_ty(&**ty);
visitor.visit_expr(&**expression)
}
}
-pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V,
- qpath_span: Span,
- qpath: &'v QPath) {
- visitor.visit_ty(&*qpath.self_type);
- visitor.visit_trait_ref(&*qpath.trait_ref);
- visitor.visit_path_segment(qpath_span, &qpath.item_path);
-}
-
pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V,
path_span: Span,
segment: &'v PathSegment) {
walk_expr_opt(visitor, start);
walk_expr_opt(visitor, end)
}
- ExprPath(ref path) => {
+ ExprPath(ref maybe_qself, ref path) => {
+ if let Some(ref qself) = *maybe_qself {
+ visitor.visit_ty(&qself.ty);
+ }
visitor.visit_path(path, expression.id)
}
- ExprQPath(ref qpath) => {
- visitor.visit_qpath(expression.span, &**qpath)
- }
ExprBreak(_) | ExprAgain(_) => {}
ExprRet(ref optional_expression) => {
walk_expr_opt(visitor, optional_expression)
#![feature(unicode)]
#![feature(std_misc)]
#![feature(env)]
+#![feature(os)]
#![cfg_attr(windows, feature(libc))]
#[macro_use] extern crate log;
let s = format!("%{{1}}%{{2}}%{}%d", op);
let res = expand(s.as_bytes(), &[], &mut Variables::new());
assert!(res.is_ok(), res.err().unwrap());
- assert_eq!(res.unwrap(), vec!(b'0' + bs[0]));
+ assert_eq!(res.unwrap(), [b'0' + bs[0]]);
let s = format!("%{{1}}%{{1}}%{}%d", op);
let res = expand(s.as_bytes(), &[], &mut Variables::new());
assert!(res.is_ok(), res.err().unwrap());
- assert_eq!(res.unwrap(), vec!(b'0' + bs[1]));
+ assert_eq!(res.unwrap(), [b'0' + bs[1]]);
let s = format!("%{{2}}%{{1}}%{}%d", op);
let res = expand(s.as_bytes(), &[], &mut Variables::new());
assert!(res.is_ok(), res.err().unwrap());
- assert_eq!(res.unwrap(), vec!(b'0' + bs[2]));
+ assert_eq!(res.unwrap(), [b'0' + bs[2]]);
}
}
use std::env;
/// Return path to database entry for `term`
+#[allow(deprecated)]
pub fn get_dbpath_for_term(term: &str) -> Option<Box<Path>> {
if term.len() == 0 {
return None;
}
- let homedir = env::home_dir();
+ let homedir = ::std::os::homedir();
let mut dirs_to_search = Vec::new();
let first_char = term.char_at(0);
//! Implementation of the `build` subcommand, used to compile a book.
use std::env;
+use std::os;
use std::old_io;
use std::old_io::{fs, File, BufferedWriter, TempDir, IoResult};
let src;
if env::args().len() < 3 {
- src = env::current_dir().unwrap().clone();
+ src = os::getcwd().unwrap().clone();
} else {
src = Path::new(env::args().nth(2).unwrap().clone());
}
}
fn usage(&self) {}
fn execute(&mut self, term: &mut Term) -> CommandResult<()> {
- let cwd = env::current_dir().unwrap();
+ let cwd = os::getcwd().unwrap();
let src;
let tgt;
#![feature(core)]
#![feature(old_io)]
#![feature(env)]
+#![feature(os)]
#![feature(old_path)]
#![feature(rustdoc)]
use term::Term;
use book;
use std::old_io::{Command, File};
-use std::env;
+use std::os;
struct Test;
}
fn usage(&self) {}
fn execute(&mut self, term: &mut Term) -> CommandResult<()> {
- let cwd = env::current_dir().unwrap();
+ let cwd = os::getcwd().unwrap();
let src = cwd.clone();
let summary = File::open(&src.join("SUMMARY.md"));
--- /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 equality constraints in a where clause where the type being
+// equated appears in a supertrait.
+
+pub trait Vehicle {
+ type Color;
+
+ fn go(&self) { }
+}
+
+pub trait Box {
+ type Color;
+
+ fn mail(&self) { }
+}
+
+fn a<C:Vehicle+Box>(_: C::Color) {
+ //~^ ERROR ambiguous associated type `Color` in bounds of `C`
+}
+
+fn b<C>(_: C::Color) where C : Vehicle+Box {
+ //~^ ERROR ambiguous associated type `Color` in bounds of `C`
+}
+
+fn c<C>(_: C::Color) where C : Vehicle, C : Box {
+ //~^ ERROR ambiguous associated type `Color` in bounds of `C`
+}
+
+struct D<X>;
+impl<X> D<X> where X : Vehicle {
+ fn d(&self, _: X::Color) where X : Box { }
+ //~^ ERROR ambiguous associated type `Color` in bounds of `X`
+}
+
+trait E<X:Vehicle> {
+ fn e(&self, _: X::Color) where X : Box;
+ //~^ ERROR ambiguous associated type `Color` in bounds of `X`
+
+ fn f(&self, _: X::Color) where X : Box { }
+ //~^ ERROR ambiguous associated type `Color` in bounds of `X`
+}
+
+pub fn main() { }
//~^ ERROR ambiguous associated type
}
+type X = std::ops::Deref::Target;
+//~^ ERROR ambiguous associated type
+
fn main() {
}
//~^ ERROR too many type parameters provided
let _ = S::<'a,isize>::new::<f64>(1, 1.0);
- //~^ ERROR too many lifetime parameters provided
+ //~^ ERROR wrong number of lifetime parameters
let _: S2 = Trait::new::<isize,f64>(1, 1.0);
//~^ ERROR too many type parameters provided
--- /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.
+
+// Check that we check fns appearing in constant declarations.
+// Issue #22382.
+
+const MOVE: fn(&String) -> String = {
+ fn broken(x: &String) -> String {
+ return *x //~ ERROR cannot move
+ }
+ broken
+};
+
+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.
+
+// Check that we check fns appearing in constant declarations.
+// Issue #22382.
+
+// How about mutating an immutable vector?
+const MUTATE: fn(&Vec<String>) = {
+ fn broken(x: &Vec<String>) {
+ x.push(format!("this is broken"));
+ //~^ ERROR cannot borrow
+ }
+ broken
+};
+
+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.
+
+// Check that we check fns appearing in constant declarations.
+// Issue #22382.
+
+// Returning local references?
+struct DropString {
+ inner: String
+}
+impl Drop for DropString {
+ fn drop(&mut self) {
+ self.inner.clear();
+ self.inner.push_str("dropped");
+ }
+}
+const LOCAL_REF: fn() -> &'static str = {
+ fn broken() -> &'static str {
+ let local = DropString { inner: format!("Some local string") };
+ return &local.inner; //~ ERROR does not live long enough
+ }
+ broken
+};
+
+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.
+
+// Example cycle where a bound on `T` uses a shorthand for `T`. This
+// creates a cycle because we have to know the bounds on `T` to figure
+// out what trait defines `Item`, but we can't know the bounds on `T`
+// without knowing how to handle `T::Item`.
+//
+// Note that in the future cases like this could perhaps become legal,
+// if we got more fine-grained about our cycle detection or changed
+// how we handle `T::Item` resolution.
+
+use std::ops::Add;
+
+// Preamble.
+trait Trait { type Item; }
+
+struct A<T>
+ where T : Trait,
+ T : Add<T::Item>
+ //~^ ERROR illegal recursive type
+{
+ data: 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 a supertrait cycle where a trait extends itself.
+
+trait Chromosome: Chromosome {
+ //~^ ERROR unsupported cyclic reference
+}
+
+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 a supertrait cycle where the first trait we find (`A`) is not
+// a direct participant in the cycle.
+
+trait A: B {
+}
+
+trait B: C { }
+
+trait C: B { }
+ //~^ ERROR unsupported cyclic reference
+
+fn main() { }
// Unresolved bounds should still error.
fn align_of<T: NoSuchTrait>() -> usize;
- //~^ ERROR attempt to bound type parameter with a nonexistent trait `NoSuchTrait`
+ //~^ ERROR use of undeclared trait name `NoSuchTrait`
}
fn main() {}
fn main() {
Foo::<isize>::new();
- //~^ ERROR too few type parameters provided
+ //~^ ERROR wrong number of type arguments
}
fn main() {
Vec::<isize, Heap, bool>::new();
- //~^ ERROR too many type parameters provided
+ //~^ ERROR wrong number of type arguments
}
import(); //~ ERROR: unresolved
foo::<A>(); //~ ERROR: undeclared
- //~^ ERROR: undeclared
foo::<C>(); //~ ERROR: undeclared
- //~^ ERROR: undeclared
foo::<D>(); //~ ERROR: undeclared
- //~^ ERROR: undeclared
}
struct Foo;
impl Foo {
fn orange(&self){}
- fn orange(&self){} //~ ERROR error: duplicate definition of value `orange`
+ fn orange(&self){} //~ ERROR error: duplicate method in trait impl
}
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.
-
-mod foo {
- pub struct Foo {
- x: isize,
- y: isize,
- }
-}
-
-impl foo::Foo {
-//~^ ERROR implementations may only be implemented in the same module
- fn bar() {}
-}
-
-fn main() {}
-
fn foo<T>() {
static a: Bar<T> = Bar::What;
- //~^ ERROR: cannot use an outer type parameter in this context
+ //~^ ERROR cannot use an outer type parameter in this context
+ //~| ERROR use of undeclared type name `T`
}
fn main() {
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-tidy-linelength
-
-pub struct Foo;
-
-mod bar {
- use Foo;
-
- impl Foo { //~ERROR inherent implementations are only allowed on types defined in the current module
- fn baz(&self) {}
- }
-}
-fn main() {}
-
fn main() {
a::Foo::new();
- //~^ ERROR: static method `new` is inaccessible
+ //~^ ERROR: method `new` is inaccessible
//~^^ NOTE: struct `Foo` is private
a::Bar::new();
- //~^ ERROR: static method `new` is inaccessible
+ //~^ ERROR: method `new` is inaccessible
//~^^ NOTE: enum `Bar` is private
}
baz();
//~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`?
a;
- //~^ ERROR: unresolved name `a`. Did you mean to call `BarTy::a`?
+ //~^ ERROR: unresolved name `a`
}
}
y;
//~^ ERROR: unresolved name `y`. Did you mean `self.y`?
a;
- //~^ ERROR: unresolved name `a`. Did you mean to call `BarTy::a`?
+ //~^ ERROR: unresolved name `a`
bah;
//~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`?
b;
- //~^ ERROR: unresolved name `b`. Did you mean to call `self.b`?
+ //~^ ERROR: unresolved name `b`
}
}
y;
//~^ ERROR: unresolved name `y`. Did you mean `self.y`?
a;
- //~^ ERROR: unresolved name `a`. Did you mean to call `BarTy::a`?
+ //~^ ERROR: unresolved name `a`
bah;
//~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`?
b;
- //~^ ERROR: unresolved name `b`. Did you mean to call `self.b`?
+ //~^ ERROR: unresolved name `b`
}
}
}
trait To {
- // This is a typo, the return type should be `<Dst as From<Self>>::Output`
- fn to<Dst: From<Self>>(
- self
- //~^ error: the trait `core::marker::Sized` is not implemented
- ) ->
+ fn to<Dst: From<Self>>(self) ->
<Dst as From<Self>>::Dst
- //~^ error: the trait `core::marker::Sized` is not implemented
+ //~^ ERROR use of undeclared associated type `From::Dst`
{
- From::from(
- //~^ error: the trait `core::marker::Sized` is not implemented
- self
- )
+ From::from(self)
}
}
use crate1::A::Foo;
fn bar(f: Foo) {
Foo::foo(&f);
- //~^ ERROR: function `foo` is private
+ //~^ ERROR: method `foo` is private
}
}
shave(4);
//~^ ERROR: unresolved name `shave`. Did you mean to call `Groom::shave`?
purr();
- //~^ ERROR: unresolved name `purr`. Did you mean to call `self.purr`?
+ //~^ ERROR: unresolved name `purr`
}
}
fn purr_louder() {
static_method();
- //~^ ERROR: unresolved name `static_method`. Did you mean to call `cat::static_method`
+ //~^ ERROR: unresolved name `static_method`
purr();
- //~^ ERROR: unresolved name `purr`. Did you mean to call `self.purr`?
+ //~^ ERROR: unresolved name `purr`
purr();
- //~^ ERROR: unresolved name `purr`. Did you mean to call `self.purr`?
+ //~^ ERROR: unresolved name `purr`
purr();
- //~^ ERROR: unresolved name `purr`. Did you mean to call `self.purr`?
+ //~^ ERROR: unresolved name `purr`
}
}
fn purr(&self) {
grow_older();
- //~^ ERROR: unresolved name `grow_older`. Did you mean to call `cat::grow_older`
+ //~^ ERROR: unresolved name `grow_older`
shave();
//~^ ERROR: unresolved name `shave`
}
whiskers = 4;
//~^ ERROR: unresolved name `whiskers`. Did you mean `self.whiskers`?
purr_louder();
- //~^ ERROR: unresolved name `purr_louder`. Did you mean to call `cat::purr_louder`
+ //~^ ERROR: unresolved name `purr_louder`
}
}
fn main() {
let foo = 100;
- static y: isize = foo + 1; //~ ERROR: attempt to use a non-constant value in a constant
+ static y: isize = foo + 1;
+ //~^ ERROR attempt to use a non-constant value in a constant
+ //~| ERROR unresolved name `foo`
println!("{}", y);
}
#[derive(Debug)]
enum Stuff {
- Bar = foo //~ ERROR attempt to use a non-constant value in a constant
+ Bar = foo
+ //~^ ERROR attempt to use a non-constant value in a constant
+ //~| ERROR unresolved name `foo`
}
println!("{}", Stuff::Bar);
// except according to those terms.
fn f(x:isize) {
- static child: isize = x + 1; //~ ERROR attempt to use a non-constant value in a constant
+ static child: isize = x + 1;
+ //~^ ERROR attempt to use a non-constant value in a constant
+ //~| ERROR unresolved name `x`
}
fn main() {}
fn getChildOption(&self) -> Option<Box<P>> {
static childVal: Box<P> = self.child.get();
//~^ ERROR attempt to use a non-constant value in a constant
+ //~| ERROR unresolved name `self`
panic!();
}
}
fn main() {
let p = Point::new(0.0, 0.0);
- //~^ ERROR unresolved name `Point::new`
- //~^^ ERROR failed to resolve. Use of undeclared type or module `Point`
println!("{}", p.to_string());
}
Foo { baz: 0 }.bar();
}
- fn bar() { //~ ERROR duplicate definition of value `bar`
+ fn bar() { //~ ERROR duplicate method in trait impl
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-tidy-linelength
-
struct Foo {
x: isize
}
-impl Fo { //~ERROR inherent implementations are not allowed for types not defined in the current module
+impl Fo { //~ ERROR use of undeclared type name `Fo`
fn foo() {}
}
+++ /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.
-
-// ignore-tidy-linelength
-
-pub mod a {
- pub struct Foo { a: usize }
-}
-
-pub mod b {
- use a::Foo;
- impl Foo { //~ERROR inherent implementations are only allowed on types defined in the current module
- fn bar(&self) { }
- }
-}
-
-pub fn main() { }
-
-
// ignore-tidy-linelength
-impl B { //~ERROR inherent implementations are not allowed for types not defined in the current module
+impl B { //~ ERROR use of undeclared type name `B`
}
fn main() {
use lint_stability::*;
fn test() {
+ type Foo = MethodTester;
let foo = MethodTester;
deprecated(); //~ ERROR use of deprecated item
foo.method_deprecated(); //~ ERROR use of deprecated item
+ Foo::method_deprecated(&foo); //~ ERROR use of deprecated item
+ <Foo>::method_deprecated(&foo); //~ ERROR use of deprecated item
foo.trait_deprecated(); //~ ERROR use of deprecated item
+ Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item
+ <Foo>::trait_deprecated(&foo); //~ ERROR use of deprecated item
+ <Foo as Trait>::trait_deprecated(&foo); //~ ERROR use of deprecated item
deprecated_text(); //~ ERROR use of deprecated item: text
foo.method_deprecated_text(); //~ ERROR use of deprecated item: text
+ Foo::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text
+ <Foo>::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text
foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
+ Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
+ <Foo>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
+ <Foo as Trait>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
deprecated_unstable(); //~ ERROR use of deprecated item
//~^ WARNING use of unstable library feature
foo.method_deprecated_unstable(); //~ ERROR use of deprecated item
//~^ WARNING use of unstable library feature
+ Foo::method_deprecated_unstable(&foo); //~ ERROR use of deprecated item
+ //~^ WARNING use of unstable library feature
+ <Foo>::method_deprecated_unstable(&foo); //~ ERROR use of deprecated item
+ //~^ WARNING use of unstable library feature
foo.trait_deprecated_unstable(); //~ ERROR use of deprecated item
//~^ WARNING use of unstable library feature
+ Trait::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item
+ //~^ WARNING use of unstable library feature
+ <Foo>::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item
+ //~^ WARNING use of unstable library feature
+ <Foo as Trait>::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item
+ //~^ WARNING use of unstable library feature
deprecated_unstable_text(); //~ ERROR use of deprecated item: text
//~^ WARNING use of unstable library feature
foo.method_deprecated_unstable_text(); //~ ERROR use of deprecated item: text
//~^ WARNING use of unstable library feature
+ Foo::method_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text
+ //~^ WARNING use of unstable library feature
+ <Foo>::method_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text
+ //~^ WARNING use of unstable library feature
foo.trait_deprecated_unstable_text(); //~ ERROR use of deprecated item: text
//~^ WARNING use of unstable library feature
+ Trait::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text
+ //~^ WARNING use of unstable library feature
+ <Foo>::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text
+ //~^ WARNING use of unstable library feature
+ <Foo as Trait>::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text
+ //~^ WARNING use of unstable library feature
unstable(); //~ WARNING use of unstable library feature
foo.method_unstable(); //~ WARNING use of unstable library feature
+ Foo::method_unstable(&foo); //~ WARNING use of unstable library feature
+ <Foo>::method_unstable(&foo); //~ WARNING use of unstable library feature
foo.trait_unstable(); //~ WARNING use of unstable library feature
+ Trait::trait_unstable(&foo); //~ WARNING use of unstable library feature
+ <Foo>::trait_unstable(&foo); //~ WARNING use of unstable library feature
+ <Foo as Trait>::trait_unstable(&foo); //~ WARNING use of unstable library feature
- unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text
- foo.method_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text
- foo.trait_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text
+ unstable_text();
+ //~^ WARNING use of unstable library feature 'test_feature': text
+ foo.method_unstable_text();
+ //~^ WARNING use of unstable library feature 'test_feature': text
+ Foo::method_unstable_text(&foo);
+ //~^ WARNING use of unstable library feature 'test_feature': text
+ <Foo>::method_unstable_text(&foo);
+ //~^ WARNING use of unstable library feature 'test_feature': text
+ foo.trait_unstable_text();
+ //~^ WARNING use of unstable library feature 'test_feature': text
+ Trait::trait_unstable_text(&foo);
+ //~^ WARNING use of unstable library feature 'test_feature': text
+ <Foo>::trait_unstable_text(&foo);
+ //~^ WARNING use of unstable library feature 'test_feature': text
+ <Foo as Trait>::trait_unstable_text(&foo);
+ //~^ WARNING use of unstable library feature 'test_feature': text
stable();
foo.method_stable();
+ Foo::method_stable(&foo);
+ <Foo>::method_stable(&foo);
foo.trait_stable();
+ Trait::trait_stable(&foo);
+ <Foo>::trait_stable(&foo);
+ <Foo as Trait>::trait_stable(&foo);
stable_text();
foo.method_stable_text();
+ Foo::method_stable_text(&foo);
+ <Foo>::method_stable_text(&foo);
foo.trait_stable_text();
+ Trait::trait_stable_text(&foo);
+ <Foo>::trait_stable_text(&foo);
+ <Foo as Trait>::trait_stable_text(&foo);
let _ = DeprecatedStruct { i: 0 }; //~ ERROR use of deprecated item
let _ = DeprecatedUnstableStruct { i: 0 }; //~ ERROR use of deprecated item
macro_test_arg!(macro_test_arg!(deprecated_text())); //~ ERROR use of deprecated item: text
}
- fn test_method_param<F: Trait>(foo: F) {
+ fn test_method_param<Foo: Trait>(foo: Foo) {
foo.trait_deprecated(); //~ ERROR use of deprecated item
+ Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item
+ <Foo>::trait_deprecated(&foo); //~ ERROR use of deprecated item
+ <Foo as Trait>::trait_deprecated(&foo); //~ ERROR use of deprecated item
foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
+ Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
+ <Foo>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
+ <Foo as Trait>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
foo.trait_deprecated_unstable(); //~ ERROR use of deprecated item
//~^ WARNING use of unstable library feature
+ Trait::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item
+ //~^ WARNING use of unstable library feature
+ <Foo>::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item
+ //~^ WARNING use of unstable library feature
+ <Foo as Trait>::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item
+ //~^ WARNING use of unstable library feature
foo.trait_deprecated_unstable_text(); //~ ERROR use of deprecated item: text
//~^ WARNING use of unstable library feature
+ Trait::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text
+ //~^ WARNING use of unstable library feature
+ <Foo>::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text
+ //~^ WARNING use of unstable library feature
+ <Foo as Trait>::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text
+ //~^ WARNING use of unstable library feature
foo.trait_unstable(); //~ WARNING use of unstable library feature
- foo.trait_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text
+ Trait::trait_unstable(&foo); //~ WARNING use of unstable library feature
+ <Foo>::trait_unstable(&foo); //~ WARNING use of unstable library feature
+ <Foo as Trait>::trait_unstable(&foo); //~ WARNING use of unstable library feature
+ foo.trait_unstable_text();
+ //~^ WARNING use of unstable library feature 'test_feature': text
+ Trait::trait_unstable_text(&foo);
+ //~^ WARNING use of unstable library feature 'test_feature': text
+ <Foo>::trait_unstable_text(&foo);
+ //~^ WARNING use of unstable library feature 'test_feature': text
+ <Foo as Trait>::trait_unstable_text(&foo);
+ //~^ WARNING use of unstable library feature 'test_feature': text
foo.trait_stable();
+ Trait::trait_stable(&foo);
+ <Foo>::trait_stable(&foo);
+ <Foo as Trait>::trait_stable(&foo);
}
fn test_method_object(foo: &Trait) {
foo.trait_deprecated_unstable_text(); //~ ERROR use of deprecated item: text
//~^ WARNING use of unstable library feature
foo.trait_unstable(); //~ WARNING use of unstable library feature
- foo.trait_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text
+ foo.trait_unstable_text();
+ //~^ WARNING use of unstable library feature 'test_feature': text
foo.trait_stable();
}
// errors, because other stability attributes now have meaning
// only *across* crates, not within a single crate.
+ type Foo = MethodTester;
let foo = MethodTester;
deprecated(); //~ ERROR use of deprecated item
foo.method_deprecated(); //~ ERROR use of deprecated item
+ Foo::method_deprecated(&foo); //~ ERROR use of deprecated item
+ <Foo>::method_deprecated(&foo); //~ ERROR use of deprecated item
foo.trait_deprecated(); //~ ERROR use of deprecated item
+ Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item
+ <Foo>::trait_deprecated(&foo); //~ ERROR use of deprecated item
+ <Foo as Trait>::trait_deprecated(&foo); //~ ERROR use of deprecated item
deprecated_text(); //~ ERROR use of deprecated item: text
foo.method_deprecated_text(); //~ ERROR use of deprecated item: text
+ Foo::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text
+ <Foo>::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text
foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
+ Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
+ <Foo>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
+ <Foo as Trait>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
unstable();
foo.method_unstable();
+ Foo::method_unstable(&foo);
+ <Foo>::method_unstable(&foo);
foo.trait_unstable();
+ Trait::trait_unstable(&foo);
+ <Foo>::trait_unstable(&foo);
+ <Foo as Trait>::trait_unstable(&foo);
unstable_text();
foo.method_unstable_text();
+ Foo::method_unstable_text(&foo);
+ <Foo>::method_unstable_text(&foo);
foo.trait_unstable_text();
+ Trait::trait_unstable_text(&foo);
+ <Foo>::trait_unstable_text(&foo);
+ <Foo as Trait>::trait_unstable_text(&foo);
stable();
foo.method_stable();
+ Foo::method_stable(&foo);
+ <Foo>::method_stable(&foo);
foo.trait_stable();
+ Trait::trait_stable(&foo);
+ <Foo>::trait_stable(&foo);
+ <Foo as Trait>::trait_stable(&foo);
stable_text();
foo.method_stable_text();
+ Foo::method_stable_text(&foo);
+ <Foo>::method_stable_text(&foo);
foo.trait_stable_text();
+ Trait::trait_stable_text(&foo);
+ <Foo>::trait_stable_text(&foo);
+ <Foo as Trait>::trait_stable_text(&foo);
let _ = DeprecatedStruct { i: 0 }; //~ ERROR use of deprecated item
let _ = UnstableStruct { i: 0 };
let _ = StableTupleStruct (1);
}
- fn test_method_param<F: Trait>(foo: F) {
+ fn test_method_param<Foo: Trait>(foo: Foo) {
foo.trait_deprecated(); //~ ERROR use of deprecated item
+ Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item
+ <Foo>::trait_deprecated(&foo); //~ ERROR use of deprecated item
+ <Foo as Trait>::trait_deprecated(&foo); //~ ERROR use of deprecated item
foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
+ Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
+ <Foo>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
+ <Foo as Trait>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
foo.trait_unstable();
+ Trait::trait_unstable(&foo);
+ <Foo>::trait_unstable(&foo);
+ <Foo as Trait>::trait_unstable(&foo);
foo.trait_unstable_text();
+ Trait::trait_unstable_text(&foo);
+ <Foo>::trait_unstable_text(&foo);
+ <Foo as Trait>::trait_unstable_text(&foo);
foo.trait_stable();
+ Trait::trait_stable(&foo);
+ <Foo>::trait_stable(&foo);
+ <Foo as Trait>::trait_stable(&foo);
}
fn test_method_object(foo: &Trait) {
use std::marker::PhantomFn;
struct Bar;
+struct Bar2;
+struct Bar3;
#[allow(unsafe_code)]
mod allowed_unsafe {
unsafe fn provided_override(&self) {} //~ ERROR: implementation of an `unsafe` method
}
+
+#[allow(unsafe_code)]
+trait A {
+ unsafe fn allowed_unsafe(&self);
+ unsafe fn allowed_unsafe_provided(&self) {}
+}
+
+#[allow(unsafe_code)]
+impl Baz for Bar2 {
+ unsafe fn baz(&self) {}
+ unsafe fn provided_override(&self) {}
+}
+
+impl Baz for Bar3 {
+ #[allow(unsafe_code)]
+ unsafe fn baz(&self) {}
+ unsafe fn provided_override(&self) {} //~ ERROR: implementation of an `unsafe` method
+}
+
+#[allow(unsafe_code)]
+unsafe trait B {
+ fn dummy(&self) {}
+}
+
+trait C {
+ #[allow(unsafe_code)]
+ unsafe fn baz(&self);
+ unsafe fn provided(&self) {} //~ ERROR: implementation of an `unsafe` method
+}
+
+impl C for Bar {
+ #[allow(unsafe_code)]
+ unsafe fn baz(&self) {}
+ unsafe fn provided(&self) {} //~ ERROR: implementation of an `unsafe` method
+}
+
+impl C for Bar2 {
+ unsafe fn baz(&self) {} //~ ERROR: implementation of an `unsafe` method
+}
+
+trait D {
+ #[allow(unsafe_code)]
+ unsafe fn unsafe_provided(&self) {}
+}
+
+impl D for Bar {}
+
fn main() {
unsafe {} //~ ERROR: usage of an `unsafe` block
// Cause an error. It shouldn't have any macro backtrace frames.
fn bar(&self) { }
- fn bar(&self) { } //~ ERROR duplicate definition
+ fn bar(&self) { } //~ ERROR duplicate method
}
fn main() { }
mod foo {
mod baz {
struct Test;
- impl Add for Test {} //~ ERROR: attempt to implement a nonexistent trait
- impl Clone for Test {} //~ ERROR: attempt to implement a nonexistent trait
- impl Iterator for Test {} //~ ERROR: attempt to implement a nonexistent trait
- impl ToString for Test {} //~ ERROR: attempt to implement a nonexistent trait
- impl Writer for Test {} //~ ERROR: attempt to implement a nonexistent trait
+ impl Add for Test {} //~ ERROR: use of undeclared trait
+ impl Clone for Test {} //~ ERROR: use of undeclared trait
+ impl Iterator for Test {} //~ ERROR: use of undeclared trait
+ impl ToString for Test {} //~ ERROR: use of undeclared trait
+ impl Writer for Test {} //~ ERROR: use of undeclared trait
fn foo() {
drop(2) //~ ERROR: unresolved name
}
struct Test;
- impl Add for Test {} //~ ERROR: attempt to implement a nonexistent trait
- impl Clone for Test {} //~ ERROR: attempt to implement a nonexistent trait
- impl Iterator for Test {} //~ ERROR: attempt to implement a nonexistent trait
- impl ToString for Test {} //~ ERROR: attempt to implement a nonexistent trait
- impl Writer for Test {} //~ ERROR: attempt to implement a nonexistent trait
+ impl Add for Test {} //~ ERROR: use of undeclared trait
+ impl Clone for Test {} //~ ERROR: use of undeclared trait
+ impl Iterator for Test {} //~ ERROR: use of undeclared trait
+ impl ToString for Test {} //~ ERROR: use of undeclared trait
+ impl Writer for Test {} //~ ERROR: use of undeclared trait
fn foo() {
drop(2) //~ ERROR: unresolved name
#[no_implicit_prelude]
mod qux_inner {
struct Test;
- impl Add for Test {} //~ ERROR: attempt to implement a nonexistent trait
- impl Clone for Test {} //~ ERROR: attempt to implement a nonexistent trait
- impl Iterator for Test {} //~ ERROR: attempt to implement a nonexistent trait
- impl ToString for Test {} //~ ERROR: attempt to implement a nonexistent trait
- impl Writer for Test {} //~ ERROR: attempt to implement a nonexistent trait
+ impl Add for Test {} //~ ERROR: use of undeclared trait
+ impl Clone for Test {} //~ ERROR: use of undeclared trait
+ impl Iterator for Test {} //~ ERROR: use of undeclared trait
+ impl ToString for Test {} //~ ERROR: use of undeclared trait
+ impl Writer for Test {} //~ ERROR: use of undeclared trait
fn foo() {
drop(2) //~ ERROR: unresolved name
// fail with the same error message).
struct Test;
-impl Add for Test {} //~ ERROR: attempt to implement a nonexistent trait
-impl Clone for Test {} //~ ERROR: attempt to implement a nonexistent trait
-impl Iterator for Test {} //~ ERROR: attempt to implement a nonexistent trait
-impl ToString for Test {} //~ ERROR: attempt to implement a nonexistent trait
-impl Writer for Test {} //~ ERROR: attempt to implement a nonexistent trait
+impl Add for Test {} //~ ERROR: use of undeclared trait
+impl Clone for Test {} //~ ERROR: use of undeclared trait
+impl Iterator for Test {} //~ ERROR: use of undeclared trait
+impl ToString for Test {} //~ ERROR: use of undeclared trait
+impl Writer for Test {} //~ ERROR: use of undeclared trait
fn main() {
drop(2) //~ ERROR: unresolved name
trait NewTrait : SomeNonExistentTrait {}
-//~^ ERROR attempt to derive a nonexistent trait `SomeNonExistentTrait`
+//~^ ERROR use of undeclared trait name `SomeNonExistentTrait`
impl SomeNonExistentTrait for isize {}
-//~^ ERROR attempt to implement a nonexistent trait `SomeNonExistentTrait`
+//~^ ERROR use of undeclared trait name `SomeNonExistentTrait`
fn f<T:SomeNonExistentTrait>() {}
-//~^ ERROR attempt to bound type parameter with a nonexistent trait `SomeNonExistentTrait`
+//~^ ERROR use of undeclared trait name `SomeNonExistentTrait`
+++ /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 calling methods on an impl for a bare trait. This test checks trait impls
-// must be in the same module as the trait.
-
-mod Foo {
- trait T {}
-}
-
-mod Bar {
- impl<'a> ::Foo::T+'a { //~ERROR: inherent implementations may only be implemented in the same
- fn foo(&self) {}
- }
-}
-
-fn main() {}
trait A {
}
-impl A for a { //~ERROR found module name used as a type
+impl A for a { //~ ERROR use of undeclared type name `a`
}
fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-tidy-linelength
-
-impl<T> Option<T> { //~ERROR inherent implementations are not allowed for types not defined in the current module
+impl<T> Option<T> {
+//~^ ERROR cannot associate methods with a type outside the crate the type is defined in
pub fn foo(&self) { }
}
fn main() {
<String as IntoCow>::into_cow("foo".to_string());
- //~^ ERROR wrong number of type arguments: expected 1, found 0
+ //~^ ERROR too few type parameters provided: expected 1 parameter(s)
}
#![feature(unboxed_closures)]
-fn f<F:Nonexist(isize) -> isize>(x: F) {} //~ ERROR nonexistent trait `Nonexist`
+fn f<F:Nonexist(isize) -> isize>(x: F) {} //~ ERROR undeclared trait name `Nonexist`
type Typedef = isize;
--- /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.
+
+pub struct T;
+
+#[unsafe_no_drop_flag]
+//~^ ERROR unsafe_no_drop_flag has unstable semantics and may be removed
+pub struct S {
+ pub x: T,
+}
+
+impl Drop for S {
+ fn drop(&mut self) {}
+}
+
+pub fn main() {}
use Trait::foo;
//~^ ERROR `foo` is not directly importable
use Foo::new;
-//~^ ERROR `new` is not directly importable
+//~^ ERROR unresolved import `Foo::new`. Not a module `Foo`
pub trait Trait {
fn 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.
+
+// Various uses of `T::Item` syntax where the bound that supplies
+// `Item` originates in a where-clause, not the declaration of
+// `T`. Issue #20300.
+
+use std::marker::{MarkerTrait, PhantomData};
+use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
+use std::sync::atomic::Ordering::SeqCst;
+
+static COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
+
+// Preamble.
+trait Trait : MarkerTrait { type Item; }
+struct Struct;
+impl Trait for Struct {
+ type Item = u32;
+}
+
+// Where-clause attached on the method which declares `T`.
+struct A;
+impl A {
+ fn foo<T>(_x: T::Item) where T: Trait {
+ COUNTER.fetch_add(1, SeqCst);
+ }
+}
+
+// Where-clause attached on the method to a parameter from the struct.
+struct B<T>(PhantomData<T>);
+impl<T> B<T> {
+ fn foo(_x: T::Item) where T: Trait {
+ COUNTER.fetch_add(10, SeqCst);
+ }
+}
+
+// Where-clause attached to free fn.
+fn c<T>(_: T::Item) where T : Trait {
+ COUNTER.fetch_add(100, SeqCst);
+}
+
+// Where-clause attached to defaulted and non-defaulted trait method.
+trait AnotherTrait {
+ fn method<T>(&self, _: T::Item) where T: Trait;
+ fn default_method<T>(&self, _: T::Item) where T: Trait {
+ COUNTER.fetch_add(1000, SeqCst);
+ }
+}
+struct D;
+impl AnotherTrait for D {
+ fn method<T>(&self, _: T::Item) where T: Trait {
+ COUNTER.fetch_add(10000, SeqCst);
+ }
+}
+
+// Where-clause attached to trait and impl containing the method.
+trait YetAnotherTrait<T>
+ where T : Trait
+{
+ fn method(&self, _: T::Item);
+ fn default_method(&self, _: T::Item) {
+ COUNTER.fetch_add(100000, SeqCst);
+ }
+}
+struct E<T>(PhantomData<T>);
+impl<T> YetAnotherTrait<T> for E<T>
+ where T : Trait
+{
+ fn method(&self, _: T::Item) {
+ COUNTER.fetch_add(1000000, SeqCst);
+ }
+}
+
+// Where-clause attached to inherent impl containing the method.
+struct F<T>(PhantomData<T>);
+impl<T> F<T> where T : Trait {
+ fn method(&self, _: T::Item) {
+ COUNTER.fetch_add(10000000, SeqCst);
+ }
+}
+
+// Where-clause attached to struct.
+#[allow(dead_code)]
+struct G<T> where T : Trait {
+ data: T::Item,
+ phantom: PhantomData<T>,
+}
+
+fn main() {
+ A::foo::<Struct>(22);
+ B::<Struct>::foo(22);
+ c::<Struct>(22);
+ D.method::<Struct>(22);
+ D.default_method::<Struct>(22);
+ E(PhantomData::<Struct>).method(22);
+ E(PhantomData::<Struct>).default_method(22);
+ F(PhantomData::<Struct>).method(22);
+ G::<Struct> { data: 22, phantom: PhantomData };
+ assert_eq!(COUNTER.load(SeqCst), 11111111);
+}
let mut v = vec!(1);
v.push_val(2);
v.push_val(3);
- assert_eq!(v, vec!(1, 2, 3));
+ assert_eq!(v, [1, 2, 3]);
}
pub fn main() {
let mut the_vec = vec!(1, 2, 3, 100);
bar(&mut the_vec);
- assert_eq!(the_vec, vec!(100, 3, 2, 1));
+ assert_eq!(the_vec, [100, 3, 2, 1]);
}
pub fn main() {
let mut the_vec = vec!(1, 2, 3, 100);
bar(&mut the_vec);
- assert_eq!(the_vec, vec!(100, 3, 2, 1));
+ assert_eq!(the_vec, [100, 3, 2, 1]);
}
+++ /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.
-
-#![feature(macro_rules)]
-
-use std::borrow::{Cow, IntoCow};
-use std::collections::BitVec;
-use std::default::Default;
-use std::iter::FromIterator;
-use std::ops::Add;
-use std::option::IntoIter as OptionIter;
-use std::rand::Rand;
-use std::rand::XorShiftRng as DummyRng;
-// FIXME the glob std::prelude::*; import of Vec is missing non-static inherent methods.
-use std::vec::Vec;
-
-#[derive(PartialEq, Eq)]
-struct Newt<T>(T);
-
-fn id<T>(x: T) -> T { x }
-fn eq<T: Eq>(a: T, b: T) -> bool { a == b }
-fn u8_as_i8(x: u8) -> i8 { x as i8 }
-fn odd(x: uint) -> bool { x % 2 == 1 }
-fn dummy_rng() -> DummyRng { DummyRng::new_unseeded() }
-
-trait Size: Sized {
- fn size() -> uint { std::mem::size_of::<Self>() }
-}
-impl<T> Size for T {}
-
-macro_rules! tests {
- ($($expr:expr, $ty:ty, ($($test:expr),*);)+) => (pub fn main() {$({
- const C: $ty = $expr;
- static S: $ty = $expr;
- assert!(eq(C($($test),*), $expr($($test),*)));
- assert!(eq(S($($test),*), $expr($($test),*)));
- assert!(eq(C($($test),*), S($($test),*)));
- })+})
-}
-
-tests! {
- // Free function.
- id, fn(int) -> int, (5);
- id::<int>, fn(int) -> int, (5);
-
- // Enum variant constructor.
- Some, fn(int) -> Option<int>, (5);
- Some::<int>, fn(int) -> Option<int>, (5);
-
- // Tuple struct constructor.
- Newt, fn(int) -> Newt<int>, (5);
- Newt::<int>, fn(int) -> Newt<int>, (5);
-
- // Inherent static methods.
- Vec::new, fn() -> Vec<()>, ();
- Vec::<()>::new, fn() -> Vec<()>, ();
- Vec::with_capacity, fn(uint) -> Vec<()>, (5);
- Vec::<()>::with_capacity, fn(uint) -> Vec<()>, (5);
- BitVec::from_fn, fn(uint, fn(uint) -> bool) -> BitVec, (5, odd);
- BitVec::from_fn::<fn(uint) -> bool>, fn(uint, fn(uint) -> bool) -> BitVec, (5, odd);
-
- // Inherent non-static method.
- Vec::map_in_place, fn(Vec<u8>, fn(u8) -> i8) -> Vec<i8>, (vec![b'f', b'o', b'o'], u8_as_i8);
- Vec::map_in_place::<i8, fn(u8) -> i8>, fn(Vec<u8>, fn(u8) -> i8) -> Vec<i8>,
- (vec![b'f', b'o', b'o'], u8_as_i8);
- // FIXME these break with "type parameter might not appear here pointing at `<u8>`.
- // Vec::<u8>::map_in_place: fn(Vec<u8>, fn(u8) -> i8) -> Vec<i8>
- // , (vec![b'f', b'o', b'o'], u8_as_i8);
- // Vec::<u8>::map_in_place::<i8, fn(u8) -> i8>: fn(Vec<u8>, fn(u8) -> i8) -> Vec<i8>
- // , (vec![b'f', b'o', b'o'], u8_as_i8);
-
- // Trait static methods.
- <bool as Size>::size, fn() -> uint, ();
- Default::default, fn() -> int, ();
- <int as Default>::default, fn() -> int, ();
- Rand::rand, fn(&mut DummyRng) -> int, (&mut dummy_rng());
- <int as Rand>::rand, fn(&mut DummyRng) -> int, (&mut dummy_rng());
- Rand::rand::<DummyRng>, fn(&mut DummyRng) -> int, (&mut dummy_rng());
- <int as Rand>::rand::<DummyRng>, fn(&mut DummyRng) -> int, (&mut dummy_rng());
-
- // Trait non-static methods.
- Clone::clone, fn(&int) -> int, (&5);
- <int as Clone>::clone, fn(&int) -> int, (&5);
- FromIterator::from_iter, fn(OptionIter<int>) -> Vec<int>, (Some(5).into_iter());
- <Vec<_> as FromIterator<_>>::from_iter, fn(OptionIter<int>) -> Vec<int>,
- (Some(5).into_iter());
- <Vec<int> as FromIterator<_>>::from_iter, fn(OptionIter<int>) -> Vec<int>,
- (Some(5).into_iter());
- FromIterator::from_iter::<OptionIter<int>>, fn(OptionIter<int>) -> Vec<int>,
- (Some(5).into_iter());
- <Vec<int> as FromIterator<_>>::from_iter::<OptionIter<int>>, fn(OptionIter<int>) -> Vec<int>,
- (Some(5).into_iter());
- Add::add, fn(i32, i32) -> i32, (5, 6);
- <i32 as Add<_>>::add, fn(i32, i32) -> i32, (5, 6);
- <i32 as Add<i32>>::add, fn(i32, i32) -> i32, (5, 6);
- <String as IntoCow<_>>::into_cow, fn(String) -> Cow<'static, str>,
- ("foo".to_string());
- <String as IntoCow<'static, _>>::into_cow, fn(String) -> Cow<'static, str>,
- ("foo".to_string());
-}
--- /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 #15477. This test just needs to compile.
+
+use std::marker::PhantomFn;
+
+trait Chromosome<X: Chromosome<i32>> : PhantomFn<(Self,X)> {
+}
+
+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 a case where a supertrait references a type that references
+// the original trait. This poses no problem at the moment.
+
+trait Chromosome: Get<Struct<i32>> {
+}
+
+trait Get<A> {
+ fn get(&self) -> A;
+}
+
+struct Struct<C:Chromosome> { c: C }
+
+fn main() { }
// except according to those terms.
use std::env::*;
+use std::path::PathBuf;
#[cfg(unix)]
fn main() {
let oldhome = var("HOME");
set_var("HOME", "/home/MountainView");
- assert!(home_dir() == Some(Path::new("/home/MountainView")));
+ assert!(home_dir() == Some(PathBuf::new("/home/MountainView")));
remove_var("HOME");
if cfg!(target_os = "android") {
assert!(home_dir().is_some());
set_var("HOME", "/home/MountainView");
- assert!(home_dir() == Some(Path::new("/home/MountainView")));
+ assert!(home_dir() == Some(PathBuf::new("/home/MountainView")));
remove_var("HOME");
set_var("USERPROFILE", "/home/MountainView");
- assert!(home_dir() == Some(Path::new("/home/MountainView")));
+ assert!(home_dir() == Some(PathBuf::new("/home/MountainView")));
set_var("HOME", "/home/MountainView");
set_var("USERPROFILE", "/home/PaloAlto");
- assert!(home_dir() == Some(Path::new("/home/MountainView")));
+ assert!(home_dir() == Some(PathBuf::new("/home/MountainView")));
}
}
pub fn main() {
- assert_eq!(vec_utils::map_(&vec!(1,2,3), |&x| x+1), vec!(2,3,4));
+ assert_eq!(vec_utils::map_(&vec!(1,2,3), |&x| x+1), [2,3,4]);
}
--- /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.
+
+// Ensure that an user-defined type admits multiple inherent methods
+// with the same name, which can be called on values that have a
+// precise enough type to allow distinguishing between the methods.
+
+struct Foo<T>(T);
+
+impl Foo<usize> {
+ fn bar(&self) -> i32 { self.0 as i32 }
+}
+
+impl Foo<isize> {
+ fn bar(&self) -> i32 { -(self.0 as i32) }
+}
+
+fn main() {
+ let foo_u = Foo::<usize>(5);
+ assert_eq!(foo_u.bar(), 5);
+
+ let foo_i = Foo::<isize>(3);
+ assert_eq!(foo_i.bar(), -3);
+}
--- /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.
+
+struct Foo;
+
+trait Trait {
+ fn bar(&self);
+}
+
+// Inherent impls should be preferred over trait ones.
+impl Foo {
+ fn bar(&self) {}
+}
+
+impl Trait {
+ fn baz(_: &Foo) {}
+}
+
+impl Trait for Foo {
+ fn bar(&self) { panic!("wrong method called!") }
+}
+
+fn main() {
+ Foo.bar();
+ Foo::bar(&Foo);
+ <Foo>::bar(&Foo);
+
+ // Should work even if Trait::baz doesn't exist.
+ // N.B: `<Trait>::bar` would be ambiguous.
+ <Trait>::baz(&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.
+
+mod foo {
+ pub struct Point {
+ pub x: i32,
+ pub y: i32,
+ }
+}
+
+impl foo::Point {
+ fn x(&self) -> i32 { self.x }
+}
+
+fn main() {
+ assert_eq!((foo::Point { x: 1, y: 3}).x(), 1);
+}
--- /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.
+
+pub struct Foo;
+
+mod bar {
+ use Foo;
+
+ impl Foo {
+ fn baz(&self) {}
+ }
+}
+fn main() {}
+
-// no-prefer-dynamic
-
// 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.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::slice::SliceExt;
-use std::old_io::{fs, USER_RWX};
-use std::process;
+// no-prefer-dynamic
+
+#![feature(fs, process, env, path, rand)]
+
use std::env;
-use std::old_path::BytesContainer;
+use std::fs;
+use std::process;
use std::rand::random;
+use std::str;
fn main() {
// If we're the child, make sure we were invoked correctly
fn test() {
// If we're the parent, copy our own binary to a new directory.
let my_path = env::current_exe().unwrap();
- let my_dir = my_path.dir_path();
+ let my_dir = my_path.parent().unwrap();
let random_u32: u32 = random();
- let child_dir = Path::new(my_dir.join(format!("issue-15149-child-{}",
- random_u32)));
- fs::mkdir(&child_dir, USER_RWX).unwrap();
+ let child_dir = my_dir.join(&format!("issue-15149-child-{}", random_u32));
+ fs::create_dir(&child_dir).unwrap();
- let child_path = child_dir.join(format!("mytest{}",
- env::consts::EXE_SUFFIX));
+ let child_path = child_dir.join(&format!("mytest{}",
+ env::consts::EXE_SUFFIX));
fs::copy(&my_path, &child_path).unwrap();
// Append the new directory to our own PATH.
let path = {
let mut paths: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap()).collect();
- paths.push(child_dir.clone());
+ paths.push(child_dir.to_path_buf());
env::join_paths(paths.iter()).unwrap()
};
assert!(child_output.status.success(),
format!("child assertion failed\n child stdout:\n {}\n child stderr:\n {}",
- child_output.stdout.container_as_str().unwrap(),
- child_output.stderr.container_as_str().unwrap()));
+ str::from_utf8(&child_output.stdout).unwrap(),
+ str::from_utf8(&child_output.stderr).unwrap()));
- fs::rmdir_recursive(&child_dir).unwrap();
+ fs::remove_dir_all(&child_dir).unwrap();
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::old_io::{process, Command};
+use std::process::Command;
use std::env;
fn main() {
}
fn test() {
- let status = Command::new(env::current_exe().unwrap())
+ let status = Command::new(&env::current_exe().unwrap())
.arg("foo").arg("")
- .stdout(process::InheritFd(1))
- .stderr(process::InheritFd(2))
.status().unwrap();
assert!(status.success());
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-windows currently windows requires UTF-8 for spawning processes
-
-use std::old_io::Command;
-use std::env;
-
+#[cfg(unix)]
fn main() {
+ use std::process::Command;
+ use std::env;
+ use std::os::unix::prelude::*;
+ use std::ffi::OsStr;
+
if env::args().len() == 1 {
- assert!(Command::new(env::current_exe().unwrap()).arg(b"\xff")
+ assert!(Command::new(&env::current_exe().unwrap())
+ .arg(<OsStr as OsStrExt>::from_bytes(b"\xff"))
.status().unwrap().success())
}
}
+
+#[cfg(windows)]
+fn main() {}
let mut table = HashMap::new();
table.insert("one".to_string(), 1);
table.insert("two".to_string(), 2);
- assert!(check_strs(&format!("{:?}", table), "HashMap {\"one\": 1, \"two\": 2}") ||
- check_strs(&format!("{:?}", table), "HashMap {\"two\": 2, \"one\": 1}"));
+ assert!(check_strs(&format!("{:?}", table), "{\"one\": 1, \"two\": 2}") ||
+ check_strs(&format!("{:?}", table), "{\"two\": 2, \"one\": 1}"));
}
--- /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.
+
+pub mod a {
+ pub struct Foo { a: usize }
+}
+
+pub mod b {
+ use a::Foo;
+ impl Foo {
+ fn bar(&self) { }
+ }
+}
+
+pub fn main() { }
+
+
pub fn main() {
assert_eq!(transform(Some(10)), Some("11".to_string()));
assert_eq!(transform(None), None);
- assert!((vec!("hi".to_string()))
+ assert_eq!((vec!("hi".to_string()))
.bind(|x| vec!(x.clone(), format!("{}!", x)) )
- .bind(|x| vec!(x.clone(), format!("{}?", x)) ) ==
- vec!("hi".to_string(),
- "hi?".to_string(),
- "hi!".to_string(),
- "hi!?".to_string()));
+ .bind(|x| vec!(x.clone(), format!("{}?", x)) ),
+ ["hi".to_string(),
+ "hi?".to_string(),
+ "hi!".to_string(),
+ "hi!?".to_string()]);
}
// aux-build:sepcomp_lib.rs
// compile-flags: -C lto
// no-prefer-dynamic
+// ignore-android FIXME #18800
extern crate sepcomp_lib;
use sepcomp_lib::a::one;
--- /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::sync;
+
+fn assert_both<T: Sync + Send>() {}
+
+fn main() {
+ assert_both::<sync::StaticMutex>();
+ assert_both::<sync::StaticCondvar>();
+ assert_both::<sync::StaticRwLock>();
+ assert_both::<sync::Mutex<()>>();
+ assert_both::<sync::Condvar>();
+ assert_both::<sync::RwLock<()>>();
+ assert_both::<sync::Semaphore>();
+ assert_both::<sync::Barrier>();
+ assert_both::<sync::Arc<()>>();
+ assert_both::<sync::Weak<()>>();
+ assert_both::<sync::Once>();
+}
}
pub fn main() {
- assert_eq!(foo(vec!(1)), vec!("hi".to_string()));
- assert_eq!(bar::<int, Vec<int> >(vec!(4, 5)), vec!("4".to_string(), "5".to_string()));
+ assert_eq!(foo(vec!(1)), ["hi".to_string()]);
+ assert_eq!(bar::<int, Vec<int> >(vec!(4, 5)), ["4".to_string(), "5".to_string()]);
assert_eq!(bar::<String, Vec<String> >(vec!("x".to_string(), "y".to_string())),
- vec!("x".to_string(), "y".to_string()));
- assert_eq!(bar::<(), Vec<()>>(vec!(())), vec!("()".to_string()));
+ ["x".to_string(), "y".to_string()]);
+ assert_eq!(bar::<(), Vec<()>>(vec!(())), ["()".to_string()]);
}
--- /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.
+
+pub mod Foo {
+ pub trait Trait {
+ fn foo(&self);
+ }
+}
+
+mod Bar {
+ impl<'a> ::Foo::Trait+'a {
+ fn bar(&self) { self.foo() }
+ }
+}
+
+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.
+
+#![feature(macro_rules)]
+
+use std::borrow::{Cow, IntoCow};
+use std::collections::BitVec;
+use std::default::Default;
+use std::iter::FromIterator;
+use std::ops::Add;
+use std::option::IntoIter as OptionIter;
+use std::rand::Rand;
+use std::rand::XorShiftRng as DummyRng;
+// FIXME the glob std::prelude::*; import of Vec is missing non-static inherent methods.
+use std::vec::Vec;
+
+#[derive(PartialEq, Eq)]
+struct Newt<T>(T);
+
+fn id<T>(x: T) -> T { x }
+fn eq<T: Eq>(a: T, b: T) -> bool { a == b }
+fn u8_as_i8(x: u8) -> i8 { x as i8 }
+fn odd(x: usize) -> bool { x % 2 == 1 }
+fn dummy_rng() -> DummyRng { DummyRng::new_unseeded() }
+
+trait Size: Sized {
+ fn size() -> usize { std::mem::size_of::<Self>() }
+}
+impl<T> Size for T {}
+
+macro_rules! tests {
+ ($($expr:expr, $ty:ty, ($($test:expr),*);)+) => (pub fn main() {$({
+ const C: $ty = $expr;
+ static S: $ty = $expr;
+ assert!(eq(C($($test),*), $expr($($test),*)));
+ assert!(eq(S($($test),*), $expr($($test),*)));
+ assert!(eq(C($($test),*), S($($test),*)));
+ })+})
+}
+
+tests! {
+ // Free function.
+ id, fn(i32) -> i32, (5);
+ id::<i32>, fn(i32) -> i32, (5);
+
+ // Enum variant constructor.
+ Some, fn(i32) -> Option<i32>, (5);
+ Some::<i32>, fn(i32) -> Option<i32>, (5);
+
+ // Tuple struct constructor.
+ Newt, fn(i32) -> Newt<i32>, (5);
+ Newt::<i32>, fn(i32) -> Newt<i32>, (5);
+
+ // Inherent static methods.
+ Vec::new, fn() -> Vec<()>, ();
+ Vec::<()>::new, fn() -> Vec<()>, ();
+ <Vec<()>>::new, fn() -> Vec<()>, ();
+ Vec::with_capacity, fn(usize) -> Vec<()>, (5);
+ Vec::<()>::with_capacity, fn(usize) -> Vec<()>, (5);
+ <Vec<()>>::with_capacity, fn(usize) -> Vec<()>, (5);
+ BitVec::from_fn, fn(usize, fn(usize) -> bool) -> BitVec, (5, odd);
+ BitVec::from_fn::<fn(usize) -> bool>, fn(usize, fn(usize) -> bool) -> BitVec, (5, odd);
+
+ // Inherent non-static method.
+ Vec::map_in_place, fn(Vec<u8>, fn(u8) -> i8) -> Vec<i8>, (vec![b'f', b'o', b'o'], u8_as_i8);
+ Vec::map_in_place::<i8, fn(u8) -> i8>, fn(Vec<u8>, fn(u8) -> i8) -> Vec<i8>,
+ (vec![b'f', b'o', b'o'], u8_as_i8);
+ // FIXME these break with "type parameter might not appear here pointing at `<u8>`.
+ // Vec::<u8>::map_in_place: fn(Vec<u8>, fn(u8) -> i8) -> Vec<i8>
+ // , (vec![b'f', b'o', b'o'], u8_as_i8);
+ // Vec::<u8>::map_in_place::<i8, fn(u8) -> i8>: fn(Vec<u8>, fn(u8) -> i8) -> Vec<i8>
+ // , (vec![b'f', b'o', b'o'], u8_as_i8);
+
+ // Trait static methods.
+ bool::size, fn() -> usize, ();
+ <bool>::size, fn() -> usize, ();
+ <bool as Size>::size, fn() -> usize, ();
+
+ Default::default, fn() -> i32, ();
+ i32::default, fn() -> i32, ();
+ <i32>::default, fn() -> i32, ();
+ <i32 as Default>::default, fn() -> i32, ();
+
+ Rand::rand, fn(&mut DummyRng) -> i32, (&mut dummy_rng());
+ i32::rand, fn(&mut DummyRng) -> i32, (&mut dummy_rng());
+ <i32>::rand, fn(&mut DummyRng) -> i32, (&mut dummy_rng());
+ <i32 as Rand>::rand, fn(&mut DummyRng) -> i32, (&mut dummy_rng());
+ Rand::rand::<DummyRng>, fn(&mut DummyRng) -> i32, (&mut dummy_rng());
+ i32::rand::<DummyRng>, fn(&mut DummyRng) -> i32, (&mut dummy_rng());
+ <i32>::rand::<DummyRng>, fn(&mut DummyRng) -> i32, (&mut dummy_rng());
+ <i32 as Rand>::rand::<DummyRng>, fn(&mut DummyRng) -> i32, (&mut dummy_rng());
+
+ // Trait non-static methods.
+ Clone::clone, fn(&i32) -> i32, (&5);
+ i32::clone, fn(&i32) -> i32, (&5);
+ <i32>::clone, fn(&i32) -> i32, (&5);
+ <i32 as Clone>::clone, fn(&i32) -> i32, (&5);
+
+ FromIterator::from_iter, fn(OptionIter<i32>) -> Vec<i32>, (Some(5).into_iter());
+ Vec::from_iter, fn(OptionIter<i32>) -> Vec<i32>, (Some(5).into_iter());
+ <Vec<_>>::from_iter, fn(OptionIter<i32>) -> Vec<i32>, (Some(5).into_iter());
+ <Vec<_> as FromIterator<_>>::from_iter, fn(OptionIter<i32>) -> Vec<i32>,
+ (Some(5).into_iter());
+ <Vec<i32> as FromIterator<_>>::from_iter, fn(OptionIter<i32>) -> Vec<i32>,
+ (Some(5).into_iter());
+ FromIterator::from_iter::<OptionIter<i32>>, fn(OptionIter<i32>) -> Vec<i32>,
+ (Some(5).into_iter());
+ <Vec<i32> as FromIterator<_>>::from_iter::<OptionIter<i32>>, fn(OptionIter<i32>) -> Vec<i32>,
+ (Some(5).into_iter());
+
+ Add::add, fn(i32, i32) -> i32, (5, 6);
+ i32::add, fn(i32, i32) -> i32, (5, 6);
+ <i32>::add, fn(i32, i32) -> i32, (5, 6);
+ <i32 as Add<_>>::add, fn(i32, i32) -> i32, (5, 6);
+ <i32 as Add<i32>>::add, fn(i32, i32) -> i32, (5, 6);
+
+ String::into_cow, fn(String) -> Cow<'static, str>,
+ ("foo".to_string());
+ <String>::into_cow, fn(String) -> Cow<'static, str>,
+ ("foo".to_string());
+ <String as IntoCow<_>>::into_cow, fn(String) -> Cow<'static, str>,
+ ("foo".to_string());
+ <String as IntoCow<'static, _>>::into_cow, fn(String) -> Cow<'static, str>,
+ ("foo".to_string());
+}
fn main() {
let mut v: Vec<_> = vec![];
f(|| v.push(0));
- assert_eq!(v, vec![0]);
+ assert_eq!(v, [0]);
}