which starts happening after ~2 hours of machine uptime.
Closes #17845
* [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
A _character literal_ is a single Unicode character enclosed within two
`U+0027` (single-quote) characters, with the exception of `U+0027` itself,
-which must be _escaped_ by a preceding U+005C character (`\`).
+which must be _escaped_ by a preceding `U+005C` character (`\`).
##### String literals
which must be _escaped_ by a preceding `U+005C` character (`\`), or a _raw
string literal_.
+A multi-line string literal may be defined by terminating each line with a
+`U+005C` character (`\`) immediately before the newline. This causes the
+`U+005C` character, the newline, and all whitespace at the beginning of the
+next line to be ignored.
+
+```rust
+let a = "foobar";
+let b = "foo\
+ bar";
+
+assert_eq!(a,b);
+```
+
##### Character escapes
Some additional _escapes_ are available in either character or non-raw string
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*
// This function is only included when compiling for a unixish OS with a 32-bit
// architecture
-#[cfg(all(unix, target_word_size = "32"))]
+#[cfg(all(unix, target_pointer_width = "32"))]
fn on_32bit_unix() {
// ...
}
* `target_os = "..."`. Operating system of the target, examples include
`"win32"`, `"macos"`, `"linux"`, `"android"`, `"freebsd"`, `"dragonfly"`,
`"bitrig"` or `"openbsd"`.
-* `target_word_size = "..."`. Target word size in bits. This is set to `"32"`
- for targets with 32-bit pointers, and likewise set to `"64"` for 64-bit
- pointers.
+* `target_pointer_width = "..."`. Target pointer width in bits. This is set
+ to `"32"` for targets with 32-bit pointers, and likewise set to `"64"` for
+ 64-bit pointers.
* `unix`. See `target_family`.
* `windows`. See `target_family`.
/* General structure */
body {
+ background-color: white;
margin: 0 auto;
padding: 0 15px;
font-family: "Source Serif Pro", Georgia, Times, "Times New Roman", serif;
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.
README](https://github.com/rust-lang/cargo#installing-cargo-from-nightlies)
for specific instructions about installing it.
+## Converting to Cargo
+
Let's convert Hello World to Cargo.
To Cargo-ify our project, we need to do two things: Make a `Cargo.toml`
configuration file, and put our source file in the right place. Let's
do that part first:
-```{bash}
+```bash
$ mkdir src
$ mv main.rs src/main.rs
```
Next, our configuration file:
-```{bash}
+```bash
$ editor Cargo.toml
```
Once you have this file in place, we should be ready to build! Try this:
-```{bash}
+```bash
$ cargo build
Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world)
$ ./target/hello_world
program is simple, it's using much of the real tooling that you'll use for the
rest of your Rust career.
+## A New Project
+
+You don't have to go through this whole process every time you want to start a new
+project! Cargo has the ability to make a bare-bones project directory in which you
+can start developing right away.
+
+To start a new project with Cargo, use `cargo new`:
+
+```bash
+$ cargo new hello_world --bin
+```
+
+We're passing `--bin` because we're making a binary program: if we
+were making a library, we'd leave it off.
+
+Let's check out what Cargo has generated for us:
+
+```bash
+$ cd hello_world
+$ tree .
+.
+├── Cargo.toml
+└── src
+ └── main.rs
+
+1 directory, 2 files
+```
+
+If you don't have the `tree` command, you can probably get it from your distro's package
+manager. It's not necessary, but it's certainly useful.
+
+This is all we need to get started. First, let's check out `Cargo.toml`:
+
+```toml
+[package]
+
+name = "hello_world"
+version = "0.0.1"
+authors = ["Your Name <you@example.com>"]
+```
+
+Cargo has populated this file with reasonable defaults based off the arguments you gave
+it and your `git` global configuration. You may notice that Cargo has also initialized
+the `hello_world` directory as a `git` repository.
+
+Here's what's in `src/main.rs`:
+
+```rust
+fn main() {
+ println!("Hello, world!");
+}
+```
+
+Cargo has generated a "Hello World!" for us, and you're ready to start coding! A
+much more in-depth guide to Cargo can be found [here](http://doc.crates.io/guide.html).
+
Now that you've got the tools down, let's actually learn more about the Rust
language itself. These are the basics that will serve you well through the rest
-of your time with Rust.
+of your time with Rust.
\ No newline at end of file
};
}
# 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
```{rust}
fn main() {
- let x = &mut 5;
+ let mut x = 5;
- if *x < 10 {
+ if x < 10 {
let y = &x;
println!("Oh no: {}", y);
return;
}
- *x -= 1;
+ x -= 1;
println!("Oh no: {}", x);
}
```{rust,ignore}
fn main() {
- let x = &mut 5;
+ let mut x = 5;
- if *x < 10 {
+ if x < 10 {
let y = &x;
- *x -= 1;
+
+ x -= 1;
println!("Oh no: {}", y);
return;
}
- *x -= 1;
+ x -= 1;
println!("Oh no: {}", x);
}
It gives this error:
```text
-test.rs:5:8: 5:10 error: cannot assign to `*x` because it is borrowed
-test.rs:5 *x -= 1;
- ^~
-test.rs:4:16: 4:18 note: borrow of `*x` occurs here
-test.rs:4 let y = &x;
- ^~
+test.rs:7:9: 7:15 error: cannot assign to `x` because it is borrowed
+test.rs:7 x -= 1;
+ ^~~~~~
+test.rs:5:18: 5:19 note: borrow of `x` occurs here
+test.rs:5 let y = &x;
+ ^
```
As you might guess, this kind of analysis is complex for a human, and therefore
However, the common case is that it is more efficient to use static dispatch,
and one can always have a thin statically-dispatched wrapper function that does
-a dynamic, but not vice versa, meaning static calls are more flexible. The
-standard library tries to be statically dispatched where possible for this
+a dynamic dispatch, but not vice versa, meaning static calls are more flexible.
+The standard library tries to be statically dispatched where possible for this
reason.
## Dynamic dispatch
highlights for example. If you want to simply check the presence of
given node or attribute, use an empty string (`""`) as a `PATTERN`.
+* `@count PATH XPATH COUNT' checks for the occurrence of given XPath
+ in the given file. The number of occurrences must match the given count.
+
All conditions can be negated with `!`. `@!has foo/type.NoSuch.html`
checks if the given file does not exist, for example.
return ret
+def check_tree_count(tree, path, count):
+ path = normalize_xpath(path)
+ return len(tree.findall(path)) == count
+
+
def check(target, commands):
cache = CachedFiles(target)
for c in commands:
raise RuntimeError('Invalid number of @{} arguments \
at line {}'.format(c.cmd, c.lineno))
+ elif c.cmd == 'count': # count test
+ if len(c.args) == 3: # @count <path> <pat> <count> = count test
+ ret = check_tree_count(cache.get_tree(c.args[0]), c.args[1], int(c.args[2]))
+ else:
+ raise RuntimeError('Invalid number of @{} arguments \
+ at line {}'.format(c.cmd, c.lineno))
+
elif c.cmd == 'valid-html':
raise RuntimeError('Unimplemented @valid-html at line {}'.format(c.lineno))
unsafe impl<T: Sync + Send> Send for Weak<T> { }
unsafe impl<T: Sync + Send> Sync for Weak<T> { }
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: fmt::Debug> fmt::Debug for Weak<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "(Weak)")
+ }
+}
+
struct ArcInner<T> {
strong: atomic::AtomicUsize,
weak: atomic::AtomicUsize,
libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
} else {
let new_ptr = allocate(size, align);
- ptr::copy_memory(new_ptr, ptr, cmp::min(size, old_size));
+ ptr::copy(new_ptr, ptr, cmp::min(size, old_size));
deallocate(ptr, old_size, align);
new_ptr
}
#![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();
/// ```rust
/// use std::borrow::Cow;
///
-/// fn abs_all(input: &mut Cow<[int]>) {
+/// fn abs_all(input: &mut Cow<[i32]>) {
/// for i in 0..input.len() {
/// let v = input[i];
/// if v < 0 {
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 {
vals: RawItems::from_slice(self.vals()),
edges: RawItems::from_slice(self.edges()),
- ptr: *self.keys as *mut u8,
+ ptr: Unique::new(*self.keys as *mut u8),
capacity: self.capacity(),
is_leaf: self.is_leaf()
},
// 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
edges: RawItems<Node<K, V>>,
// For deallocation when we are done iterating.
- ptr: *mut u8,
+ ptr: Unique<u8>,
capacity: usize,
is_leaf: bool
}
+unsafe impl<K: Sync, V: Sync> Sync for MoveTraversalImpl<K, V> {}
+unsafe impl<K: Send, V: Send> Send for MoveTraversalImpl<K, V> {}
+
impl<K, V> TraversalImpl for MoveTraversalImpl<K, V> {
type Item = (K, V);
type Edge = Node<K, V>;
let (alignment, size) =
calculate_allocation_generic::<K, V>(self.capacity, self.is_leaf);
- unsafe { heap::deallocate(self.ptr, size, alignment) };
+ unsafe { heap::deallocate(*self.ptr, size, alignment) };
}
}
/// A traversal over a node's entries and edges
pub type Traversal<'a, K, V> = AbsTraversal<ElemsAndEdges<Zip<slice::Iter<'a, K>,
slice::Iter<'a, V>>,
- slice::Iter<'a, Node<K, V>>>>;
+ slice::Iter<'a, Node<K, V>>>>;
/// A mutable traversal over a node's entries and edges
pub type MutTraversal<'a, K, V> = AbsTraversal<ElemsAndEdges<Zip<slice::Iter<'a, K>,
slice::IterMut<'a, V>>,
- slice::IterMut<'a, Node<K, V>>>>;
+ slice::IterMut<'a, Node<K, V>>>>;
/// An owning traversal over a node's entries and edges
pub type MoveTraversal<K, V> = AbsTraversal<MoveTraversalImpl<K, V>>;
/// }
///
/// 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]
#![stable(feature = "rust1", since = "1.0.0")]
pub use core::fmt::{Formatter, Result, Write, rt};
-pub use core::fmt::{Show, String, Octal, Binary};
+pub use core::fmt::{Octal, Binary};
pub use core::fmt::{Display, Debug};
pub use core::fmt::{LowerHex, UpperHex, Pointer};
pub use core::fmt::{LowerExp, UpperExp};
#![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
}
impl<T> Copy for Rawlink<T> {}
-unsafe impl<T:'static+Send> Send for Rawlink<T> {}
-unsafe impl<T:Send+Sync> Sync for Rawlink<T> {}
+unsafe impl<T:Send> Send for Rawlink<T> {}
+unsafe impl<T:Sync> Sync for Rawlink<T> {}
struct Node<T> {
next: Link<T>,
/// }
/// {
/// 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) {
marker: PhantomData<&'a T>,
}
+unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {}
+unsafe impl<'a, T: Send> Send for Drain<'a, T> {}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Iterator for Drain<'a, T> {
type Item = T;
}
}
- 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]
use core::default::Default;
use core::fmt;
use core::iter::{self, repeat, FromIterator, IntoIterator, RandomAccessIterator};
-use core::marker;
use core::mem;
use core::num::{Int, UnsignedInt};
use core::ops::{Index, IndexMut};
ptr: Unique<T>,
}
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Send> Send for VecDeque<T> {}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Sync> Sync for VecDeque<T> {}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Clone> Clone for VecDeque<T> {
fn clone(&self) -> VecDeque<T> {
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);
IterMut {
tail: self.tail,
head: self.head,
- cap: self.cap,
- ptr: *self.ptr,
- marker: marker::PhantomData,
+ ring: unsafe { self.buffer_as_mut_slice() },
}
}
// `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);
}
}
}
}
-// FIXME This was implemented differently from Iter because of a problem
-// with returning the mutable reference. I couldn't find a way to
-// make the lifetime checker happy so, but there should be a way.
/// `VecDeque` mutable iterator.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IterMut<'a, T:'a> {
- ptr: *mut T,
+ ring: &'a mut [T],
tail: usize,
head: usize,
- cap: usize,
- marker: marker::PhantomData<&'a mut T>,
}
#[stable(feature = "rust1", since = "1.0.0")]
return None;
}
let tail = self.tail;
- self.tail = wrap_index(self.tail + 1, self.cap);
+ self.tail = wrap_index(self.tail + 1, self.ring.len());
unsafe {
- Some(&mut *self.ptr.offset(tail as isize))
+ let elem = self.ring.get_unchecked_mut(tail);
+ Some(&mut *(elem as *mut _))
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
- let len = count(self.tail, self.head, self.cap);
+ let len = count(self.tail, self.head, self.ring.len());
(len, Some(len))
}
}
if self.tail == self.head {
return None;
}
- self.head = wrap_index(self.head - 1, self.cap);
+ self.head = wrap_index(self.head - 1, self.ring.len());
unsafe {
- Some(&mut *self.ptr.offset(self.head as isize))
+ let elem = self.ring.get_unchecked_mut(self.head);
+ Some(&mut *(elem as *mut _))
}
}
}
#[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]
pub enum SignificantDigits {
/// At most the given number of digits will be printed, truncating any
/// trailing zeroes.
- DigMax(uint),
+ DigMax(usize),
/// Precisely the given number of digits will be printed.
- DigExact(uint)
+ DigExact(usize)
}
/// How to emit the sign of a number.
// If reached left end of number, have to
// insert additional digit:
if i < 0
- || buf[i as uint] == b'-'
- || buf[i as uint] == b'+' {
- for j in (i as uint + 1..end).rev() {
+ || buf[i as usize] == b'-'
+ || buf[i as usize] == b'+' {
+ for j in (i as usize + 1..end).rev() {
buf[j + 1] = buf[j];
}
- buf[(i + 1) as uint] = value2ascii(1);
+ buf[(i + 1) as usize] = value2ascii(1);
end += 1;
break;
}
// Skip the '.'
- if buf[i as uint] == b'.' { i -= 1; continue; }
+ if buf[i as usize] == b'.' { i -= 1; continue; }
// Either increment the digit,
// or set to 0 if max and carry the 1.
- let current_digit = ascii2value(buf[i as uint]);
+ let current_digit = ascii2value(buf[i as usize]);
if current_digit < (radix - 1) {
- buf[i as uint] = value2ascii(current_digit+1);
+ buf[i as usize] = value2ascii(current_digit+1);
break;
} else {
- buf[i as uint] = value2ascii(0);
+ buf[i as usize] = value2ascii(0);
i -= 1;
}
}
struct Filler<'a> {
buf: &'a mut [u8],
- end: &'a mut uint,
+ end: &'a mut usize,
}
impl<'a> fmt::Write for Filler<'a> {
/// traits.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Formatter<'a> {
- flags: uint,
+ flags: u32,
fill: char,
align: rt::v1::Alignment,
- width: Option<uint>,
- precision: Option<uint>,
+ width: Option<usize>,
+ precision: Option<usize>,
buf: &'a mut (Write+'a),
curarg: slice::Iter<'a, ArgumentV1<'a>>,
impl<'a> ArgumentV1<'a> {
#[inline(never)]
- fn show_uint(x: &uint, f: &mut Formatter) -> Result {
+ fn show_usize(x: &usize, f: &mut Formatter) -> Result {
Display::fmt(x, f)
}
#[doc(hidden)]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn from_uint(x: &uint) -> ArgumentV1 {
- ArgumentV1::new(x, ArgumentV1::show_uint)
+ pub fn from_usize(x: &usize) -> ArgumentV1 {
+ ArgumentV1::new(x, ArgumentV1::show_usize)
}
- fn as_uint(&self) -> Option<uint> {
- if self.formatter as uint == ArgumentV1::show_uint as uint {
- Some(unsafe { *(self.value as *const _ as *const uint) })
+ fn as_usize(&self) -> Option<usize> {
+ if self.formatter as usize == ArgumentV1::show_usize as usize {
+ Some(unsafe { *(self.value as *const _ as *const usize) })
} else {
None
}
/// The `pieces` array must be at least as long as `fmt` to construct
/// a valid Arguments structure. Also, any `Count` within `fmt` that is
/// `CountIsParam` or `CountIsNextParam` has to point to an argument
- /// created with `argumentuint`. However, failing to do so doesn't cause
+ /// created with `argumentusize`. However, failing to do so doesn't cause
/// unsafety, but will ignore invalid .
#[doc(hidden)] #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
}
}
-/// Format trait for the `:?` format. Useful for debugging, all types
-/// should implement this.
-#[deprecated(since = "1.0.0", reason = "renamed to Debug")]
-#[unstable(feature = "old_fmt")]
-pub trait Show {
- /// Formats the value using the given formatter.
- #[stable(feature = "rust1", since = "1.0.0")]
- fn fmt(&self, &mut Formatter) -> Result;
-}
-
/// Format trait for the `:?` format. Useful for debugging, all types
/// should implement this.
#[stable(feature = "rust1", since = "1.0.0")]
fn fmt(&self, &mut Formatter) -> Result;
}
-#[allow(deprecated)]
-impl<T: Show + ?Sized> Debug for T {
- #[allow(deprecated)]
- fn fmt(&self, f: &mut Formatter) -> Result { Show::fmt(self, f) }
-}
-
-/// When a value can be semantically expressed as a String, this trait may be
-/// used. It corresponds to the default format, `{}`.
-#[deprecated(since = "1.0.0", reason = "renamed to Display")]
-#[unstable(feature = "old_fmt")]
-pub trait String {
- /// Formats the value using the given formatter.
- #[stable(feature = "rust1", since = "1.0.0")]
- fn fmt(&self, &mut Formatter) -> Result;
-}
-
/// When a value can be semantically expressed as a String, this trait may be
/// used. It corresponds to the default format, `{}`.
#[rustc_on_unimplemented = "`{Self}` cannot be formatted with the default \
fn fmt(&self, &mut Formatter) -> Result;
}
-#[allow(deprecated)]
-impl<T: String + ?Sized> Display for T {
- #[allow(deprecated)]
- fn fmt(&self, f: &mut Formatter) -> Result { String::fmt(self, f) }
-}
-
/// Format trait for the `o` character
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Octal {
(value.formatter)(value.value, self)
}
- fn getcount(&mut self, cnt: &rt::v1::Count) -> Option<uint> {
+ fn getcount(&mut self, cnt: &rt::v1::Count) -> Option<usize> {
match *cnt {
rt::v1::Count::Is(n) => Some(n),
rt::v1::Count::Implied => None,
rt::v1::Count::Param(i) => {
- self.args[i].as_uint()
+ self.args[i].as_usize()
}
rt::v1::Count::NextParam => {
- self.curarg.next().and_then(|arg| arg.as_uint())
+ self.curarg.next().and_then(|arg| arg.as_usize())
}
}
}
let mut sign = None;
if !is_positive {
sign = Some('-'); width += 1;
- } else if self.flags & (1 << (FlagV1::SignPlus as uint)) != 0 {
+ } else if self.flags & (1 << (FlagV1::SignPlus as u32)) != 0 {
sign = Some('+'); width += 1;
}
let mut prefixed = false;
- if self.flags & (1 << (FlagV1::Alternate as uint)) != 0 {
+ if self.flags & (1 << (FlagV1::Alternate as u32)) != 0 {
prefixed = true; width += prefix.char_len();
}
}
// The sign and prefix goes before the padding if the fill character
// is zero
- Some(min) if self.flags & (1 << (FlagV1::SignAwareZeroPad as uint)) != 0 => {
+ Some(min) if self.flags & (1 << (FlagV1::SignAwareZeroPad as u32)) != 0 => {
self.fill = '0';
try!(write_prefix(self));
self.with_padding(min - width, Alignment::Right, |f| {
/// Runs a callback, emitting the correct padding either before or
/// afterwards depending on whether right or left alignment is requested.
- fn with_padding<F>(&mut self, padding: uint, default: Alignment,
+ fn with_padding<F>(&mut self, padding: usize, default: Alignment,
f: F) -> Result
where F: FnOnce(&mut Formatter) -> Result,
{
/// Flags for formatting (packed version of rt::Flag)
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn flags(&self) -> usize { self.flags }
+ pub fn flags(&self) -> u32 { self.flags }
/// Character used as 'fill' whenever there is alignment
#[unstable(feature = "core", reason = "method was just created")]
/// Optionally specified integer width that the output should be
#[unstable(feature = "core", reason = "method was just created")]
- pub fn width(&self) -> Option<uint> { self.width }
+ pub fn width(&self) -> Option<usize> { self.width }
/// Optionally specified precision for numeric types
#[unstable(feature = "core", reason = "method was just created")]
- pub fn precision(&self) -> Option<uint> { self.precision }
+ pub fn precision(&self) -> Option<usize> { self.precision }
}
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Pointer for *const T {
fn fmt(&self, f: &mut Formatter) -> Result {
- f.flags |= 1 << (FlagV1::Alternate as uint);
- let ret = LowerHex::fmt(&(*self as uint), f);
- f.flags &= !(1 << (FlagV1::Alternate as uint));
+ f.flags |= 1 << (FlagV1::Alternate as u32);
+ let ret = LowerHex::fmt(&(*self as u32), f);
+ f.flags &= !(1 << (FlagV1::Alternate as u32));
ret
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Debug> Debug for [T] {
fn fmt(&self, f: &mut Formatter) -> Result {
- if f.flags & (1 << (FlagV1::Alternate as uint)) == 0 {
+ if f.flags & (1 << (FlagV1::Alternate as u32)) == 0 {
try!(write!(f, "["));
}
let mut is_first = true;
}
try!(write!(f, "{:?}", *x))
}
- if f.flags & (1 << (FlagV1::Alternate as uint)) == 0 {
+ if f.flags & (1 << (FlagV1::Alternate as u32)) == 0 {
try!(write!(f, "]"));
}
Ok(())
show! { $Uint with $SU }
}
}
-integer! { int, uint, "i", "u" }
+integer! { isize, usize, "i", "u" }
integer! { i8, u8 }
integer! { i16, u16 }
integer! { i32, u32 }
#[stable(feature = "rust1", since = "1.0.0")]
pub align: Alignment,
#[stable(feature = "rust1", since = "1.0.0")]
- pub flags: uint,
+ pub flags: u32,
#[stable(feature = "rust1", since = "1.0.0")]
pub precision: Count,
#[stable(feature = "rust1", since = "1.0.0")]
//!
//! #[derive(Hash)]
//! struct Person {
-//! id: uint,
+//! id: u32,
//! name: String,
//! phone: u64,
//! }
//! use std::hash::{hash, Hash, Hasher, SipHasher};
//!
//! struct Person {
-//! id: uint,
+//! id: u32,
//! name: String,
//! phone: u64,
//! }
pub struct SipHasher {
k0: u64,
k1: u64,
- length: uint, // how many bytes we've processed
+ length: usize, // how many bytes we've processed
v0: u64, // hash state
v1: u64,
v2: u64,
v3: u64,
tail: u64, // unprocessed bytes le
- ntail: uint, // how many bytes in tail are valid
+ ntail: usize, // how many bytes in tail are valid
}
// sadly, these macro definitions can't appear later,
/// will trigger a compiler error.
pub fn return_address() -> *const u8;
- /// Returns `true` if a type requires drop glue.
+ /// Returns `true` if the actual type given as `T` requires drop
+ /// glue; returns `false` if the actual type provided for `T`
+ /// implements `Copy`.
+ ///
+ /// If the actual type neither requires drop glue nor implements
+ /// `Copy`, then may return `true` or `false`.
pub fn needs_drop<T>() -> bool;
/// Returns `true` if a type is managed (will be allocated on the local heap)
/// }
/// }
/// ```
- #[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
use ops::{Add, Deref, FnMut};
use option::Option;
use option::Option::{Some, None};
-use marker::Sized;
+use marker::{Send, Sized, Sync};
use usize;
/// An interface for dealing with "external iterators". These types of iterators
#[rustc_on_unimplemented = "`{Self}` is not an iterator; maybe try calling `.iter()` or a similar \
method"]
pub trait Iterator {
+ /// The type of the elements being iterated
#[stable(feature = "rust1", since = "1.0.0")]
type Item;
/// Conversion into an `Iterator`
#[stable(feature = "rust1", since = "1.0.0")]
pub trait IntoIterator {
+ /// The type of the elements being iterated
#[stable(feature = "rust1", since = "1.0.0")]
type Item;
+ /// A container for iterating over elements of type Item
#[stable(feature = "rust1", since = "1.0.0")]
type IntoIter: Iterator<Item=Self::Item>;
/// ```
/// 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 }
}
peeked: Option<I::Item>,
}
+// FIXME: after #22828 being fixed, the following unsafe impl should be removed
+unsafe impl<I: Iterator> Sync for Peekable<I> where I: Sync, I::Item: Sync {}
+unsafe impl<I: Iterator> Send for Peekable<I> where I: Send, I::Item: Send {}
+
impl<I: Iterator + Clone> Clone for Peekable<I> where I::Item: Clone {
fn clone(&self) -> Peekable<I> {
Peekable {
panic!("explicit panic")
);
($msg:expr) => ({
- #[cfg(stage0)]
- static _MSG_FILE_LINE: (&'static str, &'static str, usize) = ($msg, file!(), line!());
- #[cfg(not(stage0))]
static _MSG_FILE_LINE: (&'static str, &'static str, u32) = ($msg, file!(), line!());
::core::panicking::panic(&_MSG_FILE_LINE)
});
// used inside a dead function. Just `#[allow(dead_code)]` is
// insufficient, since the user may have
// `#[forbid(dead_code)]` and which cannot be overridden.
- #[cfg(stage0)]
- static _FILE_LINE: (&'static str, usize) = (file!(), line!());
- #[cfg(not(stage0))]
static _FILE_LINE: (&'static str, u32) = (file!(), line!());
::core::panicking::panic_fmt(format_args!($fmt, $($arg)*), &_FILE_LINE)
});
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;
#[lang="add"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Add<RHS=Self> {
+ /// The resulting type after applying the `+` operator
#[stable(feature = "rust1", since = "1.0.0")]
type Output;
#[lang="sub"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Sub<RHS=Self> {
+ /// The resulting type after applying the `-` operator
#[stable(feature = "rust1", since = "1.0.0")]
type Output;
#[lang="mul"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Mul<RHS=Self> {
+ /// The resulting type after applying the `*` operator
#[stable(feature = "rust1", since = "1.0.0")]
type Output;
#[lang="div"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Div<RHS=Self> {
+ /// The resulting type after applying the `/` operator
#[stable(feature = "rust1", since = "1.0.0")]
type Output;
#[lang="rem"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Rem<RHS=Self> {
+ /// The resulting type after applying the `%` operator
#[stable(feature = "rust1", since = "1.0.0")]
type Output = Self;
#[lang="neg"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Neg {
+ /// The resulting type after applying the `-` operator
#[stable(feature = "rust1", since = "1.0.0")]
type Output;
#[lang="not"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Not {
+ /// The resulting type after applying the `!` operator
#[stable(feature = "rust1", since = "1.0.0")]
type Output;
#[lang="bitand"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait BitAnd<RHS=Self> {
+ /// The resulting type after applying the `&` operator
#[stable(feature = "rust1", since = "1.0.0")]
type Output;
#[lang="bitor"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait BitOr<RHS=Self> {
+ /// The resulting type after applying the `|` operator
#[stable(feature = "rust1", since = "1.0.0")]
type Output;
#[lang="bitxor"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait BitXor<RHS=Self> {
+ /// The resulting type after applying the `^` operator
#[stable(feature = "rust1", since = "1.0.0")]
type Output;
#[lang="shl"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Shl<RHS> {
+ /// The resulting type after applying the `<<` operator
#[stable(feature = "rust1", since = "1.0.0")]
type Output;
#[lang="shr"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Shr<RHS> {
+ /// The resulting type after applying the `>>` operator
#[stable(feature = "rust1", since = "1.0.0")]
type Output;
#[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Index<Idx: ?Sized> {
+ /// The returned type after indexing
type Output: ?Sized;
/// The method for the indexing (`Foo[Bar]`) operation
#[lang="deref"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Deref {
+ /// The resulting type after dereferencing
#[stable(feature = "rust1", since = "1.0.0")]
type Target: ?Sized;
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_paren_sugar]
pub trait Fn<Args> {
+ /// The returned type after the call operator is used.
type Output;
/// This is called when the call operator is used.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_paren_sugar]
pub trait FnMut<Args> {
+ /// The returned type after the call operator is used.
type Output;
/// This is called when the call operator is used.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_paren_sugar]
pub trait FnOnce<Args> {
+ /// The returned type after the call operator is used.
type Output;
/// This is called when the call operator is used.
/// ```
/// 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();
#[cold] #[inline(never)] // this is the slow path, always
#[lang="panic"]
-#[cfg(stage0)]
-pub fn panic(expr_file_line: &(&'static str, &'static str, usize)) -> ! {
- let (expr, file, line) = *expr_file_line;
- panic_fmt(format_args!("{}", expr), &(file, line))
-}
-#[cold] #[inline(never)] // this is the slow path, always
-#[lang="panic"]
-#[cfg(not(stage0))]
pub fn panic(expr_file_line: &(&'static str, &'static str, u32)) -> ! {
let (expr, file, line) = *expr_file_line;
panic_fmt(format_args!("{}", expr), &(file, line))
#[cold] #[inline(never)]
#[lang="panic_bounds_check"]
-#[cfg(stage0)]
-fn panic_bounds_check(file_line: &(&'static str, usize),
- index: usize, len: usize) -> ! {
- panic_fmt(format_args!("index out of bounds: the len is {} but the index is {}",
- len, index), file_line)
-}
-#[cold] #[inline(never)]
-#[lang="panic_bounds_check"]
-#[cfg(not(stage0))]
fn panic_bounds_check(file_line: &(&'static str, u32),
index: usize, len: usize) -> ! {
panic_fmt(format_args!("index out of bounds: the len is {} but the index is {}",
}
#[cold] #[inline(never)]
-#[cfg(stage0)]
-pub fn panic_fmt(fmt: fmt::Arguments, file_line: &(&'static str, usize)) -> ! {
- #[allow(improper_ctypes)]
- extern {
- #[lang = "panic_fmt"]
- fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: uint) -> !;
- }
- let (file, line) = *file_line;
- unsafe { panic_impl(fmt, file, line as uint) }
-}
-#[cold] #[inline(never)]
-#[cfg(not(stage0))]
pub fn panic_fmt(fmt: fmt::Arguments, file_line: &(&'static str, u32)) -> ! {
#[allow(improper_ctypes)]
extern {
// 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 {
- type Target;
+pub trait PtrExt {
+ /// The type which is being pointed at
+ 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 {
- type Target;
+ /// The type which is being pointed at
+ 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")]
use ptr::PtrExt;
use mem;
use mem::size_of;
-use marker::{Sized, self};
+use marker::{Send, Sized, Sync, self};
use raw::Repr;
// Avoid conflicts with *both* the Slice trait (buggy) and the `slice::raw` module.
use raw::Slice as RawSlice;
_marker: marker::PhantomData<&'a T>,
}
+unsafe impl<'a, T: Sync> Sync for Iter<'a, T> {}
+unsafe impl<'a, T: Sync> Send for Iter<'a, T> {}
+
#[unstable(feature = "core")]
impl<'a, T> ops::Index<ops::Range<usize>> for Iter<'a, T> {
type Output = [T];
_marker: marker::PhantomData<&'a mut T>,
}
+unsafe impl<'a, T: Sync> Sync for IterMut<'a, T> {}
+unsafe impl<'a, T: Send> Send for IterMut<'a, T> {}
#[unstable(feature = "core")]
impl<'a, T> ops::Index<ops::Range<usize>> for IterMut<'a, T> {
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);
}
}
}
type Item = &'a str;
#[inline]
+ #[allow(deprecated)]
fn next(&mut self) -> Option<&'a str> {
Iterator::next(&mut self.0)
}
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;
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
-#![feature(int_uint)]
#![feature(staged_api)]
#![feature(unicode)]
/// Optionally specified alignment
pub align: Alignment,
/// Packed version of various flags provided
- pub flags: uint,
+ pub flags: u32,
/// The integer precision to use
pub precision: Count<'a>,
/// The string width requested for the resulting format
/// The argument will be in the next position. This is the default.
ArgumentNext,
/// The argument is located at a specific index.
- ArgumentIs(uint),
+ ArgumentIs(usize),
/// The argument has a name.
ArgumentNamed(&'a str),
}
#[derive(Copy, PartialEq)]
pub enum Count<'a> {
/// The count is specified explicitly.
- CountIs(uint),
+ CountIs(usize),
/// The count is specified by the argument with the given name.
CountIsName(&'a str),
/// The count is specified by the argument at the given index.
- CountIsParam(uint),
+ CountIsParam(usize),
/// The count is specified by the next parameter.
CountIsNextParam,
/// The count is implied and cannot be explicitly specified.
/// Parses all of a string which is to be considered a "raw literal" in a
/// format string. This is everything outside of the braces.
- fn string(&mut self, start: uint) -> &'a str {
+ fn string(&mut self, start: usize) -> &'a str {
loop {
// we may not consume the character, so clone the iterator
match self.cur.clone().next() {
}
// Sign flags
if self.consume('+') {
- spec.flags |= 1 << (FlagSignPlus as uint);
+ spec.flags |= 1 << (FlagSignPlus as u32);
} else if self.consume('-') {
- spec.flags |= 1 << (FlagSignMinus as uint);
+ spec.flags |= 1 << (FlagSignMinus as u32);
}
// Alternate marker
if self.consume('#') {
- spec.flags |= 1 << (FlagAlternate as uint);
+ spec.flags |= 1 << (FlagAlternate as u32);
}
// Width and precision
let mut havewidth = false;
spec.width = CountIsParam(0);
havewidth = true;
} else {
- spec.flags |= 1 << (FlagSignAwareZeroPad as uint);
+ spec.flags |= 1 << (FlagSignAwareZeroPad as u32);
}
}
if !havewidth {
/// Optionally parses an integer at the current position. This doesn't deal
/// with overflow at all, it's just accumulating digits.
- fn integer(&mut self) -> Option<uint> {
+ fn integer(&mut self) -> Option<usize> {
let mut cur = 0;
let mut found = false;
loop {
format: FormatSpec {
fill: None,
align: AlignUnknown,
- flags: (1 << FlagSignMinus as uint),
+ flags: (1 << FlagSignMinus as u32),
precision: CountImplied,
width: CountImplied,
ty: "",
format: FormatSpec {
fill: None,
align: AlignUnknown,
- flags: (1 << FlagSignPlus as uint) | (1 << FlagAlternate as uint),
+ flags: (1 << FlagSignPlus as u32) | (1 << FlagAlternate as u32),
precision: CountImplied,
width: CountImplied,
ty: "",
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;
#[macro_export]
macro_rules! log {
($lvl:expr, $($arg:tt)+) => ({
- #[cfg(stage0)]
- static LOC: ::log::LogLocation = ::log::LogLocation {
- line: line!() as u32,
- file: file!(),
- module_path: module_path!(),
- };
- #[cfg(not(stage0))]
static LOC: ::log::LogLocation = ::log::LogLocation {
line: line!(),
file: file!(),
/// 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")
}
}
}
tm.span, "a type method");
}
+ fn check_trait_method(&mut self, cx: &Context, it: &ast::TraitItem) {
+ if let ast::TraitItem::TypeTraitItem(ref ty) = *it {
+ let assoc_ty = &ty.ty_param;
+ self.check_missing_docs_attrs(cx, Some(assoc_ty.id), &ty.attrs,
+ assoc_ty.span, "an associated type");
+ }
+ }
+
fn check_struct_field(&mut self, cx: &Context, sf: &ast::StructField) {
if let ast::NamedField(_, vis) = sf.node.kind {
if vis == ast::Public || self.in_variant {
stability::check_path(cx.tcx, path, id,
&mut |id, sp, stab| self.lint(cx, id, sp, stab));
}
+
+ fn check_pat(&mut self, cx: &Context, pat: &ast::Pat) {
+ stability::check_pat(cx.tcx, pat,
+ &mut |id, sp, stab| self.lint(cx, id, sp, stab))
+ }
}
declare_lint! {
continue
}
visited.insert(cfg_id);
- let node_id = cfg.graph.node_data(idx).id;
+ let node_id = cfg.graph.node_data(idx).id();
// is this a recursive call?
if node_id != ast::DUMMY_NODE_ID && checker(cx.tcx, impl_node_id, id, name, node_id) {
_: 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); }
+ }
+ }
+}
+
ty::ty_err => {
mywrite!(w, "e");
}
- ty::ty_open(_) => {
- cx.diag.handler().bug("unexpected type in enc_sty (ty_open)");
- }
}
let end = w.tell().unwrap();
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);
use middle::cfg::*;
use middle::def;
use middle::graph;
+use middle::pat_util;
use middle::region::CodeExtent;
use middle::ty;
use syntax::ast;
use syntax::ast_util;
use syntax::ptr::P;
-use util::nodemap::NodeMap;
struct CFGBuilder<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
- exit_map: NodeMap<CFGIndex>,
graph: CFGGraph,
fn_exit: CFGIndex,
loop_scopes: Vec<LoopScope>,
pub fn construct(tcx: &ty::ctxt,
blk: &ast::Block) -> CFG {
let mut graph = graph::Graph::new();
- let entry = add_initial_dummy_node(&mut graph);
+ let entry = graph.add_node(CFGNodeData::Entry);
// `fn_exit` is target of return exprs, which lies somewhere
// outside input `blk`. (Distinguishing `fn_exit` and `block_exit`
// also resolves chicken-and-egg problem that arises if you try to
// have return exprs jump to `block_exit` during construction.)
- let fn_exit = add_initial_dummy_node(&mut graph);
+ let fn_exit = graph.add_node(CFGNodeData::Exit);
let block_exit;
let mut cfg_builder = CFGBuilder {
- exit_map: NodeMap(),
graph: graph,
fn_exit: fn_exit,
tcx: tcx,
};
block_exit = cfg_builder.block(blk, entry);
cfg_builder.add_contained_edge(block_exit, fn_exit);
- let CFGBuilder {exit_map, graph, ..} = cfg_builder;
- CFG {exit_map: exit_map,
- graph: graph,
+ let CFGBuilder {graph, ..} = cfg_builder;
+ CFG {graph: graph,
entry: entry,
exit: fn_exit}
}
-fn add_initial_dummy_node(g: &mut CFGGraph) -> CFGIndex {
- g.add_node(CFGNodeData { id: ast::DUMMY_NODE_ID })
-}
-
impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
fn block(&mut self, blk: &ast::Block, pred: CFGIndex) -> CFGIndex {
let mut stmts_exit = pred;
let expr_exit = self.opt_expr(&blk.expr, stmts_exit);
- self.add_node(blk.id, &[expr_exit])
+ self.add_ast_node(blk.id, &[expr_exit])
}
fn stmt(&mut self, stmt: &ast::Stmt, pred: CFGIndex) -> CFGIndex {
match stmt.node {
ast::StmtDecl(ref decl, id) => {
let exit = self.decl(&**decl, pred);
- self.add_node(id, &[exit])
+ self.add_ast_node(id, &[exit])
}
ast::StmtExpr(ref expr, id) | ast::StmtSemi(ref expr, id) => {
let exit = self.expr(&**expr, pred);
- self.add_node(id, &[exit])
+ self.add_ast_node(id, &[exit])
}
ast::StmtMac(..) => {
ast::PatLit(..) |
ast::PatRange(..) |
ast::PatWild(_) => {
- self.add_node(pat.id, &[pred])
+ self.add_ast_node(pat.id, &[pred])
}
ast::PatBox(ref subpat) |
ast::PatRegion(ref subpat, _) |
ast::PatIdent(_, _, Some(ref subpat)) => {
let subpat_exit = self.pat(&**subpat, pred);
- self.add_node(pat.id, &[subpat_exit])
+ self.add_ast_node(pat.id, &[subpat_exit])
}
ast::PatEnum(_, Some(ref subpats)) |
ast::PatTup(ref subpats) => {
let pats_exit = self.pats_all(subpats.iter(), pred);
- self.add_node(pat.id, &[pats_exit])
+ self.add_ast_node(pat.id, &[pats_exit])
}
ast::PatStruct(_, ref subpats, _) => {
let pats_exit =
self.pats_all(subpats.iter().map(|f| &f.node.pat), pred);
- self.add_node(pat.id, &[pats_exit])
+ self.add_ast_node(pat.id, &[pats_exit])
}
ast::PatVec(ref pre, ref vec, ref post) => {
let pre_exit = self.pats_all(pre.iter(), pred);
let vec_exit = self.pats_all(vec.iter(), pre_exit);
let post_exit = self.pats_all(post.iter(), vec_exit);
- self.add_node(pat.id, &[post_exit])
+ self.add_ast_node(pat.id, &[post_exit])
}
ast::PatMac(_) => {
pats.fold(pred, |pred, pat| self.pat(&**pat, pred))
}
- fn pats_any(&mut self,
- pats: &[P<ast::Pat>],
- pred: CFGIndex) -> CFGIndex {
- //! Handles case where just one of the patterns must match.
-
- if pats.len() == 1 {
- self.pat(&*pats[0], pred)
- } else {
- let collect = self.add_dummy_node(&[]);
- for pat in pats {
- let pat_exit = self.pat(&**pat, pred);
- self.add_contained_edge(pat_exit, collect);
- }
- collect
- }
- }
-
fn expr(&mut self, expr: &ast::Expr, pred: CFGIndex) -> CFGIndex {
match expr.node {
ast::ExprBlock(ref blk) => {
let blk_exit = self.block(&**blk, pred);
- self.add_node(expr.id, &[blk_exit])
+ self.add_ast_node(expr.id, &[blk_exit])
}
ast::ExprIf(ref cond, ref then, None) => {
//
let cond_exit = self.expr(&**cond, pred); // 1
let then_exit = self.block(&**then, cond_exit); // 2
- self.add_node(expr.id, &[cond_exit, then_exit]) // 3,4
+ self.add_ast_node(expr.id, &[cond_exit, then_exit]) // 3,4
}
ast::ExprIf(ref cond, ref then, Some(ref otherwise)) => {
let cond_exit = self.expr(&**cond, pred); // 1
let then_exit = self.block(&**then, cond_exit); // 2
let else_exit = self.expr(&**otherwise, cond_exit); // 3
- self.add_node(expr.id, &[then_exit, else_exit]) // 4, 5
+ self.add_ast_node(expr.id, &[then_exit, else_exit]) // 4, 5
}
ast::ExprIfLet(..) => {
// Is the condition considered part of the loop?
let loopback = self.add_dummy_node(&[pred]); // 1
let cond_exit = self.expr(&**cond, loopback); // 2
- let expr_exit = self.add_node(expr.id, &[cond_exit]); // 3
+ let expr_exit = self.add_ast_node(expr.id, &[cond_exit]); // 3
self.loop_scopes.push(LoopScope {
loop_id: expr.id,
continue_index: loopback,
// may cause additional edges.
let loopback = self.add_dummy_node(&[pred]); // 1
- let expr_exit = self.add_node(expr.id, &[]); // 2
+ let expr_exit = self.add_ast_node(expr.id, &[]); // 2
self.loop_scopes.push(LoopScope {
loop_id: expr.id,
continue_index: loopback,
}
ast::ExprMatch(ref discr, ref arms, _) => {
- //
- // [pred]
- // |
- // v 1
- // [discr]
- // |
- // v 2
- // [cond1]
- // / \
- // | \
- // v 3 \
- // [pat1] \
- // | |
- // v 4 |
- // [guard1] |
- // | |
- // | |
- // v 5 v
- // [body1] [cond2]
- // | / \
- // | ... ...
- // | | |
- // v 6 v v
- // [.....expr.....]
- //
- let discr_exit = self.expr(&**discr, pred); // 1
-
- let expr_exit = self.add_node(expr.id, &[]);
- let mut cond_exit = discr_exit;
- for arm in arms {
- cond_exit = self.add_dummy_node(&[cond_exit]); // 2
- let pats_exit = self.pats_any(&arm.pats,
- cond_exit); // 3
- let guard_exit = self.opt_expr(&arm.guard,
- pats_exit); // 4
- let body_exit = self.expr(&*arm.body, guard_exit); // 5
- self.add_contained_edge(body_exit, expr_exit); // 6
- }
- expr_exit
+ self.match_(expr.id, &discr, &arms, pred)
}
ast::ExprBinary(op, ref l, ref r) if ast_util::lazy_binop(op.node) => {
//
let l_exit = self.expr(&**l, pred); // 1
let r_exit = self.expr(&**r, l_exit); // 2
- self.add_node(expr.id, &[l_exit, r_exit]) // 3,4
+ self.add_ast_node(expr.id, &[l_exit, r_exit]) // 3,4
}
ast::ExprRet(ref v) => {
let v_exit = self.opt_expr(v, pred);
- let b = self.add_node(expr.id, &[v_exit]);
+ let b = self.add_ast_node(expr.id, &[v_exit]);
self.add_returning_edge(expr, b);
- self.add_node(ast::DUMMY_NODE_ID, &[])
+ self.add_unreachable_node()
}
ast::ExprBreak(label) => {
let loop_scope = self.find_scope(expr, label);
- let b = self.add_node(expr.id, &[pred]);
+ let b = self.add_ast_node(expr.id, &[pred]);
self.add_exiting_edge(expr, b,
loop_scope, loop_scope.break_index);
- self.add_node(ast::DUMMY_NODE_ID, &[])
+ self.add_unreachable_node()
}
ast::ExprAgain(label) => {
let loop_scope = self.find_scope(expr, label);
- let a = self.add_node(expr.id, &[pred]);
+ let a = self.add_ast_node(expr.id, &[pred]);
self.add_exiting_edge(expr, a,
loop_scope, loop_scope.continue_index);
- self.add_node(ast::DUMMY_NODE_ID, &[])
+ self.add_unreachable_node()
}
ast::ExprVec(ref elems) => {
let &(_, ref expr, _) = a;
&**expr
}), post_inputs);
- self.add_node(expr.id, &[post_outputs])
+ self.add_ast_node(expr.id, &[post_outputs])
}
ast::ExprMac(..) |
ast::ExprClosure(..) |
ast::ExprLit(..) |
- ast::ExprPath(..) |
- ast::ExprQPath(..) => {
+ ast::ExprPath(..) => {
self.straightline(expr, pred, None::<ast::Expr>.iter())
}
}
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
if return_ty.diverges() {
- self.add_node(ast::DUMMY_NODE_ID, &[])
+ self.add_unreachable_node()
} else {
ret
}
//! Handles case of an expression that evaluates `subexprs` in order
let subexprs_exit = self.exprs(subexprs, pred);
- self.add_node(expr.id, &[subexprs_exit])
+ self.add_ast_node(expr.id, &[subexprs_exit])
+ }
+
+ fn match_(&mut self, id: ast::NodeId, discr: &ast::Expr,
+ arms: &[ast::Arm], pred: CFGIndex) -> CFGIndex {
+ // The CFG for match expression is quite complex, so no ASCII
+ // art for it (yet).
+ //
+ // The CFG generated below matches roughly what trans puts
+ // out. Each pattern and guard is visited in parallel, with
+ // arms containing multiple patterns generating multiple nodes
+ // for the same guard expression. The guard expressions chain
+ // into each other from top to bottom, with a specific
+ // exception to allow some additional valid programs
+ // (explained below). Trans differs slightly in that the
+ // pattern matching may continue after a guard but the visible
+ // behaviour should be the same.
+ //
+ // What is going on is explained in further comments.
+
+ // Visit the discriminant expression
+ let discr_exit = self.expr(discr, pred);
+
+ // Add a node for the exit of the match expression as a whole.
+ let expr_exit = self.add_ast_node(id, &[]);
+
+ // Keep track of the previous guard expressions
+ let mut prev_guards = Vec::new();
+ // Track if the previous pattern contained bindings or wildcards
+ let mut prev_has_bindings = false;
+
+ for arm in arms {
+ // Add an exit node for when we've visited all the
+ // patterns and the guard (if there is one) in the arm.
+ let arm_exit = self.add_dummy_node(&[]);
+
+ for pat in &arm.pats {
+ // Visit the pattern, coming from the discriminant exit
+ let mut pat_exit = self.pat(&**pat, discr_exit);
+
+ // If there is a guard expression, handle it here
+ if let Some(ref guard) = arm.guard {
+ // Add a dummy node for the previous guard
+ // expression to target
+ let guard_start = self.add_dummy_node(&[pat_exit]);
+ // Visit the guard expression
+ let guard_exit = self.expr(&**guard, guard_start);
+
+ let this_has_bindings = pat_util::pat_contains_bindings_or_wild(
+ &self.tcx.def_map, &**pat);
+
+ // If both this pattern and the previous pattern
+ // were free of bindings, they must consist only
+ // of "constant" patterns. Note we cannot match an
+ // all-constant pattern, fail the guard, and then
+ // match *another* all-constant pattern. This is
+ // because if the previous pattern matches, then
+ // we *cannot* match this one, unless all the
+ // constants are the same (which is rejected by
+ // `check_match`).
+ //
+ // We can use this to be smarter about the flow
+ // along guards. If the previous pattern matched,
+ // then we know we will not visit the guard in
+ // this one (whether or not the guard succeeded),
+ // if the previous pattern failed, then we know
+ // the guard for that pattern will not have been
+ // visited. Thus, it is not possible to visit both
+ // the previous guard and the current one when
+ // both patterns consist only of constant
+ // sub-patterns.
+ //
+ // However, if the above does not hold, then all
+ // previous guards need to be wired to visit the
+ // current guard pattern.
+ if prev_has_bindings || this_has_bindings {
+ while let Some(prev) = prev_guards.pop() {
+ self.add_contained_edge(prev, guard_start);
+ }
+ }
+
+ prev_has_bindings = this_has_bindings;
+
+ // Push the guard onto the list of previous guards
+ prev_guards.push(guard_exit);
+
+ // Update the exit node for the pattern
+ pat_exit = guard_exit;
+ }
+
+ // Add an edge from the exit of this pattern to the
+ // exit of the arm
+ self.add_contained_edge(pat_exit, arm_exit);
+ }
+
+ // Visit the body of this arm
+ let body_exit = self.expr(&arm.body, arm_exit);
+
+ // Link the body to the exit of the expression
+ self.add_contained_edge(body_exit, expr_exit);
+ }
+
+ expr_exit
}
fn add_dummy_node(&mut self, preds: &[CFGIndex]) -> CFGIndex {
- self.add_node(ast::DUMMY_NODE_ID, preds)
+ self.add_node(CFGNodeData::Dummy, preds)
}
- fn add_node(&mut self, id: ast::NodeId, preds: &[CFGIndex]) -> CFGIndex {
- assert!(!self.exit_map.contains_key(&id));
- let node = self.graph.add_node(CFGNodeData {id: id});
- if id != ast::DUMMY_NODE_ID {
- assert!(!self.exit_map.contains_key(&id));
- self.exit_map.insert(id, node);
- }
+ fn add_ast_node(&mut self, id: ast::NodeId, preds: &[CFGIndex]) -> CFGIndex {
+ assert!(id != ast::DUMMY_NODE_ID);
+ self.add_node(CFGNodeData::AST(id), preds)
+ }
+
+ fn add_unreachable_node(&mut self) -> CFGIndex {
+ self.add_node(CFGNodeData::Unreachable, &[])
+ }
+
+ fn add_node(&mut self, data: CFGNodeData, preds: &[CFGIndex]) -> CFGIndex {
+ let node = self.graph.add_node(data);
for &pred in preds {
self.add_contained_edge(pred, node);
}
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));
}
}
}
dot::LabelText::LabelStr("entry".into_cow())
} else if i == self.cfg.exit {
dot::LabelText::LabelStr("exit".into_cow())
- } else if n.data.id == ast::DUMMY_NODE_ID {
+ } else if n.data.id() == ast::DUMMY_NODE_ID {
dot::LabelText::LabelStr("(dummy_node)".into_cow())
} else {
- let s = self.ast_map.node_to_string(n.data.id);
+ let s = self.ast_map.node_to_string(n.data.id());
// left-aligns the lines
let s = replace_newline_with_backslash_l(s);
dot::LabelText::EscStr(s.into_cow())
use middle::graph;
use middle::ty;
use syntax::ast;
-use util::nodemap::NodeMap;
mod construct;
pub mod graphviz;
pub struct CFG {
- pub exit_map: NodeMap<CFGIndex>,
pub graph: CFGGraph,
pub entry: CFGIndex,
pub exit: CFGIndex,
}
-#[derive(Copy)]
-pub struct CFGNodeData {
- pub id: ast::NodeId
+#[derive(Copy, PartialEq)]
+pub enum CFGNodeData {
+ AST(ast::NodeId),
+ Entry,
+ Exit,
+ Dummy,
+ Unreachable,
+}
+
+impl CFGNodeData {
+ pub fn id(&self) -> ast::NodeId {
+ if let CFGNodeData::AST(id) = *self {
+ id
+ } else {
+ ast::DUMMY_NODE_ID
+ }
+ }
}
pub struct CFGEdgeData {
}
pub fn node_is_reachable(&self, id: ast::NodeId) -> bool {
- self.graph.depth_traverse(self.entry).any(|node| node.id == id)
+ self.graph.depth_traverse(self.entry).any(|node| node.id() == id)
}
}
}
}
}
- 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) {
// mapping from node to cfg node index
// FIXME (#6298): Shouldn't this go with CFG?
- nodeid_to_index: NodeMap<CFGIndex>,
+ nodeid_to_index: NodeMap<Vec<CFGIndex>>,
// Bit sets per cfg node. The following three fields (`gens`, `kills`,
// and `on_entry`) all have the same structure. For each id in
changed: bool
}
-fn to_cfgidx_or_die(id: ast::NodeId, index: &NodeMap<CFGIndex>) -> CFGIndex {
- let opt_cfgindex = index.get(&id).cloned();
- opt_cfgindex.unwrap_or_else(|| {
- panic!("nodeid_to_index does not have entry for NodeId {}", id);
- })
+fn get_cfg_indices<'a>(id: ast::NodeId, index: &'a NodeMap<Vec<CFGIndex>>) -> &'a [CFGIndex] {
+ let opt_indices = index.get(&id);
+ opt_indices.map(|v| &v[..]).unwrap_or(&[])
}
impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
pprust::NodePat(pat) => pat.id
};
- if self.has_bitset_for_nodeid(id) {
- assert!(self.bits_per_id > 0);
- let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
+ if !self.has_bitset_for_nodeid(id) {
+ return Ok(());
+ }
+
+ assert!(self.bits_per_id > 0);
+ let indices = get_cfg_indices(id, &self.nodeid_to_index);
+ for &cfgidx in indices {
let (start, end) = self.compute_id_range(cfgidx);
let on_entry = &self.on_entry[start.. end];
let entry_str = bits_to_string(on_entry);
}
fn build_nodeid_to_index(decl: Option<&ast::FnDecl>,
- cfg: &cfg::CFG) -> NodeMap<CFGIndex> {
+ cfg: &cfg::CFG) -> NodeMap<Vec<CFGIndex>> {
let mut index = NodeMap();
// FIXME (#6298): Would it be better to fold formals from decl
}
cfg.graph.each_node(|node_idx, node| {
- if node.data.id != ast::DUMMY_NODE_ID {
- index.insert(node.data.id, node_idx);
+ if let cfg::CFGNodeData::AST(id) = node.data {
+ match index.entry(id).get() {
+ Ok(v) => v.push(node_idx),
+ Err(e) => {
+ e.insert(vec![node_idx]);
+ }
+ }
}
true
});
return index;
- fn add_entries_from_fn_decl(index: &mut NodeMap<CFGIndex>,
+ fn add_entries_from_fn_decl(index: &mut NodeMap<Vec<CFGIndex>>,
decl: &ast::FnDecl,
entry: CFGIndex) {
//! add mappings from the ast nodes for the formal bindings to
//! the entry-node in the graph.
struct Formals<'a> {
entry: CFGIndex,
- index: &'a mut NodeMap<CFGIndex>,
+ index: &'a mut NodeMap<Vec<CFGIndex>>,
}
let mut formals = Formals { entry: entry, index: index };
visit::walk_fn_decl(&mut formals, decl);
impl<'a, 'v> visit::Visitor<'v> for Formals<'a> {
fn visit_pat(&mut self, p: &ast::Pat) {
- self.index.insert(p.id, self.entry);
+ match self.index.entry(p.id).get() {
+ Ok(v) => v.push(self.entry),
+ Err(e) => {
+ e.insert(vec![self.entry]);
+ }
+ }
visit::walk_pat(self, p)
}
}
assert!(self.nodeid_to_index.contains_key(&id));
assert!(self.bits_per_id > 0);
- let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
- let (start, end) = self.compute_id_range(cfgidx);
- let gens = &mut self.gens[start.. end];
- set_bit(gens, bit);
+ let indices = get_cfg_indices(id, &self.nodeid_to_index);
+ for &cfgidx in indices {
+ let (start, end) = self.compute_id_range(cfgidx);
+ let gens = &mut self.gens[start.. end];
+ set_bit(gens, bit);
+ }
}
pub fn add_kill(&mut self, id: ast::NodeId, bit: uint) {
assert!(self.nodeid_to_index.contains_key(&id));
assert!(self.bits_per_id > 0);
- let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
- let (start, end) = self.compute_id_range(cfgidx);
- let kills = &mut self.kills[start.. end];
- set_bit(kills, bit);
+ let indices = get_cfg_indices(id, &self.nodeid_to_index);
+ for &cfgidx in indices {
+ let (start, end) = self.compute_id_range(cfgidx);
+ let kills = &mut self.kills[start.. end];
+ set_bit(kills, bit);
+ }
}
fn apply_gen_kill(&self, cfgidx: CFGIndex, bits: &mut [uint]) {
}
- pub fn each_bit_on_entry<F>(&self, id: ast::NodeId, f: F) -> bool where
+ pub fn each_bit_on_entry<F>(&self, id: ast::NodeId, mut f: F) -> bool where
F: FnMut(uint) -> bool,
{
//! Iterates through each bit that is set on entry to `id`.
if !self.has_bitset_for_nodeid(id) {
return true;
}
- let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
- self.each_bit_for_node(Entry, cfgidx, f)
+ let indices = get_cfg_indices(id, &self.nodeid_to_index);
+ for &cfgidx in indices {
+ if !self.each_bit_for_node(Entry, cfgidx, |i| f(i)) {
+ return false;
+ }
+ }
+ return true;
}
pub fn each_bit_for_node<F>(&self, e: EntryOrExit, cfgidx: CFGIndex, f: F) -> bool where
self.each_bit(slice, f)
}
- pub fn each_gen_bit<F>(&self, id: ast::NodeId, f: F) -> bool where
+ pub fn each_gen_bit<F>(&self, id: ast::NodeId, mut f: F) -> bool where
F: FnMut(uint) -> bool,
{
//! Iterates through each bit in the gen set for `id`.
return true;
}
- let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
- let (start, end) = self.compute_id_range(cfgidx);
- let gens = &self.gens[start.. end];
- debug!("{} each_gen_bit(id={}, gens={})",
- self.analysis_name, id, bits_to_string(gens));
- self.each_bit(gens, f)
+ let indices = get_cfg_indices(id, &self.nodeid_to_index);
+ for &cfgidx in indices {
+ let (start, end) = self.compute_id_range(cfgidx);
+ let gens = &self.gens[start.. end];
+ debug!("{} each_gen_bit(id={}, gens={})",
+ self.analysis_name, id, bits_to_string(gens));
+ if !self.each_bit(gens, |i| f(i)) {
+ return false;
+ }
+ }
+ return true;
}
fn each_bit<F>(&self, words: &[uint], mut f: F) -> bool where
let mut changed = false;
for &node_id in &edge.data.exiting_scopes {
- let opt_cfg_idx = self.nodeid_to_index.get(&node_id).cloned();
+ let opt_cfg_idx = self.nodeid_to_index.get(&node_id);
match opt_cfg_idx {
- Some(cfg_idx) => {
- let (start, end) = self.compute_id_range(cfg_idx);
- let kills = &self.kills[start.. end];
- if bitwise(&mut orig_kills, kills, &Union) {
- changed = true;
+ Some(indices) => {
+ for &cfg_idx in indices {
+ let (start, end) = self.compute_id_range(cfg_idx);
+ let kills = &self.kills[start.. end];
+ if bitwise(&mut orig_kills, kills, &Union) {
+ changed = true;
+ }
}
}
None => {
cfg.graph.each_node(|node_index, node| {
debug!("DataFlowContext::walk_cfg idx={:?} id={} begin in_out={}",
- node_index, node.data.id, bits_to_string(in_out));
+ node_index, node.data.id(), bits_to_string(in_out));
let (start, end) = self.dfcx.compute_id_range(node_index);
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.
None
}
}
- ty::ty_open(_) | ty::ty_infer(_) | ty::ty_err => None,
+ ty::ty_infer(_) | ty::ty_err => None,
}
}
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));
t
}
- ty::ty_open(..) |
ty::ty_bool |
ty::ty_char |
ty::ty_int(..) |
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
}
}
contains_bindings
}
+/// Checks if the pattern contains any patterns that bind something to
+/// an ident or wildcard, e.g. `foo`, or `Foo(_)`, `foo @ Bar(..)`,
+pub fn pat_contains_bindings_or_wild(dm: &DefMap, pat: &ast::Pat) -> bool {
+ let mut contains_bindings = false;
+ walk_pat(pat, |p| {
+ if pat_is_binding_or_wild(dm, p) {
+ contains_bindings = true;
+ false // there's at least one binding/wildcard, can short circuit now.
+ } else {
+ true
+ }
+ });
+ contains_bindings
+}
+
pub fn simple_identifier<'a>(pat: &'a ast::Pat) -> Option<&'a ast::Ident> {
match pat.node {
ast::PatIdent(ast::BindByValue(_), ref path1, None) => {
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> {
attrs: &Vec<Attribute>, item_sp: Span, f: F, required: bool) where
F: FnOnce(&mut Annotator),
{
+ debug!("annotate(id = {:?}, attrs = {:?})", id, attrs);
match attr::find_stability(self.sess.diagnostic(), attrs, item_sp) {
Some(stab) => {
+ debug!("annotate: found {:?}", stab);
self.index.local.insert(id, stab.clone());
// Don't inherit #[stable(feature = "rust1", since = "1.0.0")]
}
}
None => {
+ debug!("annotate: not found, use_parent = {:?}, parent = {:?}",
+ use_parent, self.parent);
if use_parent {
if let Some(stab) = self.parent.clone() {
self.index.local.insert(id, stab);
&mut |id, sp, stab| self.check(id, sp, stab));
visit::walk_path(self, path)
}
+
+ fn visit_pat(&mut self, pat: &ast::Pat) {
+ check_pat(self.tcx, pat,
+ &mut |id, sp, stab| self.check(id, sp, stab));
+ visit::walk_pat(self, pat)
+ }
}
/// Helper for discovering nodes to check for stability
None => return
}
}
+ ast::ExprField(ref base_e, ref field) => {
+ span = field.span;
+ match ty::expr_ty_adjusted(tcx, base_e).sty {
+ ty::ty_struct(did, _) => {
+ ty::lookup_struct_fields(tcx, did)
+ .iter()
+ .find(|f| f.name == field.node.name)
+ .unwrap_or_else(|| {
+ tcx.sess.span_bug(field.span,
+ "stability::check_expr: unknown named field access")
+ })
+ .id
+ }
+ _ => tcx.sess.span_bug(e.span,
+ "stability::check_expr: named field access on non-struct")
+ }
+ }
+ ast::ExprTupField(ref base_e, ref field) => {
+ span = field.span;
+ match ty::expr_ty_adjusted(tcx, base_e).sty {
+ ty::ty_struct(did, _) => {
+ ty::lookup_struct_fields(tcx, did)
+ .get(field.node)
+ .unwrap_or_else(|| {
+ tcx.sess.span_bug(field.span,
+ "stability::check_expr: unknown unnamed field access")
+ })
+ .id
+ }
+ ty::ty_tup(..) => return,
+ _ => tcx.sess.span_bug(e.span,
+ "stability::check_expr: unnamed field access on \
+ something other than a tuple or struct")
+ }
+ }
+ ast::ExprStruct(_, ref expr_fields, _) => {
+ let type_ = ty::expr_ty(tcx, e);
+ match type_.sty {
+ ty::ty_struct(did, _) => {
+ let struct_fields = ty::lookup_struct_fields(tcx, did);
+ // check the stability of each field that appears
+ // in the construction expression.
+ for field in expr_fields {
+ let did = struct_fields
+ .iter()
+ .find(|f| f.name == field.ident.node.name)
+ .unwrap_or_else(|| {
+ tcx.sess.span_bug(field.span,
+ "stability::check_expr: unknown named \
+ field access")
+ })
+ .id;
+ maybe_do_stability_check(tcx, did, field.span, cb);
+ }
+
+ // we're done.
+ return
+ }
+ // we don't look at stability attributes on
+ // struct-like enums (yet...), but it's definitely not
+ // a bug to have construct one.
+ ty::ty_enum(..) => return,
+ _ => {
+ tcx.sess.span_bug(e.span,
+ &format!("stability::check_expr: struct construction \
+ of non-struct, type {:?}",
+ type_.repr(tcx)));
+ }
+ }
+ }
_ => return
};
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
+ 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 => {}
+ }
+
+}
+
+pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat,
+ cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
+ debug!("check_pat(pat = {:?})", pat);
+ if is_internal(tcx, pat.span) { return; }
+
+ let did = match ty::pat_ty_opt(tcx, pat) {
+ Some(&ty::TyS { sty: ty::ty_struct(did, _), .. }) => did,
+ Some(_) | None => return,
};
- maybe_do_stability_check(tcx, did, path.span, cb)
+ let struct_fields = ty::lookup_struct_fields(tcx, did);
+ match pat.node {
+ // Foo(a, b, c)
+ ast::PatEnum(_, Some(ref pat_fields)) => {
+ for (field, struct_field) in pat_fields.iter().zip(struct_fields.iter()) {
+ // a .. pattern is fine, but anything positional is
+ // not.
+ if let ast::PatWild(ast::PatWildMulti) = field.node {
+ continue
+ }
+ maybe_do_stability_check(tcx, struct_field.id, field.span, cb)
+ }
+ }
+ // Foo { a, b, c }
+ ast::PatStruct(_, ref pat_fields, _) => {
+ for field in pat_fields {
+ let did = struct_fields
+ .iter()
+ .find(|f| f.name == field.node.ident.name)
+ .unwrap_or_else(|| {
+ tcx.sess.span_bug(field.span,
+ "stability::check_pat: unknown named field access")
+ })
+ .id;
+ maybe_do_stability_check(tcx, did, field.span, cb);
+ }
+ }
+ // everything else is fine.
+ _ => {}
+ }
}
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
ty::ty_closure(..) |
ty::ty_infer(..) |
- ty::ty_open(..) |
ty::ty_err => {
tcx.sess.bug(
&format!("ty_is_local invoked on unexpected type: {}",
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)
}
/// Reasons a method might not be object-safe.
#[derive(Copy,Clone,Debug)]
pub enum MethodViolationCode {
- /// e.g., `fn(self)`
- ByValueSelf,
-
/// e.g., `fn foo()`
StaticMethod,
fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
trait_def_id: ast::DefId)
-> bool
+{
+ let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
+ let trait_predicates = ty::lookup_predicates(tcx, trait_def_id);
+ generics_require_sized_self(tcx, &trait_def.generics, &trait_predicates)
+}
+
+fn generics_require_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
+ generics: &ty::Generics<'tcx>,
+ predicates: &ty::GenericPredicates<'tcx>)
+ -> bool
{
let sized_def_id = match tcx.lang_items.sized_trait() {
Some(def_id) => def_id,
};
// Search for a predicate like `Self : Sized` amongst the trait bounds.
- let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
- let free_substs = ty::construct_free_substs(tcx, &trait_def.generics, ast::DUMMY_NODE_ID);
-
- let trait_predicates = ty::lookup_predicates(tcx, trait_def_id);
- let predicates = trait_predicates.instantiate(tcx, &free_substs).predicates.into_vec();
-
+ let free_substs = ty::construct_free_substs(tcx, generics, ast::DUMMY_NODE_ID);
+ let predicates = predicates.instantiate(tcx, &free_substs).predicates.into_vec();
elaborate_predicates(tcx, predicates)
.any(|predicate| {
match predicate {
method: &ty::Method<'tcx>)
-> Option<MethodViolationCode>
{
- // The method's first parameter must be something that derefs to
- // `&self`. For now, we only accept `&self` and `Box<Self>`.
- match method.explicit_self {
- ty::ByValueExplicitSelfCategory => {
- return Some(MethodViolationCode::ByValueSelf);
- }
+ // Any method that has a `Self : Sized` requisite is otherwise
+ // exempt from the regulations.
+ if generics_require_sized_self(tcx, &method.generics, &method.predicates) {
+ return None;
+ }
+ // The method's first parameter must be something that derefs (or
+ // autorefs) to `&self`. For now, we only accept `self`, `&self`
+ // and `Box<Self>`.
+ match method.explicit_self {
ty::StaticExplicitSelfCategory => {
return Some(MethodViolationCode::StaticMethod);
}
+ ty::ByValueExplicitSelfCategory |
ty::ByReferenceExplicitSelfCategory(..) |
ty::ByBoxExplicitSelfCategory => {
}
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_open(ty) => {
- // these only crop up in trans, and represent an
- // "opened" unsized/existential type (one that has
- // been dereferenced)
- match bound {
- ty::BoundCopy => {
- Ok(If(vec!(ty)))
- }
-
- ty::BoundSized => {
- Err(Unimplemented)
- }
-
- ty::BoundSync |
- ty::BoundSend => {
- self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()");
- }
- }
- }
- 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>
Some(vec![referent_ty])
}
- ty::ty_open(element_ty) => {Some(vec![element_ty])},
-
ty::ty_ptr(ty::mt { ty: element_ty, ..}) |
ty::ty_rptr(_, ty::mt { ty: element_ty, ..}) => {
Some(vec![element_ty])
}).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
sty_debug_print!(
self,
ty_enum, ty_uniq, ty_vec, ty_ptr, ty_rptr, ty_bare_fn, ty_trait,
- ty_struct, ty_closure, ty_tup, ty_param, ty_open, ty_infer, ty_projection);
+ ty_struct, ty_closure, ty_tup, ty_param, ty_infer, ty_projection);
println!("Substs interner: #{}", self.substs_interner.borrow().len());
println!("BareFnTy interner: #{}", self.bare_fn_interner.borrow().len());
ty_projection(ProjectionTy<'tcx>),
ty_param(ParamTy), // type parameter
- ty_open(Ty<'tcx>), // A deref'ed fat pointer, i.e., a dynamically sized value
- // and its size. Only ever used in trans. It is not necessary
- // earlier since we don't need to distinguish a DST with its
- // size (e.g., in a deref) vs a DST with the size elsewhere (
- // e.g., in a field).
-
ty_infer(InferTy), // something used only during inference/typeck
ty_err, // Also only used during inference/typeck, to represent
// the type of an erroneous expression (helps cut down
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,
self.add_bounds(bounds);
}
- &ty_uniq(tt) | &ty_vec(tt, _) | &ty_open(tt) => {
+ &ty_uniq(tt) | &ty_vec(tt, _) => {
self.add_ty(tt)
}
mk_param(cx, def.space, def.index, def.name)
}
-pub fn mk_open<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { mk_t(cx, ty_open(ty)) }
-
impl<'tcx> TyS<'tcx> {
/// Iterator that walks `self` and any types reachable from
/// `self`, in depth-first order. Note that just walks the types
_ => 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)
match ty.sty {
ty_vec(ty, _) => ty,
ty_str => mk_mach_uint(cx, ast::TyU8),
- ty_open(ty) => sequence_element_type(cx, ty),
_ => cx.sess.bug(&format!("sequence_element_type called on non-sequence value: {}",
ty_to_string(cx, ty))),
}
TC::All
}
- ty_open(ty) => {
- let result = tc_ty(cx, ty, cache);
- assert!(!result.is_sized(cx));
- result.unsafe_pointer() | TC::Nonsized
- }
-
ty_infer(_) |
ty_err => {
cx.sess.bug("asked to compute contents of error type");
ty_vec(_, None) => {
false
}
- ty_uniq(typ) | ty_open(typ) => {
+ ty_uniq(typ) => {
type_requires(cx, seen, r_ty, typ)
}
ty_rptr(_, ref mt) => {
}
}
-pub fn close_type<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
- match ty.sty {
- ty_open(ty) => mk_rptr(cx, cx.mk_region(ReStatic), mt {ty: ty, mutbl:ast::MutImmutable}),
- _ => cx.sess.bug(&format!("Trying to close a non-open type {}",
- ty_to_string(cx, ty)))
- }
-}
-
pub fn type_content<'tcx>(ty: Ty<'tcx>) -> Ty<'tcx> {
match ty.sty {
ty_uniq(ty) => ty,
}
}
-// Extract the unsized type in an open type (or just return ty if it is not open).
-pub fn unopen_type<'tcx>(ty: Ty<'tcx>) -> Ty<'tcx> {
- match ty.sty {
- ty_open(ty) => ty,
- _ => ty
- }
-}
-
// Returns the type of ty[i]
pub fn index<'tcx>(ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
match ty.sty {
}
}
-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 pat_ty<'tcx>(cx: &ctxt<'tcx>, pat: &ast::Pat) -> Ty<'tcx> {
return node_id_to_type(cx, pat.id);
}
+pub fn pat_ty_opt<'tcx>(cx: &ctxt<'tcx>, pat: &ast::Pat) -> Option<Ty<'tcx>> {
+ return node_id_to_type_opt(cx, pat.id);
+}
// Returns the type of an expression as a monotype.
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 {
}
}
ty_err => "type error".to_string(),
- ty_open(_) => "opened DST".to_string(),
}
}
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,
..
hash!(p.idx);
hash!(token::get_name(p.name));
}
- ty_open(_) => byte!(22),
ty_infer(_) => unreachable!(),
- ty_err => byte!(23),
+ ty_err => byte!(21),
ty_closure(d, r, _) => {
- byte!(24);
+ byte!(22);
did(state, d);
region(state, *r);
}
ty_projection(ref data) => {
- byte!(25);
+ byte!(23);
did(state, data.trait_ref.def_id);
hash!(token::get_name(data.item_name));
}
ty_projection(_) |
ty_param(_) |
ty_infer(_) |
- ty_open(_) |
ty_err => {
}
}
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),
}
ty::ty_vec(typ, sz) => {
ty::ty_vec(typ.fold_with(this), sz)
}
- ty::ty_open(typ) => {
- ty::ty_open(typ.fold_with(this))
- }
ty::ty_enum(tid, ref substs) => {
let substs = substs.fold_with(this);
ty::ty_enum(tid, this.tcx().mk_substs(substs))
ty::ty_bool | ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) |
ty::ty_str | ty::ty_infer(_) | ty::ty_param(_) | ty::ty_err => {
}
- ty::ty_uniq(ty) | ty::ty_vec(ty, _) | ty::ty_open(ty) => {
+ ty::ty_uniq(ty) | ty::ty_vec(ty, _) => {
self.stack.push(ty);
}
ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => {
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 middle::ty::{mt, Ty, ParamTy};
use middle::ty::{ty_bool, ty_char, ty_struct, ty_enum};
use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn};
-use middle::ty::{ty_param, ty_ptr, ty_rptr, ty_tup, ty_open};
+use middle::ty::{ty_param, ty_ptr, ty_rptr, ty_tup};
use middle::ty::{ty_closure};
use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer};
use middle::ty;
buf.push_str(&mt_to_string(cx, tm));
buf
}
- ty_open(typ) =>
- format!("opened<{}>", ty_to_string(cx, typ)),
ty_tup(ref elems) => {
let strs = elems
.iter()
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);
linker_is_gnu: true,
has_rpath: true,
pre_link_args: vec!(
+ // GNU-style linkers will use this to omit linking to libraries
+ // which don't actually fulfill any relocations, but only for
+ // libraries which follow this flag. Thus, use it before
+ // specifying libraries to link to.
+ "-Wl,--as-needed".to_string(),
),
position_independent_executables: true,
.. Default::default()
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.
};
let (suggestion, _) =
move_suggestion(param_env, expr_span, expr_ty, ("moved by default", ""));
- self.tcx.sess.span_note(
- expr_span,
- &format!("`{}` moved here{} because it has type `{}`, which is {}",
- ol,
- moved_lp_msg,
- expr_ty.user_string(self.tcx),
- suggestion));
+ // If the two spans are the same, it's because the expression will be evaluated
+ // multiple times. Avoid printing the same span and adjust the wording so it makes
+ // more sense that it's from multiple evalutations.
+ if expr_span == use_span {
+ self.tcx.sess.note(
+ &format!("`{}` was previously moved here{} because it has type `{}`, \
+ which is {}",
+ ol,
+ moved_lp_msg,
+ expr_ty.user_string(self.tcx),
+ suggestion));
+ } else {
+ self.tcx.sess.span_note(
+ expr_span,
+ &format!("`{}` moved here{} because it has type `{}`, which is {}",
+ ol,
+ moved_lp_msg,
+ expr_ty.user_string(self.tcx),
+ suggestion));
+ }
}
move_data::MovePat => {
impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> {
fn dataflow_for(&self, e: EntryOrExit, n: &Node<'a>) -> String {
- let id = n.1.data.id;
+ let id = n.1.data.id();
debug!("dataflow_for({:?}, id={}) {:?}", e, id, self.variants);
let mut sets = "".to_string();
let mut seen_one = false;
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};
ast::ItemEnum(ref def, _) if public_first => {
for variant in &def.variants {
self.exported_items.insert(variant.node.id);
+ self.public_items.insert(variant.node.id);
}
}
// * 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();
Some(id) => { self.exported_items.insert(id); }
None => {}
}
+ // fields can be public or private, so lets check
+ for field in &def.fields {
+ let vis = match field.node.kind {
+ ast::NamedField(_, vis) | ast::UnnamedField(vis) => vis
+ };
+ if vis == ast::Public {
+ self.public_items.insert(field.node.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);
}
fn extract_vec_elems<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- left_ty: Ty,
+ left_ty: Ty<'tcx>,
before: uint,
after: uint,
val: ValueRef)
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)))
fn create_dummy_locals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
pat: &ast::Pat)
-> Block<'blk, 'tcx> {
+ let _icx = push_ctxt("create_dummy_locals");
// create dummy memory for the variables if we have no
// value to store into them immediately
let tcx = bcx.tcx();
}
}
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);
st.fields.iter().filter(|&ty| !dst || type_is_sized(cx.tcx(), *ty))
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
} else {
- st.fields.iter().map(|&ty| type_of::type_of(cx, ty)).collect()
+ st.fields.iter().map(|&ty| type_of::in_memory_type_of(cx, ty)).collect()
}
}
let val = if common::type_is_sized(cx.tcx(), field_ty) {
llfld_a
} else {
- let boxed_ty = ty::mk_open(cx.tcx(), field_ty);
- let scratch = datum::rvalue_scratch_datum(cx, boxed_ty, "__fat_ptr_iter");
+ let scratch = datum::rvalue_scratch_datum(cx, field_ty, "__fat_ptr_iter");
Store(cx, llfld_a, GEPi(cx, scratch.val, &[0, abi::FAT_PTR_ADDR]));
Store(cx, info.unwrap(), GEPi(cx, scratch.val, &[0, abi::FAT_PTR_EXTRA]));
scratch.val
// the clobbering of the existing value in the return slot.
fn has_nested_returns(tcx: &ty::ctxt, cfg: &cfg::CFG, blk_id: ast::NodeId) -> bool {
for n in cfg.graph.depth_traverse(cfg.entry) {
- match tcx.map.find(n.id) {
+ match tcx.map.find(n.id()) {
Some(ast_map::NodeExpr(ex)) => {
if let ast::ExprRet(Some(ref ret_expr)) = ex.node {
let mut visitor = FindNestedReturn::new();
// 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 {:?} \
};
if !is_rust_fn ||
type_of::return_uses_outptr(ccx, ret_ty) ||
- common::type_needs_drop(bcx.tcx(), ret_ty) {
+ bcx.fcx.type_needs_drop(ret_ty) {
// Push the out-pointer if we use an out-pointer for this
// return type, otherwise push "undef".
if common::type_is_zero_size(ccx, ret_ty) {
cleanup_scope: ScopeId,
val: ValueRef,
ty: Ty<'tcx>) {
- if !common::type_needs_drop(self.ccx.tcx(), ty) { return; }
+ if !self.type_needs_drop(ty) { return; }
let drop = box DropValue {
is_immediate: false,
must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty),
cleanup_scope: ScopeId,
val: ValueRef,
ty: Ty<'tcx>) {
- if !common::type_needs_drop(self.ccx.tcx(), ty) { return; }
+ if !self.type_needs_drop(ty) { return; }
+
let drop = box DropValue {
is_immediate: false,
must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty),
val: ValueRef,
ty: Ty<'tcx>) {
- if !common::type_needs_drop(self.ccx.tcx(), ty) { return; }
+ if !self.type_needs_drop(ty) { return; }
let drop = box DropValue {
is_immediate: true,
must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty),
bcx: Block<'blk, 'tcx>,
debug_loc: DebugLoc)
-> Block<'blk, 'tcx> {
+ let _icx = base::push_ctxt("<DropValue as Cleanup>::trans");
let bcx = if self.is_immediate {
glue::drop_ty_immediate(bcx, self.val, self.ty, debug_loc)
} else {
// Is the type's representation size known at compile time?
pub fn type_is_sized<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
let param_env = ty::empty_parameter_environment(tcx);
- ty::type_is_sized(¶m_env, DUMMY_SP, ty)
-}
-
-pub fn lltype_is_sized<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
- match ty.sty {
- ty::ty_open(_) => true,
- _ => type_is_sized(cx, ty),
+ // FIXME(#4287) This can cause errors due to polymorphic recursion,
+ // a better span should be provided, if available.
+ let err_count = tcx.sess.err_count();
+ let is_sized = ty::type_is_sized(¶m_env, DUMMY_SP, ty);
+ // Those errors aren't fatal, but an incorrect result can later
+ // trip over asserts in both rustc's trans and LLVM.
+ if err_count < tcx.sess.err_count() {
+ tcx.sess.abort_if_errors();
}
+ is_sized
}
pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
}
}
-pub fn type_needs_drop<'tcx>(cx: &ty::ctxt<'tcx>,
- ty: Ty<'tcx>)
- -> bool {
- ty::type_contents(cx, ty).needs_drop(cx)
+/// If `type_needs_drop` returns true, then `ty` is definitely
+/// non-copy and *might* have a destructor attached; if it returns
+/// false, then `ty` definitely has no destructor (i.e. no drop glue).
+///
+/// (Note that this implies that if `ty` has a destructor attached,
+/// then `type_needs_drop` will definitely return `true` for `ty`.)
+pub fn type_needs_drop<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
+ type_needs_drop_given_env(cx, ty, &ty::empty_parameter_environment(cx))
+}
+
+/// Core implementation of type_needs_drop, potentially making use of
+/// and/or updating caches held in the `param_env`.
+fn type_needs_drop_given_env<'a,'tcx>(cx: &ty::ctxt<'tcx>,
+ ty: Ty<'tcx>,
+ param_env: &ty::ParameterEnvironment<'a,'tcx>) -> bool {
+ // Issue #22536: We first query type_moves_by_default. It sees a
+ // normalized version of the type, and therefore will definitely
+ // know whether the type implements Copy (and thus needs no
+ // cleanup/drop/zeroing) ...
+ let implements_copy = !ty::type_moves_by_default(¶m_env, DUMMY_SP, ty);
+
+ if implements_copy { return false; }
+
+ // ... (issue #22536 continued) but as an optimization, still use
+ // prior logic of asking if the `needs_drop` bit is set; we need
+ // not zero non-Copy types if they have no destructor.
+
+ // FIXME(#22815): Note that calling `ty::type_contents` is a
+ // conservative heuristic; it may report that `needs_drop` is set
+ // when actual type does not actually have a destructor associated
+ // with it. But since `ty` absolutely did not have the `Copy`
+ // bound attached (see above), it is sound to treat it as having a
+ // destructor (e.g. zero its memory on move).
+
+ let contents = ty::type_contents(cx, ty);
+ debug!("type_needs_drop ty={} contents={:?}", ty.repr(cx), contents);
+ contents.needs_drop(cx)
}
fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
self.param_substs,
value)
}
+
+ /// This is the same as `common::type_needs_drop`, except that it
+ /// may use or update caches within this `FunctionContext`.
+ pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
+ type_needs_drop_given_env(self.ccx.tcx(), ty, &self.param_env)
+ }
}
// Basic block context. We create a block context for each basic block
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));
(const_deref_ptr(cx, v), mt.ty)
} else {
// Derefing a fat pointer does not change the representation,
- // just the type to ty_open.
- (v, ty::mk_open(cx.tcx(), mt.ty))
+ // just the type to the unsized contents.
+ (v, mt.ty)
}
}
None => {
-> 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) {
// an optimisation, it is necessary for mutable vectors to
// work properly.
ty = match ty::deref(ty, true) {
- Some(mt) => {
- if type_is_sized(cx.tcx(), mt.ty) {
- mt.ty
- } else {
- // Derefing a fat pointer does not change the representation,
- // just the type to ty_open.
- ty::mk_open(cx.tcx(), mt.ty)
- }
- }
+ Some(mt) => mt.ty,
None => {
cx.sess().bug(&format!("unexpected dereferenceable type {}",
ty_to_string(cx.tcx(), ty)))
llconst = addr_of(cx, llconst, "autoref", e.id);
}
Some(box ty::AutoUnsize(ref k)) => {
- let unsized_ty = ty::unsize_ty(cx.tcx(), ty, k, e.span);
let info = expr::unsized_info(cx, k, e.id, ty, param_substs,
|t| ty::mk_imm_rptr(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), t));
- let base = ptrcast(llconst, type_of::type_of(cx, unsized_ty).ptr_to());
+ let unsized_ty = ty::unsize_ty(cx.tcx(), ty, k, e.span);
+ let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to();
+ let base = ptrcast(llconst, ptr_ty);
let prev_const = cx.const_unsized().borrow_mut()
.insert(base, llconst);
assert!(prev_const.is_none() || prev_const == Some(llconst));
};
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
}
};
let (arr, len) = match bt.sty {
ty::ty_vec(_, Some(u)) => (bv, C_uint(cx, u)),
- ty::ty_open(ty) => match ty.sty {
- ty::ty_vec(_, None) | ty::ty_str => {
- let e1 = const_get_elt(cx, bv, &[0]);
- (const_deref_ptr(cx, e1), const_get_elt(cx, bv, &[1]))
- },
- _ => cx.sess().span_bug(base.span,
- &format!("index-expr base must be a vector \
- or string type, found {}",
- ty_to_string(cx.tcx(), bt)))
- },
+ ty::ty_vec(_, None) | ty::ty_str => {
+ let e1 = const_get_elt(cx, bv, &[0]);
+ (const_deref_ptr(cx, e1), const_get_elt(cx, bv, &[1]))
+ }
ty::ty_rptr(_, mt) => match mt.ty.sty {
ty::ty_vec(_, Some(u)) => {
(const_deref_ptr(cx, bv), C_uint(cx, u))
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")
- };
+ }
}
}
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_stmt_semi");
let ty = expr_ty(cx, e);
- if type_needs_drop(cx.tcx(), ty) {
+ if cx.fcx.type_needs_drop(ty) {
expr::trans_to_lvalue(cx, e, "stmt").bcx
} else {
expr::trans_into(cx, e, expr::Ignore)
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))
}
}
}
val: ValueRef,
ty: Ty<'tcx>)
-> Block<'blk, 'tcx> {
- if type_needs_drop(bcx.tcx(), ty) {
+ let _icx = push_ctxt("<Lvalue as KindOps>::post_store");
+ if bcx.fcx.type_needs_drop(ty) {
// cancel cleanup of affine values by zeroing out
let () = zero_mem(bcx, val, ty);
bcx
-> DatumBlock<'blk, 'tcx, Lvalue> {
debug!("to_lvalue_datum self: {}", self.to_string(bcx.ccx()));
- assert!(lltype_is_sized(bcx.tcx(), self.ty),
- "Trying to convert unsized value to lval");
self.match_kind(
|l| DatumBlock::new(bcx, l),
|r| {
-> Datum<'tcx, Lvalue> where
F: FnOnce(ValueRef) -> ValueRef,
{
- let val = match self.ty.sty {
- _ if type_is_sized(bcx.tcx(), self.ty) => gep(self.val),
- ty::ty_open(_) => {
- let base = Load(bcx, expr::get_dataptr(bcx, self.val));
- gep(base)
- }
- _ => bcx.tcx().sess.bug(
- &format!("Unexpected unsized type in get_element: {}",
- bcx.ty_to_string(self.ty)))
+ let val = if type_is_sized(bcx.tcx(), self.ty) {
+ gep(self.val)
+ } else {
+ gep(Load(bcx, expr::get_dataptr(bcx, self.val)))
};
Datum {
val: val,
}
}
- pub fn get_vec_base_and_len(&self, bcx: Block) -> (ValueRef, ValueRef) {
+ pub fn get_vec_base_and_len<'blk>(&self, bcx: Block<'blk, 'tcx>)
+ -> (ValueRef, ValueRef) {
//! Converts a vector into the slice pair.
tvec::get_base_and_len(bcx, self.val, self.ty)
/// scalar-ish (like an int or a pointer) which (1) does not require drop glue and (2) is
/// naturally passed around by value, and not by reference.
pub fn to_llscalarish<'blk>(self, bcx: Block<'blk, 'tcx>) -> ValueRef {
- assert!(!type_needs_drop(bcx.tcx(), self.ty));
+ assert!(!bcx.fcx.type_needs_drop(self.ty));
assert!(self.appropriate_rvalue_mode(bcx.ccx()) == ByValue);
if self.kind.is_by_ref() {
load_ty(bcx, self.val, self.ty)
ast::ExprLit(_) |
ast::ExprBreak(_) |
ast::ExprAgain(_) |
- ast::ExprPath(_) |
- ast::ExprQPath(_) => {}
+ ast::ExprPath(..) => {}
ast::ExprCast(ref sub_exp, _) |
ast::ExprAddrOf(_, ref sub_exp) |
}
ty::ty_err |
ty::ty_infer(_) |
- ty::ty_open(_) |
ty::ty_projection(..) |
ty::ty_param(_) => {
cx.sess().bug(&format!("debuginfo: Trying to create type name for \
// 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);
let datum_ty = datum.ty;
let unsized_ty = ty::unsize_ty(tcx, datum_ty, k, expr.span);
debug!("unsized_ty={}", unsized_ty.repr(bcx.tcx()));
- let dest_ty = ty::mk_open(tcx, unsized_ty);
- debug!("dest_ty={}", unsized_ty.repr(bcx.tcx()));
let info = unsized_info(bcx.ccx(), k, expr.id, datum_ty, bcx.fcx.param_substs,
|t| ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), t));
datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id));
// Compute the base pointer. This doesn't change the pointer value,
// but merely its type.
- let base = match *k {
- ty::UnsizeStruct(..) | ty::UnsizeVtable(..) => {
- PointerCast(bcx, lval.val, type_of::type_of(bcx.ccx(), unsized_ty).ptr_to())
- }
- ty::UnsizeLength(..) => {
- GEPi(bcx, lval.val, &[0, 0])
- }
- };
+ let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), unsized_ty).ptr_to();
+ let base = PointerCast(bcx, lval.val, ptr_ty);
- let scratch = rvalue_scratch_datum(bcx, dest_ty, "__fat_ptr");
- Store(bcx, base, get_dataptr(bcx, scratch.val));
- Store(bcx, info, get_len(bcx, scratch.val));
+ let llty = type_of::type_of(bcx.ccx(), unsized_ty);
+ // HACK(eddyb) get around issues with lifetime intrinsics.
+ let scratch = alloca_no_lifetime(bcx, llty, "__fat_ptr");
+ Store(bcx, base, get_dataptr(bcx, scratch));
+ Store(bcx, info, get_len(bcx, scratch));
- DatumBlock::new(bcx, scratch.to_expr_datum())
+ DatumBlock::new(bcx, Datum::new(scratch, unsized_ty, LvalueExpr))
}
fn unsize_unique_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
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_rec_field");
let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field"));
- let bare_ty = ty::unopen_type(base_datum.ty);
+ let bare_ty = base_datum.ty;
let repr = adt::represent_type(bcx.ccx(), bare_ty);
with_field_tys(bcx.tcx(), bare_ty, None, move |discr, field_tys| {
let ix = get_idx(bcx.tcx(), field_tys);
if type_is_sized(bcx.tcx(), d.ty) {
DatumBlock { datum: d.to_expr_datum(), bcx: bcx }
} else {
- let scratch = rvalue_scratch_datum(bcx, ty::mk_open(bcx.tcx(), d.ty), "");
+ let scratch = rvalue_scratch_datum(bcx, d.ty, "");
Store(bcx, d.val, get_dataptr(bcx, scratch.val));
let info = Load(bcx, get_len(bcx, base_datum.val));
Store(bcx, info, get_len(bcx, scratch.val));
if type_is_sized(bcx.tcx(), elt_ty) {
Datum::new(datum.to_llscalarish(bcx), elt_ty, LvalueExpr)
} else {
- Datum::new(datum.val, ty::mk_open(bcx.tcx(), elt_ty), LvalueExpr)
+ Datum::new(datum.val, elt_ty, LvalueExpr)
}
}
None => {
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);
let src_datum = unpack_datum!(bcx, trans(bcx, &**src));
let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &**dst, "assign"));
- if type_needs_drop(bcx.tcx(), dst_datum.ty) {
+ if bcx.fcx.type_needs_drop(dst_datum.ty) {
// If there are destructors involved, make sure we
// are copying from an rvalue, since that cannot possible
// alias an lvalue. We are concerned about code like:
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(
assert_eq!(discr, 0);
match ty::expr_kind(bcx.tcx(), &*base.expr) {
- ty::RvalueDpsExpr | ty::RvalueDatumExpr if !type_needs_drop(bcx.tcx(), ty) => {
+ ty::RvalueDpsExpr | ty::RvalueDatumExpr if !bcx.fcx.type_needs_drop(ty) => {
bcx = trans_into(bcx, &*base.expr, SaveIn(addr));
},
ty::RvalueStmtExpr => bcx.tcx().sess.bug("unexpected expr kind for struct base expr"),
fn ref_fat_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
lval: Datum<'tcx, Lvalue>)
-> DatumBlock<'blk, 'tcx, Expr> {
- let dest_ty = ty::close_type(bcx.tcx(), lval.ty);
+ let dest_ty = ty::mk_imm_rptr(bcx.tcx(), bcx.tcx().mk_region(ty::ReStatic), lval.ty);
let scratch = rvalue_scratch_datum(bcx, dest_ty, "__fat_ptr");
memcpy_ty(bcx, scratch.val, lval.val, scratch.ty);
let _icx = push_ctxt("trans_addr_of");
let mut bcx = bcx;
let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of"));
- match sub_datum.ty.sty {
- ty::ty_open(_) => {
- // Opened DST value, close to a fat pointer
- ref_fat_ptr(bcx, sub_datum)
- }
- _ => {
- // Sized value, ref to a thin pointer
- let ty = expr_ty(bcx, expr);
- immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock()
- }
+ if !type_is_sized(bcx.tcx(), sub_datum.ty) {
+ // DST lvalue, close to a fat pointer
+ ref_fat_ptr(bcx, sub_datum)
+ } else {
+ // Sized value, ref to a thin pointer
+ let ty = expr_ty(bcx, expr);
+ immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock()
}
}
// Evaluate LHS (destination), which should be an lvalue
let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
- assert!(!type_needs_drop(bcx.tcx(), dst_datum.ty));
+ assert!(!bcx.fcx.type_needs_drop(dst_datum.ty));
let dst_ty = dst_datum.ty;
let dst = load_ty(bcx, dst_datum.val, dst_datum.ty);
if type_is_sized(bcx.tcx(), content_ty) {
deref_owned_pointer(bcx, expr, datum, content_ty)
} else {
- // A fat pointer and an opened DST value have the same
- // representation just different types. Since there is no
- // temporary for `*e` here (because it is unsized), we cannot
- // emulate the sized object code path for running drop glue and
- // free. Instead, we schedule cleanup for `e`, turning it into
- // an lvalue.
+ // A fat pointer and a DST lvalue have the same representation
+ // just different types. Since there is no temporary for `*e`
+ // here (because it is unsized), we cannot emulate the sized
+ // object code path for running drop glue and free. Instead,
+ // we schedule cleanup for `e`, turning it into an lvalue.
let datum = unpack_datum!(
bcx, datum.to_lvalue_datum(bcx, "deref", expr.id));
- let datum = Datum::new(datum.val, ty::mk_open(bcx.tcx(), content_ty), LvalueExpr);
+ let datum = Datum::new(datum.val, content_ty, LvalueExpr);
DatumBlock::new(bcx, datum)
}
}
// owner (or, in the case of *T, by the user).
DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr))
} else {
- // A fat pointer and an opened DST value have the same representation
+ // A fat pointer and a DST lvalue have the same representation
// just different types.
- DatumBlock::new(bcx, Datum::new(datum.val,
- ty::mk_open(bcx.tcx(), content_ty),
- LvalueExpr))
+ DatumBlock::new(bcx, Datum::new(datum.val, content_ty, LvalueExpr))
}
}
use trans::machine::*;
use trans::tvec;
use trans::type_::Type;
-use trans::type_of::{type_of, sizing_type_of, align_of};
+use trans::type_of::{self, type_of, sizing_type_of, align_of};
use middle::ty::{self, Ty};
use util::ppaux::{ty_to_short_str, Repr};
use util::ppaux;
if !type_is_sized(tcx, t) {
return t
}
+
+ // FIXME (#22815): note that type_needs_drop conservatively
+ // approximates in some cases and may say a type expression
+ // requires drop glue when it actually does not.
+ //
+ // (In this case it is not clear whether any harm is done, i.e.
+ // erroneously returning `t` in some cases where we could have
+ // returned `tcx.types.i8` does not appear unsound. The impact on
+ // code quality is unknown at this time.)
+
if !type_needs_drop(tcx, t) {
return tcx.types.i8;
}
// NB: v is an *alias* of type t here, not a direct value.
debug!("drop_ty(t={})", t.repr(bcx.tcx()));
let _icx = push_ctxt("drop_ty");
- if type_needs_drop(bcx.tcx(), t) {
+ if bcx.fcx.type_needs_drop(t) {
let ccx = bcx.ccx();
let glue = get_drop_glue(ccx, t);
let glue_type = get_drop_glue_type(ccx, t);
assert_eq!(params.len(), 1);
let self_arg = if type_is_fat_ptr(bcx.tcx(), self_ty) {
// The dtor expects a fat pointer, so make one, even if we have to fake it.
- let boxed_ty = ty::mk_open(bcx.tcx(), t);
- let scratch = datum::rvalue_scratch_datum(bcx, boxed_ty, "__fat_ptr_drop_self");
+ let scratch = datum::rvalue_scratch_datum(bcx, t, "__fat_ptr_drop_self");
Store(bcx, value, GEPi(bcx, scratch.val, &[0, abi::FAT_PTR_ADDR]));
Store(bcx,
// If we just had a thin pointer, make a fat pointer by sticking
// Add all the fields as a value which needs to be cleaned at the end of
// this scope. Iterate in reverse order so a Drop impl doesn't reverse
// the order in which fields get dropped.
- for (i, ty) in st.fields.iter().enumerate().rev() {
+ for (i, &ty) in st.fields.iter().enumerate().rev() {
let llfld_a = adt::struct_field_ptr(variant_cx, &*st, value, i, false);
- let val = if type_is_sized(bcx.tcx(), *ty) {
+ let val = if type_is_sized(bcx.tcx(), ty) {
llfld_a
} else {
- let boxed_ty = ty::mk_open(bcx.tcx(), *ty);
- let scratch = datum::rvalue_scratch_datum(bcx, boxed_ty, "__fat_ptr_drop_field");
+ let scratch = datum::rvalue_scratch_datum(bcx, ty, "__fat_ptr_drop_field");
Store(bcx, llfld_a, GEPi(bcx, scratch.val, &[0, abi::FAT_PTR_ADDR]));
Store(bcx, info.unwrap(), GEPi(bcx, scratch.val, &[0, abi::FAT_PTR_EXTRA]));
scratch.val
};
- variant_cx.fcx.schedule_drop_mem(cleanup::CustomScope(field_scope),
- val, *ty);
+ variant_cx.fcx.schedule_drop_mem(cleanup::CustomScope(field_scope), val, ty);
}
let dtor_ty = ty::mk_ctor_fn(bcx.tcx(),
},
_ => {
assert!(type_is_sized(bcx.tcx(), t));
- if type_needs_drop(bcx.tcx(), t) && ty::type_is_structural(t) {
+ if bcx.fcx.type_needs_drop(t) && ty::type_is_structural(t) {
iter_structural_ty(bcx,
v0,
t,
// tydescs.
assert!(!ccx.finished_tydescs().get());
- let llty = type_of(ccx, t);
+ // This really shouldn't be like this, size/align will be wrong for
+ // unsized types (i.e. [T] will have the size/align of T).
+ // But we need it until we split this out into a "type name" intrinsic.
+ let llty = type_of::in_memory_type_of(ccx, t);
if ccx.sess().count_type_sizes() {
println!("{}\t{}", llsize_of_real(ccx, llty),
let ccx = fcx.ccx;
let tcx = bcx.tcx();
+ let _icx = push_ctxt("trans_intrinsic_call");
+
let ret_ty = match callee_ty.sty {
ty::ty_bare_fn(_, ref f) => {
ty::erase_late_bound_regions(bcx.tcx(), &f.sig.output())
}
(_, "needs_drop") => {
let tp_ty = *substs.types.get(FnSpace, 0);
- C_bool(ccx, type_needs_drop(ccx.tcx(), tp_ty))
+
+ C_bool(ccx, bcx.fcx.type_needs_drop(tp_ty))
}
(_, "owns_managed") => {
let tp_ty = *substs.types.get(FnSpace, 0);
let self_datum = unpack_datum!(
bcx, expr::trans(bcx, self_expr));
- let llval = if type_needs_drop(bcx.tcx(), self_datum.ty) {
+ let llval = if bcx.fcx.type_needs_drop(self_datum.ty) {
let self_datum = unpack_datum!(
bcx, self_datum.to_rvalue_datum(bcx, "trait_callee"));
param_substs,
substs.clone()).val;
- // currently, at least, by-value self is not object safe
- assert!(m.explicit_self != ty::ByValueExplicitSelfCategory);
-
Some(fn_ref).into_iter()
}
}
let not_null = IsNotNull(bcx, vptr);
with_cond(bcx, not_null, |bcx| {
let ccx = bcx.ccx();
- let tcx = bcx.tcx();
let _icx = push_ctxt("tvec::make_drop_glue_unboxed");
let dataptr = get_dataptr(bcx, vptr);
- let bcx = if type_needs_drop(tcx, unit_ty) {
+ let bcx = if bcx.fcx.type_needs_drop(unit_ty) {
let len = get_len(bcx, vptr);
iter_vec_raw(bcx,
dataptr,
(base, len)
}
-fn get_slice_base_and_len(bcx: Block,
- llval: ValueRef)
- -> (ValueRef, ValueRef) {
- let base = Load(bcx, GEPi(bcx, llval, &[0, abi::FAT_PTR_ADDR]));
- let len = Load(bcx, GEPi(bcx, llval, &[0, abi::FAT_PTR_EXTRA]));
- (base, len)
-}
-
/// Converts a vector into the slice pair. The vector should be stored in `llval` which should be
/// by-reference. If you have a datum, you would probably prefer to call
/// `Datum::get_base_and_len()` which will handle any conversions for you.
-pub fn get_base_and_len(bcx: Block,
- llval: ValueRef,
- vec_ty: Ty)
- -> (ValueRef, ValueRef) {
+pub fn get_base_and_len<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ llval: ValueRef,
+ vec_ty: Ty<'tcx>)
+ -> (ValueRef, ValueRef) {
let ccx = bcx.ccx();
match vec_ty.sty {
ty::ty_vec(_, Some(n)) => get_fixed_base_and_len(bcx, llval, n),
- ty::ty_open(ty) => match ty.sty {
- ty::ty_vec(_, None) | ty::ty_str => get_slice_base_and_len(bcx, llval),
- _ => ccx.sess().bug("unexpected type in get_base_and_len")
- },
+ ty::ty_vec(_, None) | ty::ty_str => {
+ let base = Load(bcx, expr::get_dataptr(bcx, llval));
+ let len = Load(bcx, expr::get_len(bcx, llval));
+ (base, len)
+ }
// Only used for pattern matching.
- ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty.sty {
- ty::ty_vec(_, None) | ty::ty_str => get_slice_base_and_len(bcx, llval),
- ty::ty_vec(_, Some(n)) => {
- let base = GEPi(bcx, Load(bcx, llval), &[0, 0]);
- (base, C_uint(ccx, n))
- }
- _ => ccx.sess().bug("unexpected type in get_base_and_len"),
+ ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => {
+ let inner = if type_is_sized(bcx.tcx(), ty) {
+ Load(bcx, llval)
+ } else {
+ llval
+ };
+ get_base_and_len(bcx, inner, ty)
},
_ => ccx.sess().bug("unexpected type in get_base_and_len"),
}
Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to().ptr_to()
}
- pub fn opaque_trait(ccx: &CrateContext) -> Type {
- Type::struct_(ccx, &[Type::opaque_trait_data(ccx).ptr_to(), Type::vtable_ptr(ccx)], false)
- }
-
- pub fn opaque_trait_data(ccx: &CrateContext) -> Type {
- Type::i8(ccx)
- }
-
pub fn kind(&self) -> TypeKind {
unsafe {
llvm::LLVMGetTypeKind(self.to_ref())
#![allow(non_camel_case_types)]
-pub use self::named_ty::*;
-
use middle::subst;
use trans::adt;
use trans::common::*;
}
let llsizingty = match t.sty {
- _ if !lltype_is_sized(cx.tcx(), t) => {
- cx.sess().bug(&format!("trying to take the sizing type of {}, an unsized type",
- ppaux::ty_to_string(cx.tcx(), t)))
+ _ if !type_is_sized(cx.tcx(), t) => {
+ Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false)
}
ty::ty_bool => Type::bool(cx),
}
}
- ty::ty_open(_) => {
- Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false)
- }
-
ty::ty_projection(..) | ty::ty_infer(..) | ty::ty_param(..) | ty::ty_err(..) => {
cx.sess().bug(&format!("fictitious type {} in sizing_type_of()",
ppaux::ty_to_string(cx.tcx(), t)))
}
- ty::ty_vec(_, None) | ty::ty_trait(..) | ty::ty_str => panic!("unreachable")
+ ty::ty_vec(_, None) | ty::ty_trait(..) | ty::ty_str => unreachable!()
};
cx.llsizingtypes().borrow_mut().insert(t, llsizingty);
}
}
-// NB: If you update this, be sure to update `sizing_type_of()` as well.
-pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
- fn type_of_unsize_info<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
- // It is possible to end up here with a sized type. This happens with a
- // struct which might be unsized, but is monomorphised to a sized type.
- // In this case we'll fake a fat pointer with no unsize info (we use 0).
- // However, its still a fat pointer, so we need some type use.
- if type_is_sized(cx.tcx(), t) {
- return Type::i8p(cx);
- }
-
- match unsized_part_of_type(cx.tcx(), t).sty {
- ty::ty_str | ty::ty_vec(..) => Type::uint_from_ty(cx, ast::TyUs(false)),
- ty::ty_trait(_) => Type::vtable_ptr(cx),
- _ => panic!("Unexpected type returned from unsized_part_of_type : {}",
- t.repr(cx.tcx()))
- }
- }
+/// Get the LLVM type corresponding to a Rust type, i.e. `middle::ty::Ty`.
+/// This is the right LLVM type for an alloca containg a value of that type,
+/// and the pointee of an Lvalue Datum (which is always a LLVM pointer).
+/// For unsized types, the returned type is a fat pointer, thus the resulting
+/// LLVM type for a `Trait` Lvalue is `{ i8*, void(i8*)** }*`, which is a double
+/// indirection to the actual data, unlike a `i8` Lvalue, which is just `i8*`.
+/// This is needed due to the treatment of immediate values, as a fat pointer
+/// is too large for it to be placed in SSA value (by our rules).
+/// For the raw type without far pointer indirection, see `in_memory_type_of`.
+pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
+ let ty = if !type_is_sized(cx.tcx(), ty) {
+ ty::mk_imm_ptr(cx.tcx(), ty)
+ } else {
+ ty
+ };
+ in_memory_type_of(cx, ty)
+}
+/// Get the LLVM type corresponding to a Rust type, i.e. `middle::ty::Ty`.
+/// This is the right LLVM type for a field/array element of that type,
+/// and is the same as `type_of` for all Sized types.
+/// Unsized types, however, are represented by a "minimal unit", e.g.
+/// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this
+/// is useful for indexing slices, as `&[T]`'s data pointer is `T*`.
+/// If the type is an unsized struct, the regular layout is generated,
+/// with the inner-most trailing unsized field using the "minimal unit"
+/// of that field's type - this is useful for taking the address of
+/// that field and ensuring the struct has the right alignment.
+/// For the LLVM type of a value as a whole, see `type_of`.
+/// NB: If you update this, be sure to update `sizing_type_of()` as well.
+pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
// Check the cache.
match cx.lltypes().borrow().get(&t) {
Some(&llty) => return llty,
let t_norm = erase_regions(cx.tcx(), &t);
if t != t_norm {
- let llty = type_of(cx, t_norm);
+ let llty = in_memory_type_of(cx, t_norm);
debug!("--> normalized {} {:?} to {} {:?} llty={}",
t.repr(cx.tcx()),
t,
// of the enum's variants refers to the enum itself.
let repr = adt::represent_type(cx, t);
let tps = substs.types.get_slice(subst::TypeSpace);
- let name = llvm_type_name(cx, an_enum, did, tps);
+ let name = llvm_type_name(cx, did, tps);
adt::incomplete_type_of(cx, &*repr, &name[..])
}
- ty::ty_closure(did, _, ref substs) => {
+ ty::ty_closure(..) => {
// Only create the named struct, but don't fill it in. We
// fill it in *after* placing it into the type cache.
let repr = adt::represent_type(cx, t);
// inherited from their environment, so we use entire
// contents of the VecPerParamSpace to to construct the llvm
// name
- let name = llvm_type_name(cx, a_closure, did, substs.types.as_slice());
- adt::incomplete_type_of(cx, &*repr, &name[..])
+ adt::incomplete_type_of(cx, &*repr, "closure")
}
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) | ty::ty_ptr(ty::mt{ty, ..}) => {
- match ty.sty {
- ty::ty_str => {
+ if !type_is_sized(cx.tcx(), ty) {
+ if let ty::ty_str = ty.sty {
// This means we get a nicer name in the output (str is always
// unsized).
cx.tn().find_type("str_slice").unwrap()
+ } else {
+ let ptr_ty = in_memory_type_of(cx, ty).ptr_to();
+ let unsized_part = unsized_part_of_type(cx.tcx(), ty);
+ let info_ty = match unsized_part.sty {
+ ty::ty_str | ty::ty_vec(..) => {
+ Type::uint_from_ty(cx, ast::TyUs(false))
+ }
+ ty::ty_trait(_) => Type::vtable_ptr(cx),
+ _ => panic!("Unexpected type returned from \
+ unsized_part_of_type: {} for ty={}",
+ unsized_part.repr(cx.tcx()), ty.repr(cx.tcx()))
+ };
+ Type::struct_(cx, &[ptr_ty, info_ty], false)
}
- ty::ty_trait(..) => Type::opaque_trait(cx),
- _ if !type_is_sized(cx.tcx(), ty) => {
- let p_ty = type_of(cx, ty).ptr_to();
- Type::struct_(cx, &[p_ty, type_of_unsize_info(cx, ty)], false)
- }
- _ => type_of(cx, ty).ptr_to(),
+ } else {
+ in_memory_type_of(cx, ty).ptr_to()
}
}
ty::ty_vec(ty, Some(size)) => {
let size = size as u64;
- let llty = type_of(cx, ty);
+ let llty = in_memory_type_of(cx, ty);
ensure_array_fits_in_address_space(cx, llty, size, t);
Type::array(&llty, size)
}
- ty::ty_vec(ty, None) => {
- type_of(cx, ty)
- }
- ty::ty_trait(..) => {
- Type::opaque_trait_data(cx)
- }
-
- ty::ty_str => Type::i8(cx),
+ // Unsized slice types (and str) have the type of their element, and
+ // traits have the type of u8. This is so that the data pointer inside
+ // fat pointers is of the right type (e.g. for array accesses), even
+ // when taking the address of an unsized field in a struct.
+ ty::ty_vec(ty, None) => in_memory_type_of(cx, ty),
+ ty::ty_str | ty::ty_trait(..) => Type::i8(cx),
ty::ty_bare_fn(..) => {
type_of_fn_from_ty(cx, t).ptr_to()
}
ty::ty_struct(did, ref substs) => {
if ty::type_is_simd(cx.tcx(), t) {
- let llet = type_of(cx, ty::simd_type(cx.tcx(), t));
+ let llet = in_memory_type_of(cx, ty::simd_type(cx.tcx(), t));
let n = ty::simd_size(cx.tcx(), t) as u64;
ensure_array_fits_in_address_space(cx, llet, n, t);
Type::vector(&llet, n)
// infinite recursion with recursive struct types.
let repr = adt::represent_type(cx, t);
let tps = substs.types.get_slice(subst::TypeSpace);
- let name = llvm_type_name(cx, a_struct, did, tps);
+ let name = llvm_type_name(cx, did, tps);
adt::incomplete_type_of(cx, &*repr, &name[..])
}
}
- ty::ty_open(t) => match t.sty {
- ty::ty_struct(..) => {
- let p_ty = type_of(cx, t).ptr_to();
- Type::struct_(cx, &[p_ty, type_of_unsize_info(cx, t)], false)
- }
- ty::ty_vec(ty, None) => {
- let p_ty = type_of(cx, ty).ptr_to();
- Type::struct_(cx, &[p_ty, type_of_unsize_info(cx, t)], false)
- }
- ty::ty_str => {
- let p_ty = Type::i8p(cx);
- Type::struct_(cx, &[p_ty, type_of_unsize_info(cx, t)], false)
- }
- ty::ty_trait(..) => Type::opaque_trait(cx),
- _ => cx.sess().bug(&format!("ty_open with sized type: {}",
- ppaux::ty_to_string(cx.tcx(), t)))
- },
-
ty::ty_infer(..) => cx.sess().bug("type_of with ty_infer"),
ty::ty_projection(..) => cx.sess().bug("type_of with ty_projection"),
ty::ty_param(..) => cx.sess().bug("type_of with ty_param"),
_ => ()
}
- return llty;
+ llty
}
pub fn align_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>)
machine::llalign_of_min(cx, llty)
}
-// Want refinements! (Or case classes, I guess
-#[derive(Copy)]
-pub enum named_ty {
- a_struct,
- an_enum,
- a_closure,
-}
-
-pub fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
- what: named_ty,
- did: ast::DefId,
- tps: &[Ty<'tcx>])
- -> String {
- let name = match what {
- a_struct => "struct",
- an_enum => "enum",
- a_closure => return "closure".to_string(),
- };
-
+fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
+ did: ast::DefId,
+ tps: &[Ty<'tcx>])
+ -> String {
let base = ty::item_path_str(cx.tcx(), did);
let strings: Vec<String> = tps.iter().map(|t| t.repr(cx.tcx())).collect();
let tstr = if strings.is_empty() {
base
} else {
- format!("{}<{:?}>", base, strings)
+ format!("{}<{}>", base, strings.connect(", "))
};
if did.krate == 0 {
- format!("{}.{}", name, tstr)
+ tstr
} else {
- format!("{}.{}[{}{}]", name, tstr, "#", did.krate)
+ format!("{}.{}", did.krate, tstr)
}
}
//! 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, span: Span, id: ast::DefId)
+ -> Result<Rc<ty::TraitDef<'tcx>>, ErrorReported>;
- fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef<'tcx>>;
+ 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,
rscope.anon_regions(span, expected_num_region_params);
if supplied_num_region_params != 0 || anon_regions.is_err() {
- span_err!(tcx.sess, span, E0107,
- "wrong number of lifetime parameters: expected {}, found {}",
- expected_num_region_params, supplied_num_region_params);
+ report_lifetime_number_error(tcx, span,
+ supplied_num_region_params,
+ expected_num_region_params);
}
match anon_regions {
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);
+
if supplied_ty_param_count < required_ty_param_count {
- let expected = if required_ty_param_count < formal_ty_param_count {
- "expected at least"
- } else {
- "expected"
- };
- span_err!(this.tcx().sess, span, E0243,
- "wrong number of type arguments: {} {}, found {}",
- expected,
- required_ty_param_count,
- supplied_ty_param_count);
while type_substs.len() < required_ty_param_count {
type_substs.push(tcx.types.err);
}
} else if supplied_ty_param_count > formal_ty_param_count {
- let expected = if required_ty_param_count < formal_ty_param_count {
- "expected at most"
- } else {
- "expected"
- };
- span_err!(this.tcx().sess, span, E0244,
- "wrong number of type arguments: {} {}, found {}",
- expected,
- formal_ty_param_count,
- supplied_ty_param_count);
type_substs.truncate(formal_ty_param_count);
}
assert!(type_substs.len() >= required_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 }
-}
-
-/// 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 (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;
+ }
+ };
- 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
- };
+ let substs = ast_path_substs_for_ty(this, rscope,
+ span, param_mode,
+ &generics, item_segment);
- // FIXME(#12938): This is a hack until we have full support for
- // DST.
- 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();
+
+ check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS);
- let self_type = ast_ty_to_ty(this, rscope, &*qpath.self_type);
+ 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_type.repr(this.tcx()));
+ 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()));
+ debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx));
- // `<T as Trait>::U<V>` shouldn't parse right now.
- assert!(qpath.item_path.parameters.is_empty());
-
- 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
if ty::try_add_builtin_trait(tcx,
trait_did,
&mut builtin_bounds) {
- // FIXME(#20302) -- we should check for things like Copy<T>
+ let segments = &b.trait_ref.path.segments;
+ let parameters = &segments[segments.len() - 1].parameters;
+ if parameters.types().len() > 0 {
+ check_type_argument_count(tcx, b.trait_ref.path.span,
+ parameters.types().len(), 0, 0);
+ }
+ if parameters.lifetimes().len() > 0{
+ report_lifetime_number_error(tcx, b.trait_ref.path.span,
+ parameters.lifetimes().len(), 0);
+ }
continue; // success
}
}
"associated type bindings are not allowed here");
}
}
+
+fn check_type_argument_count(tcx: &ty::ctxt, span: Span, supplied: usize,
+ required: usize, accepted: usize) {
+ if supplied < required {
+ let expected = if required < accepted {
+ "expected at least"
+ } else {
+ "expected"
+ };
+ span_err!(tcx.sess, span, E0243,
+ "wrong number of type arguments: {} {}, found {}",
+ expected, required, supplied);
+ } else if supplied > accepted {
+ let expected = if required < accepted {
+ "expected at most"
+ } else {
+ "expected"
+ };
+ span_err!(tcx.sess, span, E0244,
+ "wrong number of type arguments: {} {}, found {}",
+ expected,
+ accepted,
+ supplied);
+ }
+}
+
+fn report_lifetime_number_error(tcx: &ty::ctxt, span: Span, number: usize, expected: usize) {
+ span_err!(tcx.sess, span, E0107,
+ "wrong number of lifetime parameters: expected {}, found {}",
+ expected, number);
+}
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);
// entering the fn check. We should do this after
// the fn check, then we can call this case a bug().
}
-
- ty::ty_open(_) => {
- self.tcx().sess.bug(
- &format!("Unexpected type encountered while doing wf check: {}",
- ty.repr(self.tcx())));
- }
}
}
all_substs.repr(self.tcx()));
// Instantiate the bounds on the method with the
- // type/early-bound-regions substitutions performed. The only
- // late-bound-regions that can appear in bounds are from the
- // impl, and those were already instantiated above.
- //
- // FIXME(DST). Super hack. For a method on a trait object
- // `Trait`, the generic signature requires that
- // `Self:Trait`. Since, for an object, we bind `Self` to the
- // type `Trait`, this leads to an obligation
- // `Trait:Trait`. Until such time we DST is fully implemented,
- // that obligation is not necessarily satisfied. (In the
- // future, it would be.) But we know that the true `Self` DOES implement
- // the trait. So we just delete this requirement. Hack hack hack.
- let mut method_predicates = pick.method_ty.predicates.instantiate(self.tcx(), &all_substs);
- match pick.kind {
- probe::ObjectPick(..) => {
- assert_eq!(method_predicates.predicates.get_slice(subst::SelfSpace).len(), 1);
- method_predicates.predicates.pop(subst::SelfSpace);
- }
- _ => { }
- }
+ // type/early-bound-regions substitutions performed. There can
+ // be no late-bound regions appearing here.
+ let method_predicates = pick.method_ty.predicates.instantiate(self.tcx(), &all_substs);
let method_predicates = self.fcx.normalize_associated_types_in(self.span,
&method_predicates);
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>,
expr.span);
}
Err(..) => {
- rcx.fcx.tcx().sess.span_note(expr.span,
- "cat_expr_unadjusted Errd during dtor check");
+ let tcx = rcx.fcx.tcx();
+ if tcx.sess.has_errors() {
+ // cannot run dropck; okay b/c in error state anyway.
+ } else {
+ tcx.sess.span_bug(expr.span, "cat_expr_unadjusted Errd");
+ }
}
}
}
check_safety_of_rvalue_destructor_if_necessary(rcx, head_cmt, expr.span);
}
Err(..) => {
- rcx.fcx.tcx().sess.span_note(expr.span,
- "cat_expr Errd during dtor check");
+ let tcx = rcx.fcx.tcx();
+ if tcx.sess.has_errors() {
+ // cannot run dropck; okay b/c in error state anyway.
+ } else {
+ tcx.sess.span_bug(expr.span, "cat_expr Errd");
+ }
}
}
in the supertrait listing");
}
- ObjectSafetyViolation::Method(method, MethodViolationCode::ByValueSelf) => {
- tcx.sess.span_note(
- span,
- &format!("method `{}` has a receiver type of `Self`, \
- which cannot be used with a trait object",
- method.name.user_string(tcx)));
- }
-
ObjectSafetyViolation::Method(method, MethodViolationCode::StaticMethod) => {
tcx.sess.span_note(
span,
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(..) => {}
use middle::ty::{Ty, ty_bool, ty_char, ty_enum, ty_err};
use middle::ty::{ty_param, TypeScheme, ty_ptr};
use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup};
-use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_open};
+use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int};
use middle::ty::{ty_uint, ty_closure, ty_uniq, ty_bare_fn};
use middle::ty::{ty_projection};
use middle::ty;
ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_tup(..) |
- ty_param(..) | ty_err | ty_open(..) |
+ ty_param(..) | ty_err |
ty_ptr(_) | ty_rptr(_, _) | ty_projection(..) => {
None
}
//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);
+ }
}
}
}
self.add_constraints_from_mt(generics, mt, variance);
}
- ty::ty_uniq(typ) | ty::ty_vec(typ, _) | ty::ty_open(typ) => {
+ ty::ty_uniq(typ) | ty::ty_vec(typ, _) => {
self.add_constraints_from_ty(generics, typ, variance);
}
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))
}
if method.vis != ast::Public && associated_trait.is_none() {
return None
}
+ if method.provided_source.is_some() {
+ return None
+ }
let mut item = method.clean(cx);
item.inner = match item.inner.clone() {
clean::TyMethodItem(clean::TyMethod {
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))
},
ty::ty_closure(..) => Tuple(vec![]), // FIXME(pcwalton)
ty::ty_infer(..) => panic!("ty_infer"),
- ty::ty_open(..) => panic!("ty_open"),
ty::ty_err => panic!("ty_err"),
}
}
}
-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]
/// Extension methods for ASCII-subset only operations on string slices
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsciiExt {
+ /// Container type for copied ASCII characters.
#[stable(feature = "rust1", since = "1.0.0")]
type Owned;
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]
/// to `Default` when asked to create a hasher.
#[unstable(feature = "std_misc", reason = "hasher stuff is unclear")]
pub trait HashState {
+ /// Type of the hasher that will be created.
type Hasher: hash::Hasher;
/// Creates a new hasher based on the given state of this object.
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);
use boxed::Box;
use cmp;
-use io::{self, SeekFrom, Read, Write, Seek, BufRead};
+use io::{self, SeekFrom, Read, Write, Seek, BufRead, Error, ErrorKind};
+use fmt;
use mem;
use slice;
+use string::String;
use vec::Vec;
// =============================================================================
impl<'a, R: Read + ?Sized> Read for &'a mut R {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { (**self).read(buf) }
+
+ fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<()> { (**self).read_to_end(buf) }
+
+ fn read_to_string(&mut self, buf: &mut String) -> io::Result<()> {
+ (**self).read_to_string(buf)
+ }
}
impl<'a, W: Write + ?Sized> Write for &'a mut W {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }
+
+ fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { (**self).write_all(buf) }
+
+ fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> { (**self).write_fmt(fmt) }
+
fn flush(&mut self) -> io::Result<()> { (**self).flush() }
}
impl<'a, S: Seek + ?Sized> Seek for &'a mut S {
}
impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B {
fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }
+
fn consume(&mut self, amt: usize) { (**self).consume(amt) }
+
+ fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<()> {
+ (**self).read_until(byte, buf)
+ }
+
+ fn read_line(&mut self, buf: &mut String) -> io::Result<()> { (**self).read_line(buf) }
}
impl<R: Read + ?Sized> Read for Box<R> {
*self = b;
Ok(amt)
}
+
+ fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
+ if try!(self.write(data)) == data.len() {
+ Ok(())
+ } else {
+ Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer", None))
+ }
+ }
+
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
self.push_all(buf);
Ok(buf.len())
}
+
+ fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+ try!(self.write(buf));
+ Ok(())
+ }
+
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
#![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.
use net::{SocketAddr, IpAddr};
use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+static PORT: AtomicUsize = ATOMIC_USIZE_INIT;
+
pub fn next_test_ip4() -> SocketAddr {
- static PORT: AtomicUsize = ATOMIC_USIZE_INIT;
SocketAddr::new(IpAddr::new_v4(127, 0, 0, 1),
PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port())
}
pub fn next_test_ip6() -> SocketAddr {
- static PORT: AtomicUsize = ATOMIC_USIZE_INIT;
SocketAddr::new(IpAddr::new_v6(0, 0, 0, 0, 0, 0, 0, 1),
PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port())
}
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",
impl Writer for MemWriter {
#[inline]
+ #[allow(deprecated)]
fn write_all(&mut self, buf: &[u8]) -> IoResult<()> {
self.buf.push_all(buf);
Ok(())
///
/// 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
use core::prelude::*;
use ascii::*;
-use borrow::{Borrow, ToOwned, Cow};
+use borrow::{Borrow, IntoCow, ToOwned, Cow};
use cmp;
use iter::{self, IntoIterator};
use mem;
}
}
+impl IntoCow<'static, Path> for PathBuf {
+ fn into_cow(self) -> Cow<'static, Path> {
+ Cow::Owned(self)
+ }
+}
+
+impl<'a> IntoCow<'a, Path> for &'a Path {
+ fn into_cow(self) -> Cow<'a, Path> {
+ Cow::Borrowed(self)
+ }
+}
+
impl ToOwned for Path {
type Owned = PathBuf;
fn to_owned(&self) -> PathBuf { self.to_path_buf() }
);
);
+ #[test]
+ fn into_cow() {
+ use borrow::{Cow, IntoCow};
+
+ let static_path = Path::new("/home/foo");
+ let static_cow_path: Cow<'static, Path> = static_path.into_cow();
+ let pathbuf = PathBuf::new("/home/foo");
+
+ {
+ let path: &Path = &pathbuf;
+ let borrowed_cow_path: Cow<Path> = path.into_cow();
+
+ assert_eq!(static_cow_path, borrowed_cow_path);
+ }
+
+ let owned_cow_path: Cow<'static, Path> = pathbuf.into_cow();
+
+ assert_eq!(static_cow_path, owned_cow_path);
+ }
+
#[test]
#[cfg(unix)]
pub fn test_decompositions_unix() {
#[doc(no_inline)] pub use mem::drop;
// Reexported types and traits
-
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use boxed::Box;
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use result::Result::{self, Ok, Err};
#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(no_inline)] pub use slice::AsSlice;
-#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(no_inline)] pub use slice::{SliceExt, SliceConcatExt};
+#[doc(no_inline)] pub use slice::{SliceExt, SliceConcatExt, AsSlice};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use str::{Str, StrExt};
#[stable(feature = "rust1", since = "1.0.0")]
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" {
pub struct Barrier {
lock: Mutex<BarrierState>,
cvar: Condvar,
- num_threads: uint,
+ num_threads: usize,
}
// The inner state of a double barrier
struct BarrierState {
- count: uint,
- generation_id: uint,
+ count: usize,
+ generation_id: usize,
}
/// A result returned from wait.
/// A barrier will block `n`-1 threads which call `wait` and then wake up
/// all threads at once when the `n`th thread calls `wait`.
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn new(n: uint) -> Barrier {
+ pub fn new(n: usize) -> Barrier {
Barrier {
lock: Mutex::new(BarrierState {
count: 0,
#[test]
fn test_barrier() {
- const N: uint = 10;
+ const N: usize = 10;
let barrier = Arc::new(Barrier::new(N));
let (tx, rx) = channel();
#[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")]
}
fn verify(&self, mutex: &sys_mutex::Mutex) {
- let addr = mutex as *const _ as uint;
+ let addr = mutex as *const _ as usize;
match self.mutex.compare_and_swap(0, addr, Ordering::SeqCst) {
// If we got out 0, then we have successfully bound the mutex to
// this cvar.
#[test]
fn notify_all() {
- const N: uint = 10;
+ const N: usize = 10;
let data = Arc::new((Mutex::new(0), Condvar::new()));
let (tx, rx) = channel();
pub use self::poison::{PoisonError, TryLockError, TryLockResult, LockResult};
pub use self::future::Future;
+#[allow(deprecated)]
pub use self::task_pool::TaskPool;
pub mod mpsc;
wake
}
- /// Convert to an unsafe uint value. Useful for storing in a pipe's state
+ /// Convert to an unsafe usize value. Useful for storing in a pipe's state
/// flag.
#[inline]
- pub unsafe fn cast_to_uint(self) -> uint {
+ pub unsafe fn cast_to_usize(self) -> usize {
mem::transmute(self.inner)
}
- /// Convert from an unsafe uint value. Useful for retrieving a pipe's state
+ /// Convert from an unsafe usize value. Useful for retrieving a pipe's state
/// flag.
#[inline]
- pub unsafe fn cast_from_uint(signal_ptr: uint) -> SignalToken {
+ pub unsafe fn cast_from_usize(signal_ptr: usize) -> SignalToken {
SignalToken { inner: mem::transmute(signal_ptr) }
}
//!
//! // The call to recv() will return an error because the channel has already
//! // hung up (or been deallocated)
-//! let (tx, rx) = channel::<int>();
+//! let (tx, rx) = channel::<i32>();
//! drop(tx);
//! assert!(rx.recv().is_err());
//! ```
//! use std::thread;
//! use std::sync::mpsc::sync_channel;
//!
-//! let (tx, rx) = sync_channel::<int>(0);
+//! let (tx, rx) = sync_channel::<i32>(0);
//! thread::spawn(move|| {
//! // This will wait for the parent task to start receiving
//! tx.send(53).unwrap();
//! use std::old_io::timer::Timer;
//! use std::time::Duration;
//!
-//! let (tx, rx) = channel::<int>();
+//! let (tx, rx) = channel::<i32>();
//! let mut timer = Timer::new().unwrap();
//! let timeout = timer.oneshot(Duration::seconds(10));
//!
//! use std::old_io::timer::Timer;
//! use std::time::Duration;
//!
-//! let (tx, rx) = channel::<int>();
+//! let (tx, rx) = channel::<i32>();
//! let mut timer = Timer::new().unwrap();
//!
//! loop {
/// contains the data being sent as a payload so it can be recovered.
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(PartialEq, Eq, Clone, Copy)]
-pub struct SendError<T>(pub T);
+pub struct SendError<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
/// An error returned from the `recv` function on a `Receiver`.
///
/// assert_eq!(rx.recv().unwrap(), 2);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn sync_channel<T: Send>(bound: uint) -> (SyncSender<T>, Receiver<T>) {
+pub fn sync_channel<T: Send>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
let a = Arc::new(UnsafeCell::new(sync::Packet::new(bound)));
(SyncSender::new(a.clone()), Receiver::new(Flavor::Sync(a)))
}
use super::*;
use thread;
- pub fn stress_factor() -> uint {
+ pub fn stress_factor() -> usize {
match env::var("RUST_TEST_STRESS") {
Ok(val) => val.parse().unwrap(),
Err(..) => 1,
#[test]
fn smoke() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
tx.send(1).unwrap();
assert_eq!(rx.recv().unwrap(), 1);
}
#[test]
fn smoke_shared() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
tx.send(1).unwrap();
assert_eq!(rx.recv().unwrap(), 1);
let tx = tx.clone();
#[test]
fn smoke_threads() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
let _t = thread::spawn(move|| {
tx.send(1).unwrap();
});
#[test]
fn smoke_port_gone() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
drop(rx);
assert!(tx.send(1).is_err());
}
#[test]
fn smoke_shared_port_gone() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
drop(rx);
assert!(tx.send(1).is_err())
}
#[test]
fn smoke_shared_port_gone2() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
drop(rx);
let tx2 = tx.clone();
drop(tx);
#[test]
fn port_gone_concurrent() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
let _t = thread::spawn(move|| {
rx.recv().unwrap();
});
#[test]
fn port_gone_concurrent_shared() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
let tx2 = tx.clone();
let _t = thread::spawn(move|| {
rx.recv().unwrap();
#[test]
fn smoke_chan_gone() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
drop(tx);
assert!(rx.recv().is_err());
}
#[test]
fn chan_gone_concurrent() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
let _t = thread::spawn(move|| {
tx.send(1).unwrap();
tx.send(1).unwrap();
#[test]
fn stress() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
let t = thread::spawn(move|| {
for _ in 0..10000 { tx.send(1).unwrap(); }
});
#[test]
fn stress_shared() {
- static AMT: uint = 10000;
- static NTHREADS: uint = 8;
- let (tx, rx) = channel::<int>();
+ static AMT: u32 = 10000;
+ static NTHREADS: u32 = 8;
+ let (tx, rx) = channel::<i32>();
let t = thread::spawn(move|| {
for _ in 0..AMT * NTHREADS {
#[test]
fn send_from_outside_runtime() {
let (tx1, rx1) = channel::<()>();
- let (tx2, rx2) = channel::<int>();
+ let (tx2, rx2) = channel::<i32>();
let t1 = thread::spawn(move|| {
tx1.send(()).unwrap();
for _ in 0..40 {
#[test]
fn recv_from_outside_runtime() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
let t = thread::spawn(move|| {
for _ in 0..40 {
assert_eq!(rx.recv().unwrap(), 1);
#[test]
fn no_runtime() {
- let (tx1, rx1) = channel::<int>();
- let (tx2, rx2) = channel::<int>();
+ let (tx1, rx1) = channel::<i32>();
+ let (tx2, rx2) = channel::<i32>();
let t1 = thread::spawn(move|| {
assert_eq!(rx1.recv().unwrap(), 1);
tx2.send(2).unwrap();
#[test]
fn oneshot_single_thread_close_port_first() {
// Simple test of closing without sending
- let (_tx, rx) = channel::<int>();
+ let (_tx, rx) = channel::<i32>();
drop(rx);
}
#[test]
fn oneshot_single_thread_close_chan_first() {
// Simple test of closing without sending
- let (tx, _rx) = channel::<int>();
+ let (tx, _rx) = channel::<i32>();
drop(tx);
}
#[test]
fn oneshot_single_thread_send_port_close() {
// Testing that the sender cleans up the payload if receiver is closed
- let (tx, rx) = channel::<Box<int>>();
+ let (tx, rx) = channel::<Box<i32>>();
drop(rx);
assert!(tx.send(box 0).is_err());
}
fn oneshot_single_thread_recv_chan_close() {
// Receiving on a closed chan will panic
let res = thread::spawn(move|| {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
drop(tx);
rx.recv().unwrap();
}).join();
#[test]
fn oneshot_single_thread_send_then_recv() {
- let (tx, rx) = channel::<Box<int>>();
+ let (tx, rx) = channel::<Box<i32>>();
tx.send(box 10).unwrap();
assert!(rx.recv().unwrap() == box 10);
}
#[test]
fn oneshot_single_thread_try_send_open() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
assert!(tx.send(10).is_ok());
assert!(rx.recv().unwrap() == 10);
}
#[test]
fn oneshot_single_thread_try_send_closed() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
drop(rx);
assert!(tx.send(10).is_err());
}
#[test]
fn oneshot_single_thread_try_recv_open() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
tx.send(10).unwrap();
assert!(rx.recv() == Ok(10));
}
#[test]
fn oneshot_single_thread_try_recv_closed() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
drop(tx);
assert!(rx.recv().is_err());
}
#[test]
fn oneshot_single_thread_peek_data() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
tx.send(10).unwrap();
assert_eq!(rx.try_recv(), Ok(10));
#[test]
fn oneshot_single_thread_peek_close() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
drop(tx);
assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
#[test]
fn oneshot_single_thread_peek_open() {
- let (_tx, rx) = channel::<int>();
+ let (_tx, rx) = channel::<i32>();
assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
}
#[test]
fn oneshot_multi_task_recv_then_send() {
- let (tx, rx) = channel::<Box<int>>();
+ let (tx, rx) = channel::<Box<i32>>();
let _t = thread::spawn(move|| {
assert!(rx.recv().unwrap() == box 10);
});
#[test]
fn oneshot_multi_task_recv_then_close() {
- let (tx, rx) = channel::<Box<int>>();
+ let (tx, rx) = channel::<Box<i32>>();
let _t = thread::spawn(move|| {
drop(tx);
});
#[test]
fn oneshot_multi_thread_close_stress() {
for _ in 0..stress_factor() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
let _t = thread::spawn(move|| {
drop(rx);
});
#[test]
fn oneshot_multi_thread_send_close_stress() {
for _ in 0..stress_factor() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
let _t = thread::spawn(move|| {
drop(rx);
});
#[test]
fn oneshot_multi_thread_recv_close_stress() {
for _ in 0..stress_factor() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
thread::spawn(move|| {
let res = thread::spawn(move|| {
rx.recv().unwrap();
send(tx, 0);
recv(rx, 0);
- fn send(tx: Sender<Box<int>>, i: int) {
+ fn send(tx: Sender<Box<i32>>, i: i32) {
if i == 10 { return }
thread::spawn(move|| {
});
}
- fn recv(rx: Receiver<Box<int>>, i: int) {
+ fn recv(rx: Receiver<Box<i32>>, i: i32) {
if i == 10 { return }
thread::spawn(move|| {
#[test]
fn test_nested_recv_iter() {
- let (tx, rx) = channel::<int>();
- let (total_tx, total_rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
+ let (total_tx, total_rx) = channel::<i32>();
let _t = thread::spawn(move|| {
let mut acc = 0;
#[test]
fn test_recv_iter_break() {
- let (tx, rx) = channel::<int>();
+ let (tx, rx) = channel::<i32>();
let (count_tx, count_rx) = channel();
let _t = thread::spawn(move|| {
#[test]
fn try_recv_states() {
- let (tx1, rx1) = channel::<int>();
+ let (tx1, rx1) = channel::<i32>();
let (tx2, rx2) = channel::<()>();
let (tx3, rx3) = channel::<()>();
let _t = thread::spawn(move|| {
use thread;
use super::*;
- pub fn stress_factor() -> uint {
+ pub fn stress_factor() -> usize {
match env::var("RUST_TEST_STRESS") {
Ok(val) => val.parse().unwrap(),
Err(..) => 1,
#[test]
fn smoke() {
- let (tx, rx) = sync_channel::<int>(1);
+ let (tx, rx) = sync_channel::<i32>(1);
tx.send(1).unwrap();
assert_eq!(rx.recv().unwrap(), 1);
}
#[test]
fn smoke_shared() {
- let (tx, rx) = sync_channel::<int>(1);
+ let (tx, rx) = sync_channel::<i32>(1);
tx.send(1).unwrap();
assert_eq!(rx.recv().unwrap(), 1);
let tx = tx.clone();
#[test]
fn smoke_threads() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
let _t = thread::spawn(move|| {
tx.send(1).unwrap();
});
#[test]
fn smoke_port_gone() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
drop(rx);
assert!(tx.send(1).is_err());
}
#[test]
fn smoke_shared_port_gone2() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
drop(rx);
let tx2 = tx.clone();
drop(tx);
#[test]
fn port_gone_concurrent() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
let _t = thread::spawn(move|| {
rx.recv().unwrap();
});
#[test]
fn port_gone_concurrent_shared() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
let tx2 = tx.clone();
let _t = thread::spawn(move|| {
rx.recv().unwrap();
#[test]
fn smoke_chan_gone() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
drop(tx);
assert!(rx.recv().is_err());
}
#[test]
fn chan_gone_concurrent() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
thread::spawn(move|| {
tx.send(1).unwrap();
tx.send(1).unwrap();
#[test]
fn stress() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
thread::spawn(move|| {
for _ in 0..10000 { tx.send(1).unwrap(); }
});
#[test]
fn stress_shared() {
- static AMT: uint = 1000;
- static NTHREADS: uint = 8;
- let (tx, rx) = sync_channel::<int>(0);
+ static AMT: u32 = 1000;
+ static NTHREADS: u32 = 8;
+ let (tx, rx) = sync_channel::<i32>(0);
let (dtx, drx) = sync_channel::<()>(0);
thread::spawn(move|| {
#[test]
fn oneshot_single_thread_close_port_first() {
// Simple test of closing without sending
- let (_tx, rx) = sync_channel::<int>(0);
+ let (_tx, rx) = sync_channel::<i32>(0);
drop(rx);
}
#[test]
fn oneshot_single_thread_close_chan_first() {
// Simple test of closing without sending
- let (tx, _rx) = sync_channel::<int>(0);
+ let (tx, _rx) = sync_channel::<i32>(0);
drop(tx);
}
#[test]
fn oneshot_single_thread_send_port_close() {
// Testing that the sender cleans up the payload if receiver is closed
- let (tx, rx) = sync_channel::<Box<int>>(0);
+ let (tx, rx) = sync_channel::<Box<i32>>(0);
drop(rx);
assert!(tx.send(box 0).is_err());
}
fn oneshot_single_thread_recv_chan_close() {
// Receiving on a closed chan will panic
let res = thread::spawn(move|| {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
drop(tx);
rx.recv().unwrap();
}).join();
#[test]
fn oneshot_single_thread_send_then_recv() {
- let (tx, rx) = sync_channel::<Box<int>>(1);
+ let (tx, rx) = sync_channel::<Box<i32>>(1);
tx.send(box 10).unwrap();
assert!(rx.recv().unwrap() == box 10);
}
#[test]
fn oneshot_single_thread_try_send_open() {
- let (tx, rx) = sync_channel::<int>(1);
+ let (tx, rx) = sync_channel::<i32>(1);
assert_eq!(tx.try_send(10), Ok(()));
assert!(rx.recv().unwrap() == 10);
}
#[test]
fn oneshot_single_thread_try_send_closed() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
drop(rx);
assert_eq!(tx.try_send(10), Err(TrySendError::Disconnected(10)));
}
#[test]
fn oneshot_single_thread_try_send_closed2() {
- let (tx, _rx) = sync_channel::<int>(0);
+ let (tx, _rx) = sync_channel::<i32>(0);
assert_eq!(tx.try_send(10), Err(TrySendError::Full(10)));
}
#[test]
fn oneshot_single_thread_try_recv_open() {
- let (tx, rx) = sync_channel::<int>(1);
+ let (tx, rx) = sync_channel::<i32>(1);
tx.send(10).unwrap();
assert!(rx.recv() == Ok(10));
}
#[test]
fn oneshot_single_thread_try_recv_closed() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
drop(tx);
assert!(rx.recv().is_err());
}
#[test]
fn oneshot_single_thread_peek_data() {
- let (tx, rx) = sync_channel::<int>(1);
+ let (tx, rx) = sync_channel::<i32>(1);
assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
tx.send(10).unwrap();
assert_eq!(rx.try_recv(), Ok(10));
#[test]
fn oneshot_single_thread_peek_close() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
drop(tx);
assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
#[test]
fn oneshot_single_thread_peek_open() {
- let (_tx, rx) = sync_channel::<int>(0);
+ let (_tx, rx) = sync_channel::<i32>(0);
assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
}
#[test]
fn oneshot_multi_task_recv_then_send() {
- let (tx, rx) = sync_channel::<Box<int>>(0);
+ let (tx, rx) = sync_channel::<Box<i32>>(0);
let _t = thread::spawn(move|| {
assert!(rx.recv().unwrap() == box 10);
});
#[test]
fn oneshot_multi_task_recv_then_close() {
- let (tx, rx) = sync_channel::<Box<int>>(0);
+ let (tx, rx) = sync_channel::<Box<i32>>(0);
let _t = thread::spawn(move|| {
drop(tx);
});
#[test]
fn oneshot_multi_thread_close_stress() {
for _ in 0..stress_factor() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
let _t = thread::spawn(move|| {
drop(rx);
});
#[test]
fn oneshot_multi_thread_send_close_stress() {
for _ in 0..stress_factor() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
let _t = thread::spawn(move|| {
drop(rx);
});
#[test]
fn oneshot_multi_thread_recv_close_stress() {
for _ in 0..stress_factor() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
let _t = thread::spawn(move|| {
let res = thread::spawn(move|| {
rx.recv().unwrap();
#[test]
fn oneshot_multi_thread_send_recv_stress() {
for _ in 0..stress_factor() {
- let (tx, rx) = sync_channel::<Box<int>>(0);
+ let (tx, rx) = sync_channel::<Box<i32>>(0);
let _t = thread::spawn(move|| {
tx.send(box 10).unwrap();
});
#[test]
fn stream_send_recv_stress() {
for _ in 0..stress_factor() {
- let (tx, rx) = sync_channel::<Box<int>>(0);
+ let (tx, rx) = sync_channel::<Box<i32>>(0);
send(tx, 0);
recv(rx, 0);
- fn send(tx: SyncSender<Box<int>>, i: int) {
+ fn send(tx: SyncSender<Box<i32>>, i: i32) {
if i == 10 { return }
thread::spawn(move|| {
});
}
- fn recv(rx: Receiver<Box<int>>, i: int) {
+ fn recv(rx: Receiver<Box<i32>>, i: i32) {
if i == 10 { return }
thread::spawn(move|| {
#[test]
fn test_nested_recv_iter() {
- let (tx, rx) = sync_channel::<int>(0);
- let (total_tx, total_rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
+ let (total_tx, total_rx) = sync_channel::<i32>(0);
let _t = thread::spawn(move|| {
let mut acc = 0;
#[test]
fn test_recv_iter_break() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
let (count_tx, count_rx) = sync_channel(0);
let _t = thread::spawn(move|| {
#[test]
fn try_recv_states() {
- let (tx1, rx1) = sync_channel::<int>(1);
+ let (tx1, rx1) = sync_channel::<i32>(1);
let (tx2, rx2) = sync_channel::<()>(1);
let (tx3, rx3) = sync_channel::<()>(1);
let _t = thread::spawn(move|| {
#[test]
fn send1() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
let _t = thread::spawn(move|| { rx.recv().unwrap(); });
assert_eq!(tx.send(1), Ok(()));
}
#[test]
fn send2() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
let _t = thread::spawn(move|| { drop(rx); });
assert!(tx.send(1).is_err());
}
#[test]
fn send3() {
- let (tx, rx) = sync_channel::<int>(1);
+ let (tx, rx) = sync_channel::<i32>(1);
assert_eq!(tx.send(1), Ok(()));
let _t =thread::spawn(move|| { drop(rx); });
assert!(tx.send(1).is_err());
#[test]
fn send4() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
let tx2 = tx.clone();
let (done, donerx) = channel();
let done2 = done.clone();
#[test]
fn try_send1() {
- let (tx, _rx) = sync_channel::<int>(0);
+ let (tx, _rx) = sync_channel::<i32>(0);
assert_eq!(tx.try_send(1), Err(TrySendError::Full(1)));
}
#[test]
fn try_send2() {
- let (tx, _rx) = sync_channel::<int>(1);
+ let (tx, _rx) = sync_channel::<i32>(1);
assert_eq!(tx.try_send(1), Ok(()));
assert_eq!(tx.try_send(1), Err(TrySendError::Full(1)));
}
#[test]
fn try_send3() {
- let (tx, rx) = sync_channel::<int>(1);
+ let (tx, rx) = sync_channel::<i32>(1);
assert_eq!(tx.try_send(1), Ok(()));
drop(rx);
assert_eq!(tx.try_send(1), Err(TrySendError::Disconnected(1)));
///
/// # Implementation
///
-/// Oneshots are implemented around one atomic uint variable. This variable
+/// Oneshots are implemented around one atomic usize variable. This variable
/// indicates both the state of the port/chan but also contains any tasks
/// blocked on the port. All atomic operations happen on this one word.
///
use sync::atomic::{AtomicUsize, Ordering};
// Various states you can find a port in.
-const EMPTY: uint = 0; // initial state: no data, no blocked receiver
-const DATA: uint = 1; // data ready for receiver to take
-const DISCONNECTED: uint = 2; // channel is disconnected OR upgraded
+const EMPTY: usize = 0; // initial state: no data, no blocked receiver
+const DATA: usize = 1; // data ready for receiver to take
+const DISCONNECTED: usize = 2; // channel is disconnected OR upgraded
// Any other value represents a pointer to a SignalToken value. The
// protocol ensures that when the state moves *to* a pointer,
// ownership of the token is given to the packet, and when the state
// There is a thread waiting on the other end. We leave the 'DATA'
// state inside so it'll pick it up on the other end.
ptr => unsafe {
- SignalToken::cast_from_uint(ptr).signal();
+ SignalToken::cast_from_usize(ptr).signal();
Ok(())
}
}
// like we're not empty, then immediately go through to `try_recv`.
if self.state.load(Ordering::SeqCst) == EMPTY {
let (wait_token, signal_token) = blocking::tokens();
- let ptr = unsafe { signal_token.cast_to_uint() };
+ let ptr = unsafe { signal_token.cast_to_usize() };
// race with senders to enter the blocking state
if self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) == EMPTY {
debug_assert!(self.state.load(Ordering::SeqCst) != EMPTY);
} else {
// drop the signal token, since we never blocked
- drop(unsafe { SignalToken::cast_from_uint(ptr) });
+ drop(unsafe { SignalToken::cast_from_usize(ptr) });
}
}
DISCONNECTED => { self.upgrade = prev; UpDisconnected }
// If someone's waiting, we gotta wake them up
- ptr => UpWoke(unsafe { SignalToken::cast_from_uint(ptr) })
+ ptr => UpWoke(unsafe { SignalToken::cast_from_usize(ptr) })
}
}
// If someone's waiting, we gotta wake them up
ptr => unsafe {
- SignalToken::cast_from_uint(ptr).signal();
+ SignalToken::cast_from_usize(ptr).signal();
}
}
}
// Attempts to start selection on this port. This can either succeed, fail
// because there is data, or fail because there is an upgrade pending.
pub fn start_selection(&mut self, token: SignalToken) -> SelectionResult<T> {
- let ptr = unsafe { token.cast_to_uint() };
+ let ptr = unsafe { token.cast_to_usize() };
match self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) {
EMPTY => SelSuccess,
DATA => {
- drop(unsafe { SignalToken::cast_from_uint(ptr) });
+ drop(unsafe { SignalToken::cast_from_usize(ptr) });
SelCanceled
}
DISCONNECTED if self.data.is_some() => {
- drop(unsafe { SignalToken::cast_from_uint(ptr) });
+ drop(unsafe { SignalToken::cast_from_usize(ptr) });
SelCanceled
}
DISCONNECTED => {
// propagate upwards whether the upgrade can receive
// data
GoUp(upgrade) => {
- SelUpgraded(unsafe { SignalToken::cast_from_uint(ptr) }, upgrade)
+ SelUpgraded(unsafe { SignalToken::cast_from_usize(ptr) }, upgrade)
}
// If the other end disconnected without sending an
// disconnected).
up => {
self.upgrade = up;
- drop(unsafe { SignalToken::cast_from_uint(ptr) });
+ drop(unsafe { SignalToken::cast_from_usize(ptr) });
SelCanceled
}
}
// We woke ourselves up from select.
ptr => unsafe {
- drop(SignalToken::cast_from_uint(ptr));
+ drop(SignalToken::cast_from_usize(ptr));
Ok(false)
}
}
pub struct Select {
head: *mut Handle<'static, ()>,
tail: *mut Handle<'static, ()>,
- next_id: Cell<uint>,
+ next_id: Cell<usize>,
}
impl !marker::Send for Select {}
pub struct Handle<'rx, T:'rx> {
/// The ID of this handle, used to compare against the return value of
/// `Select::wait()`
- id: uint,
+ id: usize,
selector: &'rx Select,
next: *mut Handle<'static, ()>,
prev: *mut Handle<'static, ()>,
/// the matching `id` will have some sort of event available on it. The
/// event could either be that data is available or the corresponding
/// channel has been closed.
- pub fn wait(&self) -> uint {
+ pub fn wait(&self) -> usize {
self.wait2(true)
}
/// Helper method for skipping the preflight checks during testing
- fn wait2(&self, do_preflight_checks: bool) -> uint {
+ fn wait2(&self, do_preflight_checks: bool) -> usize {
// Note that this is currently an inefficient implementation. We in
// theory have knowledge about all receivers in the set ahead of time,
// so this method shouldn't really have to iterate over all of them yet
impl<'rx, T: Send> Handle<'rx, T> {
/// Retrieve the id of this handle.
#[inline]
- pub fn id(&self) -> uint { self.id }
+ pub fn id(&self) -> usize { self.id }
/// Block to receive a value on the underlying receiver, returning `Some` on
/// success or `None` if the channel disconnects. This function has the same
#[test]
fn smoke() {
- let (tx1, rx1) = channel::<int>();
- let (tx2, rx2) = channel::<int>();
+ let (tx1, rx1) = channel::<i32>();
+ let (tx2, rx2) = channel::<i32>();
tx1.send(1).unwrap();
select! {
foo = rx1.recv() => { assert_eq!(foo.unwrap(), 1); },
#[test]
fn smoke2() {
- let (_tx1, rx1) = channel::<int>();
- let (_tx2, rx2) = channel::<int>();
- let (_tx3, rx3) = channel::<int>();
- let (_tx4, rx4) = channel::<int>();
- let (tx5, rx5) = channel::<int>();
+ let (_tx1, rx1) = channel::<i32>();
+ let (_tx2, rx2) = channel::<i32>();
+ let (_tx3, rx3) = channel::<i32>();
+ let (_tx4, rx4) = channel::<i32>();
+ let (tx5, rx5) = channel::<i32>();
tx5.send(4).unwrap();
select! {
_foo = rx1.recv() => { panic!("1") },
#[test]
fn closed() {
- let (_tx1, rx1) = channel::<int>();
- let (tx2, rx2) = channel::<int>();
+ let (_tx1, rx1) = channel::<i32>();
+ let (tx2, rx2) = channel::<i32>();
drop(tx2);
select! {
#[test]
fn unblocks() {
- let (tx1, rx1) = channel::<int>();
- let (_tx2, rx2) = channel::<int>();
- let (tx3, rx3) = channel::<int>();
+ let (tx1, rx1) = channel::<i32>();
+ let (_tx2, rx2) = channel::<i32>();
+ let (tx3, rx3) = channel::<i32>();
let _t = thread::spawn(move|| {
for _ in 0..20 { thread::yield_now(); }
#[test]
fn both_ready() {
- let (tx1, rx1) = channel::<int>();
- let (tx2, rx2) = channel::<int>();
+ let (tx1, rx1) = channel::<i32>();
+ let (tx2, rx2) = channel::<i32>();
let (tx3, rx3) = channel::<()>();
let _t = thread::spawn(move|| {
#[test]
fn stress() {
- static AMT: int = 10000;
- let (tx1, rx1) = channel::<int>();
- let (tx2, rx2) = channel::<int>();
+ static AMT: i32 = 10000;
+ let (tx1, rx1) = channel::<i32>();
+ let (tx2, rx2) = channel::<i32>();
let (tx3, rx3) = channel::<()>();
let _t = thread::spawn(move|| {
#[test]
fn cloning() {
- let (tx1, rx1) = channel::<int>();
- let (_tx2, rx2) = channel::<int>();
+ let (tx1, rx1) = channel::<i32>();
+ let (_tx2, rx2) = channel::<i32>();
let (tx3, rx3) = channel::<()>();
let _t = thread::spawn(move|| {
#[test]
fn cloning2() {
- let (tx1, rx1) = channel::<int>();
- let (_tx2, rx2) = channel::<int>();
+ let (tx1, rx1) = channel::<i32>();
+ let (_tx2, rx2) = channel::<i32>();
let (tx3, rx3) = channel::<()>();
let _t = thread::spawn(move|| {
#[test]
fn sync1() {
- let (tx, rx) = sync_channel::<int>(1);
+ let (tx, rx) = sync_channel::<i32>(1);
tx.send(1).unwrap();
select! {
n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
#[test]
fn sync2() {
- let (tx, rx) = sync_channel::<int>(0);
+ let (tx, rx) = sync_channel::<i32>(0);
let _t = thread::spawn(move|| {
for _ in 0..100 { thread::yield_now() }
tx.send(1).unwrap();
#[test]
fn sync3() {
- let (tx1, rx1) = sync_channel::<int>(0);
- let (tx2, rx2): (Sender<int>, Receiver<int>) = channel();
+ let (tx1, rx1) = sync_channel::<i32>(0);
+ let (tx2, rx2): (Sender<i32>, Receiver<i32>) = channel();
let _t = thread::spawn(move|| { tx1.send(1).unwrap(); });
let _t = thread::spawn(move|| { tx2.send(2).unwrap(); });
select! {
token.map(|token| {
assert_eq!(self.cnt.load(Ordering::SeqCst), 0);
assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
- self.to_wake.store(unsafe { token.cast_to_uint() }, Ordering::SeqCst);
+ self.to_wake.store(unsafe { token.cast_to_usize() }, Ordering::SeqCst);
self.cnt.store(-1, Ordering::SeqCst);
// This store is a little sketchy. What's happening here is that
// Returns true if blocking should proceed.
fn decrement(&mut self, token: SignalToken) -> StartResult {
assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
- let ptr = unsafe { token.cast_to_uint() };
+ let ptr = unsafe { token.cast_to_usize() };
self.to_wake.store(ptr, Ordering::SeqCst);
let steals = self.steals;
}
self.to_wake.store(0, Ordering::SeqCst);
- drop(unsafe { SignalToken::cast_from_uint(ptr) });
+ drop(unsafe { SignalToken::cast_from_usize(ptr) });
Abort
}
let ptr = self.to_wake.load(Ordering::SeqCst);
self.to_wake.store(0, Ordering::SeqCst);
assert!(ptr != 0);
- unsafe { SignalToken::cast_from_uint(ptr) }
+ unsafe { SignalToken::cast_from_usize(ptr) }
}
////////////////////////////////////////////////////////////////////////////
// Cache maintenance fields. Additions and subtractions are stored
// separately in order to allow them to use nonatomic addition/subtraction.
- cache_bound: uint,
+ cache_bound: usize,
cache_additions: AtomicUsize,
cache_subtractions: AtomicUsize,
}
/// cache (if desired). If the value is 0, then the cache has
/// no bound. Otherwise, the cache will never grow larger than
/// `bound` (although the queue itself could be much larger.
- pub unsafe fn new(bound: uint) -> Queue<T> {
+ pub unsafe fn new(bound: usize) -> Queue<T> {
let n1 = Node::new();
let n2 = Node::new();
(*n1).next.store(n2, Ordering::Relaxed);
stress_bound(1);
}
- unsafe fn stress_bound(bound: uint) {
+ unsafe fn stress_bound(bound: usize) {
let q = Arc::new(Queue::new(bound));
let (tx, rx) = channel();
queue: spsc::Queue<Message<T>>, // internal queue for all message
cnt: AtomicIsize, // How many items are on this channel
- steals: int, // How many times has a port received without blocking?
+ steals: isize, // How many times has a port received without blocking?
to_wake: AtomicUsize, // SignalToken for the blocked thread to wake up
port_dropped: AtomicBool, // flag if the channel has been destroyed.
let ptr = self.to_wake.load(Ordering::SeqCst);
self.to_wake.store(0, Ordering::SeqCst);
assert!(ptr != 0);
- unsafe { SignalToken::cast_from_uint(ptr) }
+ unsafe { SignalToken::cast_from_usize(ptr) }
}
// Decrements the count on the channel for a sleeper, returning the sleeper
// steals into account.
fn decrement(&mut self, token: SignalToken) -> Result<(), SignalToken> {
assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
- let ptr = unsafe { token.cast_to_uint() };
+ let ptr = unsafe { token.cast_to_usize() };
self.to_wake.store(ptr, Ordering::SeqCst);
let steals = self.steals;
}
self.to_wake.store(0, Ordering::SeqCst);
- Err(unsafe { SignalToken::cast_from_uint(ptr) })
+ Err(unsafe { SignalToken::cast_from_usize(ptr) })
}
pub fn recv(&mut self) -> Result<T, Failure<T>> {
}
// increment the count on the channel (used for selection)
- fn bump(&mut self, amt: int) -> int {
+ fn bump(&mut self, amt: isize) -> isize {
match self.cnt.fetch_add(amt, Ordering::SeqCst) {
DISCONNECTED => {
self.cnt.store(DISCONNECTED, Ordering::SeqCst);
queue: Queue, // queue of senders waiting to send data
blocker: Blocker, // currently blocked task on this channel
buf: Buffer<T>, // storage for buffered messages
- cap: uint, // capacity of this channel
+ cap: usize, // capacity of this channel
/// A curious flag used to indicate whether a sender failed or succeeded in
/// blocking. This is used to transmit information back to the task that it
/// A simple ring-buffer
struct Buffer<T> {
buf: Vec<Option<T>>,
- start: uint,
- size: uint,
+ start: usize,
+ size: usize,
}
#[derive(Debug)]
}
impl<T: Send> Packet<T> {
- pub fn new(cap: uint) -> Packet<T> {
+ pub fn new(cap: usize) -> Packet<T> {
Packet {
channels: AtomicUsize::new(1),
lock: Mutex::new(State {
result.take().unwrap()
}
- fn size(&self) -> uint { self.size }
- fn cap(&self) -> uint { self.buf.len() }
+ fn size(&self) -> usize { self.size }
+ fn cap(&self) -> usize { self.buf.len() }
}
////////////////////////////////////////////////////////////////////////////////
use ops::{Deref, DerefMut};
use sync::poison::{self, TryLockError, TryLockResult, LockResult};
use sys_common::mutex as sys;
+use fmt;
/// A mutual exclusion primitive useful for protecting shared data
///
/// use std::thread;
/// use std::sync::mpsc::channel;
///
-/// const N: uint = 10;
+/// const N: usize = 10;
///
/// // Spawn a few threads to increment a shared variable (non-atomically), and
/// // let the main thread know once all increments are done.
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.
///
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: fmt::Debug + Send + 'static> fmt::Debug for Mutex<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self.try_lock() {
+ Ok(guard) => write!(f, "Mutex {{ data: {:?} }}", *guard),
+ Err(TryLockError::Poisoned(err)) => {
+ write!(f, "Mutex {{ data: Poisoned({:?}) }}", **err.get_ref())
+ },
+ Err(TryLockError::WouldBlock) => write!(f, "Mutex {{ <locked> }}")
+ }
+ }
+}
+
struct Dummy(UnsafeCell<()>);
unsafe impl Sync for Dummy {}
static DUMMY: Dummy = Dummy(UnsafeCell { value: () });
#[test]
fn lots_and_lots() {
static M: StaticMutex = MUTEX_INIT;
- static mut CNT: uint = 0;
- static J: uint = 1000;
- static K: uint = 3;
+ static mut CNT: u32 = 0;
+ static J: u32 = 1000;
+ static K: u32 = 3;
fn inc() {
for _ in 0..J {
let arc2 = arc.clone();
let _ = thread::spawn(move|| -> () {
struct Unwinder {
- i: Arc<Mutex<int>>,
+ i: Arc<Mutex<i32>>,
}
impl Drop for Unwinder {
fn drop(&mut self) {
//! 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 {
use ops::{Deref, DerefMut};
use sync::poison::{self, LockResult, TryLockError, TryLockResult};
use sys_common::rwlock as sys;
+use fmt;
/// A reader-writer lock
///
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")]
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: fmt::Debug + Send + Sync> fmt::Debug for RwLock<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self.try_read() {
+ Ok(guard) => write!(f, "RwLock {{ data: {:?} }}", *guard),
+ Err(TryLockError::Poisoned(err)) => {
+ write!(f, "RwLock {{ data: Poisoned({:?}) }}", **err.get_ref())
+ },
+ Err(TryLockError::WouldBlock) => write!(f, "RwLock {{ <locked> }}")
+ }
+ }
+}
+
struct Dummy(UnsafeCell<()>);
unsafe impl Sync for Dummy {}
static DUMMY: Dummy = Dummy(UnsafeCell { value: () });
//! 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::*;
/// # Panics
///
/// This function will panic if `threads` is 0.
- pub fn new(threads: uint) -> TaskPool {
+ pub fn new(threads: usize) -> TaskPool {
assert!(threads >= 1);
let (tx, rx) = channel::<Thunk>();
use super::*;
use sync::mpsc::channel;
- const TEST_TASKS: uint = 4;
+ const TEST_TASKS: usize = 4;
#[test]
fn test_works() {
#[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));
}
// FileStat times are in milliseconds
fn mktime(secs: u64, nsecs: u64) -> u64 { secs * 1000 + nsecs / 1000000 }
- #[cfg(target_os = "bitrig")]
- fn ctime(stat: &libc::stat) -> u64 {
- mktime(stat.st_ctim.tv_sec as u64, stat.st_ctim.tv_nsec as u64)
- }
- #[cfg(not(target_os = "bitrig"))]
fn ctime(stat: &libc::stat) -> u64 {
mktime(stat.st_ctime as u64, stat.st_ctime_nsec as u64)
}
- #[cfg(target_os = "bitrig")]
- fn atime(stat: &libc::stat) -> u64 {
- mktime(stat.st_atim.tv_sec as u64, stat.st_atim.tv_nsec as u64)
- }
- #[cfg(not(target_os = "bitrig"))]
fn atime(stat: &libc::stat) -> u64 {
mktime(stat.st_atime as u64, stat.st_atime_nsec as u64)
}
- #[cfg(target_os = "bitrig")]
- fn mtime(stat: &libc::stat) -> u64 {
- mktime(stat.st_mtim.tv_sec as u64, stat.st_mtim.tv_nsec as u64)
- }
- #[cfg(not(target_os = "bitrig"))]
fn mtime(stat: &libc::stat) -> u64 {
mktime(stat.st_mtime as u64, stat.st_mtime_nsec as u64)
}
use mem;
use path::{Path, PathBuf};
use ptr;
-use rc::Rc;
+use sync::Arc;
use sys::fd::FileDesc;
use sys::{c, cvt, cvt_r};
use sys_common::FromInner;
}
pub struct ReadDir {
- dirp: *mut libc::DIR,
- root: Rc<PathBuf>,
+ dirp: Dir,
+ root: Arc<PathBuf>,
}
+struct Dir(*mut libc::DIR);
+
+unsafe impl Send for Dir {}
+unsafe impl Sync for Dir {}
+
pub struct DirEntry {
- buf: Vec<u8>,
- dirent: *mut libc::dirent_t,
- root: Rc<PathBuf>,
+ buf: Vec<u8>, // actually *mut libc::dirent_t
+ root: Arc<PathBuf>,
}
#[derive(Clone)]
self.mode |= 0o222;
}
}
+ pub fn mode(&self) -> i32 { self.mode as i32 }
}
impl FromInner<i32> for FilePermissions {
let mut entry_ptr = ptr::null_mut();
loop {
- if unsafe { libc::readdir_r(self.dirp, ptr, &mut entry_ptr) != 0 } {
+ if unsafe { libc::readdir_r(self.dirp.0, ptr, &mut entry_ptr) != 0 } {
return Some(Err(Error::last_os_error()))
}
if entry_ptr.is_null() {
let entry = DirEntry {
buf: buf,
- dirent: entry_ptr,
root: self.root.clone()
};
if entry.name_bytes() == b"." || entry.name_bytes() == b".." {
}
}
-impl Drop for ReadDir {
+impl Drop for Dir {
fn drop(&mut self) {
- let r = unsafe { libc::closedir(self.dirp) };
+ let r = unsafe { libc::closedir(self.0) };
debug_assert_eq!(r, 0);
}
}
fn rust_list_dir_val(ptr: *mut libc::dirent_t) -> *const c_char;
}
unsafe {
- CStr::from_ptr(rust_list_dir_val(self.dirent)).to_bytes()
+ CStr::from_ptr(rust_list_dir_val(self.dirent())).to_bytes()
}
}
+
+ fn dirent(&self) -> *mut libc::dirent_t {
+ self.buf.as_ptr() as *mut _
+ }
}
impl OpenOptions {
}
pub fn readdir(p: &Path) -> io::Result<ReadDir> {
- let root = Rc::new(p.to_path_buf());
+ let root = Arc::new(p.to_path_buf());
let p = try!(cstr(p));
unsafe {
let ptr = libc::opendir(p.as_ptr());
if ptr.is_null() {
Err(Error::last_os_error())
} else {
- Ok(ReadDir { dirp: ptr, root: root })
+ Ok(ReadDir { dirp: Dir(ptr), root: root })
}
}
}
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()))
+ let vec = CStr::from_ptr(v).to_bytes().to_vec();
+ Ok(PathBuf::new::<OsString>(&OsStringExt::from_vec(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| {
target_os = "ios",
target_os = "freebsd",
target_os = "dragonfly",
+ target_os = "bitrig",
target_os = "openbsd"))]
mod imp {
pub fn WIFEXITED(status: i32) -> bool { (status & 0x7f) == 0 }
// 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 mem;
use path::{Path, PathBuf};
use ptr;
+use sync::Arc;
use sys::handle::Handle as RawHandle;
use sys::{c, cvt};
use vec::Vec;
pub struct FileAttr { data: c::WIN32_FILE_ATTRIBUTE_DATA }
pub struct ReadDir {
- handle: libc::HANDLE,
- root: PathBuf,
+ handle: FindNextFileHandle,
+ root: Arc<PathBuf>,
first: Option<libc::WIN32_FIND_DATAW>,
}
-pub struct DirEntry { path: PathBuf }
+struct FindNextFileHandle(libc::HANDLE);
+
+unsafe impl Send for FindNextFileHandle {}
+unsafe impl Sync for FindNextFileHandle {}
+
+pub struct DirEntry {
+ root: Arc<PathBuf>,
+ data: libc::WIN32_FIND_DATAW,
+}
#[derive(Clone, Default)]
pub struct OpenOptions {
unsafe {
let mut wfd = mem::zeroed();
loop {
- if libc::FindNextFileW(self.handle, &mut wfd) == 0 {
+ if libc::FindNextFileW(self.handle.0, &mut wfd) == 0 {
if libc::GetLastError() ==
c::ERROR_NO_MORE_FILES as libc::DWORD {
return None
}
}
-impl Drop for ReadDir {
+impl Drop for FindNextFileHandle {
fn drop(&mut self) {
- let r = unsafe { libc::FindClose(self.handle) };
+ let r = unsafe { libc::FindClose(self.0) };
debug_assert!(r != 0);
}
}
impl DirEntry {
- fn new(root: &Path, wfd: &libc::WIN32_FIND_DATAW) -> Option<DirEntry> {
+ fn new(root: &Arc<PathBuf>, wfd: &libc::WIN32_FIND_DATAW) -> Option<DirEntry> {
match &wfd.cFileName[0..3] {
// check for '.' and '..'
[46, 0, ..] |
_ => {}
}
- let filename = super::truncate_utf16_at_nul(&wfd.cFileName);
- let filename: OsString = OsStringExt::from_wide(filename);
- Some(DirEntry { path: root.join(&filename) })
+ Some(DirEntry {
+ root: root.clone(),
+ data: *wfd,
+ })
}
pub fn path(&self) -> PathBuf {
- self.path.clone()
+ let filename = super::truncate_utf16_at_nul(&self.data.cFileName);
+ self.root.join(&<OsString as OsStringExt>::from_wide(filename))
}
}
let mut wfd = mem::zeroed();
let find_handle = libc::FindFirstFileW(path.as_ptr(), &mut wfd);
if find_handle != libc::INVALID_HANDLE_VALUE {
- Ok(ReadDir { handle: find_handle, root: root, first: Some(wfd) })
+ Ok(ReadDir {
+ handle: FindNextFileHandle(find_handle),
+ root: Arc::new(root),
+ first: Some(wfd),
+ })
} else {
Err(Error::last_os_error())
}
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,
}
}
-/// Spawn a new, returning a join handle for it.
+/// Spawn a new thread, returning a `JoinHandle` for it.
///
-/// The child thread may outlive the parent (unless the parent thread
-/// is the main thread; the whole process is terminated when the main
-/// thread finishes.) The join handle can be used to block on
-/// termination of the child thread, including recovering its panics.
+/// The join handle will implicitly *detach* the child thread upon being
+/// dropped. In this case, the child thread may outlive the parent (unless
+/// the parent thread is the main thread; the whole process is terminated when
+/// the main thread finishes.) Additionally, the join handle provides a `join`
+/// method that can be used to join the child thread. If the child thread
+/// panics, `join` will return an `Err` containing the argument given to
+/// `panic`.
///
/// # Panics
///
/// use std::cell::RefCell;
/// use std::thread;
///
-/// thread_local!(static FOO: RefCell<uint> = RefCell::new(1));
+/// thread_local!(static FOO: RefCell<u32> = RefCell::new(1));
///
/// FOO.with(|f| {
/// assert_eq!(*f.borrow(), 1);
// This is trivially devirtualizable by LLVM because we never store anything
// to this field and rustc can declare the `static` as constant as well.
#[doc(hidden)]
+ #[unstable(feature = "thread_local_internals")]
pub inner: fn() -> &'static __impl::KeyInner<UnsafeCell<Option<T>>>,
// initialization routine to invoke to create a value
#[doc(hidden)]
+ #[unstable(feature = "thread_local_internals")]
pub init: fn() -> T,
}
unsafe fn ptr(&'static self) -> Option<*mut T> {
let ptr = self.os.get() as *mut Value<T>;
if !ptr.is_null() {
- if ptr as uint == 1 {
+ if ptr as usize == 1 {
return None
}
return Some(&mut (*ptr).value as *mut T);
#[test]
fn smoke_no_dtor() {
- thread_local!(static FOO: UnsafeCell<int> = UnsafeCell { value: 1 });
+ thread_local!(static FOO: UnsafeCell<i32> = UnsafeCell { value: 1 });
FOO.with(|f| unsafe {
assert_eq!(*f.get(), 1);
thread_local!(static K2: UnsafeCell<Option<S2>> = UnsafeCell {
value: None
});
- static mut HITS: uint = 0;
+ static mut HITS: u32 = 0;
impl Drop for S1 {
fn drop(&mut self) {
#[test]
fn smoke() {
- fn square(i: int) -> int { i * i }
- thread_local!(static FOO: int = square(3));
+ fn square(i: i32) -> i32 { i * i }
+ thread_local!(static FOO: i32 = square(3));
FOO.with(|f| {
assert_eq!(*f, 9);
#[test]
fn hashmap() {
- fn map() -> RefCell<HashMap<int, int>> {
+ fn map() -> RefCell<HashMap<i32, i32>> {
let mut m = HashMap::new();
m.insert(1, 2);
RefCell::new(m)
}
- thread_local!(static FOO: RefCell<HashMap<int, int>> = map());
+ thread_local!(static FOO: RefCell<HashMap<i32, i32>> = map());
FOO.with(|map| {
assert_eq!(map.borrow()[1], 2);
#[test]
fn refcell_vec() {
- thread_local!(static FOO: RefCell<Vec<uint>> = RefCell::new(vec![1, 2, 3]));
+ thread_local!(static FOO: RefCell<Vec<u32>> = RefCell::new(vec![1, 2, 3]));
FOO.with(|vec| {
assert_eq!(vec.borrow().len(), 3);
//! # Example
//!
//! ```
-//! scoped_thread_local!(static FOO: uint);
+//! scoped_thread_local!(static FOO: u32);
//!
//! // Initially each scoped slot is empty.
//! assert!(!FOO.is_set());
/// # Example
///
/// ```
- /// scoped_thread_local!(static FOO: uint);
+ /// scoped_thread_local!(static FOO: u32);
///
/// FOO.set(&100, || {
/// let val = FOO.with(|v| *v);
/// # Example
///
/// ```no_run
- /// scoped_thread_local!(static FOO: uint);
+ /// scoped_thread_local!(static FOO: u32);
///
/// FOO.with(|slot| {
/// // work with `slot`
use cell::Cell;
use prelude::v1::*;
- scoped_thread_local!(static FOO: uint);
+ scoped_thread_local!(static FOO: u32);
#[test]
fn smoke() {
- scoped_thread_local!(static BAR: uint);
+ scoped_thread_local!(static BAR: u32);
assert!(!BAR.is_set());
BAR.set(&1, || {
#[test]
fn cell_allowed() {
- scoped_thread_local!(static BAR: Cell<uint>);
+ scoped_thread_local!(static BAR: Cell<u32>);
BAR.set(&Cell::new(1), || {
BAR.with(|slot| {
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> {
self.expr_lit(sp, ast::LitInt(i as u64, ast::SignedIntLit(ast::TyIs(false),
ast::Sign::new(i))))
}
- fn expr_u8(&self, sp: Span, u: u8) -> P<ast::Expr> {
- self.expr_lit(sp, ast::LitInt(u as u64, ast::UnsignedIntLit(ast::TyU8)))
- }
fn expr_u32(&self, sp: Span, u: u32) -> P<ast::Expr> {
self.expr_lit(sp, ast::LitInt(u as u64, ast::UnsignedIntLit(ast::TyU32)))
}
+ fn expr_u8(&self, sp: Span, u: u8) -> P<ast::Expr> {
+ self.expr_lit(sp, ast::LitInt(u as u64, ast::UnsignedIntLit(ast::TyU8)))
+ }
fn expr_bool(&self, sp: Span, value: bool) -> P<ast::Expr> {
self.expr_lit(sp, ast::LitBool(value))
}
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]);
}
-
-
}
parse::AlignUnknown => align("Unknown"),
};
let align = self.ecx.expr_path(align);
- let flags = self.ecx.expr_usize(sp, arg.format.flags);
+ let flags = self.ecx.expr_u32(sp, arg.format.flags);
let prec = self.trans_count(arg.format.precision);
let width = self.trans_count(arg.format.width);
let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, "FormatSpec"));
ecx.ident_of_std("core"),
ecx.ident_of("fmt"),
ecx.ident_of("ArgumentV1"),
- ecx.ident_of("from_uint")], vec![arg])
+ ecx.ident_of("from_usize")], vec![arg])
}
};
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]); }
}
let tok = if let TtToken(_, ref tok) = *token { tok } else { unreachable!() };
// If T' is in the set FOLLOW(NT), continue. Else, reject.
match (&next_token, is_in_follow(cx, &next_token, frag_spec.as_str())) {
+ (_, Err(msg)) => {
+ cx.span_err(sp, &msg);
+ continue
+ }
(&Eof, _) => return Some((sp, tok.clone())),
(_, Ok(true)) => continue,
(next, Ok(false)) => {
token_to_string(next)));
continue
},
- (_, Err(msg)) => {
- cx.span_err(sp, &msg);
- continue
- }
}
},
TtSequence(sp, ref seq) => {
("no_link", Normal),
("derive", Normal),
("should_fail", Normal),
+ ("should_panic", Normal),
("ignore", Normal),
("no_implicit_prelude", Normal),
("reexport_test_harness_main", Normal),
("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"));
+S 2015-02-25 880fb89
+ freebsd-x86_64 f4cbe4227739de986444211f8ee8d74745ab8f7f
+ linux-i386 3278ebbce8cb269acc0614dac5ddac07eab6a99c
+ linux-x86_64 72287d0d88de3e5a53bae78ac0d958e1a7637d73
+ macos-i386 33b366b5287427a340a0aa6ed886d5ff4edf6a76
+ macos-x86_64 914bf9baa32081a9d5633f1d06f4d382cd71504e
+ winnt-i386 d58b415b9d8629cb6c4952f1f6611a526a38323f
+ winnt-x86_64 2cb1dcc563d2ac6deada054de15748f5dd599c7e
+
S 2015-02-19 522d09d
freebsd-x86_64 7ea14ef85a25bca70a310a2cd660b356cf61abc7
linux-i386 26e3caa1ce1c482b9941a6bdc64b3e65d036c200
pub name : String,
}
- impl fmt::String for cat {
+ impl fmt::Display for cat {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name)
}
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0")]
-pub struct DeprecatedStruct { pub i: int }
+pub struct DeprecatedStruct {
+ #[stable(feature = "test_feature", since = "1.0.0")] pub i: int
+}
#[unstable(feature = "test_feature")]
#[deprecated(since = "1.0.0")]
-pub struct DeprecatedUnstableStruct { pub i: int }
+pub struct DeprecatedUnstableStruct {
+ #[stable(feature = "test_feature", since = "1.0.0")] pub i: int
+}
#[unstable(feature = "test_feature")]
-pub struct UnstableStruct { pub i: int }
+pub struct UnstableStruct {
+ #[stable(feature = "test_feature", since = "1.0.0")] pub i: int
+}
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct StableStruct { pub i: int }
+pub struct StableStruct {
+ #[stable(feature = "test_feature", since = "1.0.0")] pub i: int
+}
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0")]
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0")]
-pub struct DeprecatedTupleStruct(pub int);
+pub struct DeprecatedTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int);
#[unstable(feature = "test_feature")]
#[deprecated(since = "1.0.0")]
-pub struct DeprecatedUnstableTupleStruct(pub int);
+pub struct DeprecatedUnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int);
#[unstable(feature = "test_feature")]
-pub struct UnstableTupleStruct(pub int);
+pub struct UnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int);
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct StableTupleStruct(pub int);
+pub struct StableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int);
#[macro_export]
macro_rules! macro_test {
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(staged_api)]
+#![staged_api]
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Stable {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub inherit: u8, // it's a lie (stable doesn't inherit)
+ #[unstable(feature = "test_feature")]
+ pub override1: u8,
+ #[deprecated(since = "1.0.0")]
+ #[unstable(feature = "test_feature")]
+ pub override2: u8,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Stable2(#[stable(feature = "rust1", since = "1.0.0")] pub u8,
+ #[unstable(feature = "test_feature")] pub u8,
+ #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] pub u8);
+
+#[unstable(feature = "test_feature")]
+pub struct Unstable {
+ pub inherit: u8,
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub override1: u8,
+ #[deprecated(since = "1.0.0")]
+ #[unstable(feature = "test_feature")]
+ pub override2: u8,
+}
+
+#[unstable(feature = "test_feature")]
+pub struct Unstable2(pub u8,
+ #[stable(feature = "rust1", since = "1.0.0")] pub u8,
+ #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] pub u8);
+
+#[unstable(feature = "test_feature")]
+#[deprecated(feature = "rust1", since = "1.0.0")]
+pub struct Deprecated {
+ pub inherit: u8,
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub override1: u8,
+ #[unstable(feature = "test_feature")]
+ pub override2: u8,
+}
+
+#[unstable(feature = "test_feature")]
+#[deprecated(feature = "rust1", since = "1.0.0")]
+pub struct Deprecated2(pub u8,
+ #[stable(feature = "rust1", since = "1.0.0")] pub u8,
+ #[unstable(feature = "test_feature")] pub u8);
--- /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() {
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::fmt::Show;
+use std::fmt::Debug;
use std::default::Default;
use std::marker::MarkerTrait;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::fmt::Show;
+use std::fmt::Debug;
use std::default::Default;
// Test that two blanket impls conflict (at least without negative
extern crate go_trait;
use go_trait::{Go,GoMut};
-use std::fmt::Show;
+use std::fmt::Debug;
use std::default::Default;
struct MyThingy;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::fmt::Show;
+use std::fmt::Debug;
use std::default::Default;
// Test that a blank impl for all T conflicts with an impl for some
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::fmt::Show;
+use std::fmt::Debug;
use std::default::Default;
// Test that a blank impl for all T conflicts with an impl for some
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::fmt::Show;
+use std::fmt::Debug;
use std::default::Default;
// Test that a blank impl for all T conflicts with an impl for some
--- /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() {
let _: () = (box |_: isize| {}) as Box<FnOnce(isize)>;
- //~^ ERROR object-safe
- //~| ERROR mismatched types
+ //~^ ERROR mismatched types
//~| expected `()`
//~| found `Box<core::ops::FnOnce(isize)>`
//~| expected ()
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() {}
-
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2015 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.
-// error-pattern: reached the recursion limit during monomorphization
-// issue 2258
+//~^^^^^^^^^^ ERROR overflow
+//
+// We get an error message at the top of file (dummy span).
+// This is not helpful, but also kind of annoying to prevent,
+// so for now just live with it.
+// This test case was originally for issue #2258.
-trait to_opt {
+trait ToOpt {
fn to_option(&self) -> Option<Self>;
}
-impl to_opt for usize {
+impl ToOpt for usize {
fn to_option(&self) -> Option<usize> {
Some(*self)
}
}
-impl<T:Clone> to_opt for Option<T> {
+impl<T:Clone> ToOpt for Option<T> {
fn to_option(&self) -> Option<Option<T>> {
Some((*self).clone())
}
}
-fn function<T:to_opt + Clone>(counter: usize, t: T) {
+fn function<T:ToOpt + Clone>(counter: usize, t: T) {
if counter > 0_usize {
function(counter - 1_usize, t.to_option());
+ // FIXME(#4287) Error message should be here. It should be
+ // a type error to instantiate `test` at a type other than T.
}
}
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`
}
}
let _foo = &[1_usize, 2] as [usize];
//~^ ERROR cast to unsized type: `&[usize; 2]` as `[usize]`
//~^^ HELP consider using an implicit coercion to `&[usize]` instead
- let _bar = box 1_usize as std::fmt::Show;
- //~^ ERROR cast to unsized type: `Box<usize>` as `core::fmt::Show`
- //~^^ HELP did you mean `Box<core::fmt::Show>`?
- let _baz = 1_usize as std::fmt::Show;
- //~^ ERROR cast to unsized type: `usize` as `core::fmt::Show`
+ let _bar = box 1_usize as std::fmt::Debug;
+ //~^ ERROR cast to unsized type: `Box<usize>` as `core::fmt::Debug`
+ //~^^ HELP did you mean `Box<core::fmt::Debug>`?
+ let _baz = 1_usize as std::fmt::Debug;
+ //~^ ERROR cast to unsized type: `usize` as `core::fmt::Debug`
//~^^ HELP consider using a box or reference as appropriate
let _quux = [1_usize, 2] as [usize];
//~^ ERROR cast to unsized type: `[usize; 2]` as `[usize]`
fn foo<T>(&self, _: &T) {}
}
-#[inline(never)] fn foo(b: &Bar) { b.foo(&0_usize) }
+#[inline(never)]
+fn foo(b: &Bar) {
+ b.foo(&0usize)
+ //~^ ERROR the trait `Foo` is not implemented for the type `Bar`
+}
fn main() {
let mut thing = Thing;
}
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() {
#![doc="More garbage"]
type Typedef = String;
-pub type PubTypedef = String; //~ ERROR: missing documentation
+pub type PubTypedef = String; //~ ERROR: missing documentation for a type alias
struct Foo {
a: isize,
b: isize,
}
-pub struct PubFoo { //~ ERROR: missing documentation
- pub a: isize, //~ ERROR: missing documentation
+pub struct PubFoo { //~ ERROR: missing documentation for a struct
+ pub a: isize, //~ ERROR: missing documentation for a struct field
b: isize,
}
}
mod module_no_dox {}
-pub mod pub_module_no_dox {} //~ ERROR: missing documentation
+pub mod pub_module_no_dox {} //~ ERROR: missing documentation for a module
/// dox
pub fn foo() {}
-pub fn foo2() {} //~ ERROR: missing documentation
+pub fn foo2() {} //~ ERROR: missing documentation for a function
fn foo3() {}
#[allow(missing_docs)] pub fn foo4() {}
fn foo_with_impl(&self) {}
}
-pub trait C { //~ ERROR: missing documentation
- fn foo(&self); //~ ERROR: missing documentation
- fn foo_with_impl(&self) {} //~ ERROR: missing documentation
+pub trait C { //~ ERROR: missing documentation for a trait
+ fn foo(&self); //~ ERROR: missing documentation for a type method
+ fn foo_with_impl(&self) {} //~ ERROR: missing documentation for a method
}
#[allow(missing_docs)]
fn dummy(&self) { }
}
+/// dox
+pub trait E {
+ type AssociatedType; //~ ERROR: missing documentation for an associated type
+ type AssociatedTypeDef = Self; //~ ERROR: missing documentation for an associated type
+
+ /// dox
+ type DocumentedType;
+ /// dox
+ type DocumentedTypeDef = Self;
+ /// dox
+ fn dummy(&self) {}
+}
+
impl Foo {
pub fn foo() {}
fn bar() {}
}
impl PubFoo {
- pub fn foo() {} //~ ERROR: missing documentation
+ pub fn foo() {} //~ ERROR: missing documentation for a method
/// dox
pub fn foo1() {}
fn foo2() {}
BarB
}
-pub enum PubBaz { //~ ERROR: missing documentation
- PubBazA { //~ ERROR: missing documentation
- a: isize, //~ ERROR: missing documentation
+pub enum PubBaz { //~ ERROR: missing documentation for an enum
+ PubBazA { //~ ERROR: missing documentation for a variant
+ a: isize, //~ ERROR: missing documentation for a struct field
},
}
mod internal_impl {
/// dox
pub fn documented() {}
- pub fn undocumented1() {} //~ ERROR: missing documentation
- pub fn undocumented2() {} //~ ERROR: missing documentation
+ pub fn undocumented1() {} //~ ERROR: missing documentation for a function
+ pub fn undocumented2() {} //~ ERROR: missing documentation for a function
fn undocumented3() {}
/// dox
pub mod globbed {
/// dox
pub fn also_documented() {}
- pub fn also_undocumented1() {} //~ ERROR: missing documentation
+ pub fn also_undocumented1() {} //~ ERROR: missing documentation for a function
fn also_undocumented2() {}
}
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:lint_stability_fields.rs
+#![deny(deprecated)]
+#![allow(dead_code)]
+#![feature(staged_api)]
+#![staged_api]
+
+mod cross_crate {
+ extern crate lint_stability_fields;
+
+ use self::lint_stability_fields::*;
+
+ pub fn foo() {
+ let x = Stable {
+ inherit: 1,
+ override1: 2, //~ WARN use of unstable
+ override2: 3,
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+ };
+
+ let _ = x.inherit;
+ let _ = x.override1; //~ WARN use of unstable
+ let _ = x.override2;
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+
+ let Stable {
+ inherit: _,
+ override1: _, //~ WARN use of unstable
+ override2: _
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+ } = x;
+ // all fine
+ let Stable { .. } = x;
+
+ let x = Stable2(1, 2, 3);
+
+ let _ = x.0;
+ let _ = x.1; //~ WARN use of unstable
+ let _ = x.2;
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+
+ let Stable2(_,
+ _, //~ WARN use of unstable
+ _)
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+ = x;
+ // all fine
+ let Stable2(..) = x;
+
+
+ let x = Unstable { //~ WARN use of unstable
+ inherit: 1, //~ WARN use of unstable
+ override1: 2,
+ override2: 3,
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+ };
+
+ let _ = x.inherit; //~ WARN use of unstable
+ let _ = x.override1;
+ let _ = x.override2;
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+
+ let Unstable { //~ WARN use of unstable
+ inherit: _, //~ WARN use of unstable
+ override1: _,
+ override2: _
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+ } = x;
+
+ let Unstable //~ WARN use of unstable
+ // the patterns are all fine:
+ { .. } = x;
+
+
+ let x = Unstable2(1, 2, 3); //~ WARN use of unstable
+
+ let _ = x.0; //~ WARN use of unstable
+ let _ = x.1;
+ let _ = x.2;
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+
+ let Unstable2 //~ WARN use of unstable
+ (_, //~ WARN use of unstable
+ _,
+ _)
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+ = x;
+ let Unstable2 //~ WARN use of unstable
+ // the patterns are all fine:
+ (..) = x;
+
+
+ let x = Deprecated {
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+ inherit: 1,
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+ override1: 2,
+ override2: 3, //~ WARN use of unstable
+ };
+
+ let _ = x.inherit;
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+ let _ = x.override1;
+ let _ = x.override2; //~ WARN use of unstable
+
+ let Deprecated {
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+ inherit: _,
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+ override1: _,
+ override2: _ //~ WARN use of unstable
+ } = x;
+
+ let Deprecated
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+ // the patterns are all fine:
+ { .. } = x;
+
+ let x = Deprecated2(1, 2, 3);
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+
+ let _ = x.0;
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+ let _ = x.1;
+ let _ = x.2; //~ WARN use of unstable
+
+ let Deprecated2
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+ (_,
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+ _,
+ _) //~ WARN use of unstable
+ = x;
+ let Deprecated2
+ //~^ ERROR use of deprecated item
+ //~^^ WARN use of unstable
+ // the patterns are all fine:
+ (..) = x;
+ }
+}
+
+mod this_crate {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ struct Stable {
+ inherit: u8,
+ #[unstable(feature = "test_feature")]
+ override1: u8,
+ #[deprecated(since = "1.0.0")]
+ #[unstable(feature = "test_feature")]
+ override2: u8,
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ struct Stable2(u8,
+ #[stable(feature = "rust1", since = "1.0.0")] u8,
+ #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] u8);
+
+ #[unstable(feature = "test_feature")]
+ struct Unstable {
+ inherit: u8,
+ #[stable(feature = "rust1", since = "1.0.0")]
+ override1: u8,
+ #[deprecated(since = "1.0.0")]
+ #[unstable(feature = "test_feature")]
+ override2: u8,
+ }
+
+ #[unstable(feature = "test_feature")]
+ struct Unstable2(u8,
+ #[stable(feature = "rust1", since = "1.0.0")] u8,
+ #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] u8);
+
+ #[unstable(feature = "test_feature")]
+ #[deprecated(feature = "rust1", since = "1.0.0")]
+ struct Deprecated {
+ inherit: u8,
+ #[stable(feature = "rust1", since = "1.0.0")]
+ override1: u8,
+ #[unstable(feature = "test_feature")]
+ override2: u8,
+ }
+
+ #[unstable(feature = "test_feature")]
+ #[deprecated(feature = "rust1", since = "1.0.0")]
+ struct Deprecated2(u8,
+ #[stable(feature = "rust1", since = "1.0.0")] u8,
+ #[unstable(feature = "test_feature")] u8);
+
+ pub fn foo() {
+ let x = Stable {
+ inherit: 1,
+ override1: 2,
+ override2: 3,
+ //~^ ERROR use of deprecated item
+ };
+
+ let _ = x.inherit;
+ let _ = x.override1;
+ let _ = x.override2;
+ //~^ ERROR use of deprecated item
+
+ let Stable {
+ inherit: _,
+ override1: _,
+ override2: _
+ //~^ ERROR use of deprecated item
+ } = x;
+ // all fine
+ let Stable { .. } = x;
+
+ let x = Stable2(1, 2, 3);
+
+ let _ = x.0;
+ let _ = x.1;
+ let _ = x.2;
+ //~^ ERROR use of deprecated item
+
+ let Stable2(_,
+ _,
+ _)
+ //~^ ERROR use of deprecated item
+ = x;
+ // all fine
+ let Stable2(..) = x;
+
+
+ let x = Unstable {
+ inherit: 1,
+ override1: 2,
+ override2: 3,
+ //~^ ERROR use of deprecated item
+ };
+
+ let _ = x.inherit;
+ let _ = x.override1;
+ let _ = x.override2;
+ //~^ ERROR use of deprecated item
+
+ let Unstable {
+ inherit: _,
+ override1: _,
+ override2: _
+ //~^ ERROR use of deprecated item
+ } = x;
+
+ let Unstable
+ // the patterns are all fine:
+ { .. } = x;
+
+
+ let x = Unstable2(1, 2, 3);
+
+ let _ = x.0;
+ let _ = x.1;
+ let _ = x.2;
+ //~^ ERROR use of deprecated item
+
+ let Unstable2
+ (_,
+ _,
+ _)
+ //~^ ERROR use of deprecated item
+ = x;
+ let Unstable2
+ // the patterns are all fine:
+ (..) = x;
+
+
+ let x = Deprecated {
+ //~^ ERROR use of deprecated item
+ inherit: 1,
+ //~^ ERROR use of deprecated item
+ override1: 2,
+ override2: 3,
+ };
+
+ let _ = x.inherit;
+ //~^ ERROR use of deprecated item
+ let _ = x.override1;
+ let _ = x.override2;
+
+ let Deprecated {
+ //~^ ERROR use of deprecated item
+ inherit: _,
+ //~^ ERROR use of deprecated item
+ override1: _,
+ override2: _
+ } = x;
+
+ let Deprecated
+ //~^ ERROR use of deprecated item
+ // the patterns are all fine:
+ { .. } = x;
+
+ let x = Deprecated2(1, 2, 3);
+ //~^ ERROR use of deprecated item
+
+ let _ = x.0;
+ //~^ ERROR use of deprecated item
+ let _ = x.1;
+ let _ = x.2;
+
+ let Deprecated2
+ //~^ ERROR use of deprecated item
+ (_,
+ //~^ ERROR use of deprecated item
+ _,
+ _)
+ = x;
+ let Deprecated2
+ //~^ ERROR use of deprecated item
+ // the patterns are all fine:
+ (..) = x;
+ }
+}
+
+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();
}
#[unstable(feature = "test_feature")]
#[deprecated(since = "1.0.0")]
- pub struct DeprecatedStruct { i: isize }
+ pub struct DeprecatedStruct {
+ #[stable(feature = "test_feature", since = "1.0.0")] i: isize
+ }
#[unstable(feature = "test_feature")]
- pub struct UnstableStruct { i: isize }
+ pub struct UnstableStruct {
+ #[stable(feature = "test_feature", since = "1.0.0")] i: isize
+ }
#[stable(feature = "rust1", since = "1.0.0")]
- pub struct StableStruct { i: isize }
+ pub struct StableStruct {
+ #[stable(feature = "test_feature", since = "1.0.0")] i: isize
+ }
#[unstable(feature = "test_feature")]
#[deprecated(since = "1.0.0")]
// 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() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(box_syntax)]
+
+pub fn main() {
+ let x = box 1;
+
+ let v = (1, 2);
+
+ match v {
+ (1, _) if take(x) => (),
+ (_, 2) if take(x) => (), //~ ERROR use of moved value: `x`
+ _ => (),
+ }
+}
+
+fn take<T>(_: T) -> bool { false }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(box_syntax)]
+
+pub fn main() {
+ let x = box 1;
+
+ let v = (1, 2);
+
+ match v {
+ (1, _) |
+ (_, 2) if take(x) => (), //~ ERROR use of moved value: `x`
+ _ => (),
+ }
+}
+
+fn take<T>(_: T) -> bool { false }
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
--- /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 while a trait with by-value self is object-safe, we
+// can't actually invoke it from an object (yet...?).
+
+#![feature(rustc_attrs)]
+
+trait Bar {
+ fn bar(self);
+}
+
+trait Baz {
+ fn baz(self: Self);
+}
+
+fn use_bar(t: Box<Bar>) {
+ t.bar() //~ ERROR cannot move a value of type Bar
+}
+
+fn main() { }
+
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Check that we correctly prevent users from making trait objects
-// from traits with a `fn(self)` method.
+// Check that a trait with by-value self is considered object-safe.
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
trait Bar {
fn bar(self);
fn baz(self: Self);
}
+trait Quux {
+ // Legal because of the where clause:
+ fn baz(self: Self) where Self : Sized;
+}
+
fn make_bar<T:Bar>(t: &T) -> &Bar {
- t
- //~^ ERROR `Bar` is not object-safe
- //~| NOTE method `bar` has a receiver type of `Self`
+ t // legal
}
fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
- t as &Bar
- //~^ ERROR `Bar` is not object-safe
- //~| NOTE method `bar` has a receiver type of `Self`
+ t as &Bar // legal
}
fn make_baz<T:Baz>(t: &T) -> &Baz {
- t
- //~^ ERROR `Baz` is not object-safe
- //~| NOTE method `baz` has a receiver type of `Self`
+ t // legal
}
fn make_baz_explicit<T:Baz>(t: &T) -> &Baz {
- t as &Baz
- //~^ ERROR `Baz` is not object-safe
- //~| NOTE method `baz` has a receiver type of `Self`
+ t as &Baz // legal
+}
+
+fn make_quux<T:Quux>(t: &T) -> &Quux {
+ t
+}
+
+fn make_quux_explicit<T:Quux>(t: &T) -> &Quux {
+ t as &Quux
}
-fn main() {
+#[rustc_error]
+fn main() { //~ ERROR compilation successful
}
// except according to those terms.
// Check that we correctly prevent users from making trait objects
-// from traits with generic methods.
+// from traits with generic methods, unless `where Self : Sized` is
+// present.
trait Bar {
fn bar<T>(&self, t: T);
}
+trait Quux {
+ fn bar<T>(&self, t: T)
+ where Self : Sized;
+}
+
fn make_bar<T:Bar>(t: &T) -> &Bar {
t
//~^ ERROR `Bar` is not object-safe
//~| NOTE method `bar` has generic type parameters
}
+fn make_quux<T:Quux>(t: &T) -> &Quux {
+ t
+}
+
+fn make_quux_explicit<T:Quux>(t: &T) -> &Quux {
+ t as &Quux
+}
+
fn main() {
}
// except according to those terms.
// Check that we correctly prevent users from making trait objects
-// form traits that make use of `Self` in an argument or return position.
+// form traits that make use of `Self` in an argument or return
+// position, unless `where Self : Sized` is present..
trait Bar {
fn bar(&self, x: &Self);
fn bar(&self) -> Self;
}
+trait Quux {
+ fn get(&self, s: &Self) -> Self where Self : Sized;
+}
+
fn make_bar<T:Bar>(t: &T) -> &Bar {
t
//~^ ERROR `Bar` is not object-safe
//~| NOTE method `bar` references the `Self` type in its arguments or return type
}
+fn make_quux<T:Quux>(t: &T) -> &Quux {
+ t
+}
+
+fn make_quux_explicit<T:Quux>(t: &T) -> &Quux {
+ t as &Quux
+}
+
fn main() {
}
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
//~^^^^^^^^^^ ERROR overflow
//
-// We also get a second error message at the top of file (dummy
-// span). This is not helpful, but also kind of annoying to prevent,
-// so for now just live with it, since we also get a second message
-// that is more helpful.
+// We get an error message at the top of file (dummy span).
+// This is not helpful, but also kind of annoying to prevent,
+// so for now just live with it.
enum Nil {NilValue}
struct Cons<T> {head:isize, tail:T}
}
fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize {
match n { 0 => {first.dot(second)}
- //~^ ERROR: reached the recursion limit during monomorphization
- // Error message should be here. It should be a type error
- // to instantiate `test` at a type other than T. (See #4287)
+ // FIXME(#4287) Error message should be here. It should be
+ // a type error to instantiate `test` at a type other than T.
_ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
}
}
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) { }
}
10.dup::<i32>(); //~ ERROR does not take type parameters
10.blah::<i32, i32>(); //~ ERROR incorrect number of type parameters
(box 10 as Box<bar>).dup(); //~ ERROR cannot convert to a trait object
+ //~^ ERROR the trait `bar` is not implemented for the type `bar`
}
--- /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.
+
+fn foo1<T:Copy<U>, U>(x: T) {}
+//~^ ERROR: wrong number of type arguments: expected 0, found 1
+
+trait Trait: Copy<Send> {}
+//~^ ERROR: wrong number of type arguments: expected 0, found 1
+
+struct MyStruct1<T: Copy<T>>;
+//~^ ERROR wrong number of type arguments: expected 0, found 1
+
+struct MyStruct2<'a, T: Copy<'a>>;
+//~^ ERROR: wrong number of lifetime parameters: expected 0, found 1
+
+fn foo2<'a, T:Copy<'a, U>, U>(x: T) {}
+//~^ ERROR: wrong number of type arguments: expected 0, found 1
+//~^^ ERROR: wrong number of lifetime parameters: expected 0, found 1
+
+fn main() {
+}
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() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Issue #21370
+
+macro_rules! test {
+ ($wrong:t_ty) => () //~ ERROR invalid fragment specifier `t_ty`
+}
+
+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.
+
+macro_rules! test {
+ ($e:expr +) => () //~ ERROR not allowed for `expr` fragments
+}
+
+fn main() { }
n: i64
}
-impl fmt::String for Number {
+impl fmt::Display for Number {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.n)
}
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.
+
+fn main() {
+ let caller<F> = |f: F| //~ ERROR unexpected token: `<`
+ where F: Fn() -> i32
+ {
+ let x = f();
+ println!("Y {}",x);
+ return x;
+ };
+
+ caller(bar_handler);
+}
+
+fn bar_handler() -> i32 {
+ 5
+}
--- /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<B> {
+ buffer: B
+}
+
+fn bar() {
+ let Foo<Vec<u8>> //~ ERROR unexpected token: `<`
+}
+
+fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::fmt::Show;
+use std::fmt::Debug;
fn main() {
- let x: Box<Show+> = box 3 as Box<Show+>;
+ let x: Box<Debug+> = box 3 as Box<Debug+>;
//~^ ERROR at least one type parameter bound must be specified
//~^^ ERROR at least one type parameter bound must be specified
}
-
N3 -> N4;
N4 -> N5;
N5 -> N6;
- N6 -> N8;
- N8 -> N9;
+ N6 -> N9;
N9 -> N10;
N10 -> N11;
N11 -> N12;
- N12 -> N13;
+ N12 -> N8;
+ N8 -> N13;
N13 -> N14;
N14 -> N15;
N15 -> N7;
N6 -> N7;
N7 -> N8;
N8 -> N9;
- N9 -> N11;
- N11 -> N12;
- N12 -> N13;
+ N9 -> N12;
+ N12 -> N11;
+ N11 -> N13;
N13 -> N14;
N14 -> N15;
N15 -> N10;
- N11 -> N16;
- N16 -> N17;
+ N9 -> N17;
N17 -> N18;
- N18 -> N19;
+ N18 -> N16;
+ N16 -> N19;
N19 -> N20;
N20 -> N21;
N21 -> N22;
--- /dev/null
+-include ../tools.mk
+
+all: lib.rs ext.rs
+ $(HOST_RPATH_ENV) $(RUSTC) ext.rs
+ $(HOST_RPATH_ENV) $(RUSTDOC) -L $(TMPDIR) -w html -o $(TMPDIR)/doc lib.rs
+ $(HTMLDOCCK) $(TMPDIR)/doc lib.rs
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type="lib"]
+
+pub trait Trait {
+ fn provided(&self) {}
+}
+
+pub struct Struct;
+
+impl Trait for Struct {
+ fn provided(&self) {}
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate ext;
+
+// @count lib/struct.Struct.html '//*[@id="method.provided"]' 1
+pub use ext::Struct;
--- /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]);
}
}
}
-impl fmt::String for cat {
+impl fmt::Display for cat {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name)
}
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]);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::fmt::Show;
+use std::fmt::Debug;
use std::default::Default;
// Test that an impl for homogeneous pairs does not conflict with a
+++ /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() {}
--- /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 Issue #22536: If a type implements Copy, then
+// moving it must not zero the original memory.
+
+trait Resources {
+ type Buffer: Copy;
+ fn foo(&self) {}
+}
+
+struct BufferHandle<R: Resources> {
+ raw: <R as Resources>::Buffer,
+}
+impl<R: Resources> Copy for BufferHandle<R> {}
+
+enum Res {}
+impl Resources for Res {
+ type Buffer = u32;
+}
+impl Copy for Res { }
+
+fn main() {
+ let b: BufferHandle<Res> = BufferHandle { raw: 1 };
+ let c = b;
+ assert_eq!(c.raw, b.raw)
+}
--- /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::{fs, net};
+
+fn assert_both<T: Send + Sync>() {}
+
+fn main() {
+ assert_both::<fs::File>();
+ assert_both::<fs::Metadata>();
+ assert_both::<fs::ReadDir>();
+ assert_both::<fs::DirEntry>();
+ assert_both::<fs::WalkDir>();
+ assert_both::<fs::OpenOptions>();
+ assert_both::<fs::Permissions>();
+
+ assert_both::<net::TcpStream>();
+ assert_both::<net::TcpListener>();
+ assert_both::<net::UdpSocket>();
+ assert_both::<net::SocketAddr>();
+ assert_both::<net::IpAddr>();
+}
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}"));
}
// Allows AsciiArt to be converted to a string using the libcore ToString trait.
// Note that the %s fmt! specifier will not call this automatically.
-impl fmt::String for AsciiArt {
+impl fmt::Display for AsciiArt {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Convert each line into a string.
let lines = self.lines.iter()
--- /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()]);
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(box_syntax)]
+
+fn main() {
+ let x = box 1;
+
+ let v = (1, 2);
+
+ match v {
+ (2, 1) if take(x) => (),
+ (1, 2) if take(x) => (),
+ _ => (),
+ }
+}
+
+fn take<T>(_: T) -> bool { false }
--- /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 a trait is still object-safe (and usable) if it has
+// methods with by-value self so long as they require `Self : Sized`.
+
+trait Counter {
+ fn tick(&mut self) -> u32;
+ fn get(self) -> u32 where Self : Sized;
+}
+
+struct CCounter {
+ c: u32
+}
+
+impl Counter for CCounter {
+ fn tick(&mut self) -> u32 { self.c += 1; self.c }
+ fn get(self) -> u32 where Self : Sized { self.c }
+}
+
+fn tick1<C:Counter>(mut c: C) -> u32 {
+ tick2(&mut c);
+ c.get()
+}
+
+fn tick2(c: &mut Counter) {
+ tick3(c);
+}
+
+fn tick3<C:?Sized+Counter>(c: &mut C) {
+ c.tick();
+ c.tick();
+}
+
+fn main() {
+ let mut c = CCounter { c: 0 };
+ let value = tick1(c);
+ assert_eq!(value, 2);
+}
--- /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 a trait is still object-safe (and usable) if it has
+// generic methods so long as they require `Self : Sized`.
+
+trait Counter {
+ fn tick(&mut self) -> u32;
+ fn with<F:FnOnce(u32)>(&self, f: F) where Self : Sized;
+}
+
+struct CCounter {
+ c: u32
+}
+
+impl Counter for CCounter {
+ fn tick(&mut self) -> u32 { self.c += 1; self.c }
+ fn with<F:FnOnce(u32)>(&self, f: F) { f(self.c); }
+}
+
+fn tick1<C:Counter>(c: &mut C) {
+ tick2(c);
+ c.with(|i| ());
+}
+
+fn tick2(c: &mut Counter) {
+ tick3(c);
+}
+
+fn tick3<C:?Sized+Counter>(c: &mut C) {
+ c.tick();
+ c.tick();
+}
+
+fn main() {
+ let mut c = CCounter { c: 0 };
+ tick1(&mut c);
+ assert_eq!(c.tick(), 3);
+}
--- /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 a trait is still object-safe (and usable) if it has
+// methods that return `Self` so long as they require `Self : Sized`.
+
+trait Counter {
+ fn new() -> Self where Self : Sized;
+ fn tick(&mut self) -> u32;
+}
+
+struct CCounter {
+ c: u32
+}
+
+impl Counter for CCounter {
+ fn new() -> CCounter { CCounter { c: 0 } }
+ fn tick(&mut self) -> u32 { self.c += 1; self.c }
+}
+
+fn preticked<C:Counter>() -> C {
+ let mut c: C = Counter::new();
+ tick(&mut c);
+ c
+}
+
+fn tick(c: &mut Counter) {
+ tick_generic(c);
+}
+
+fn tick_generic<C:?Sized+Counter>(c: &mut C) {
+ c.tick();
+ c.tick();
+}
+
+fn main() {
+ let mut c = preticked::<CCounter>();
+ tick(&mut c);
+ assert_eq!(c.tick(), 5);
+}
// 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>();
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(unused_mut)]
+#![feature(collections)]
+
+extern crate collections;
+
+use collections::BinaryHeap;
+use collections::{BitSet, BitVec};
+use collections::{BTreeMap, BTreeSet};
+use collections::EnumSet;
+use collections::LinkedList;
+use collections::Vec;
+use collections::VecDeque;
+use collections::VecMap;
+
+use collections::Bound::Included;
+use collections::enum_set::CLike;
+use std::mem;
+
+fn is_sync<T>(_: T) where T: Sync {}
+fn is_send<T>(_: T) where T: Send {}
+
+macro_rules! all_sync_send {
+ ($ctor:expr, $($iter:ident),+) => ({
+ $(
+ let mut x = $ctor;
+ is_sync(x.$iter());
+ let mut y = $ctor;
+ is_send(y.$iter());
+ )+
+ })
+}
+
+macro_rules! is_sync_send {
+ ($ctor:expr, $iter:ident($($param:expr),+)) => ({
+ let mut x = $ctor;
+ is_sync(x.$iter($( $param ),+));
+ let mut y = $ctor;
+ is_send(y.$iter($( $param ),+));
+ })
+}
+
+fn main() {
+ // The iterator "generator" list should exhaust what corresponding
+ // implementations have where `Sync` and `Send` semantics apply.
+ all_sync_send!(BinaryHeap::<usize>::new(), iter, drain, into_iter);
+
+ all_sync_send!(BitVec::new(), iter);
+
+ all_sync_send!(BitSet::new(), iter);
+ is_sync_send!(BitSet::new(), union(&BitSet::new()));
+ is_sync_send!(BitSet::new(), intersection(&BitSet::new()));
+ is_sync_send!(BitSet::new(), difference(&BitSet::new()));
+ is_sync_send!(BitSet::new(), symmetric_difference(&BitSet::new()));
+
+ all_sync_send!(BTreeMap::<usize, usize>::new(), iter, iter_mut, into_iter, keys, values);
+ is_sync_send!(BTreeMap::<usize, usize>::new(), range(Included(&0), Included(&9)));
+ is_sync_send!(BTreeMap::<usize, usize>::new(), range_mut(Included(&0), Included(&9)));
+
+ all_sync_send!(BTreeSet::<usize>::new(), iter, into_iter);
+ is_sync_send!(BTreeSet::<usize>::new(), range(Included(&0), Included(&9)));
+ is_sync_send!(BTreeSet::<usize>::new(), difference(&BTreeSet::<usize>::new()));
+ is_sync_send!(BTreeSet::<usize>::new(), symmetric_difference(&BTreeSet::<usize>::new()));
+ is_sync_send!(BTreeSet::<usize>::new(), intersection(&BTreeSet::<usize>::new()));
+ is_sync_send!(BTreeSet::<usize>::new(), union(&BTreeSet::<usize>::new()));
+
+ all_sync_send!(LinkedList::<usize>::new(), iter, iter_mut, into_iter);
+
+ #[derive(Copy)]
+ #[repr(usize)]
+ #[allow(dead_code)]
+ enum Foo { A, B, C }
+ impl CLike for Foo {
+ fn to_usize(&self) -> usize {
+ *self as usize
+ }
+
+ fn from_usize(v: usize) -> Foo {
+ unsafe { mem::transmute(v) }
+ }
+ }
+ all_sync_send!(EnumSet::<Foo>::new(), iter);
+
+ all_sync_send!(VecDeque::<usize>::new(), iter, iter_mut, drain, into_iter);
+
+ all_sync_send!(VecMap::<usize>::new(), iter, iter_mut, drain, into_iter, keys, values);
+
+ all_sync_send!(Vec::<usize>::new(), into_iter, drain);
+}
}
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]);
}