This adds the assume() calls back that got lost when rebasing #21886.
## Building from Source
1. Make sure you have installed the dependencies:
- * `g++` 4.7 or `clang++` 3.x
- * `python` 2.6 or later (but not 3.x)
- * GNU `make` 3.81 or later
- * `curl`
- * `git`
+
+ * `g++` 4.7 or `clang++` 3.x
+ * `python` 2.6 or later (but not 3.x)
+ * GNU `make` 3.81 or later
+ * `curl`
+ * `git`
2. Clone the [source] with `git`:
- $ git clone https://github.com/rust-lang/rust.git
- $ cd rust
+ ```sh
+ $ git clone https://github.com/rust-lang/rust.git
+ $ cd rust
+ ```
[source]: https://github.com/rust-lang/rust
3. Build and install:
- $ ./configure
- $ make && make install
+ ```sh
+ $ ./configure
+ $ make && make install
+ ```
- > ***Note:*** You may need to use `sudo make install` if you do not normally have
- > permission to modify the destination directory. The install locations can
- > be adjusted by passing a `--prefix` argument to `configure`. Various other
- > options are also supported, pass `--help` for more information on them.
+ > ***Note:*** You may need to use `sudo make install` if you do not
+ > normally have permission to modify the destination directory. The
+ > install locations can be adjusted by passing a `--prefix` argument
+ > to `configure`. Various other options are also supported – pass
+ > `--help` for more information on them.
When complete, `make install` will place several programs into
`/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
### Building on Windows
-To easily build on windows we can use [MSYS2](http://msys2.github.io/):
+[MSYS2](http://msys2.github.io/) can be used to easily build Rust on Windows:
1. Grab the latest MSYS2 installer and go through the installer.
-2. Now from the MSYS2 terminal we want to install the mingw64 toolchain and the other
- tools we need.
-```bash
-# choose one based on platform
-$ pacman -S mingw-w64-i686-toolchain
-$ pacman -S mingw-w64-x86_64-toolchain
+2. From the MSYS2 terminal, install the `mingw64` toolchain and other required
+ tools.
+
+ ```sh
+ # Choose one based on platform:
+ $ pacman -S mingw-w64-i686-toolchain
+ $ pacman -S mingw-w64-x86_64-toolchain
+
+ $ pacman -S base-devel
+ ```
-$ pacman -S base-devel
-```
+3. Run `mingw32_shell.bat` or `mingw64_shell.bat` from wherever you installed
+ MYSY2 (i.e. `C:\msys`), depending on whether you want 32-bit or 64-bit Rust.
-3. With that now start `mingw32_shell.bat` or `mingw64_shell.bat`
- from where you installed MSYS2 (i.e. `C:\msys`). Which one you
- choose depends on if you want 32 or 64 bit Rust.
-4. From there just navigate to where you have Rust's source code, configure and build it:
+4. Navigate to Rust's source code, configure and build it:
- $ ./configure
- $ make && make install
+ ```sh
+ $ ./configure
+ $ make && make install
+ ```
## Notes
[CONTRIBUTING.md]: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md
-## Getting help
+## Getting Help
The Rust community congregates in a few places:
-* [StackOverflow] - Direct questions about using the language here.
-* [users.rust-lang.org] - General discussion, broader questions.
+* [Stack Overflow] - Direct questions about using the language.
+* [users.rust-lang.org] - General discussion and broader questions.
* [/r/rust] - News and general discussion.
-[StackOverflow]: http://stackoverflow.com/questions/tagged/rust
+[Stack Overflow]: http://stackoverflow.com/questions/tagged/rust
[/r/rust]: http://reddit.com/r/rust
[users.rust-lang.org]: http://users.rust-lang.org/
Rust has an [IRC] culture and most real-time collaboration happens in a
variety of channels on Mozilla's IRC network, irc.mozilla.org. The
most popular channel is [#rust], a venue for general discussion about
-Rust, and a good place to ask for help,
+Rust, and a good place to ask for help.
[IRC]: https://en.wikipedia.org/wiki/Internet_Relay_Chat
[#rust]: irc://irc.mozilla.org/rust
logfile: config.logfile.clone(),
run_tests: true,
run_benchmarks: true,
- nocapture: false,
+ nocapture: env::var("RUST_TEST_NOCAPTURE").is_ok(),
color: test::AutoColor,
}
}
fn parse_expected(last_nonfollow_error: Option<uint>,
line_num: uint,
line: &str) -> Option<(WhichLine, ExpectedError)> {
- let start = match line.find_str("//~") { Some(i) => i, None => return None };
+ let start = match line.find("//~") { Some(i) => i, None => return None };
let (follow, adjusts) = if line.char_at(start + 3) == '|' {
(true, 0)
} else {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use std::env;
+
use common::Config;
use common;
use util;
true
});
+ for key in vec!["RUST_TEST_NOCAPTURE", "RUST_TEST_TASKS"] {
+ match env::var(key) {
+ Ok(val) =>
+ if exec_env.iter().find(|&&(ref x, _)| *x == key.to_string()).is_none() {
+ exec_env.push((key.to_string(), val))
+ },
+ Err(..) => {}
+ }
+ }
+
TestProps {
error_patterns: error_patterns,
compile_flags: compile_flags,
pub fn parse_name_value_directive(line: &str, directive: &str)
-> Option<String> {
let keycolon = format!("{}:", directive);
- match line.find_str(&keycolon) {
+ match line.find(&keycolon) {
Some(colon) => {
let value = line[(colon + keycolon.len()) .. line.len()].to_string();
debug!("{}: {}", directive, value);
let proc_res = compile_test(config, props, testfile);
if proc_res.status.success() {
- fatal_proc_rec(&format!("{} test compiled successfully!", config.mode)[],
+ fatal_proc_rec(&format!("{} test compiled successfully!", config.mode)[..],
&proc_res);
}
for line in breakpoint_lines.iter() {
script_str.push_str(&format!("break {:?}:{}\n",
testfile.filename_display(),
- *line)[]);
+ *line)[..]);
}
script_str.push_str(&cmds);
script_str.push_str("quit\n");
script_str.push_str("set print pretty off\n");
// Add the pretty printer directory to GDB's source-file search path
- script_str.push_str(&format!("directory {}\n", rust_pp_module_abs_path)[]);
+ script_str.push_str(&format!("directory {}\n", rust_pp_module_abs_path)[..]);
// Load the target executable
script_str.push_str(&format!("file {}\n",
- exe_file.as_str().unwrap().replace("\\", "\\\\"))[]);
+ exe_file.as_str().unwrap().replace("\\", "\\\\"))[..]);
// Add line breakpoints
for line in &breakpoint_lines {
script_str.push_str(&format!("break '{}':{}\n",
testfile.filename_display(),
- *line)[]);
+ *line)[..]);
}
script_str.push_str(&cmds);
.unwrap()
.to_string();
- script_str.push_str(&format!("command script import {}\n", &rust_pp_module_abs_path[..])[]);
+ script_str.push_str(&format!("command script import {}\n", &rust_pp_module_abs_path[..])[..]);
script_str.push_str("type summary add --no-value ");
script_str.push_str("--python-function lldb_rust_formatters.print_val ");
script_str.push_str("-x \".*\" --category Rust\n");
check_lines.iter().map(|s| {
s
.trim()
- .split_str("[...]")
+ .split("[...]")
.map(|x| x.to_string())
.collect()
}).collect();
None
}
} else {
- rest.find_str(frag)
+ rest.find(frag)
};
match found {
None => {
* [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
fn main() {
let mut numbers = vec![1, 2, 3];
- for i in 0..3 {
- Thread::spawn(move || {
+ let guards: Vec<_> = (0..3).map(|i| {
+ Thread::scoped(move || {
for j in 0..3 { numbers[j] += 1 }
});
- }
+ }).collect();
}
```
It gives us this error:
```text
-6:71 error: capture of moved value: `numbers`
- for j in 0..3 { numbers[j] += 1 }
- ^~~~~~~
-7:50 note: `numbers` moved into closure environment here
- spawn(move || {
- for j in 0..3 { numbers[j] += 1 }
- });
-6:79 error: cannot assign to immutable dereference (dereference is implicit, due to indexing)
- for j in 0..3 { numbers[j] += 1 }
- ^~~~~~~~~~~~~~~
+7:29: 9:10 error: cannot move out of captured outer variable in an `FnMut` closure
+7 Thread::scoped(move || {
+8 for j in 0..3 { numbers[j] += 1 }
+9 });
```
-It mentions that "numbers moved into closure environment". Because we
-declared the closure as a moving closure, and it referred to
-`numbers`, the closure will try to take ownership of the vector. But
-the closure itself is created in a loop, and hence we will actually
-create three closures, one for every iteration of the loop. This means
-that all three of those closures would try to own `numbers`, which is
-impossible -- `numbers` must have just one owner. Rust detects this
-and gives us the error: we claim that `numbers` has ownership, but our
-code tries to make three owners. This may cause a safety problem, so
-Rust disallows it.
+It mentions that "captured outer variable in an `FnMut` closure".
+Because we declared the closure as a moving closure, and it referred
+to `numbers`, the closure will try to take ownership of the
+vector. But the closure itself is created in a loop, and hence we will
+actually create three closures, one for every iteration of the
+loop. This means that all three of those closures would try to own
+`numbers`, which is impossible -- `numbers` must have just one
+owner. Rust detects this and gives us the error: we claim that
+`numbers` has ownership, but our code tries to make three owners. This
+may cause a safety problem, so Rust disallows it.
What to do here? Rust has two types that helps us: `Arc<T>` and `Mutex<T>`.
*Arc* stands for "atomically reference counted". In other words, an Arc will
fn main() {
let numbers = Arc::new(Mutex::new(vec![1, 2, 3]));
- for i in 0..3 {
+ let guards: Vec<_> = (0..3).map(|i| {
let number = numbers.clone();
- Thread::spawn(move || {
+ Thread::scoped(move || {
let mut array = number.lock().unwrap();
array[i] += 1;
println!("numbers[{}] is {}", i, array[i]);
});
- }
+ }).collect();
}
```
numbers[0] is 2
```
-Each time, we get a slightly different output, because each thread works in a
-different order. You may not get the same output as this sample, even.
+Each time, we can get a slithtly different output because the threads
+are not quaranteed to run in any set order. If you get the same order
+every time it is because each of these threads are very small and
+complete too fast for their indeterminate behavior to surface.
The important part here is that the Rust compiler was able to use ownership to
give us assurance _at compile time_ that we weren't doing something incorrect
use std::thread::Thread;
fn main() {
- let vec = vec![1, 2, 3];
-
- for i in 0..3 {
- Thread::spawn(move || {
- println!("{}", vec[i]);
+ let numbers = vec![1, 2, 3];
+
+ let guards: Vec<_> = (0..3).map(|i| {
+ Thread::scoped(move || {
+ println!("{}", numbers[i]);
});
- }
+ }).collect();
}
```
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
syntax with a floating point literal ending in a period. `2.f64` would attempt
to call a method named `f64` on `2`.
+The representation semantics of floating-point numbers are described in
+["Machine Types"](#machine-types).
+
#### Boolean literals
The two values of the boolean type are written `true` and `false`.
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`.
elements, respectively, in a parenthesized, comma-separated list.
Because tuple elements don't have a name, they can only be accessed by
-pattern-matching.
+pattern-matching or by using `N` directly as a field to access the
+`N`th element.
An example of a tuple type and its use:
let p: Pair<'static> = (10, "hello");
let (a, b) = p;
assert!(b != "world");
+assert!(p.0 == 10);
```
### Array, and Slice types
/* 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.
*module*. A crate is synonymous with a *library* or *package* in other
languages. Hence "Cargo" as the name of Rust's package management tool: you
ship your crates to others with Cargo. Crates can produce an executable or a
-shared library, depending on the project.
+library, depending on the project.
Each crate has an implicit *root module* that contains the code for that crate.
You can then define a tree of sub-modules under that root module. Modules allow
.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
}
```
-This is strictly worse than using an actual iterator. The `.iter()` method on
-vectors returns an iterator which iterates through a reference to each element
-of the vector in turn. So write this:
+This is strictly worse than using an actual iterator. You can iterate over vectors
+directly, so write this:
```rust
let nums = vec![1, 2, 3];
-for num in nums.iter() {
+for num in &nums {
println!("{}", num);
}
```
```rust
let nums = vec![1, 2, 3];
-for num in nums.iter() {
+for num in &nums {
println!("{}", *num);
}
```
-Now we're explicitly dereferencing `num`. Why does `iter()` give us references?
-Well, if it gave us the data itself, we would have to be its owner, which would
-involve making a copy of the data and giving us the copy. With references,
-we're just borrowing a reference to the data, and so it's just passing
-a reference, without needing to do the copy.
+Now we're explicitly dereferencing `num`. Why does `&nums` give us
+references? Firstly, because we explicitly asked it to with
+`&`. Secondly, if it gave us the data itself, we would have to be its
+owner, which would involve making a copy of the data and giving us the
+copy. With references, we're just borrowing a reference to the data,
+and so it's just passing a reference, without needing to do the move.
So, now that we've established that ranges are often not what you want, let's
talk about what you do want instead.
Now, `collect()` will require that the range gives it some numbers, and so
it will do the work of generating the sequence.
-Ranges are one of two basic iterators that you'll see. The other is `iter()`,
-which you've used before. `iter()` can turn a vector into a simple iterator
-that gives you each element in turn:
+Ranges are one of two basic iterators that you'll see. The other is `iter()`.
+`iter()` can turn a vector into a simple iterator that gives you each element
+in turn:
```rust
let nums = [1, 2, 3];
};
}
# 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
# String
-A `String` is a heap-allocated string. This string is growable, and is also
-guaranteed to be UTF-8.
+A `String` is a heap-allocated string. This string is growable, and is
+also guaranteed to be UTF-8. `String`s are commonly created by
+converting from a string slice using the `to_string` method.
```
let mut s = "Hello".to_string();
println!("{}", s);
```
-You can coerce a `String` into a `&str` by dereferencing it:
+A reference to a `String` will automatically coerce to a string slice:
```
fn takes_slice(slice: &str) {
fn main() {
let s = "Hello".to_string();
- takes_slice(&*s);
+ takes_slice(&s);
}
```
## 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
}
```
-This has some upsides: static dispatching of any method calls, allowing for
-inlining and hence usually higher performance. It also has some downsides:
-causing code bloat due to many copies of the same function existing in the
-binary, one for each type.
+This has a great upside: static dispatch allows function calls to be
+inlined because the callee is known at compile time, and inlining is
+the key to good optimization. Static dispatch is fast, but it comes at
+a tradeoff: 'code bloat', due to many copies of the same function
+existing in the binary, one for each type.
Furthermore, compilers aren’t perfect and may “optimize” code to become slower.
For example, functions inlined too eagerly will bloat the instruction cache
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
binding is a reference to this statically allocated string. String slices
have a fixed size, and cannot be mutated.
-A `String`, on the other hand, is an in-memory string. This string is
-growable, and is also guaranteed to be UTF-8.
+A `String`, on the other hand, is a heap-allocated string. This string
+is growable, and is also guaranteed to be UTF-8. `String`s are
+commonly created by converting from a string slice using the
+`to_string` method.
```{rust}
let mut s = "Hello".to_string(); // mut s: String
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,
/// After this function call, pointer is owned by resulting box.
/// In particular, it means that `Box` destructor calls destructor
/// of `T` and releases memory. Since the way `Box` allocates and
- /// releases memory is unspecified, so the only valid pointer to
- /// pass to this function is the one taken from another `Box` with
- /// `box::into_raw` function.
+ /// releases memory is unspecified, the only valid pointer to pass
+ /// to this function is the one taken from another `Box` with
+ /// `boxed::into_raw` function.
///
/// Function is unsafe, because improper use of this function may
/// lead to memory problems like double-free, for example if the
/// function is called twice on the same raw pointer.
#[unstable(feature = "alloc",
reason = "may be renamed or moved out of Box scope")]
+ #[inline]
pub unsafe fn from_raw(raw: *mut T) -> Self {
mem::transmute(raw)
}
/// ```
#[unstable(feature = "alloc",
reason = "may be renamed")]
+#[inline]
pub unsafe fn into_raw<T : ?Sized>(b: Box<T>) -> *mut T {
mem::transmute(b)
}
if self.is::<T>() {
unsafe {
// Get the raw representation of the trait object
+ let raw = into_raw(self);
let to: TraitObject =
- mem::transmute::<Box<Any>, TraitObject>(self);
+ mem::transmute::<*mut Any, TraitObject>(raw);
// Extract the data pointer
- Ok(mem::transmute(to.data))
+ Ok(Box::from_raw(to.data as *mut T))
}
} else {
Err(self)
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))]
//! ```
#![stable(feature = "rust1", since = "1.0.0")]
-
+#[cfg(not(test))]
+use boxed;
+#[cfg(test)]
+use std::boxed;
use core::cell::Cell;
use core::clone::Clone;
use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
use core::fmt;
use core::hash::{Hasher, Hash};
use core::marker;
-use core::mem::{transmute, min_align_of, size_of, forget};
+use core::mem::{min_align_of, size_of, forget};
use core::nonzero::NonZero;
use core::ops::{Deref, Drop};
use core::option::Option;
// there is an implicit weak pointer owned by all the strong pointers, which
// ensures that the weak destructor never frees the allocation while the strong
// destructor is running, even if the weak pointer is stored inside the strong one.
- _ptr: NonZero::new(transmute(box RcBox {
+ _ptr: NonZero::new(boxed::into_raw(box RcBox {
value: value,
strong: Cell::new(1),
weak: Cell::new(1)
/// 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();
result
}
-// Take two BitV's, and return iterators of their words, where the shorter one
+// Take two BitVec's, and return iterators of their words, where the shorter one
// has been padded with 0's
fn match_words <'a,'b>(a: &'a BitVec, b: &'b BitVec) -> (MatchWords<'a>, MatchWords<'b>) {
let a_len = a.storage.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 (left, right) = values.split_at_mut(2);
{
let left: &[_] = left;
- assert!(left[..left.len()] == [1, 2][]);
+ assert!(left[..left.len()] == [1, 2]);
}
for p in left {
*p += 1;
{
let right: &[_] = right;
- assert!(right[..right.len()] == [3, 4, 5][]);
+ assert!(right[..right.len()] == [3, 4, 5]);
}
for p in right {
*p += 2;
//
// ignore-lexer-test FIXME #15679
-//! Unicode string manipulation (`str` type)
+//! Unicode string manipulation (the `str` type).
//!
-//! # Basic Usage
+//! Rust's `str` type is one of the core primitive types of the language. `&str` is the borrowed
+//! string type. This type of string can only be created from other strings, unless it is a static
+//! string (see below). As the word "borrowed" implies, this type of string is owned elsewhere, and
+//! this string cannot be moved out of.
//!
-//! Rust's string type is one of the core primitive types of the language. While
-//! represented by the name `str`, the name `str` is not actually a valid type in
-//! Rust. Each string must also be decorated with a pointer. `String` is used
-//! for an owned string, so there is only one commonly-used `str` type in Rust:
-//! `&str`.
+//! # Examples
//!
-//! `&str` is the borrowed string type. This type of string can only be created
-//! from other strings, unless it is a static string (see below). As the word
-//! "borrowed" implies, this type of string is owned elsewhere, and this string
-//! cannot be moved out of.
+//! Here's some code that uses a `&str`:
//!
-//! As an example, here's some code that uses a string.
-//!
-//! ```rust
-//! fn main() {
-//! let borrowed_string = "This string is borrowed with the 'static lifetime";
-//! }
//! ```
+//! let s = "Hello, world.";
+//! ```
+//!
+//! This `&str` is a `&'static str`, which is the type of string literals. They're `'static`
+//! because literals are available for the entire lifetime of the program.
//!
-//! From the example above, you can guess that Rust's string literals have the
-//! `'static` lifetime. This is akin to C's concept of a static string.
-//! More precisely, string literals are immutable views with a 'static lifetime
-//! (otherwise known as the lifetime of the entire program), and thus have the
-//! type `&'static str`.
+//! You can get a non-`'static` `&str` by taking a slice of a `String`:
+//!
+//! ```
+//! # let some_string = "Hello, world.".to_string();
+//! let s = &some_string;
+//! ```
//!
//! # Representation
//!
-//! Rust's string type, `str`, is a sequence of Unicode scalar values encoded as a
-//! stream of UTF-8 bytes. All [strings](../../reference.html#literals) are
-//! guaranteed to be validly encoded UTF-8 sequences. Additionally, strings are
-//! not null-terminated and can thus contain null bytes.
+//! Rust's string type, `str`, is a sequence of Unicode scalar values encoded as a stream of UTF-8
+//! bytes. All [strings](../../reference.html#literals) are guaranteed to be validly encoded UTF-8
+//! sequences. Additionally, strings are not null-terminated and can thus contain null bytes.
//!
-//! The actual representation of strings have direct mappings to slices: `&str`
-//! is the same as `&[u8]`.
+//! The actual representation of `str`s have direct mappings to slices: `&str` is the same as
+//! `&[u8]`.
#![doc(primitive = "str")]
#![stable(feature = "rust1", since = "1.0.0")]
pub use core::str::{from_utf8, CharEq, Chars, CharIndices, Bytes};
pub use core::str::{from_utf8_unchecked, from_c_str, ParseBoolError};
pub use unicode::str::{Words, Graphemes, GraphemeIndices};
+pub use core::str::Pattern;
+pub use core::str::{Searcher, ReverseSearcher, DoubleEndedSearcher, SearchStep};
/*
Section: Creating a string
Compatible
}
-/// External iterator for a string's decomposition's characters.
-/// Use with the `std::iter` module.
+/// External iterator for a string decomposition's characters.
+///
+/// For use with the `std::iter` module.
#[derive(Clone)]
#[unstable(feature = "collections")]
pub struct Decompositions<'a> {
Finished
}
-/// External iterator for a string's recomposition's characters.
-/// Use with the `std::iter` module.
+/// External iterator for a string recomposition's characters.
+///
+/// For use with the `std::iter` module.
#[derive(Clone)]
#[unstable(feature = "collections")]
pub struct Recompositions<'a> {
}
/// External iterator for a string's UTF16 codeunits.
-/// Use with the `std::iter` module.
+///
+/// For use with the `std::iter` module.
#[derive(Clone)]
#[unstable(feature = "collections")]
pub struct Utf16Units<'a> {
/// Replaces all occurrences of one string with another.
///
- /// # Arguments
- ///
- /// * `from` - The string to replace
- /// * `to` - The replacement string
- ///
- /// # Return value
- ///
- /// The original string with all occurrences of `from` replaced with `to`.
+ /// `replace` takes two arguments, a sub-`&str` to find in `self`, and a second `&str` to
+ /// replace it with. If the original `&str` isn't found, no change occurs.
///
/// # Examples
///
- /// ```rust
+ /// ```
/// let s = "this is old";
///
/// assert_eq!(s.replace("old", "new"), "this is new");
+ /// ```
///
- /// // not found, so no change.
+ /// When a `&str` isn't found:
+ ///
+ /// ```
+ /// let s = "this is old";
/// assert_eq!(s.replace("cookie monster", "little lamb"), s);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
}
}
- /// Returns true if a string contains a string pattern.
+ /// Returns `true` if `self` contains another `&str`.
///
- /// # Arguments
- ///
- /// - pat - The string pattern to look for
- ///
- /// # Example
+ /// # Examples
///
- /// ```rust
+ /// ```
/// assert!("bananas".contains("nana"));
+ ///
+ /// assert!(!"bananas".contains("foobar"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- fn contains(&self, pat: &str) -> bool {
+ fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
core_str::StrExt::contains(&self[..], pat)
}
- /// Returns true if a string contains a char pattern.
- ///
- /// # Arguments
+ /// Returns `true` if `self` contains a `char`.
///
- /// - pat - The char pattern to look for
- ///
- /// # Example
+ /// # Examples
///
- /// ```rust
+ /// ```
/// assert!("hello".contains_char('e'));
+ ///
+ /// assert!(!"hello".contains_char('z'));
/// ```
- #[unstable(feature = "collections",
- reason = "might get removed in favour of a more generic contains()")]
- fn contains_char<P: CharEq>(&self, pat: P) -> bool {
+ #[unstable(feature = "collections")]
+ #[deprecated(since = "1.0.0", reason = "use `contains()` with a char")]
+ fn contains_char<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
core_str::StrExt::contains_char(&self[..], pat)
}
- /// An iterator over the characters of `self`. Note, this iterates
- /// over Unicode code-points, not Unicode graphemes.
+ /// An iterator over the codepoints of `self`.
///
- /// # Example
+ /// # Examples
///
- /// ```rust
+ /// ```
/// 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 {
core_str::StrExt::chars(&self[..])
}
- /// An iterator over the bytes of `self`
+ /// An iterator over the bytes of `self`.
///
- /// # Example
+ /// # Examples
///
- /// ```rust
+ /// ```
/// let v: Vec<u8> = "bors".bytes().collect();
+ ///
/// assert_eq!(v, b"bors".to_vec());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
}
/// An iterator over the characters of `self` and their byte offsets.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v: Vec<(usize, char)> = "abc".char_indices().collect();
+ /// let b = vec![(0, 'a'), (1, 'b'), (2, 'c')];
+ ///
+ /// assert_eq!(v, b);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn char_indices(&self) -> CharIndices {
core_str::StrExt::char_indices(&self[..])
}
/// An iterator over substrings of `self`, separated by characters
- /// matched by the pattern `pat`.
+ /// matched by a pattern.
///
- /// # Example
+ /// The pattern can be a simple `&str`, or a closure that determines
+ /// the split.
///
- /// ```rust
+ /// # Examples
+ ///
+ /// Simple `&str` patterns:
+ ///
+ /// ```
/// 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, [""]);
+ /// ```
+ ///
+ /// 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"]);
- ///
- /// let v: Vec<&str> = "".split('X').collect();
- /// assert_eq!(v, vec![""]);
+ /// assert_eq!(v, ["lion", "", "tiger", "leopard"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- fn split<P: CharEq>(&self, pat: P) -> Split<P> {
+ fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
core_str::StrExt::split(&self[..], pat)
}
- /// An iterator over substrings of `self`, separated by characters
- /// matched by the pattern `pat`, restricted to splitting at most `count`
- /// times.
+ /// An iterator over substrings of `self`, separated by characters matched by a pattern,
+ /// restricted to splitting at most `count` times.
///
- /// # Example
+ /// The pattern can be a simple `&str`, or a closure that determines
+ /// the split.
///
- /// ```rust
- /// let v: Vec<&str> = "Mary had a little lambda".splitn(2, ' ').collect();
- /// assert_eq!(v, vec!["Mary", "had", "a little lambda"]);
+ /// # Examples
///
- /// let v: Vec<&str> = "abc1def2ghi".splitn(1, |c: char| c.is_numeric()).collect();
- /// assert_eq!(v, vec!["abc", "def2ghi"]);
+ /// Simple `&str` patterns:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "Mary had a little lambda".splitn(2, ' ').collect();
+ /// 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, ["abc", "def2ghi"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- fn splitn<P: CharEq>(&self, count: usize, pat: P) -> SplitN<P> {
+ fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> {
core_str::StrExt::splitn(&self[..], count, pat)
}
/// An iterator over substrings of `self`, separated by characters
- /// matched by the pattern `pat`.
+ /// matched by a pattern.
///
- /// Equivalent to `split`, except that the trailing substring
- /// is skipped if empty (terminator semantics).
+ /// Equivalent to `split`, except that the trailing substring is skipped if empty.
///
- /// # Example
+ /// The pattern can be a simple `&str`, or a closure that determines
+ /// the split.
///
- /// ```rust
+ /// # Examples
+ ///
+ /// Simple `&str` patterns:
+ ///
+ /// ```
/// 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", ""]);
- ///
- /// let v: Vec<&str> = "Mary had a little lamb".split(' ').rev().collect();
- /// assert_eq!(v, vec!["lamb", "little", "a", "had", "Mary"]);
+ /// assert_eq!(v, ["A", "", "B", ""]);
+ /// ```
///
- /// let v: Vec<&str> = "abc1def2ghi".split(|c: char| c.is_numeric()).rev().collect();
- /// assert_eq!(v, vec!["ghi", "def", "abc"]);
+ /// More complex patterns with a lambda:
///
- /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').rev().collect();
- /// assert_eq!(v, vec!["leopard", "tiger", "", "lion"]);
/// ```
- #[unstable(feature = "collections", reason = "might get removed")]
- fn split_terminator<P: CharEq>(&self, pat: P) -> SplitTerminator<P> {
+ /// let v: Vec<&str> = "abc1def2ghi3".split_terminator(|c: char| c.is_numeric()).collect();
+ /// 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> {
core_str::StrExt::split_terminator(&self[..], pat)
}
- /// An iterator over substrings of `self`, separated by characters
- /// matched by the pattern `pat`, starting from the end of the string.
+ /// An iterator over substrings of `self`, separated by characters matched by a pattern,
+ /// starting from the end of the string.
+ ///
/// Restricted to splitting at most `count` times.
///
- /// # Example
+ /// The pattern can be a simple `&str`, or a closure that determines the split.
///
- /// ```rust
- /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(2, ' ').collect();
- /// assert_eq!(v, vec!["lamb", "little", "Mary had a"]);
+ /// # Examples
///
- /// let v: Vec<&str> = "abc1def2ghi".rsplitn(1, |c: char| c.is_numeric()).collect();
- /// assert_eq!(v, vec!["ghi", "abc1def"]);
+ /// Simple `&str` patterns:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(2, ' ').collect();
+ /// 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, ["ghi", "abc1def"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- fn rsplitn<P: CharEq>(&self, count: usize, pat: P) -> RSplitN<P> {
+ fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> {
core_str::StrExt::rsplitn(&self[..], count, pat)
}
- /// An iterator over the start and end indices of the disjoint
- /// matches of the pattern `pat` within `self`.
+ /// An iterator over the start and end indices of the disjoint matches of a `&str` within
+ /// `self`.
///
- /// That is, each returned value `(start, end)` satisfies
- /// `self.slice(start, end) == sep`. For matches of `sep` within
- /// `self` that overlap, only the indices corresponding to the
- /// first match are returned.
+ /// That is, each returned value `(start, end)` satisfies `self.slice(start, end) == sep`. For
+ /// matches of `sep` within `self` that overlap, only the indices corresponding to the first
+ /// match are returned.
///
- /// # Example
+ /// # Examples
///
- /// ```rust
+ /// ```
/// 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")]
- fn match_indices<'a>(&'a self, pat: &'a str) -> MatchIndices<'a> {
+ // NB: Right now MatchIndices yields `(usize, usize)`,
+ // but it would be more consistent and useful to return `(usize, &str)`
+ fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
core_str::StrExt::match_indices(&self[..], pat)
}
- /// An iterator over the substrings of `self` separated by the pattern `sep`.
+ /// An iterator over the substrings of `self` separated by a `&str`.
///
- /// # Example
+ /// # Examples
///
- /// ```rust
+ /// ```
/// 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",
- reason = "might get removed in the future in favor of a more generic split()")]
- fn split_str<'a>(&'a self, pat: &'a str) -> SplitStr<'a> {
+ #[unstable(feature = "collections")]
+ #[deprecated(since = "1.0.0", reason = "use `split()` with a `&str`")]
+ fn split_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitStr<'a, P> {
core_str::StrExt::split_str(&self[..], pat)
}
- /// An iterator over the lines of a string (subsequences separated
- /// by `\n`). This does not include the empty string after a
- /// trailing `\n`.
+ /// An iterator over the lines of a string, separated by `\n`.
///
- /// # Example
+ /// This does not include the empty string after a trailing `\n`.
///
- /// ```rust
+ /// # Examples
+ ///
+ /// ```
+ /// let four_lines = "foo\nbar\n\nbaz";
+ /// let v: Vec<&str> = four_lines.lines().collect();
+ ///
+ /// 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 {
core_str::StrExt::lines(&self[..])
}
- /// An iterator over the lines of a string, separated by either
- /// `\n` or `\r\n`. As with `.lines()`, this does not include an
- /// empty trailing line.
+ /// An iterator over the lines of a string, separated by either `\n` or `\r\n`.
///
- /// # Example
+ /// As with `.lines()`, this does not include an empty trailing line.
///
- /// ```rust
+ /// # Examples
+ ///
+ /// ```
+ /// let four_lines = "foo\r\nbar\n\r\nbaz";
+ /// let v: Vec<&str> = four_lines.lines_any().collect();
+ ///
+ /// 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 {
#[deprecated(since = "1.0.0", reason = "use slice notation [..a] instead")]
fn slice_to(&self, end: usize) -> &str;
- /// Returns a slice of the string from the character range
- /// [`begin`..`end`).
+ /// Returns a slice of the string from the character range [`begin`..`end`).
///
- /// That is, start at the `begin`-th code point of the string and
- /// continue to the `end`-th code point. This does not detect or
- /// handle edge cases such as leaving a combining character as the
- /// first code point of the string.
+ /// That is, start at the `begin`-th code point of the string and continue to the `end`-th code
+ /// point. This does not detect or handle edge cases such as leaving a combining character as
+ /// the first code point of the string.
///
- /// Due to the design of UTF-8, this operation is `O(end)`.
- /// See `slice`, `slice_to` and `slice_from` for `O(1)`
- /// variants that use byte indices rather than code point
- /// indices.
+ /// Due to the design of UTF-8, this operation is `O(end)`. See `slice`, `slice_to` and
+ /// `slice_from` for `O(1)` variants that use byte indices rather than code point indices.
///
- /// Panics if `begin` > `end` or the either `begin` or `end` are
- /// beyond the last character of the string.
+ /// # Panics
///
- /// # Example
+ /// Panics if `begin` > `end` or the either `begin` or `end` are beyond the last character of
+ /// the string.
///
- /// ```rust
+ /// # Examples
+ ///
+ /// ```
/// let s = "Löwe 老虎 Léopard";
+ ///
/// assert_eq!(s.slice_chars(0, 4), "Löwe");
/// assert_eq!(s.slice_chars(5, 7), "老虎");
/// ```
core_str::StrExt::slice_chars(&self[..], begin, end)
}
- /// Takes a bytewise (not UTF-8) slice from a string.
+ /// Takes a bytewise slice from a string.
///
/// Returns the substring from [`begin`..`end`).
///
- /// Caller must check both UTF-8 character boundaries and the boundaries of
- /// the entire slice as well.
+ /// # Unsafety
+ ///
+ /// Caller must check both UTF-8 character boundaries and the boundaries of the entire slice as
+ /// well.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ ///
+ /// unsafe {
+ /// assert_eq!(s.slice_unchecked(0, 21), "Löwe 老虎 Léopard");
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
core_str::StrExt::slice_unchecked(&self[..], begin, end)
}
- /// Returns true if the pattern `pat` is a prefix of the string.
+ /// Returns `true` if the given `&str` is a prefix of the string.
///
- /// # Example
+ /// # Examples
///
- /// ```rust
+ /// ```
/// assert!("banana".starts_with("ba"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- fn starts_with(&self, pat: &str) -> bool {
+ fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
core_str::StrExt::starts_with(&self[..], pat)
}
- /// Returns true if the pattern `pat` is a suffix of the string.
+ /// Returns true if the given `&str` is a suffix of the string.
///
- /// # Example
+ /// # Examples
///
/// ```rust
/// assert!("banana".ends_with("nana"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- fn ends_with(&self, pat: &str) -> bool {
+ fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
+ where P::Searcher: ReverseSearcher<'a>
+ {
core_str::StrExt::ends_with(&self[..], pat)
}
- /// Returns a string with all pre- and suffixes that match
- /// the pattern `pat` repeatedly removed.
+ /// Returns a string with all pre- and suffixes that match a pattern repeatedly removed.
///
- /// # Arguments
+ /// The pattern can be a simple `&str`, or a closure that determines the split.
///
- /// * pat - a string pattern
+ /// # Examples
///
- /// # Example
+ /// Simple `&str` patterns:
///
- /// ```rust
+ /// ```
/// assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar");
+ ///
/// let x: &[_] = &['1', '2'];
/// assert_eq!("12foo1bar12".trim_matches(x), "foo1bar");
+ /// ```
+ ///
+ /// More complex patterns with a lambda:
+ ///
+ /// ```
/// assert_eq!("123foo1bar123".trim_matches(|c: char| c.is_numeric()), "foo1bar");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- fn trim_matches<P: CharEq>(&self, pat: P) -> &str {
+ fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
+ where P::Searcher: DoubleEndedSearcher<'a>
+ {
core_str::StrExt::trim_matches(&self[..], pat)
}
- /// Returns a string with all prefixes that match
- /// the pattern `pat` repeatedly removed.
+ /// Returns a string with all prefixes that match a pattern repeatedly removed.
///
- /// # Arguments
+ /// The pattern can be a simple `&str`, or a closure that determines the split.
///
- /// * pat - a string pattern
+ /// # Examples
///
- /// # Example
+ /// Simple `&str` patterns:
///
- /// ```rust
+ /// ```
/// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11");
+ ///
/// let x: &[_] = &['1', '2'];
/// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12");
+ /// ```
+ ///
+ /// More complex patterns with a lambda:
+ ///
+ /// ```
/// assert_eq!("123foo1bar123".trim_left_matches(|c: char| c.is_numeric()), "foo1bar123");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- fn trim_left_matches<P: CharEq>(&self, pat: P) -> &str {
+ fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
core_str::StrExt::trim_left_matches(&self[..], pat)
}
- /// Returns a string with all suffixes that match
- /// the pattern `pat` repeatedly removed.
+ /// Returns a string with all suffixes that match a pattern repeatedly removed.
///
- /// # Arguments
+ /// The pattern can be a simple `&str`, or a closure that determines the split.
///
- /// * pat - a string pattern
+ /// # Examples
///
- /// # Example
+ /// Simple `&str` patterns:
///
- /// ```rust
+ /// ```
/// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar");
/// let x: &[_] = &['1', '2'];
/// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar");
+ /// ```
+ ///
+ /// More complex patterns with a lambda:
+ ///
+ /// ```
/// assert_eq!("123foo1bar123".trim_right_matches(|c: char| c.is_numeric()), "123foo1bar");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- fn trim_right_matches<P: CharEq>(&self, pat: P) -> &str {
+ fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
+ where P::Searcher: ReverseSearcher<'a>
+ {
core_str::StrExt::trim_right_matches(&self[..], pat)
}
- /// Check that `index`-th byte lies at the start and/or end of a
- /// UTF-8 code point sequence.
+ /// Check that `index`-th byte lies at the start and/or end of a UTF-8 code point sequence.
///
- /// The start and end of the string (when `index == self.len()`)
- /// are considered to be boundaries.
+ /// The start and end of the string (when `index == self.len()`) are considered to be
+ /// boundaries.
+ ///
+ /// # Panics
///
/// Panics if `index` is greater than `self.len()`.
///
- /// # Example
+ /// # Examples
///
- /// ```rust
+ /// ```
/// let s = "Löwe 老虎 Léopard";
/// assert!(s.is_char_boundary(0));
/// // start of `老`
core_str::StrExt::is_char_boundary(&self[..], index)
}
- /// Pluck a character out of a string and return the index of the next
- /// character.
+ /// Given a byte position, return the next char and its index.
///
- /// This function can be used to iterate over the Unicode characters of a
- /// string.
+ /// This can be used to iterate over the Unicode characters of a string.
///
- /// # Example
+ /// # Panics
///
- /// This example manually iterates through the characters of a
- /// string; this should normally be done by `.chars()` or
- /// `.char_indices`.
+ /// If `i` is greater than or equal to the length of the string.
+ /// If `i` is not the index of the beginning of a valid UTF-8 character.
///
- /// ```rust
+ /// # Examples
+ ///
+ /// This example manually iterates through the characters of a string; this should normally be
+ /// done by `.chars()` or `.char_indices()`.
+ ///
+ /// ```
/// use std::str::CharRange;
///
/// let s = "中华Việt Nam";
/// 14: a
/// 15: m
/// ```
- ///
- /// # Arguments
- ///
- /// * s - The string
- /// * i - The byte offset of the char to extract
- ///
- /// # Return value
- ///
- /// A record {ch: char, next: usize} containing the char value and the byte
- /// index of the next Unicode character.
- ///
- /// # Panics
- ///
- /// If `i` is greater than or equal to the length of the string.
- /// If `i` is not the index of the beginning of a valid UTF-8 character.
#[unstable(feature = "collections",
reason = "naming is uncertain with container conventions")]
fn char_range_at(&self, start: usize) -> CharRange {
core_str::StrExt::char_range_at(&self[..], start)
}
- /// Given a byte position and a str, return the previous char and its position.
+ /// Given a byte position, return the previous `char` and its position.
///
/// This function can be used to iterate over a Unicode string in reverse.
///
///
/// If `i` is greater than the length of the string.
/// If `i` is not an index following a valid UTF-8 character.
+ ///
+ /// # Examples
+ ///
+ /// This example manually iterates through the characters of a string; this should normally be
+ /// done by `.chars().rev()` or `.char_indices()`.
+ ///
+ /// ```
+ /// use std::str::CharRange;
+ ///
+ /// let s = "中华Việt Nam";
+ /// let mut i = s.len();
+ /// while i < 0 {
+ /// let CharRange {ch, next} = s.char_range_at_reverse(i);
+ /// println!("{}: {}", i, ch);
+ /// i = next;
+ /// }
+ /// ```
+ ///
+ /// This outputs:
+ ///
+ /// ```text
+ /// 16: m
+ /// 15: a
+ /// 14: N
+ /// 13:
+ /// 12: t
+ /// 11: ệ
+ /// 8: i
+ /// 7: V
+ /// 6: 华
+ /// 3: 中
+ /// ```
#[unstable(feature = "collections",
reason = "naming is uncertain with container conventions")]
fn char_range_at_reverse(&self, start: usize) -> CharRange {
core_str::StrExt::char_range_at_reverse(&self[..], start)
}
- /// Plucks the character starting at the `i`th byte of a string.
+ /// Given a byte position, return the `char` at that position.
///
- /// # Example
+ /// # Panics
///
- /// ```rust
+ /// If `i` is greater than or equal to the length of the string.
+ /// If `i` is not the index of the beginning of a valid UTF-8 character.
+ ///
+ /// # Examples
+ ///
+ /// ```
/// let s = "abπc";
/// assert_eq!(s.char_at(1), 'b');
/// assert_eq!(s.char_at(2), 'π');
- /// assert_eq!(s.char_at(4), 'c');
/// ```
- ///
- /// # Panics
- ///
- /// If `i` is greater than or equal to the length of the string.
- /// If `i` is not the index of the beginning of a valid UTF-8 character.
#[unstable(feature = "collections",
reason = "naming is uncertain with container conventions")]
fn char_at(&self, i: usize) -> char {
core_str::StrExt::char_at(&self[..], i)
}
- /// Plucks the character ending at the `i`th byte of a string.
+ /// Given a byte position, return the `char` at that position, counting from the end.
///
/// # Panics
///
/// If `i` is greater than the length of the string.
/// If `i` is not an index following a valid UTF-8 character.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let s = "abπc";
+ /// assert_eq!(s.char_at_reverse(1), 'a');
+ /// assert_eq!(s.char_at_reverse(2), 'b');
+ /// ```
#[unstable(feature = "collections",
reason = "naming is uncertain with container conventions")]
fn char_at_reverse(&self, i: usize) -> char {
core_str::StrExt::char_at_reverse(&self[..], i)
}
- /// Work with the byte buffer of a string as a byte slice.
+ /// Convert `self` to a byte slice.
///
- /// # Example
+ /// # Examples
///
- /// ```rust
+ /// ```
/// assert_eq!("bors".as_bytes(), b"bors");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
core_str::StrExt::as_bytes(&self[..])
}
- /// Returns the byte index of the first character of `self` that
- /// matches the pattern `pat`.
+ /// Returns the byte index of the first character of `self` that matches the pattern, if it
+ /// exists.
///
- /// # Return value
+ /// Returns `None` if it doesn't exist.
///
- /// `Some` containing the byte index of the last matching character
- /// or `None` if there is no match
+ /// The pattern can be a simple `&str`, or a closure that determines the split.
///
- /// # Example
+ /// # Examples
///
- /// ```rust
+ /// Simple `&str` patterns:
+ ///
+ /// ```
/// let s = "Löwe 老虎 Léopard";
///
/// assert_eq!(s.find('L'), Some(0));
/// assert_eq!(s.find('é'), Some(14));
///
- /// // the first space
+ /// ```
+ ///
+ /// More complex patterns with a lambda:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ ///
/// assert_eq!(s.find(|c: char| c.is_whitespace()), Some(5));
+ /// ```
///
- /// // neither are found
+ /// Not finding the pattern:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
/// let x: &[_] = &['1', '2'];
+ ///
/// assert_eq!(s.find(x), None);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- fn find<P: CharEq>(&self, pat: P) -> Option<usize> {
+ fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
core_str::StrExt::find(&self[..], pat)
}
- /// Returns the byte index of the last character of `self` that
- /// matches the pattern `pat`.
+ /// Returns the byte index of the last character of `self` that matches the pattern, if it
+ /// exists.
///
- /// # Return value
+ /// Returns `None` if it doesn't exist.
///
- /// `Some` containing the byte index of the last matching character
- /// or `None` if there is no match.
+ /// The pattern can be a simple `&str`, or a closure that determines the split.
///
- /// # Example
+ /// # Examples
///
- /// ```rust
+ /// Simple `&str` patterns:
+ ///
+ /// ```
/// let s = "Löwe 老虎 Léopard";
///
/// assert_eq!(s.rfind('L'), Some(13));
/// assert_eq!(s.rfind('é'), Some(14));
+ /// ```
+ ///
+ /// More complex patterns with a lambda:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
///
- /// // the second space
/// assert_eq!(s.rfind(|c: char| c.is_whitespace()), Some(12));
+ /// ```
+ ///
+ /// Not finding the pattern:
///
- /// // searches for an occurrence of either `1` or `2`, but neither are found
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
/// let x: &[_] = &['1', '2'];
+ ///
/// assert_eq!(s.rfind(x), None);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- fn rfind<P: CharEq>(&self, pat: P) -> Option<usize> {
+ fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
+ where P::Searcher: ReverseSearcher<'a>
+ {
core_str::StrExt::rfind(&self[..], pat)
}
- /// Returns the byte index of the first matching substring
+ /// Returns the byte index of the first matching substring if it exists.
///
- /// # Arguments
+ /// Returns `None` if it doesn't exist.
///
- /// * `needle` - The string to search for
+ /// The pattern can be a simple `&str`, or a closure that determines the split.
///
- /// # Return value
- ///
- /// `Some` containing the byte index of the first matching substring
- /// or `None` if there is no match.
- ///
- /// # Example
+ /// # Examples
///
- /// ```rust
+ /// ```
/// let s = "Löwe 老虎 Léopard";
///
/// assert_eq!(s.find_str("老虎 L"), Some(6));
/// assert_eq!(s.find_str("muffin man"), None);
/// ```
- #[unstable(feature = "collections",
- reason = "might get removed in favor of a more generic find in the future")]
- fn find_str(&self, needle: &str) -> Option<usize> {
+ #[unstable(feature = "collections")]
+ #[deprecated(since = "1.0.0", reason = "use `find()` with a `&str`")]
+ fn find_str<'a, P: Pattern<'a>>(&'a self, needle: P) -> Option<usize> {
core_str::StrExt::find_str(&self[..], needle)
}
- /// Retrieves the first character from a string slice and returns
- /// it. This does not allocate a new string; instead, it returns a
- /// slice that point one character beyond the character that was
- /// shifted. If the string does not contain any characters,
- /// None is returned instead.
+ /// Retrieves the first character from a `&str` and returns it.
///
- /// # Example
+ /// This does not allocate a new string; instead, it returns a slice that points one character
+ /// beyond the character that was shifted.
///
- /// ```rust
+ /// If the slice does not contain any characters, None is returned instead.
+ ///
+ /// # Examples
+ ///
+ /// ```
/// let s = "Löwe 老虎 Léopard";
/// let (c, s1) = s.slice_shift_char().unwrap();
+ ///
/// assert_eq!(c, 'L');
/// assert_eq!(s1, "öwe 老虎 Léopard");
///
/// let (c, s2) = s1.slice_shift_char().unwrap();
+ ///
/// assert_eq!(c, 'ö');
/// assert_eq!(s2, "we 老虎 Léopard");
/// ```
/// Returns the byte offset of an inner slice relative to an enclosing outer slice.
///
+ /// # Panics
+ ///
/// Panics if `inner` is not a direct slice contained within self.
///
- /// # Example
+ /// # Examples
///
- /// ```rust
+ /// ```
/// let string = "a\nb\nc";
/// let lines: Vec<&str> = string.lines().collect();
///
core_str::StrExt::subslice_offset(&self[..], inner)
}
- /// Return an unsafe pointer to the strings buffer.
+ /// Return an unsafe pointer to the `&str`'s buffer.
+ ///
+ /// The caller must ensure that the string outlives this pointer, and that it is not
+ /// reallocated (e.g. by pushing to the string).
+ ///
+ /// # Examples
///
- /// The caller must ensure that the string outlives this pointer,
- /// and that it is not reallocated (e.g. by pushing to the
- /// string).
+ /// ```
+ /// let s = "Hello";
+ /// let p = s.as_ptr();
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
fn as_ptr(&self) -> *const u8 {
Utf16Units { encoder: Utf16Encoder::new(self[..].chars()) }
}
- /// Return the number of bytes in this string
+ /// Returns the length of `self` in bytes.
///
- /// # Example
+ /// # Examples
///
/// ```
/// assert_eq!("foo".len(), 3);
- /// assert_eq!("ƒoo".len(), 4);
+ /// assert_eq!("ƒoo".len(), 4); // fancy f!
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
core_str::StrExt::len(&self[..])
}
- /// Returns true if this slice contains no bytes
+ /// Returns true if this slice has a length of zero bytes.
///
- /// # Example
+ /// # Examples
///
/// ```
/// assert!("".is_empty());
core_str::StrExt::is_empty(&self[..])
}
- /// Parse this string into the specified type.
+ /// Parses `self` into the specified type.
+ ///
+ /// # Failure
+ ///
+ /// Will return `Err` if it's not possible to parse `self` into the type.
///
/// # Example
///
/// ```
/// assert_eq!("4".parse::<u32>(), Ok(4));
+ /// ```
+ ///
+ /// Failing:
+ ///
+ /// ```
/// assert!("j".parse::<u32>().is_err());
/// ```
#[inline]
core_str::StrExt::parse(&self[..])
}
- /// Returns an iterator over the
- /// [grapheme clusters](http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries)
- /// of the string.
+ /// Returns an iterator over the [grapheme clusters][graphemes] of `self`.
+ ///
+ /// [graphemes]: http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries
///
/// If `is_extended` is true, the iterator is over the *extended grapheme clusters*;
/// otherwise, the iterator is over the *legacy grapheme clusters*.
/// [UAX#29](http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries)
/// recommends extended grapheme cluster boundaries for general processing.
///
- /// # Example
+ /// # Examples
///
- /// ```rust
+ /// ```
/// let gr1 = "a\u{310}e\u{301}o\u{308}\u{332}".graphemes(true).collect::<Vec<&str>>();
/// let b: &[_] = &["a\u{310}", "e\u{301}", "o\u{308}\u{332}"];
+ ///
/// assert_eq!(gr1.as_slice(), b);
+ ///
/// let gr2 = "a\r\nb🇷🇺🇸🇹".graphemes(true).collect::<Vec<&str>>();
/// let b: &[_] = &["a", "\r\n", "b", "🇷🇺🇸🇹"];
+ ///
/// assert_eq!(gr2.as_slice(), b);
/// ```
#[unstable(feature = "collections",
UnicodeStr::graphemes(&self[..], is_extended)
}
- /// Returns an iterator over the grapheme clusters of self and their byte offsets.
- /// See `graphemes()` method for more information.
+ /// Returns an iterator over the grapheme clusters of `self` and their byte offsets. See
+ /// `graphemes()` for more information.
///
- /// # Example
+ /// # Examples
///
- /// ```rust
+ /// ```
/// let gr_inds = "a̐éö̲\r\n".grapheme_indices(true).collect::<Vec<(usize, &str)>>();
/// let b: &[_] = &[(0, "a̐"), (3, "é"), (6, "ö̲"), (11, "\r\n")];
+ ///
/// assert_eq!(gr_inds.as_slice(), b);
/// ```
#[unstable(feature = "collections",
UnicodeStr::grapheme_indices(&self[..], is_extended)
}
- /// An iterator over the words of a string (subsequences separated
- /// by any sequence of whitespace). Sequences of whitespace are
- /// collapsed, so empty "words" are not included.
+ /// An iterator over the non-empty words of `self`.
///
- /// # Example
+ /// A 'word' is a subsequence separated by any sequence of whitespace. Sequences of whitespace
+ /// are collapsed, so empty "words" are not included.
///
- /// ```rust
+ /// # Examples
+ ///
+ /// ```
/// 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")]
UnicodeStr::words(&self[..])
}
- /// Returns a string's displayed width in columns, treating control
- /// characters as zero-width.
+ /// Returns a string's displayed width in columns.
+ ///
+ /// Control characters have zero width.
///
- /// `is_cjk` determines behavior for characters in the Ambiguous category:
- /// if `is_cjk` is `true`, these are 2 columns wide; otherwise, they are 1.
- /// In CJK locales, `is_cjk` should be `true`, else it should be `false`.
- /// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/)
- /// recommends that these characters be treated as 1 column (i.e.,
- /// `is_cjk` = `false`) if the locale is unknown.
+ /// `is_cjk` determines behavior for characters in the Ambiguous category: if `is_cjk` is
+ /// `true`, these are 2 columns wide; otherwise, they are 1. In CJK locales, `is_cjk` should be
+ /// `true`, else it should be `false`. [Unicode Standard Annex
+ /// #11](http://www.unicode.org/reports/tr11/) recommends that these characters be treated as 1
+ /// column (i.e., `is_cjk` = `false`) if the locale is unknown.
#[unstable(feature = "collections",
reason = "this functionality may only be provided by libunicode")]
fn width(&self, is_cjk: bool) -> usize {
UnicodeStr::width(&self[..], is_cjk)
}
- /// Returns a string with leading and trailing whitespace removed.
+ /// Returns a `&str` with leading and trailing whitespace removed.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let s = " Hello\tworld\t";
+ /// assert_eq!(s.trim(), "Hello\tworld");
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn trim(&self) -> &str {
UnicodeStr::trim(&self[..])
}
- /// Returns a string with leading whitespace removed.
+ /// Returns a `&str` with leading whitespace removed.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let s = " Hello\tworld\t";
+ /// assert_eq!(s.trim_left(), "Hello\tworld\t");
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn trim_left(&self) -> &str {
UnicodeStr::trim_left(&self[..])
}
- /// Returns a string with trailing whitespace removed.
+ /// Returns a `&str` with trailing whitespace removed.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let s = " Hello\tworld\t";
+ /// assert_eq!(s.trim_right(), " Hello\tworld");
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn trim_right(&self) -> &str {
UnicodeStr::trim_right(&self[..])
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]
b.iter(|| assert_eq!(s.split('V').count(), 3));
}
- #[bench]
- fn split_unicode_not_ascii(b: &mut Bencher) {
- struct NotAscii(char);
- impl CharEq for NotAscii {
- fn matches(&mut self, c: char) -> bool {
- let NotAscii(cc) = *self;
- cc == c
- }
- fn only_ascii(&self) -> bool { false }
- }
- let s = "ประเทศไทย中华Việt Namประเทศไทย中华Việt Nam";
-
- b.iter(|| assert_eq!(s.split(NotAscii('V')).count(), 3));
- }
-
-
#[bench]
fn split_ascii(b: &mut Bencher) {
let s = "Mary had a little lamb, Little lamb, little-lamb.";
b.iter(|| assert_eq!(s.split(' ').count(), len));
}
- #[bench]
- fn split_not_ascii(b: &mut Bencher) {
- struct NotAscii(char);
- impl CharEq for NotAscii {
- #[inline]
- fn matches(&mut self, c: char) -> bool {
- let NotAscii(cc) = *self;
- cc == c
- }
- fn only_ascii(&self) -> bool { false }
- }
- let s = "Mary had a little lamb, Little lamb, little-lamb.";
- let len = s.split(' ').count();
-
- b.iter(|| assert_eq!(s.split(NotAscii(' ')).count(), len));
- }
-
#[bench]
fn split_extern_fn(b: &mut Bencher) {
let s = "Mary had a little lamb, Little lamb, little-lamb.";
/// 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
}
pub fn into_boxed_slice(mut self) -> Box<[T]> {
self.shrink_to_fit();
unsafe {
- let xs: Box<[T]> = mem::transmute(&mut *self);
+ let xs: Box<[T]> = Box::from_raw(&mut *self);
mem::forget(self);
xs
}
/// ```
/// 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) {
}
}
-impl<A, B> PartialEq<Vec<B>> for Vec<A> where A: PartialEq<B> {
- #[inline]
- fn eq(&self, other: &Vec<B>) -> bool { PartialEq::eq(&**self, &**other) }
- #[inline]
- fn ne(&self, other: &Vec<B>) -> bool { PartialEq::ne(&**self, &**other) }
-}
-
-macro_rules! impl_eq {
- ($lhs:ty, $rhs:ty) => {
- impl<'b, A, B> PartialEq<$rhs> for $lhs where A: PartialEq<B> {
- #[inline]
- fn eq(&self, other: &$rhs) -> bool { PartialEq::eq(&**self, &**other) }
- #[inline]
- fn ne(&self, other: &$rhs) -> bool { PartialEq::ne(&**self, &**other) }
- }
-
- impl<'b, A, B> PartialEq<$lhs> for $rhs where B: PartialEq<A> {
- #[inline]
- fn eq(&self, other: &$lhs) -> bool { PartialEq::eq(&**self, &**other) }
- #[inline]
- fn ne(&self, other: &$lhs) -> bool { PartialEq::ne(&**self, &**other) }
- }
+__impl_slice_eq1! { Vec<A>, Vec<B> }
+__impl_slice_eq2! { Vec<A>, &'b [B] }
+__impl_slice_eq2! { Vec<A>, &'b mut [B] }
+__impl_slice_eq2! { CowVec<'a, A>, &'b [B], Clone }
+__impl_slice_eq2! { CowVec<'a, A>, &'b mut [B], Clone }
+__impl_slice_eq2! { CowVec<'a, A>, Vec<B>, Clone }
+
+macro_rules! array_impls {
+ ($($N: expr)+) => {
+ $(
+ // NOTE: some less important impls are omitted to reduce code bloat
+ __impl_slice_eq2! { Vec<A>, [B; $N] }
+ __impl_slice_eq2! { Vec<A>, &'b [B; $N] }
+ // __impl_slice_eq2! { Vec<A>, &'b mut [B; $N] }
+ // __impl_slice_eq2! { CowVec<'a, A>, [B; $N], Clone }
+ // __impl_slice_eq2! { CowVec<'a, A>, &'b [B; $N], Clone }
+ // __impl_slice_eq2! { CowVec<'a, A>, &'b mut [B; $N], Clone }
+ )+
}
}
-impl_eq! { Vec<A>, &'b [B] }
-impl_eq! { Vec<A>, &'b mut [B] }
-
-impl<'a, A, B> PartialEq<Vec<B>> for Cow<'a, [A]> where A: PartialEq<B> + Clone {
- #[inline]
- fn eq(&self, other: &Vec<B>) -> bool { PartialEq::eq(&**self, &**other) }
- #[inline]
- fn ne(&self, other: &Vec<B>) -> bool { PartialEq::ne(&**self, &**other) }
-}
-
-impl<'a, A, B> PartialEq<Cow<'a, [A]>> for Vec<B> where A: Clone, B: PartialEq<A> {
- #[inline]
- fn eq(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::eq(&**self, &**other) }
- #[inline]
- fn ne(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::ne(&**self, &**other) }
-}
-
-macro_rules! impl_eq_for_cowvec {
- ($rhs:ty) => {
- impl<'a, 'b, A, B> PartialEq<$rhs> for Cow<'a, [A]> where A: PartialEq<B> + Clone {
- #[inline]
- fn eq(&self, other: &$rhs) -> bool { PartialEq::eq(&**self, &**other) }
- #[inline]
- fn ne(&self, other: &$rhs) -> bool { PartialEq::ne(&**self, &**other) }
- }
-
- impl<'a, 'b, A, B> PartialEq<Cow<'a, [A]>> for $rhs where A: Clone, B: PartialEq<A> {
- #[inline]
- fn eq(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::eq(&**self, &**other) }
- #[inline]
- fn ne(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::ne(&**self, &**other) }
- }
- }
+array_impls! {
+ 0 1 2 3 4 5 6 7 8 9
+ 10 11 12 13 14 15 16 17 18 19
+ 20 21 22 23 24 25 26 27 28 29
+ 30 31 32
}
-impl_eq_for_cowvec! { &'b [B] }
-impl_eq_for_cowvec! { &'b mut [B] }
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PartialOrd> PartialOrd for Vec<T> {
#[inline]
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;
let (left, right) = values.split_at_mut(2);
{
let left: &[_] = left;
- assert!(&left[..left.len()] == &[1, 2][]);
+ assert!(&left[..left.len()] == &[1, 2]);
}
for p in left {
*p += 1;
{
let right: &[_] = right;
- assert!(&right[..right.len()] == &[3, 4, 5][]);
+ assert!(&right[..right.len()] == &[3, 4, 5]);
}
for p in right {
*p += 2;
}
}
- 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]
fn test_into_boxed_slice() {
let xs = vec![1, 2, 3];
let ys = xs.into_boxed_slice();
- assert_eq!(ys, [1, 2, 3]);
+ assert_eq!(&*ys, [1, 2, 3]);
}
#[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<_>>(), []);
}
}
use core::prelude::*;
-use core::cmp::Ordering;
+use core::cmp::{max, Ordering};
use core::default::Default;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::iter::{Enumerate, FilterMap, Map, FromIterator, IntoIterator};
use core::iter;
-use core::mem::replace;
+use core::mem::{replace, swap};
use core::ops::{Index, IndexMut};
use {vec, slice};
///
/// 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> {
IntoIter { iter: self.v.into_iter().enumerate().filter_map(filter) }
}
+ /// Moves all elements from `other` into the map while overwriting existing keys.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::VecMap;
+ ///
+ /// let mut a = VecMap::new();
+ /// a.insert(1, "a");
+ /// a.insert(2, "b");
+ ///
+ /// let mut b = VecMap::new();
+ /// b.insert(3, "c");
+ /// b.insert(4, "d");
+ ///
+ /// a.append(&mut b);
+ ///
+ /// assert_eq!(a.len(), 4);
+ /// assert_eq!(b.len(), 0);
+ /// assert_eq!(a[1], "a");
+ /// assert_eq!(a[2], "b");
+ /// assert_eq!(a[3], "c");
+ /// assert_eq!(a[4], "d");
+ /// ```
+ #[unstable(feature = "collections",
+ reason = "recently added as part of collections reform 2")]
+ pub fn append(&mut self, other: &mut Self) {
+ self.extend(other.drain());
+ }
+
+ /// Splits the collection into two at the given key.
+ ///
+ /// Returns a newly allocated `Self`. `self` contains elements `[0, at)`,
+ /// and the returned `Self` contains elements `[at, max_key)`.
+ ///
+ /// Note that the capacity of `self` does not change.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::VecMap;
+ ///
+ /// let mut a = VecMap::new();
+ /// a.insert(1, "a");
+ /// a.insert(2, "b");
+ /// a.insert(3, "c");
+ /// a.insert(4, "d");
+ ///
+ /// let b = a.split_off(3);
+ ///
+ /// assert_eq!(a[1], "a");
+ /// assert_eq!(a[2], "b");
+ ///
+ /// assert_eq!(b[3], "c");
+ /// assert_eq!(b[4], "d");
+ /// ```
+ #[unstable(feature = "collections",
+ reason = "recently added as part of collections reform 2")]
+ pub fn split_off(&mut self, at: usize) -> Self {
+ let mut other = VecMap::new();
+
+ if at == 0 {
+ // Move all elements to other
+ swap(self, &mut other);
+ return other
+ } else if at > self.v.len() {
+ // No elements to copy
+ return other;
+ }
+
+ // Look up the index of the first non-None item
+ let first_index = self.v.iter().position(|el| el.is_some());
+ let start_index = match first_index {
+ Some(index) => max(at, index),
+ None => {
+ // self has no elements
+ return other;
+ }
+ };
+
+ // Fill the new VecMap with `None`s until `start_index`
+ other.v.extend((0..start_index).map(|_| None));
+
+ // Move elements beginning with `start_index` from `self` into `other`
+ other.v.extend(self.v[start_index..].iter_mut().map(|el| el.take()));
+
+ other
+ }
+
/// Returns an iterator visiting all key-value pairs in ascending order of
/// the keys, emptying (but not consuming) the original `VecMap`.
/// The iterator's element type is `(usize, &'r V)`. Keeps the allocated memory for reuse.
///
/// 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);
}
+ #[test]
+ fn test_append() {
+ let mut a = VecMap::new();
+ a.insert(1, "a");
+ a.insert(2, "b");
+ a.insert(3, "c");
+
+ let mut b = VecMap::new();
+ b.insert(3, "d"); // Overwrite element from a
+ b.insert(4, "e");
+ b.insert(5, "f");
+
+ a.append(&mut b);
+
+ assert_eq!(a.len(), 5);
+ assert_eq!(b.len(), 0);
+ // Capacity shouldn't change for possible reuse
+ assert!(b.capacity() >= 4);
+
+ assert_eq!(a[1], "a");
+ assert_eq!(a[2], "b");
+ assert_eq!(a[3], "d");
+ assert_eq!(a[4], "e");
+ assert_eq!(a[5], "f");
+ }
+
+ #[test]
+ fn test_split_off() {
+ // Split within the key range
+ let mut a = VecMap::new();
+ a.insert(1, "a");
+ a.insert(2, "b");
+ a.insert(3, "c");
+ a.insert(4, "d");
+
+ let b = a.split_off(3);
+
+ assert_eq!(a.len(), 2);
+ assert_eq!(b.len(), 2);
+
+ assert_eq!(a[1], "a");
+ assert_eq!(a[2], "b");
+
+ assert_eq!(b[3], "c");
+ assert_eq!(b[4], "d");
+
+ // Split at 0
+ a.clear();
+ a.insert(1, "a");
+ a.insert(2, "b");
+ a.insert(3, "c");
+ a.insert(4, "d");
+
+ let b = a.split_off(0);
+
+ assert_eq!(a.len(), 0);
+ assert_eq!(b.len(), 4);
+ assert_eq!(b[1], "a");
+ assert_eq!(b[2], "b");
+ assert_eq!(b[3], "c");
+ assert_eq!(b[4], "d");
+
+ // Split behind max_key
+ a.clear();
+ a.insert(1, "a");
+ a.insert(2, "b");
+ a.insert(3, "c");
+ a.insert(4, "d");
+
+ let b = a.split_off(5);
+
+ assert_eq!(a.len(), 4);
+ assert_eq!(b.len(), 0);
+ assert_eq!(a[1], "a");
+ assert_eq!(a[2], "b");
+ assert_eq!(a[3], "c");
+ assert_eq!(a[4], "d");
+ }
+
#[test]
fn test_show() {
let mut map = VecMap::new();
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]
use fmt;
use hash::{Hash, self};
use iter::IntoIterator;
-use marker::Copy;
-use ops::Deref;
+use marker::{Copy, Sized};
use option::Option;
use slice::{Iter, IterMut, SliceExt};
}
}
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<A, B> PartialEq<[B; $N]> for [A; $N] where A: PartialEq<B> {
- #[inline]
- fn eq(&self, other: &[B; $N]) -> bool {
- &self[..] == &other[..]
- }
- #[inline]
- fn ne(&self, other: &[B; $N]) -> bool {
- &self[..] != &other[..]
- }
- }
-
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<'a, A, B, Rhs> PartialEq<Rhs> for [A; $N] where
- A: PartialEq<B>,
- Rhs: Deref<Target=[B]>,
- {
- #[inline(always)]
- fn eq(&self, other: &Rhs) -> bool {
- PartialEq::eq(&self[..], &**other)
- }
- #[inline(always)]
- fn ne(&self, other: &Rhs) -> bool {
- PartialEq::ne(&self[..], &**other)
- }
- }
-
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<'a, A, B, Lhs> PartialEq<[B; $N]> for Lhs where
- A: PartialEq<B>,
- Lhs: Deref<Target=[A]>
- {
- #[inline(always)]
- fn eq(&self, other: &[B; $N]) -> bool {
- PartialEq::eq(&**self, &other[..])
- }
- #[inline(always)]
- fn ne(&self, other: &[B; $N]) -> bool {
- PartialEq::ne(&**self, &other[..])
- }
- }
+ // NOTE: some less important impls are omitted to reduce code bloat
+ __impl_slice_eq1! { [A; $N], [B; $N] }
+ __impl_slice_eq2! { [A; $N], [B] }
+ __impl_slice_eq2! { [A; $N], &'b [B] }
+ __impl_slice_eq2! { [A; $N], &'b mut [B] }
+ // __impl_slice_eq2! { [A; $N], &'b [B; $N] }
+ // __impl_slice_eq2! { [A; $N], &'b mut [B; $N] }
#[stable(feature = "rust1", since = "1.0.0")]
impl<T:Eq> Eq for [T; $N] { }
use clone::Clone;
use cmp::PartialEq;
use default::Default;
-use marker::{Copy, Send};
+use marker::{Copy, Send, Sync};
use ops::{Deref, DerefMut, Drop};
use option::Option;
use option::Option::{None, Some};
pub value: T,
}
+impl<T> !Sync for UnsafeCell<T> {}
+
impl<T> UnsafeCell<T> {
/// Construct a new instance of `UnsafeCell` which will wrap the specified
/// value.
use slice::SliceExt;
// UTF-8 ranges and tags for encoding characters
-static TAG_CONT: u8 = 0b1000_0000u8;
-static TAG_TWO_B: u8 = 0b1100_0000u8;
-static TAG_THREE_B: u8 = 0b1110_0000u8;
-static TAG_FOUR_B: u8 = 0b1111_0000u8;
-static MAX_ONE_B: u32 = 0x80u32;
-static MAX_TWO_B: u32 = 0x800u32;
-static MAX_THREE_B: u32 = 0x10000u32;
+const TAG_CONT: u8 = 0b1000_0000u8;
+const TAG_TWO_B: u8 = 0b1100_0000u8;
+const TAG_THREE_B: u8 = 0b1110_0000u8;
+const TAG_FOUR_B: u8 = 0b1111_0000u8;
+const MAX_ONE_B: u32 = 0x80u32;
+const MAX_TWO_B: u32 = 0x800u32;
+const MAX_THREE_B: u32 = 0x10000u32;
/*
Lu Uppercase_Letter an uppercase letter
#[stable(feature = "rust1", since = "1.0.0")]
fn len_utf8(self) -> usize {
let code = self as u32;
- match () {
- _ if code < MAX_ONE_B => 1,
- _ if code < MAX_TWO_B => 2,
- _ if code < MAX_THREE_B => 3,
- _ => 4,
+ if code < MAX_ONE_B {
+ 1
+ } else if code < MAX_TWO_B {
+ 2
+ } else if code < MAX_THREE_B {
+ 3
+ } else {
+ 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.
+
+// Utility macros for implementing PartialEq on slice-like types
+
+#![doc(hidden)]
+
+#[macro_export]
+macro_rules! __impl_slice_eq1 {
+ ($Lhs: ty, $Rhs: ty) => {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ impl<'a, 'b, A, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
+ #[inline]
+ fn eq(&self, other: &$Rhs) -> bool { &self[..] == &other[..] }
+ #[inline]
+ fn ne(&self, other: &$Rhs) -> bool { &self[..] != &other[..] }
+ }
+ }
+}
+
+#[macro_export]
+macro_rules! __impl_slice_eq2 {
+ ($Lhs: ty, $Rhs: ty) => {
+ __impl_slice_eq2! { $Lhs, $Rhs, Sized }
+ };
+ ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
+ #[inline]
+ fn eq(&self, other: &$Rhs) -> bool { &self[..] == &other[..] }
+ #[inline]
+ fn ne(&self, other: &$Rhs) -> bool { &self[..] != &other[..] }
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ impl<'a, 'b, A: $Bound, B> PartialEq<$Lhs> for $Rhs where B: PartialEq<A> {
+ #[inline]
+ fn eq(&self, other: &$Lhs) -> bool { &self[..] == &other[..] }
+ #[inline]
+ fn ne(&self, other: &$Lhs) -> bool { &self[..] != &other[..] }
+ }
+ }
+}
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>;
self.fold(0, |cnt, _x| cnt + 1)
}
- /// Loops through the entire iterator, returning the last element of the
- /// iterator.
+ /// Loops through the entire iterator, returning the last element.
///
/// # Examples
///
/// ```
/// 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")]
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- fn all<F>(self, mut f: F) -> bool where F: FnMut(Self::Item) -> bool {
- for x in self { if !f(x) { return false; } }
+ fn all<F>(&mut self, mut f: F) -> bool where F: FnMut(Self::Item) -> bool {
+ for x in self.by_ref() { if !f(x) { return false; } }
true
}
#[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 }
}
for x in self.iter.by_ref() {
if (self.predicate)(&x) {
return Some(x);
- } else {
- continue
}
}
None
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 {
#![feature(staged_api)]
#![feature(unboxed_closures)]
#![feature(rustc_attrs)]
+#![feature(optin_builtin_traits)]
#[macro_use]
mod macros;
+#[macro_use]
+mod cmp_macros;
+
#[path = "num/float_macros.rs"]
#[macro_use]
mod float_macros;
panic!("explicit panic")
);
($msg:expr) => ({
- static _MSG_FILE_LINE: (&'static str, &'static str, usize) = ($msg, file!(), line!());
+ static _MSG_FILE_LINE: (&'static str, &'static str, u32) = ($msg, file!(), line!());
::core::panicking::panic(&_MSG_FILE_LINE)
});
($fmt:expr, $($arg:tt)*) => ({
// used inside a dead function. Just `#[allow(dead_code)]` is
// insufficient, since the user may have
// `#[forbid(dead_code)]` and which cannot be overridden.
- static _FILE_LINE: (&'static str, usize) = (file!(), line!());
+ static _FILE_LINE: (&'static str, u32) = (file!(), line!());
::core::panicking::panic_fmt(format_args!($fmt, $($arg)*), &_FILE_LINE)
});
}
// empty.
}
+impl<T> !Send for *const T { }
+impl<T> !Send for *mut T { }
+impl !Send for Managed { }
+
/// Types with a constant size known at compile-time.
#[stable(feature = "rust1", since = "1.0.0")]
#[lang="sized"]
// Empty
}
+impl<T> !Sync for *const T { }
+impl<T> !Sync for *mut T { }
+impl !Sync for Managed { }
+
/// A type which is considered "not POD", meaning that it is not
/// implicitly copyable. This is typically embedded in other types to
/// ensure that they are never copied, even if they lack a destructor.
/// any methods, but instead is used to gate access to data.
///
/// FIXME. Better documentation needed here!
-pub trait MarkerTrait : PhantomFn<Self> { }
+pub trait MarkerTrait : PhantomFn<Self,Self> { }
+// ~~~~~ <-- FIXME(#22806)?
+//
+// Marker trait has been made invariant so as to avoid inf recursion,
+// but we should ideally solve the underlying problem. That's a bit
+// complicated.
+
impl<T:?Sized> MarkerTrait for T { }
/// `PhantomFn` is a marker trait for use with traits that contain
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"]
-pub fn panic(expr_file_line: &(&'static str, &'static str, uint)) -> ! {
+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"]
-fn panic_bounds_check(file_line: &(&'static str, uint),
- index: uint, len: uint) -> ! {
+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 {}",
len, index), file_line)
}
#[cold] #[inline(never)]
-pub fn panic_fmt(fmt: fmt::Arguments, file_line: &(&'static str, uint)) -> ! {
+pub fn panic_fmt(fmt: fmt::Arguments, file_line: &(&'static str, u32)) -> ! {
#[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) }
+ unsafe { panic_impl(fmt, file, line as uint) }
}
// 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")]
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn or(self, res: Result<T, E>) -> Result<T, E> {
+ pub fn or<F>(self, res: Result<T, F>) -> Result<T, F> {
match self {
- Ok(_) => self,
+ Ok(v) => Ok(v),
Err(_) => res,
}
}
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;
fn next(&mut self) -> Option<$elem> {
// could be implemented with slices, but this avoids bounds checks
unsafe {
+ ::intrinsics::assume(!self.ptr.is_null());
+ ::intrinsics::assume(!self.end.is_null());
if self.ptr == self.end {
None
} else {
fn next_back(&mut self) -> Option<$elem> {
// could be implemented with slices, but this avoids bounds checks
unsafe {
+ ::intrinsics::assume(!self.ptr.is_null());
+ ::intrinsics::assume(!self.end.is_null());
if self.end == self.ptr {
None
} else {
_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);
}
}
}
#![doc(primitive = "str")]
-use self::Searcher::{Naive, TwoWay, TwoWayLong};
+use self::OldSearcher::{TwoWay, TwoWayLong};
use clone::Clone;
use cmp::{self, Eq};
use slice::{self, SliceExt};
use usize;
+pub use self::pattern::Pattern;
+pub use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher, SearchStep};
+
+mod pattern;
+
macro_rules! delegate_iter {
(exact $te:ty : $ti:ty) => {
delegate_iter!{$te : $ti}
};
(pattern $te:ty : $ti:ty) => {
#[stable(feature = "rust1", since = "1.0.0")]
- impl<'a, P: CharEq> Iterator for $ti {
+ impl<'a, P: Pattern<'a>> Iterator for $ti {
type Item = $te;
#[inline]
}
}
#[stable(feature = "rust1", since = "1.0.0")]
- impl<'a, P: CharEq> DoubleEndedIterator for $ti {
+ impl<'a, P: Pattern<'a>> DoubleEndedIterator for $ti
+ where P::Searcher: DoubleEndedSearcher<'a> {
#[inline]
fn next_back(&mut self) -> Option<$te> {
self.0.next_back()
};
(pattern forward $te:ty : $ti:ty) => {
#[stable(feature = "rust1", since = "1.0.0")]
- impl<'a, P: CharEq> Iterator for $ti {
+ impl<'a, P: Pattern<'a>> Iterator for $ti
+ where P::Searcher: DoubleEndedSearcher<'a> {
type Item = $te;
#[inline]
}
/// Something that can be used to compare against a character
-#[unstable(feature = "core",
- reason = "definition may change as pattern-related methods are stabilized")]
+#[unstable(feature = "core")]
+#[deprecated(since = "1.0.0",
+ reason = "use `Pattern` instead")]
+// NB: Rather than removing it, make it private and move it into self::pattern
pub trait CharEq {
/// Determine if the splitter should split at the given character
fn matches(&mut self, char) -> bool;
fn only_ascii(&self) -> bool;
}
+#[allow(deprecated) /* for CharEq */ ]
impl CharEq for char {
#[inline]
fn matches(&mut self, c: char) -> bool { *self == c }
fn only_ascii(&self) -> bool { (*self as u32) < 128 }
}
+#[allow(deprecated) /* for CharEq */ ]
impl<F> CharEq for F where F: FnMut(char) -> bool {
#[inline]
fn matches(&mut self, c: char) -> bool { (*self)(c) }
fn only_ascii(&self) -> bool { false }
}
+#[allow(deprecated) /* for CharEq */ ]
impl<'a> CharEq for &'a [char] {
#[inline]
+ #[allow(deprecated) /* for CharEq */ ]
fn matches(&mut self, c: char) -> bool {
self.iter().any(|&m| { let mut m = m; m.matches(c) })
}
#[inline]
+ #[allow(deprecated) /* for CharEq */ ]
fn only_ascii(&self) -> bool {
self.iter().all(|m| m.only_ascii())
}
/// Reads the next code point out of a byte iterator (assuming a
/// UTF-8-like encoding).
#[unstable(feature = "core")]
+#[inline]
pub fn next_code_point(bytes: &mut slice::Iter<u8>) -> Option<u32> {
// Decode UTF-8
let x = match bytes.next() {
Some(ch)
}
+/// Reads the last code point out of a byte iterator (assuming a
+/// UTF-8-like encoding).
+#[unstable(feature = "core")]
+#[inline]
+pub fn next_code_point_reverse(bytes: &mut slice::Iter<u8>) -> Option<u32> {
+ // Decode UTF-8
+ let w = match bytes.next_back() {
+ None => return None,
+ Some(&next_byte) if next_byte < 128 => return Some(next_byte as u32),
+ Some(&back_byte) => back_byte,
+ };
+
+ // Multibyte case follows
+ // Decode from a byte combination out of: [x [y [z w]]]
+ let mut ch;
+ let z = unwrap_or_0(bytes.next_back());
+ ch = utf8_first_byte!(z, 2);
+ if utf8_is_cont_byte!(z) {
+ let y = unwrap_or_0(bytes.next_back());
+ ch = utf8_first_byte!(y, 3);
+ if utf8_is_cont_byte!(y) {
+ let x = unwrap_or_0(bytes.next_back());
+ ch = utf8_first_byte!(x, 4);
+ ch = utf8_acc_cont_byte!(ch, y);
+ }
+ ch = utf8_acc_cont_byte!(ch, z);
+ }
+ ch = utf8_acc_cont_byte!(ch, w);
+
+ Some(ch)
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Iterator for Chars<'a> {
type Item = char;
impl<'a> DoubleEndedIterator for Chars<'a> {
#[inline]
fn next_back(&mut self) -> Option<char> {
- let w = match self.iter.next_back() {
- None => return None,
- Some(&back_byte) if back_byte < 128 => return Some(back_byte as char),
- Some(&back_byte) => back_byte,
- };
-
- // Multibyte case follows
- // Decode from a byte combination out of: [x [y [z w]]]
- let mut ch;
- let z = unwrap_or_0(self.iter.next_back());
- ch = utf8_first_byte!(z, 2);
- if utf8_is_cont_byte!(z) {
- let y = unwrap_or_0(self.iter.next_back());
- ch = utf8_first_byte!(y, 3);
- if utf8_is_cont_byte!(y) {
- let x = unwrap_or_0(self.iter.next_back());
- ch = utf8_first_byte!(x, 4);
- ch = utf8_acc_cont_byte!(ch, y);
+ next_code_point_reverse(&mut self.iter).map(|ch| {
+ // str invariant says `ch` is a valid Unicode Scalar Value
+ unsafe {
+ mem::transmute(ch)
}
- ch = utf8_acc_cont_byte!(ch, z);
- }
- ch = utf8_acc_cont_byte!(ch, w);
-
- // str invariant says `ch` is a valid Unicode Scalar Value
- unsafe {
- Some(mem::transmute(ch))
- }
+ })
}
}
}
/// An iterator over the substrings of a string, separated by `sep`.
-#[derive(Clone)]
-struct CharSplits<'a, Sep> {
+struct CharSplits<'a, P: Pattern<'a>> {
/// The slice remaining to be iterated
- string: &'a str,
- sep: Sep,
+ start: usize,
+ end: usize,
+ matcher: P::Searcher,
/// Whether an empty string at the end is allowed
allow_trailing_empty: bool,
- only_ascii: bool,
finished: bool,
}
/// An iterator over the substrings of a string, separated by `sep`,
/// splitting at most `count` times.
-#[derive(Clone)]
-struct CharSplitsN<'a, Sep> {
- iter: CharSplits<'a, Sep>,
+struct CharSplitsN<'a, P: Pattern<'a>> {
+ iter: CharSplits<'a, P>,
/// The number of splits remaining
count: usize,
invert: bool,
inner: Map<Lines<'a>, fn(&str) -> &str>,
}
-impl<'a, Sep> CharSplits<'a, Sep> {
+impl<'a, P: Pattern<'a>> CharSplits<'a, P> {
#[inline]
fn get_end(&mut self) -> Option<&'a str> {
- if !self.finished && (self.allow_trailing_empty || self.string.len() > 0) {
+ if !self.finished && (self.allow_trailing_empty || self.end - self.start > 0) {
self.finished = true;
- Some(self.string)
+ unsafe {
+ let string = self.matcher.haystack().slice_unchecked(self.start, self.end);
+ Some(string)
+ }
} else {
None
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, Sep: CharEq> Iterator for CharSplits<'a, Sep> {
+impl<'a, P: Pattern<'a>> Iterator for CharSplits<'a, P> {
type Item = &'a str;
#[inline]
fn next(&mut self) -> Option<&'a str> {
if self.finished { return None }
- let mut next_split = None;
- if self.only_ascii {
- for (idx, byte) in self.string.bytes().enumerate() {
- if self.sep.matches(byte as char) && byte < 128u8 {
- next_split = Some((idx, idx + 1));
- break;
- }
- }
- } else {
- for (idx, ch) in self.string.char_indices() {
- if self.sep.matches(ch) {
- next_split = Some((idx, self.string.char_range_at(idx).next));
- break;
- }
- }
- }
- match next_split {
+ let haystack = self.matcher.haystack();
+ match self.matcher.next_match() {
Some((a, b)) => unsafe {
- let elt = self.string.slice_unchecked(0, a);
- self.string = self.string.slice_unchecked(b, self.string.len());
+ let elt = haystack.slice_unchecked(self.start, a);
+ self.start = b;
Some(elt)
},
None => self.get_end(),
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, Sep: CharEq> DoubleEndedIterator for CharSplits<'a, Sep> {
+impl<'a, P: Pattern<'a>> DoubleEndedIterator for CharSplits<'a, P>
+where P::Searcher: DoubleEndedSearcher<'a> {
#[inline]
fn next_back(&mut self) -> Option<&'a str> {
if self.finished { return None }
_ => if self.finished { return None }
}
}
- let len = self.string.len();
- let mut next_split = None;
-
- if self.only_ascii {
- for (idx, byte) in self.string.bytes().enumerate().rev() {
- if self.sep.matches(byte as char) && byte < 128u8 {
- next_split = Some((idx, idx + 1));
- break;
- }
- }
- } else {
- for (idx, ch) in self.string.char_indices().rev() {
- if self.sep.matches(ch) {
- next_split = Some((idx, self.string.char_range_at(idx).next));
- break;
- }
- }
- }
- match next_split {
+
+ let haystack = self.matcher.haystack();
+ match self.matcher.next_match_back() {
Some((a, b)) => unsafe {
- let elt = self.string.slice_unchecked(b, len);
- self.string = self.string.slice_unchecked(0, a);
+ let elt = haystack.slice_unchecked(b, self.end);
+ self.end = a;
Some(elt)
},
- None => { self.finished = true; Some(self.string) }
+ None => unsafe {
+ self.finished = true;
+ Some(haystack.slice_unchecked(self.start, self.end))
+ },
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, Sep: CharEq> Iterator for CharSplitsN<'a, Sep> {
+impl<'a, P: Pattern<'a>> Iterator for CharSplitsN<'a, P>
+where P::Searcher: DoubleEndedSearcher<'a> {
type Item = &'a str;
#[inline]
}
}
-/// The internal state of an iterator that searches for matches of a substring
-/// within a larger string using naive search
-#[derive(Clone)]
-struct NaiveSearcher {
- position: usize
-}
-
-impl NaiveSearcher {
- fn new() -> NaiveSearcher {
- NaiveSearcher { position: 0 }
- }
-
- fn next(&mut self, haystack: &[u8], needle: &[u8]) -> Option<(usize, usize)> {
- while self.position + needle.len() <= haystack.len() {
- if &haystack[self.position .. self.position + needle.len()] == needle {
- let match_pos = self.position;
- self.position += needle.len(); // add 1 for all matches
- return Some((match_pos, match_pos + needle.len()));
- } else {
- self.position += 1;
- }
- }
- None
- }
-}
-
/// The internal state of an iterator that searches for matches of a substring
/// within a larger string using two-way search
#[derive(Clone)]
*/
impl TwoWaySearcher {
+ #[allow(dead_code)]
fn new(needle: &[u8]) -> TwoWaySearcher {
let (crit_pos_false, period_false) = TwoWaySearcher::maximal_suffix(needle, false);
let (crit_pos_true, period_true) = TwoWaySearcher::maximal_suffix(needle, true);
// Specifically, returns (i, p), where i is the starting index of v in some
// critical factorization (u, v) and p = period(v)
#[inline]
+ #[allow(dead_code)]
fn maximal_suffix(arr: &[u8], reversed: bool) -> (usize, usize) {
let mut left = -1; // Corresponds to i in the paper
let mut right = 0; // Corresponds to j in the paper
/// The internal state of an iterator that searches for matches of a substring
/// within a larger string using a dynamically chosen search algorithm
#[derive(Clone)]
-enum Searcher {
- Naive(NaiveSearcher),
+// NB: This is kept around for convenience because
+// it is planned to be used again in the future
+enum OldSearcher {
TwoWay(TwoWaySearcher),
- TwoWayLong(TwoWaySearcher)
+ TwoWayLong(TwoWaySearcher),
}
-impl Searcher {
- fn new(haystack: &[u8], needle: &[u8]) -> Searcher {
+impl OldSearcher {
+ #[allow(dead_code)]
+ fn new(haystack: &[u8], needle: &[u8]) -> OldSearcher {
+ if needle.len() == 0 {
+ // Handle specially
+ unimplemented!()
// FIXME: Tune this.
// FIXME(#16715): This unsigned integer addition will probably not
// overflow because that would mean that the memory almost solely
// consists of the needle. Needs #16715 to be formally fixed.
- if needle.len() + 20 > haystack.len() {
- Naive(NaiveSearcher::new())
+ } else if needle.len() + 20 > haystack.len() {
+ // Use naive searcher
+ unimplemented!()
} else {
let searcher = TwoWaySearcher::new(needle);
if searcher.memory == usize::MAX { // If the period is long
}
}
-/// An iterator over the start and end indices of the matches of a
-/// substring within a larger string
#[derive(Clone)]
-#[unstable(feature = "core", reason = "type may be removed")]
-pub struct MatchIndices<'a> {
+// NB: This is kept around for convenience because
+// it is planned to be used again in the future
+struct OldMatchIndices<'a, 'b> {
// constants
haystack: &'a str,
- needle: &'a str,
- searcher: Searcher
+ needle: &'b str,
+ searcher: OldSearcher
}
-/// An iterator over the substrings of a string separated by a given
-/// search string
-#[derive(Clone)]
+// FIXME: #21637 Prevents a Clone impl
+/// An iterator over the start and end indices of the matches of a
+/// substring within a larger string
#[unstable(feature = "core", reason = "type may be removed")]
-pub struct SplitStr<'a> {
- it: MatchIndices<'a>,
- last_end: usize,
- finished: bool
-}
+pub struct MatchIndices<'a, P: Pattern<'a>>(P::Searcher);
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> Iterator for MatchIndices<'a> {
+impl<'a, P: Pattern<'a>> Iterator for MatchIndices<'a, P> {
type Item = (usize, usize);
#[inline]
fn next(&mut self) -> Option<(usize, usize)> {
- match self.searcher {
- Naive(ref mut searcher)
- => searcher.next(self.haystack.as_bytes(), self.needle.as_bytes()),
- TwoWay(ref mut searcher)
- => searcher.next(self.haystack.as_bytes(), self.needle.as_bytes(), false),
- TwoWayLong(ref mut searcher)
- => searcher.next(self.haystack.as_bytes(), self.needle.as_bytes(), true)
- }
+ self.0.next_match()
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> Iterator for SplitStr<'a> {
+/// An iterator over the substrings of a string separated by a given
+/// search string
+#[unstable(feature = "core")]
+#[deprecated(since = "1.0.0", reason = "use `Split` with a `&str`")]
+pub struct SplitStr<'a, P: Pattern<'a>>(Split<'a, P>);
+impl<'a, P: Pattern<'a>> Iterator for SplitStr<'a, P> {
type Item = &'a str;
#[inline]
+ #[allow(deprecated)]
fn next(&mut self) -> Option<&'a str> {
- if self.finished { return None; }
+ Iterator::next(&mut self.0)
+ }
+}
- match self.it.next() {
- Some((from, to)) => {
- let ret = Some(&self.it.haystack[self.last_end .. from]);
- self.last_end = to;
- ret
- }
- None => {
- self.finished = true;
- Some(&self.it.haystack[self.last_end .. self.it.haystack.len()])
- }
+impl<'a, 'b> OldMatchIndices<'a, 'b> {
+ #[inline]
+ #[allow(dead_code)]
+ fn next(&mut self) -> Option<(usize, usize)> {
+ match self.searcher {
+ TwoWay(ref mut searcher)
+ => searcher.next(self.haystack.as_bytes(), self.needle.as_bytes(), false),
+ TwoWayLong(ref mut searcher)
+ => searcher.next(self.haystack.as_bytes(), self.needle.as_bytes(), true),
}
}
}
-
/*
Section: Comparing strings
*/
}
/// Return type of `StrExt::split`
-#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Split<'a, P>(CharSplits<'a, P>);
-delegate_iter!{pattern &'a str : Split<'a, P>}
+pub struct Split<'a, P: Pattern<'a>>(CharSplits<'a, P>);
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, P: Pattern<'a>> Iterator for Split<'a, P> {
+ type Item = &'a str;
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a str> {
+ self.0.next()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, P: Pattern<'a>> DoubleEndedIterator for Split<'a, P>
+where P::Searcher: DoubleEndedSearcher<'a> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a str> {
+ self.0.next_back()
+ }
+}
/// Return type of `StrExt::split_terminator`
-#[derive(Clone)]
-#[unstable(feature = "core",
- reason = "might get removed in favour of a constructor method on Split")]
-pub struct SplitTerminator<'a, P>(CharSplits<'a, P>);
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SplitTerminator<'a, P: Pattern<'a>>(CharSplits<'a, P>);
delegate_iter!{pattern &'a str : SplitTerminator<'a, P>}
/// Return type of `StrExt::splitn`
-#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct SplitN<'a, P>(CharSplitsN<'a, P>);
+pub struct SplitN<'a, P: Pattern<'a>>(CharSplitsN<'a, P>);
delegate_iter!{pattern forward &'a str : SplitN<'a, P>}
/// Return type of `StrExt::rsplitn`
-#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct RSplitN<'a, P>(CharSplitsN<'a, P>);
+pub struct RSplitN<'a, P: Pattern<'a>>(CharSplitsN<'a, P>);
delegate_iter!{pattern forward &'a str : RSplitN<'a, P>}
/// Methods for string slices
// NB there are no docs here are they're all located on the StrExt trait in
// libcollections, not here.
- fn contains(&self, pat: &str) -> bool;
- fn contains_char<P: CharEq>(&self, pat: P) -> bool;
+ fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool;
+ fn contains_char<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool;
fn chars<'a>(&'a self) -> Chars<'a>;
fn bytes<'a>(&'a self) -> Bytes<'a>;
fn char_indices<'a>(&'a self) -> CharIndices<'a>;
- fn split<'a, P: CharEq>(&'a self, pat: P) -> Split<'a, P>;
- fn splitn<'a, P: CharEq>(&'a self, count: usize, pat: P) -> SplitN<'a, P>;
- fn split_terminator<'a, P: CharEq>(&'a self, pat: P) -> SplitTerminator<'a, P>;
- fn rsplitn<'a, P: CharEq>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>;
- fn match_indices<'a>(&'a self, sep: &'a str) -> MatchIndices<'a>;
- fn split_str<'a>(&'a self, pat: &'a str) -> SplitStr<'a>;
+ fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P>;
+ fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P>;
+ fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P>;
+ fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>;
+ fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P>;
+ fn split_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitStr<'a, P>;
fn lines<'a>(&'a self) -> Lines<'a>;
fn lines_any<'a>(&'a self) -> LinesAny<'a>;
fn char_len(&self) -> usize;
fn slice_chars<'a>(&'a self, begin: usize, end: usize) -> &'a str;
unsafe fn slice_unchecked<'a>(&'a self, begin: usize, end: usize) -> &'a str;
- fn starts_with(&self, pat: &str) -> bool;
- fn ends_with(&self, pat: &str) -> bool;
- fn trim_matches<'a, P: CharEq>(&'a self, pat: P) -> &'a str;
- fn trim_left_matches<'a, P: CharEq>(&'a self, pat: P) -> &'a str;
- fn trim_right_matches<'a, P: CharEq>(&'a self, pat: P) -> &'a str;
+ fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool;
+ fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
+ where P::Searcher: ReverseSearcher<'a>;
+ fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
+ where P::Searcher: DoubleEndedSearcher<'a>;
+ fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str;
+ fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
+ where P::Searcher: ReverseSearcher<'a>;
fn is_char_boundary(&self, index: usize) -> bool;
fn char_range_at(&self, start: usize) -> CharRange;
fn char_range_at_reverse(&self, start: usize) -> CharRange;
fn char_at(&self, i: usize) -> char;
fn char_at_reverse(&self, i: usize) -> char;
fn as_bytes<'a>(&'a self) -> &'a [u8];
- fn find<P: CharEq>(&self, pat: P) -> Option<usize>;
- fn rfind<P: CharEq>(&self, pat: P) -> Option<usize>;
- fn find_str(&self, pat: &str) -> Option<usize>;
+ fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>;
+ fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
+ where P::Searcher: ReverseSearcher<'a>;
+ fn find_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>;
fn slice_shift_char<'a>(&'a self) -> Option<(char, &'a str)>;
fn subslice_offset(&self, inner: &str) -> usize;
fn as_ptr(&self) -> *const u8;
impl StrExt for str {
#[inline]
- fn contains(&self, needle: &str) -> bool {
- self.find_str(needle).is_some()
+ fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
+ pat.is_contained_in(self)
}
#[inline]
- fn contains_char<P: CharEq>(&self, pat: P) -> bool {
- self.find(pat).is_some()
+ fn contains_char<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
+ pat.is_contained_in(self)
}
#[inline]
}
#[inline]
- fn split<P: CharEq>(&self, pat: P) -> Split<P> {
+ fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
Split(CharSplits {
- string: self,
- only_ascii: pat.only_ascii(),
- sep: pat,
+ start: 0,
+ end: self.len(),
+ matcher: pat.into_searcher(self),
allow_trailing_empty: true,
finished: false,
})
}
#[inline]
- fn splitn<P: CharEq>(&self, count: usize, pat: P) -> SplitN<P> {
+ fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> {
SplitN(CharSplitsN {
iter: self.split(pat).0,
count: count,
}
#[inline]
- fn split_terminator<P: CharEq>(&self, pat: P) -> SplitTerminator<P> {
+ fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> {
SplitTerminator(CharSplits {
allow_trailing_empty: false,
..self.split(pat).0
}
#[inline]
- fn rsplitn<P: CharEq>(&self, count: usize, pat: P) -> RSplitN<P> {
+ fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> {
RSplitN(CharSplitsN {
iter: self.split(pat).0,
count: count,
}
#[inline]
- fn match_indices<'a>(&'a self, sep: &'a str) -> MatchIndices<'a> {
- assert!(!sep.is_empty());
- MatchIndices {
- haystack: self,
- needle: sep,
- searcher: Searcher::new(self.as_bytes(), sep.as_bytes())
- }
+ fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
+ MatchIndices(pat.into_searcher(self))
}
#[inline]
- fn split_str<'a>(&'a self, sep: &'a str) -> SplitStr<'a> {
- SplitStr {
- it: self.match_indices(sep),
- last_end: 0,
- finished: false
- }
+ #[allow(deprecated) /* for SplitStr */ ]
+ fn split_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitStr<'a, P> {
+ SplitStr(self.split(pat))
}
#[inline]
#[inline]
unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
mem::transmute(Slice {
- data: self.as_ptr().offset(begin as isize),
+ data: self.as_ptr().offset(begin as int),
len: end - begin,
})
}
#[inline]
- fn starts_with(&self, needle: &str) -> bool {
- let n = needle.len();
- self.len() >= n && needle.as_bytes() == &self.as_bytes()[..n]
+ fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
+ pat.is_prefix_of(self)
}
#[inline]
- fn ends_with(&self, needle: &str) -> bool {
- let (m, n) = (self.len(), needle.len());
- m >= n && needle.as_bytes() == &self.as_bytes()[m-n..]
+ fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ pat.is_suffix_of(self)
}
#[inline]
- fn trim_matches<P: CharEq>(&self, mut pat: P) -> &str {
- let cur = match self.find(|c: char| !pat.matches(c)) {
- None => "",
- Some(i) => unsafe { self.slice_unchecked(i, self.len()) }
- };
- match cur.rfind(|c: char| !pat.matches(c)) {
- None => "",
- Some(i) => {
- let right = cur.char_range_at(i).next;
- unsafe { cur.slice_unchecked(0, right) }
- }
+ fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
+ where P::Searcher: DoubleEndedSearcher<'a>
+ {
+ let mut i = 0;
+ let mut j = 0;
+ let mut matcher = pat.into_searcher(self);
+ if let Some((a, b)) = matcher.next_reject() {
+ i = a;
+ j = b; // Rember earliest known match, correct it below if
+ // last match is different
+ }
+ if let Some((_, b)) = matcher.next_reject_back() {
+ j = b;
+ }
+ unsafe {
+ // Searcher is known to return valid indices
+ self.slice_unchecked(i, j)
}
}
#[inline]
- fn trim_left_matches<P: CharEq>(&self, mut pat: P) -> &str {
- match self.find(|c: char| !pat.matches(c)) {
- None => "",
- Some(first) => unsafe { self.slice_unchecked(first, self.len()) }
+ fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
+ let mut i = self.len();
+ let mut matcher = pat.into_searcher(self);
+ if let Some((a, _)) = matcher.next_reject() {
+ i = a;
+ }
+ unsafe {
+ // Searcher is known to return valid indices
+ self.slice_unchecked(i, self.len())
}
}
#[inline]
- fn trim_right_matches<P: CharEq>(&self, mut pat: P) -> &str {
- match self.rfind(|c: char| !pat.matches(c)) {
- None => "",
- Some(last) => {
- let next = self.char_range_at(last).next;
- unsafe { self.slice_unchecked(0, next) }
- }
+ fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ let mut j = 0;
+ let mut matcher = pat.into_searcher(self);
+ if let Some((_, b)) = matcher.next_reject_back() {
+ j = b;
+ }
+ unsafe {
+ // Searcher is known to return valid indices
+ self.slice_unchecked(0, j)
}
}
unsafe { mem::transmute(self) }
}
- fn find<P: CharEq>(&self, mut pat: P) -> Option<usize> {
- if pat.only_ascii() {
- self.bytes().position(|b| pat.matches(b as char))
- } else {
- for (index, c) in self.char_indices() {
- if pat.matches(c) { return Some(index); }
- }
- None
- }
+ fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
+ pat.into_searcher(self).next_match().map(|(i, _)| i)
}
- fn rfind<P: CharEq>(&self, mut pat: P) -> Option<usize> {
- if pat.only_ascii() {
- self.bytes().rposition(|b| pat.matches(b as char))
- } else {
- for (index, c) in self.char_indices().rev() {
- if pat.matches(c) { return Some(index); }
- }
- None
- }
+ fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ pat.into_searcher(self).next_match_back().map(|(i, _)| i)
}
- fn find_str(&self, needle: &str) -> Option<usize> {
- if needle.is_empty() {
- Some(0)
- } else {
- self.match_indices(needle)
- .next()
- .map(|(start, _end)| start)
- }
+ fn find_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
+ self.find(pat)
}
#[inline]
--- /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(deprecated) /* for CharEq */ ]
+
+use prelude::*;
+use super::CharEq;
+
+// Pattern
+
+/// A string pattern.
+///
+/// A `Pattern<'a>` expresses that the implementing type
+/// can be used as a string pattern for searching in a `&'a str`.
+///
+/// For example, both `'a'` and `"aa"` are patterns that
+/// would match at index `1` in the string `"baaaab"`.
+///
+/// The trait itself acts as a builder for an associated
+/// `Searcher` type, which does the actual work of finding
+/// occurences of the pattern in a string.
+pub trait Pattern<'a>: Sized {
+ /// Associated searcher for this pattern
+ type Searcher: Searcher<'a>;
+
+ /// Construct the associated searcher from
+ /// `self` and the `haystack` to search in.
+ fn into_searcher(self, haystack: &'a str) -> Self::Searcher;
+
+ /// Check whether the pattern matches anywhere in the haystack
+ #[inline]
+ fn is_contained_in(self, haystack: &'a str) -> bool {
+ self.into_searcher(haystack).next_match().is_some()
+ }
+
+ /// Check whether the pattern matches at the front of the haystack
+ #[inline]
+ fn is_prefix_of(self, haystack: &'a str) -> bool {
+ match self.into_searcher(haystack).next() {
+ SearchStep::Match(0, _) => true,
+ _ => false,
+ }
+ }
+
+ /// Check whether the pattern matches at the back of the haystack
+ #[inline]
+ fn is_suffix_of(self, haystack: &'a str) -> bool
+ where Self::Searcher: ReverseSearcher<'a>
+ {
+ match self.into_searcher(haystack).next_back() {
+ SearchStep::Match(_, j) if haystack.len() == j => true,
+ _ => false,
+ }
+ }
+}
+
+// Searcher
+
+/// Result of calling `Searcher::next()` or `ReverseSearcher::next_back()`.
+#[derive(Copy, Clone, Eq, PartialEq, Debug)]
+pub enum SearchStep {
+ /// Expresses that a match of the pattern has been found at
+ /// `haystack[a..b]`.
+ Match(usize, usize),
+ /// Expresses that `haystack[a..b]` has been rejected as a possible match
+ /// of the pattern.
+ ///
+ /// Note that there might be more than one `Reject` betwen two `Match`es,
+ /// there is no requirement for them to be combined into one.
+ Reject(usize, usize),
+ /// Expresses that every byte of the haystack has been visted, ending
+ /// the iteration.
+ Done
+}
+
+/// A searcher for a string pattern.
+///
+/// This trait provides methods for searching for non-overlapping
+/// matches of a pattern starting from the front (left) of a string.
+///
+/// It will be implemented by associated `Searcher`
+/// types of the `Pattern` trait.
+///
+/// The trait is marked unsafe because the indices returned by the
+/// `next()` methods are required to lie on valid utf8 boundaries in
+/// the haystack. This enables consumers of this trait to
+/// slice the haystack without additional runtime checks.
+pub unsafe trait Searcher<'a> {
+ /// Getter for the underlaying string to be searched in
+ ///
+ /// Will always return the same `&str`
+ fn haystack(&self) -> &'a str;
+
+ /// Performs the next search step starting from the front.
+ ///
+ /// - Returns `Match(a, b)` if `haystack[a..b]` matches the pattern.
+ /// - Returns `Reject(a, b)` if `haystack[a..b]` can not match the
+ /// pattern, even partially.
+ /// - Returns `Done` if every byte of the haystack has been visited
+ ///
+ /// The stream of `Match` and `Reject` values up to a `Done`
+ /// will contain index ranges that are adjacent, non-overlapping,
+ /// covering the whole haystack, and laying on utf8 boundaries.
+ ///
+ /// A `Match` result needs to contain the whole matched pattern,
+ /// however `Reject` results may be split up into arbitrary
+ /// many adjacent fragments. Both ranges may have zero length.
+ ///
+ /// As an example, the pattern `"aaa"` and the haystack `"cbaaaaab"`
+ /// might produce the stream
+ /// `[Reject(0, 1), Reject(1, 2), Match(2, 5), Reject(5, 8)]`
+ fn next(&mut self) -> SearchStep;
+
+ /// Find the next `Match` result. See `next()`
+ #[inline]
+ fn next_match(&mut self) -> Option<(usize, usize)> {
+ loop {
+ match self.next() {
+ SearchStep::Match(a, b) => return Some((a, b)),
+ SearchStep::Done => return None,
+ _ => continue,
+ }
+ }
+ }
+
+ /// Find the next `Reject` result. See `next()`
+ #[inline]
+ fn next_reject(&mut self) -> Option<(usize, usize)> {
+ loop {
+ match self.next() {
+ SearchStep::Reject(a, b) => return Some((a, b)),
+ SearchStep::Done => return None,
+ _ => continue,
+ }
+ }
+ }
+}
+
+/// A reverse searcher for a string pattern.
+///
+/// This trait provides methods for searching for non-overlapping
+/// matches of a pattern starting from the back (right) of a string.
+///
+/// It will be implemented by associated `Searcher`
+/// types of the `Pattern` trait if the pattern supports searching
+/// for it from the back.
+///
+/// The index ranges returned by this trait are not required
+/// to exactly match those of the forward search in reverse.
+///
+/// For the reason why this trait is marked unsafe, see them
+/// parent trait `Searcher`.
+pub unsafe trait ReverseSearcher<'a>: Searcher<'a> {
+ /// Performs the next search step starting from the back.
+ ///
+ /// - Returns `Match(a, b)` if `haystack[a..b]` matches the pattern.
+ /// - Returns `Reject(a, b)` if `haystack[a..b]` can not match the
+ /// pattern, even partially.
+ /// - Returns `Done` if every byte of the haystack has been visited
+ ///
+ /// The stream of `Match` and `Reject` values up to a `Done`
+ /// will contain index ranges that are adjacent, non-overlapping,
+ /// covering the whole haystack, and laying on utf8 boundaries.
+ ///
+ /// A `Match` result needs to contain the whole matched pattern,
+ /// however `Reject` results may be split up into arbitrary
+ /// many adjacent fragments. Both ranges may have zero length.
+ ///
+ /// As an example, the pattern `"aaa"` and the haystack `"cbaaaaab"`
+ /// might produce the stream
+ /// `[Reject(7, 8), Match(4, 7), Reject(1, 4), Reject(0, 1)]`
+ fn next_back(&mut self) -> SearchStep;
+
+ /// Find the next `Match` result. See `next_back()`
+ #[inline]
+ fn next_match_back(&mut self) -> Option<(usize, usize)>{
+ loop {
+ match self.next_back() {
+ SearchStep::Match(a, b) => return Some((a, b)),
+ SearchStep::Done => return None,
+ _ => continue,
+ }
+ }
+ }
+
+ /// Find the next `Reject` result. See `next_back()`
+ #[inline]
+ fn next_reject_back(&mut self) -> Option<(usize, usize)>{
+ loop {
+ match self.next_back() {
+ SearchStep::Reject(a, b) => return Some((a, b)),
+ SearchStep::Done => return None,
+ _ => continue,
+ }
+ }
+ }
+}
+
+/// A marker trait to express that a `ReverseSearcher`
+/// can be used for a `DoubleEndedIterator` implementation.
+///
+/// For this, the impl of `Searcher` and `ReverseSearcher` need
+/// to follow these conditions:
+///
+/// - All results of `next()` need to be identical
+/// to the results of `next_back()` in reverse order.
+/// - `next()` and `next_back()` need to behave as
+/// the two ends of a range of values, that is they
+/// can not "walk past each other".
+///
+/// # Example
+///
+/// `char::Searcher` is a `DoubleEndedSearcher` because searching for a
+/// `char` only requires looking at one at a time, which behaves the same
+/// from both ends.
+///
+/// `(&str)::Searcher` is not a `DoubleEndedSearcher` because
+/// the pattern `"aa"` in the haystack `"aaa"` matches as either
+/// `"[aa]a"` or `"a[aa]"`, depending from which side it is searched.
+pub trait DoubleEndedSearcher<'a>: ReverseSearcher<'a> {}
+
+// Impl for a CharEq wrapper
+
+struct CharEqPattern<C: CharEq>(C);
+
+struct CharEqSearcher<'a, C: CharEq> {
+ char_eq: C,
+ haystack: &'a str,
+ char_indices: super::CharIndices<'a>,
+ #[allow(dead_code)]
+ ascii_only: bool,
+}
+
+impl<'a, C: CharEq> Pattern<'a> for CharEqPattern<C> {
+ type Searcher = CharEqSearcher<'a, C>;
+
+ #[inline]
+ fn into_searcher(self, haystack: &'a str) -> CharEqSearcher<'a, C> {
+ CharEqSearcher {
+ ascii_only: self.0.only_ascii(),
+ haystack: haystack,
+ char_eq: self.0,
+ char_indices: haystack.char_indices(),
+ }
+ }
+}
+
+unsafe impl<'a, C: CharEq> Searcher<'a> for CharEqSearcher<'a, C> {
+ #[inline]
+ fn haystack(&self) -> &'a str {
+ self.haystack
+ }
+
+ #[inline]
+ fn next(&mut self) -> SearchStep {
+ let s = &mut self.char_indices;
+ // Compare lengths of the internal byte slice iterator
+ // to find length of current char
+ let (pre_len, _) = s.iter.iter.size_hint();
+ if let Some((i, c)) = s.next() {
+ let (len, _) = s.iter.iter.size_hint();
+ let char_len = pre_len - len;
+ if self.char_eq.matches(c) {
+ return SearchStep::Match(i, i + char_len);
+ } else {
+ return SearchStep::Reject(i, i + char_len);
+ }
+ }
+ SearchStep::Done
+ }
+}
+
+unsafe impl<'a, C: CharEq> ReverseSearcher<'a> for CharEqSearcher<'a, C> {
+ #[inline]
+ fn next_back(&mut self) -> SearchStep {
+ let s = &mut self.char_indices;
+ // Compare lengths of the internal byte slice iterator
+ // to find length of current char
+ let (pre_len, _) = s.iter.iter.size_hint();
+ if let Some((i, c)) = s.next_back() {
+ let (len, _) = s.iter.iter.size_hint();
+ let char_len = pre_len - len;
+ if self.char_eq.matches(c) {
+ return SearchStep::Match(i, i + char_len);
+ } else {
+ return SearchStep::Reject(i, i + char_len);
+ }
+ }
+ SearchStep::Done
+ }
+}
+
+impl<'a, C: CharEq> DoubleEndedSearcher<'a> for CharEqSearcher<'a, C> {}
+
+// Impl for &str
+
+// Todo: Optimize the naive implementation here
+
+#[derive(Clone)]
+struct StrSearcher<'a, 'b> {
+ haystack: &'a str,
+ needle: &'b str,
+ start: usize,
+ end: usize,
+ done: bool,
+}
+
+/// Non-allocating substring search.
+///
+/// Will handle the pattern `""` as returning empty matches at each utf8
+/// boundary.
+impl<'a, 'b> Pattern<'a> for &'b str {
+ type Searcher = StrSearcher<'a, 'b>;
+
+ #[inline]
+ fn into_searcher(self, haystack: &'a str) -> StrSearcher<'a, 'b> {
+ StrSearcher {
+ haystack: haystack,
+ needle: self,
+ start: 0,
+ end: haystack.len(),
+ done: false,
+ }
+ }
+}
+
+unsafe impl<'a, 'b> Searcher<'a> for StrSearcher<'a, 'b> {
+ #[inline]
+ fn haystack(&self) -> &'a str {
+ self.haystack
+ }
+
+ #[inline]
+ fn next(&mut self) -> SearchStep {
+ str_search_step(self,
+ |m: &mut StrSearcher| {
+ // Forward step for empty needle
+ let current_start = m.start;
+ if !m.done {
+ m.start = m.haystack.char_range_at(current_start).next;
+ }
+ SearchStep::Match(current_start, current_start)
+ },
+ |m: &mut StrSearcher| {
+ // Forward step for nonempty needle
+ let current_start = m.start;
+ // Compare byte window because this might break utf8 boundaries
+ let possible_match = &m.haystack.as_bytes()[m.start .. m.start + m.needle.len()];
+ if possible_match == m.needle.as_bytes() {
+ m.start += m.needle.len();
+ SearchStep::Match(current_start, m.start)
+ } else {
+ // Skip a char
+ let haystack_suffix = &m.haystack[m.start..];
+ m.start += haystack_suffix.chars().next().unwrap().len_utf8();
+ SearchStep::Reject(current_start, m.start)
+ }
+ })
+ }
+}
+
+unsafe impl<'a, 'b> ReverseSearcher<'a> for StrSearcher<'a, 'b> {
+ #[inline]
+ fn next_back(&mut self) -> SearchStep {
+ str_search_step(self,
+ |m: &mut StrSearcher| {
+ // Backward step for empty needle
+ let current_end = m.end;
+ if !m.done {
+ m.end = m.haystack.char_range_at_reverse(current_end).next;
+ }
+ SearchStep::Match(current_end, current_end)
+ },
+ |m: &mut StrSearcher| {
+ // Backward step for nonempty needle
+ let current_end = m.end;
+ // Compare byte window because this might break utf8 boundaries
+ let possible_match = &m.haystack.as_bytes()[m.end - m.needle.len() .. m.end];
+ if possible_match == m.needle.as_bytes() {
+ m.end -= m.needle.len();
+ SearchStep::Match(m.end, current_end)
+ } else {
+ // Skip a char
+ let haystack_prefix = &m.haystack[..m.end];
+ m.end -= haystack_prefix.chars().rev().next().unwrap().len_utf8();
+ SearchStep::Reject(m.end, current_end)
+ }
+ })
+ }
+}
+
+// Helper function for encapsulating the common control flow
+// of doing a search step from the front or doing a search step from the back
+fn str_search_step<F, G>(mut m: &mut StrSearcher,
+ empty_needle_step: F,
+ nonempty_needle_step: G) -> SearchStep
+ where F: FnOnce(&mut StrSearcher) -> SearchStep,
+ G: FnOnce(&mut StrSearcher) -> SearchStep
+{
+ if m.done {
+ SearchStep::Done
+ } else if m.needle.len() == 0 && m.start <= m.end {
+ // Case for needle == ""
+ if m.start == m.end {
+ m.done = true;
+ }
+ empty_needle_step(&mut m)
+ } else if m.start + m.needle.len() <= m.end {
+ // Case for needle != ""
+ nonempty_needle_step(&mut m)
+ } else if m.start < m.end {
+ // Remaining slice shorter than needle, reject it
+ m.done = true;
+ SearchStep::Reject(m.start, m.end)
+ } else {
+ m.done = true;
+ SearchStep::Done
+ }
+}
+
+macro_rules! associated_items {
+ ($t:ty, $s:ident, $e:expr) => {
+ // FIXME: #22463
+ //type Searcher = $t;
+
+ fn into_searcher(self, haystack: &'a str) -> $t {
+ let $s = self;
+ $e.into_searcher(haystack)
+ }
+
+ #[inline]
+ fn is_contained_in(self, haystack: &'a str) -> bool {
+ let $s = self;
+ $e.is_contained_in(haystack)
+ }
+
+ #[inline]
+ fn is_prefix_of(self, haystack: &'a str) -> bool {
+ let $s = self;
+ $e.is_prefix_of(haystack)
+ }
+
+ // FIXME: #21750
+ /*#[inline]
+ fn is_suffix_of(self, haystack: &'a str) -> bool
+ where $t: ReverseSearcher<'a>
+ {
+ let $s = self;
+ $e.is_suffix_of(haystack)
+ }*/
+ }
+}
+
+// CharEq delegation impls
+
+/// Searches for chars that are equal to a given char
+impl<'a> Pattern<'a> for char {
+ type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
+ associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
+ s, CharEqPattern(s));
+}
+
+/// Searches for chars that are equal to any of the chars in the array
+impl<'a, 'b> Pattern<'a> for &'b [char] {
+ type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
+ associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
+ s, CharEqPattern(s));
+}
+
+/// Searches for chars that match the given predicate
+impl<'a, F> Pattern<'a> for F where F: FnMut(char) -> bool {
+ type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
+ associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
+ s, CharEqPattern(s));
+}
+
+// Deref-forward impl
+
+use ops::Deref;
+
+/// Delegates to the next deref coercion of `Self` that implements `Pattern`
+impl<'a, 'b, P: 'b + ?Sized, T: Deref<Target = P> + ?Sized> Pattern<'a> for &'b T
+ where &'b P: Pattern<'a>
+{
+ type Searcher = <&'b P as Pattern<'a>>::Searcher;
+ associated_items!(<&'b P as Pattern<'a>>::Searcher,
+ s, (&**s));
+}
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]);
}
}
#[test]
pub fn test_or() {
- assert_eq!(op1().or(Ok(667)).unwrap(), 666);
+ assert_eq!(op1().or(Ok::<_, &'static str>(667)).unwrap(), 666);
assert_eq!(op1().or(Err("bad")).unwrap(), 666);
- assert_eq!(op2().or(Ok(667)).unwrap(), 667);
+ assert_eq!(op2().or(Ok::<_, &'static str>(667)).unwrap(), 667);
assert_eq!(op2().or(Err("bad")).unwrap_err(), "bad");
}
let mut iter = data.iter_mut();
assert_eq!(&iter[..], &other_data[..]);
// mutability:
- assert!(&mut iter[] == other_data);
+ assert!(&mut iter[..] == other_data);
iter.next();
assert_eq!(&iter[..], &other_data[1..]);
- assert!(&mut iter[] == &mut other_data[1..]);
+ assert!(&mut iter[..] == &mut other_data[1..]);
iter.next_back();
assert_eq!(&iter[..], &other_data[1..2]);
- assert!(&mut iter[] == &mut other_data[1..2]);
+ assert!(&mut iter[..] == &mut other_data[1..2]);
let s = iter.into_slice();
assert!(s == &mut other_data[1..2]);
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2014-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.
+#[test]
+fn test_pattern_deref_forward() {
+ let data = "aabcdaa";
+ assert!(data.contains("bcd"));
+ assert!(data.contains(&"bcd"));
+ assert!(data.contains(&&"bcd"));
+ assert!(data.contains(&"bcd".to_string()));
+ assert!(data.contains(&&"bcd".to_string()));
+}
+
+#[test]
+fn test_empty_match_indices() {
+ let data = "aä中!";
+ let vec: Vec<_> = data.match_indices("").collect();
+ assert_eq!(vec, [(0, 0), (1, 1), (3, 3), (6, 6), (7, 7)]);
+}
+
#[test]
fn test_bool_from_str() {
assert_eq!("true".parse().ok(), Some(true));
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]
+fn starts_with_in_unicode() {
+ assert!(!"├── Cargo.toml".starts_with("# "));
+}
+
+#[test]
+fn starts_short_long() {
+ assert!(!"".starts_with("##"));
+ assert!(!"##".starts_with("####"));
+ assert!("####".starts_with("##"));
+ assert!(!"##ä".starts_with("####"));
+ assert!("####ä".starts_with("##"));
+ assert!(!"##".starts_with("####ä"));
+ assert!("##ä##".starts_with("##ä"));
+
+ assert!("".starts_with(""));
+ assert!("ä".starts_with(""));
+ assert!("#ä".starts_with(""));
+ assert!("##ä".starts_with(""));
+ assert!("ä###".starts_with(""));
+ assert!("#ä##".starts_with(""));
+ assert!("##ä#".starts_with(""));
+}
+
+#[test]
+fn contains_weird_cases() {
+ assert!("* \t".contains_char(' '));
+ assert!(!"* \t".contains_char('?'));
+ assert!(!"* \t".contains_char('\u{1F4A9}'));
+}
+
+#[test]
+fn trim_ws() {
+ assert_eq!(" \t a \t ".trim_left_matches(|c: char| c.is_whitespace()),
+ "a \t ");
+ assert_eq!(" \t a \t ".trim_right_matches(|c: char| c.is_whitespace()),
+ " \t a");
+ assert_eq!(" \t a \t ".trim_matches(|c: char| c.is_whitespace()),
+ "a");
+ assert_eq!(" \t \t ".trim_left_matches(|c: char| c.is_whitespace()),
+ "");
+ assert_eq!(" \t \t ".trim_right_matches(|c: char| c.is_whitespace()),
+ "");
+ assert_eq!(" \t \t ".trim_matches(|c: char| c.is_whitespace()),
+ "");
+}
+
+mod pattern {
+ use std::str::Pattern;
+ use std::str::{Searcher, ReverseSearcher, DoubleEndedSearcher};
+ use std::str::SearchStep::{self, Match, Reject, Done};
+
+ macro_rules! make_test {
+ ($name:ident, $p:expr, $h:expr, [$($e:expr,)*]) => {
+ mod $name {
+ use std::str::Pattern;
+ use std::str::{Searcher, ReverseSearcher, DoubleEndedSearcher};
+ use std::str::SearchStep::{self, Match, Reject, Done};
+ use super::{cmp_search_to_vec};
+ #[test]
+ fn fwd() {
+ cmp_search_to_vec(false, $p, $h, vec![$($e),*]);
+ }
+ #[test]
+ fn bwd() {
+ cmp_search_to_vec(true, $p, $h, vec![$($e),*]);
+ }
+ }
+ }
+ }
+
+ fn cmp_search_to_vec<'a, P: Pattern<'a>>(rev: bool, pat: P, haystack: &'a str,
+ right: Vec<SearchStep>)
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ let mut searcher = pat.into_searcher(haystack);
+ let mut v = vec![];
+ loop {
+ match if !rev {searcher.next()} else {searcher.next_back()} {
+ Match(a, b) => v.push(Match(a, b)),
+ Reject(a, b) => v.push(Reject(a, b)),
+ Done => break,
+ }
+ }
+ if rev {
+ v.reverse();
+ }
+ assert_eq!(v, right);
+ }
+
+ make_test!(str_searcher_ascii_haystack, "bb", "abbcbbd", [
+ Reject(0, 1),
+ Match (1, 3),
+ Reject(3, 4),
+ Match (4, 6),
+ Reject(6, 7),
+ ]);
+ make_test!(str_searcher_empty_needle_ascii_haystack, "", "abbcbbd", [
+ Match(0, 0),
+ Match(1, 1),
+ Match(2, 2),
+ Match(3, 3),
+ Match(4, 4),
+ Match(5, 5),
+ Match(6, 6),
+ Match(7, 7),
+ ]);
+ make_test!(str_searcher_mulibyte_haystack, " ", "├──", [
+ Reject(0, 3),
+ Reject(3, 6),
+ Reject(6, 9),
+ ]);
+ make_test!(str_searcher_empty_needle_mulibyte_haystack, "", "├──", [
+ Match(0, 0),
+ Match(3, 3),
+ Match(6, 6),
+ Match(9, 9),
+ ]);
+ make_test!(str_searcher_empty_needle_empty_haystack, "", "", [
+ Match(0, 0),
+ ]);
+ make_test!(str_searcher_nonempty_needle_empty_haystack, "├", "", [
+ ]);
+ make_test!(char_searcher_ascii_haystack, 'b', "abbcbbd", [
+ Reject(0, 1),
+ Match (1, 2),
+ Match (2, 3),
+ Reject(3, 4),
+ Match (4, 5),
+ Match (5, 6),
+ Reject(6, 7),
+ ]);
+ make_test!(char_searcher_mulibyte_haystack, ' ', "├──", [
+ Reject(0, 3),
+ Reject(3, 6),
+ Reject(6, 9),
+ ]);
+ make_test!(char_searcher_short_haystack, '\u{1F4A9}', "* \t", [
+ Reject(0, 1),
+ Reject(1, 2),
+ Reject(2, 3),
+ ]);
+
+}
+
+mod bench {
+ macro_rules! make_test_inner {
+ ($s:ident, $code:expr, $name:ident, $str:expr) => {
+ #[bench]
+ fn $name(bencher: &mut Bencher) {
+ let mut $s = $str;
+ black_box(&mut $s);
+ bencher.iter(|| $code);
+ }
+ }
+ }
+
+ macro_rules! make_test {
+ ($name:ident, $s:ident, $code:expr) => {
+ mod $name {
+ use test::Bencher;
+ use test::black_box;
+
+ // Short strings: 65 bytes each
+ make_test_inner!($s, $code, short_ascii,
+ "Mary had a little lamb, Little lamb Mary had a littl lamb, lamb!");
+ make_test_inner!($s, $code, short_mixed,
+ "ศไทย中华Việt Nam; Mary had a little lamb, Little lam!");
+ make_test_inner!($s, $code, short_pile_of_poo,
+ "💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩!");
+ make_test_inner!($s, $code, long_lorem_ipsum,"\
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \
+ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \
+eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \
+sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \
+tempus vel, gravida nec quam.
+
+In est dui, tincidunt sed tempus interdum, adipiscing laoreet ante. Etiam tempor, tellus quis \
+sagittis interdum, nulla purus mattis sem, quis auctor erat odio ac tellus. In nec nunc sit amet \
+diam volutpat molestie at sed ipsum. Vestibulum laoreet consequat vulputate. Integer accumsan \
+lorem ac dignissim placerat. Suspendisse convallis faucibus lorem. Aliquam erat volutpat. In vel \
+eleifend felis. Sed suscipit nulla lorem, sed mollis est sollicitudin et. Nam fermentum egestas \
+interdum. Curabitur ut nisi justo.
+
+Sed sollicitudin ipsum tellus, ut condimentum leo eleifend nec. Cras ut velit ante. Phasellus nec \
+mollis odio. Mauris molestie erat in arcu mattis, at aliquet dolor vehicula. Quisque malesuada \
+lectus sit amet nisi pretium, a condimentum ipsum porta. Morbi at dapibus diam. Praesent egestas \
+est sed risus elementum, eu rutrum metus ultrices. Etiam fermentum consectetur magna, id rutrum \
+felis accumsan a. Aliquam ut pellentesque libero. Sed mi nulla, lobortis eu tortor id, suscipit \
+ultricies neque. Morbi iaculis sit amet risus at iaculis. Praesent eget ligula quis turpis \
+feugiat suscipit vel non arcu. Interdum et malesuada fames ac ante ipsum primis in faucibus. \
+Aliquam sit amet placerat lorem.
+
+Cras a lacus vel ante posuere elementum. Nunc est leo, bibendum ut facilisis vel, bibendum at \
+mauris. Nullam adipiscing diam vel odio ornare, luctus adipiscing mi luctus. Nulla facilisi. \
+Mauris adipiscing bibendum neque, quis adipiscing lectus tempus et. Sed feugiat erat et nisl \
+lobortis pharetra. Donec vitae erat enim. Nullam sit amet felis et quam lacinia tincidunt. Aliquam \
+suscipit dapibus urna. Sed volutpat urna in magna pulvinar volutpat. Phasellus nec tellus ac diam \
+cursus accumsan.
+
+Nam lectus enim, dapibus non nisi tempor, consectetur convallis massa. Maecenas eleifend dictum \
+feugiat. Etiam quis mauris vel risus luctus mattis a a nunc. Nullam orci quam, imperdiet id \
+vehicula in, porttitor ut nibh. Duis sagittis adipiscing nisl vitae congue. Donec mollis risus eu \
+leo suscipit, varius porttitor nulla porta. Pellentesque ut sem nec nisi euismod vehicula. Nulla \
+malesuada sollicitudin quam eu fermentum!");
+ }
+ }
+ }
+
+ make_test!(chars_count, s, s.chars().count());
+
+ make_test!(contains_bang_str, s, s.contains("!"));
+ make_test!(contains_bang_char, s, s.contains_char('!'));
+
+ make_test!(match_indices_a_str, s, s.match_indices("a").count());
+
+ make_test!(split_str_a_str, s, s.split_str("a").count());
+
+ make_test!(trim_ascii_char, s, {
+ use std::ascii::AsciiExt;
+ s.trim_matches(|c: char| c.is_ascii())
+ });
+ make_test!(trim_left_ascii_char, s, {
+ use std::ascii::AsciiExt;
+ s.trim_left_matches(|c: char| c.is_ascii())
+ });
+ make_test!(trim_right_ascii_char, s, {
+ use std::ascii::AsciiExt;
+ s.trim_right_matches(|c: char| c.is_ascii())
+ });
+
+ make_test!(find_underscore_char, s, s.find('_'));
+ make_test!(rfind_underscore_char, s, s.rfind('_'));
+ make_test!(find_underscore_str, s, s.find_str("_"));
+
+ make_test!(find_zzz_char, s, s.find('\u{1F4A4}'));
+ make_test!(rfind_zzz_char, s, s.rfind('\u{1F4A4}'));
+ make_test!(find_zzz_str, s, s.find_str("\u{1F4A4}"));
+
+ make_test!(split_space_char, s, s.split(' ').count());
+ make_test!(split_terminator_space_char, s, s.split_terminator(' ').count());
+
+ make_test!(splitn_space_char, s, s.splitn(10, ' ').count());
+ make_test!(rsplitn_space_char, s, s.rsplitn(10, ' ').count());
+
+ make_test!(split_str_space_str, s, s.split_str(" ").count());
+ make_test!(split_str_ad_str, s, s.split_str("ad").count());
}
#![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: "",
fn pre_escaped_content(self) -> Cow<'a, str> {
match self {
EscStr(s) => s,
- LabelStr(s) => if s.contains_char('\\') {
+ LabelStr(s) => if s.contains('\\') {
(&*s).escape_default().into_cow()
} else {
s
//! one from Berkeley after the lawsuits died down and the CSRG dissolved.
#![allow(bad_style, raw_pointer_derive)]
+#![cfg_attr(target_os = "nacl", allow(unused_imports))]
#[cfg(feature = "cargo-build")] extern crate "std" as core;
#[cfg(not(feature = "cargo-build"))] extern crate core;
// you can write more-platform-agnostic code if you stick to just these
// symbols.
-pub use types::common::c95::{FILE, c_void, fpos_t};
-pub use types::common::c99::{int8_t, int16_t, int32_t, int64_t};
-pub use types::common::c99::{uint8_t, uint16_t, uint32_t, uint64_t};
-pub use types::common::posix88::{DIR, dirent_t};
-pub use types::os::common::posix01::{timeval};
-pub use types::os::common::bsd44::{addrinfo, in_addr, in6_addr, sockaddr_storage};
-pub use types::os::common::bsd44::{ip_mreq, ip6_mreq, sockaddr, sockaddr_un};
-pub use types::os::common::bsd44::{sa_family_t, sockaddr_in, sockaddr_in6, socklen_t};
-pub use types::os::arch::c95::{c_char, c_double, c_float, c_int, c_uint};
-pub use types::os::arch::c95::{c_long, c_short, c_uchar, c_ulong, wchar_t};
-pub use types::os::arch::c95::{c_ushort, clock_t, ptrdiff_t, c_schar};
-pub use types::os::arch::c95::{size_t, time_t, suseconds_t};
-pub use types::os::arch::c99::{c_longlong, c_ulonglong};
-pub use types::os::arch::c99::{intptr_t, uintptr_t};
-pub use types::os::arch::c99::{intmax_t, uintmax_t};
-pub use types::os::arch::posix88::{dev_t, ino_t, mode_t};
-pub use types::os::arch::posix88::{off_t, pid_t, ssize_t};
-
-pub use consts::os::c95::{_IOFBF, _IOLBF, _IONBF, BUFSIZ, EOF};
-pub use consts::os::c95::{EXIT_FAILURE, EXIT_SUCCESS};
-pub use consts::os::c95::{FILENAME_MAX, FOPEN_MAX, L_tmpnam};
-pub use consts::os::c95::{RAND_MAX, SEEK_CUR, SEEK_END};
-pub use consts::os::c95::{SEEK_SET, TMP_MAX};
-pub use consts::os::posix88::{F_OK, O_APPEND, O_CREAT, O_EXCL};
-pub use consts::os::posix88::{O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY};
-pub use consts::os::posix88::{R_OK, S_IEXEC, S_IFBLK, S_IFCHR};
-pub use consts::os::posix88::{S_IFDIR, S_IFIFO, S_IFMT, S_IFREG, S_IFLNK};
-pub use consts::os::posix88::{S_IREAD, S_IRUSR, S_IRWXU, S_IWUSR};
-pub use consts::os::posix88::{STDERR_FILENO, STDIN_FILENO, S_IXUSR};
-pub use consts::os::posix88::{STDOUT_FILENO, W_OK, X_OK};
-pub use consts::os::bsd44::{AF_INET, AF_INET6, SOCK_STREAM, SOCK_DGRAM, SOCK_RAW};
-pub use consts::os::bsd44::{IPPROTO_IP, IPPROTO_IPV6, IPPROTO_TCP, TCP_NODELAY};
-pub use consts::os::bsd44::{SOL_SOCKET, SO_KEEPALIVE, SO_ERROR};
-pub use consts::os::bsd44::{SO_REUSEADDR, SO_BROADCAST, SHUT_WR, IP_MULTICAST_LOOP};
-pub use consts::os::bsd44::{IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP};
-pub use consts::os::bsd44::{IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP};
-pub use consts::os::bsd44::{IP_MULTICAST_TTL, IP_TTL, IP_HDRINCL, SHUT_RD};
-pub use consts::os::extra::{IPPROTO_RAW};
-
-pub use funcs::c95::ctype::{isalnum, isalpha, iscntrl, isdigit};
-pub use funcs::c95::ctype::{islower, isprint, ispunct, isspace};
-pub use funcs::c95::ctype::{isupper, isxdigit, tolower, toupper};
-
-pub use funcs::c95::stdio::{fclose, feof, ferror, fflush, fgetc};
-pub use funcs::c95::stdio::{fgetpos, fgets, fopen, fputc, fputs};
-pub use funcs::c95::stdio::{fread, freopen, fseek, fsetpos, ftell};
-pub use funcs::c95::stdio::{fwrite, perror, puts, remove, rename, rewind};
-pub use funcs::c95::stdio::{setbuf, setvbuf, tmpfile, ungetc};
-
-pub use funcs::c95::stdlib::{abs, atof, atoi, calloc, exit, _exit, atexit};
-pub use funcs::c95::stdlib::{free, getenv, labs, malloc, rand};
-pub use funcs::c95::stdlib::{realloc, srand, strtod, strtol};
-pub use funcs::c95::stdlib::{strtoul, system};
-
-pub use funcs::c95::string::{memchr, memcmp};
-pub use funcs::c95::string::{strcat, strchr, strcmp};
-pub use funcs::c95::string::{strcoll, strcpy, strcspn, strerror};
-pub use funcs::c95::string::{strlen, strncat, strncmp, strncpy};
-pub use funcs::c95::string::{strpbrk, strrchr, strspn, strstr};
-pub use funcs::c95::string::{strtok, strxfrm};
-
-pub use funcs::posix88::fcntl::{open, creat};
-pub use funcs::posix88::stat_::{chmod, fstat, mkdir, stat};
-pub use funcs::posix88::stdio::{fdopen, fileno, pclose, popen};
-pub use funcs::posix88::unistd::{access, chdir, close, dup, dup2};
-pub use funcs::posix88::unistd::{execv, execve, execvp, getcwd};
-pub use funcs::posix88::unistd::{getpid, isatty, lseek, pipe, read};
-pub use funcs::posix88::unistd::{rmdir, unlink, write};
-
-pub use funcs::bsd43::{socket, setsockopt, bind, send, recv, recvfrom};
-pub use funcs::bsd43::{listen, sendto, accept, connect, getpeername, getsockname};
-pub use funcs::bsd43::{shutdown};
+pub use types::common::c95::*;
+pub use types::common::c99::*;
+pub use types::common::posix88::*;
+pub use types::os::common::posix01::*;
+pub use types::os::common::bsd44::*;
+pub use types::os::arch::c95::*;
+pub use types::os::arch::c99::*;
+pub use types::os::arch::posix88::*;
+pub use types::os::arch::posix01::*;
+pub use types::os::arch::extra::*;
+
+pub use consts::os::c95::*;
+pub use consts::os::posix88::*;
+pub use consts::os::posix01::*;
+pub use consts::os::bsd44::*;
+pub use consts::os::extra::*;
+
+pub use funcs::c95::ctype::*;
+pub use funcs::c95::stdio::*;
+pub use funcs::c95::stdlib::*;
+pub use funcs::c95::string::*;
+pub use funcs::posix88::fcntl::*;
+pub use funcs::posix88::stat_::*;
+pub use funcs::posix88::stdio::*;
+pub use funcs::posix88::unistd::*;
+
+pub use funcs::bsd43::*;
// But we also reexport most everything
// if you're interested in writing platform-specific code.
//
// So the following exports don't follow any particular plan.
-#[cfg(unix)] pub use consts::os::sysconf::{_SC_PAGESIZE};
-#[cfg(unix)] pub use consts::os::posix88::{PROT_READ, PROT_WRITE, PROT_EXEC};
-#[cfg(unix)] pub use consts::os::posix88::{MAP_FIXED, MAP_FILE, MAP_ANON, MAP_PRIVATE, MAP_FAILED};
-#[cfg(unix)] pub use consts::os::posix88::{EACCES, EBADF, EINVAL, ENODEV, ENOMEM};
-#[cfg(unix)] pub use consts::os::posix88::{ECONNREFUSED, ECONNRESET, EPERM, EPIPE};
-#[cfg(unix)] pub use consts::os::posix88::{ENOTCONN, ECONNABORTED, EADDRNOTAVAIL, EINTR};
-#[cfg(unix)] pub use consts::os::posix88::{EADDRINUSE, ENOENT, EISDIR, EAGAIN, EWOULDBLOCK};
-#[cfg(unix)] pub use consts::os::posix88::{ECANCELED, SIGINT, EINPROGRESS};
-#[cfg(unix)] pub use consts::os::posix88::{ENOSYS, ENOTTY, ETIMEDOUT, EMFILE};
-#[cfg(unix)] pub use consts::os::posix88::{SIGTERM, SIGKILL, SIGPIPE, PROT_NONE};
-#[cfg(unix)] pub use consts::os::posix01::{SIG_IGN, F_GETFL, F_SETFL};
-#[cfg(unix)] pub use consts::os::bsd44::{AF_UNIX};
-#[cfg(unix)] pub use consts::os::extra::{O_NONBLOCK};
-
-#[cfg(unix)] pub use types::os::common::posix01::{pthread_t, timespec, timezone};
-
-#[cfg(unix)] pub use types::os::arch::posix88::{uid_t, gid_t};
-#[cfg(unix)] pub use types::os::arch::posix01::{pthread_attr_t};
-#[cfg(unix)] pub use types::os::arch::posix01::{stat, utimbuf};
-#[cfg(unix)] pub use types::os::common::bsd44::{ifaddrs};
-#[cfg(unix)] pub use funcs::posix88::unistd::{sysconf, setgid, setsid, setuid, pread, pwrite};
-#[cfg(unix)] pub use funcs::posix88::unistd::{getgid, getuid, getsid};
-#[cfg(unix)] pub use funcs::posix88::unistd::{_PC_NAME_MAX, utime, nanosleep, pathconf, link};
-#[cfg(unix)] pub use funcs::posix88::unistd::{chown};
-#[cfg(unix)] pub use funcs::posix88::mman::{mmap, munmap, mprotect};
-#[cfg(unix)] pub use funcs::posix88::dirent::{opendir, readdir_r, closedir};
-#[cfg(unix)] pub use funcs::posix88::fcntl::{fcntl};
-#[cfg(unix)] pub use funcs::posix88::net::{if_nametoindex};
-#[cfg(unix)] pub use funcs::posix01::stat_::{lstat};
-#[cfg(unix)] pub use funcs::posix01::unistd::{fsync, ftruncate};
-#[cfg(unix)] pub use funcs::posix01::unistd::{readlink, symlink};
-#[cfg(unix)] pub use funcs::bsd43::{getifaddrs, freeifaddrs};
-
-#[cfg(windows)] pub use consts::os::c95::{WSAECONNREFUSED, WSAECONNRESET, WSAEACCES};
-#[cfg(windows)] pub use consts::os::c95::{WSAEWOULDBLOCK, WSAENOTCONN, WSAECONNABORTED};
-#[cfg(windows)] pub use consts::os::c95::{WSAEADDRNOTAVAIL, WSAEADDRINUSE, WSAEINTR};
-#[cfg(windows)] pub use consts::os::c95::{WSAEINPROGRESS, WSAEINVAL, WSAEMFILE};
-#[cfg(windows)] pub use consts::os::extra::{ERROR_INSUFFICIENT_BUFFER};
-#[cfg(windows)] pub use consts::os::extra::{O_BINARY, O_NOINHERIT, PAGE_NOACCESS};
-#[cfg(windows)] pub use consts::os::extra::{PAGE_READONLY, PAGE_READWRITE, PAGE_EXECUTE};
-#[cfg(windows)] pub use consts::os::extra::{PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE};
-#[cfg(windows)] pub use consts::os::extra::{MEM_COMMIT, MEM_RESERVE, MEM_RELEASE};
-#[cfg(windows)] pub use consts::os::extra::{FILE_MAP_READ, FILE_MAP_WRITE, FILE_MAP_EXECUTE};
-#[cfg(windows)] pub use consts::os::extra::{ERROR_ALREADY_EXISTS, ERROR_NO_DATA};
-#[cfg(windows)] pub use consts::os::extra::{ERROR_FILE_NOT_FOUND, ERROR_INVALID_NAME};
-#[cfg(windows)] pub use consts::os::extra::{ERROR_BROKEN_PIPE, ERROR_INVALID_FUNCTION};
-#[cfg(windows)] pub use consts::os::extra::{ERROR_CALL_NOT_IMPLEMENTED};
-#[cfg(windows)] pub use consts::os::extra::{ERROR_NOTHING_TO_TERMINATE};
-#[cfg(windows)] pub use consts::os::extra::{ERROR_INVALID_HANDLE};
-#[cfg(windows)] pub use consts::os::extra::{TRUE, FALSE, INFINITE};
-#[cfg(windows)] pub use consts::os::extra::{PROCESS_TERMINATE, PROCESS_QUERY_INFORMATION};
-#[cfg(windows)] pub use consts::os::extra::{STILL_ACTIVE, DETACHED_PROCESS};
-#[cfg(windows)] pub use consts::os::extra::{CREATE_NEW_PROCESS_GROUP, CREATE_UNICODE_ENVIRONMENT};
-#[cfg(windows)] pub use consts::os::extra::{FILE_BEGIN, FILE_END, FILE_CURRENT};
-#[cfg(windows)] pub use consts::os::extra::{FILE_GENERIC_READ, FILE_GENERIC_WRITE};
-#[cfg(windows)] pub use consts::os::extra::{FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_DELETE};
-#[cfg(windows)] pub use consts::os::extra::{TRUNCATE_EXISTING, CREATE_ALWAYS, OPEN_EXISTING};
-#[cfg(windows)] pub use consts::os::extra::{CREATE_NEW, FILE_APPEND_DATA, FILE_WRITE_DATA};
-#[cfg(windows)] pub use consts::os::extra::{OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL};
-#[cfg(windows)] pub use consts::os::extra::{FILE_FLAG_BACKUP_SEMANTICS, INVALID_HANDLE_VALUE};
-#[cfg(windows)] pub use consts::os::extra::{MOVEFILE_REPLACE_EXISTING};
-#[cfg(windows)] pub use consts::os::extra::{GENERIC_READ, GENERIC_WRITE};
-#[cfg(windows)] pub use consts::os::extra::{VOLUME_NAME_DOS};
-#[cfg(windows)] pub use consts::os::extra::{PIPE_ACCESS_DUPLEX, FILE_FLAG_FIRST_PIPE_INSTANCE};
-#[cfg(windows)] pub use consts::os::extra::{FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE};
-#[cfg(windows)] pub use consts::os::extra::{PIPE_READMODE_BYTE, PIPE_WAIT};
-#[cfg(windows)] pub use consts::os::extra::{PIPE_UNLIMITED_INSTANCES, ERROR_ACCESS_DENIED};
-#[cfg(windows)] pub use consts::os::extra::{FILE_WRITE_ATTRIBUTES, FILE_READ_ATTRIBUTES};
-#[cfg(windows)] pub use consts::os::extra::{ERROR_PIPE_BUSY, ERROR_IO_PENDING};
-#[cfg(windows)] pub use consts::os::extra::{ERROR_PIPE_CONNECTED, WAIT_OBJECT_0};
-#[cfg(windows)] pub use consts::os::extra::{ERROR_NOT_FOUND};
-#[cfg(windows)] pub use consts::os::extra::{ERROR_OPERATION_ABORTED};
-#[cfg(windows)] pub use consts::os::extra::{FIONBIO};
-#[cfg(windows)] pub use types::os::common::bsd44::{SOCKET};
-#[cfg(windows)] pub use types::os::common::posix01::{stat, utimbuf};
-#[cfg(windows)] pub use types::os::arch::extra::{HANDLE, BOOL, LPSECURITY_ATTRIBUTES};
-#[cfg(windows)] pub use types::os::arch::extra::{LPCSTR, WORD, DWORD, BYTE, FILETIME};
-#[cfg(windows)] pub use types::os::arch::extra::{LARGE_INTEGER, LPVOID, LONG};
-#[cfg(windows)] pub use types::os::arch::extra::{time64_t, OVERLAPPED, LPCWSTR};
-#[cfg(windows)] pub use types::os::arch::extra::{LPOVERLAPPED, SIZE_T, LPDWORD};
-#[cfg(windows)] pub use types::os::arch::extra::{SECURITY_ATTRIBUTES, WIN32_FIND_DATAW};
-#[cfg(windows)] pub use funcs::c95::string::{wcslen};
-#[cfg(windows)] pub use funcs::posix88::stat_::{wstat, wutime, wchmod, wrmdir};
-#[cfg(windows)] pub use funcs::bsd43::{closesocket};
-#[cfg(windows)] pub use funcs::extra::kernel32::{GetCurrentDirectoryW, GetLastError};
-#[cfg(windows)] pub use funcs::extra::kernel32::{GetEnvironmentVariableW, SetEnvironmentVariableW};
-#[cfg(windows)] pub use funcs::extra::kernel32::{GetModuleFileNameW, SetCurrentDirectoryW};
-#[cfg(windows)] pub use funcs::extra::kernel32::{GetSystemInfo, VirtualAlloc, VirtualFree};
-#[cfg(windows)] pub use funcs::extra::kernel32::{CreateFileMappingW, MapViewOfFile};
-#[cfg(windows)] pub use funcs::extra::kernel32::{UnmapViewOfFile, CloseHandle};
-#[cfg(windows)] pub use funcs::extra::kernel32::{WaitForSingleObject, GetSystemTimeAsFileTime};
-#[cfg(windows)] pub use funcs::extra::kernel32::{QueryPerformanceCounter};
-#[cfg(windows)] pub use funcs::extra::kernel32::{QueryPerformanceFrequency};
-#[cfg(windows)] pub use funcs::extra::kernel32::{GetExitCodeProcess, TerminateProcess};
-#[cfg(windows)] pub use funcs::extra::kernel32::{ReadFile, WriteFile, SetFilePointerEx};
-#[cfg(windows)] pub use funcs::extra::kernel32::{SetEndOfFile, CreateFileW};
-#[cfg(windows)] pub use funcs::extra::kernel32::{CreateDirectoryW, FindFirstFileW};
-#[cfg(windows)] pub use funcs::extra::kernel32::{FindNextFileW, FindClose, DeleteFileW};
-#[cfg(windows)] pub use funcs::extra::kernel32::{CreateHardLinkW, CreateEventW};
-#[cfg(windows)] pub use funcs::extra::kernel32::{FlushFileBuffers, CreateNamedPipeW};
-#[cfg(windows)] pub use funcs::extra::kernel32::{SetNamedPipeHandleState, WaitNamedPipeW};
-#[cfg(windows)] pub use funcs::extra::kernel32::{GetOverlappedResult, ConnectNamedPipe};
-#[cfg(windows)] pub use funcs::extra::kernel32::{DisconnectNamedPipe, OpenProcess};
-#[cfg(windows)] pub use funcs::extra::kernel32::{MoveFileExW, VirtualProtect};
-#[cfg(windows)] pub use funcs::extra::kernel32::{RemoveDirectoryW};
-#[cfg(windows)] pub use funcs::extra::msvcrt::{get_osfhandle, open_osfhandle};
-#[cfg(windows)] pub use funcs::extra::winsock::{ioctlsocket};
-
-#[cfg(any(target_os = "linux",
- target_os = "android",
- target_os = "freebsd",
- target_os = "dragonfly",
- target_os = "bitrig",
- target_os = "openbsd"))]
-pub use consts::os::posix01::{CLOCK_REALTIME, CLOCK_MONOTONIC};
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-pub use funcs::posix01::unistd::{fdatasync};
-#[cfg(any(target_os = "linux", target_os = "android"))]
-pub use types::os::arch::extra::{sockaddr_ll};
-#[cfg(any(target_os = "linux", target_os = "android"))]
-pub use consts::os::extra::{AF_PACKET};
-
-#[cfg(all(unix, not(any(target_os = "freebsd", target_os = "bitrig", target_os = "openbsd"))))]
-pub use consts::os::extra::{MAP_STACK};
-
-#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
-pub use consts::os::bsd44::{TCP_KEEPIDLE};
-
-#[cfg(any(target_os = "macos", target_os = "ios"))]
-pub use consts::os::bsd44::{TCP_KEEPALIVE};
-#[cfg(any(target_os = "macos", target_os = "ios"))]
-pub use consts::os::extra::{F_FULLFSYNC};
-
-#[cfg(any(target_os = "macos", target_os = "ios"))]
-pub use types::os::arch::extra::{mach_timebase_info};
-
-
-#[cfg(not(windows))]
+#[cfg(unix)] pub use consts::os::sysconf::*;
+
+#[cfg(unix)] pub use funcs::posix88::mman::*;
+#[cfg(unix)] pub use funcs::posix88::dirent::*;
+#[cfg(unix)] pub use funcs::posix88::net::*;
+#[cfg(unix)] pub use funcs::posix01::stat_::*;
+#[cfg(unix)] pub use funcs::posix01::unistd::*;
+
+
+#[cfg(windows)] pub use funcs::extra::kernel32::*;
+#[cfg(windows)] pub use funcs::extra::winsock::*;
+#[cfg(windows)] pub use funcs::extra::msvcrt::*;
+
+// On NaCl, these libraries are static. Thus it would be a Bad Idea to link them
+// in when creating a test crate.
+#[cfg(not(any(windows, all(target_os = "nacl", test))))]
#[link(name = "c")]
#[link(name = "m")]
extern {}
+// libnacl provides functions that require a trip through the IRT to work.
+// ie: _exit, mmap, nanosleep, etc. Anything that would otherwise require a trip
+// to the kernel.
+#[cfg(all(target_os = "nacl", not(feature = "cargo-build"), not(test)))]
+#[link(name = "nacl", kind = "static")]
+extern {}
+
+// pnaclmm provides a number of functions that the toolchain's Clang emits calls
+// to when codegening atomic ops. All the functions within wrap various atomic
+// operations.
+// Yes, it could be linked by rustc explicitly, however by linking it here
+// instead we save a bit of time where bins are involved (by not running the
+// optimizations on the whole pnaclmm foreach binary built).
+#[cfg(all(target_os = "nacl", not(feature = "cargo-build"), not(test)))]
+#[link(name = "pnaclmm", kind = "static")]
+extern {}
+
pub mod types {
// Types tend to vary *per architecture* so we pull their definitions out
// Standard types that are scalar but vary by OS and arch.
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android", target_os = "nacl"))]
pub mod os {
pub mod common {
pub mod posix01 {
use types::os::arch::c95::{c_char, c_ulong, size_t,
time_t, suseconds_t, c_long};
+ #[cfg(not(target_os = "nacl"))]
pub type pthread_t = c_ulong;
+ #[cfg(target_os = "nacl")]
+ pub type pthread_t = *mut c_void;
#[repr(C)]
#[derive(Copy)] pub struct glob_t {
#[cfg(target_os = "linux")]
pub ai_canonname: *mut c_char,
- #[cfg(target_os = "android")]
+ #[cfg(any(target_os = "android", target_os = "nacl"))]
pub ai_canonname: *mut c_char,
- #[cfg(target_os = "android")]
+ #[cfg(any(target_os = "android", target_os = "nacl"))]
pub ai_addr: *mut sockaddr,
pub ai_next: *mut addrinfo,
target_arch = "arm",
target_arch = "mips",
target_arch = "mipsel",
- target_arch = "powerpc"))]
+ target_arch = "powerpc",
+ target_arch = "le32"))]
pub mod arch {
pub mod c95 {
pub type c_char = i8;
#[cfg(any(target_arch = "x86",
target_arch = "mips",
target_arch = "mipsel",
- target_arch = "powerpc"))]
+ target_arch = "powerpc",
+ target_arch = "le32"))]
pub mod posix88 {
pub type off_t = i32;
pub type dev_t = u64;
pub type ssize_t = i32;
}
#[cfg(any(target_arch = "x86",
+ target_arch = "le32",
target_arch = "powerpc"))]
pub mod posix01 {
use types::os::arch::c95::{c_short, c_long, time_t};
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;
pub const SHUT_RDWR: c_int = 2;
}
pub mod extra {
- use SOCKET;
+ use types::os::common::bsd44::SOCKET;
use types::os::arch::c95::{c_int, c_long};
use types::os::arch::extra::{WORD, DWORD, BOOL, HANDLE};
}
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android", target_os = "nacl"))]
pub mod os {
pub mod c95 {
use types::os::arch::c95::{c_int, c_uint};
target_arch = "x86_64",
target_arch = "arm",
target_arch = "aarch64",
+ target_arch = "le32",
target_arch = "powerpc"))]
pub mod posix88 {
use types::os::arch::c95::c_int;
pub const EDQUOT: c_int = 1133;
}
+ #[cfg(not(target_os = "nacl"))]
pub mod posix01 {
use types::os::arch::c95::{c_int, size_t};
pub const F_SETFL : c_int = 4;
pub const SIGTRAP : c_int = 5;
- pub const SIGPIPE: c_int = 13;
pub const SIG_IGN: size_t = 1;
pub const GLOB_ERR : c_int = 1 << 0;
pub const CLOCK_REALTIME: c_int = 0;
pub const CLOCK_MONOTONIC: c_int = 1;
}
+ #[cfg(target_os = "nacl")]
+ pub mod posix01 {
+ use types::os::arch::c95::{c_int, size_t};
+
+ pub const F_DUPFD : c_int = 0;
+ pub const F_GETFD : c_int = 1;
+ pub const F_SETFD : c_int = 2;
+ pub const F_GETFL : c_int = 3;
+ pub const F_SETFL : c_int = 4;
+
+ pub const SIGTRAP : c_int = 5;
+ pub const SIG_IGN: size_t = 1;
+
+ pub const GLOB_ERR : c_int = 1 << 0;
+ pub const GLOB_MARK : c_int = 1 << 1;
+ pub const GLOB_NOSORT : c_int = 1 << 2;
+ pub const GLOB_DOOFFS : c_int = 1 << 3;
+ pub const GLOB_NOCHECK : c_int = 1 << 4;
+ pub const GLOB_APPEND : c_int = 1 << 5;
+ pub const GLOB_NOESCAPE : c_int = 1 << 6;
+
+ pub const GLOB_NOSPACE : c_int = 1;
+ pub const GLOB_ABORTED : c_int = 2;
+ pub const GLOB_NOMATCH : c_int = 3;
+
+ pub const POSIX_MADV_NORMAL : c_int = 0;
+ pub const POSIX_MADV_RANDOM : c_int = 1;
+ pub const POSIX_MADV_SEQUENTIAL : c_int = 2;
+ pub const POSIX_MADV_WILLNEED : c_int = 3;
+ pub const POSIX_MADV_DONTNEED : c_int = 4;
+
+ pub const _SC_MQ_PRIO_MAX : c_int = 28;
+ pub const _SC_IOV_MAX : c_int = 60;
+ pub const _SC_GETGR_R_SIZE_MAX : c_int = 69;
+ pub const _SC_GETPW_R_SIZE_MAX : c_int = 70;
+ pub const _SC_LOGIN_NAME_MAX : c_int = 71;
+ pub const _SC_TTY_NAME_MAX : c_int = 72;
+ pub const _SC_THREADS : c_int = 67;
+ pub const _SC_THREAD_SAFE_FUNCTIONS : c_int = 68;
+ pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 73;
+ pub const _SC_THREAD_KEYS_MAX : c_int = 74;
+ pub const _SC_THREAD_STACK_MIN : c_int = 75;
+ pub const _SC_THREAD_THREADS_MAX : c_int = 76;
+ pub const _SC_THREAD_ATTR_STACKADDR : c_int = 77;
+ pub const _SC_THREAD_ATTR_STACKSIZE : c_int = 78;
+ pub const _SC_THREAD_PRIORITY_SCHEDULING : c_int = 79;
+ pub const _SC_THREAD_PRIO_INHERIT : c_int = 80;
+ pub const _SC_THREAD_PRIO_PROTECT : c_int = 81;
+ pub const _SC_THREAD_PROCESS_SHARED : c_int = 82;
+ pub const _SC_ATEXIT_MAX : c_int = 87;
+ pub const _SC_XOPEN_VERSION : c_int = 89;
+ pub const _SC_XOPEN_XCU_VERSION : c_int = 90;
+ pub const _SC_XOPEN_UNIX : c_int = 91;
+ pub const _SC_XOPEN_CRYPT : c_int = 92;
+ pub const _SC_XOPEN_ENH_I18N : c_int = 93;
+ pub const _SC_XOPEN_SHM : c_int = 94;
+ pub const _SC_XOPEN_LEGACY : c_int = 129;
+ pub const _SC_XOPEN_REALTIME : c_int = 130;
+ pub const _SC_XOPEN_REALTIME_THREADS : c_int = 131;
+
+ pub const PTHREAD_CREATE_JOINABLE: c_int = 1;
+ pub const PTHREAD_CREATE_DETACHED: c_int = 0;
+
+ pub const PTHREAD_STACK_MIN: size_t = 1024;
+
+ pub const CLOCK_REALTIME: c_int = 0;
+ pub const CLOCK_MONOTONIC: c_int = 1;
+ }
pub mod posix08 {
}
#[cfg(any(target_arch = "arm",
target_arch = "aarch64",
target_arch = "x86",
target_arch = "x86_64",
+ target_arch = "le32",
target_arch = "powerpc"))]
pub mod bsd44 {
use types::os::arch::c95::c_int;
target_arch = "x86_64",
target_arch = "arm",
target_arch = "aarch64",
+ target_arch = "le32",
target_arch = "powerpc"))]
pub mod extra {
use types::os::arch::c95::c_int;
pub const _SC_XBS5_ILP32_OFFBIG : c_int = 126;
pub const _SC_XBS5_LPBIG_OFFBIG : c_int = 128;
}
+ #[cfg(target_os = "nacl")]
+ pub mod sysconf {
+ use types::os::arch::c95::c_int;
+
+ pub static _SC_SENDMSG_MAX_SIZE : c_int = 0;
+ pub static _SC_NPROCESSORS_ONLN : c_int = 1;
+ pub static _SC_PAGESIZE : c_int = 2;
+ }
#[cfg(target_os = "android")]
pub mod sysconf {
use types::os::arch::c95::c_int;
pub const F_SETFL : c_int = 4;
pub const SIGTRAP : c_int = 5;
- pub const SIGPIPE: c_int = 13;
pub const SIG_IGN: size_t = 1;
pub const GLOB_APPEND : c_int = 0x0001;
pub const F_DUPFD_CLOEXEC : c_int = 10;
pub const SIGTRAP : c_int = 5;
- pub const SIGPIPE: c_int = 13;
pub const SIG_IGN: size_t = 1;
pub const GLOB_APPEND : c_int = 0x0001;
pub const F_SETFL : c_int = 4;
pub const SIGTRAP : c_int = 5;
- pub const SIGPIPE: c_int = 13;
pub const SIG_IGN: size_t = 1;
pub const GLOB_APPEND : c_int = 0x0001;
target_os = "freebsd",
target_os = "dragonfly",
target_os = "bitrig",
- target_os = "openbsd"))]
+ target_os = "openbsd",
+ target_os = "nacl"))]
pub mod posix88 {
pub mod stat_ {
use types::os::arch::c95::{c_char, c_int};
target_os = "bitrig",
target_os = "openbsd",
target_os = "android",
- target_os = "ios"))]
+ target_os = "ios",
+ target_os = "nacl"))]
pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int;
#[cfg(target_os = "macos")]
pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int;
pub fn mkdir(path: *const c_char, mode: mode_t) -> c_int;
+ #[cfg(not(target_os = "nacl"))]
pub fn mkfifo(path: *const c_char, mode: mode_t) -> c_int;
#[cfg(any(target_os = "linux",
target_os = "bitrig",
target_os = "openbsd",
target_os = "android",
- target_os = "ios"))]
+ target_os = "ios",
+ target_os = "nacl"))]
pub fn stat(path: *const c_char, buf: *mut stat) -> c_int;
#[cfg(target_os = "macos")]
pub const _PC_NAME_MAX: c_int = 4;
+ #[cfg(not(target_os = "nacl"))]
extern {
pub fn access(path: *const c_char, amode: c_int) -> c_int;
pub fn alarm(seconds: c_uint) -> c_uint;
pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char;
pub fn getegid() -> gid_t;
pub fn geteuid() -> uid_t;
- pub fn getgid() -> gid_t ;
+ pub fn getgid() -> gid_t;
pub fn getgroups(ngroups_max: c_int, groups: *mut gid_t)
-> c_int;
pub fn getlogin() -> *mut c_char;
offset: off_t) -> ssize_t;
pub fn utime(file: *const c_char, buf: *const utimbuf) -> c_int;
}
+ #[cfg(target_os = "nacl")]
+ extern {
+ pub fn access(path: *const c_char, amode: c_int) -> c_int;
+ pub fn chdir(dir: *const c_char) -> c_int;
+ pub fn chown(path: *const c_char, uid: uid_t,
+ gid: gid_t) -> c_int;
+ pub fn close(fd: c_int) -> c_int;
+ pub fn dup(fd: c_int) -> c_int;
+ pub fn dup2(src: c_int, dst: c_int) -> c_int;
+ pub fn execv(prog: *const c_char,
+ argv: *mut *const c_char) -> c_int;
+ pub fn execve(prog: *const c_char, argv: *mut *const c_char,
+ envp: *mut *const c_char)
+ -> c_int;
+ pub fn execvp(c: *const c_char,
+ argv: *mut *const c_char) -> c_int;
+ pub fn fork() -> pid_t;
+ pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char;
+ pub fn getegid() -> gid_t;
+ pub fn geteuid() -> uid_t;
+ pub fn getgid() -> gid_t;
+ pub fn getlogin() -> *mut c_char;
+ pub fn getopt(argc: c_int, argv: *mut *const c_char,
+ optstr: *const c_char) -> c_int;
+ pub fn getuid() -> uid_t;
+ pub fn getsid(pid: pid_t) -> pid_t;
+ pub fn isatty(fd: c_int) -> c_int;
+ pub fn link(src: *const c_char, dst: *const c_char) -> c_int;
+ pub fn lseek(fd: c_int, offset: off_t, whence: c_int)
+ -> off_t;
+ pub fn pipe(fds: *mut c_int) -> c_int;
+ pub fn read(fd: c_int, buf: *mut c_void, count: size_t)
+ -> ssize_t;
+ pub fn rmdir(path: *const c_char) -> c_int;
+ pub fn setgid(gid: gid_t) -> c_int;
+ pub fn setuid(uid: uid_t) -> c_int;
+ pub fn sleep(secs: c_uint) -> c_uint;
+ pub fn usleep(secs: c_uint) -> c_int;
+ pub fn nanosleep(rqtp: *const timespec,
+ rmtp: *mut timespec) -> c_int;
+ pub fn sysconf(name: c_int) -> c_long;
+ pub fn ttyname(fd: c_int) -> *mut c_char;
+ pub fn unlink(c: *const c_char) -> c_int;
+ pub fn write(fd: c_int, buf: *const c_void, count: size_t)
+ -> ssize_t;
+ pub fn pread(fd: c_int, buf: *mut c_void, count: size_t,
+ offset: off_t) -> ssize_t;
+ pub fn pwrite(fd: c_int, buf: *const c_void, count: size_t,
+ offset: off_t) -> ssize_t;
+ pub fn utime(file: *const c_char, buf: *const utimbuf) -> c_int;
+ }
}
pub mod signal {
use types::os::arch::c95::{size_t, c_int, c_char};
use types::os::arch::posix88::{mode_t, off_t};
+ #[cfg(not(target_os = "nacl"))]
extern {
pub fn mlock(addr: *const c_void, len: size_t) -> c_int;
pub fn munlock(addr: *const c_void, len: size_t) -> c_int;
pub fn mlockall(flags: c_int) -> c_int;
pub fn munlockall() -> c_int;
+ pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int)
+ -> c_int;
+
+ pub fn msync(addr: *mut c_void, len: size_t, flags: c_int)
+ -> c_int;
+ pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t)
+ -> c_int;
+ pub fn shm_unlink(name: *const c_char) -> c_int;
+ }
+
+ extern {
pub fn mmap(addr: *mut c_void,
len: size_t,
prot: c_int,
-> *mut c_void;
pub fn munmap(addr: *mut c_void, len: size_t) -> c_int;
- pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int)
- -> c_int;
-
- pub fn msync(addr: *mut c_void, len: size_t, flags: c_int)
- -> c_int;
- pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t)
- -> c_int;
- pub fn shm_unlink(name: *const c_char) -> c_int;
}
}
target_os = "freebsd",
target_os = "dragonfly",
target_os = "bitrig",
- target_os = "openbsd"))]
+ target_os = "openbsd",
+ target_os = "nacl"))]
pub mod posix01 {
pub mod stat_ {
use types::os::arch::c95::{c_char, c_int};
target_os = "bitrig",
target_os = "openbsd",
target_os = "android",
- target_os = "ios"))]
+ target_os = "ios",
+ target_os = "nacl"))]
pub fn lstat(path: *const c_char, buf: *mut stat) -> c_int;
#[cfg(target_os = "macos")]
use types::common::c95::{c_void};
use types::os::arch::c95::{c_int, size_t};
+ #[cfg(not(target_os = "nacl"))]
extern {
pub fn posix_madvise(addr: *mut c_void,
len: size_t,
target_os = "freebsd",
target_os = "dragonfly",
target_os = "bitrig",
- target_os = "openbsd"))]
+ target_os = "openbsd",
+ target_os = "nacl"))]
pub mod posix08 {
pub mod unistd {
}
}
}
+ #[cfg(target_os = "nacl")]
+ pub mod bsd44 {
+ use types::os::arch::c95::c_int;
+ extern {
+ pub fn getdtablesize() -> c_int;
+ }
+ }
#[cfg(target_os = "windows")]
pub mod bsd44 {
pub mod extra {
}
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android", target_os = "nacl"))]
pub mod extra {
}
html_playground_url = "http://play.rust-lang.org/")]
#![deny(missing_docs)]
+#![feature(alloc)]
#![feature(staged_api)]
#![feature(box_syntax)]
#![feature(int_uint)]
#![feature(std_misc)]
#![feature(env)]
+use std::boxed;
use std::cell::RefCell;
use std::fmt;
use std::old_io::LineBufferedWriter;
/// logging statement should be run.
static mut LOG_LEVEL: u32 = MAX_LOG_LEVEL;
-static mut DIRECTIVES: *const Vec<directive::LogDirective> =
- 0 as *const Vec<directive::LogDirective>;
+static mut DIRECTIVES: *mut Vec<directive::LogDirective> =
+ 0 as *mut Vec<directive::LogDirective>;
/// Optional filter.
-static mut FILTER: *const String = 0 as *const _;
+static mut FILTER: *mut String = 0 as *mut _;
/// Debug log level
pub const DEBUG: u32 = 4;
pub file: &'a str,
/// The line number of where the LogRecord originated.
- pub line: uint,
+ pub line: u32,
}
#[doc(hidden)]
pub struct LogLocation {
pub module_path: &'static str,
pub file: &'static str,
- pub line: uint,
+ pub line: u32,
}
/// Tests whether a given module's name is enabled for a particular level of
assert!(FILTER.is_null());
match filter {
- Some(f) => FILTER = mem::transmute(box f),
+ Some(f) => FILTER = boxed::into_raw(box f),
None => {}
}
assert!(DIRECTIVES.is_null());
- DIRECTIVES = mem::transmute(box directives);
+ DIRECTIVES = boxed::into_raw(box directives);
// Schedule the cleanup for the globals for when the runtime exits.
rt::at_exit(move || {
assert!(!DIRECTIVES.is_null());
let _directives: Box<Vec<directive::LogDirective>> =
- mem::transmute(DIRECTIVES);
- DIRECTIVES = ptr::null();
+ Box::from_raw(DIRECTIVES);
+ DIRECTIVES = ptr::null_mut();
if !FILTER.is_null() {
- let _filter: Box<String> = mem::transmute(FILTER);
- FILTER = 0 as *const _;
+ let _filter: Box<String> = Box::from_raw(FILTER);
+ FILTER = 0 as *mut _;
}
});
}
/// Reseed an RNG using a `Default` instance. This reseeds by
/// replacing the RNG with the result of a `Default::default` call.
#[derive(Copy)]
-pub struct ReseedWithDefault { __hack: [u8; 0] }
-// FIXME(#21721) used to be an unit struct but that can cause
-// certain LLVM versions to abort during optimizations.
-#[allow(non_upper_case_globals)]
-pub const ReseedWithDefault: ReseedWithDefault = ReseedWithDefault { __hack: [] };
+pub struct ReseedWithDefault;
impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
fn reseed(&mut self, rng: &mut R) {
/// 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"),
_ => ()
}
}
// start with a non-lowercase letter rather than non-uppercase
// ones (some scripts don't have a concept of upper/lowercase)
- ident.len() > 0 && !ident.char_at(0).is_lowercase() && !ident.contains_char('_')
+ ident.len() > 0 && !ident.char_at(0).is_lowercase() && !ident.contains('_')
}
fn to_camel_case(s: &str) -> String {
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`
};
if s.len() == 0 {
err("crate name must not be empty");
+ } else if s.char_at(0) == '-' {
+ err(&format!("crate name cannot start with a hyphen: {}", s));
}
for c in s.chars() {
if c.is_alphanumeric() { continue }
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)
decoder::is_associated_type(&*cdata, def.node)
}
+pub fn is_default_trait(cstore: &cstore::CStore, def: ast::DefId) -> bool {
+ let cdata = cstore.get_crate_data(def.krate);
+ decoder::is_default_trait(&*cdata, def.node)
+}
StaticMethod, // F
Method, // h
Type, // y
- ForeignType, // T
Mod, // m
ForeignMod, // n
Enum, // t
TupleVariant, // v
StructVariant, // V
Impl, // i
+ DefaultImpl, // d
Trait, // I
Struct, // S
PublicField, // g
'F' => StaticMethod,
'h' => Method,
'y' => Type,
- 'T' => ForeignType,
'm' => Mod,
'n' => ForeignMod,
't' => Enum,
'v' => TupleVariant,
'V' => StructVariant,
'i' => Impl,
+ 'd' => DefaultImpl,
'I' => Trait,
'S' => Struct,
'g' => PublicField,
}
}
-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 => {
}
Trait => DlDef(def::DefTrait(did)),
Enum => DlDef(def::DefTy(did, true)),
- Impl => DlImpl(did),
+ Impl | DefaultImpl => DlImpl(did),
PublicField | InheritedField => DlField,
}
}
let item_doc = lookup_item(id, cdata.data());
let fam = item_family(item_doc);
match fam {
- Family::Impl => {
+ Family::Impl | Family::DefaultImpl => {
reader::maybe_get_doc(item_doc, tag_item_trait_ref).map(|tp| {
doc_trait_ref(tp, tcx, cdata)
})
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 parent_item_doc = lookup_item(parent_item_id.node, cdata.data());
match item_family(parent_item_doc) {
Trait => Some(item_def_id(parent_item_doc, cdata)),
- Impl => {
+ Impl | DefaultImpl => {
reader::maybe_get_doc(parent_item_doc, tag_item_trait_ref)
.map(|_| item_trait_ref(parent_item_doc, tcx, cdata).def_id)
}
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'),
+ }
+}
+
+
+pub fn is_default_trait<'tcx>(cdata: Cmd, id: ast::NodeId) -> bool {
+ let item_doc = lookup_item(id, cdata.data());
+ match item_family(item_doc) {
+ Family::DefaultImpl => true,
+ _ => false
}
}
encode_attributes(rbml_w, &ast_method.attrs);
let scheme = ty::lookup_item_type(ecx.tcx, m.def_id);
let any_types = !scheme.generics.types.is_empty();
- if any_types || is_default_impl || should_inline(&ast_method.attrs) {
+ if any_types || is_default_impl || attr::requests_inline(&ast_method.attrs) {
encode_inlined_item(ecx, rbml_w, IIImplItemRef(local_def(parent_id),
ast_item_opt.unwrap()));
}
const STATIC_METHOD_FAMILY: char = 'F';
const METHOD_FAMILY: char = 'h';
-fn should_inline(attrs: &[ast::Attribute]) -> bool {
- use syntax::attr::*;
- match find_inline_attr(attrs) {
- InlineNone | InlineNever => false,
- InlineHint | InlineAlways => true
- }
-}
-
// Encodes the inherent implementations of a structure, enumeration, or trait.
fn encode_inherent_implementations(ecx: &EncodeContext,
rbml_w: &mut Encoder,
encode_name(rbml_w, item.ident.name);
encode_path(rbml_w, path);
encode_attributes(rbml_w, &item.attrs);
- if tps_len > 0 || should_inline(&item.attrs) {
+ if tps_len > 0 || attr::requests_inline(&item.attrs) {
encode_inlined_item(ecx, rbml_w, IIItemRef(item));
}
if tps_len == 0 {
None => {}
}
}
+ 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_family(rbml_w, 'd');
+ encode_name(rbml_w, item.ident.name);
+ encode_unsafety(rbml_w, unsafety);
+
+ 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();
+ }
ast::ItemImpl(unsafety, polarity, _, ref opt_trait, ref ty, ref ast_items) => {
// We need to encode information about the default methods we
// have inherited, so we drive this based on the impl structure.
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")
}
let mut env_rust_path: Vec<Path> = match get_rust_path() {
Some(env_path) => {
let env_path_components =
- env_path.split_str(PATH_ENTRY_SEPARATOR);
+ env_path.split(PATH_ENTRY_SEPARATOR);
env_path_components.map(|s| Path::new(s)).collect()
}
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::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),
+ DefAssociatedTy(ast::DefId /* trait */, ast::DefId),
DefTrait(ast::DefId),
DefPrimTy(ast::PrimTy),
DefTyParam(ParamSpace, u32, ast::DefId, ast::Name),
/// - 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) |
+ 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) |
- DefAssociatedPath(TyParamProvenance::FromSelf(id), _) |
- DefAssociatedPath(TyParamProvenance::FromParam(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(..) |
* Replace all regions bound by `binder` with skolemized regions and
* return a map indicating which bound-region was replaced with what
* skolemized region. This is the first step of checking subtyping
- * when higher-ranked things are involved. See `doc.rs` for more details.
+ * when higher-ranked things are involved. See `README.md` for more
+ * details.
*/
let (result, map) = ty::replace_late_bound_regions(infcx.tcx, binder, |br| {
* and checks to determine whether any of the skolemized regions created
* in `skol_map` would "escape" -- meaning that they are related to
* other regions in some way. If so, the higher-ranked subtyping doesn't
- * hold. See `doc.rs` for more details.
+ * hold. See `README.md` for more details.
*/
debug!("leak_check: skol_map={}",
/// passed; currently, it's used in the trait matching code to create
/// a set of nested obligations frmo an impl that matches against
/// something higher-ranked. More details can be found in
-/// `middle::traits::doc.rs`.
+/// `librustc/middle/traits/README.md`.
///
/// As a brief example, consider the obligation `for<'a> Fn(&'a int)
/// -> &'a int`, and the impl:
tcx.sess.bug("empty string provided as RUST_REGION_GRAPH");
}
- if output_template.contains_char('%') {
+ if output_template.contains('%') {
let mut new_str = String::new();
for c in output_template.chars() {
if c == '%' {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! See doc.rs
+//! See README.md
pub use self::Constraint::*;
pub use self::Verify::*;
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::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) |
- def::DefTyParam(..) | def::DefTyParamBinder(..) | def::DefRegion(_) |
+ 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),
use syntax::ast;
use syntax::ast_map;
use syntax::ast_util::{is_local, PostExpansionMethod};
-use syntax::attr::{InlineAlways, InlineHint, InlineNever, InlineNone};
use syntax::attr;
use syntax::visit::Visitor;
use syntax::visit;
-// Returns true if the given set of attributes contains the `#[inline]`
-// attribute.
-fn attributes_specify_inlining(attrs: &[ast::Attribute]) -> bool {
- match attr::find_inline_attr(attrs) {
- InlineNone | InlineNever => false,
- InlineAlways | InlineHint => true,
- }
-}
-
// Returns true if the given set of generics implies that the item it's
// associated with must be inlined.
fn generics_require_inlining(generics: &ast::Generics) -> bool {
// monomorphized or it was marked with `#[inline]`. This will only return
// true for functions.
fn item_might_be_inlined(item: &ast::Item) -> bool {
- if attributes_specify_inlining(&item.attrs) {
+ if attr::requests_inline(&item.attrs) {
return true
}
fn method_might_be_inlined(tcx: &ty::ctxt, method: &ast::Method,
impl_src: ast::DefId) -> bool {
- if attributes_specify_inlining(&method.attrs) ||
+ if attr::requests_inline(&method.attrs) ||
generics_require_inlining(method.pe_generics()) {
return true
}
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?!")
match *impl_item {
ast::MethodImplItem(ref method) => {
if generics_require_inlining(method.pe_generics()) ||
- attributes_specify_inlining(
- &method.attrs) {
+ attr::requests_inline(&method.attrs) {
true
} else {
let impl_did = self.tcx
ast::ItemTy(..) | ast::ItemStatic(_, _, _) |
ast::ItemMod(..) | ast::ItemForeignMod(..) |
ast::ItemImpl(..) | ast::ItemTrait(..) |
- ast::ItemStruct(..) | ast::ItemEnum(..) => {}
+ ast::ItemStruct(..) | ast::ItemEnum(..) |
+ ast::ItemDefaultImpl(..) => {}
_ => {
self.tcx.sess.span_bug(item.span,
// The idea is that call.callee_id represents *the time when
// the invoked function is actually running* and call.id
// represents *the time to prepare the arguments and make the
- // call*. See the section "Borrows in Calls" borrowck/doc.rs
+ // call*. See the section "Borrows in Calls" borrowck/README.md
// for an extended explanation of why this distinction is
// important.
//
ast::ItemUse(_) |
ast::ItemMod(..) |
ast::ItemMac(..) |
+ ast::ItemDefaultImpl(..) |
ast::ItemForeignMod(..) |
ast::ItemStatic(..) |
ast::ItemConst(..) => {
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::DefTrait(..)) => {
+ 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,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! See `doc.rs` for high-level documentation
+//! See `README.md` for high-level documentation
use super::Normalized;
use super::SelectionContext;
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;
/// Vtable identifying a particular impl.
VtableImpl(VtableImplData<'tcx, N>),
+ /// Vtable for default trait implementations
+ /// This carries the information and nested obligations with regards
+ /// to a default implementation for a trait `Trait`. The nested obligations
+ /// ensure the trait implementation holds for all the constituent types.
+ VtableDefaultImpl(VtableDefaultImplData<N>),
+
/// Successful resolution to an obligation provided by the caller
/// for some type parameter. The `Vec<N>` represents the
/// obligations incurred from normalizing the where-clause (if
pub nested: subst::VecPerParamSpace<N>
}
+#[derive(Debug,Clone)]
+pub struct VtableDefaultImplData<N> {
+ pub trait_def_id: ast::DefId,
+ pub nested: Vec<N>
+}
+
#[derive(Debug,Clone)]
pub struct VtableBuiltinData<N> {
pub nested: subst::VecPerParamSpace<N>
}
}
+/// 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)
}
pub fn iter_nested(&self) -> Iter<N> {
match *self {
VtableImpl(ref i) => i.iter_nested(),
- VtableFnPointer(..) => (&[]).iter(),
- VtableClosure(..) => (&[]).iter(),
VtableParam(ref n) => n.iter(),
- VtableObject(_) => (&[]).iter(),
VtableBuiltin(ref i) => i.iter_nested(),
+ VtableObject(_) |
+ VtableDefaultImpl(..) | VtableFnPointer(..) |
+ VtableClosure(..) => (&[]).iter(),
}
}
pub fn map_nested<M, F>(&self, op: F) -> Vtable<'tcx, M> where F: FnMut(&N) -> M {
match *self {
VtableImpl(ref i) => VtableImpl(i.map_nested(op)),
+ VtableDefaultImpl(ref t) => VtableDefaultImpl(t.map_nested(op)),
VtableFnPointer(ref sig) => VtableFnPointer((*sig).clone()),
VtableClosure(d, ref s) => VtableClosure(d, s.clone()),
VtableParam(ref n) => VtableParam(n.iter().map(op).collect()),
VtableImpl(i) => VtableImpl(i.map_move_nested(op)),
VtableFnPointer(sig) => VtableFnPointer(sig),
VtableClosure(d, s) => VtableClosure(d, s),
+ VtableDefaultImpl(t) => VtableDefaultImpl(t.map_move_nested(op)),
VtableParam(n) => VtableParam(n.into_iter().map(op).collect()),
VtableObject(p) => VtableObject(p),
VtableBuiltin(no) => VtableBuiltin(no.map_move_nested(op)),
}
}
+impl<N> VtableDefaultImplData<N> {
+ pub fn iter_nested(&self) -> Iter<N> {
+ self.nested.iter()
+ }
+
+ pub fn map_nested<M, F>(&self, op: F) -> VtableDefaultImplData<M> where
+ F: FnMut(&N) -> M,
+ {
+ VtableDefaultImplData {
+ trait_def_id: self.trait_def_id,
+ nested: self.nested.iter().map(op).collect()
+ }
+ }
+
+ pub fn map_move_nested<M, F>(self, op: F) -> VtableDefaultImplData<M> where
+ F: FnMut(N) -> M,
+ {
+ let VtableDefaultImplData { trait_def_id, nested } = self;
+ VtableDefaultImplData {
+ trait_def_id: trait_def_id,
+ nested: nested.into_iter().map(op).collect()
+ }
+ }
+}
+
impl<N> VtableBuiltinData<N> {
pub fn iter_nested(&self) -> Iter<N> {
self.nested.iter()
/// 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 => {
}
// projection. And the projection where clause is handled
// in `assemble_candidates_from_param_env`.
}
+ super::VtableDefaultImpl(..) |
super::VtableBuiltin(..) => {
// These traits have no associated types.
selcx.tcx().sess.span_bug(
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! See `doc.rs` for high-level documentation
+//! See `README.md` for high-level documentation
#![allow(dead_code)] // FIXME -- just temporarily
pub use self::MethodMatchResult::*;
use self::BuiltinBoundConditions::*;
use self::EvaluationResult::*;
-use super::{DerivedObligationCause};
-use super::{project};
-use super::project::Normalized;
+use super::DerivedObligationCause;
+use super::project;
+use super::project::{normalize_with_depth, Normalized};
use super::{PredicateObligation, TraitObligation, ObligationCause};
-use super::{ObligationCauseCode, BuiltinDerivedObligation};
+use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation};
use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch};
use super::{Selection};
use super::{SelectionResult};
use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure,
- VtableFnPointer, VtableObject};
-use super::{VtableImplData, VtableObjectData, VtableBuiltinData};
+ VtableFnPointer, VtableObject, VtableDefaultImpl};
+use super::{VtableImplData, VtableObjectData, VtableBuiltinData, VtableDefaultImplData};
use super::object_safety;
use super::{util};
BuiltinCandidate(ty::BuiltinBound),
ParamCandidate(ty::PolyTraitRef<'tcx>),
ImplCandidate(ast::DefId),
+ DefaultImplCandidate(ast::DefId),
/// This is a trait matching with a projected type as `Self`, and
/// we found an applicable bound in the trait definition.
ObjectCandidate,
+ BuiltinObjectCandidate,
+
ErrorCandidate,
}
//
// The selection process begins by examining all in-scope impls,
// caller obligations, and so forth and assembling a list of
- // candidates. See `doc.rs` and the `Candidate` type for more details.
+ // candidates. See `README.md` and the `Candidate` type for more
+ // details.
fn candidate_from_obligation<'o>(&mut self,
stack: &TraitObligationStack<'o, 'tcx>)
debug!("obligation self ty is {}",
obligation.predicate.0.self_ty().repr(self.tcx()));
+ // User-defined copy impls are permitted, but only for
+ // structs and enums.
try!(self.assemble_candidates_from_impls(obligation, &mut candidates));
+ // For other types, we'll use the builtin rules.
try!(self.assemble_builtin_bound_candidates(ty::BoundCopy,
stack,
&mut candidates));
}
- Some(bound @ ty::BoundSend) |
- Some(bound @ ty::BoundSync) => {
- try!(self.assemble_candidates_from_impls(obligation, &mut candidates));
-
- // No explicit impls were declared for this type, consider the fallback rules.
- if candidates.vec.is_empty() && !candidates.ambiguous {
- try!(self.assemble_builtin_bound_candidates(bound, stack, &mut candidates));
- }
- }
-
Some(bound @ ty::BoundSized) => {
- // Sized and Copy are always automatically computed.
+ // Sized is never implementable by end-users, it is
+ // always automatically computed.
try!(self.assemble_builtin_bound_candidates(bound, stack, &mut candidates));
}
+ Some(ty::BoundSend) |
+ Some(ty::BoundSync) |
None => {
- // For the time being, we ignore user-defined impls for builtin-bounds, other than
- // `Copy`.
- // (And unboxed candidates only apply to the Fn/FnMut/etc traits.)
try!(self.assemble_closure_candidates(obligation, &mut candidates));
try!(self.assemble_fn_pointer_candidates(obligation, &mut candidates));
try!(self.assemble_candidates_from_impls(obligation, &mut candidates));
self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
try!(self.assemble_candidates_from_caller_bounds(stack, &mut candidates));
+ // Default implementations have lower priority, so we only
+ // consider triggering a default if there is no other impl that can apply.
+ if candidates.vec.len() == 0 {
+ try!(self.assemble_candidates_from_default_impls(obligation, &mut candidates));
+ }
debug!("candidate list size: {}", candidates.vec.len());
Ok(candidates)
}
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
debug!("assemble_candidates_from_impls(self_ty={})", self_ty.repr(self.tcx()));
- let all_impls = self.all_impls(obligation.predicate.def_id());
+ let def_id = obligation.predicate.def_id();
+ let all_impls = self.all_impls(def_id);
for &impl_def_id in &all_impls {
self.infcx.probe(|snapshot| {
let (skol_obligation_trait_pred, skol_map) =
}
});
}
+
+ Ok(())
+ }
+
+ fn assemble_candidates_from_default_impls(&mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>)
+ -> Result<(), SelectionError<'tcx>>
+ {
+
+ let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+ debug!("assemble_candidates_from_default_impls(self_ty={})", self_ty.repr(self.tcx()));
+
+ let def_id = obligation.predicate.def_id();
+
+ if ty::trait_has_default_impl(self.tcx(), def_id) {
+ match self_ty.sty {
+ ty::ty_trait(..) |
+ ty::ty_param(..) |
+ ty::ty_projection(..) => {
+ // In these cases, we don't know what the actual
+ // type is. Therefore, we cannot break it down
+ // into its constituent types. So we don't
+ // consider the `..` impl but instead just add no
+ // candidates: this means that typeck will only
+ // succeed if there is another reason to believe
+ // that this obligation holds. That could be a
+ // where-clause or, in the case of an object type,
+ // it could be that the object type lists the
+ // trait (e.g. `Foo+Send : Send`). See
+ // `compile-fail/typeck-default-trait-impl-send-param.rs`
+ // for an example of a test case that exercises
+ // this path.
+ }
+ ty::ty_infer(ty::TyVar(_)) => {
+ // the defaulted impl might apply, we don't know
+ candidates.ambiguous = true;
+ }
+ _ => {
+ if self.constituent_types_for_ty(self_ty).is_some() {
+ candidates.vec.push(DefaultImplCandidate(def_id.clone()))
+ } else {
+ // We don't yet know what the constituent
+ // types are. So call it ambiguous for now,
+ // though this is a bit stronger than
+ // necessary: that is, we know that the
+ // defaulted impl applies, but we can't
+ // process the confirmation step without
+ // knowing the constituent types. (Anyway, in
+ // the particular case of defaulted impls, it
+ // doesn't really matter much either way,
+ // since we won't be aiding inference by
+ // processing the confirmation step.)
+ candidates.ambiguous = true;
+ }
+ }
+ }
+ }
+
Ok(())
}
let poly_trait_ref = match self_ty.sty {
ty::ty_trait(ref data) => {
+ match self.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) {
+ Some(bound @ ty::BoundSend) | Some(bound @ ty::BoundSync) => {
+ if data.bounds.builtin_bounds.contains(&bound) {
+ debug!("assemble_candidates_from_object_ty: matched builtin bound, \
+ pushing candidate");
+ candidates.vec.push(BuiltinObjectCandidate);
+ return;
+ }
+ }
+ _ => {}
+ }
+
data.principal_trait_ref_with_self_ty(self.tcx(), self_ty)
}
ty::ty_infer(ty::TyVar(_)) => {
(&ImplCandidate(..), &ParamCandidate(..)) |
(&ClosureCandidate(..), &ParamCandidate(..)) |
(&FnPointerCandidate(..), &ParamCandidate(..)) |
+ (&BuiltinObjectCandidate(..), &ParamCandidate(_)) |
(&BuiltinCandidate(..), &ParamCandidate(..)) => {
// We basically prefer always prefer to use a
// where-clause over another option. Where clauses
// #18453.
true
}
+ (&DefaultImplCandidate(_), _) => {
+ // Prefer other candidates over default implementations.
+ self.tcx().sess.bug(
+ "default implementations shouldn't be recorded \
+ when there are other valid candidates");
+ }
(&ProjectionCandidate, &ParamCandidate(_)) => {
// FIXME(#20297) -- this gives where clauses precedent
// over projections. Really these are just two means
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(referent_ty) => { // Box<T>
+ 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 => {
- Ok(If(vec![referent_ty]))
+ 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 => {
- // sync and send are not implemented for *const, *mut
- Err(Unimplemented)
+ 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::BoundCopy | ty::BoundSync | ty::BoundSend => {
+ ty::BoundSized => Err(Unimplemented),
+ ty::BoundCopy => {
if data.bounds.builtin_bounds.contains(&bound) {
Ok(If(Vec::new()))
} else {
Err(Unimplemented)
}
}
+ ty::BoundSync | ty::BoundSend => {
+ self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()");
+ }
}
}
- ty::ty_rptr(_, ty::mt { ty: referent_ty, mutbl }) => {
+ ty::ty_rptr(_, ty::mt { ty: _, mutbl }) => {
// &mut T or &T
match bound {
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 => {
- Ok(If(vec![referent_ty]))
+ 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),
}
}
}
}
- ty::BoundSync |
- ty::BoundSend => {
- Ok(If(vec![element_ty]))
+ ty::BoundSync | ty::BoundSend => {
+ self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()");
}
}
}
ty::ty_str => {
// Equivalent to [u8]
match bound {
- ty::BoundSync |
- ty::BoundSend => {
- Ok(If(Vec::new()))
+ ty::BoundSync | ty::BoundSend => {
+ 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)
ty::struct_fields(self.tcx(), def_id, substs).iter()
.map(|f| f.mt.ty)
.collect();
- nominal(self, bound, def_id, types)
+ nominal(bound, types)
}
ty::ty_enum(def_id, substs) => {
.flat_map(|variant| variant.args.iter())
.cloned()
.collect();
- nominal(self, bound, def_id, types)
+ 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 |
- ty::BoundSync |
- ty::BoundSend => {
- Ok(If(vec!(ty)))
- }
-
- ty::BoundSized => {
- Err(Unimplemented)
- }
- }
- }
- 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>(this: &mut SelectionContext<'cx, 'tcx>,
- bound: ty::BuiltinBound,
- def_id: ast::DefId,
+ 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.
- let tcx = this.tcx();
match bound {
- ty::BoundSend => {
- if Some(def_id) == tcx.lang_items.managed_bound() {
- return Err(Unimplemented)
- }
- }
+ // Fallback to whatever user-defined impls exist in this case.
+ ty::BoundCopy => Ok(ParameterBuiltin),
- ty::BoundCopy => {
- return Ok(ParameterBuiltin)
- }
+ // Sized if all the component types are sized.
+ ty::BoundSized => Ok(If(types)),
- ty::BoundSync => {
- if
- Some(def_id) == tcx.lang_items.managed_bound() ||
- Some(def_id) == tcx.lang_items.unsafe_cell_type()
- {
- return Err(Unimplemented)
+ // Shouldn't be coming through here.
+ ty::BoundSend | ty::BoundSync => unreachable!(),
+ }
+ }
+ }
+
+ /// For default impls, we need to break apart a type into its
+ /// "constituent types" -- meaning, the types that it contains.
+ ///
+ /// Here are some (simple) examples:
+ ///
+ /// ```
+ /// (i32, u32) -> [i32, u32]
+ /// Foo where struct Foo { x: i32, y: u32 } -> [i32, u32]
+ /// Bar<i32> where struct Bar<T> { x: T, y: u32 } -> [i32, u32]
+ /// Zed<i32> where enum Zed { A(T), B(u32) } -> [i32, u32]
+ /// ```
+ fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Option<Vec<Ty<'tcx>>> {
+ match t.sty {
+ ty::ty_uint(_) |
+ ty::ty_int(_) |
+ ty::ty_bool |
+ ty::ty_float(_) |
+ ty::ty_bare_fn(..) |
+ ty::ty_str |
+ ty::ty_err |
+ ty::ty_infer(ty::IntVar(_)) |
+ ty::ty_infer(ty::FloatVar(_)) |
+ ty::ty_char => {
+ Some(Vec::new())
+ }
+
+ ty::ty_trait(..) |
+ ty::ty_param(..) |
+ ty::ty_projection(..) |
+ ty::ty_infer(ty::TyVar(_)) |
+ ty::ty_infer(ty::FreshTy(_)) |
+ ty::ty_infer(ty::FreshIntTy(_)) => {
+ self.tcx().sess.bug(
+ &format!(
+ "asked to assemble constituent types of unexpected type: {}",
+ t.repr(self.tcx())));
+ }
+
+ ty::ty_uniq(referent_ty) => { // Box<T>
+ Some(vec![referent_ty])
+ }
+
+ ty::ty_ptr(ty::mt { ty: element_ty, ..}) |
+ ty::ty_rptr(_, ty::mt { ty: element_ty, ..}) => {
+ Some(vec![element_ty])
+ },
+
+ ty::ty_vec(element_ty, _) => {
+ Some(vec![element_ty])
+ }
+
+ ty::ty_tup(ref tys) => {
+ // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
+ Some(tys.clone())
+ }
+
+ ty::ty_closure(def_id, _, substs) => {
+ assert_eq!(def_id.krate, ast::LOCAL_CRATE);
+
+ match self.closure_typer.closure_upvars(def_id, substs) {
+ Some(upvars) => {
+ Some(upvars.iter().map(|c| c.ty).collect())
+ }
+ None => {
+ None
}
}
+ }
- ty::BoundSized => { }
+ ty::ty_struct(def_id, substs) => {
+ Some(ty::struct_fields(self.tcx(), def_id, substs).iter()
+ .map(|f| f.mt.ty)
+ .collect())
}
- Ok(If(types))
+ ty::ty_enum(def_id, substs) => {
+ Some(ty::substd_enum_variants(self.tcx(), def_id, substs)
+ .iter()
+ .flat_map(|variant| variant.args.iter())
+ .map(|&ty| ty)
+ .collect())
+ }
}
}
//
// Confirmation unifies the output type parameters of the trait
// with the values found in the obligation, possibly yielding a
- // type error. See `doc.rs` for more details.
+ // type error. See `README.md` for more details.
fn confirm_candidate(&mut self,
obligation: &TraitObligation<'tcx>,
Ok(VtableParam(obligations))
}
+ DefaultImplCandidate(trait_def_id) => {
+ let data = try!(self.confirm_default_impl_candidate(obligation, trait_def_id));
+ Ok(VtableDefaultImpl(data))
+ }
+
ImplCandidate(impl_def_id) => {
let vtable_impl =
try!(self.confirm_impl_candidate(obligation, impl_def_id));
Ok(VtableClosure(closure_def_id, substs))
}
+ BuiltinObjectCandidate => {
+ // This indicates something like `(Trait+Send) :
+ // Send`. In this case, we know that this holds
+ // because that's what the object type is telling us,
+ // and there's really no additional obligations to
+ // prove and no types in particular to unify etc.
+ Ok(VtableParam(Vec::new()))
+ }
+
ObjectCandidate => {
let data = self.confirm_object_candidate(obligation);
Ok(VtableObject(data))
}).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());
VtableBuiltinData { nested: obligations }
}
+ /// This handles the case where a `impl Foo for ..` impl is being used.
+ /// The idea is that the impl applies to `X : Foo` if the following conditions are met:
+ ///
+ /// 1. For each constituent type `Y` in `X`, `Y : Foo` holds
+ /// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds.
+ fn confirm_default_impl_candidate(&mut self,
+ obligation: &TraitObligation<'tcx>,
+ impl_def_id: ast::DefId)
+ -> Result<VtableDefaultImplData<PredicateObligation<'tcx>>,
+ SelectionError<'tcx>>
+ {
+ debug!("confirm_default_impl_candidate({}, {})",
+ obligation.repr(self.tcx()),
+ impl_def_id.repr(self.tcx()));
+
+ 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)),
+ None => {
+ self.tcx().sess.bug(
+ &format!(
+ "asked to confirm default implementation for ambiguous type: {}",
+ self_ty.repr(self.tcx())));
+ }
+ }
+ }
+
+ /// See `confirm_default_impl_candidate`
+ fn vtable_default_impl(&mut self,
+ obligation: &TraitObligation<'tcx>,
+ trait_def_id: ast::DefId,
+ nested: Vec<Ty<'tcx>>)
+ -> VtableDefaultImplData<PredicateObligation<'tcx>>
+ {
+ let derived_cause = self.derived_cause(obligation, ImplDerivedObligation);
+
+ let obligations = nested.iter().map(|&nested_ty| {
+ // the obligation might be higher-ranked, e.g. for<'a> &'a
+ // int : Copy. In that case, we will wind up with
+ // late-bound regions in the `nested` vector. So for each
+ // one we instantiate to a skolemized region, do our work
+ // to produce something like `&'0 int : Copy`, and then
+ // re-bind it. This is a bit of busy-work but preserves
+ // the invariant that we only manipulate free regions, not
+ // bound ones.
+ self.infcx.try(|snapshot| {
+ let (skol_ty, skol_map) =
+ self.infcx().skolemize_late_bound_regions(&ty::Binder(nested_ty), snapshot);
+ let skol_predicate =
+ util::predicate_for_default_trait_impl(
+ self.tcx(),
+ derived_cause.clone(),
+ trait_def_id,
+ obligation.recursion_depth + 1,
+ skol_ty);
+ match skol_predicate {
+ Ok(skol_predicate) => Ok(self.infcx().plug_leaks(skol_map, snapshot,
+ &skol_predicate)),
+ Err(ErrorReported) => Err(ErrorReported)
+ }
+ })
+ }).collect::<Result<_, _>>();
+
+ let mut obligations = match obligations {
+ Ok(o) => o,
+ Err(ErrorReported) => Vec::new()
+ };
+
+ let _: Result<(),()> = self.infcx.try(|snapshot| {
+ let (_, skol_map) =
+ self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot);
+
+ let substs = obligation.predicate.to_poly_trait_ref().substs();
+ let trait_obligations = self.impl_or_trait_obligations(obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ trait_def_id,
+ substs,
+ skol_map,
+ snapshot);
+ obligations.push_all(trait_obligations.as_slice());
+ Ok(())
+ });
+
+ debug!("vtable_default_impl_data: obligations={}", obligations.repr(self.tcx()));
+
+ VtableDefaultImplData {
+ trait_def_id: trait_def_id,
+ nested: obligations
+ }
+ }
+
fn confirm_impl_candidate(&mut self,
obligation: &TraitObligation<'tcx>,
impl_def_id: ast::DefId)
skol_map.repr(self.tcx()));
let mut impl_obligations =
- self.impl_obligations(cause,
- recursion_depth,
- impl_def_id,
- &substs.value,
- skol_map,
- snapshot);
+ self.impl_or_trait_obligations(cause,
+ recursion_depth,
+ impl_def_id,
+ &substs.value,
+ skol_map,
+ snapshot);
debug!("vtable_impl: impl_def_id={} impl_obligations={}",
impl_def_id.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(),
}
}
ty::Binder(trait_ref)
}
- fn impl_obligations(&mut self,
- cause: ObligationCause<'tcx>,
- recursion_depth: uint,
- impl_def_id: ast::DefId,
- impl_substs: &Substs<'tcx>,
- skol_map: infer::SkolemizationMap,
- snapshot: &infer::CombinedSnapshot)
- -> VecPerParamSpace<PredicateObligation<'tcx>>
+ /// Returns the obligations that are implied by instantiating an
+ /// impl or trait. The obligations are substituted and fully
+ /// normalized. This is used when confirming an impl or default
+ /// impl.
+ fn impl_or_trait_obligations(&mut self,
+ cause: ObligationCause<'tcx>,
+ recursion_depth: uint,
+ def_id: ast::DefId, // of impl or trait
+ substs: &Substs<'tcx>, // for impl or trait
+ skol_map: infer::SkolemizationMap,
+ snapshot: &infer::CombinedSnapshot)
+ -> VecPerParamSpace<PredicateObligation<'tcx>>
{
- let impl_bounds = ty::lookup_predicates(self.tcx(), impl_def_id);
- let bounds = impl_bounds.instantiate(self.tcx(), impl_substs);
- let normalized_bounds =
- project::normalize_with_depth(self, cause.clone(), recursion_depth, &bounds);
- let normalized_bounds =
- self.infcx().plug_leaks(skol_map, snapshot, &normalized_bounds);
- let mut impl_obligations =
+ let predicates = ty::lookup_predicates(self.tcx(), def_id);
+ let predicates = predicates.instantiate(self.tcx(), substs);
+ let predicates = normalize_with_depth(self, cause.clone(), recursion_depth, &predicates);
+ let predicates = self.infcx().plug_leaks(skol_map, snapshot, &predicates);
+ let mut obligations =
util::predicates_for_generics(self.tcx(),
cause,
recursion_depth,
- &normalized_bounds.value);
- impl_obligations.extend(TypeSpace, normalized_bounds.obligations.into_iter());
- impl_obligations
+ &predicates.value);
+ obligations.extend(TypeSpace, predicates.obligations.into_iter());
+ obligations
}
#[allow(unused_comparisons)]
PhantomFnCandidate => format!("PhantomFnCandidate"),
ErrorCandidate => format!("ErrorCandidate"),
BuiltinCandidate(b) => format!("BuiltinCandidate({:?})", b),
+ BuiltinObjectCandidate => format!("BuiltinObjectCandidate"),
ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)),
ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)),
+ 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 util::ppaux::Repr;
use super::{Obligation, ObligationCause, PredicateObligation,
- VtableImpl, VtableParam, VtableImplData};
+ VtableImpl, VtableParam, VtableImplData, VtableDefaultImplData};
struct PredicateSet<'a,'tcx:'a> {
tcx: &'a ty::ctxt<'tcx>,
}
}
+
+pub fn predicate_for_trait_ref<'tcx>(
+ cause: ObligationCause<'tcx>,
+ trait_ref: Rc<ty::TraitRef<'tcx>>,
+ recursion_depth: uint)
+ -> Result<PredicateObligation<'tcx>, ErrorReported>
+{
+ Ok(Obligation {
+ cause: cause,
+ recursion_depth: recursion_depth,
+ predicate: trait_ref.as_predicate(),
+ })
+}
+
+pub fn predicate_for_default_trait_impl<'tcx>(
+ tcx: &ty::ctxt<'tcx>,
+ cause: ObligationCause<'tcx>,
+ trait_def_id: ast::DefId,
+ recursion_depth: uint,
+ param_ty: Ty<'tcx>)
+ -> Result<PredicateObligation<'tcx>, ErrorReported>
+{
+ let trait_ref = Rc::new(ty::TraitRef {
+ def_id: trait_def_id,
+ substs: tcx.mk_substs(Substs::empty().with_self_ty(param_ty))
+ });
+ predicate_for_trait_ref(cause, trait_ref, recursion_depth)
+}
+
pub fn predicate_for_builtin_bound<'tcx>(
tcx: &ty::ctxt<'tcx>,
cause: ObligationCause<'tcx>,
-> Result<PredicateObligation<'tcx>, ErrorReported>
{
let trait_ref = try!(trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty));
- Ok(Obligation {
- cause: cause,
- recursion_depth: recursion_depth,
- predicate: trait_ref.as_predicate(),
- })
+ predicate_for_trait_ref(cause, trait_ref, recursion_depth)
}
/// Cast a trait reference into a reference to one of its super
super::VtableImpl(ref v) =>
v.repr(tcx),
+ super::VtableDefaultImpl(ref t) =>
+ t.repr(tcx),
+
super::VtableClosure(ref d, ref s) =>
format!("VtableClosure({},{})",
d.repr(tcx),
}
}
+impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableDefaultImplData<N> {
+ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+ format!("VtableDefaultImplData(trait_def_id={}, nested={})",
+ self.trait_def_id.repr(tcx),
+ self.nested.repr(tcx))
+ }
+}
+
impl<'tcx> Repr<'tcx> for super::VtableObjectData<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
format!("VtableObject(object_ty={})",
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
/// Maps a trait onto a list of impls of that trait.
pub trait_impls: RefCell<DefIdMap<Rc<RefCell<Vec<ast::DefId>>>>>,
+ /// Maps a trait onto a list of *default* trait implementations
+ default_trait_impls: RefCell<DefIdMap<ast::DefId>>,
+
/// Maps a DefId of a type to a list of its inherent impls.
/// Contains implementations of methods that are inherent to a type.
/// Methods in these implementations don't need to be exported.
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()),
destructor_for_type: RefCell::new(DefIdMap()),
destructors: RefCell::new(DefIdSet()),
trait_impls: RefCell::new(DefIdMap()),
+ default_trait_impls: RefCell::new(DefIdMap()),
inherent_impls: RefCell::new(DefIdMap()),
impl_items: RefCell::new(DefIdMap()),
used_unsafe: RefCell::new(NodeSet()),
{
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) => {
let types_a = substs_a.types.get_slice(subst::TypeSpace);
let types_b = substs_b.types.get_slice(subst::TypeSpace);
- let pairs = types_a.iter().zip(types_b.iter());
+ let mut pairs = types_a.iter().zip(types_b.iter());
pairs.all(|(&a, &b)| same_type(a, b))
}
}
}
-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
- }
- }
- _ => 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,
..
|| Rc::new(csearch::get_item_variances(&tcx.sess.cstore, item_id)))
}
+pub fn trait_default_impl(tcx: &ctxt, trait_def_id: DefId) -> Option<ast::DefId> {
+ match tcx.default_trait_impls.borrow().get(&trait_def_id) {
+ Some(id) => Some(*id),
+ None => None
+ }
+}
+
+pub fn trait_has_default_impl(tcx: &ctxt, trait_def_id: DefId) -> bool {
+ match tcx.lang_items.to_builtin_kind(trait_def_id) {
+ Some(BoundSend) | Some(BoundSync) => true,
+ _ => tcx.default_trait_impls.borrow().contains_key(&trait_def_id)
+ }
+}
+
+/// Records a trait-to-implementation mapping.
+pub fn record_default_trait_implementation(tcx: &ctxt,
+ trait_def_id: DefId,
+ impl_def_id: DefId) {
+
+ // We're using the latest implementation found as the reference one.
+ // Duplicated implementations are caught and reported in the coherence
+ // step.
+ tcx.default_trait_impls.borrow_mut().insert(trait_def_id, impl_def_id);
+}
+
+
/// Records a trait-to-implementation mapping.
pub fn record_trait_implementation(tcx: &ctxt,
trait_def_id: DefId,
}
csearch::each_implementation_for_trait(&tcx.sess.cstore, trait_id,
- |implementation_def_id| {
+ |implementation_def_id|{
let impl_items = csearch::get_impl_items(&tcx.sess.cstore, implementation_def_id);
- // Record the trait->implementation mapping.
- record_trait_implementation(tcx, trait_id, implementation_def_id);
+ if csearch::is_default_trait(&tcx.sess.cstore, implementation_def_id) {
+ record_default_trait_implementation(tcx, trait_id,
+ implementation_def_id);
+ tcx.populated_external_traits.borrow_mut().insert(trait_id);
+
+ // Nothing else to do for default trait implementations since
+ // they are not allowed to have type parameters, methods, or any
+ // other item that could be associated to a trait implementation.
+ return;
+ } else {
+ // Record the trait->implementation mapping.
+ record_trait_implementation(tcx, trait_id, implementation_def_id);
+ }
// For any methods that use a default implementation, add them to
// the map. This is a bit unfortunate.
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),
}
}
}
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableDefaultImplData<N> {
+ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableDefaultImplData<N> {
+ traits::VtableDefaultImplData {
+ trait_def_id: self.trait_def_id,
+ nested: self.nested.fold_with(folder),
+ }
+ }
+}
+
impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinData<N> {
fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableBuiltinData<N> {
traits::VtableBuiltinData {
fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Vtable<'tcx, N> {
match *self {
traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)),
+ traits::VtableDefaultImpl(ref t) => traits::VtableDefaultImpl(t.fold_with(folder)),
traits::VtableClosure(d, ref s) => {
traits::VtableClosure(d, s.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 {
}
let mut tail = &msg[head..];
- let third = tail.find_str("(values differ")
- .or(tail.find_str("(lifetime"))
- .or(tail.find_str("(cyclic type of infinite size"));
+ let third = tail.find("(values differ")
+ .or(tail.find("(lifetime"))
+ .or(tail.find("(cyclic type of infinite size"));
// Insert `\n` before any remaining messages which match.
if let Some(pos) = third {
// The end of the message may just be wrapped in `()` without
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()),
F: FnOnce(T) -> U,
{
let key = arg.clone();
- let result = cache.borrow().get(&key).map(|result| result.clone());
+ let result = cache.borrow().get(&key).cloned();
match result {
Some(result) => result,
None => {
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()
and `*LV` is a pointer dereference. There is no auto-deref or other
niceties. This means that if you have a type like:
-```text
-struct S { f: uint }
+```rust
+struct S { f: i32 }
```
and a variable `a: Box<S>`, then the rust expression `a.f` would correspond
Here is the formal grammar for the types we'll consider:
```text
-TY = () | S<'LT...> | Box<TY> | & 'LT MQ TY
-MQ = mut | imm | const
+TY = i32 | bool | S<'LT...> | Box<TY> | & 'LT MQ TY
+MQ = mut | imm
```
Most of these types should be pretty self explanatory. Here `S` is a
Now, imagine we had a program like this:
-```text
-struct Foo { f: uint, g: uint }
+```rust
+struct Foo { f: i32, g: i32 }
...
'a: {
- let mut x: Box<Foo> = ...;
- let y = &mut (*x).f;
- x = ...;
+ let mut x: Box<Foo> = ...;
+ let y = &mut (*x).f;
+ x = ...;
}
```
Now that we hopefully have some kind of intuitive feeling for how the
borrow checker works, let's look a bit more closely now at the precise
-conditions that it uses. For simplicity I will ignore const loans.
+conditions that it uses.
I will present the rules in a modified form of standard inference
rules, which looks as follows:
## Checking mutability
Checking mutability is fairly straightforward. We just want to prevent
-immutable data from being borrowed as mutable. Note that it is ok to
-borrow mutable data as immutable, since that is simply a
-freeze. Formally we define a predicate `MUTABLE(LV, MQ)` which, if
-defined, means that "borrowing `LV` with mutability `MQ` is ok. The
-Rust code corresponding to this predicate is the function
-`check_mutability` in `middle::borrowck::gather_loans`.
+immutable data from being borrowed as mutable. Note that it is ok to borrow
+mutable data as immutable, since that is simply a freeze. The judgement
+`MUTABILITY(LV, MQ)` means the mutability of `LV` is compatible with a borrow
+of mutability `MQ`. The Rust code corresponding to this predicate is the
+function `check_mutability` in `middle::borrowck::gather_loans`.
### Checking mutability of variables
Let's begin with the rules for variables, which state that if a
variable is declared as mutable, it may be borrowed any which way, but
-otherwise the variable must be borrowed as immutable or const:
+otherwise the variable must be borrowed as immutable:
```text
MUTABILITY(X, MQ) // M-Var-Mut
DECL(X) = mut
-MUTABILITY(X, MQ) // M-Var-Imm
+MUTABILITY(X, imm) // M-Var-Imm
DECL(X) = imm
- MQ = imm | const
```
### Checking mutability of owned content
### Checking mutability of immutable pointer types
Immutable pointer types like `&T` can only
-be borrowed if MQ is immutable or const:
+be borrowed if MQ is immutable:
```text
-MUTABILITY(*LV, MQ) // M-Deref-Borrowed-Imm
+MUTABILITY(*LV, imm) // M-Deref-Borrowed-Imm
TYPE(LV) = &Ty
- MQ == imm | const
```
### Checking mutability of mutable pointer types
## Checking aliasability
-The goal of the aliasability check is to ensure that we never permit
-`&mut` borrows of aliasable data. Formally we define a predicate
-`ALIASABLE(LV, MQ)` which if defined means that
-"borrowing `LV` with mutability `MQ` is ok". The
-Rust code corresponding to this predicate is the function
-`check_aliasability()` in `middle::borrowck::gather_loans`.
+The goal of the aliasability check is to ensure that we never permit `&mut`
+borrows of aliasable data. The judgement `ALIASABLE(LV, MQ)` means the
+aliasability of `LV` is compatible with a borrow of mutability `MQ`. The Rust
+code corresponding to this predicate is the function `check_aliasability()` in
+`middle::borrowck::gather_loans`.
### Checking aliasability of variables
`MQ`". The Rust code corresponding to this predicate is the module
`middle::borrowck::gather_loans::lifetime`.
-### The Scope function
-
-Several of the rules refer to a helper function `SCOPE(LV)=LT`. The
-`SCOPE(LV)` yields the lifetime `LT` for which the lvalue `LV` is
-guaranteed to exist, presuming that no mutations occur.
-
-The scope of a local variable is the block where it is declared:
-
-```text
- SCOPE(X) = block where X is declared
-```
-
-The scope of a field is the scope of the struct:
-
-```text
- SCOPE(LV.f) = SCOPE(LV)
-```
-
-The scope of a unique referent is the scope of the pointer, since
-(barring mutation or moves) the pointer will not be freed until
-the pointer itself `LV` goes out of scope:
-
-```text
- SCOPE(*LV) = SCOPE(LV) if LV has type Box<T>
-```
-
-The scope of a borrowed referent is the scope associated with the
-pointer. This is a conservative approximation, since the data that
-the pointer points at may actually live longer:
-
-```text
- SCOPE(*LV) = LT if LV has type &'LT T or &'LT mut T
-```
-
### Checking lifetime of variables
The rule for variables states that a variable can only be borrowed a
```text
LIFETIME(X, LT, MQ) // L-Local
- LT <= SCOPE(X)
+ LT <= block where X is declared
```
### Checking lifetime for owned content
```text
&mut LV => RESTRICTIONS(LV, LT, MUTATE|CLAIM|FREEZE)
&LV => RESTRICTIONS(LV, LT, MUTATE|CLAIM)
-&const LV => RESTRICTIONS(LV, LT, [])
```
The reasoning here is that a mutable borrow must be the only writer,
therefore it prevents other writes (`MUTATE`), mutable borrows
(`CLAIM`), and immutable borrows (`FREEZE`). An immutable borrow
permits other immutable borrows but forbids writes and mutable borrows.
-Finally, a const borrow just wants to be sure that the value is not
-moved out from under it, so no actions are forbidden.
### Restrictions for loans of a local variable
of the `&Ty` pointer. In simple cases, this clause is redundant, since
the `LIFETIME()` function will already enforce the required rule:
-```
-fn foo(point: &'a Point) -> &'static f32 {
+```rust
+fn foo(point: &'a Point) -> &'static i32 {
&point.x // Error
}
```
but also by the basic `LIFETIME()` check. However, in more advanced
examples involving multiple nested pointers, clause (1) is needed:
-```
-fn foo(point: &'a &'b mut Point) -> &'b f32 {
+```rust
+fn foo(point: &'a &'b mut Point) -> &'b i32 {
&point.x // Error
}
```
As a final twist, consider the case of two nested *immutable*
pointers, rather than a mutable pointer within an immutable one:
-```
-fn foo(point: &'a &'b Point) -> &'b f32 {
+```rust
+fn foo(point: &'a &'b Point) -> &'b i32 {
&point.x // OK
}
```
create a borrowed pointer that outlives the memory it points at. So
`LIFETIME` prevents a function like this:
-```
-fn get_1<'a>() -> &'a int {
+```rust
+fn get_1<'a>() -> &'a i32 {
let x = 1;
&x
}
mutate it. This distinction is important for type checking functions
like this one:
-```
-fn inc_and_get<'a>(p: &'a mut Point) -> &'a int {
+```rust
+fn inc_and_get<'a>(p: &'a mut Point) -> &'a i32 {
p.x += 1;
&p.x
}
`*p` is borrowed since that would be a move of `p`, as `&mut` pointers
are affine.)
-### Restrictions for loans of const aliasable referents
-
-Freeze pointers are read-only. There may be `&mut` or `&` aliases, and
-we can not prevent *anything* but moves in that case. So the
-`RESTRICTIONS` function is only defined if `ACTIONS` is the empty set.
-Because moves from a `&const` lvalue are never legal, it is not
-necessary to add any restrictions at all to the final result.
-
-```text
- RESTRICTIONS(*LV, LT, []) = [] // R-Deref-Freeze-Borrowed
- TYPE(LV) = &const Ty
-```
-
### Restrictions for loans of mutable borrowed referents
Mutable borrowed pointers are guaranteed to be the only way to mutate
Here is a concrete example of a bug this rule prevents:
-```
+```rust
// Test region-reborrow-from-shorter-mut-ref.rs:
fn copy_pointer<'a,'b,T>(x: &'a mut &'b mut T) -> &'b mut T {
&mut **p // ERROR due to clause (1)
and access it via that new name, thus bypassing the restrictions on
the old name. Here is an example:
-```
+```rust
// src/test/compile-fail/borrowck-move-mut-base-ptr.rs
-fn foo(t0: &mut int) {
- let p: &int = &*t0; // Freezes `*t0`
+fn foo(t0: &mut i32) {
+ let p: &i32 = &*t0; // Freezes `*t0`
let t1 = t0; //~ ERROR cannot move out of `t0`
*t1 = 22; // OK, not a write through `*t0`
}
scenarios. The most obvious is that the mutable borrow itself becomes
another path to access the same data, as shown here:
-```
+```rust
// src/test/compile-fail/borrowck-mut-borrow-of-mut-base-ptr.rs
-fn foo<'a>(mut t0: &'a mut int,
- mut t1: &'a mut int) {
- let p: &int = &*t0; // Freezes `*t0`
+fn foo<'a>(mut t0: &'a mut i32,
+ mut t1: &'a mut i32) {
+ let p: &i32 = &*t0; // Freezes `*t0`
let mut t2 = &mut t0; //~ ERROR cannot borrow `t0`
**t2 += 1; // Mutates `*t0`
}
Another danger with an `&mut` pointer is that we could swap the `t0`
value away to create a new path:
-```
+```rust
// src/test/compile-fail/borrowck-swap-mut-base-ptr.rs
-fn foo<'a>(mut t0: &'a mut int,
- mut t1: &'a mut int) {
- let p: &int = &*t0; // Freezes `*t0`
+fn foo<'a>(mut t0: &'a mut i32,
+ mut t1: &'a mut i32) {
+ let p: &i32 = &*t0; // Freezes `*t0`
swap(&mut t0, &mut t1); //~ ERROR cannot borrow `t0`
*t1 = 22;
}
referent is claimed, even freezing the base pointer can be dangerous,
as shown in the following example:
-```
+```rust
// src/test/compile-fail/borrowck-borrow-of-mut-base-ptr.rs
-fn foo<'a>(mut t0: &'a mut int,
- mut t1: &'a mut int) {
- let p: &mut int = &mut *t0; // Claims `*t0`
+fn foo<'a>(mut t0: &'a mut i32,
+ mut t1: &'a mut i32) {
+ let p: &mut i32 = &mut *t0; // Claims `*t0`
let mut t2 = &t0; //~ ERROR cannot borrow `t0`
- let q: &int = &*t2; // Freezes `*t0` but not through `*p`
+ let q: &i32 = &*t2; // Freezes `*t0` but not through `*p`
*p += 1; // violates type of `*q`
}
```
Here the problem is that `*t0` is claimed by `p`, and hence `p` wants
to be the controlling pointer through which mutation or freezes occur.
-But `t2` would -- if it were legal -- have the type `& &mut int`, and
+But `t2` would -- if it were legal -- have the type `& &mut i32`, and
hence would be a mutable pointer in an aliasable location, which is
considered frozen (since no one can write to `**t2` as it is not a
-unique path). Therefore, we could reasonably create a frozen `&int`
+unique path). Therefore, we could reasonably create a frozen `&i32`
pointer pointing at `*t0` that coexists with the mutable pointer `p`,
which is clearly unsound.
However, it is not always unsafe to freeze the base pointer. In
particular, if the referent is frozen, there is no harm in it:
-```
+```rust
// src/test/run-pass/borrowck-borrow-of-mut-base-ptr-safe.rs
-fn foo<'a>(mut t0: &'a mut int,
- mut t1: &'a mut int) {
- let p: &int = &*t0; // Freezes `*t0`
+fn foo<'a>(mut t0: &'a mut i32,
+ mut t1: &'a mut i32) {
+ let p: &i32 = &*t0; // Freezes `*t0`
let mut t2 = &t0;
- let q: &int = &*t2; // Freezes `*t0`, but that's ok...
- let r: &int = &*t0; // ...after all, could do same thing directly.
+ let q: &i32 = &*t2; // Freezes `*t0`, but that's ok...
+ let r: &i32 = &*t0; // ...after all, could do same thing directly.
}
```
already frozen. In particular, we cannot assign to `*t0` through the
new alias `t2`, as demonstrated in this test case:
-```
+```rust
// src/test/run-pass/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs
-fn foo(t0: & &mut int) {
+fn foo(t0: & &mut i32) {
let t1 = t0;
- let p: &int = &**t0;
+ let p: &i32 = &**t0;
**t1 = 22; //~ ERROR cannot assign
}
```
prevent `const` borrows of the base pointer when the referent is
borrowed.
+[ Previous revisions of this document discussed `&const` in more detail.
+See the revision history. ]
+
# Moves and initialization
The borrow checker is also in charge of ensuring that:
Let's look at a simple example:
-```
-fn foo(a: Box<int>) {
- let b: Box<int>; // Gen bit 0.
+```rust
+fn foo(a: Box<i32>) {
+ let b: Box<i32>; // Gen bit 0.
if cond { // Bits: 0
use(&*a);
use(&*b); // Error.
}
-fn use(a: &int) { }
+fn use(a: &i32) { }
```
In this example, the variable `b` is created uninitialized. In one
A simple example of this is the following:
```rust
-struct D { p: int }
-impl D { fn new(x: int) -> D { ... }
+struct D { p: i32 }
+impl D { fn new(x: i32) -> D { ... }
impl Drop for D { ... }
fn foo(a: D, b: D, t: || -> bool) {
the following:
```rust
-fn foo(a: [D; 10], i: uint) -> D {
+fn foo(a: [D; 10], i: i32) -> D {
a[i]
}
```
would arise is the following:
```rust
-fn foo(a: [D; 10], b: [D; 10], i: uint, t: bool) -> D {
+fn foo(a: [D; 10], b: [D; 10], i: i32, t: bool) -> D {
if t {
a[i]
} else {
There are a number of ways that the trans backend could choose to
compile this (e.g. a `[bool; 10]` array for each such moved array;
-or an `Option<uint>` for each moved array). From the viewpoint of the
+or an `Option<usize>` for each moved array). From the viewpoint of the
borrow-checker, the important thing is to record what kind of fragment
is implied by the relevant moves.
//! Helper routines used for fragmenting structural paths due to moves for
//! tracking drop obligations. Please see the extensive comments in the
-//! section "Structural fragments" in `doc.rs`.
+//! section "Structural fragments" in `README.md`.
use self::Fragment::*;
//! lvalue `cmt` is guaranteed to be valid without any
//! rooting etc, and presuming `cmt` is not mutated.
- // See the SCOPE(LV) function in doc.rs
-
match cmt.cat {
mc::cat_rvalue(temp_scope) => {
temp_scope
}
}
-/// Implements the A-* rules in doc.rs.
+/// Implements the A-* rules in README.md.
fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
borrow_span: Span,
loan_cause: euv::LoanCause,
cmt: mc::cmt<'tcx>,
req_kind: ty::BorrowKind)
-> Result<(),()> {
- //! Implements the M-* rules in doc.rs.
+ //! Implements the M-* rules in README.md.
match req_kind {
ty::UniqueImmBorrow | ty::ImmBorrow => {
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.
#[derive(PartialEq, Eq, Hash, Debug)]
pub enum LoanPathKind<'tcx> {
- LpVar(ast::NodeId), // `x` in doc.rs
+ LpVar(ast::NodeId), // `x` in README.md
LpUpvar(ty::UpvarId), // `x` captured by-value into closure
LpDowncast(Rc<LoanPath<'tcx>>, ast::DefId), // `x` downcast to particular enum variant
LpExtend(Rc<LoanPath<'tcx>>, mc::MutabilityCategory, LoanPathElem)
#[derive(Copy, PartialEq, Eq, Hash, Debug)]
pub enum LoanPathElem {
- LpDeref(mc::PointerKind), // `*LV` in doc.rs
- LpInterior(InteriorKind), // `LV.f` in doc.rs
+ LpDeref(mc::PointerKind), // `*LV` in README.md
+ LpInterior(InteriorKind), // `LV.f` in README.md
}
pub fn closure_to_block(closure_id: ast::NodeId,
};
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 => {
// except according to those terms.
//! Data structures used for tracking moves. Please see the extensive
-//! comments in the section "Moves and initialization" in `doc.rs`.
+//! comments in the section "Moves and initialization" in `README.md`.
pub use self::MoveKind::*;
pub mod fragments;
pub struct MoveData<'tcx> {
- /// Move paths. See section "Move paths" in `doc.rs`.
+ /// Move paths. See section "Move paths" in `README.md`.
pub paths: RefCell<Vec<MovePath<'tcx>>>,
/// Cache of loan path to move path index, for easy lookup.
/// assignments into the provided data flow contexts.
/// Moves are generated by moves and killed by assignments and
/// scoping. Assignments are generated by assignment to variables and
- /// killed by scoping. See `doc.rs` for more details.
+ /// killed by scoping. See `README.md` for more details.
fn add_gen_kills(&self,
tcx: &ty::ctxt<'tcx>,
dfcx_moves: &mut MoveDataFlow,
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", (), |_|
type Err = ();
fn from_str(s: &str) -> Result<UserIdentifiedItem, ()> {
Ok(s.parse().map(ItemViaNode).unwrap_or_else(|_| {
- ItemViaPath(s.split_str("::").map(|s| s.to_string()).collect())
+ ItemViaPath(s.split("::").map(|s| s.to_string()).collect())
}))
}
}
ast::ItemEnum(..) | ast::ItemStruct(..) |
ast::ItemTrait(..) | ast::ItemImpl(..) |
- ast::ItemMac(..) => {
+ ast::ItemMac(..) | ast::ItemDefaultImpl(..) => {
None
}
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};
match item.node {
// impls/extern blocks do not break the "public chain" because they
// cannot have visibility qualifiers on them anyway
- ast::ItemImpl(..) | ast::ItemForeignMod(..) => {}
+ ast::ItemImpl(..) | ast::ItemDefaultImpl(..) | ast::ItemForeignMod(..) => {}
// Traits are a little special in that even if they themselves are
// not public they may still be exported.
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::DefTy(_, true) => ck("enum"),
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);
}
}
}
}
+ ast::ItemDefaultImpl(..) |
ast::ItemConst(..) | ast::ItemStatic(..) | ast::ItemStruct(..) |
ast::ItemFn(..) | ast::ItemMod(..) | ast::ItemTy(..) |
ast::ItemExternCrate(_) | ast::ItemUse(_) | ast::ItemMac(..) => {}
}
}
- ast::ItemExternCrate(_) | ast::ItemUse(_) |
+ ast::ItemDefaultImpl(..) | ast::ItemExternCrate(_) | ast::ItemUse(_) |
ast::ItemStatic(..) | ast::ItemConst(..) |
ast::ItemFn(..) | ast::ItemMod(..) | ast::ItemTy(..) |
ast::ItemMac(..) => {}
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::{ForeignItem, ForeignItemFn, ForeignItemStatic};
use syntax::ast::{Item, ItemConst, ItemEnum, ItemExternCrate, ItemFn};
-use syntax::ast::{ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic};
+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()
- }
-
- ItemImpl(_, _, _, Some(_), _, _) => parent.clone(),
+ ItemDefaultImpl(_, _) |
+ 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(DefTrait(def_id), sp, modifiers);
}
/// 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
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};
+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.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_) => {
- self.with_scope(Some(name), |this| {
- this.resolve_module(module_, item.span, name,
- item.id);
- });
- }
-
- ItemForeignMod(ref foreign_module) => {
+ ItemMod(_) | ItemForeignMod(_) => {
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(&DefTrait(..)) | 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);
-
- // 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);
- }
- }
+ self.label_ribs.push(Rib::new(rib_kind));
- // 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 {
- (DefTrait(_), _) => {
- 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,
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::DefTrait(_) => Some(recorder::TypeRef),
def::DefStatic(_, _) |
def::DefConst(_) |
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) => {
- match self.lookup_type_ref(id) {
- Some(id) => {
- let sub_span = self.span.sub_span_for_type_name(path.span);
- self.fmt.ref_str(recorder::TypeRef,
- path.span,
- sub_span,
- id,
- self.cur_scope);
- self.fmt.impl_str(path.span,
- sub_span,
- item.id,
- Some(id),
- trait_id,
- self.cur_scope);
- },
- None => ()
- }
+ ast::TyPath(None, ref path) => {
+ let sub_span = self.span.sub_span_for_type_name(path.span);
+ let self_id = self.lookup_type_ref(typ.id).map(|id| {
+ self.fmt.ref_str(recorder::TypeRef,
+ path.span,
+ sub_span,
+ id,
+ self.cur_scope);
+ id
+ });
+ self.fmt.impl_str(path.span,
+ sub_span,
+ item.id,
+ self_id,
+ trait_id,
+ self.cur_scope);
},
_ => {
// Less useful case, impl for a compound type.
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(..) |
ast::PatStruct(ref path, ref fields, _) => {
self.collected_paths.push((p.id, path.clone(), false, recorder::StructRef));
visit::walk_path(self, path);
- let struct_def = match self.lookup_type_ref(p.id) {
- Some(sd) => sd,
- None => {
- self.sess.span_bug(p.span,
- &format!("Could not find struct_def for `{}`",
- self.span.snippet(p.span)));
+
+ 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 ty::ty_to_def_id(ty::node_id_to_type(&self.analysis.ty_cx, p.id)) {
+ None => {
+ self.sess.span_bug(p.span,
+ &format!("Could not find struct_def for `{}`",
+ self.span.snippet(p.span)));
+ }
+ Some(def_id) => Some(def_id),
+ }
}
};
- for &Spanned { node: ref field, span } in fields {
- let sub_span = self.span.span_for_first_ident(span);
- let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def);
- for f in fields {
- if f.name == field.ident.name {
- self.fmt.ref_str(recorder::VarRef,
- span,
- sub_span,
- f.id,
- self.cur_scope);
- break;
+
+ if let Some(struct_def) = struct_def {
+ let struct_fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def);
+ for &Spanned { node: ref field, span } in fields {
+ let sub_span = self.span.span_for_first_ident(span);
+ for f in &struct_fields {
+ if f.name == field.ident.name {
+ self.fmt.ref_str(recorder::VarRef,
+ span,
+ sub_span,
+ f.id,
+ self.cur_scope);
+ break;
+ }
}
+ self.visit_pat(&*field.pat);
}
- self.visit_pat(&*field.pat);
}
}
ast::PatEnum(ref path, _) => {
}
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()
}
}
self_type.repr(ccx.tcx()));
(&function_type.sig, RustCall, Some(llenvironment_type))
}
- _ => panic!("expected closure or fn")
+ _ => ccx.sess().bug("expected closure or fn")
};
let sig = ty::erase_late_bound_regions(ccx.tcx(), sig);
pub fn set_llvm_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) {
use syntax::attr::*;
// Set the inline hint if there is one
- match find_inline_attr(attrs) {
+ match find_inline_attr(Some(ccx.sess().diagnostic()), attrs) {
InlineHint => set_inline_hint(llfn),
InlineAlways => set_always_inline(llfn),
InlineNever => set_no_inline(llfn),
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();
node_id: ast::NodeId,
node_type: Ty<'tcx>)
-> ValueRef {
- match node_type.sty {
- ty::ty_bare_fn(_, ref f) => {
- assert!(f.abi == Rust || f.abi == RustCall);
+ if let ty::ty_bare_fn(_, ref f) = node_type.sty {
+ if f.abi != Rust && f.abi != RustCall {
+ ccx.sess().span_bug(sp, &format!("only the `{}` or `{}` calling conventions are valid \
+ for this function; `{}` was specified",
+ Rust.name(), RustCall.name(), f.abi.name()));
}
- _ => panic!("expected bare rust fn")
- };
+ } else {
+ ccx.sess().span_bug(sp, "expected bare rust function")
+ }
let llfn = decl_rust_fn(ccx, node_type, &sym[..]);
finish_register_fn(ccx, sp, sym, node_id, llfn);
llfn
}
- _ => panic!("get_item_val: weird result in table")
+ _ => ccx.sess().bug("get_item_val: weird result in table")
};
match attr::first_attr_value_str_by_name(&i.attrs,
let args = match v.node.kind {
ast::TupleVariantKind(ref args) => args,
ast::StructVariantKind(_) => {
- panic!("struct variant kind unexpected in get_item_val")
+ ccx.sess().bug("struct variant kind unexpected in get_item_val")
}
};
assert!(args.len() != 0);
ast::ItemEnum(_, _) => {
register_fn(ccx, (*v).span, sym, id, ty)
}
- _ => panic!("NodeVariant, shouldn't happen")
+ _ => ccx.sess().bug("NodeVariant, shouldn't happen")
};
set_inline_hint(llfn);
llfn
let sym = exported_name(ccx, id, mty, &m.attrs);
- let llfn = register_fn(ccx, m.span, sym, id, mty);
- set_llvm_fn_attrs(ccx, &m.attrs, llfn);
- llfn
+ if let ty::ty_bare_fn(_, ref f) = mty.sty {
+ let llfn = if f.abi == Rust || f.abi == RustCall {
+ register_fn(ccx, m.span, sym, id, mty)
+ } else {
+ foreign::register_rust_fn_with_foreign_abi(ccx, m.span, sym, id)
+ };
+ set_llvm_fn_attrs(ccx, &m.attrs, llfn);
+ return llfn;
+ } else {
+ ccx.sess().span_bug(m.span, "expected bare rust function");
+ }
}
pub fn crate_ctxt_to_encode_parms<'a, 'tcx>(cx: &'a SharedCrateContext<'tcx>,
// 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::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) {
if is_rust_fn {
let mut llargs = Vec::new();
- if let (ty::FnConverging(ret_ty), Some(llretslot)) = (ret_ty, opt_llretslot) {
+ if let (ty::FnConverging(ret_ty), Some(mut llretslot)) = (ret_ty, opt_llretslot) {
if type_of::return_uses_outptr(ccx, ret_ty) {
+ let llformal_ret_ty = type_of::type_of(ccx, ret_ty).ptr_to();
+ let llret_ty = common::val_ty(llretslot);
+ if llformal_ret_ty != llret_ty {
+ // this could happen due to e.g. subtyping
+ debug!("casting actual return type ({}) to match formal ({})",
+ bcx.llty_str(llret_ty), bcx.llty_str(llformal_ret_ty));
+ llretslot = PointerCast(bcx, llretslot, llformal_ret_ty);
+ }
llargs.push(llretslot);
}
}
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));
C_integral(Type::i32(ccx), i as u64, true)
}
+pub fn C_u32(ccx: &CrateContext, i: u32) -> ValueRef {
+ C_integral(Type::i32(ccx), i as u64, false)
+}
+
pub fn C_u64(ccx: &CrateContext, i: u64) -> ValueRef {
C_integral(Type::i64(ccx), i, false)
}
(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))
}
}
}
let loc = bcx.sess().codemap().lookup_char_pos(call_info.span.lo);
let filename = token::intern_and_get_ident(&loc.file.name);
let filename = C_str_slice(ccx, filename);
- let line = C_uint(ccx, loc.line);
+ let line = C_u32(ccx, loc.line as u32);
let expr_file_line_const = C_struct(ccx, &[v_str, filename, line], false);
let expr_file_line = consts::addr_of(ccx, expr_file_line_const,
"panic_loc", call_info.id);
// Invoke the lang item
let filename = C_str_slice(ccx, filename);
- let line = C_uint(ccx, loc.line);
+ let line = C_u32(ccx, loc.line as u32);
let file_line_const = C_struct(ccx, &[filename, line], false);
let file_line = consts::addr_of(ccx, file_line_const,
"panic_bounds_check_loc", call_info.id);
/// A `Datum` encapsulates the result of evaluating an expression. It
/// describes where the value is stored, what Rust type the value has,
/// whether it is addressed by reference, and so forth. Please refer
-/// the section on datums in `doc.rs` for more details.
+/// the section on datums in `README.md` for more details.
#[derive(Clone, Copy)]
pub struct Datum<'tcx, K> {
/// The llvm value. This is either a pointer to the Rust value or
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);
Callee { bcx: bcx, data: Fn(llfn) }
}
traits::VtableBuiltin(..) |
+ traits::VtableDefaultImpl(..) |
traits::VtableParam(..) => {
bcx.sess().bug(
&format!("resolved vtable bad vtable {} in trans",
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"));
let methods = traits::supertraits(tcx, trait_ref.clone()).flat_map(|trait_ref| {
let vtable = fulfill_obligation(ccx, DUMMY_SP, trait_ref.clone());
match vtable {
+ // Should default trait error here?
+ traits::VtableDefaultImpl(_) |
traits::VtableBuiltin(_) => {
Vec::new().into_iter()
}
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) {
+ 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::DefTrait(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))
}
result
}
+fn report_ambiguous_associated_type(tcx: &ty::ctxt,
+ span: Span,
+ type_str: &str,
+ trait_str: &str,
+ name: &str) {
+ span_err!(tcx.sess, span, E0223,
+ "ambiguous associated type; specify the type using the syntax \
+ `<{} as {}>::{}`",
+ type_str, trait_str, name);
+}
+
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 {
+ report_ambiguous_associated_type(
+ tcx, span, &ty.user_string(tcx), "Trait", &token::get_name(assoc_name));
+ return (tcx.types.err, ty_path_def);
+ };
+
+ let ty_param_name = tcx.ty_param_defs.borrow()[ty_param_node_id].name;
+
+ // FIXME(#20300) -- search where clauses, not bounds
+ let bounds =
+ this.get_type_parameter_bounds(span, ty_param_node_id)
+ .unwrap_or(Vec::new());
+
+ let mut suitable_bounds: Vec<_> =
+ traits::transitive_bounds(tcx, &bounds)
+ .filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name))
+ .collect();
if suitable_bounds.len() == 0 {
- span_err!(tcx.sess, ast_ty.span, E0220,
+ span_err!(tcx.sess, span, E0220,
"associated type `{}` not found for type parameter `{}`",
token::get_name(assoc_name),
token::get_name(ty_param_name));
- return this.tcx().types.err;
+ return (this.tcx().types.err, ty_path_def);
}
if suitable_bounds.len() > 1 {
- span_err!(tcx.sess, ast_ty.span, E0221,
+ span_err!(tcx.sess, span, E0221,
"ambiguous associated type `{}` in bounds of `{}`",
token::get_name(assoc_name),
token::get_name(ty_param_name));
for suitable_bound in &suitable_bounds {
- span_note!(this.tcx().sess, ast_ty.span,
+ span_note!(this.tcx().sess, span,
"associated type `{}` could derive from `{}`",
token::get_name(ty_param_name),
suitable_bound.user_string(this.tcx()));
}
let suitable_bound = suitable_bounds.pop().unwrap().clone();
- return this.projected_ty_from_poly_trait_ref(ast_ty.span, suitable_bound, assoc_name);
+ let trait_did = suitable_bound.0.def_id;
+
+ let ty = this.projected_ty_from_poly_trait_ref(span, suitable_bound, assoc_name);
+
+ let item_did = if trait_did.krate == ast::LOCAL_CRATE {
+ // `ty::trait_items` used below requires information generated
+ // by type collection, which may be in progress at this point.
+ match this.tcx().map.expect_item(trait_did.node).node {
+ ast::ItemTrait(_, _, _, ref trait_items) => {
+ trait_items.iter().filter_map(|i| {
+ if let ast::TypeTraitItem(ref assoc) = *i {
+ if assoc.ty_param.ident.name == assoc_name {
+ return Some(ast_util::local_def(assoc.ty_param.id));
+ }
+ }
+ None
+ }).next().expect("missing associated type")
+ }
+ _ => unreachable!()
+ }
+ } else {
+ let trait_items = ty::trait_items(this.tcx(), trait_did);
+ let item = trait_items.iter().find(|i| i.name() == assoc_name);
+ item.expect("missing associated type").def_id()
+ };
+ (ty, def::DefAssociatedTy(trait_did, item_did))
}
fn trait_defines_associated_type_named(this: &AstConv,
fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
rscope: &RegionScope,
- ast_ty: &ast::Ty, // the TyQPath
- qpath: &ast::QPath)
+ span: Span,
+ param_mode: PathParamMode,
+ opt_self_ty: Option<Ty<'tcx>>,
+ trait_def_id: ast::DefId,
+ trait_segment: &ast::PathSegment,
+ item_segment: &ast::PathSegment)
-> Ty<'tcx>
{
- debug!("qpath_to_ty(ast_ty={})",
- ast_ty.repr(this.tcx()));
+ let tcx = this.tcx();
- let self_type = ast_ty_to_ty(this, rscope, &*qpath.self_type);
+ check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS);
- debug!("qpath_to_ty: self_type={}", self_type.repr(this.tcx()));
+ let self_ty = if let Some(ty) = opt_self_ty {
+ ty
+ } else {
+ let path_str = ty::item_path_str(tcx, trait_def_id);
+ report_ambiguous_associated_type(
+ tcx, span, "Type", &path_str, &token::get_ident(item_segment.identifier));
+ return tcx.types.err;
+ };
- let trait_ref = instantiate_trait_ref(this,
+ debug!("qpath_to_ty: self_type={}", self_ty.repr(tcx));
+
+ let trait_ref = ast_path_to_trait_ref(this,
rscope,
- &*qpath.trait_ref,
- Some(self_type),
+ span,
+ param_mode,
+ trait_def_id,
+ Some(self_ty),
+ trait_segment,
None);
- debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(this.tcx()));
-
- // `<T as Trait>::U<V>` shouldn't parse right now.
- assert!(qpath.item_path.parameters.is_empty());
+ debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx));
- return this.projected_ty(ast_ty.span,
- trait_ref,
- qpath.item_path.identifier.name);
+ this.projected_ty(span, trait_ref, item_segment.identifier.name)
}
/// Convert a type supplied as value for a type argument from AST into our
}
}
+pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>,
+ rscope: &RegionScope,
+ span: Span,
+ param_mode: PathParamMode,
+ def: &mut def::Def,
+ opt_self_ty: Option<Ty<'tcx>>,
+ segments: &[ast::PathSegment],
+ assoc_segments: &[ast::PathSegment])
+ -> Ty<'tcx> {
+ let tcx = this.tcx();
+
+ let base_ty = match *def {
+ def::DefTrait(trait_def_id) => {
+ // N.B. this case overlaps somewhat with
+ // TyObjectSum, see that fn for details
+ let mut projection_bounds = Vec::new();
+
+ let trait_ref = object_path_to_poly_trait_ref(this,
+ rscope,
+ span,
+ param_mode,
+ trait_def_id,
+ segments.last().unwrap(),
+ &mut projection_bounds);
+
+ check_path_args(tcx, segments.init(), NO_TPS | NO_REGIONS);
+ trait_ref_to_object_type(this, rscope, span, trait_ref,
+ projection_bounds, &[])
+ }
+ def::DefTy(did, _) | def::DefStruct(did) => {
+ check_path_args(tcx, segments.init(), NO_TPS | NO_REGIONS);
+ ast_path_to_ty(this, rscope, span,
+ param_mode, did,
+ segments.last().unwrap())
+ }
+ def::DefTyParam(space, index, _, name) => {
+ check_path_args(tcx, segments, NO_TPS | NO_REGIONS);
+ ty::mk_param(tcx, space, index, name)
+ }
+ def::DefSelfTy(_) => {
+ // n.b.: resolve guarantees that the this type only appears in a
+ // trait, which we rely upon in various places when creating
+ // substs
+ check_path_args(tcx, segments, NO_TPS | NO_REGIONS);
+ ty::mk_self_type(tcx)
+ }
+ def::DefAssociatedTy(trait_did, _) => {
+ check_path_args(tcx, &segments[..segments.len()-2], NO_TPS | NO_REGIONS);
+ qpath_to_ty(this, rscope, span, param_mode,
+ opt_self_ty, trait_did,
+ &segments[segments.len()-2],
+ segments.last().unwrap())
+ }
+ def::DefMod(id) => {
+ // Used as sentinel by callers to indicate the `<T>::A::B::C` form.
+ // FIXME(#22519) This part of the resolution logic should be
+ // avoided entirely for that form, once we stop needed a Def
+ // for `associated_path_def_to_ty`.
+ if segments.is_empty() {
+ opt_self_ty.expect("missing T in <T>::a::b::c")
+ } else {
+ tcx.sess.span_bug(span,
+ &format!("found module name used as a type: {}",
+ tcx.map.node_to_string(id.node)));
+ }
+ }
+ def::DefPrimTy(prim_ty) => {
+ prim_ty_to_ty(tcx, segments, prim_ty)
+ }
+ _ => {
+ span_fatal!(tcx.sess, span, E0248,
+ "found value name used as a type: {:?}", *def);
+ }
+ };
+
+ // If any associated type segments remain, attempt to resolve them.
+ let mut ty = base_ty;
+ for segment in assoc_segments {
+ if ty.sty == ty::ty_err {
+ break;
+ }
+ // This is pretty bad (it will fail except for T::A and Self::A).
+ let (a_ty, a_def) = associated_path_def_to_ty(this, span,
+ ty, *def, segment);
+ ty = a_ty;
+ *def = a_def;
+ }
+ ty
+}
+
/// Parses the programmer's textual representation of a type into our
/// internal notion of a type.
pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
ast_ty_to_ty_cache.insert(ast_ty.id, ty::atttce_unresolved);
drop(ast_ty_to_ty_cache);
- let typ = ast_ty_to_builtin_ty(this, rscope, ast_ty).unwrap_or_else(|| {
- match ast_ty.node {
- ast::TyVec(ref ty) => {
- ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), None)
- }
- ast::TyObjectSum(ref ty, ref bounds) => {
- match ast_ty_to_trait_ref(this, rscope, &**ty, &bounds[..]) {
- Ok((trait_ref, projection_bounds)) => {
- trait_ref_to_object_type(this,
- rscope,
- ast_ty.span,
- trait_ref,
- projection_bounds,
- &bounds[..])
- }
- Err(ErrorReported) => {
- this.tcx().types.err
- }
+ let typ = match ast_ty.node {
+ ast::TyVec(ref ty) => {
+ ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), None)
+ }
+ ast::TyObjectSum(ref ty, ref bounds) => {
+ match ast_ty_to_trait_ref(this, rscope, &**ty, bounds) {
+ Ok((trait_ref, projection_bounds)) => {
+ trait_ref_to_object_type(this,
+ rscope,
+ ast_ty.span,
+ trait_ref,
+ projection_bounds,
+ bounds)
}
- }
- ast::TyPtr(ref mt) => {
- ty::mk_ptr(tcx, ty::mt {
- ty: ast_ty_to_ty(this, rscope, &*mt.ty),
- mutbl: mt.mutbl
- })
- }
- ast::TyRptr(ref region, ref mt) => {
- let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region);
- debug!("ty_rptr r={}", r.repr(this.tcx()));
- let rscope1 =
- &ObjectLifetimeDefaultRscope::new(
- rscope,
- Some(ty::ObjectLifetimeDefault::Specific(r)));
- let t = ast_ty_to_ty(this, rscope1, &*mt.ty);
- ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl})
- }
- ast::TyTup(ref fields) => {
- let flds = fields.iter()
- .map(|t| ast_ty_to_ty(this, rscope, &**t))
- .collect();
- ty::mk_tup(tcx, flds)
- }
- ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ),
- ast::TyBareFn(ref bf) => {
- if bf.decl.variadic && bf.abi != abi::C {
- span_err!(tcx.sess, ast_ty.span, E0222,
- "variadic function must have C calling convention");
+ Err(ErrorReported) => {
+ this.tcx().types.err
}
- let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl);
- ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(bare_fn))
}
- ast::TyPolyTraitRef(ref bounds) => {
- conv_ty_poly_trait_ref(this, rscope, ast_ty.span, &bounds[..])
+ }
+ ast::TyPtr(ref mt) => {
+ ty::mk_ptr(tcx, ty::mt {
+ ty: ast_ty_to_ty(this, rscope, &*mt.ty),
+ mutbl: mt.mutbl
+ })
+ }
+ ast::TyRptr(ref region, ref mt) => {
+ let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region);
+ debug!("ty_rptr r={}", r.repr(this.tcx()));
+ let rscope1 =
+ &ObjectLifetimeDefaultRscope::new(
+ rscope,
+ Some(ty::ObjectLifetimeDefault::Specific(r)));
+ let t = ast_ty_to_ty(this, rscope1, &*mt.ty);
+ ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl})
+ }
+ ast::TyTup(ref fields) => {
+ let flds = fields.iter()
+ .map(|t| ast_ty_to_ty(this, rscope, &**t))
+ .collect();
+ ty::mk_tup(tcx, flds)
+ }
+ ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ),
+ ast::TyBareFn(ref bf) => {
+ if bf.decl.variadic && bf.abi != abi::C {
+ span_err!(tcx.sess, ast_ty.span, E0222,
+ "variadic function must have C calling convention");
}
- ast::TyPath(ref path, id) => {
- let a_def = match tcx.def_map.borrow().get(&id) {
- None => {
- tcx.sess
- .span_bug(ast_ty.span,
- &format!("unbound path {}",
- path.repr(tcx)))
- }
- Some(&d) => d
- };
- match a_def {
- def::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,
- 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) {
+ 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
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::DefTrait(_) => {
let name = pprust::path_to_string(path);
};
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);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Method lookup: the secret sauce of Rust. See `doc.rs`.
+//! Method lookup: the secret sauce of Rust. See `README.md`.
use astconv::AstConv;
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)]
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::DefTrait(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::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::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) => {}
Some(_) | None => {
- span_err!(ccx.tcx.sess, item.span, E0192,
- "negative impls are currently \
- allowed just for `Send` and `Sync`")
+ if !ty::trait_has_default_impl(ccx.tcx, trait_ref.def_id) {
+ span_err!(ccx.tcx.sess, item.span, E0192,
+ "negative impls are only allowed for traits with \
+ default impls (e.g., `Send` and `Sync`)")
+ }
}
}
}
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(..) => {
+ // "Trait" impl
+ debug!("coherence2::orphan check: default trait impl {}", item.repr(self.tcx));
+ 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 \
+ crate they're defined in; define a new trait instead.");
+ }
+ }
_ => {
// Not an impl
}
use syntax::ast::{DefId};
use syntax::ast::{LOCAL_CRATE};
use syntax::ast;
-use syntax::codemap::{Span};
+use syntax::ast_util;
+use syntax::visit;
+use syntax::codemap::Span;
use util::ppaux::Repr;
pub fn check(tcx: &ty::ctxt) {
- let overlap = OverlapChecker { tcx: tcx };
+ let mut overlap = OverlapChecker { tcx: tcx };
overlap.check_for_overlapping_impls();
+
+ // this secondary walk specifically checks for impls of defaulted
+ // traits, for which additional overlap rules exist
+ visit::walk_crate(&mut overlap, tcx.map.krate());
}
struct OverlapChecker<'cx, 'tcx:'cx> {
- tcx: &'cx ty::ctxt<'tcx>
+ tcx: &'cx ty::ctxt<'tcx>,
}
impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
return;
}
- span_err!(self.tcx.sess, self.span_of_impl(impl1_def_id), E0119,
+ self.report_overlap_error(trait_def_id, impl1_def_id, impl2_def_id);
+ }
+
+ fn report_overlap_error(&self, trait_def_id: ast::DefId,
+ impl1: ast::DefId, impl2: ast::DefId) {
+
+ span_err!(self.tcx.sess, self.span_of_impl(impl1), E0119,
"conflicting implementations for trait `{}`",
ty::item_path_str(self.tcx, trait_def_id));
- if impl2_def_id.krate == ast::LOCAL_CRATE {
- span_note!(self.tcx.sess, self.span_of_impl(impl2_def_id),
+ self.report_overlap_note(impl1, impl2);
+ }
+
+ fn report_overlap_note(&self, impl1: ast::DefId, impl2: ast::DefId) {
+
+ if impl2.krate == ast::LOCAL_CRATE {
+ span_note!(self.tcx.sess, self.span_of_impl(impl2),
"note conflicting implementation here");
} else {
let crate_store = &self.tcx.sess.cstore;
- let cdata = crate_store.get_crate_data(impl2_def_id.krate);
- span_note!(self.tcx.sess, self.span_of_impl(impl1_def_id),
+ let cdata = crate_store.get_crate_data(impl2.krate);
+ span_note!(self.tcx.sess, self.span_of_impl(impl1),
"conflicting implementation in crate `{}`",
cdata.name);
}
self.tcx.map.span(impl_did.node)
}
}
+
+
+impl<'cx, 'tcx,'v> visit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
+ fn visit_item(&mut self, item: &'v ast::Item) {
+ match item.node {
+ ast::ItemDefaultImpl(_, _) => {
+ let impl_def_id = ast_util::local_def(item.id);
+ match ty::impl_trait_ref(self.tcx, impl_def_id) {
+ Some(ref trait_ref) => {
+ match ty::trait_default_impl(self.tcx, trait_ref.def_id) {
+ Some(other_impl) if other_impl != impl_def_id => {
+ self.report_overlap_error(trait_ref.def_id,
+ other_impl,
+ impl_def_id);
+ }
+ Some(_) => {}
+ None => {
+ self.tcx.sess.bug(
+ &format!("no default implementation recorded for `{:?}`",
+ 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)));
}
}
}
+}
+
+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_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef<'tcx>> {
- get_trait_def(self, 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 {
predicates,
&enum_definition.variants);
},
+ ast::ItemDefaultImpl(_, ref ast_trait_ref) => {
+ 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))
+ }
ast::ItemImpl(_, _,
ref generics,
ref opt_trait_ref,
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) => {
let t = ty::mk_struct(tcx, local_def(it.id), tcx.mk_substs(substs));
ty::TypeScheme { ty: t, generics: ty_generics }
}
+ ast::ItemDefaultImpl(..) |
ast::ItemTrait(..) |
ast::ItemImpl(..) |
ast::ItemMod(..) |
}
}
-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::ItemExternCrate(..) |
ast::ItemUse(..) |
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,
E0247, // found module name used as a type
E0248, // found value name used as a type
E0249, // expected constant expr for array length
- E0250 // expected constant expr for array length
+ E0250, // expected constant expr for array length
+ E0318, // can't create default impls for traits outside their crates
+ E0319 // trait impls for defaulted traits allowed just for structs/enums
}
__build_diagnostic_array! { DIAGNOSTICS }
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::*;
ast::ItemExternCrate(_) |
ast::ItemUse(_) |
+ ast::ItemDefaultImpl(..) |
ast::ItemImpl(..) |
ast::ItemStatic(..) |
ast::ItemConst(..) |
&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);
+ }
}
}
}
ast::ItemForeignMod(..) |
ast::ItemTy(..) |
ast::ItemImpl(..) |
+ ast::ItemDefaultImpl(..) |
ast::ItemMac(..) => {
}
}
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();
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);
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()))
})
}
pub vis: ast::Visibility,
pub stab: Option<attr::Stability>,
pub impls: Vec<Impl>,
+ pub def_traits: Vec<DefaultImpl>,
pub foreigns: Vec<ast::ForeignMod>,
pub macros: Vec<Macro>,
pub is_crate: bool,
constants : Vec::new(),
traits : Vec::new(),
impls : Vec::new(),
+ def_traits : Vec::new(),
foreigns : Vec::new(),
macros : Vec::new(),
is_crate : false,
pub id: ast::NodeId,
}
+pub struct DefaultImpl {
+ pub unsafety: ast::Unsafety,
+ pub trait_: ast::TraitRef,
+ pub id: ast::NodeId,
+}
+
pub struct Macro {
pub name: Ident,
pub id: ast::NodeId,
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)
}
fn shorter<'a>(s: Option<&'a str>) -> &'a str {
match s {
- Some(s) => match s.find_str("\n\n") {
+ Some(s) => match s.find("\n\n") {
Some(pos) => &s[..pos],
None => s,
},
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
};
om.impls.push(i);
},
+ ast::ItemDefaultImpl(unsafety, ref trait_ref) => {
+ let i = DefaultImpl {
+ unsafety: unsafety,
+ trait_: trait_ref.clone(),
+ id: item.id
+ };
+ om.def_traits.push(i);
+ }
ast::ItemForeignMod(ref fm) => {
om.foreigns.push(fm.clone());
}
#[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]
#[test]
fn test_encode_hashmap_with_arbitrary_key() {
- use std::old_io::Writer;
use std::collections::HashMap;
- use std::fmt;
#[derive(PartialEq, Eq, Hash, RustcEncodable)]
struct ArbitraryType(uint);
let mut hm: HashMap<ArbitraryType, bool> = HashMap::new();
/// 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;
// produces identical results to a linear naive reinsertion from the same
// element.
//
-// FIXME(Gankro, pczarn): review the proof and put it all in a separate doc.rs
+// FIXME(Gankro, pczarn): review the proof and put it all in a separate README.md
/// A hash map implementation which uses linear probing with Robin
/// Hood bucket stealing.
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
}
}
//!
//! Rust's collections can be grouped into four major categories:
//!
-//! * Sequences: `Vec`, `VecDeque`, `LinkedList`, `BitV`
+//! * Sequences: `Vec`, `VecDeque`, `LinkedList`, `BitVec`
//! * Maps: `HashMap`, `BTreeMap`, `VecMap`
-//! * Sets: `HashSet`, `BTreeSet`, `BitVSet`
+//! * Sets: `HashSet`, `BTreeSet`, `BitSet`
//! * Misc: `BinaryHeap`
//!
//! # When Should You Use Which Collection?
//! * There is no meaningful value to associate with your keys.
//! * You just want a set.
//!
-//! ### Use a `BitV` when:
+//! ### Use a `BitVec` when:
//! * You want to store an unbounded number of booleans in a small space.
//! * You want a bit vector.
//!
-//! ### Use a `BitVSet` when:
+//! ### Use a `BitSet` when:
//! * You want a `VecSet`.
//!
//! ### Use a `BinaryHeap` when:
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 [""]));
/// Returns the contents of this `CString` as a slice of bytes.
///
/// The returned slice does **not** contain the trailing nul separator and
- /// it is guaranteet to not have any interior nul bytes.
+ /// it is guaranteed to not have any interior nul bytes.
pub fn as_bytes(&self) -> &[u8] {
&self.inner[..self.inner.len() - 1]
}
/// Return the inner pointer to this C string.
///
/// The returned pointer will be valid for as long as `self` is and points
- /// to a continguous region of memory terminated with a 0 byte to represent
+ /// to a contiguous region of memory terminated with a 0 byte to represent
/// the end of the string.
pub fn as_ptr(&self) -> *const libc::c_char {
self.inner.as_ptr()
impl PartialEq for CStr {
fn eq(&self, other: &CStr) -> bool {
- self.to_bytes().eq(&other.to_bytes())
+ self.to_bytes().eq(other.to_bytes())
}
}
impl Eq for CStr {}
+++ /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);
assert_eq!(writer.write(&[1, 2, 3]), Ok(3));
assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4));
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
- assert_eq!(&writer.get_ref()[], b);
+ assert_eq!(&writer.get_ref()[..], b);
}
#[test]
assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4));
assert_eq!(writer.position(), 8);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
- assert_eq!(&writer.get_ref()[], b);
+ assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::Start(0)), Ok(0));
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[3, 4]), Ok(2));
let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7];
- assert_eq!(&writer.get_ref()[], b);
+ assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::Current(1)), Ok(3));
assert_eq!(writer.write(&[0, 1]), Ok(2));
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7];
- assert_eq!(&writer.get_ref()[], b);
+ assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::End(-1)), Ok(7));
assert_eq!(writer.write(&[1, 2]), Ok(2));
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2];
- assert_eq!(&writer.get_ref()[], b);
+ assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::End(1)), Ok(10));
assert_eq!(writer.write(&[1]), Ok(1));
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1];
- assert_eq!(&writer.get_ref()[], b);
+ assert_eq!(&writer.get_ref()[..], b);
}
#[test]
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(()) }
}
impl<T: Read> Read for Take<T> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
+ // Don't call into inner reader at all at EOF because it may still block
+ if self.limit == 0 {
+ return Ok(0);
+ }
+
let max = cmp::min(buf.len() as u64, self.limit) as usize;
let n = try!(self.inner.read(&mut buf[..max]));
self.limit -= n as u64;
}
}
+impl<T: BufRead> BufRead for Take<T> {
+ fn fill_buf(&mut self) -> Result<&[u8]> {
+ let buf = try!(self.inner.fill_buf());
+ let cap = cmp::min(buf.len() as u64, self.limit) as usize;
+ Ok(&buf[..cap])
+ }
+
+ fn consume(&mut self, amt: usize) {
+ // Don't let callers reset the limit by passing an overlarge value
+ let amt = cmp::min(amt as u64, self.limit) as usize;
+ self.limit -= amt as u64;
+ self.inner.consume(amt);
+ }
+}
+
/// An adaptor which will emit all read data to a specified writer as well.
///
/// For more information see `ReadExt::tee`
mod tests {
use prelude::v1::*;
use io::prelude::*;
+ use io;
use super::Cursor;
#[test]
let mut v = String::new();
assert!(c.read_to_string(&mut v).is_err());
}
+
+ #[test]
+ fn take_eof() {
+ struct R;
+
+ impl Read for R {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ Err(io::Error::new(io::ErrorKind::Other, "", None))
+ }
+ }
+
+ let mut buf = [0; 1];
+ assert_eq!(Ok(0), R.take(0).read(&mut buf));
+ }
}
#![feature(unsafe_destructor)]
#![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.
($msg:expr) => ({
$crate::rt::begin_unwind($msg, {
// static requires less code at runtime, more constant data
- static _FILE_LINE: (&'static str, usize) = (file!(), line!());
+ static _FILE_LINE: (&'static str, usize) = (file!(), line!() as usize);
&_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.
- static _FILE_LINE: (&'static str, usize) = (file!(), line!());
+ static _FILE_LINE: (&'static str, usize) = (file!(), line!() as usize);
&_FILE_LINE
})
});
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
}
assert_pow!((8, 3 ) => 512);
assert_pow!((2u64, 50) => 1125899906842624);
}
+
+ #[test]
+ fn test_uint_to_str_overflow() {
+ let mut u8_val: u8 = 255_u8;
+ assert_eq!(u8_val.to_string(), "255");
+
+ u8_val += 1 as u8;
+ assert_eq!(u8_val.to_string(), "0");
+
+ let mut u16_val: u16 = 65_535_u16;
+ assert_eq!(u16_val.to_string(), "65535");
+
+ u16_val += 1 as u16;
+ assert_eq!(u16_val.to_string(), "0");
+
+ let mut u32_val: u32 = 4_294_967_295_u32;
+ assert_eq!(u32_val.to_string(), "4294967295");
+
+ u32_val += 1 as u32;
+ assert_eq!(u32_val.to_string(), "0");
+
+ let mut u64_val: u64 = 18_446_744_073_709_551_615_u64;
+ assert_eq!(u64_val.to_string(), "18446744073709551615");
+
+ u64_val += 1 as u64;
+ assert_eq!(u64_val.to_string(), "0");
+ }
+
+ fn from_str<T: ::str::FromStr>(t: &str) -> Option<T> {
+ ::str::FromStr::from_str(t).ok()
+ }
+
+ #[test]
+ fn test_uint_from_str_overflow() {
+ let mut u8_val: u8 = 255_u8;
+ assert_eq!(from_str::<u8>("255"), Some(u8_val));
+ assert_eq!(from_str::<u8>("256"), None);
+
+ u8_val += 1 as u8;
+ assert_eq!(from_str::<u8>("0"), Some(u8_val));
+ assert_eq!(from_str::<u8>("-1"), None);
+
+ let mut u16_val: u16 = 65_535_u16;
+ assert_eq!(from_str::<u16>("65535"), Some(u16_val));
+ assert_eq!(from_str::<u16>("65536"), None);
+
+ u16_val += 1 as u16;
+ assert_eq!(from_str::<u16>("0"), Some(u16_val));
+ assert_eq!(from_str::<u16>("-1"), None);
+
+ let mut u32_val: u32 = 4_294_967_295_u32;
+ assert_eq!(from_str::<u32>("4294967295"), Some(u32_val));
+ assert_eq!(from_str::<u32>("4294967296"), None);
+
+ u32_val += 1 as u32;
+ assert_eq!(from_str::<u32>("0"), Some(u32_val));
+ assert_eq!(from_str::<u32>("-1"), None);
+
+ let mut u64_val: u64 = 18_446_744_073_709_551_615_u64;
+ assert_eq!(from_str::<u64>("18446744073709551615"), Some(u64_val));
+ assert_eq!(from_str::<u64>("18446744073709551616"), None);
+
+ u64_val += 1 as u64;
+ assert_eq!(from_str::<u64>("0"), Some(u64_val));
+ assert_eq!(from_str::<u64>("-1"), None);
+ }
}
assert_eq!(FromStrRadix::from_str_radix("Z", 10).ok(), None::<$T>);
assert_eq!(FromStrRadix::from_str_radix("_", 2).ok(), None::<$T>);
}
-
- #[test]
- fn test_uint_to_str_overflow() {
- let mut u8_val: u8 = 255_u8;
- assert_eq!(u8_val.to_string(), "255");
-
- u8_val += 1 as u8;
- assert_eq!(u8_val.to_string(), "0");
-
- let mut u16_val: u16 = 65_535_u16;
- assert_eq!(u16_val.to_string(), "65535");
-
- u16_val += 1 as u16;
- assert_eq!(u16_val.to_string(), "0");
-
- let mut u32_val: u32 = 4_294_967_295_u32;
- assert_eq!(u32_val.to_string(), "4294967295");
-
- u32_val += 1 as u32;
- assert_eq!(u32_val.to_string(), "0");
-
- let mut u64_val: u64 = 18_446_744_073_709_551_615_u64;
- assert_eq!(u64_val.to_string(), "18446744073709551615");
-
- u64_val += 1 as u64;
- assert_eq!(u64_val.to_string(), "0");
- }
-
- #[test]
- fn test_uint_from_str_overflow() {
- let mut u8_val: u8 = 255_u8;
- assert_eq!(from_str::<u8>("255"), Some(u8_val));
- assert_eq!(from_str::<u8>("256"), None);
-
- u8_val += 1 as u8;
- assert_eq!(from_str::<u8>("0"), Some(u8_val));
- assert_eq!(from_str::<u8>("-1"), None);
-
- let mut u16_val: u16 = 65_535_u16;
- assert_eq!(from_str::<u16>("65535"), Some(u16_val));
- assert_eq!(from_str::<u16>("65536"), None);
-
- u16_val += 1 as u16;
- assert_eq!(from_str::<u16>("0"), Some(u16_val));
- assert_eq!(from_str::<u16>("-1"), None);
-
- let mut u32_val: u32 = 4_294_967_295_u32;
- assert_eq!(from_str::<u32>("4294967295"), Some(u32_val));
- assert_eq!(from_str::<u32>("4294967296"), None);
-
- u32_val += 1 as u32;
- assert_eq!(from_str::<u32>("0"), Some(u32_val));
- assert_eq!(from_str::<u32>("-1"), None);
-
- let mut u64_val: u64 = 18_446_744_073_709_551_615_u64;
- assert_eq!(from_str::<u64>("18446744073709551615"), Some(u64_val));
- assert_eq!(from_str::<u64>("18446744073709551616"), None);
-
- u64_val += 1 as u64;
- assert_eq!(from_str::<u64>("0"), Some(u64_val));
- assert_eq!(from_str::<u64>("-1"), None);
- }
}
) }
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]
use self::StdSource::*;
+use boxed;
use boxed::Box;
use cell::RefCell;
use clone::Clone;
/// See `stdout()` for more notes about this function.
pub fn stdin() -> StdinReader {
// We're following the same strategy as kimundi's lazy_static library
- static mut STDIN: *const StdinReader = 0 as *const StdinReader;
+ static mut STDIN: *mut StdinReader = 0 as *mut StdinReader;
static ONCE: Once = ONCE_INIT;
unsafe {
let stdin = StdinReader {
inner: Arc::new(Mutex::new(RaceBox(stdin)))
};
- STDIN = mem::transmute(box stdin);
+ STDIN = boxed::into_raw(box stdin);
// Make sure to free it at exit
rt::at_exit(|| {
- mem::transmute::<_, Box<StdinReader>>(STDIN);
- STDIN = ptr::null();
+ Box::from_raw(STDIN);
+ STDIN = ptr::null_mut();
});
});
/// 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]
fn path_relative_from(&self, base: &Path) -> Option<Path> {
fn comp_requires_verbatim(s: &str) -> bool {
- s == "." || s == ".." || s.contains_char(SEP2)
+ s == "." || s == ".." || s.contains(SEP2)
}
if !self.equiv_prefix(base) {
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" {
use core::prelude::*;
+use boxed;
use boxed::Box;
use vec::Vec;
-use mem;
use thunk::Thunk;
use sys_common::mutex::{Mutex, MUTEX_INIT};
unsafe fn init() {
if QUEUE.is_null() {
let state: Box<Queue> = box Vec::new();
- QUEUE = mem::transmute(state);
+ QUEUE = boxed::into_raw(state);
} else {
// can't re-init after a cleanup
rtassert!(QUEUE as uint != 1);
// If we never called init, not need to cleanup!
if queue as uint != 0 {
- let queue: Box<Queue> = mem::transmute(queue);
+ let queue: Box<Queue> = Box::from_raw(queue);
for to_run in *queue {
to_run.invoke(());
}
use prelude::v1::*;
use any::Any;
+use boxed;
use cell::Cell;
use cmp;
use panicking;
},
cause: Some(cause),
};
- let error = uw::_Unwind_RaiseException(mem::transmute(exception));
+ let exception_param = boxed::into_raw(exception) as *mut uw::_Unwind_Exception;
+ let error = uw::_Unwind_RaiseException(exception_param);
rtabort!("Could not unwind stack, error = {}", error as int)
}
exception: *mut uw::_Unwind_Exception) {
rtdebug!("exception_cleanup()");
unsafe {
- let _: Box<Exception> = mem::transmute(exception);
+ let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
}
}
}
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 {
// The receiver port can be sent from place to place, so long as it
// is not used to receive non-sendable things.
-unsafe impl<T: Send + 'static> Send for Receiver<T> { }
+unsafe impl<T: Send> Send for Receiver<T> { }
/// An iterator over messages on a receiver, this iterator will block
/// whenever `next` is called, waiting for a new message, and `None` will be
// The send port can be sent from place to place, so long as it
// is not used to send non-sendable things.
-unsafe impl<T: Send + 'static> Send for Sender<T> { }
+unsafe impl<T: Send> Send for Sender<T> { }
/// The sending-half of Rust's synchronous channel type. This half can only be
/// owned by one task, but it can be cloned to send to other tasks.
inner: Arc<UnsafeCell<sync::Packet<T>>>,
}
-unsafe impl<T: Send + 'static> Send for SyncSender<T> {}
+unsafe impl<T: Send> Send for SyncSender<T> {}
impl<T> !Sync for SyncSender<T> {}
/// 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`.
///
/// println!("{:?}", rx.recv().unwrap());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn channel<T: Send + 'static>() -> (Sender<T>, Receiver<T>) {
+pub fn channel<T: Send>() -> (Sender<T>, Receiver<T>) {
let a = Arc::new(UnsafeCell::new(oneshot::Packet::new()));
(Sender::new(Flavor::Oneshot(a.clone())), Receiver::new(Flavor::Oneshot(a)))
}
/// assert_eq!(rx.recv().unwrap(), 2);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn sync_channel<T: Send + 'static>(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)))
}
// Sender
////////////////////////////////////////////////////////////////////////////////
-impl<T: Send + 'static> Sender<T> {
+impl<T: Send> Sender<T> {
fn new(inner: Flavor<T>) -> Sender<T> {
Sender {
inner: UnsafeCell::new(inner),
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send + 'static> Clone for Sender<T> {
+impl<T: Send> Clone for Sender<T> {
fn clone(&self) -> Sender<T> {
let (packet, sleeper, guard) = match *unsafe { self.inner() } {
Flavor::Oneshot(ref p) => {
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send + 'static> Drop for Sender<T> {
+impl<T: Send> Drop for Sender<T> {
fn drop(&mut self) {
match *unsafe { self.inner_mut() } {
Flavor::Oneshot(ref mut p) => unsafe { (*p.get()).drop_chan(); },
// SyncSender
////////////////////////////////////////////////////////////////////////////////
-impl<T: Send + 'static> SyncSender<T> {
+impl<T: Send> SyncSender<T> {
fn new(inner: Arc<UnsafeCell<sync::Packet<T>>>) -> SyncSender<T> {
SyncSender { inner: inner }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send + 'static> Clone for SyncSender<T> {
+impl<T: Send> Clone for SyncSender<T> {
fn clone(&self) -> SyncSender<T> {
unsafe { (*self.inner.get()).clone_chan(); }
return SyncSender::new(self.inner.clone());
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send + 'static> Drop for SyncSender<T> {
+impl<T: Send> Drop for SyncSender<T> {
fn drop(&mut self) {
unsafe { (*self.inner.get()).drop_chan(); }
}
// Receiver
////////////////////////////////////////////////////////////////////////////////
-impl<T: Send + 'static> Receiver<T> {
+impl<T: Send> Receiver<T> {
fn new(inner: Flavor<T>) -> Receiver<T> {
Receiver { inner: UnsafeCell::new(inner) }
}
}
}
-impl<T: Send + 'static> select::Packet for Receiver<T> {
+impl<T: Send> select::Packet for Receiver<T> {
fn can_recv(&self) -> bool {
loop {
let new_port = match *unsafe { self.inner() } {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T: Send + 'static> Iterator for Iter<'a, T> {
+impl<'a, T: Send> Iterator for Iter<'a, T> {
type Item = T;
fn next(&mut self) -> Option<T> { self.rx.recv().ok() }
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send + 'static> Drop for Receiver<T> {
+impl<T: Send> Drop for Receiver<T> {
fn drop(&mut self) {
match *unsafe { self.inner_mut() } {
Flavor::Oneshot(ref mut p) => unsafe { (*p.get()).drop_port(); },
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)));
use core::prelude::*;
+use alloc::boxed;
use alloc::boxed::Box;
-use core::mem;
use core::ptr;
use core::cell::UnsafeCell;
}
unsafe impl<T:Send> Send for Queue<T> { }
-unsafe impl<T: Send + 'static> Sync for Queue<T> { }
+unsafe impl<T: Send> Sync for Queue<T> { }
impl<T> Node<T> {
unsafe fn new(v: Option<T>) -> *mut Node<T> {
- mem::transmute(box Node {
+ boxed::into_raw(box Node {
next: AtomicPtr::new(ptr::null_mut()),
value: v,
})
}
}
-impl<T: Send + 'static> Queue<T> {
+impl<T: Send> Queue<T> {
/// Creates a new queue that is safe to share among multiple producers and
/// one consumer.
pub fn new() -> Queue<T> {
assert!((*tail).value.is_none());
assert!((*next).value.is_some());
let ret = (*next).value.take().unwrap();
- let _: Box<Node<T>> = mem::transmute(tail);
+ let _: Box<Node<T>> = Box::from_raw(tail);
return Data(ret);
}
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send + 'static> Drop for Queue<T> {
+impl<T: Send> Drop for Queue<T> {
fn drop(&mut self) {
unsafe {
let mut cur = *self.tail.get();
while !cur.is_null() {
let next = (*cur).next.load(Ordering::Relaxed);
- let _: Box<Node<T>> = mem::transmute(cur);
+ let _: Box<Node<T>> = Box::from_raw(cur);
cur = next;
}
}
///
/// # 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
GoUp(Receiver<T>),
}
-impl<T: Send + 'static> Packet<T> {
+impl<T: Send> Packet<T> {
pub fn new() -> Packet<T> {
Packet {
data: None,
// 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)
}
}
}
#[unsafe_destructor]
-impl<T: Send + 'static> Drop for Packet<T> {
+impl<T: Send> Drop for Packet<T> {
fn drop(&mut self) {
assert_eq!(self.state.load(Ordering::SeqCst), DISCONNECTED);
}
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, ()>,
/// Creates a new handle into this receiver set for a new receiver. Note
/// that this does *not* add the receiver to the receiver set, for that you
/// must call the `add` method on the handle itself.
- pub fn handle<'a, T: Send + 'static>(&'a self, rx: &'a Receiver<T>) -> Handle<'a, T> {
+ pub fn handle<'a, T: Send>(&'a self, rx: &'a Receiver<T>) -> Handle<'a, T> {
let id = self.next_id.get();
self.next_id.set(id + 1);
Handle {
/// 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
fn iter(&self) -> Packets { Packets { cur: self.head } }
}
-impl<'rx, T: Send + 'static> Handle<'rx, T> {
+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
}
#[unsafe_destructor]
-impl<'rx, T: Send + 'static> Drop for Handle<'rx, T> {
+impl<'rx, T: Send> Drop for Handle<'rx, T> {
fn drop(&mut self) {
unsafe { self.remove() }
}
#[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! {
Disconnected,
}
-impl<T: Send + 'static> Packet<T> {
+impl<T: Send> Packet<T> {
// Creation of a packet *must* be followed by a call to postinit_lock
// and later by inherit_blocker
pub fn new() -> Packet<T> {
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) }
}
////////////////////////////////////////////////////////////////////////////
}
#[unsafe_destructor]
-impl<T: Send + 'static> Drop for Packet<T> {
+impl<T: Send> Drop for Packet<T> {
fn drop(&mut self) {
// Note that this load is not only an assert for correctness about
// disconnection, but also a proper fence before the read of
use core::prelude::*;
+use alloc::boxed;
use alloc::boxed::Box;
-use core::mem;
use core::ptr;
use core::cell::UnsafeCell;
// 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,
}
-unsafe impl<T: Send + 'static> Send for Queue<T> { }
+unsafe impl<T: Send> Send for Queue<T> { }
-unsafe impl<T: Send + 'static> Sync for Queue<T> { }
+unsafe impl<T: Send> Sync for Queue<T> { }
-impl<T: Send + 'static> Node<T> {
+impl<T: Send> Node<T> {
fn new() -> *mut Node<T> {
unsafe {
- mem::transmute(box Node {
+ boxed::into_raw(box Node {
value: None,
next: AtomicPtr::new(ptr::null_mut::<Node<T>>()),
})
}
}
-impl<T: Send + 'static> Queue<T> {
+impl<T: Send> Queue<T> {
/// Creates a new queue.
///
/// This is unsafe as the type system doesn't enforce a single
/// 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);
.next.store(next, Ordering::Relaxed);
// We have successfully erased all references to 'tail', so
// now we can safely drop it.
- let _: Box<Node<T>> = mem::transmute(tail);
+ let _: Box<Node<T>> = Box::from_raw(tail);
}
}
return ret;
}
#[unsafe_destructor]
-impl<T: Send + 'static> Drop for Queue<T> {
+impl<T: Send> Drop for Queue<T> {
fn drop(&mut self) {
unsafe {
let mut cur = *self.first.get();
while !cur.is_null() {
let next = (*cur).next.load(Ordering::Relaxed);
- let _n: Box<Node<T>> = mem::transmute(cur);
+ let _n: Box<Node<T>> = Box::from_raw(cur);
cur = next;
}
}
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.
GoUp(Receiver<T>),
}
-impl<T: Send + 'static> Packet<T> {
+impl<T: Send> Packet<T> {
pub fn new() -> Packet<T> {
Packet {
queue: unsafe { spsc::Queue::new(128) },
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);
}
#[unsafe_destructor]
-impl<T: Send + 'static> Drop for Packet<T> {
+impl<T: Send> Drop for Packet<T> {
fn drop(&mut self) {
// Note that this load is not only an assert for correctness about
// disconnection, but also a proper fence before the read of
lock: Mutex<State<T>>,
}
-unsafe impl<T: Send + 'static> Send for Packet<T> { }
+unsafe impl<T: Send> Send for Packet<T> { }
-unsafe impl<T: Send + 'static> Sync for Packet<T> { }
+unsafe impl<T: Send> Sync for Packet<T> { }
struct State<T> {
disconnected: bool, // Is the channel disconnected yet?
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
canceled: Option<&'static mut bool>,
}
-unsafe impl<T: Send + 'static> Send for State<T> {}
+unsafe impl<T: Send> Send for State<T> {}
/// Possible flavors of threads who can be blocked on this channel.
enum Blocker {
/// A simple ring-buffer
struct Buffer<T> {
buf: Vec<Option<T>>,
- start: uint,
- size: uint,
+ start: usize,
+ size: usize,
}
#[derive(Debug)]
/// Atomically blocks the current thread, placing it into `slot`, unlocking `lock`
/// in the meantime. This re-locks the mutex upon returning.
-fn wait<'a, 'b, T: Send + 'static>(lock: &'a Mutex<State<T>>,
+fn wait<'a, 'b, T: Send>(lock: &'a Mutex<State<T>>,
mut guard: MutexGuard<'b, State<T>>,
f: fn(SignalToken) -> Blocker)
-> MutexGuard<'a, State<T>>
token.signal();
}
-impl<T: Send + 'static> Packet<T> {
- pub fn new(cap: uint) -> Packet<T> {
+impl<T: Send> Packet<T> {
+ pub fn new(cap: usize) -> Packet<T> {
Packet {
channels: AtomicUsize::new(1),
lock: Mutex::new(State {
}
#[unsafe_destructor]
-impl<T: Send + 'static> Drop for Packet<T> {
+impl<T: Send> Drop for Packet<T> {
fn drop(&mut self) {
assert_eq!(self.channels.load(Ordering::SeqCst), 0);
let mut guard = self.lock.lock().unwrap();
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.
data: UnsafeCell<T>,
}
-unsafe impl<T: Send + 'static> Send for Mutex<T> { }
+unsafe impl<T: Send> Send for Mutex<T> { }
-unsafe impl<T: Send + 'static> Sync for Mutex<T> { }
+unsafe impl<T: Send> Sync for Mutex<T> { }
/// The static mutex type is provided to allow for static allocation of mutexes.
///
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.
///
poison: poison::FLAG_INIT,
};
-impl<T: Send + 'static> Mutex<T> {
+impl<T: Send> Mutex<T> {
/// Creates a new mutex in an unlocked state ready for use.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(t: T) -> Mutex<T> {
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send + 'static> Drop for Mutex<T> {
+impl<T: Send> Drop for Mutex<T> {
fn drop(&mut self) {
// This is actually safe b/c we know that there is no further usage of
// this mutex (it's up to the user to arrange for a mutex to get
}
}
+#[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: () });
struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
- unsafe impl<T:'static+Send> Send for Packet<T> {}
+ unsafe impl<T: Send> Send for Packet<T> {}
unsafe impl<T> Sync for Packet<T> {}
#[test]
#[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
///
data: UnsafeCell<T>,
}
-unsafe impl<T:'static+Send> Send for RwLock<T> {}
-unsafe impl<T> Sync for RwLock<T> {}
+unsafe impl<T: Send + Sync> Send for RwLock<T> {}
+unsafe impl<T: Send + Sync> Sync for RwLock<T> {}
/// Structure representing a statically allocated RwLock.
///
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() {
use prelude::v1::*;
+use boxed;
use cell::UnsafeCell;
-use mem;
use ptr;
use rt;
use sync::{StaticMutex, StaticCondvar};
let _guard = self.lock.lock().unwrap();
if !*self.initialized.get() {
let (tx, rx) = channel();
- *self.chan.get() = mem::transmute(box tx);
+ *self.chan.get() = boxed::into_raw(box tx);
let (receive, send) = helper_signal::new();
*self.signal.get() = send as uint;
let mut guard = self.lock.lock().unwrap();
// Close the channel by destroying it
- let chan: Box<Sender<M>> = mem::transmute(*self.chan.get());
+ let chan: Box<Sender<M>> = Box::from_raw(*self.chan.get());
*self.chan.get() = ptr::null_mut();
drop(chan);
helper_signal::signal(*self.signal.get() as helper_signal::signal);
#[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<()> {
unsafe {
stack::record_os_managed_stack_bounds(0, usize::MAX);
let handler = stack_overflow::Handler::new();
- let f: Box<Thunk> = mem::transmute(main);
+ let f: Box<Thunk> = Box::from_raw(main as *mut Thunk);
f.invoke(());
drop(handler);
mem::transmute(0 as thread::rust_thread_return)
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,
use core::prelude::*;
use io;
+use boxed;
use boxed::Box;
use cmp;
use mem;
},
};
- let arg: *mut libc::c_void = mem::transmute(box p); // must box since sizeof(p)=2*uint
+ // must box since sizeof(p)=2*uint
+ let raw_p = boxed::into_raw(box p);
+ let arg = raw_p as *mut libc::c_void;
let ret = pthread_create(&mut native, &attr, thread_start, arg);
assert_eq!(pthread_attr_destroy(&mut attr), 0);
if ret != 0 {
// be sure to not leak the closure
- let _p: Box<Box<FnOnce()+Send>> = mem::transmute(arg);
+ let _p: Box<Thunk> = Box::from_raw(raw_p);
Err(io::Error::from_os_error(ret))
} else {
Ok(native)
// 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)
}
}
use prelude::v1::*;
+use boxed;
use cmp;
use io;
-use mem;
use ptr;
use libc;
use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, SIZE_T, BOOL,
}
pub unsafe fn create(stack: uint, p: Thunk) -> io::Result<rust_thread> {
- let arg: *mut libc::c_void = mem::transmute(box p);
+ let raw_p = boxed::into_raw(box p);
+ let arg = raw_p as *mut libc::c_void;
// FIXME On UNIX, we guard against stack sizes that are too small but
// that's because pthreads enforces that stacks are at least
// PTHREAD_STACK_MIN bytes big. Windows has no such lower limit, it's
if ret as uint == 0 {
// be sure to not leak the closure
- let _p: Box<Thunk> = mem::transmute(arg);
+ let _p: Box<Thunk> = Box::from_raw(raw_p);
Err(io::Error::last_os_error())
} else {
Ok(ret)
use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL};
-use mem;
+use boxed;
use ptr;
use rt;
use sys_common::mutex::{MUTEX_INIT, Mutex};
if !DTORS.is_null() { return }
let dtors = box Vec::<(Key, Dtor)>::new();
- DTORS = mem::transmute(dtors);
+ DTORS = boxed::into_raw(dtors);
rt::at_exit(move|| {
DTOR_LOCK.lock();
let dtors = DTORS;
DTORS = ptr::null_mut();
- mem::transmute::<_, Box<Vec<(Key, Dtor)>>>(dtors);
+ Box::from_raw(dtors);
assert!(DTORS.is_null()); // can't re-init after destructing
DTOR_LOCK.unlock();
});
use time::Duration;
use sync::{Once, ONCE_INIT};
+const NANOS_PER_SEC: i64 = 1_000_000_000;
+
pub struct SteadyTime {
t: libc::LARGE_INTEGER,
}
}
pub fn ns(&self) -> u64 {
- self.t as u64 * 1_000_000_000 / frequency() as u64
+ mul_div_i64(self.t as i64, NANOS_PER_SEC, frequency() as i64) as u64
}
}
fn sub(self, other: &SteadyTime) -> Duration {
let diff = self.t as i64 - other.t as i64;
- Duration::microseconds(diff * 1_000_000 / frequency() as i64)
+ Duration::nanoseconds(mul_div_i64(diff, NANOS_PER_SEC, frequency() as i64))
}
}
+
+// Computes (value*numer)/denom without overflow, as long as both
+// (numer*denom) and the overall result fit into i64 (which is the case
+// for our time conversions).
+fn mul_div_i64(value: i64, numer: i64, denom: i64) -> i64 {
+ let q = value / denom;
+ let r = value % denom;
+ // Decompose value as (value/denom*denom + value%denom),
+ // substitute into (value*numer)/denom and simplify.
+ // r < denom, so (denom*numer) is the upper bound of (r*numer)
+ q * numer + r * numer / denom
+}
+
+#[test]
+fn test_muldiv() {
+ assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000);
+ assert_eq!(mul_div_i64(-1_000_000_000_001, 1_000_000_000, 1_000_000), -1_000_000_000_001_000);
+ assert_eq!(mul_div_i64(-1_000_000_000_001,-1_000_000_000, 1_000_000), 1_000_000_000_001_000);
+ assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000,-1_000_000), -1_000_000_000_001_000);
+ assert_eq!(mul_div_i64( 1_000_000_000_001,-1_000_000_000,-1_000_000), 1_000_000_000_001_000);
+}
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,
}
// Due to rust-lang/rust#18804, make sure this is not generic!
#[cfg(target_os = "linux")]
unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
+ use boxed;
use mem;
use libc;
use sys_common::thread_local as os;
type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>;
if DTORS.get().is_null() {
let v: Box<List> = box Vec::new();
- DTORS.set(mem::transmute(v));
+ DTORS.set(boxed::into_raw(v) as *mut u8);
}
let list: &mut List = &mut *(DTORS.get() as *mut List);
list.push((t, dtor));
unsafe extern fn run_dtors(mut ptr: *mut u8) {
while !ptr.is_null() {
- let list: Box<List> = mem::transmute(ptr);
+ let list: Box<List> = Box::from_raw(ptr as *mut List);
for &(ptr, dtor) in &*list {
dtor(ptr);
}
mod imp {
use prelude::v1::*;
+ use alloc::boxed;
use cell::UnsafeCell;
use mem;
use ptr;
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);
key: self,
value: mem::transmute_copy(&self.inner),
};
- let ptr: *mut Value<T> = mem::transmute(ptr);
+ let ptr: *mut Value<T> = boxed::into_raw(ptr);
self.os.set(ptr as *mut u8);
Some(&mut (*ptr).value as *mut T)
}
//
// Note that to prevent an infinite loop we reset it back to null right
// before we return from the destructor ourselves.
- let ptr: Box<Value<T>> = mem::transmute(ptr);
+ let ptr: Box<Value<T>> = Box::from_raw(ptr as *mut Value<T>);
let key = ptr.key;
key.os.set(1 as *mut u8);
drop(ptr);
#[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
Generics,
TyParamBounds,
Vec<TraitItem>),
+
+ // Default trait implementations
+ // `impl Trait for ..`
+ ItemDefaultImpl(Unsafety, TraitRef),
ItemImpl(Unsafety,
ImplPolarity,
Generics,
ItemStruct(..) => "struct",
ItemTrait(..) => "trait",
ItemMac(..) |
- ItemImpl(..) => "item"
+ ItemImpl(..) |
+ ItemDefaultImpl(..) => "item"
}
}
}
ItemStruct(..) => "struct",
ItemTrait(..) => "trait",
ItemImpl(..) => "impl",
+ ItemDefaultImpl(..) => "default impl",
ItemMac(..) => "macro"
};
format!("{} {}{}", item_str, path_str, id_str)
}
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.
/// hint of where they came from, (previously they would all just be
/// listed as `__extensions__::method_name::hash`, with no indication
/// of the type).
-pub fn impl_pretty_name(trait_ref: &Option<TraitRef>, ty: &Ty) -> Ident {
- let mut pretty = pprust::ty_to_string(ty);
+pub fn impl_pretty_name(trait_ref: &Option<TraitRef>, ty: Option<&Ty>) -> Ident {
+ let mut pretty = match ty {
+ Some(t) => pprust::ty_to_string(t),
+ None => String::from_str("..")
+ };
+
match *trait_ref {
Some(ref trait_ref) => {
pretty.push('.');
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,
#[test] fn idents_name_eq_test() {
assert!(segments_name_eq(
&[Ident{name:Name(3),ctxt:4}, Ident{name:Name(78),ctxt:82}]
- .iter().map(ident_to_segment).collect::<Vec<PathSegment>>()[],
+ .iter().map(ident_to_segment).collect::<Vec<PathSegment>>(),
&[Ident{name:Name(3),ctxt:104}, Ident{name:Name(78),ctxt:182}]
- .iter().map(ident_to_segment).collect::<Vec<PathSegment>>()[]));
+ .iter().map(ident_to_segment).collect::<Vec<PathSegment>>()));
assert!(!segments_name_eq(
&[Ident{name:Name(3),ctxt:4}, Ident{name:Name(78),ctxt:82}]
- .iter().map(ident_to_segment).collect::<Vec<PathSegment>>()[],
+ .iter().map(ident_to_segment).collect::<Vec<PathSegment>>(),
&[Ident{name:Name(3),ctxt:104}, Ident{name:Name(77),ctxt:182}]
- .iter().map(ident_to_segment).collect::<Vec<PathSegment>>()[]));
+ .iter().map(ident_to_segment).collect::<Vec<PathSegment>>()));
}
}
}
/// Determine what `#[inline]` attribute is present in `attrs`, if any.
-pub fn find_inline_attr(attrs: &[Attribute]) -> InlineAttr {
+pub fn find_inline_attr(diagnostic: Option<&SpanHandler>, attrs: &[Attribute]) -> InlineAttr {
// FIXME (#2809)---validate the usage of #[inline] and #[inline]
attrs.iter().fold(InlineNone, |ia,attr| {
match attr.node.value.node {
}
MetaList(ref n, ref items) if *n == "inline" => {
mark_used(attr);
- if contains_name(&items[..], "always") {
+ if items.len() != 1 {
+ diagnostic.map(|d|{ d.span_err(attr.span, "expected one argument"); });
+ InlineNone
+ } else if contains_name(&items[..], "always") {
InlineAlways
} else if contains_name(&items[..], "never") {
InlineNever
} else {
- InlineHint
+ diagnostic.map(|d|{ d.span_err((*items[0]).span, "invalid argument"); });
+ InlineNone
}
}
_ => ia
/// True if `#[inline]` or `#[inline(always)]` is present in `attrs`.
pub fn requests_inline(attrs: &[Attribute]) -> bool {
- match find_inline_attr(attrs) {
+ match find_inline_attr(None, attrs) {
InlineHint | InlineAlways => true,
InlineNone | InlineNever => false,
}
-> 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>;
fn expr_usize(&self, span: Span, i: usize) -> P<ast::Expr>;
fn expr_int(&self, sp: Span, i: isize) -> P<ast::Expr>;
fn expr_u8(&self, sp: Span, u: u8) -> P<ast::Expr>;
+ fn expr_u32(&self, sp: Span, u: u32) -> P<ast::Expr>;
fn expr_bool(&self, sp: Span, value: bool) -> P<ast::Expr>;
fn expr_vec(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> 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_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)))
}
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)
// Just mark it now since we know that it'll end up used downstream
attr::mark_used(&attr);
let opt_trait_ref = Some(trait_ref);
- let ident = ast_util::impl_pretty_name(&opt_trait_ref, &*self_type);
+ let ident = ast_util::impl_pretty_name(&opt_trait_ref, Some(&*self_type));
let mut a = vec![attr];
a.extend(self.attributes.iter().cloned());
cx.item(
)
}
+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 topmost = cx.original_span_in_file();
let loc = cx.codemap().lookup_char_pos(topmost.lo);
- base::MacExpr::new(cx.expr_usize(topmost, loc.line))
+ base::MacExpr::new(cx.expr_u32(topmost, loc.line as u32))
}
/* column!(): expands to the current column number */
let topmost = cx.original_span_in_file();
let loc = cx.codemap().lookup_char_pos(topmost.lo);
- base::MacExpr::new(cx.expr_usize(topmost, loc.col.to_usize()))
+
+ base::MacExpr::new(cx.expr_u32(topmost, loc.col.to_usize() as u32))
}
/// file!(): expands to the current filename */
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 {
let struct_def = folder.fold_struct_def(struct_def);
ItemStruct(struct_def, folder.fold_generics(generics))
}
+ ItemDefaultImpl(unsafety, ref trait_ref) => {
+ ItemDefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone()))
+ }
ItemImpl(unsafety, polarity, generics, ifce, ty, impl_items) => {
let new_impl_items = impl_items.into_iter().flat_map(|item| {
folder.fold_impl_item(item).into_iter()
let ident = match node {
// The node may have changed, recompute the "pretty" impl name.
ItemImpl(_, _, _, ref maybe_trait, ref ty, _) => {
- ast_util::impl_pretty_name(maybe_trait, &**ty)
+ ast_util::impl_pretty_name(maybe_trait, Some(&**ty))
}
_ => ident
};
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))),
let mut first = true;
for line in &lines {
for (j, c) in line.chars().enumerate() {
- if j > i || !"* \t".contains_char(c) {
+ if j > i || !"* \t".contains(c) {
can_trim = false;
break;
}
if is_block_doc_comment(&curr_line[..]) {
return
}
- assert!(!curr_line.contains_char('\n'));
+ assert!(!curr_line.contains('\n'));
lines.push(curr_line);
} else {
let mut level: isize = 1;
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::{Ident, Inherited, ImplItem, Item, Item_, ItemStatic};
use ast::{ItemEnum, ItemFn, ItemForeignMod, ItemImpl, ItemConst};
-use ast::{ItemMac, ItemMod, ItemStruct, ItemTrait, ItemTy};
+use ast::{ItemMac, ItemMod, ItemStruct, ItemTrait, ItemTy, ItemDefaultImpl};
use ast::{ItemExternCrate, ItemUse};
use ast::{LifetimeDef, Lit, Lit_};
use ast::{LitBool, LitChar, LitByte, LitBinary};
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 fstr = n.as_str();
self.span_err(last_span,
&format!("unexpected token: `{}`", n.as_str()));
- if fstr.chars().all(|x| "0123456789.".contains_char(x)) {
+ if fstr.chars().all(|x| "0123456789.".contains(x)) {
let float = match fstr.parse::<f64>().ok() {
Some(f) => f,
None => continue,
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()
};
};
pat = PatIdent(BindByValue(MutImmutable), pth1, sub);
}
+ } else if self.look_ahead(1, |t| *t == token::Lt) {
+ self.bump();
+ self.unexpected()
} else {
// parse an enum pat
let enum_path = self.parse_path(LifetimeAndTypesWithColons);
(impl_items, inner_attrs)
}
- /// Parses two variants (with the region/type params always optional):
+ /// Parses items implementations variants
/// impl<T> Foo { ... }
- /// impl<T> ToString for ~[T] { ... }
+ /// impl<T> ToString for &'static T { ... }
+ /// impl Send for .. {}
fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> ItemInfo {
+ let impl_span = self.span;
+
// First, parse type parameters if necessary.
let mut generics = self.parse_generics();
// Parse traits, if necessary.
let opt_trait = if could_be_trait && self.eat_keyword(keywords::For) {
// New-style trait. Reinterpret the type as a trait.
- let opt_trait_ref = match ty.node {
- TyPath(ref path, node_id) => {
+ match ty.node {
+ TyPath(None, ref path) => {
Some(TraitRef {
path: (*path).clone(),
- ref_id: node_id,
+ ref_id: ty.id,
})
}
_ => {
self.span_err(ty.span, "not a trait");
None
}
- };
-
- ty = self.parse_ty_sum();
- opt_trait_ref
+ }
} else {
match polarity {
ast::ImplPolarity::Negative => {
None
};
- self.parse_where_clause(&mut generics);
- let (impl_items, attrs) = self.parse_impl_items();
+ if self.eat(&token::DotDot) {
+ if generics.is_parameterized() {
+ self.span_err(impl_span, "default trait implementations are not \
+ allowed to have genercis");
+ }
- let ident = ast_util::impl_pretty_name(&opt_trait, &*ty);
+ self.expect(&token::OpenDelim(token::Brace));
+ self.expect(&token::CloseDelim(token::Brace));
+ (ast_util::impl_pretty_name(&opt_trait, None),
+ ItemDefaultImpl(unsafety, opt_trait.unwrap()), None)
+ } else {
+ if opt_trait.is_some() {
+ ty = self.parse_ty_sum();
+ }
+ self.parse_where_clause(&mut generics);
+ let (impl_items, attrs) = self.parse_impl_items();
- (ident,
- ItemImpl(unsafety, polarity, generics, opt_trait, ty, impl_items),
- Some(attrs))
+ (ast_util::impl_pretty_name(&opt_trait, Some(&*ty)),
+ ItemImpl(unsafety, polarity, generics, opt_trait, ty, impl_items),
+ Some(attrs))
+ }
}
/// Parse a::B<String,i32>
}
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));
try!(self.print_struct(&**struct_def, generics, item.ident, item.span));
}
+ ast::ItemDefaultImpl(unsafety, ref trait_ref) => {
+ try!(self.head(""));
+ try!(self.print_visibility(item.vis));
+ try!(self.print_unsafety(unsafety));
+ try!(self.word_nbsp("impl"));
+ try!(self.print_trait_ref(trait_ref));
+ try!(space(&mut self.s));
+ try!(self.word_space("for"));
+ try!(self.word_space(".."));
+ try!(self.bopen());
+ try!(self.bclose(item.span));
+ }
ast::ItemImpl(unsafety,
polarity,
ref generics,
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)
}
visitor.visit_generics(type_parameters);
walk_enum_def(visitor, enum_definition, type_parameters)
}
+ ItemDefaultImpl(_, ref trait_ref) => {
+ visitor.visit_trait_ref(trait_ref)
+ }
ItemImpl(_, _,
ref type_parameters,
ref trait_reference,
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);
if self.use_color {
try!(term.reset());
}
- Ok(())
+ term.flush()
+ }
+ Raw(ref mut stdout) => {
+ try!(stdout.write_all(word.as_bytes()));
+ stdout.flush()
}
- Raw(ref mut stdout) => stdout.write_all(word.as_bytes())
}
}
pub fn write_plain(&mut self, s: &str) -> old_io::IoResult<()> {
match self.out {
- Pretty(ref mut term) => term.write_all(s.as_bytes()),
- Raw(ref mut stdout) => stdout.write_all(s.as_bytes())
+ Pretty(ref mut term) => {
+ try!(term.write_all(s.as_bytes()));
+ term.flush()
+ },
+ Raw(ref mut stdout) => {
+ try!(stdout.write_all(s.as_bytes()));
+ stdout.flush()
+ },
}
}
/// Returns a HashMap with the number of occurrences of every element in the
/// sequence that the iterator exposes.
+#[cfg(not(stage0))]
pub fn freq_count<T, U>(iter: T) -> hash_map::HashMap<U, uint>
where T: Iterator<Item=U>, U: Eq + Clone + Hash
{
#[inline]
fn trim(&self) -> &str {
- self.trim_left().trim_right()
+ self.trim_matches(|c: char| c.is_whitespace())
}
#[inline]
-Subproject commit 4891e6382e3e8aa89d530aa18427836428c47157
+Subproject commit b89c3f039b61edbb077771eda2ee8a718dbec7e0
let mut section = "".to_string();
for &(_, idx) in &self.stack {
- section.push_str(&(idx + 1).to_string()[]);
+ section.push_str(&(idx + 1).to_string()[..]);
section.push('.');
}
- section.push_str(&(self.cur_idx + 1).to_string()[]);
+ section.push_str(&(self.cur_idx + 1).to_string()[..]);
section.push('.');
self.stack.push((self.cur_items, self.cur_idx));
- self.cur_items = &cur.children[];
+ self.cur_items = &cur.children[..];
self.cur_idx = 0;
return Some((section, cur))
}
impl Book {
pub fn iter(&self) -> BookItems {
BookItems {
- cur_items: &self.chapters[],
+ cur_items: &self.chapters[..],
cur_idx: 0,
stack: Vec::new(),
}
}
};
- let star_idx = match line.find_str("*") { Some(i) => i, None => continue };
+ let star_idx = match line.find("*") { Some(i) => i, None => continue };
- let start_bracket = star_idx + line[star_idx..].find_str("[").unwrap();
- let end_bracket = start_bracket + line[start_bracket..].find_str("](").unwrap();
+ let start_bracket = star_idx + line[star_idx..].find("[").unwrap();
+ let end_bracket = start_bracket + line[start_bracket..].find("](").unwrap();
let start_paren = end_bracket + 1;
- let end_paren = start_paren + line[start_paren..].find_str(")").unwrap();
+ let end_paren = start_paren + line[start_paren..].find(")").unwrap();
let given_path = &line[start_paren + 1 .. end_paren];
let title = line[start_bracket + 1..end_bracket].to_string();
//! Implementation of the `build` subcommand, used to compile a book.
-use std::os;
use std::env;
+use std::os;
use std::old_io;
use std::old_io::{fs, File, BufferedWriter, TempDir, IoResult};
path_to_root: &Path,
out: &mut Writer) -> IoResult<()> {
for (i, item) in items.iter().enumerate() {
- try!(walk_item(item, &format!("{}{}.", section, i + 1)[], path_to_root, out));
+ try!(walk_item(item, &format!("{}{}.", section, i + 1)[..], path_to_root, out));
}
Ok(())
}
item.title));
if !item.children.is_empty() {
try!(writeln!(out, "<ul class='section'>"));
- let _ = walk_items(&item.children[], section, path_to_root, out);
+ let _ = walk_items(&item.children[..], section, path_to_root, out);
try!(writeln!(out, "</ul>"));
}
try!(writeln!(out, "</li>"));
try!(writeln!(out, "<div id='toc' class='mobile-hidden'>"));
try!(writeln!(out, "<ul class='chapter'>"));
- try!(walk_items(&book.chapters[], "", path_to_root, out));
+ try!(walk_items(&book.chapters[..], "", path_to_root, out));
try!(writeln!(out, "</ul>"));
try!(writeln!(out, "</div>"));
Err(errors) => {
let n = errors.len();
for err in errors {
- term.err(&format!("error: {}", err)[]);
+ term.err(&format!("error: {}", err)[..]);
}
Err(box format!("{} errors occurred", n) as Box<Error>)
#![feature(collections)]
#![feature(core)]
#![feature(old_io)]
-#![feature(os)]
#![feature(env)]
+#![feature(os)]
#![feature(old_path)]
#![feature(rustdoc)]
if cmd.len() <= 1 {
help::usage()
} else {
- match subcommand::parse_name(&cmd[1][]) {
+ match subcommand::parse_name(&cmd[1][..]) {
Some(mut subcmd) => {
match subcmd.parse_args(cmd.tail()) {
Ok(_) => {
match subcmd.execute(&mut term) {
Ok(_) => (),
Err(err) => {
- term.err(&format!("error: {}", err.description())[]);
+ term.err(&format!("error: {}", err.description())[..]);
err.detail().map(|detail| {
- term.err(&format!("detail: {}", detail)[]);
+ term.err(&format!("detail: {}", detail)[..]);
});
}
}
Ok(output) => {
if !output.status.success() {
term.err(&format!("{}\n{}",
- String::from_utf8_lossy(&output.output[]),
- String::from_utf8_lossy(&output.error[]))[]);
+ String::from_utf8_lossy(&output.output[..]),
+ String::from_utf8_lossy(&output.error[..]))[..]);
return Err(box "Some tests failed." as Box<Error>);
}
# If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
# The actual contents of this file do not matter, but to trigger a change on the
# build bots then the contents should be changed so git updates the mtime.
-2015-02-13
+2015-02-19
+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);
#![crate_name="static_methods_crate"]
#![crate_type = "lib"]
-use std::int;
-
pub trait read {
fn readMaybe(s: String) -> Option<Self>;
}
-impl read for int {
- fn readMaybe(s: String) -> Option<int> {
+impl read for isize {
+ fn readMaybe(s: String) -> Option<isize> {
s.parse().ok()
}
}
}
}
-// FIXME(#21721) used to be `List<()>` but that can cause
-// certain LLVM versions to abort during optimizations.
-type nillist = List<[u8; 0]>;
+type nillist = List<()>;
// Filled with things that have to be unwound
}
Some(st) => {
let mut v = st.vec.clone();
- v.push_all(&[box List::Cons([], st.vec.last().unwrap().clone())]);
+ v.push_all(&[box List::Cons((), st.vec.last().unwrap().clone())]);
State {
- unique: box List::Cons([], box *st.unique),
+ unique: box List::Cons((), box *st.unique),
vec: v,
- res: r(box List::Cons([], st.res._l.clone())),
+ res: r(box List::Cons((), st.res._l.clone())),
}
}
};
--- /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
// Test that attempt to reborrow an `&mut` pointer in an aliasable
// location yields an error.
//
-// Example from src/middle/borrowck/doc.rs
+// Example from src/librustc_borrowck/borrowck/README.md
fn foo(t0: & &mut isize) {
let t1 = t0;
--- /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() {
+}
// Test that attempt to move `&mut` pointer while pointee is borrowed
// yields an error.
//
-// Example from src/middle/borrowck/doc.rs
+// Example from src/librustc_borrowck/borrowck/README.md
fn foo(t0: &mut isize) {
let p: &isize = &*t0; // Freezes `*t0`
// Test that attempt to mutably borrow `&mut` pointer while pointee is
// borrowed yields an error.
//
-// Example from src/middle/borrowck/doc.rs
+// Example from src/librustc_borrowck/borrowck/README.md
fn foo<'a>(mut t0: &'a mut isize,
mut t1: &'a mut isize) {
// Test that attempt to swap `&mut` pointer while pointee is borrowed
// yields an error.
//
-// Example from src/middle/borrowck/doc.rs
+// Example from src/librustc_borrowck/borrowck/README.md
use std::mem::swap;
// 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
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+
+#![feature(optin_builtin_traits)]
+
+use std::marker::MarkerTrait;
+
+trait MyTrait: MarkerTrait {}
+
+impl MyTrait for .. {}
+
+impl MyTrait for .. {}
+//~^ ERROR conflicting implementations for trait `MyTrait`
+
+fn main() {}
unsafe impl Send for &'static [NotSync] {}
//~^ ERROR builtin traits can only be implemented on structs or enums
+//~^^ ERROR conflicting implementations for trait `core::marker::Send`
fn is_send<T: Send>() {}
// 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 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![allow(dead_code)]
+
+#[inline(please_no)] //~ ERROR invalid argument
+fn a() {
+}
+
+#[inline(please,no)] //~ ERROR expected one argument
+fn b() {
+}
+
+#[inline()] //~ ERROR expected one argument
+fn c() {
+}
+
+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
}
}
--- /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() {
+ match 42 {
+ x < 7 => (),
+ //~^ error: unexpected token: `<`
+ _ => ()
+ }
+}
--- /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 a(B<) {}
+ //~^ error: unexpected token: `<`
--- /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<T>(T, T);
+
+impl<T> Foo<T> {
+ fn foo(&self) {
+ match *self {
+ Foo<T>(x, y) => {
+ //~^ error: unexpected token: `<`
+ println!("Goodbye, World!")
+ }
+ }
+ }
+}
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})}
}
}
//~^^^^ ERROR overflow evaluating
//~^^^^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
//~^^^^^^ NOTE required by `is_send`
+ //~^^^^^^^ ERROR overflow evaluating
+ //~^^^^^^^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
+ //~^^^^^^^^^ NOTE required by `is_send`
}
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 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(rustc_attrs)]
+#![allow(warnings)]
+
+pub fn fail(x: Option<& (Iterator+Send)>) -> Option<&Iterator> {
+ // This call used to trigger an LLVM assertion because the return slot had type
+ // "Option<&Iterator>"* instead of "Option<&(Iterator+Send)>"*
+ inner(x)
+}
+
+pub fn inner(x: Option<& (Iterator+Send)>) -> Option<&(Iterator+Send)> {
+ x
+}
+
+#[rustc_error]
+fn main() {} //~ ERROR compilation successful
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// basic tests to see that certain "obvious" errors are caught by
+// these types no longer requiring `'static` (RFC 458)
+
+#![allow(dead_code)]
+
+use std::sync::{Mutex, RwLock, mpsc};
+
+fn mutex() {
+ let lock = {
+ let x = 1;
+ Mutex::new(&x) //~ ERROR does not live long enough
+ };
+
+ let _dangling = *lock.lock().unwrap();
+}
+
+fn rwlock() {
+ let lock = {
+ let x = 1;
+ RwLock::new(&x) //~ ERROR does not live long enough
+ };
+ let _dangling = *lock.read().unwrap();
+}
+
+fn channel() {
+ let (_tx, rx) = {
+ let x = 1;
+ let (tx, rx) = mpsc::channel();
+ let _ = tx.send(&x); //~ ERROR does not live long enough
+ (tx, rx)
+ };
+
+ let _dangling = rx.recv();
+}
+
+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.
+
+// basic tests to see that certain "obvious" errors are caught by
+// these types no longer requiring `'static` (RFC 458)
+
+#![allow(dead_code)]
+
+use std::sync::{Mutex, RwLock, mpsc};
+
+fn mutex() {
+ let x = 1;
+ let y = Box::new(1);
+ let lock = Mutex::new(&x);
+ *lock.lock().unwrap() = &*y;
+ drop(y); //~ ERROR cannot move out
+ {
+ let z = 2;
+ *lock.lock().unwrap() = &z; //~ ERROR does not live long enough
+ }
+}
+
+fn rwlock() {
+ let x = 1;
+ let y = Box::new(1);
+ let lock = RwLock::new(&x);
+ *lock.write().unwrap() = &*y;
+ drop(y); //~ ERROR cannot move out
+ {
+ let z = 2;
+ *lock.write().unwrap() = &z; //~ ERROR does not live long enough
+ }
+}
+
+fn channel() {
+ let x = 1;
+ let y = Box::new(1);
+ let (tx, rx) = mpsc::channel();
+
+ tx.send(&x).unwrap();
+ tx.send(&*y);
+ drop(y); //~ ERROR cannot move out
+ {
+ let z = 2;
+ tx.send(&z).unwrap(); //~ ERROR does not live long enough
+ }
+}
+
+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(optin_builtin_traits)]
+
+trait MyDefaultImpl {}
+
+impl<T> MyDefaultImpl for .. {}
+//~^ ERROR default trait implementations are not allowed to have genercis
+
+fn main() {}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Test 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() {
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we do not consider associated types to be sendable without
+// some applicable trait bound (and we don't ICE).
+
+trait Trait {
+ type AssocType;
+ fn dummy(&self) { }
+}
+fn bar<T:Trait+Send>() {
+ is_send::<T::AssocType>(); //~ ERROR not implemented
+}
+
+fn is_send<T:Send>() {
+}
+
+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(optin_builtin_traits)]
+
+use std::marker::MarkerTrait;
+
+trait MyTrait: MarkerTrait {}
+
+impl MyTrait for .. {}
+
+struct MyS;
+
+struct MyS2;
+
+impl !MyTrait for MyS2 {}
+
+fn is_mytrait<T: MyTrait>() {}
+
+fn main() {
+ is_mytrait::<MyS>();
+
+ is_mytrait::<(MyS2, MyS)>();
+ //~^ ERROR the trait `MyTrait` is not implemented for the type `MyS2`
+}
--- /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(optin_builtin_traits)]
+
+use std::marker::MarkerTrait;
+
+trait MyTrait: MarkerTrait {}
+
+impl MyTrait for .. {}
+impl<T> !MyTrait for *mut T {}
+
+struct MyS;
+
+struct MyS2;
+
+impl !MyTrait for MyS2 {}
+
+struct MyS3;
+
+fn is_mytrait<T: MyTrait>() {}
+
+fn main() {
+ is_mytrait::<MyS>();
+
+ is_mytrait::<MyS2>();
+ //~^ ERROR the trait `MyTrait` is not implemented for the type `MyS2`
+}
--- /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(optin_builtin_traits)]
+
+struct MySendable {
+ t: *mut u8
+}
+
+unsafe impl Send for MySendable {}
+
+struct MyNotSendable {
+ t: *mut u8
+}
+
+impl !Send for MyNotSendable {}
+
+fn is_send<T: Send>() {}
+
+fn main() {
+ is_send::<MySendable>();
+ is_send::<MyNotSendable>();
+ //~^ ERROR the trait `core::marker::Send` is not implemented for the type `MyNotSendable`
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+
+#![feature(optin_builtin_traits)]
+
+use std::marker::Managed;
+use std::cell::UnsafeCell;
+
+struct MySync {
+ t: *mut u8
+}
+
+unsafe impl Sync for MySync {}
+
+struct MyNotSync {
+ t: *mut u8
+}
+
+impl !Sync for MyNotSync {}
+
+struct MyTypeWUnsafe {
+ t: UnsafeCell<u8>
+}
+
+struct MyTypeManaged {
+ t: Managed
+}
+
+fn is_sync<T: Sync>() {}
+
+fn main() {
+ is_sync::<MySync>();
+ is_sync::<MyNotSync>();
+ //~^ ERROR the trait `core::marker::Sync` is not implemented for the type `MyNotSync`
+
+ is_sync::<MyTypeWUnsafe>();
+ //~^ ERROR the trait `core::marker::Sync` is not implemented for the type `core::cell::UnsafeCell<u8>`
+
+ is_sync::<MyTypeManaged>();
+ //~^ ERROR the trait `core::marker::Sync` is not implemented for the type `core::marker::Managed`
+}
--- /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(optin_builtin_traits)]
+
+use std::marker::MarkerTrait;
+
+trait MyTrait: MarkerTrait {}
+
+impl MyTrait for .. {}
+
+unsafe trait MyUnsafeTrait: MarkerTrait {}
+
+unsafe impl MyUnsafeTrait for .. {}
+
+struct ThisImplsTrait;
+
+impl !MyUnsafeTrait for ThisImplsTrait {}
+
+
+struct ThisImplsUnsafeTrait;
+
+impl !MyTrait for ThisImplsUnsafeTrait {}
+
+fn is_my_trait<T: MyTrait>() {}
+fn is_my_unsafe_trait<T: MyUnsafeTrait>() {}
+
+fn main() {
+ is_my_trait::<ThisImplsTrait>();
+ is_my_trait::<ThisImplsUnsafeTrait>();
+ //~^ ERROR the trait `MyTrait` is not implemented for the type `ThisImplsUnsafeTrait`
+
+ is_my_unsafe_trait::<ThisImplsTrait>();
+ //~^ ERROR the trait `MyUnsafeTrait` is not implemented for the type `ThisImplsTrait`
+
+ is_my_unsafe_trait::<ThisImplsUnsafeTrait>();
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+
+#![feature(optin_builtin_traits)]
+
+impl Copy for .. {}
+//~^ ERROR cannot create default implementations for traits outside the crate they're defined in; define a new trait instead.
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that declaring that `&T` is `Defaulted` if `T:Signed` implies
+// that other `&T` is NOT `Defaulted` if `T:Signed` does not hold. In
+// other words, the `..` impl only applies if there are no existing
+// impls whose types unify.
+
+#![feature(optin_builtin_traits)]
+
+use std::marker::MarkerTrait;
+
+trait Defaulted : MarkerTrait { }
+impl Defaulted for .. { }
+impl<'a,T:Signed> Defaulted for &'a T { }
+impl<'a,T:Signed> Defaulted for &'a mut T { }
+fn is_defaulted<T:Defaulted>() { }
+
+trait Signed : MarkerTrait { }
+impl Signed for i32 { }
+
+fn main() {
+ is_defaulted::<&'static i32>();
+ is_defaulted::<&'static u32>();
+ //~^ ERROR the trait `Signed` is not implemented for the type `u32`
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we do not consider parameter types to be sendable without
+// an explicit trait bound.
+
+fn foo<T>() {
+ is_send::<T>() //~ ERROR not implemented
+}
+
+fn is_send<T:Send>() {
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that when a `..` impl applies, we also check that any
+// supertrait conditions are met.
+
+#![feature(optin_builtin_traits)]
+
+use std::marker::MarkerTrait;
+
+trait MyTrait : 'static {}
+
+impl MyTrait for .. {}
+
+fn foo<T:MyTrait>() { }
+
+fn bar<'a>() {
+ foo::<&'a ()>(); //~ ERROR does not fulfill the required lifetime
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that when a `..` impl applies, we also check that any
+// supertrait conditions are met.
+
+#![feature(optin_builtin_traits)]
+
+use std::marker::MarkerTrait;
+
+trait NotImplemented: MarkerTrait { }
+
+trait MyTrait : NotImplemented {}
+
+impl MyTrait for .. {}
+
+fn foo<T:MyTrait>() { bar::<T>() }
+
+fn bar<T:NotImplemented>() { }
+
+fn main() {
+ foo::<i32>(); //~ ERROR the trait `NotImplemented` is not implemented for the type `i32`
+ bar::<i64>(); //~ ERROR the trait `NotImplemented` is not implemented for the type `i64`
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+
+// Test that when a `..` impl applies, we also check that any
+// supertrait conditions are met.
+
+#![feature(optin_builtin_traits)]
+
+use std::marker::MarkerTrait;
+
+trait NotImplemented: MarkerTrait { }
+
+trait MyTrait: MarkerTrait
+ where Option<Self> : NotImplemented
+{}
+
+impl NotImplemented for i32 {}
+
+impl MyTrait for .. {}
+
+fn foo<T:MyTrait>() {
+ bar::<Option<T>>()
+ //~^ ERROR the trait `NotImplemented` is not implemented for the type `core::option::Option<T>`
+ //
+ // This should probably typecheck. This is #20671.
+}
+
+fn bar<T:NotImplemented>() { }
+
+fn test() {
+ bar::<Option<i32>>();
+ //~^ ERROR the trait `NotImplemented` is not implemented for the type `core::option::Option<i32>`
+}
+
+fn main() {
+ foo::<i32>();
+ //~^ ERROR the trait `NotImplemented` is not implemented for the type `core::option::Option<i32>`
+}
}
impl !TestTrait for TestType {}
-//~^ ERROR negative impls are currently allowed just for `Send` and `Sync`
+//~^ ERROR negative impls are only allowed for traits with default impls (e.g., `Send` and `Sync`)
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();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-impl Foo; //~ ERROR expected one of `(`, `+`, `::`, `<`, `for`, `where`, or `{`, found `;`
+impl Foo; //~ ERROR expected one of `(`, `+`, `..`, `::`, `<`, `for`, `where`, or `{`, found `;`
--- /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() {}
}
impl Cmp, ToString for S {
-//~^ ERROR: expected one of `(`, `+`, `::`, `<`, `for`, `where`, or `{`, found `,`
+//~^ ERROR: expected one of `(`, `+`, `..`, `::`, `<`, `for`, `where`, or `{`, found `,`
fn eq(&&other: S) { false }
fn to_string(&self) -> String { "hi".to_string() }
}
// 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
}
-
struct Bar;
-impl Foo + Owned for Bar { //~ ERROR not a trait
+impl Foo + Owned for Bar {
+//~^ ERROR not a trait
+//~^^ ERROR expected one of `..`, `where`, or `{`, found `Bar`
}
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(optin_builtin_traits)]
+
+// pp-exact
+
+use std::marker::MarkerTrait;
+
+trait MyTrait: MarkerTrait { }
+
+impl MyTrait for .. { }
+
+pub fn main() { }
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;
cp foo.rs $(TMPDIR)/+foo+bar
$(RUSTC) $(TMPDIR)/+foo+bar 2>&1 \
| grep "invalid character.*in crate name:"
+ cp foo.rs $(TMPDIR)/-foo.rs
+ $(RUSTC) $(TMPDIR)/-foo.rs 2>&1 \
+ | grep "crate name cannot start with a hyphen:"
--- /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]);
}
// Test that freezing an `&mut` pointer while referent is
// frozen is legal.
//
-// Example from src/middle/borrowck/doc.rs
+// Example from src/librustc_borrowck/borrowck/README.md
fn foo<'a>(mut t0: &'a mut int,
mut t1: &'a mut int) {
}
}
-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::num::FromPrimitive;
-use std::int;
+use std::isize;
#[derive(PartialEq, FromPrimitive, Debug)]
enum A {
- Foo = int::MAX,
+ Foo = isize::MAX,
Bar = 1,
Baz = 3,
Qux,
}
pub fn main() {
- let x: Option<A> = FromPrimitive::from_int(int::MAX);
+ let x: Option<A> = FromPrimitive::from_int(isize::MAX);
assert_eq!(x, Some(A::Foo));
let x: Option<A> = FromPrimitive::from_int(1);
// 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")));
}
--- /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::marker::MarkerTrait;
+
+trait A : MarkerTrait {
+ extern "fastcall" fn test1(i: i32);
+ extern fn test2(i: i32);
+}
+
+struct S;
+impl S {
+ extern "stdcall" fn test3(i: i32) {
+ assert_eq!(i, 3);
+ }
+}
+
+impl A for S {
+ extern "fastcall" fn test1(i: i32) {
+ assert_eq!(i, 1);
+ }
+ extern fn test2(i: i32) {
+ assert_eq!(i, 2);
+ }
+}
+
+fn main() {
+ <S as A>::test1(1);
+ <S as A>::test2(2);
+ S::test3(3);
+}
}
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());
}
let mut dropped = false;
{
let leak = Leak { dropped: &mut dropped };
- // FIXME(#21721) "hack" used to be () but that can cause
- // certain LLVM versions to abort during optimizations.
- for (_, leaked) in Some(("hack", leak)).into_iter() {}
+ for ((), leaked) in Some(((), leak)).into_iter() {}
}
assert!(dropped);
// 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.
+
+fn main() {
+ static NONE: Option<((), &'static u8)> = None;
+ let ptr = unsafe {
+ *(&NONE as *const _ as *const *const u8)
+ };
+ assert!(ptr.is_null());
+}
--- /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() {
+ match 42 {
+ x if x < 7 => (),
+ _ => ()
+ }
+}
--- /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() { }
+
+
// aux-build:lang-item-public.rs
// ignore-android
-// ignore-windows #13361
#![feature(lang_items, start, no_std)]
#![no_std]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::uint;
-
pub fn main() {
// sometimes we have had trouble finding
// the right type for f, as we unified
// bot and u32 here
- let f = match "1234".parse::<uint>().ok() {
+ let f = match "1234".parse::<usize>().ok() {
None => return (),
Some(num) => num as u32
};
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);
+}
{
assert!(file!().ends_with("includeme.fragment"));
- assert!(line!() == 5_usize);
+ assert!(line!() == 5u32);
format!("victory robot {}", line!())
}
pub fn main() {
assert_eq!(line!(), 25);
- //assert!((column!() == 11));
+ assert!((column!() == 4u32));
assert_eq!(indirect_line!(), 27);
assert!((file!().ends_with("syntax-extension-source-utils.rs")));
assert_eq!(stringify!((2*3) + 5).to_string(), "( 2 * 3 ) + 5".to_string());
}
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 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 #22655: This test should not lead to
+// infinite recursion.
+
+unsafe impl<T: Send + ?Sized> Send for Unique<T> { }
+
+pub struct Unique<T:?Sized> {
+ pointer: *const T,
+}
+
+pub struct Node<V> {
+ vals: V,
+ edges: Unique<Node<V>>,
+}
+
+fn is_send<T: Send>() {}
+
+fn main() {
+ is_send::<Node<&'static ()>>();
+}
--- /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]);
}
pub fn main() {
let (tx, rx) = channel();
- let _t = thread::spawn(move|| f(tx.clone()));
+ let t = thread::spawn(move|| f(tx.clone()));
println!("hiiiiiiiii");
assert!(rx.recv().unwrap());
+ drop(t.join());
}
}
pub fn main() {
- let _t = thread::spawn(f);
+ let t = thread::spawn(f);
+ drop(t.join());
}